From 7ce56f7a6a8bdd270537702ac45a8aec366764de Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Fri, 13 Sep 2024 11:28:31 -0500 Subject: [PATCH 1/6] add dpnp.require --- dpnp/dpnp_iface_manipulation.py | 118 +++++++++++++++--- tests/test_arraymanipulation.py | 22 ++++ tests/test_manipulation.py | 56 +++++++++ .../cupy/manipulation_tests/test_kind.py | 10 +- 4 files changed, 184 insertions(+), 22 deletions(-) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index be9765c3420b..5648aa96a7d8 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -76,6 +76,7 @@ "permute_dims", "ravel", "repeat", + "require", "reshape", "result_type", "roll", @@ -646,12 +647,8 @@ def atleast_1d(*arys): """ res = [] + dpnp.check_supported_arrays_type(*arys) for ary in arys: - if not dpnp.is_supported_array_type(ary): - raise TypeError( - "Each input array must be any of supported type, " - f"but got {type(ary)}" - ) if ary.ndim == 0: result = ary.reshape(1) else: @@ -704,12 +701,8 @@ def atleast_2d(*arys): """ res = [] + dpnp.check_supported_arrays_type(*arys) for ary in arys: - if not dpnp.is_supported_array_type(ary): - raise TypeError( - "Each input array must be any of supported type, " - f"but got {type(ary)}" - ) if ary.ndim == 0: result = ary.reshape(1, 1) elif ary.ndim == 1: @@ -768,12 +761,8 @@ def atleast_3d(*arys): """ res = [] + dpnp.check_supported_arrays_type(*arys) for ary in arys: - if not dpnp.is_supported_array_type(ary): - raise TypeError( - "Each input array must be any of supported type, " - f"but got {type(ary)}" - ) if ary.ndim == 0: result = ary.reshape(1, 1, 1) elif ary.ndim == 1: @@ -1954,6 +1943,105 @@ def repeat(a, repeats, axis=None): return dpnp_array._create_from_usm_ndarray(usm_res) +def require(a, dtype=None, requirements=None, *, like=None): + """ + Return an dpnp.ndarray of the provided type that satisfies requirements. + + This function is useful to be sure that an array with the correct flags + is returned for passing to compiled code (perhaps through ctypes). + + For full documentation refer to :obj:`numpy.require`. + + Parameters + ---------- + a : array_like + The object to be converted to a type-and-requirement-satisfying array. + dtype : data-type, optional + The required data-type. If None preserve the current dtype. If your + application requires the data to be in native byteorder, include + a byteorder specification as a part of the dtype specification. + requirements : {str, sequence of str}, , optional + The requirements list can be any of the following: + + * 'F_CONTIGUOUS' ('F') - ensure a Fortran-contiguous array + * 'C_CONTIGUOUS' ('C') - ensure a C-contiguous array + * 'WRITABLE' ('W') - ensure a writable array + + Returns + ------- + out : dpnp.ndarray + Array with specified requirements and type if given. + + Limitations + ----------- + Parameter `like` is supported only with default value ``None``. + Otherwise, the function raises `NotImplementedError` exception. + + See Also + -------- + :obj:`dpnp.asarray` : Convert input to an ndarray. + :obj:`dpnp.asanyarray ` : Convert to an ndarray, but pass through + ndarray subclasses. + :obj:`dpnp.ascontiguousarray` : Convert input to a contiguous array. + :obj:`dpnp.asfortranarray` : Convert input to an ndarray with + column-major memory order. + :obj:`dpnp.ndarray.flags` : Information about the memory layout + of the array. + + Notes + ----- + The returned array will be guaranteed to have the listed requirements + by making a copy if needed. + + Examples + -------- + >>> import dpnp as np + >>> x = np.arange(6).reshape(2,3) + >>> x.flags + C_CONTIGUOUS : True + F_CONTIGUOUS : False + WRITEABLE : True + + >>> y = np.require(x, dtype=np.float32, requirements=['W', 'F']) + >>> y.flags + C_CONTIGUOUS : False + F_CONTIGUOUS : True + WRITEABLE : True + + """ + + dpnp.check_limitations(like=like) + + possible_flags = { + "C": "C", + "C_CONTIGUOUS": "C", + "F": "F", + "F_CONTIGUOUS": "F", + "W": "W", + "WRITEABLE": "W", + } + + if not requirements: + return dpnp.asanyarray(a, dtype=dtype) + + requirements = {possible_flags[x.upper()] for x in requirements} + order = "A" + if requirements.issuperset({"C", "F"}): + raise ValueError("Cannot specify both 'C' and 'F' order") + if "F" in requirements: + order = "F" + requirements.remove("F") + elif "C" in requirements: + order = "C" + requirements.remove("C") + + arr = dpnp.array(a, dtype=dtype, order=order, copy=None) + if not arr.flags["W"]: + return arr.copy(order) + + return arr + + def reshape(a, /, newshape, order="C", copy=None): """ Gives a new shape to an array without changing its data. diff --git a/tests/test_arraymanipulation.py b/tests/test_arraymanipulation.py index 1779e87a0d76..e8bc95574620 100644 --- a/tests/test_arraymanipulation.py +++ b/tests/test_arraymanipulation.py @@ -1,3 +1,4 @@ +import dpctl.tensor as dpt import numpy import pytest from dpctl.tensor._numpy_helper import AxisError @@ -45,6 +46,13 @@ def test_3D_array(self): desired = [a, b] assert_array_equal(res, desired) + def test_dpnp_dpt_array(self): + a = dpnp.array([1, 2]) + b = dpt.asarray([2, 3]) + res = dpnp.atleast_1d(a, b) + desired = [dpnp.array([1, 2]), dpnp.array([2, 3])] + assert_array_equal(res, desired) + class TestAtleast2d: def test_0D_array(self): @@ -77,6 +85,13 @@ def test_3D_array(self): desired = [a, b] assert_array_equal(res, desired) + def test_dpnp_dpt_array(self): + a = dpnp.array([1, 2]) + b = dpt.asarray([2, 3]) + res = dpnp.atleast_2d(a, b) + desired = [dpnp.array([[1, 2]]), dpnp.array([[2, 3]])] + assert_array_equal(res, desired) + class TestAtleast3d: def test_0D_array(self): @@ -109,6 +124,13 @@ def test_3D_array(self): desired = [a, b] assert_array_equal(res, desired) + def test_dpnp_dpt_array(self): + a = dpnp.array([1, 2]) + b = dpt.asarray([2, 3]) + res = dpnp.atleast_3d(a, b) + desired = [dpnp.array([[[1], [2]]]), dpnp.array([[[2], [3]]])] + assert_array_equal(res, desired) + class TestColumnStack: def test_non_iterable(self): diff --git a/tests/test_manipulation.py b/tests/test_manipulation.py index b9afeef7f290..b963e92c9df9 100644 --- a/tests/test_manipulation.py +++ b/tests/test_manipulation.py @@ -1,3 +1,5 @@ +import itertools + import dpctl.tensor as dpt import numpy import pytest @@ -665,6 +667,60 @@ def test_minimum_signed_integers(self, data, dtype): assert_array_equal(result, expected) +class TestRequire: + flag_names = ["C", "C_CONTIGUOUS", "F", "F_CONTIGUOUS", "W"] + + def generate_all_false(self, dtype): + a_np = numpy.zeros((10, 10)) + a_dp = dpnp.zeros((10, 10)) + a_np = a_np[::2, ::2] + a_dp = a_dp[::2, ::2] + a_np.flags["W"] = False + a_dp.flags["W"] = False + assert not a_dp.flags["C"] + assert not a_dp.flags["F"] + assert not a_dp.flags["W"] + return a_np, a_dp + + def set_and_check_flag(self, flag, dtype, arr): + if dtype is None: + dtype = arr[1].dtype + a_np = numpy.require(arr[0], dtype, [flag]) + a_dp = dpnp.require(arr[1], dtype, [flag]) + assert a_np.flags[flag] == a_dp.flags[flag] + assert a_np.dtype == a_dp.dtype + + # a further call to dpnp.require ought to return the same array + c = dpnp.require(a_dp, None, [flag]) + assert c is a_dp + + def test_require_each(self): + id = ["f4", "i4"] + fd = [None, "f4", "c8"] + for idtype, fdtype, flag in itertools.product(id, fd, self.flag_names): + a = self.generate_all_false(idtype) + self.set_and_check_flag(flag, fdtype, a) + + @pytest.mark.parametrize("xp", [numpy, dpnp]) + def test_unknown_requirement(self, xp): + a = self.generate_all_false("f4") + assert_raises(KeyError, xp.require, a, None, "Q") + + def test_non_array_input(self): + a_np = numpy.require([1, 2, 3, 4], "i4", ["C", "W"]) + a_dp = dpnp.require([1, 2, 3, 4], "i4", ["C", "W"]) + assert a_np.flags["C"] == a_dp.flags["C"] + assert a_np.flags["F"] == a_dp.flags["F"] + assert a_np.flags["W"] == a_dp.flags["W"] + assert a_np.dtype == a_dp.dtype + assert_array_equal(a_np, a_dp) + + @pytest.mark.parametrize("xp", [numpy, dpnp]) + def test_C_and_F_simul(self, xp): + a = self.generate_all_false("f4") + assert_raises(ValueError, xp.require, a, None, ["C", "F"]) + + class TestTranspose: @pytest.mark.parametrize("axes", [(0, 1), (1, 0), [0, 1]]) def test_2d_with_axes(self, axes): diff --git a/tests/third_party/cupy/manipulation_tests/test_kind.py b/tests/third_party/cupy/manipulation_tests/test_kind.py index 8bc98cdc248d..c76cffc9440f 100644 --- a/tests/third_party/cupy/manipulation_tests/test_kind.py +++ b/tests/third_party/cupy/manipulation_tests/test_kind.py @@ -94,7 +94,6 @@ def func(xp): assert func(numpy) == func(cupy) - @pytest.mark.skip("dpnp.require() is not implemented yet") @testing.for_all_dtypes() def test_require_flag_check(self, dtype): possible_flags = [["C_CONTIGUOUS"], ["F_CONTIGUOUS"]] @@ -105,7 +104,7 @@ def test_require_flag_check(self, dtype): assert arr.flags[parameter] assert arr.dtype == dtype - @pytest.mark.skip("dpnp.require() is not implemented yet") + @pytest.mark.skip("dpnp.require() does not support requirement ['O']") @testing.for_all_dtypes() def test_require_owndata(self, dtype): x = cupy.zeros((2, 3, 4), dtype=dtype) @@ -113,28 +112,25 @@ def test_require_owndata(self, dtype): arr = cupy.require(arr, dtype, ["O"]) assert arr.flags["OWNDATA"] - @pytest.mark.skip("dpnp.require() is not implemented yet") @testing.for_all_dtypes() def test_require_C_and_F_flags(self, dtype): x = cupy.zeros((2, 3, 4), dtype=dtype) with pytest.raises(ValueError): cupy.require(x, dtype, ["C", "F"]) - @pytest.mark.skip("dpnp.require() is not implemented yet") + @pytest.mark.skip("dpnp.require() does support requirement ['W']") @testing.for_all_dtypes() def test_require_incorrect_requirments(self, dtype): x = cupy.zeros((2, 3, 4), dtype=dtype) with pytest.raises(ValueError): cupy.require(x, dtype, ["W"]) - @pytest.mark.skip("dpnp.require() is not implemented yet") @testing.for_all_dtypes() def test_require_incorrect_dtype(self, dtype): x = cupy.zeros((2, 3, 4), dtype=dtype) - with pytest.raises(ValueError): + with pytest.raises((ValueError, TypeError)): cupy.require(x, "random", "C") - @pytest.mark.skip("dpnp.require() is not implemented yet") @testing.for_all_dtypes() def test_require_empty_requirements(self, dtype): x = cupy.zeros((2, 3, 4), dtype=dtype) From ab1112a98d7ab93ed25fbac0a24b5e93492a7cb6 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Fri, 13 Sep 2024 20:05:30 -0500 Subject: [PATCH 2/6] improve coverage --- tests/test_manipulation.py | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/tests/test_manipulation.py b/tests/test_manipulation.py index b963e92c9df9..5928d8a8c390 100644 --- a/tests/test_manipulation.py +++ b/tests/test_manipulation.py @@ -685,14 +685,14 @@ def generate_all_false(self, dtype): def set_and_check_flag(self, flag, dtype, arr): if dtype is None: dtype = arr[1].dtype - a_np = numpy.require(arr[0], dtype, [flag]) - a_dp = dpnp.require(arr[1], dtype, [flag]) - assert a_np.flags[flag] == a_dp.flags[flag] - assert a_np.dtype == a_dp.dtype + result = numpy.require(arr[0], dtype, [flag]) + expected = dpnp.require(arr[1], dtype, [flag]) + assert result.flags[flag] == expected.flags[flag] + assert result.dtype == expected.dtype # a further call to dpnp.require ought to return the same array - c = dpnp.require(a_dp, None, [flag]) - assert c is a_dp + c = dpnp.require(expected, None, [flag]) + assert c is expected def test_require_each(self): id = ["f4", "i4"] @@ -707,19 +707,30 @@ def test_unknown_requirement(self, xp): assert_raises(KeyError, xp.require, a, None, "Q") def test_non_array_input(self): - a_np = numpy.require([1, 2, 3, 4], "i4", ["C", "W"]) - a_dp = dpnp.require([1, 2, 3, 4], "i4", ["C", "W"]) - assert a_np.flags["C"] == a_dp.flags["C"] - assert a_np.flags["F"] == a_dp.flags["F"] - assert a_np.flags["W"] == a_dp.flags["W"] - assert a_np.dtype == a_dp.dtype - assert_array_equal(a_np, a_dp) + expected = numpy.require([1, 2, 3, 4], "i4", ["C", "W"]) + result = dpnp.require([1, 2, 3, 4], "i4", ["C", "W"]) + assert expected.flags["C"] == result.flags["C"] + assert expected.flags["F"] == result.flags["F"] + assert expected.flags["W"] == result.flags["W"] + assert expected.dtype == result.dtype + assert_array_equal(expected, result) @pytest.mark.parametrize("xp", [numpy, dpnp]) def test_C_and_F_simul(self, xp): a = self.generate_all_false("f4") assert_raises(ValueError, xp.require, a, None, ["C", "F"]) + def test_copy(self): + a_np = numpy.arange(6).reshape(2, 3) + a_dp = dpnp.arange(6).reshape(2, 3) + a_np.flags["W"] = False + a_dp.flags["W"] = False + expected = numpy.require(a_np, requirements=["W", "C"]) + result = dpnp.require(a_dp, requirements=["W", "C"]) + # copy is done + assert result is not a_dp + assert_array_equal(expected, result) + class TestTranspose: @pytest.mark.parametrize("axes", [(0, 1), (1, 0), [0, 1]]) From d23968b3a42bd6a9940baba4037b2e70997764af Mon Sep 17 00:00:00 2001 From: vtavana <120411540+vtavana@users.noreply.github.com> Date: Sat, 14 Sep 2024 12:50:47 -0500 Subject: [PATCH 3/6] address comments --- dpnp/dpnp_iface_manipulation.py | 24 ++++++++++++------- tests/test_manipulation.py | 6 ++--- .../cupy/manipulation_tests/test_kind.py | 3 +-- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 5648aa96a7d8..3586b21b7f35 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -1945,7 +1945,8 @@ def repeat(a, repeats, axis=None): def require(a, dtype=None, requirements=None, *, like=None): """ - Return an dpnp.ndarray of the provided type that satisfies requirements. + Return a :class:`dpnp.ndarray` of the provided type that satisfies + requirements. This function is useful to be sure that an array with the correct flags is returned for passing to compiled code (perhaps through ctypes). @@ -1956,11 +1957,9 @@ def require(a, dtype=None, requirements=None, *, like=None): ---------- a : array_like The object to be converted to a type-and-requirement-satisfying array. - dtype : data-type, optional - The required data-type. If None preserve the current dtype. If your - application requires the data to be in native byteorder, include - a byteorder specification as a part of the dtype specification. - requirements : {str, sequence of str}, , optional + dtype : {None, data-type}, optional + The required data-type. If ``None`` preserve the current dtype. + requirements : {None, str, sequence of str}, optional The requirements list can be any of the following: * 'F_CONTIGUOUS' ('F') - ensure a Fortran-contiguous array @@ -1980,7 +1979,7 @@ def require(a, dtype=None, requirements=None, *, like=None): See Also -------- :obj:`dpnp.asarray` : Convert input to an ndarray. - :obj:`dpnp.asanyarray ` : Convert to an ndarray, but pass through + :obj:`dpnp.asanyarray` : Convert to an ndarray, but pass through ndarray subclasses. :obj:`dpnp.ascontiguousarray` : Convert input to a contiguous array. :obj:`dpnp.asfortranarray` : Convert input to an ndarray with @@ -1996,7 +1995,7 @@ def require(a, dtype=None, requirements=None, *, like=None): Examples -------- >>> import dpnp as np - >>> x = np.arange(6).reshape(2,3) + >>> x = np.arange(6).reshape(2, 3) >>> x.flags C_CONTIGUOUS : True F_CONTIGUOUS : False @@ -2024,7 +2023,14 @@ def require(a, dtype=None, requirements=None, *, like=None): if not requirements: return dpnp.asanyarray(a, dtype=dtype) - requirements = {possible_flags[x.upper()] for x in requirements} + try: + requirements = {possible_flags[x.upper()] for x in requirements} + except KeyError as exc: + incorrect_flag = (set(requirements) - set(possible_flags.keys())).pop() + raise ValueError( + f"Incorrect flag {incorrect_flag} in requirements" + ) from exc + order = "A" if requirements.issuperset({"C", "F"}): raise ValueError("Cannot specify both 'C' and 'F' order") diff --git a/tests/test_manipulation.py b/tests/test_manipulation.py index 5928d8a8c390..912a9e5845e4 100644 --- a/tests/test_manipulation.py +++ b/tests/test_manipulation.py @@ -671,8 +671,8 @@ class TestRequire: flag_names = ["C", "C_CONTIGUOUS", "F", "F_CONTIGUOUS", "W"] def generate_all_false(self, dtype): - a_np = numpy.zeros((10, 10)) - a_dp = dpnp.zeros((10, 10)) + a_np = numpy.zeros((10, 10), dtype=dtype) + a_dp = dpnp.zeros((10, 10), dtype=dtype) a_np = a_np[::2, ::2] a_dp = a_dp[::2, ::2] a_np.flags["W"] = False @@ -704,7 +704,7 @@ def test_require_each(self): @pytest.mark.parametrize("xp", [numpy, dpnp]) def test_unknown_requirement(self, xp): a = self.generate_all_false("f4") - assert_raises(KeyError, xp.require, a, None, "Q") + assert_raises((KeyError, ValueError), xp.require, a, None, "Q") def test_non_array_input(self): expected = numpy.require([1, 2, 3, 4], "i4", ["C", "W"]) diff --git a/tests/third_party/cupy/manipulation_tests/test_kind.py b/tests/third_party/cupy/manipulation_tests/test_kind.py index c76cffc9440f..4c74671e29b0 100644 --- a/tests/third_party/cupy/manipulation_tests/test_kind.py +++ b/tests/third_party/cupy/manipulation_tests/test_kind.py @@ -118,12 +118,11 @@ def test_require_C_and_F_flags(self, dtype): with pytest.raises(ValueError): cupy.require(x, dtype, ["C", "F"]) - @pytest.mark.skip("dpnp.require() does support requirement ['W']") @testing.for_all_dtypes() def test_require_incorrect_requirments(self, dtype): x = cupy.zeros((2, 3, 4), dtype=dtype) with pytest.raises(ValueError): - cupy.require(x, dtype, ["W"]) + cupy.require(x, dtype, ["O"]) @testing.for_all_dtypes() def test_require_incorrect_dtype(self, dtype): From 2346fbf4d19feab7489aa8c91999dadf66ddc521 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Sun, 15 Sep 2024 14:07:51 -0500 Subject: [PATCH 4/6] fix pre-commit --- tests/test_manipulation.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_manipulation.py b/tests/test_manipulation.py index 9af445f77e23..0289886f2366 100644 --- a/tests/test_manipulation.py +++ b/tests/test_manipulation.py @@ -848,7 +848,6 @@ def test_rotation_axes(self): ) - class TestTranspose: @pytest.mark.parametrize("axes", [(0, 1), (1, 0), [0, 1]]) def test_2d_with_axes(self, axes): From ac07299aa07935f57429e69e25590623f4063d59 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 16 Sep 2024 10:15:15 -0500 Subject: [PATCH 5/6] Input array should be dpnp.ndarray or usm_ndarray --- dpnp/dpnp_iface_manipulation.py | 6 ++++-- tests/test_manipulation.py | 18 ++++++++++-------- tests/test_sycl_queue.py | 20 ++++++++++++++++++++ tests/test_usm_type.py | 13 +++++++++++++ 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/dpnp/dpnp_iface_manipulation.py b/dpnp/dpnp_iface_manipulation.py index 1d0cf26c99ff..1e847366d14f 100644 --- a/dpnp/dpnp_iface_manipulation.py +++ b/dpnp/dpnp_iface_manipulation.py @@ -1960,8 +1960,9 @@ def require(a, dtype=None, requirements=None, *, like=None): Parameters ---------- - a : array_like - The object to be converted to a type-and-requirement-satisfying array. + a : {dpnp.ndarray, usm_ndarray} + The input array to be converted to a type-and-requirement-satisfying + array. dtype : {None, data-type}, optional The required data-type. If ``None`` preserve the current dtype. requirements : {None, str, sequence of str}, optional @@ -2015,6 +2016,7 @@ def require(a, dtype=None, requirements=None, *, like=None): """ dpnp.check_limitations(like=like) + dpnp.check_supported_arrays_type(a) possible_flags = { "C": "C", diff --git a/tests/test_manipulation.py b/tests/test_manipulation.py index 0289886f2366..ba0166379906 100644 --- a/tests/test_manipulation.py +++ b/tests/test_manipulation.py @@ -701,24 +701,26 @@ def test_require_each(self): a = self.generate_all_false(idtype) self.set_and_check_flag(flag, fdtype, a) - @pytest.mark.parametrize("xp", [numpy, dpnp]) - def test_unknown_requirement(self, xp): + def test_unknown_requirement(self): a = self.generate_all_false("f4") - assert_raises((KeyError, ValueError), xp.require, a, None, "Q") + assert_raises(KeyError, numpy.require, a[0], None, "Q") + assert_raises(ValueError, dpnp.require, a[1], None, "Q") def test_non_array_input(self): - expected = numpy.require([1, 2, 3, 4], "i4", ["C", "W"]) - result = dpnp.require([1, 2, 3, 4], "i4", ["C", "W"]) + a_np = numpy.array([1, 2, 3, 4]) + a_dp = dpnp.array(a_np) + expected = numpy.require(a_np, "i4", ["C", "W"]) + result = dpnp.require(a_dp, "i4", ["C", "W"]) assert expected.flags["C"] == result.flags["C"] assert expected.flags["F"] == result.flags["F"] assert expected.flags["W"] == result.flags["W"] assert expected.dtype == result.dtype assert_array_equal(expected, result) - @pytest.mark.parametrize("xp", [numpy, dpnp]) - def test_C_and_F_simul(self, xp): + def test_C_and_F_simul(self): a = self.generate_all_false("f4") - assert_raises(ValueError, xp.require, a, None, ["C", "F"]) + assert_raises(ValueError, numpy.require, a[0], None, ["C", "F"]) + assert_raises(ValueError, dpnp.require, a[1], None, ["C", "F"]) def test_copy(self): a_np = numpy.arange(6).reshape(2, 3) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 1b44b2073526..c598d45c61e4 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -1285,6 +1285,26 @@ def test_out_multi_dot(device): assert_sycl_queue_equal(result.sycl_queue, exec_q) +@pytest.mark.parametrize( + "device", + valid_devices, + ids=[device.filter_string for device in valid_devices], +) +def test_require(device): + dpnp_data = dpnp.arange(10, device=device).reshape(2, 5) + result = dpnp.require(dpnp_data, dtype="f4", requirements=["F"]) + + expected_queue = dpnp_data.sycl_queue + result_queue = result.sycl_queue + assert_sycl_queue_equal(result_queue, expected_queue) + + # No requirements + result = dpnp.require(dpnp_data, dtype="f4") + expected_queue = dpnp_data.sycl_queue + result_queue = result.sycl_queue + assert_sycl_queue_equal(result_queue, expected_queue) + + @pytest.mark.parametrize( "device", valid_devices, diff --git a/tests/test_usm_type.py b/tests/test_usm_type.py index 5e0e50738b83..592340d6c0db 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -1013,6 +1013,19 @@ def test_eigenvalue(func, shape, usm_type): assert a.usm_type == dp_val.usm_type +@pytest.mark.parametrize("usm_type", list_of_usm_types, ids=list_of_usm_types) +def test_require(usm_type): + dpnp_data = dp.arange(10, usm_type=usm_type).reshape(2, 5) + result = dp.require(dpnp_data, dtype="f4", requirements=["F"]) + assert dpnp_data.usm_type == usm_type + assert result.usm_type == usm_type + + # No requirements + result = dp.require(dpnp_data, dtype="f4") + assert dpnp_data.usm_type == usm_type + assert result.usm_type == usm_type + + @pytest.mark.parametrize("usm_type", list_of_usm_types, ids=list_of_usm_types) def test_resize(usm_type): dpnp_data = dp.arange(10, usm_type=usm_type) From 2b532af91eb819243347ea7e4489b31e69ca2f4c Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 16 Sep 2024 12:35:23 -0500 Subject: [PATCH 6/6] update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fec856083415..cce40c5f833f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ In addition, this release completes implementation of `dpnp.fft` module and adds * Added runtime dependency on `intel-gpu-ocl-icd-system` package [#2023](https://github.com/IntelPython/dpnp/pull/2023) * Added implementation of `dpnp.ravel_multi_index` and `dpnp.unravel_index` functions [#2022](https://github.com/IntelPython/dpnp/pull/2022) * Added implementation of `dpnp.resize` and `dpnp.rot90` functions [#2030](https://github.com/IntelPython/dpnp/pull/2030) +* Added implementation of `dpnp.require` function [#2036](https://github.com/IntelPython/dpnp/pull/2036) ### Change