Repository: numpy/numpy
File: numpy/_core/tests/test_ufunc.py (Python)

Code before:
        out = np.full_like(a, 0)
        np.less(a, b, where=where, out=out)
        b_where = np.broadcast_to(b, a.shape)[where]
        assert_array_equal((a[where] < b_where), out[where].astype(bool))
        assert not out[~where].any()  # outside mask, out remains all 0

    @staticmethod
    def identityless_reduce_arrs():
        yield np.empty((2, 3, 4), order='C')
        yield np.empty((2, 3, 4), order='F')
        # Mixed order (reduce order differs outer)
        yield np.empty((2, 4, 3), order='C').swapaxes(1, 2)
        # Reversed order
        yield np.empty((2, 3, 4), order='C')[::-1, ::-1, ::-1]
        # Not contiguous
        yield np.empty((3, 5, 4), order='C').swapaxes(1, 2)[1:, 1:, 1:]
        # Not contiguous and not aligned
        a = np.empty((3 * 4 * 5 * 8 + 1,), dtype='i1')
        a = a[1:].view(dtype='f8')
        a.shape = (3, 4, 5)
        a = a[1:, 1:, 1:]
        yield a

    @pytest.mark.parametrize("a", identityless_reduce_arrs())
    @pytest.mark.parametrize("pos", [(1, 0, 0), (0, 1, 0), (0, 0, 1)])
    @pytest.mark.thread_unsafe(reason="races to modify parameters")
    def test_identityless_reduction(self, a, pos):
        # np.minimum.reduce is an identityless reduction
        a[...] = 1
        a[pos] = 0

        for axis in [None, (0, 1), (0, 2), (1, 2), 0, 1, 2, ()]:
            if axis is None:
                axes = np.array([], dtype=np.intp)
            else:
                axes = np.delete(np.arange(a.ndim), axis)

            expected_pos = tuple(np.array(pos)[axes])
            expected = np.ones(np.array(a.shape)[axes])
            expected[expected_pos] = 0

            res = np.minimum.reduce(a, axis=axis)
            assert_equal(res, expected, strict=True)

            res = np.full_like(res, np.nan)
            np.minimum.reduce(a, axis=axis, out=res)
            assert_equal(res, expected, strict=True)

    @requires_memory(6 * 1024**3)
    @pytest.mark.skipif(sys.maxsize < 2**32,
            reason="test array too large for 32bit platform")

Review comment (suggestion):
Maybe we can copy `a` into a new object before modifying/using it here? The test doesn't seem to depend on the object itself. Ditto for the other "races to modify parameters" test (not sure if that's also relevant there).

Code after:
        assert_array_equal((a[where] < b_where), out[where].astype(bool))
        assert not out[~where].any()  # outside mask, out remains all 0

    def test_where_warns(self):
        a = np.arange(7)
        mask = a % 2 == 0
        with pytest.warns(UserWarning, match="'where' used without 'out'"):
            result1 = np.add(a, a, where=mask)
        # Does not warn
        result2 = np.add(a, a, where=mask, out=None)
        # Sanity check
        assert np.all(result1[::2] == [0, 4, 8, 12])
        assert np.all(result2[::2] == [0, 4, 8, 12])

    @staticmethod
    def identityless_reduce_arrs():
        yield np.empty((2, 3, 4), order='C')
        yield np.empty((2, 3, 4), order='F')
        # Mixed order (reduce order differs outer)
        yield np.empty((2, 4, 3), order='C').swapaxes(1, 2)
        # Reversed order
        yield np.empty((2, 3, 4), order='C')[::-1, ::-1, ::-1]
        # Not contiguous
        yield np.empty((3, 5, 4), order='C').swapaxes(1, 2)[1:, 1:, 1:]
        # Not contiguous and not aligned
        a = np.empty((3 * 4 * 5 * 8 + 1,), dtype='i1')
        a = a[1:].view(dtype='f8')
        a.shape = (3, 4, 5)
        a = a[1:, 1:, 1:]
        yield a

    @pytest.mark.parametrize("arrs", identityless_reduce_arrs())
    @pytest.mark.parametrize("pos", [(1, 0, 0), (0, 1, 0), (0, 0, 1)])
    def test_identityless_reduction(self, arrs, pos):
        # np.minimum.reduce is an identityless reduction
        a = arrs.copy()
        a[...] = 1
        a[pos] = 0

        for axis in [None, (0, 1), (0, 2), (1, 2), 0, 1, 2, ()]:
            if axis is None:
                axes = np.array([], dtype=np.intp)
            else:
                axes = np.delete(np.arange(a.ndim), axis)

            expected_pos = tuple(np.array(pos)[axes])
            expected = np.ones(np.array(a.shape)[axes])
            expected[expected_pos] = 0

            res = np.minimum.reduce(a, axis=axis)
            assert_equal(res, expected, strict=True)