From 7327f42816b5027e25ef56f92a5581de62fd48a3 Mon Sep 17 00:00:00 2001 From: "[6~" Date: Fri, 5 Jun 2020 10:52:02 -0500 Subject: [PATCH 01/11] Add license header to obj_array --- pytools/obj_array.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pytools/obj_array.py b/pytools/obj_array.py index d326a43..d8f82ba 100644 --- a/pytools/obj_array.py +++ b/pytools/obj_array.py @@ -1,4 +1,27 @@ from __future__ import absolute_import, division + +__copyright__ = "Copyright (C) 2009-2020 Andreas Kloeckner" + +__license__ = """ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + import numpy as np from pytools import my_decorator as decorator, MovedFunctionDeprecationWrapper -- GitLab From 56eac4b322c5c109cfa8c9150ac1167c2148e1e8 Mon Sep 17 00:00:00 2001 From: "[6~" Date: Fri, 5 Jun 2020 10:56:59 -0500 Subject: [PATCH 02/11] Deprecate large swaths of pytools.obj_array --- pytools/obj_array.py | 152 +++++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 72 deletions(-) diff --git a/pytools/obj_array.py b/pytools/obj_array.py index d8f82ba..aea02da 100644 --- a/pytools/obj_array.py +++ b/pytools/obj_array.py @@ -37,87 +37,96 @@ Handling :mod:`numpy` Object Arrays Creation -------- -.. autofunction:: join_fields .. autofunction:: make_obj_array Mapping ------- -.. autofunction:: with_object_array_or_scalar -.. autofunction:: with_object_array_or_scalar_n_args """ -def gen_len(expr): - if is_obj_array(expr): - return len(expr) else: return 1 -def gen_slice(expr, slice_): - result = expr[slice_] - if len(result) == 1: - return result[0] else: return result +# {{{ deprecated junk + def is_obj_array(val): + warn("is_obj_array is deprecated and will go away in 2021, " + "just inline the check.", DeprecationWarning, stacklevel=2) + try: - return isinstance(val, np.ndarray) and val.dtype == object + return isinstance(val, np.ndarray) and val.dtype.char == "O" except AttributeError: return False -def to_obj_array(ary): - ls = log_shape(ary) - result = np.empty(ls, dtype=object) +def log_shape(array): + """Returns the "logical shape" of the array. - from pytools import indices_in_shape - for i in indices_in_shape(ls): - result[i] = ary[i] + The "logical shape" is the shape that's left when the node-depending + dimension has been eliminated. + """ - return result + warn("log_shape is deprecated and will go away in 2021, " + "use the actual object array shape.", + DeprecationWarning, stacklevel=2) + + try: + if array.dtype.char == "O": + return array.shape + else: + return array.shape[:-1] + except AttributeError: + return () + + +def join_fields(*args): + warn("join_fields is deprecated and will go away in 2022, " + "use flat_obj_array", DeprecationWarning, stacklevel=2) + + return flat_obj_array(*args) def is_equal(a, b): + warn("is_equal is deprecated and will go away in 2021, " + "use numpy.array_equal", DeprecationWarning, stacklevel=2) + if is_obj_array(a): return is_obj_array(b) and (a.shape == b.shape) and (a == b).all() else: return not is_obj_array(b) and a == b -# moderately deprecated is_field_equal = is_equal -def make_obj_array(res_list): - result = np.empty((len(res_list),), dtype=object) - for i, v in enumerate(res_list): - result[i] = v - - return result - - -def setify_field(f): - if is_obj_array(f): - return set(f) +def gen_len(expr): + if is_obj_array(expr): + return len(expr) else: - return set([f]) - + return 1 -def obj_array_to_hashable(f): - if is_obj_array(f): - return tuple(f) - else: - return f +def gen_slice(expr, slice_): + warn("gen_slice is deprecated and will go away in 2021", + DeprecationWarning, stacklevel=2) -hashable_field = MovedFunctionDeprecationWrapper(obj_array_to_hashable) + result = expr[slice_] + if len(result) == 1: + return result[0] + else: + return result def obj_array_equal(a, b): + warn("obj_array_equal is deprecated and will go away in 2021, " + "use numpy.array_equal", DeprecationWarning, stacklevel=2) + a_is_oa = is_obj_array(a) assert a_is_oa == is_obj_array(b) @@ -127,41 +136,42 @@ def obj_array_equal(a, b): return a == b -field_equal = MovedFunctionDeprecationWrapper(obj_array_equal) +def to_obj_array(ary): + warn("to_obj_array is deprecated and will go away in 2021, " + "use make_obj_array", DeprecationWarning, + stacklevel=2) + ls = log_shape(ary) + result = np.empty(ls, dtype=object) -def join_fields(*args): - res_list = [] - for arg in args: - if isinstance(arg, list): - res_list.extend(arg) - elif isinstance(arg, np.ndarray): - if log_shape(arg) == (): - res_list.append(arg) - else: - res_list.extend(arg.flat) - else: - res_list.append(arg) + for i in np.ndindex(ls): + result[i] = ary[i] - return make_obj_array(res_list) + return result -def log_shape(array): - """Returns the "logical shape" of the array. +def setify_field(f): + warn("setify_field is deprecated and will go away in 2021", + DeprecationWarning, stacklevel=2) - The "logical shape" is the shape that's left when the node-depending - dimension has been eliminated.""" + if is_obj_array(f): + return set(f) + else: + return set([f]) - try: - if array.dtype.char == "O": - return array.shape - else: - return array.shape[:-1] - except AttributeError: - return () + +def cast_field(field, dtype): + warn("cast_field is deprecated and will go away in 2021", + DeprecationWarning, stacklevel=2) + + return with_object_array_or_scalar( + lambda f: f.astype(dtype), field) def with_object_array_or_scalar(f, field, obj_array_only=False): + warn("with_object_array_or_scalar is deprecated and will go away in 2022, " + "use oarray_vectorize", DeprecationWarning, stacklevel=2) + if obj_array_only: if is_obj_array(field): ls = field.shape @@ -170,9 +180,8 @@ def with_object_array_or_scalar(f, field, obj_array_only=False): else: ls = log_shape(field) if ls != (): - from pytools import indices_in_shape result = np.zeros(ls, dtype=object) - for i in indices_in_shape(ls): + for i in np.ndindex(ls): result[i] = f(field[i]) return result else: @@ -183,6 +192,9 @@ as_oarray_func = decorator(with_object_array_or_scalar) def with_object_array_or_scalar_n_args(f, *args): + warn("with_object_array_or_scalar is deprecated and will go away in 2022, " + "use oarray_vectorize_n_args", DeprecationWarning, stacklevel=2) + oarray_arg_indices = [] for i, arg in enumerate(args): if is_obj_array(arg): @@ -195,11 +207,10 @@ def with_object_array_or_scalar_n_args(f, *args): ls = log_shape(args[leading_oa_index]) if ls != (): - from pytools import indices_in_shape result = np.zeros(ls, dtype=object) new_args = list(args) - for i in indices_in_shape(ls): + for i in np.ndindex(ls): for arg_i in oarray_arg_indices: new_args[arg_i] = args[arg_i][i] @@ -211,11 +222,7 @@ def with_object_array_or_scalar_n_args(f, *args): as_oarray_func_n_args = decorator(with_object_array_or_scalar_n_args) - -def cast_field(field, dtype): - return with_object_array_or_scalar( - lambda f: f.astype(dtype), field) - +# }}} def oarray_real(ary): return with_object_array_or_scalar(lambda x: x.real, ary) @@ -231,3 +238,4 @@ def oarray_real_copy(ary): def oarray_imag_copy(ary): return with_object_array_or_scalar(lambda x: x.imag.copy(), ary) +# vim: foldmethod=marker -- GitLab From fe232c97d67b92b73499b0d5588c9e486054e19e Mon Sep 17 00:00:00 2001 From: "[6~" Date: Fri, 5 Jun 2020 10:58:23 -0500 Subject: [PATCH 03/11] Move oarray_{real,imag} above deprecated junk --- pytools/obj_array.py | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/pytools/obj_array.py b/pytools/obj_array.py index aea02da..0b3886a 100644 --- a/pytools/obj_array.py +++ b/pytools/obj_array.py @@ -52,6 +52,25 @@ Mapping else: return result +# {{{ workarounds for https://github.com/numpy/numpy/issues/1740 + +def oarray_real(ary): + return rec_oarray_vectorize(lambda x: x.real, ary) + + +def oarray_imag(ary): + return rec_oarray_vectorize(lambda x: x.imag, ary) + + +def oarray_real_copy(ary): + return rec_oarray_vectorize(lambda x: x.real.copy(), ary) + + +def oarray_imag_copy(ary): + return rec_oarray_vectorize(lambda x: x.imag.copy(), ary) + +# }}} + # {{{ deprecated junk @@ -224,18 +243,4 @@ as_oarray_func_n_args = decorator(with_object_array_or_scalar_n_args) # }}} -def oarray_real(ary): - return with_object_array_or_scalar(lambda x: x.real, ary) - - -def oarray_imag(ary): - return with_object_array_or_scalar(lambda x: x.imag, ary) - - -def oarray_real_copy(ary): - return with_object_array_or_scalar(lambda x: x.real.copy(), ary) - - -def oarray_imag_copy(ary): - return with_object_array_or_scalar(lambda x: x.imag.copy(), ary) # vim: foldmethod=marker -- GitLab From 066121a66952f09d356af58e8f799e2b21b2a4db Mon Sep 17 00:00:00 2001 From: "[6~" Date: Fri, 5 Jun 2020 10:59:22 -0500 Subject: [PATCH 04/11] Add obj_array.{flat_obj_array,oarray_vectorize,oarray_vectorize_n_args} --- pytools/obj_array.py | 95 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/pytools/obj_array.py b/pytools/obj_array.py index 0b3886a..e3acd30 100644 --- a/pytools/obj_array.py +++ b/pytools/obj_array.py @@ -23,7 +23,9 @@ THE SOFTWARE. """ import numpy as np -from pytools import my_decorator as decorator, MovedFunctionDeprecationWrapper +from warnings import warn +from pytools import my_decorator as decorator + __doc__ = """ Handling :mod:`numpy` Object Arrays @@ -38,19 +40,108 @@ Creation -------- .. autofunction:: make_obj_array +.. autofunction:: flat_obj_array Mapping ------- +.. autofunction:: oarray_vectorize +.. autofunction:: oarray_vectorize_n_args """ +def make_obj_array(res_list): + result = np.empty((len(res_list),), dtype=object) + result[:] = res_list + return result + + +def obj_array_to_hashable(f): + if isinstance(f, np.ndarray) and f.dtype.char == "O": + return tuple(f) else: - return 1 + return f + + +def flat_obj_array(*args): + res_list = [] + for arg in args: + if isinstance(arg, list): + res_list.extend(arg) + + # Only flatten genuine, non-subclassed object arrays. + elif type(arg) == np.ndarray: + res_list.extend(arg.flat) + + else: + res_list.append(arg) + return make_obj_array(res_list) + +def oarray_vectorize(f, ary): + """Apply the function *f* to all entries of the object array *ary*. + Return an object array of the same shape consisting of the return + values. + If *ary* is not an object array, return ``f(ary)``. + """ + + if isinstance(ary, np.ndarray) and ary.dtype.char == "O": + result = np.empty_like(ary) + for i in np.ndindex(ary.shape): + result[i] = f(ary[i]) + return result else: + return f(ary) + + +oarray_vectorized = decorator(oarray_vectorize) + + +def rec_oarray_vectorize(f, ary): + """Apply the function *f* to all entries of the object array *ary*. + Return an object array of the same shape consisting of the return + values. + If the elements of *ary* are further object arrays, recurse + until non-object-arrays are found and then apply *f* to those + entries. + If *ary* is not an object array, return ``f(ary)``. + """ + if isinstance(ary, np.ndarray) and ary.dtype.char == "O": + result = np.empty_like(ary) + for i in np.ndindex(ary.shape): + result[i] = rec_oarray_vectorize(f, ary[i]) return result + else: + return f(ary) + + +rec_oarray_vectorized = decorator(rec_oarray_vectorize) + + +def oarray_vectorize_n_args(f, *args): + oarray_arg_indices = [] + for i, arg in enumerate(args): + if isinstance(arg, np.ndarray) and arg.dtype.char == "O": + oarray_arg_indices.append(i) + + if not oarray_arg_indices: + return f(*args) + + leading_oa_index = oarray_arg_indices[0] + + template_ary = args[leading_oa_index] + result = np.empty_like(template_ary) + new_args = list(args) + for i in np.ndindex(template_ary.shape): + for arg_i in oarray_arg_indices: + new_args[arg_i] = args[arg_i][i] + result[i] = f(*new_args) + return result + + +oarray_vectorize_n_args = decorator(oarray_vectorize_n_args) + # {{{ workarounds for https://github.com/numpy/numpy/issues/1740 -- GitLab From df96f359e25a68c5749a6a2dc33fe223ccba4c5f Mon Sep 17 00:00:00 2001 From: "[6~" Date: Fri, 5 Jun 2020 17:27:48 -0500 Subject: [PATCH 05/11] Document obj_array.make_obj_array --- pytools/obj_array.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pytools/obj_array.py b/pytools/obj_array.py index e3acd30..7a1daf6 100644 --- a/pytools/obj_array.py +++ b/pytools/obj_array.py @@ -51,6 +51,32 @@ Mapping def make_obj_array(res_list): + """Create a one-dimensional object array from *res_list*. + This differs from ``numpy.array(res_list, dtype=object)`` + by whether it tries to determine its shape by descending + into nested array-like objects. Consider the following example: + + .. doctest:: + + >>> import numpy as np + >>> a = np.array([np.arange(5), np.arange(5)], dtype=object) + >>> a + array([[0, 1, 2, 3, 4], + [0, 1, 2, 3, 4]], dtype=object) + >>> a.shape + (2, 5) + >>> # meanwhile: + >>> from pytools.obj_array import make_obj_array + >>> b = make_obj_array([np.arange(5), np.arange(5)]) + >>> b + array([array([0, 1, 2, 3, 4]), array([0, 1, 2, 3, 4])], dtype=object) + >>> b.shape + (2,) + + In some settings (such as when the sub-arrays are large and/or + live on a GPU), the recursive behavior of :func:`numpy.array` + can be undesirable. + """ result = np.empty((len(res_list),), dtype=object) result[:] = res_list return result -- GitLab From 57c9749f93f88008c3d3881ac80d9e14e3bb65b5 Mon Sep 17 00:00:00 2001 From: "[6~" Date: Fri, 5 Jun 2020 17:28:57 -0500 Subject: [PATCH 06/11] Fix a few doctest failures --- pytools/__init__.py | 4 ++-- pytools/decorator.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pytools/__init__.py b/pytools/__init__.py index e5efcb2..77ba0ed 100644 --- a/pytools/__init__.py +++ b/pytools/__init__.py @@ -1335,8 +1335,8 @@ def get_read_from_map_from_permutation(original, permuted): .. doctest :: - >>> for p1 in generate_permutations(range(5)): - ... for p2 in generate_permutations(range(5)): + >>> for p1 in generate_permutations(list(range(5))): + ... for p2 in generate_permutations(list(range(5))): ... rfm = get_read_from_map_from_permutation(p1, p2) ... p2a = [p1[rfm[i]] for i in range(len(p1))] ... assert p2 == p2a diff --git a/pytools/decorator.py b/pytools/decorator.py index 1602965..2e66b2f 100644 --- a/pytools/decorator.py +++ b/pytools/decorator.py @@ -108,7 +108,7 @@ def decorator(caller, func=None): >>> @decorator ... def chatty(f, *args, **kw): - ... print "Calling %r" % f.__name__ + ... print("Calling %r" % f.__name__) ... return f(*args, **kw) >>> chatty.__name__ -- GitLab From a8d2dc769ca11ecde2a2fc4f25a560862fc68d6b Mon Sep 17 00:00:00 2001 From: "[6~" Date: Fri, 5 Jun 2020 17:41:07 -0500 Subject: [PATCH 07/11] Doctest/doc fixes for get_read_from_map_from_permutation,get_write_to_map_from_permutation --- pytools/__init__.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pytools/__init__.py b/pytools/__init__.py index 77ba0ed..39b3371 100644 --- a/pytools/__init__.py +++ b/pytools/__init__.py @@ -1326,12 +1326,12 @@ def enumerate_basic_directions(dimensions): # {{{ index mangling def get_read_from_map_from_permutation(original, permuted): - """With a permutation given by C{original} and C{permuted}, - generate a list C{rfm} of indices such that - C{permuted[i] == original[rfm[i]]}. + """With a permutation given by *original* and *permuted*, + generate a list *rfm* of indices such that + ``permuted[i] == original[rfm[i]]``. Requires that the permutation can be inferred from - C{original} and C{permuted}. + *original* and *permuted*. .. doctest :: @@ -1353,17 +1353,17 @@ def get_read_from_map_from_permutation(original, permuted): def get_write_to_map_from_permutation(original, permuted): - """With a permutation given by C{original} and C{permuted}, - generate a list C{wtm} of indices such that - C{permuted[wtm[i]] == original[i]}. + """With a permutation given by *original* and *permuted*, + generate a list *wtm* of indices such that + ``permuted[wtm[i]] == original[i]``. Requires that the permutation can be inferred from - C{original} and C{permuted}. + *original* and *permuted*. - .. doctest:: + .. doctest :: - >>> for p1 in generate_permutations(range(5)): - ... for p2 in generate_permutations(range(5)): + >>> for p1 in generate_permutations(list(range(5))): + ... for p2 in generate_permutations(list(range(5))): ... wtm = get_write_to_map_from_permutation(p1, p2) ... p2a = [0] * len(p2) ... for i, oi in enumerate(p1): -- GitLab From abefdbcf2c6e966a4d9a96dbb29a4af0391e5d22 Mon Sep 17 00:00:00 2001 From: "[6~" Date: Fri, 5 Jun 2020 17:56:43 -0500 Subject: [PATCH 08/11] obj_array: consistent naming --- pytools/obj_array.py | 77 ++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/pytools/obj_array.py b/pytools/obj_array.py index 7a1daf6..d32b94d 100644 --- a/pytools/obj_array.py +++ b/pytools/obj_array.py @@ -31,11 +31,6 @@ __doc__ = """ Handling :mod:`numpy` Object Arrays =================================== -.. autofunction:: oarray_real -.. autofunction:: oarray_imag -.. autofunction:: oarray_real_copy -.. autofunction:: oarray_imag_copy - Creation -------- @@ -45,8 +40,18 @@ Creation Mapping ------- -.. autofunction:: oarray_vectorize -.. autofunction:: oarray_vectorize_n_args +.. autofunction:: obj_array_vectorize +.. autofunction:: obj_array_vectorize_n_args + +Numpy workarounds +----------------- +These functions work around a `long-standing, annoying numpy issue +`__. + +.. autofunction:: obj_array_real +.. autofunction:: obj_array_imag +.. autofunction:: obj_array_real_copy +.. autofunction:: obj_array_imag_copy """ @@ -105,7 +110,7 @@ def flat_obj_array(*args): return make_obj_array(res_list) -def oarray_vectorize(f, ary): +def obj_array_vectorize(f, ary): """Apply the function *f* to all entries of the object array *ary*. Return an object array of the same shape consisting of the return values. @@ -121,10 +126,10 @@ def oarray_vectorize(f, ary): return f(ary) -oarray_vectorized = decorator(oarray_vectorize) +obj_array_vectorized = decorator(obj_array_vectorize) -def rec_oarray_vectorize(f, ary): +def rec_obj_array_vectorize(f, ary): """Apply the function *f* to all entries of the object array *ary*. Return an object array of the same shape consisting of the return values. @@ -136,16 +141,16 @@ def rec_oarray_vectorize(f, ary): if isinstance(ary, np.ndarray) and ary.dtype.char == "O": result = np.empty_like(ary) for i in np.ndindex(ary.shape): - result[i] = rec_oarray_vectorize(f, ary[i]) + result[i] = rec_obj_array_vectorize(f, ary[i]) return result else: return f(ary) -rec_oarray_vectorized = decorator(rec_oarray_vectorize) +rec_obj_array_vectorized = decorator(rec_obj_array_vectorize) -def oarray_vectorize_n_args(f, *args): +def obj_array_vectorize_n_args(f, *args): oarray_arg_indices = [] for i, arg in enumerate(args): if isinstance(arg, np.ndarray) and arg.dtype.char == "O": @@ -166,25 +171,25 @@ def oarray_vectorize_n_args(f, *args): return result -oarray_vectorize_n_args = decorator(oarray_vectorize_n_args) +obj_array_vectorize_n_args = decorator(obj_array_vectorize_n_args) # {{{ workarounds for https://github.com/numpy/numpy/issues/1740 -def oarray_real(ary): - return rec_oarray_vectorize(lambda x: x.real, ary) +def obj_array_real(ary): + return rec_obj_array_vectorize(lambda x: x.real, ary) -def oarray_imag(ary): - return rec_oarray_vectorize(lambda x: x.imag, ary) +def obj_array_imag(ary): + return rec_obj_array_vectorize(lambda x: x.imag, ary) -def oarray_real_copy(ary): - return rec_oarray_vectorize(lambda x: x.real.copy(), ary) +def obj_array_real_copy(ary): + return rec_obj_array_vectorize(lambda x: x.real.copy(), ary) -def oarray_imag_copy(ary): - return rec_oarray_vectorize(lambda x: x.imag.copy(), ary) +def obj_array_imag_copy(ary): + return rec_obj_array_vectorize(lambda x: x.imag.copy(), ary) # }}} @@ -306,7 +311,7 @@ def cast_field(field, dtype): def with_object_array_or_scalar(f, field, obj_array_only=False): warn("with_object_array_or_scalar is deprecated and will go away in 2022, " - "use oarray_vectorize", DeprecationWarning, stacklevel=2) + "use obj_array_vectorize", DeprecationWarning, stacklevel=2) if obj_array_only: if is_obj_array(field): @@ -329,7 +334,7 @@ as_oarray_func = decorator(with_object_array_or_scalar) def with_object_array_or_scalar_n_args(f, *args): warn("with_object_array_or_scalar is deprecated and will go away in 2022, " - "use oarray_vectorize_n_args", DeprecationWarning, stacklevel=2) + "use obj_array_vectorize_n_args", DeprecationWarning, stacklevel=2) oarray_arg_indices = [] for i, arg in enumerate(args): @@ -358,6 +363,30 @@ def with_object_array_or_scalar_n_args(f, *args): as_oarray_func_n_args = decorator(with_object_array_or_scalar_n_args) + +def oarray_real(ary): + warn("orarray_real is deprecated and will go away in 2022, " + "use obj_rarray_real", DeprecationWarning, stacklevel=2) + return obj_array_real(ary) + + +def oarray_imag(ary): + warn("orarray_imag is deprecated and will go away in 2022, " + "use obj_rarray_imag", DeprecationWarning, stacklevel=2) + return obj_array_imag(ary) + + +def oarray_real_copy(ary): + warn("orarray_real_copy is deprecated and will go away in 2022, " + "use obj_rarray_real_copy", DeprecationWarning, stacklevel=2) + return obj_array_real_copy(ary) + + +def oarray_imag_copy(ary): + warn("orarray_imag_copy is deprecated and will go away in 2022, " + "use obj_rarray_imag_copy", DeprecationWarning, stacklevel=2) + return obj_array_imag_copy(ary) + # }}} # vim: foldmethod=marker -- GitLab From 244d9284bd590d7bc25aa194dea4b24152a42909 Mon Sep 17 00:00:00 2001 From: "[6~" Date: Fri, 5 Jun 2020 18:08:56 -0500 Subject: [PATCH 09/11] Document obj_array_vectorize_n_args --- pytools/obj_array.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/pytools/obj_array.py b/pytools/obj_array.py index d32b94d..8284042 100644 --- a/pytools/obj_array.py +++ b/pytools/obj_array.py @@ -115,6 +115,11 @@ def obj_array_vectorize(f, ary): Return an object array of the same shape consisting of the return values. If *ary* is not an object array, return ``f(ary)``. + + .. note :: + + This function exists because :func:`numpy.vectorize` suffers from the same + issue described under :func:`make_obj_array`. """ if isinstance(ary, np.ndarray) and ary.dtype.char == "O": @@ -137,6 +142,11 @@ def rec_obj_array_vectorize(f, ary): until non-object-arrays are found and then apply *f* to those entries. If *ary* is not an object array, return ``f(ary)``. + + .. note :: + + This function exists because :func:`numpy.vectorize` suffers from the same + issue described under :func:`make_obj_array`. """ if isinstance(ary, np.ndarray) and ary.dtype.char == "O": result = np.empty_like(ary) @@ -151,6 +161,21 @@ rec_obj_array_vectorized = decorator(rec_obj_array_vectorize) def obj_array_vectorize_n_args(f, *args): + """Apply the function *f* elementwise to all entries of any + object arrays in *args*. All such ojbect arrays are expected + to have the same shape (but this is not checked). + Equivalent to an appropriately-looped execution of:: + + result[idx] = f(obj_array_arg1[idx], arg2, obj_array_arg3[idx]) + + Return an object array of the same shape as the arguments consisting of the + return values of *f*. + + .. note :: + + This function exists because :func:`numpy.vectorize` suffers from the same + issue described under :func:`make_obj_array`. + """ oarray_arg_indices = [] for i, arg in enumerate(args): if isinstance(arg, np.ndarray) and arg.dtype.char == "O": -- GitLab From 38c5f6f9a166cfaf9e089812cbd06fd83508b3b0 Mon Sep 17 00:00:00 2001 From: "[6~" Date: Fri, 5 Jun 2020 18:10:51 -0500 Subject: [PATCH 10/11] Extend is_obj_array's lease on life --- pytools/obj_array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytools/obj_array.py b/pytools/obj_array.py index 8284042..79656a9 100644 --- a/pytools/obj_array.py +++ b/pytools/obj_array.py @@ -222,7 +222,7 @@ def obj_array_imag_copy(ary): # {{{ deprecated junk def is_obj_array(val): - warn("is_obj_array is deprecated and will go away in 2021, " + warn("is_obj_array is deprecated and will go away in 2022, " "just inline the check.", DeprecationWarning, stacklevel=2) try: -- GitLab From 9661bd849fa1f12f43a91bab825e467a9187d3fc Mon Sep 17 00:00:00 2001 From: "[6~" Date: Fri, 5 Jun 2020 21:46:05 -0500 Subject: [PATCH 11/11] Document flat_obj_array --- pytools/obj_array.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pytools/obj_array.py b/pytools/obj_array.py index 79656a9..1d43b4a 100644 --- a/pytools/obj_array.py +++ b/pytools/obj_array.py @@ -95,6 +95,14 @@ def obj_array_to_hashable(f): def flat_obj_array(*args): + """Return a one-dimensional flattened object array consisting of + elements obtained by 'flattening' *args* as follows: + + - The first axis of any non-subclassed object arrays will be flattened + into the result. + - Instances of :class:`list` will be flattened into the result. + - Any other type will appear in the list as-is. + """ res_list = [] for arg in args: if isinstance(arg, list): -- GitLab