diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index adc2bdf15f31..567661bdb57f 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -47,7 +47,10 @@ from dpnp.dpnp_iface_arraycreation import array import dpnp +from dpnp.dpnp_array import dpnp_array + import numpy +import dpctl.tensor as dpt __all__ = [ @@ -55,6 +58,7 @@ "atleast_1d", "atleast_2d", "atleast_3d", + "broadcast_to", "concatenate", "copyto", "expand_dims", @@ -190,6 +194,46 @@ def atleast_3d(*arys): return call_origin(numpy.atleast_3d, *arys) +def broadcast_to(x, /, shape, subok=False): + """ + Broadcast an array to a new shape. + + For full documentation refer to :obj:`numpy.broadcast_to`. + + Returns + ------- + y : dpnp.ndarray + An array having a specified shape. Must have the same data type as `x`. + + Limitations + ----------- + Parameter `x` is supported as either :class:`dpnp.ndarray` + or :class:`dpctl.tensor.usm_ndarray`. + Parameter `subok` is supported with default value. + Otherwise the function will be executed sequentially on CPU. + Input array data types of `x` is limited by supported DPNP :ref:`Data types`. + + Examples + -------- + >>> import dpnp as dp + >>> x = dp.array([1, 2, 3]) + >>> dp.broadcast_to(x, (3, 3)) + array([[1, 2, 3], + [1, 2, 3], + [1, 2, 3]]) + + """ + + if subok is not False: + pass + elif isinstance(x, dpnp_array) or isinstance(x, dpt.usm_ndarray): + dpt_array = x.get_array() if isinstance(x, dpnp_array) else x + new_array = dpt.broadcast_to(dpt_array, shape) + return dpnp_array._create_from_usm_ndarray(new_array) + + return call_origin(numpy.broadcast_to, x, shape=shape, subok=subok) + + def concatenate(arrs, axis=0, out=None, dtype=None, casting="same_kind"): """ Join a sequence of arrays along an existing axis. diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index 26dd6fc59cd7..bda10cfd4973 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -648,12 +648,7 @@ tests/third_party/cupy/manipulation_tests/test_dims.py::TestBroadcast_param_8_{s tests/third_party/cupy/manipulation_tests/test_dims.py::TestBroadcast_param_8_{shapes=[(2, 0, 1, 1, 3), (2, 1, 0, 0, 3)]}::test_broadcast_arrays tests/third_party/cupy/manipulation_tests/test_dims.py::TestBroadcast_param_9_{shapes=[(0, 1, 1, 3), (2, 1, 0, 0, 3)]}::test_broadcast tests/third_party/cupy/manipulation_tests/test_dims.py::TestBroadcast_param_9_{shapes=[(0, 1, 1, 3), (2, 1, 0, 0, 3)]}::test_broadcast_arrays -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to_fail -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to_fail_numpy19 -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to_numpy19 -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to_short_shape -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to_short_shape_numpy19 + tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_squeeze_int_axis_failure1 tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_squeeze_int_axis_failure2 tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_squeeze_scalar_failure1 diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index 7e9b9e5505de..3e0026759334 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -853,12 +853,7 @@ tests/third_party/cupy/manipulation_tests/test_dims.py::TestBroadcast_param_8_{s tests/third_party/cupy/manipulation_tests/test_dims.py::TestBroadcast_param_8_{shapes=[(2, 0, 1, 1, 3), (2, 1, 0, 0, 3)]}::test_broadcast_arrays tests/third_party/cupy/manipulation_tests/test_dims.py::TestBroadcast_param_9_{shapes=[(0, 1, 1, 3), (2, 1, 0, 0, 3)]}::test_broadcast tests/third_party/cupy/manipulation_tests/test_dims.py::TestBroadcast_param_9_{shapes=[(0, 1, 1, 3), (2, 1, 0, 0, 3)]}::test_broadcast_arrays -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to_fail -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to_fail_numpy19 -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to_numpy19 -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to_short_shape -tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_broadcast_to_short_shape_numpy19 + tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_squeeze_int_axis_failure1 tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_squeeze_int_axis_failure2 tests/third_party/cupy/manipulation_tests/test_dims.py::TestDims::test_squeeze_scalar_failure1 diff --git a/tests/test_arraymanipulation.py b/tests/test_arraymanipulation.py index f22e8175c3b2..6a2b452917b0 100644 --- a/tests/test_arraymanipulation.py +++ b/tests/test_arraymanipulation.py @@ -2,7 +2,16 @@ from .helper import get_all_dtypes import dpnp + import numpy +from numpy.testing import ( + assert_, + assert_allclose, + assert_array_equal, + assert_equal, + assert_raises, + assert_warns +) @pytest.mark.usefixtures("allow_fall_back_on_numpy") @@ -14,7 +23,7 @@ def test_asfarray(dtype, data): expected = numpy.asfarray(data, dtype) result = dpnp.asfarray(data, dtype) - numpy.testing.assert_array_equal(result, expected) + assert_array_equal(result, expected) @pytest.mark.parametrize("dtype", get_all_dtypes()) @@ -24,7 +33,99 @@ 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) - numpy.testing.assert_array_equal(result, expected) + assert_array_equal(result, expected) + + +class TestDims: + @pytest.mark.parametrize("dt", get_all_dtypes()) + @pytest.mark.parametrize("sh", + [(0,), (1,), (3,)], + ids=['(0,)', '(1,)', '(3,)']) + def test_broadcast_array(self, sh, dt): + np_a = numpy.array(0, dtype=dt) + dp_a = dpnp.array(0, dtype=dt) + func = lambda xp, a: xp.broadcast_to(a, sh) + + assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + + @pytest.mark.parametrize("dt", get_all_dtypes()) + @pytest.mark.parametrize("sh", + [(1,), (2,), (1, 2, 3)], + ids=['(1,)', '(2,)', '(1, 2, 3)']) + def test_broadcast_ones(self, sh, dt): + np_a = numpy.ones(1, dtype=dt) + dp_a = dpnp.ones(1, dtype=dt) + func = lambda xp, a: xp.broadcast_to(a, sh) + + assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + + @pytest.mark.parametrize("dt", get_all_dtypes(no_bool=True)) + @pytest.mark.parametrize("sh", + [(3,), (1, 3), (2, 3)], + ids=['(3,)', '(1, 3)', '(2, 3)']) + def test_broadcast_arange(self, sh, dt): + np_a = numpy.arange(3, dtype=dt) + dp_a = dpnp.arange(3, dtype=dt) + func = lambda xp, a: xp.broadcast_to(a, sh) + + assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + + @pytest.mark.parametrize("dt", get_all_dtypes()) + @pytest.mark.parametrize( + "sh1, sh2", + [ + pytest.param([0], [0], id="(0)"), + pytest.param([1], [1], id="(1)"), + pytest.param([1], [2], id="(2)"), + ], + ) + def test_broadcast_not_tuple(self, sh1, sh2, dt): + np_a = numpy.ones(sh1, dtype=dt) + dp_a = dpnp.ones(sh1, dtype=dt) + func = lambda xp, a: xp.broadcast_to(a, sh2) + + assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + + @pytest.mark.parametrize("dt", get_all_dtypes()) + @pytest.mark.parametrize( + "sh1, sh2", + [ + pytest.param([1], (0,), id="(0,)"), + pytest.param((1, 2), (0, 2), id="(0, 2)"), + pytest.param((2, 1), (2, 0), id="(2, 0)"), + ], + ) + def test_broadcast_zero_shape(self, sh1, sh2, dt): + np_a = numpy.ones(sh1, dtype=dt) + dp_a = dpnp.ones(sh1, dtype=dt) + func = lambda xp, a: xp.broadcast_to(a, sh2) + + assert_allclose(func(numpy, np_a), func(dpnp, dp_a)) + + @pytest.mark.parametrize( + "sh1, sh2", + [ + pytest.param((0,), (), id="(0,)-()"), + pytest.param((1,), (), id="(1,)-()"), + pytest.param((3,), (), id="(3,)-()"), + pytest.param((3,), (1,), id="(3,)-(1,)"), + pytest.param((3,), (2,), id="(3,)-(2,)"), + pytest.param((3,), (4,), id="(3,)-(4,)"), + pytest.param((1, 2), (2, 1), id="(1, 2)-(2, 1)"), + pytest.param((1, 2), (1,), id="(1, 2)-(1,)"), + pytest.param((1,), -1, id="(1,)--1"), + pytest.param((1,), (-1,), id="(1,)-(-1,)"), + pytest.param((1, 2), (-1, 2), id="(1, 2)-(-1, 2)"), + ], + ) + def test_broadcast_raise(self, sh1, sh2): + np_a = numpy.zeros(sh1) + dp_a = dpnp.zeros(sh1) + func = lambda xp, a: xp.broadcast_to(a, sh2) + + with pytest.raises(ValueError): + func(numpy, np_a) + func(dpnp, dp_a) @pytest.mark.usefixtures("allow_fall_back_on_numpy") @@ -38,62 +139,62 @@ def test_returns_copy(self): def test_large_concatenate_axis_None(self): x = dpnp.arange(1, 100) r = dpnp.concatenate(x, None) - numpy.testing.assert_array_equal(x, r) + assert_array_equal(x, r) r = dpnp.concatenate(x, 100) - numpy.testing.assert_array_equal(x, r) + assert_array_equal(x, r) def test_concatenate(self): # Test concatenate function # One sequence returns unmodified (but as array) r4 = list(range(4)) - numpy.testing.assert_array_equal(dpnp.concatenate((r4,)), r4) + assert_array_equal(dpnp.concatenate((r4,)), r4) # Any sequence - numpy.testing.assert_array_equal(dpnp.concatenate((tuple(r4),)), r4) - numpy.testing.assert_array_equal(dpnp.concatenate((dpnp.array(r4),)), r4) + assert_array_equal(dpnp.concatenate((tuple(r4),)), r4) + assert_array_equal(dpnp.concatenate((dpnp.array(r4),)), r4) # 1D default concatenation r3 = list(range(3)) - numpy.testing.assert_array_equal(dpnp.concatenate((r4, r3)), r4 + r3) + assert_array_equal(dpnp.concatenate((r4, r3)), r4 + r3) # Mixed sequence types - numpy.testing.assert_array_equal(dpnp.concatenate((tuple(r4), r3)), r4 + r3) - numpy.testing.assert_array_equal( + assert_array_equal(dpnp.concatenate((tuple(r4), r3)), r4 + r3) + assert_array_equal( dpnp.concatenate((dpnp.array(r4), r3)), r4 + r3 ) # Explicit axis specification - numpy.testing.assert_array_equal(dpnp.concatenate((r4, r3), 0), r4 + r3) + assert_array_equal(dpnp.concatenate((r4, r3), 0), r4 + r3) # Including negative - numpy.testing.assert_array_equal(dpnp.concatenate((r4, r3), -1), r4 + r3) + assert_array_equal(dpnp.concatenate((r4, r3), -1), r4 + r3) # 2D a23 = dpnp.array([[10, 11, 12], [13, 14, 15]]) a13 = dpnp.array([[0, 1, 2]]) res = dpnp.array([[10, 11, 12], [13, 14, 15], [0, 1, 2]]) - numpy.testing.assert_array_equal(dpnp.concatenate((a23, a13)), res) - numpy.testing.assert_array_equal(dpnp.concatenate((a23, a13), 0), res) - numpy.testing.assert_array_equal(dpnp.concatenate((a23.T, a13.T), 1), res.T) - numpy.testing.assert_array_equal(dpnp.concatenate((a23.T, a13.T), -1), res.T) + assert_array_equal(dpnp.concatenate((a23, a13)), res) + assert_array_equal(dpnp.concatenate((a23, a13), 0), res) + assert_array_equal(dpnp.concatenate((a23.T, a13.T), 1), res.T) + assert_array_equal(dpnp.concatenate((a23.T, a13.T), -1), res.T) # Arrays much match shape - numpy.testing.assert_raises(ValueError, dpnp.concatenate, (a23.T, a13.T), 0) + assert_raises(ValueError, dpnp.concatenate, (a23.T, a13.T), 0) # 3D res = dpnp.reshape(dpnp.arange(2 * 3 * 7), (2, 3, 7)) a0 = res[..., :4] a1 = res[..., 4:6] a2 = res[..., 6:] - numpy.testing.assert_array_equal(dpnp.concatenate((a0, a1, a2), 2), res) - numpy.testing.assert_array_equal(dpnp.concatenate((a0, a1, a2), -1), res) - numpy.testing.assert_array_equal(dpnp.concatenate((a0.T, a1.T, a2.T), 0), res.T) + assert_array_equal(dpnp.concatenate((a0, a1, a2), 2), res) + assert_array_equal(dpnp.concatenate((a0, a1, a2), -1), res) + assert_array_equal(dpnp.concatenate((a0.T, a1.T, a2.T), 0), res.T) out = dpnp.copy(res) rout = dpnp.concatenate((a0, a1, a2), 2, out=out) - numpy.testing.assert_(out is rout) - numpy.testing.assert_equal(res, rout) + assert_(out is rout) + assert_equal(res, rout) class TestHstack: def test_non_iterable(self): - numpy.testing.assert_raises(TypeError, dpnp.hstack, 1) + assert_raises(TypeError, dpnp.hstack, 1) @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_empty_input(self): - numpy.testing.assert_raises(ValueError, dpnp.hstack, ()) + assert_raises(ValueError, dpnp.hstack, ()) @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_0D_array(self): @@ -101,7 +202,7 @@ def test_0D_array(self): a = dpnp.array(1) res = dpnp.hstack([a, b]) desired = dpnp.array([1, 2]) - numpy.testing.assert_array_equal(res, desired) + assert_array_equal(res, desired) @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_1D_array(self): @@ -109,7 +210,7 @@ def test_1D_array(self): b = dpnp.array([2]) res = dpnp.hstack([a, b]) desired = dpnp.array([1, 2]) - numpy.testing.assert_array_equal(res, desired) + assert_array_equal(res, desired) @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_2D_array(self): @@ -117,22 +218,22 @@ def test_2D_array(self): b = dpnp.array([[1], [2]]) res = dpnp.hstack([a, b]) desired = dpnp.array([[1, 1], [2, 2]]) - numpy.testing.assert_array_equal(res, desired) + assert_array_equal(res, desired) def test_generator(self): - with numpy.testing.assert_warns(FutureWarning): + with assert_warns(FutureWarning): dpnp.hstack((numpy.arange(3) for _ in range(2))) - with numpy.testing.assert_warns(FutureWarning): + with assert_warns(FutureWarning): dpnp.hstack(map(lambda x: x, numpy.ones((3, 2)))) class TestVstack: def test_non_iterable(self): - numpy.testing.assert_raises(TypeError, dpnp.vstack, 1) + assert_raises(TypeError, dpnp.vstack, 1) @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_empty_input(self): - numpy.testing.assert_raises(ValueError, dpnp.vstack, ()) + assert_raises(ValueError, dpnp.vstack, ()) @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_0D_array(self): @@ -140,7 +241,7 @@ def test_0D_array(self): b = dpnp.array(2) res = dpnp.vstack([a, b]) desired = dpnp.array([[1], [2]]) - numpy.testing.assert_array_equal(res, desired) + assert_array_equal(res, desired) @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_1D_array(self): @@ -148,7 +249,7 @@ def test_1D_array(self): b = dpnp.array([2]) res = dpnp.vstack([a, b]) desired = dpnp.array([[1], [2]]) - numpy.testing.assert_array_equal(res, desired) + assert_array_equal(res, desired) @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_2D_array(self): @@ -156,7 +257,7 @@ def test_2D_array(self): b = dpnp.array([[1], [2]]) res = dpnp.vstack([a, b]) desired = dpnp.array([[1], [2], [1], [2]]) - numpy.testing.assert_array_equal(res, desired) + assert_array_equal(res, desired) @pytest.mark.usefixtures("allow_fall_back_on_numpy") def test_2D_array2(self): @@ -164,8 +265,8 @@ def test_2D_array2(self): b = dpnp.array([1, 2]) res = dpnp.vstack([a, b]) desired = dpnp.array([[1, 2], [1, 2]]) - numpy.testing.assert_array_equal(res, desired) + assert_array_equal(res, desired) def test_generator(self): - with numpy.testing.assert_warns(FutureWarning): + with assert_warns(FutureWarning): dpnp.vstack((numpy.arange(3) for _ in range(2))) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 42cbe7459513..a523c46465bf 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -927,8 +927,7 @@ def test_from_dlpack(arr_dtype, shape, device): @pytest.mark.parametrize("device", valid_devices, ids=[device.filter_string for device in valid_devices]) -#TODO need to delete no_bool=True when use dlpack > 0.7 version -@pytest.mark.parametrize("arr_dtype", get_all_dtypes(no_float16=True, no_bool=True)) +@pytest.mark.parametrize("arr_dtype", get_all_dtypes(no_float16=True)) def test_from_dlpack_with_dpt(arr_dtype, device): X = dpctl.tensor.empty((64,), dtype=arr_dtype, device=device) Y = dpnp.from_dlpack(X) @@ -937,3 +936,12 @@ def test_from_dlpack_with_dpt(arr_dtype, device): assert X.__dlpack_device__() == Y.__dlpack_device__() assert X.usm_type == Y.usm_type assert_sycl_queue_equal(X.sycl_queue, Y.sycl_queue) + + +@pytest.mark.parametrize("device", + valid_devices, + ids=[device.filter_string for device in valid_devices]) +def test_broadcast_to(device): + x = dpnp.arange(5, device=device) + y = dpnp.broadcast_to(x, (3, 5)) + assert_sycl_queue_equal(x.sycl_queue, y.sycl_queue) diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index 96d55f6875c5..b0efa89968bd 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -155,6 +155,7 @@ def test_meshgrid(usm_type_x, usm_type_y): assert z[0].usm_type == usm_type_x assert z[1].usm_type == usm_type_y + @pytest.mark.parametrize( "func,data1,data2", [ @@ -173,3 +174,10 @@ def test_2in_1out(func, data1, data2, usm_type_x, usm_type_y): assert x.usm_type == usm_type_x assert y.usm_type == usm_type_y assert z.usm_type == du.get_coerced_usm_type([usm_type_x, usm_type_y]) + + +@pytest.mark.parametrize("usm_type", list_of_usm_types, ids=list_of_usm_types) +def test_broadcast_to(usm_type): + x = dp.ones(7, usm_type=usm_type) + y = dp.broadcast_to(x, (2, 7)) + assert x.usm_type == y.usm_type