From 8b38fd6b4960b06a1669182edd17dcb302d3e61c Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Fri, 15 Nov 2024 08:25:11 -0800 Subject: [PATCH 1/3] improve coverage dpnp_iface_manipulation.py --- dpnp/dpnp_iface_manipulation.py | 15 +- dpnp/tests/test_arraymanipulation.py | 345 +++++++++++++-------------- dpnp/tests/test_manipulation.py | 15 +- 3 files changed, 187 insertions(+), 188 deletions(-) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index a40bd295c5a0..bfba2704df62 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -3894,18 +3894,13 @@ def transpose(a, axes=None): """ - if isinstance(a, dpnp_array): - array = a - elif isinstance(a, dpt.usm_ndarray): - array = dpnp_array._create_from_usm_ndarray(a) - else: - raise TypeError( - f"An array must be any of supported type, but got {type(a)}" - ) + dpnp.check_supported_arrays_type(a) + if isinstance(a, dpt.usm_ndarray): + a = dpnp_array._create_from_usm_ndarray(a) if axes is None: - return array.transpose() - return array.transpose(*axes) + return a.transpose() + return a.transpose(*axes) permute_dims = transpose # permute_dims is an alias for transpose diff --git a/dpnp/tests/test_arraymanipulation.py b/dpnp/tests/test_arraymanipulation.py index 3e43ca2e627c..9af97c9b67c7 100644 --- a/dpnp/tests/test_arraymanipulation.py +++ b/dpnp/tests/test_arraymanipulation.py @@ -15,6 +15,35 @@ from .third_party.cupy import testing +class TestAsfarray: + @testing.with_requires("numpy<2.0") + @pytest.mark.parametrize("dtype", get_all_dtypes()) + @pytest.mark.parametrize( + "data", [[1, 2, 3], [1.0, 2.0, 3.0]], ids=["[1, 2, 3]", "[1., 2., 3.]"] + ) + def test_asfarray1(self, dtype, data): + expected = numpy.asfarray(data, dtype) + result = dpnp.asfarray(data, dtype) + assert_array_equal(result, expected) + + @testing.with_requires("numpy<2.0") + @pytest.mark.usefixtures("suppress_complex_warning") + @pytest.mark.parametrize("dtype", get_all_dtypes()) + @pytest.mark.parametrize("data", [[1.0, 2.0, 3.0]], ids=["[1., 2., 3.]"]) + @pytest.mark.parametrize("data_dtype", get_all_dtypes(no_none=True)) + def test_asfarray2(self, dtype, data, data_dtype): + expected = numpy.asfarray(numpy.array(data, dtype=data_dtype), dtype) + result = dpnp.asfarray(dpnp.array(data, dtype=data_dtype), dtype) + assert_array_equal(result, expected) + + # This is only for coverage with NumPy 2.0 and above + def test_asfarray_coverage(self): + expected = [1.0, 2.0, 3.0] + result = dpnp.asfarray([1, 2, 3]) + + assert_array_equal(result, expected) + + class TestAtleast1d: def test_0D_array(self): a = dpnp.array(1) @@ -132,6 +161,148 @@ def test_dpnp_dpt_array(self): assert_array_equal(res, desired) +class TestBroadcastArray: + def assert_broadcast_correct(self, input_shapes): + np_arrays = [numpy.zeros(s, dtype="i1") for s in input_shapes] + out_np_arrays = numpy.broadcast_arrays(*np_arrays) + dpnp_arrays = [dpnp.asarray(Xnp) for Xnp in np_arrays] + out_dpnp_arrays = dpnp.broadcast_arrays(*dpnp_arrays) + for Xnp, X in zip(out_np_arrays, out_dpnp_arrays): + assert_array_equal( + Xnp, dpnp.asnumpy(X), err_msg=f"Failed for {input_shapes})" + ) + + def assert_broadcast_arrays_raise(self, input_shapes): + dpnp_arrays = [dpnp.asarray(numpy.zeros(s)) for s in input_shapes] + pytest.raises(ValueError, dpnp.broadcast_arrays, *dpnp_arrays) + + def test_broadcast_arrays_same(self): + Xnp = numpy.arange(10) + Ynp = numpy.arange(10) + res_Xnp, res_Ynp = numpy.broadcast_arrays(Xnp, Ynp) + X = dpnp.asarray(Xnp) + Y = dpnp.asarray(Ynp) + res_X, res_Y = dpnp.broadcast_arrays(X, Y) + assert_array_equal(res_Xnp, dpnp.asnumpy(res_X)) + assert_array_equal(res_Ynp, dpnp.asnumpy(res_Y)) + + def test_broadcast_arrays_one_off(self): + Xnp = numpy.array([[1, 2, 3]]) + Ynp = numpy.array([[1], [2], [3]]) + res_Xnp, res_Ynp = numpy.broadcast_arrays(Xnp, Ynp) + X = dpnp.asarray(Xnp) + Y = dpnp.asarray(Ynp) + res_X, res_Y = dpnp.broadcast_arrays(X, Y) + assert_array_equal(res_Xnp, dpnp.asnumpy(res_X)) + assert_array_equal(res_Ynp, dpnp.asnumpy(res_Y)) + + @pytest.mark.parametrize( + "shapes", + [ + (), + (1,), + (3,), + (0, 1), + (0, 3), + (1, 0), + (3, 0), + (1, 3), + (3, 1), + (3, 3), + ], + ) + def test_broadcast_arrays_same_shapes(self, shapes): + for shape in shapes: + single_input_shapes = [shape] + self.assert_broadcast_correct(single_input_shapes) + double_input_shapes = [shape, shape] + self.assert_broadcast_correct(double_input_shapes) + triple_input_shapes = [shape, shape, shape] + self.assert_broadcast_correct(triple_input_shapes) + + @pytest.mark.parametrize( + "shapes", + [ + [[(1,), (3,)]], + [[(1, 3), (3, 3)]], + [[(3, 1), (3, 3)]], + [[(1, 3), (3, 1)]], + [[(1, 1), (3, 3)]], + [[(1, 1), (1, 3)]], + [[(1, 1), (3, 1)]], + [[(1, 0), (0, 0)]], + [[(0, 1), (0, 0)]], + [[(1, 0), (0, 1)]], + [[(1, 1), (0, 0)]], + [[(1, 1), (1, 0)]], + [[(1, 1), (0, 1)]], + ], + ) + def test_broadcast_arrays_same_len_shapes(self, shapes): + # Check that two different input shapes of the same length, but some have + # ones, broadcast to the correct shape. + for input_shapes in shapes: + self.assert_broadcast_correct(input_shapes) + self.assert_broadcast_correct(input_shapes[::-1]) + + @pytest.mark.parametrize( + "shapes", + [ + [[(), (3,)]], + [[(3,), (3, 3)]], + [[(3,), (3, 1)]], + [[(1,), (3, 3)]], + [[(), (3, 3)]], + [[(1, 1), (3,)]], + [[(1,), (3, 1)]], + [[(1,), (1, 3)]], + [[(), (1, 3)]], + [[(), (3, 1)]], + [[(), (0,)]], + [[(0,), (0, 0)]], + [[(0,), (0, 1)]], + [[(1,), (0, 0)]], + [[(), (0, 0)]], + [[(1, 1), (0,)]], + [[(1,), (0, 1)]], + [[(1,), (1, 0)]], + [[(), (1, 0)]], + [[(), (0, 1)]], + ], + ) + def test_broadcast_arrays_different_len_shapes(self, shapes): + # Check that two different input shapes (of different lengths) broadcast + # to the correct shape. + for input_shapes in shapes: + self.assert_broadcast_correct(input_shapes) + self.assert_broadcast_correct(input_shapes[::-1]) + + @pytest.mark.parametrize( + "shapes", + [ + [[(3,), (4,)]], + [[(2, 3), (2,)]], + [[(3,), (3,), (4,)]], + [[(1, 3, 4), (2, 3, 3)]], + ], + ) + def test_incompatible_shapes_raise_valueerror(self, shapes): + for input_shapes in shapes: + self.assert_broadcast_arrays_raise(input_shapes) + self.assert_broadcast_arrays_raise(input_shapes[::-1]) + + def test_broadcast_arrays_empty_input(self): + assert dpnp.broadcast_arrays() == [] + + def test_subok_error(self): + x = dpnp.ones((4)) + with pytest.raises(NotImplementedError): + dpnp.broadcast_arrays(x, subok=True) + + with pytest.raises(NotImplementedError): + dpnp.broadcast_to(x, (4, 4), subok=True) + + class TestColumnStack: def test_non_iterable(self): with pytest.raises(TypeError): @@ -987,180 +1158,6 @@ def test_generator(self): dpnp.vstack(map(lambda x: x, dpnp.ones((3, 2)))) -@testing.with_requires("numpy<2.0") -@pytest.mark.parametrize("dtype", get_all_dtypes()) -@pytest.mark.parametrize( - "data", [[1, 2, 3], [1.0, 2.0, 3.0]], ids=["[1, 2, 3]", "[1., 2., 3.]"] -) -def test_asfarray(dtype, data): - expected = numpy.asfarray(data, dtype) - result = dpnp.asfarray(data, dtype) - - assert_array_equal(result, expected) - - -@testing.with_requires("numpy<2.0") -@pytest.mark.usefixtures("suppress_complex_warning") -@pytest.mark.parametrize("dtype", get_all_dtypes()) -@pytest.mark.parametrize("data", [[1.0, 2.0, 3.0]], ids=["[1., 2., 3.]"]) -@pytest.mark.parametrize("data_dtype", get_all_dtypes(no_none=True)) -def test_asfarray2(dtype, data, data_dtype): - expected = numpy.asfarray(numpy.array(data, dtype=data_dtype), dtype) - result = dpnp.asfarray(dpnp.array(data, dtype=data_dtype), dtype) - - assert_array_equal(result, expected) - - -def assert_broadcast_correct(input_shapes): - np_arrays = [numpy.zeros(s, dtype="i1") for s in input_shapes] - out_np_arrays = numpy.broadcast_arrays(*np_arrays) - dpnp_arrays = [dpnp.asarray(Xnp) for Xnp in np_arrays] - out_dpnp_arrays = dpnp.broadcast_arrays(*dpnp_arrays) - for Xnp, X in zip(out_np_arrays, out_dpnp_arrays): - assert_array_equal( - Xnp, dpnp.asnumpy(X), err_msg=f"Failed for {input_shapes})" - ) - - -def assert_broadcast_arrays_raise(input_shapes): - dpnp_arrays = [dpnp.asarray(numpy.zeros(s)) for s in input_shapes] - pytest.raises(ValueError, dpnp.broadcast_arrays, *dpnp_arrays) - - -def test_broadcast_arrays_same(): - Xnp = numpy.arange(10) - Ynp = numpy.arange(10) - res_Xnp, res_Ynp = numpy.broadcast_arrays(Xnp, Ynp) - X = dpnp.asarray(Xnp) - Y = dpnp.asarray(Ynp) - res_X, res_Y = dpnp.broadcast_arrays(X, Y) - assert_array_equal(res_Xnp, dpnp.asnumpy(res_X)) - assert_array_equal(res_Ynp, dpnp.asnumpy(res_Y)) - - -def test_broadcast_arrays_one_off(): - Xnp = numpy.array([[1, 2, 3]]) - Ynp = numpy.array([[1], [2], [3]]) - res_Xnp, res_Ynp = numpy.broadcast_arrays(Xnp, Ynp) - X = dpnp.asarray(Xnp) - Y = dpnp.asarray(Ynp) - res_X, res_Y = dpnp.broadcast_arrays(X, Y) - assert_array_equal(res_Xnp, dpnp.asnumpy(res_X)) - assert_array_equal(res_Ynp, dpnp.asnumpy(res_Y)) - - -@pytest.mark.parametrize( - "shapes", - [ - (), - (1,), - (3,), - (0, 1), - (0, 3), - (1, 0), - (3, 0), - (1, 3), - (3, 1), - (3, 3), - ], -) -def test_broadcast_arrays_same_shapes(shapes): - for shape in shapes: - single_input_shapes = [shape] - assert_broadcast_correct(single_input_shapes) - double_input_shapes = [shape, shape] - assert_broadcast_correct(double_input_shapes) - triple_input_shapes = [shape, shape, shape] - assert_broadcast_correct(triple_input_shapes) - - -@pytest.mark.parametrize( - "shapes", - [ - [[(1,), (3,)]], - [[(1, 3), (3, 3)]], - [[(3, 1), (3, 3)]], - [[(1, 3), (3, 1)]], - [[(1, 1), (3, 3)]], - [[(1, 1), (1, 3)]], - [[(1, 1), (3, 1)]], - [[(1, 0), (0, 0)]], - [[(0, 1), (0, 0)]], - [[(1, 0), (0, 1)]], - [[(1, 1), (0, 0)]], - [[(1, 1), (1, 0)]], - [[(1, 1), (0, 1)]], - ], -) -def test_broadcast_arrays_same_len_shapes(shapes): - # Check that two different input shapes of the same length, but some have - # ones, broadcast to the correct shape. - - for input_shapes in shapes: - assert_broadcast_correct(input_shapes) - assert_broadcast_correct(input_shapes[::-1]) - - -@pytest.mark.parametrize( - "shapes", - [ - [[(), (3,)]], - [[(3,), (3, 3)]], - [[(3,), (3, 1)]], - [[(1,), (3, 3)]], - [[(), (3, 3)]], - [[(1, 1), (3,)]], - [[(1,), (3, 1)]], - [[(1,), (1, 3)]], - [[(), (1, 3)]], - [[(), (3, 1)]], - [[(), (0,)]], - [[(0,), (0, 0)]], - [[(0,), (0, 1)]], - [[(1,), (0, 0)]], - [[(), (0, 0)]], - [[(1, 1), (0,)]], - [[(1,), (0, 1)]], - [[(1,), (1, 0)]], - [[(), (1, 0)]], - [[(), (0, 1)]], - ], -) -def test_broadcast_arrays_different_len_shapes(shapes): - # Check that two different input shapes (of different lengths) broadcast - # to the correct shape. - - for input_shapes in shapes: - assert_broadcast_correct(input_shapes) - assert_broadcast_correct(input_shapes[::-1]) - - -@pytest.mark.parametrize( - "shapes", - [ - [[(3,), (4,)]], - [[(2, 3), (2,)]], - [[(3,), (3,), (4,)]], - [[(1, 3, 4), (2, 3, 3)]], - ], -) -def test_incompatible_shapes_raise_valueerror(shapes): - for input_shapes in shapes: - assert_broadcast_arrays_raise(input_shapes) - assert_broadcast_arrays_raise(input_shapes[::-1]) - - -def test_broadcast_arrays_empty_input(): - assert dpnp.broadcast_arrays() == [] - - -def test_subok_error(): - x = dpnp.ones((4)) - with pytest.raises(NotImplementedError): - dpnp.broadcast_arrays(x, subok=True) - dpnp.broadcast_to(x, (4, 4), subok=True) - - def test_can_cast(): X = dpnp.ones((2, 2), dtype=dpnp.int64) pytest.raises(TypeError, dpnp.can_cast, X, 1) diff --git a/dpnp/tests/test_manipulation.py b/dpnp/tests/test_manipulation.py index d3ac41c55262..e719da693c2c 100644 --- a/dpnp/tests/test_manipulation.py +++ b/dpnp/tests/test_manipulation.py @@ -1331,13 +1331,20 @@ def test_ndarray_axes_n_int(self): assert_array_equal(result, expected) def test_alias(self): - a = dpnp.ones((5, 3)) - - res1 = dpnp.transpose((a)) - res2 = dpnp.permute_dims((a)) + a = dpnp.arange(15).reshape(5, 3) + res1 = dpnp.transpose(a) + res2 = dpnp.permute_dims(a) assert_array_equal(res1, res2) + def test_usm_array(self): + a = numpy.arange(9).reshape(3, 3) + ia = dpt.asarray(a) + + expected = numpy.transpose(a) + result = dpnp.transpose(ia) + assert_array_equal(result, expected) + class TestTrimZeros: @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) From 5a6824ea52464266031a17472f6661c27dece3cb Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Fri, 15 Nov 2024 12:21:07 -0800 Subject: [PATCH 2/3] add a new test --- dpnp/tests/test_arraymanipulation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dpnp/tests/test_arraymanipulation.py b/dpnp/tests/test_arraymanipulation.py index 9af97c9b67c7..0f8b8f96d5ca 100644 --- a/dpnp/tests/test_arraymanipulation.py +++ b/dpnp/tests/test_arraymanipulation.py @@ -38,9 +38,12 @@ def test_asfarray2(self, dtype, data, data_dtype): # This is only for coverage with NumPy 2.0 and above def test_asfarray_coverage(self): - expected = [1.0, 2.0, 3.0] + expected = dpnp.array([1.0, 2.0, 3.0]) result = dpnp.asfarray([1, 2, 3]) + assert_array_equal(result, expected) + expected = dpnp.array([1.0, 2.0, 3.0], dtype=dpnp.float32) + result = dpnp.asfarray([1, 2, 3], dtype=dpnp.float32) assert_array_equal(result, expected) From 3dd591b0d29e6fd10633c6a0fd0864020896f484 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Sat, 16 Nov 2024 06:15:41 -0800 Subject: [PATCH 3/3] update docstring tranpose --- dpnp/dpnp_iface_manipulation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index bfba2704df62..d613e18b001d 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -3848,13 +3848,14 @@ def transpose(a, axes=None): ---------- a : {dpnp.ndarray, usm_ndarray} Input array. - axes : None, tuple or list of ints, optional + axes : {None, tuple or list of ints}, optional If specified, it must be a tuple or list which contains a permutation of [0, 1, ..., N-1] where N is the number of axes of `a`. The `i`'th axis of the returned array will correspond to the axis numbered ``axes[i]`` of the input. If not specified or ``None``, defaults to ``range(a.ndim)[::-1]``, which reverses the order of the axes. + Default: ``None``. Returns -------