diff options
author | Sebastian Berg <sebastian@sipsolutions.net> | 2022-01-04 14:53:23 -0800 |
---|---|---|
committer | Sebastian Berg <sebastian@sipsolutions.net> | 2022-01-05 11:53:45 -0600 |
commit | 975a94623b1c84979ef9bfe620745299f420315a (patch) | |
tree | eec32f91213579f7d68c95728e1a62de30cc8ae2 /numpy | |
parent | 84fd36cc94436bb842aa33c14f7e973d6e00c8b2 (diff) | |
download | numpy-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.c | 8 | ||||
-rw-r--r-- | numpy/core/tests/test_ufunc.py | 11 |
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. |