diff options
Diffstat (limited to 'numpy')
| -rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 3 | ||||
| -rw-r--r-- | numpy/core/tests/test_multiarray.py | 4 | ||||
| -rw-r--r-- | numpy/core/tests/test_ufunc.py | 11 | ||||
| -rw-r--r-- | numpy/lib/function_base.py | 65 | ||||
| -rw-r--r-- | numpy/lib/tests/test_function_base.py | 55 |
5 files changed, 27 insertions, 111 deletions
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index a5e8f4cbe..d4aced05f 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -5935,6 +5935,9 @@ trivial_at_loop(PyArrayMethodObject *ufuncimpl, NPY_ARRAYMETHOD_FLAGS flags, res = ufuncimpl->contiguous_indexed_loop( context, args, inner_size, steps, NULL); + if (args[2] != NULL) { + args[2] += (*inner_size) * steps[2]; + } } while (res == 0 && iter->outer_next(iter->outer)); if (res == 0 && !(flags & NPY_METH_NO_FLOATINGPOINT_ERRORS)) { diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 77f651659..3f3c1de8e 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -7225,11 +7225,11 @@ class TestMatmulInplace: @pytest.mark.parametrize("a_shape,b_shape", SHAPES.values(), ids=SHAPES) def test_shapes(self, a_shape: tuple[int, ...], b_shape: tuple[int, ...]): - a_size = np.product(a_shape) + a_size = np.prod(a_shape) a = np.arange(a_size).reshape(a_shape).astype(np.float64) a_id = id(a) - b_size = np.product(b_shape) + b_size = np.prod(b_shape) b = np.arange(b_size).reshape(b_shape) ref = a @ b diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index 498a654c8..04add9fa7 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -2054,6 +2054,17 @@ class TestUfunc: # If it is [-1, -1, -1, -100, 0] then the regular strided loop was used assert np.all(arr == [-1, -1, -1, -200, -1]) + def test_ufunc_at_large(self): + # issue gh-23457 + indices = np.zeros(8195, dtype=np.int16) + b = np.zeros(8195, dtype=float) + b[0] = 10 + b[1] = 5 + b[8192:] = 100 + a = np.zeros(1, dtype=float) + np.add.at(a, indices, b) + assert a[0] == b.sum() + def test_cast_index_fastpath(self): arr = np.zeros(10) values = np.ones(100000) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 5e1309dfd..f0f374f97 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2117,10 +2117,10 @@ def _create_arrays(broadcast_shape, dim_sizes, list_of_core_dims, dtypes, @set_module('numpy') class vectorize: """ - vectorize(pyfunc=np._NoValue, otypes=None, doc=None, excluded=None, - cache=False, signature=None) + vectorize(pyfunc, otypes=None, doc=None, excluded=None, cache=False, + signature=None) - Returns an object that acts like pyfunc, but takes arrays as input. + Generalized function class. Define a vectorized function which takes a nested sequence of objects or numpy arrays as inputs and returns a single numpy array or a tuple of numpy @@ -2134,9 +2134,8 @@ class vectorize: Parameters ---------- - pyfunc : callable, optional + pyfunc : callable A python function or method. - Can be omitted to produce a decorator with keyword arguments. otypes : str or list of dtypes, optional The output data type. It must be specified as either a string of typecode characters or a list of data type specifiers. There should @@ -2168,9 +2167,8 @@ class vectorize: Returns ------- - out : callable - A vectorized function if ``pyfunc`` was provided, - a decorator otherwise. + vectorized : callable + Vectorized function. See Also -------- @@ -2267,44 +2265,18 @@ class vectorize: [0., 0., 1., 2., 1., 0.], [0., 0., 0., 1., 2., 1.]]) - Decorator syntax is supported. The decorator can be called as - a function to provide keyword arguments. - >>>@np.vectorize - ...def identity(x): - ... return x - ... - >>>identity([0, 1, 2]) - array([0, 1, 2]) - >>>@np.vectorize(otypes=[float]) - ...def as_float(x): - ... return x - ... - >>>as_float([0, 1, 2]) - array([0., 1., 2.]) """ - def __init__(self, pyfunc=np._NoValue, otypes=None, doc=None, - excluded=None, cache=False, signature=None): - - if (pyfunc != np._NoValue) and (not callable(pyfunc)): - #Splitting the error message to keep - #the length below 79 characters. - part1 = "When used as a decorator, " - part2 = "only accepts keyword arguments." - raise TypeError(part1 + part2) - + def __init__(self, pyfunc, otypes=None, doc=None, excluded=None, + cache=False, signature=None): self.pyfunc = pyfunc self.cache = cache self.signature = signature - if pyfunc != np._NoValue: - self.__name__ = pyfunc.__name__ - self._ufunc = {} # Caching to improve default performance - self._doc = None - self.__doc__ = doc + if doc is None: self.__doc__ = pyfunc.__doc__ else: - self._doc = doc + self.__doc__ = doc if isinstance(otypes, str): for char in otypes: @@ -2326,15 +2298,7 @@ class vectorize: else: self._in_and_out_core_dims = None - def _init_stage_2(self, pyfunc, *args, **kwargs): - self.__name__ = pyfunc.__name__ - self.pyfunc = pyfunc - if self._doc is None: - self.__doc__ = pyfunc.__doc__ - else: - self.__doc__ = self._doc - - def _call_as_normal(self, *args, **kwargs): + def __call__(self, *args, **kwargs): """ Return arrays with the results of `pyfunc` broadcast (vectorized) over `args` and `kwargs` not in `excluded`. @@ -2364,13 +2328,6 @@ class vectorize: return self._vectorize_call(func=func, args=vargs) - def __call__(self, *args, **kwargs): - if self.pyfunc is np._NoValue: - self._init_stage_2(*args, **kwargs) - return self - - return self._call_as_normal(*args, **kwargs) - def _get_ufunc_and_otypes(self, func, args): """Return (ufunc, otypes).""" # frompyfunc will fail if args is empty diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 97ca13bfb..3ec46735c 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -1787,61 +1787,6 @@ class TestVectorize: assert_equal(type(r), subclass) assert_equal(r, m * v) - def test_name(self): - #See gh-23021 - @np.vectorize - def f2(a, b): - return a + b - - assert f2.__name__ == 'f2' - - def test_decorator(self): - @vectorize - def addsubtract(a, b): - if a > b: - return a - b - else: - return a + b - - r = addsubtract([0, 3, 6, 9], [1, 3, 5, 7]) - assert_array_equal(r, [1, 6, 1, 2]) - - def test_docstring(self): - @vectorize - def f(x): - """Docstring""" - return x - - assert f.__doc__ == "Docstring" - - def test_signature_otypes_decorator(self): - @vectorize(signature='(n)->(n)', otypes=['float64']) - def f(x): - return x - - r = f([1, 2, 3]) - assert_equal(r.dtype, np.dtype('float64')) - assert_array_equal(r, [1, 2, 3]) - assert f.__name__ == 'f' - - def test_bad_input(self): - with assert_raises(TypeError): - A = np.vectorize(pyfunc = 3) - - def test_no_keywords(self): - with assert_raises(TypeError): - @np.vectorize("string") - def foo(): - return "bar" - - def test_positional_regression_9477(self): - # This supplies the first keyword argument as a positional, - # to ensure that they are still properly forwarded after the - # enhancement for #9477 - f = vectorize((lambda x: x), ['float64']) - r = f([2]) - assert_equal(r.dtype, np.dtype('float64')) - class TestLeaks: class A: |
