summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2022-01-04 14:53:23 -0800
committerSebastian Berg <sebastian@sipsolutions.net>2022-01-05 11:53:45 -0600
commit975a94623b1c84979ef9bfe620745299f420315a (patch)
treeeec32f91213579f7d68c95728e1a62de30cc8ae2 /numpy
parent84fd36cc94436bb842aa33c14f7e973d6e00c8b2 (diff)
downloadnumpy-975a94623b1c84979ef9bfe620745299f420315a.tar.gz
BUG: Relax dtype identity check in reductions
In some cases, e.g. ensure-native-byte-order will return not the default, but a copy of the descriptor. This (and maybe metadata) makes it somewhat annoying to ensure exact identity between descriptors for reduce "operands" as returned by the resolve-descirptors method of the ArrayMethod. To avoid this problem, we check for no-casting (which implies viewable with `offset == 0`) rather than strict identity. Unfortunately, this means that descriptor resolution must be slightly more careful, but in general this should all be perfectly well defined. Closes gh-20699
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/umath/ufunc_object.c8
-rw-r--r--numpy/core/tests/test_ufunc.py11
2 files changed, 17 insertions, 2 deletions
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index 52b354353..83e18a363 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -2764,9 +2764,13 @@ reducelike_promote_and_resolve(PyUFuncObject *ufunc,
* The first operand and output should be the same array, so they should
* be identical. The second argument can be different for reductions,
* but is checked to be identical for accumulate and reduceat.
+ * Ideally, the type-resolver ensures that all are identical, but we do
+ * not enforce this here strictly. Otherwise correct handling of
+ * byte-order changes (or metadata) requires a lot of care; see gh-20699.
*/
- if (out_descrs[0] != out_descrs[2] || (
- enforce_uniform_args && out_descrs[0] != out_descrs[1])) {
+ if (!PyArray_EquivTypes(out_descrs[0], out_descrs[2]) || (
+ enforce_uniform_args && !PyArray_EquivTypes(
+ out_descrs[0], out_descrs[1]))) {
PyErr_Format(PyExc_TypeError,
"the resolved dtypes are not compatible with %s.%s. "
"Resolved (%R, %R, %R)",
diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py
index 76e4cdcfd..9a9d46da0 100644
--- a/numpy/core/tests/test_ufunc.py
+++ b/numpy/core/tests/test_ufunc.py
@@ -2148,6 +2148,17 @@ class TestUfunc:
# It would be safe, but not equiv casting:
ufunc(a, c, out=out, casting="equiv")
+ def test_reducelike_byteorder_resolution(self):
+ # See gh-20699, byte-order changes need some extra care in the type
+ # resolution to make the following succeed:
+ arr_be = np.arange(10, dtype=">i8")
+ arr_le = np.arange(10, dtype="<i8")
+
+ assert np.add.reduce(arr_be) == np.add.reduce(arr_le)
+ assert_array_equal(np.add.accumulate(arr_be), np.add.accumulate(arr_le))
+ assert_array_equal(
+ np.add.reduceat(arr_be, [1]), np.add.reduceat(arr_le, [1]))
+
def test_reducelike_out_promotes(self):
# Check that the out argument to reductions is considered for
# promotion. See also gh-20455.