summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/umath/ufunc_object.c3
-rw-r--r--numpy/core/tests/test_multiarray.py4
-rw-r--r--numpy/core/tests/test_ufunc.py11
-rw-r--r--numpy/lib/function_base.py65
-rw-r--r--numpy/lib/tests/test_function_base.py55
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: