From c31557cdc74e2d90b7fda410bb6e47ce05824b89 Mon Sep 17 00:00:00 2001 From: vtavana <120411540+vtavana@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:18:31 -0600 Subject: [PATCH] in place divide and floor_divide (#1587) * in place divide and floor_divide * address comments * add more tests for floor_divide * fix format --- tests/test_mathematical.py | 260 +++++++++++++++++++++++++++++++------ 1 file changed, 222 insertions(+), 38 deletions(-) diff --git a/tests/test_mathematical.py b/tests/test_mathematical.py index 63d5172c08e..89a09a7dc29 100644 --- a/tests/test_mathematical.py +++ b/tests/test_mathematical.py @@ -1070,9 +1070,9 @@ def test_invalid_out(self, out): assert_raises(TypeError, numpy.add, a.asnumpy(), 2, out) -class TestHypot: - @pytest.mark.parametrize("dtype", get_float_dtypes()) - def test_hypot(self, dtype): +class TestDivide: + @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) + def test_divide(self, dtype): array1_data = numpy.arange(10) array2_data = numpy.arange(5, 15) out = numpy.empty(10, dtype=dtype) @@ -1081,55 +1081,169 @@ def test_hypot(self, dtype): dp_array1 = dpnp.array(array1_data, dtype=dtype) dp_array2 = dpnp.array(array2_data, dtype=dtype) dp_out = dpnp.array(out, dtype=dtype) - result = dpnp.hypot(dp_array1, dp_array2, out=dp_out) + result = dpnp.divide(dp_array1, dp_array2, out=dp_out) # original np_array1 = numpy.array(array1_data, dtype=dtype) np_array2 = numpy.array(array2_data, dtype=dtype) - expected = numpy.hypot(np_array1, np_array2, out=out) + expected = numpy.divide(np_array1, np_array2, out=out) - assert_allclose(expected, result) - assert_allclose(out, dp_out) + assert_dtype_allclose(result, expected) + assert_dtype_allclose(dp_out, out) - @pytest.mark.parametrize("dtype", get_float_dtypes()) + @pytest.mark.usefixtures("suppress_divide_invalid_numpy_warnings") + @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) def test_out_dtypes(self, dtype): size = 10 np_array1 = numpy.arange(size, 2 * size, dtype=dtype) np_array2 = numpy.arange(size, dtype=dtype) - np_out = numpy.empty(size, dtype=numpy.float32) - expected = numpy.hypot(np_array1, np_array2, out=np_out) + np_out = numpy.empty(size, dtype=numpy.complex64) + expected = numpy.divide(np_array1, np_array2, out=np_out) dp_array1 = dpnp.arange(size, 2 * size, dtype=dtype) dp_array2 = dpnp.arange(size, dtype=dtype) - dp_out = dpnp.empty(size, dtype=dpnp.float32) - if dtype != dpnp.float32: + dp_out = dpnp.empty(size, dtype=dpnp.complex64) + if dtype != dpnp.complex64: # dtype of out mismatches types of input arrays with pytest.raises(TypeError): - dpnp.hypot(dp_array1, dp_array2, out=dp_out) + dpnp.divide(dp_array1, dp_array2, out=dp_out) # allocate new out with expected type dp_out = dpnp.empty(size, dtype=dtype) - result = dpnp.hypot(dp_array1, dp_array2, out=dp_out) + result = dpnp.divide(dp_array1, dp_array2, out=dp_out) + assert_dtype_allclose(result, expected) - tol = numpy.finfo(numpy.float32).resolution - assert_allclose(expected, result, rtol=tol, atol=tol) + @pytest.mark.usefixtures("suppress_divide_invalid_numpy_warnings") + @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) + def test_out_overlap(self, dtype): + size = 15 + # DPNP + dp_a = dpnp.arange(2 * size, dtype=dtype) + dpnp.divide(dp_a[size::], dp_a[::2], out=dp_a[:size:]) - @pytest.mark.parametrize("dtype", get_float_dtypes()) + # original + np_a = numpy.arange(2 * size, dtype=dtype) + numpy.divide(np_a[size::], np_a[::2], out=np_a[:size:]) + + assert_dtype_allclose(dp_a, np_a) + + @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) + def test_inplace_strided_out(self, dtype): + size = 21 + + np_a = numpy.arange(size, dtype=dtype) + np_a[::3] /= 4 + + dp_a = dpnp.arange(size, dtype=dtype) + dp_a[::3] /= 4 + + assert_allclose(dp_a, np_a) + + @pytest.mark.parametrize( + "shape", [(0,), (15,), (2, 2)], ids=["(0,)", "(15, )", "(2,2)"] + ) + def test_invalid_shape(self, shape): + dp_array1 = dpnp.arange(10) + dp_array2 = dpnp.arange(5, 15) + dp_out = dpnp.empty(shape) + + with pytest.raises(ValueError): + dpnp.divide(dp_array1, dp_array2, out=dp_out) + + @pytest.mark.parametrize( + "out", + [4, (), [], (3, 7), [2, 4]], + ids=["4", "()", "[]", "(3, 7)", "[2, 4]"], + ) + def test_invalid_out(self, out): + a = dpnp.arange(10) + + assert_raises(TypeError, dpnp.divide, a, 2, out) + assert_raises(TypeError, numpy.divide, a.asnumpy(), 2, out) + + +class TestFloorDivide: + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) + ) + def test_floor_divide(self, dtype): + array1_data = numpy.arange(10) + array2_data = numpy.arange(5, 15) + out = numpy.empty(10, dtype=dtype) + + # DPNP + dp_array1 = dpnp.array(array1_data, dtype=dtype) + dp_array2 = dpnp.array(array2_data, dtype=dtype) + dp_out = dpnp.array(out, dtype=dtype) + result = dpnp.floor_divide(dp_array1, dp_array2, out=dp_out) + + # original + np_array1 = numpy.array(array1_data, dtype=dtype) + np_array2 = numpy.array(array2_data, dtype=dtype) + expected = numpy.floor_divide(np_array1, np_array2, out=out) + + assert_allclose(result, expected) + assert_allclose(dp_out, out) + + @pytest.mark.usefixtures("suppress_divide_invalid_numpy_warnings") + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) + ) + def test_out_dtypes(self, dtype): + size = 10 + + np_array1 = numpy.arange(size, 2 * size, dtype=dtype) + np_array2 = numpy.arange(size, dtype=dtype) + np_out = numpy.empty(size, dtype=numpy.complex64) + expected = numpy.floor_divide(np_array1, np_array2, out=np_out) + + dp_array1 = dpnp.arange(size, 2 * size, dtype=dtype) + dp_array2 = dpnp.arange(size, dtype=dtype) + + dp_out = dpnp.empty(size, dtype=dpnp.complex64) + if dtype != dpnp.complex64: + # dtype of out mismatches types of input arrays + with pytest.raises(TypeError): + dpnp.floor_divide(dp_array1, dp_array2, out=dp_out) + + # allocate new out with expected type + dp_out = dpnp.empty(size, dtype=dtype) + + result = dpnp.floor_divide(dp_array1, dp_array2, out=dp_out) + assert_allclose(result, expected) + + @pytest.mark.usefixtures("suppress_divide_invalid_numpy_warnings") + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) + ) def test_out_overlap(self, dtype): size = 15 # DPNP dp_a = dpnp.arange(2 * size, dtype=dtype) - dpnp.hypot(dp_a[size::], dp_a[::2], out=dp_a[:size:]) + dpnp.floor_divide(dp_a[size::], dp_a[::2], out=dp_a[:size:]) # original np_a = numpy.arange(2 * size, dtype=dtype) - numpy.hypot(np_a[size::], np_a[::2], out=np_a[:size:]) + numpy.floor_divide(np_a[size::], np_a[::2], out=np_a[:size:]) - tol = numpy.finfo(numpy.float32).resolution - assert_allclose(np_a, dp_a, rtol=tol, atol=tol) + assert_allclose(dp_a, np_a) + + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) + ) + def test_inplace_strided_out(self, dtype): + size = 21 + + np_a = numpy.arange(size, dtype=dtype) + np_a[::3] //= 4 + + dp_a = dpnp.arange(size, dtype=dtype) + dp_a[::3] //= 4 + + assert_allclose(dp_a, np_a) @pytest.mark.parametrize( "shape", [(0,), (15,), (2, 2)], ids=["(0,)", "(15, )", "(2,2)"] @@ -1140,7 +1254,7 @@ def test_invalid_shape(self, shape): dp_out = dpnp.empty(shape) with pytest.raises(ValueError): - dpnp.hypot(dp_array1, dp_array2, out=dp_out) + dpnp.floor_divide(dp_array1, dp_array2, out=dp_out) @pytest.mark.parametrize( "out", @@ -1150,8 +1264,8 @@ def test_invalid_shape(self, shape): def test_invalid_out(self, out): a = dpnp.arange(10) - assert_raises(TypeError, dpnp.hypot, a, 2, out) - assert_raises(TypeError, numpy.hypot, a.asnumpy(), 2, out) + assert_raises(TypeError, dpnp.floor_divide, a, 2, out) + assert_raises(TypeError, numpy.floor_divide, a.asnumpy(), 2, out) class TestFmax: @@ -1316,6 +1430,90 @@ def test_invalid_out(self, out): assert_raises(TypeError, numpy.fmin, a.asnumpy(), 2, out) +class TestHypot: + @pytest.mark.parametrize("dtype", get_float_dtypes()) + def test_hypot(self, dtype): + array1_data = numpy.arange(10) + array2_data = numpy.arange(5, 15) + out = numpy.empty(10, dtype=dtype) + + # DPNP + dp_array1 = dpnp.array(array1_data, dtype=dtype) + dp_array2 = dpnp.array(array2_data, dtype=dtype) + dp_out = dpnp.array(out, dtype=dtype) + result = dpnp.hypot(dp_array1, dp_array2, out=dp_out) + + # original + np_array1 = numpy.array(array1_data, dtype=dtype) + np_array2 = numpy.array(array2_data, dtype=dtype) + expected = numpy.hypot(np_array1, np_array2, out=out) + + assert_allclose(expected, result) + assert_allclose(out, dp_out) + + @pytest.mark.parametrize("dtype", get_float_dtypes()) + def test_out_dtypes(self, dtype): + size = 10 + + np_array1 = numpy.arange(size, 2 * size, dtype=dtype) + np_array2 = numpy.arange(size, dtype=dtype) + np_out = numpy.empty(size, dtype=numpy.float32) + expected = numpy.hypot(np_array1, np_array2, out=np_out) + + dp_array1 = dpnp.arange(size, 2 * size, dtype=dtype) + dp_array2 = dpnp.arange(size, dtype=dtype) + + dp_out = dpnp.empty(size, dtype=dpnp.float32) + if dtype != dpnp.float32: + # dtype of out mismatches types of input arrays + with pytest.raises(TypeError): + dpnp.hypot(dp_array1, dp_array2, out=dp_out) + + # allocate new out with expected type + dp_out = dpnp.empty(size, dtype=dtype) + + result = dpnp.hypot(dp_array1, dp_array2, out=dp_out) + + tol = numpy.finfo(numpy.float32).resolution + assert_allclose(expected, result, rtol=tol, atol=tol) + + @pytest.mark.parametrize("dtype", get_float_dtypes()) + def test_out_overlap(self, dtype): + size = 15 + # DPNP + dp_a = dpnp.arange(2 * size, dtype=dtype) + dpnp.hypot(dp_a[size::], dp_a[::2], out=dp_a[:size:]) + + # original + np_a = numpy.arange(2 * size, dtype=dtype) + numpy.hypot(np_a[size::], np_a[::2], out=np_a[:size:]) + + tol = numpy.finfo(numpy.float32).resolution + assert_allclose(np_a, dp_a, rtol=tol, atol=tol) + + @pytest.mark.parametrize( + "shape", [(0,), (15,), (2, 2)], ids=["(0,)", "(15, )", "(2,2)"] + ) + def test_invalid_shape(self, shape): + dp_array1 = dpnp.arange(10) + dp_array2 = dpnp.arange(5, 15) + dp_out = dpnp.empty(shape) + + with pytest.raises(ValueError): + dpnp.hypot(dp_array1, dp_array2, out=dp_out) + + @pytest.mark.parametrize( + "out", + [4, (), [], (3, 7), [2, 4]], + ids=["4", "()", "[]", "(3, 7)", "[2, 4]"], + ) + def test_invalid_out(self, out): + a = dpnp.arange(10) + + assert_raises(TypeError, dpnp.hypot, a, 2, out) + assert_raises(TypeError, numpy.hypot, a.asnumpy(), 2, out) + + class TestMaximum: @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) def test_maximum(self, dtype): @@ -1846,17 +2044,3 @@ def test_inplace_remainder(dtype): dp_a %= 4 assert_allclose(dp_a, np_a) - - -@pytest.mark.parametrize( - "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) -) -def test_inplace_floor_divide(dtype): - size = 21 - np_a = numpy.arange(size, dtype=dtype) - dp_a = dpnp.arange(size, dtype=dtype) - - np_a //= 4 - dp_a //= 4 - - assert_allclose(dp_a, np_a)