From 3c2ef682d7fad9a6cb6cc329fdf6458a7e190774 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Fri, 15 Dec 2023 02:30:11 -0600 Subject: [PATCH 1/3] Implement of dpnp.clip() --- dpnp/dpnp_array.py | 13 ++++++- dpnp/dpnp_iface_mathematical.py | 66 +++++++++++++++++++++++++++++++++ tests/skipped_tests.tbl | 10 ----- tests/skipped_tests_gpu.tbl | 11 +----- tests/test_dparray.py | 9 +++++ tests/test_mathematical.py | 28 ++++++++++++++ 6 files changed, 116 insertions(+), 21 deletions(-) diff --git a/dpnp/dpnp_array.py b/dpnp/dpnp_array.py index 88db5d695f9d..ea3bec05e91e 100644 --- a/dpnp/dpnp_array.py +++ b/dpnp/dpnp_array.py @@ -628,7 +628,18 @@ def choose(input, choices, out=None, mode="raise"): return dpnp.choose(input, choices, out, mode) - # 'clip', + def clip(self, a_min, a_max, *, out=None, order="K"): + """ + Clip (limit) the values in an array. + + See Also + -------- + :obj:`dpnp.clip` + + """ + + return dpnp.clip(self, a_min, a_max, out=out, order=order) + # 'compress', def conj(self): diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index cacab84510bc..9458084715f6 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -83,6 +83,7 @@ "add", "around", "ceil", + "clip", "conj", "conjugate", "convolve", @@ -355,6 +356,71 @@ def ceil( ) +def clip(a, a_min, a_max, *, out=None, order="K"): + """ + Clip (limit) the values in an array. + + For full documentation refer to :obj:`numpy.clip`. + + Parameters + ---------- + a : {dpnp_array, usm_ndarray} + Array containing elements to clip. + a_min, a_max : {dpnp_array, usm_ndarray, None} + Minimum and maximum value. If ``None``, clipping is not performed on the corresponding edge + Only one of `a_min` and `a_max` may be ``None``. Both are broadcast against a. + out : dpnp_array, optional + The results will be placed in this array. It may be the input array for in-place clipping. + `out` must be of the right shape to hold the output. Its type is preserved. + + Returns + ------- + out : dpnp_array + An array with the elements of `a`, but where values < `a_min` are replaced with `a_min`, + and those > `a_max` with `a_max`. + + Examples + -------- + >>> import dpnp as np + >>> a = np.arange(10) + >>> a + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + >>> np.clip(a, 1, 8) + array([1, 1, 2, 3, 4, 5, 6, 7, 8, 8]) + >>> np.clip(a, 8, 1) + array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) + >>> np.clip(a, 3, 6, out=a) + array([3, 3, 3, 3, 4, 5, 6, 6, 6, 6]) + >>> a + array([3, 3, 3, 3, 4, 5, 6, 6, 6, 6]) + + >>> a = np.arange(10) + >>> a + array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) + >>> min = np.array([3, 4, 1, 1, 1, 4, 4, 4, 4, 4]) + >>> np.clip(a, min, 8) + array([3, 4, 2, 3, 4, 5, 6, 7, 8, 8]) + + """ + + usm_arr = dpnp.get_usm_ndarray(a) + usm_min = ( + dpnp.get_usm_ndarray(a_min) if isinstance(a_min, dpnp_array) else a_min + ) + usm_max = ( + dpnp.get_usm_ndarray(a_max) if isinstance(a_max, dpnp_array) else a_max + ) + + if out is not None: + usm_out = dpnp.get_usm_ndarray(out) + dpt.clip(usm_arr, usm_min, usm_max, out=usm_out, order=order) + return out + + return dpnp_array._create_from_usm_ndarray( + dpt.clip(usm_arr, usm_min, usm_max, order=order) + ) + + def conjugate( x, /, diff --git a/tests/skipped_tests.tbl b/tests/skipped_tests.tbl index d32f1ee78c0c..bb695ff9b31a 100644 --- a/tests/skipped_tests.tbl +++ b/tests/skipped_tests.tbl @@ -412,8 +412,6 @@ tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_max_none -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip4 tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_fmax_nan tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_fmin_nan tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_nan_to_num @@ -435,14 +433,6 @@ tests/third_party/cupy/math_tests/test_misc.py::TestConvolveInvalid_param_1_{mod tests/third_party/cupy/math_tests/test_misc.py::TestConvolveInvalid_param_2_{mode='full'}::test_convolve_empty tests/third_party/cupy/math_tests/test_misc.py::TestConvolveInvalid_param_2_{mode='full'}::test_convolve_ndim -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip1 -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip3 -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_none -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_max_none -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip1 -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip2 -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip3 -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip2 tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_fabs tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_fabs_negative tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_nan_to_num_scalar_nan diff --git a/tests/skipped_tests_gpu.tbl b/tests/skipped_tests_gpu.tbl index c5cf53b2a71c..207d4a94e71f 100644 --- a/tests/skipped_tests_gpu.tbl +++ b/tests/skipped_tests_gpu.tbl @@ -509,8 +509,6 @@ tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_ldexp tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_combination tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_nextafter_float -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_max_none -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip4 tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_fmax_nan tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_fmin_nan tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_nan_to_num @@ -532,14 +530,7 @@ tests/third_party/cupy/math_tests/test_misc.py::TestConvolveInvalid_param_1_{mod tests/third_party/cupy/math_tests/test_misc.py::TestConvolveInvalid_param_2_{mode='full'}::test_convolve_empty tests/third_party/cupy/math_tests/test_misc.py::TestConvolveInvalid_param_2_{mode='full'}::test_convolve_ndim -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip1 -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip3 -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_min_none -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip_max_none -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip1 -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip2 -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_external_clip3 -tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_clip2 + tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_fabs tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_fabs_negative tests/third_party/cupy/math_tests/test_misc.py::TestMisc::test_nan_to_num_scalar_nan diff --git a/tests/test_dparray.py b/tests/test_dparray.py index 3c57d44bf912..26446c855ac1 100644 --- a/tests/test_dparray.py +++ b/tests/test_dparray.py @@ -246,3 +246,12 @@ def test_repeat(): numpy_array = numpy.arange(4).repeat(3) dpnp_array = dpnp.arange(4).repeat(3) assert_array_equal(numpy_array, dpnp_array) + + +def test_clip(): + numpy_array = numpy.arange(10) + dpnp_array = dpnp.arange(10) + result = dpnp.clip(dpnp_array, 3, 7) + expected = numpy.clip(numpy_array, 3, 7) + + assert_array_equal(expected, result) diff --git a/tests/test_mathematical.py b/tests/test_mathematical.py index b0c8caff3ad9..13779589032e 100644 --- a/tests/test_mathematical.py +++ b/tests/test_mathematical.py @@ -2044,3 +2044,31 @@ 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_clip(dtype): + dp_array = dpnp.asarray([1, 2, 8, 1, 6, 4, 1], dtype=dtype) + np_array = dpnp.asnumpy(dp_array) + + result = dpnp.clip(dp_array, 2, 6) + expected = numpy.clip(np_array, 2, 6) + assert_allclose(expected, result) + + +@pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) +) +def test_clip_arrays(dtype): + dp_array = dpnp.asarray([1, 2, 8, 1, 6, 4, 1], dtype=dtype) + np_array = dpnp.asnumpy(dp_array) + + min_v = dpnp.asarray(2, dtype=dtype) + max_v = dpnp.asarray(6, dtype=dtype) + + result = dpnp.clip(dp_array, min_v, max_v) + expected = numpy.clip(np_array, min_v.asnumpy(), max_v.asnumpy()) + + assert_allclose(expected, result) From 4448dc9ef776d4671ed4b448b704283cc59e4fb7 Mon Sep 17 00:00:00 2001 From: Natalia Polina Date: Fri, 15 Dec 2023 15:26:59 -0600 Subject: [PATCH 2/3] address comments --- dpnp/dpnp_array.py | 8 +++---- dpnp/dpnp_iface_mathematical.py | 32 +++++++++++++++++++------- tests/test_mathematical.py | 40 +++++++++++++++++++++++++++++---- tests/test_sycl_queue.py | 11 +++++++++ tests/test_usm_type.py | 7 ++++++ 5 files changed, 81 insertions(+), 17 deletions(-) diff --git a/dpnp/dpnp_array.py b/dpnp/dpnp_array.py index c1fc6622f243..fad7d76d00c5 100644 --- a/dpnp/dpnp_array.py +++ b/dpnp/dpnp_array.py @@ -628,17 +628,15 @@ def choose(input, choices, out=None, mode="raise"): return dpnp.choose(input, choices, out, mode) - def clip(self, a_min, a_max, *, out=None, order="K"): + def clip(self, min=None, max=None, out=None, **kwargs): """ Clip (limit) the values in an array. - See Also - -------- - :obj:`dpnp.clip` + Refer to :obj:`dpnp.clip` for full documentation. """ - return dpnp.clip(self, a_min, a_max, out=out, order=order) + return dpnp.clip(self, min, max, out=out, **kwargs) # 'compress', diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index 67a0207a2603..c759e56d5c52 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -388,7 +388,7 @@ def ceil( ) -def clip(a, a_min, a_max, *, out=None, order="K"): +def clip(a, a_min, a_max, *, out=None, order="K", **kwargs): """ Clip (limit) the values in an array. @@ -399,11 +399,14 @@ def clip(a, a_min, a_max, *, out=None, order="K"): a : {dpnp_array, usm_ndarray} Array containing elements to clip. a_min, a_max : {dpnp_array, usm_ndarray, None} - Minimum and maximum value. If ``None``, clipping is not performed on the corresponding edge - Only one of `a_min` and `a_max` may be ``None``. Both are broadcast against a. - out : dpnp_array, optional + Minimum and maximum value. If ``None``, clipping is not performed on the corresponding edge. + Only one of `a_min` and `a_max` may be ``None``. Both are broadcast against `a`. + ut : {dpnp_array, usm_ndarray}, optional The results will be placed in this array. It may be the input array for in-place clipping. `out` must be of the right shape to hold the output. Its type is preserved. + order : ("C","F","A","K", optional) + Memory layout of the newly output array, if parameter `out` is `None`. + Default: "K". Returns ------- @@ -411,6 +414,10 @@ def clip(a, a_min, a_max, *, out=None, order="K"): An array with the elements of `a`, but where values < `a_min` are replaced with `a_min`, and those > `a_max` with `a_max`. + Limitations + ----------- + Keyword argument `kwargs` is currently unsupported. + Examples -------- >>> import dpnp as np @@ -435,18 +442,27 @@ def clip(a, a_min, a_max, *, out=None, order="K"): """ + if len(kwargs) != 0: + raise NotImplementedError(f"kwargs={kwargs} is currently not supported") + + if order is None: + order = "K" + usm_arr = dpnp.get_usm_ndarray(a) usm_min = ( - dpnp.get_usm_ndarray(a_min) if isinstance(a_min, dpnp_array) else a_min + dpnp.get_usm_ndarray_or_scalar(a_min) if a_min is not None else a_min ) usm_max = ( - dpnp.get_usm_ndarray(a_max) if isinstance(a_max, dpnp_array) else a_max + dpnp.get_usm_ndarray_or_scalar(a_max) if a_max is not None else a_max ) if out is not None: usm_out = dpnp.get_usm_ndarray(out) - dpt.clip(usm_arr, usm_min, usm_max, out=usm_out, order=order) - return out + usm_res = dpt.clip(usm_arr, usm_min, usm_max, out=usm_out, order=order) + if isinstance(out, dpnp_array): + return out + else: + return dpnp_array._create_from_usm_ndarray(usm_res) return dpnp_array._create_from_usm_ndarray( dpt.clip(usm_arr, usm_min, usm_max, order=order) diff --git a/tests/test_mathematical.py b/tests/test_mathematical.py index 3f40e1aaad05..79dcb9bea43a 100644 --- a/tests/test_mathematical.py +++ b/tests/test_mathematical.py @@ -2152,13 +2152,16 @@ def test_inplace_remainder(dtype): @pytest.mark.parametrize( "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) ) -def test_clip(dtype): - dp_array = dpnp.asarray([1, 2, 8, 1, 6, 4, 1], dtype=dtype) +@pytest.mark.parametrize("order", ["C", "F", "A", "K", None]) +def test_clip(dtype, order): + dp_array = dpnp.asarray([[1, 2, 8], [1, 6, 4], [9, 5, 1]], dtype=dtype) np_array = dpnp.asnumpy(dp_array) - result = dpnp.clip(dp_array, 2, 6) - expected = numpy.clip(np_array, 2, 6) + result = dpnp.clip(dp_array, 2, 6, order=order) + expected = numpy.clip(np_array, 2, 6, order=order) assert_allclose(expected, result) + assert expected.flags.c_contiguous == result.flags.c_contiguous + assert expected.flags.f_contiguous == result.flags.f_contiguous @pytest.mark.parametrize( @@ -2175,3 +2178,32 @@ def test_clip_arrays(dtype): expected = numpy.clip(np_array, min_v.asnumpy(), max_v.asnumpy()) assert_allclose(expected, result) + + +@pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) +) +def test_clip_out(dtype): + dp_array = dpnp.asarray([[1, 2, 8], [1, 6, 4], [9, 5, 1]], dtype=dtype) + np_array = dpnp.asnumpy(dp_array) + + out = dpnp.zeros_like(dp_array) + + result = dpnp.clip(dp_array, 2, 6, out=out) + expected = numpy.clip(np_array, 2, 6) + assert_allclose(expected, out) + assert result is out + + +@pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) +) +def test_clip_out_dpt(dtype): + dp_array = dpnp.asarray([[1, 2, 8], [1, 6, 4], [9, 5, 1]], dtype=dtype) + np_array = dpnp.asnumpy(dp_array) + + out = dpt.zeros_like(dpnp.get_usm_ndarray(dp_array)) + + dpnp.clip(dp_array, 2, 6, out=out) + expected = numpy.clip(np_array, 2, 6) + assert_allclose(expected, out) diff --git a/tests/test_sycl_queue.py b/tests/test_sycl_queue.py index 19104d7bd434..d087ea05f8f9 100644 --- a/tests/test_sycl_queue.py +++ b/tests/test_sycl_queue.py @@ -1369,3 +1369,14 @@ def test_solve(device): assert_sycl_queue_equal(result_queue, dpnp_x.sycl_queue) assert_sycl_queue_equal(result_queue, dpnp_y.sycl_queue) + + +@pytest.mark.parametrize( + "device", + valid_devices, + ids=[device.filter_string for device in valid_devices], +) +def test_clip(device): + x = dpnp.arange(10, device=device) + y = dpnp.clip(x, 3, 7) + 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 fa2931cc5054..38585484bcd9 100644 --- a/tests/test_usm_type.py +++ b/tests/test_usm_type.py @@ -524,3 +524,10 @@ def test_solve(matrix, vector, usm_type_matrix, usm_type_vector): assert z.usm_type == du.get_coerced_usm_type( [usm_type_matrix, usm_type_vector] ) + + +@pytest.mark.parametrize("usm_type", list_of_usm_types, ids=list_of_usm_types) +def test_clip(usm_type): + x = dp.arange(10, usm_type=usm_type) + y = dp.clip(x, 2, 7) + assert x.usm_type == y.usm_type From e4a602bccfbb5e67de6e6fe52725c0138da612a8 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Sat, 16 Dec 2023 14:07:06 +0100 Subject: [PATCH 3/3] Increased tests coverage --- dpnp/dpnp_iface_mathematical.py | 35 ++-- tests/test_mathematical.py | 153 +++++++++++------- .../third_party/cupy/math_tests/test_misc.py | 2 +- 3 files changed, 107 insertions(+), 83 deletions(-) diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index c759e56d5c52..255588d6a670 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -401,12 +401,12 @@ def clip(a, a_min, a_max, *, out=None, order="K", **kwargs): a_min, a_max : {dpnp_array, usm_ndarray, None} Minimum and maximum value. If ``None``, clipping is not performed on the corresponding edge. Only one of `a_min` and `a_max` may be ``None``. Both are broadcast against `a`. - ut : {dpnp_array, usm_ndarray}, optional + out : {dpnp_array, usm_ndarray}, optional The results will be placed in this array. It may be the input array for in-place clipping. `out` must be of the right shape to hold the output. Its type is preserved. - order : ("C","F","A","K", optional) + order : {"C", "F", "A", "K", None}, optional Memory layout of the newly output array, if parameter `out` is `None`. - Default: "K". + If `order` is ``None``, the default value "K" will be used. Returns ------- @@ -417,6 +417,7 @@ def clip(a, a_min, a_max, *, out=None, order="K", **kwargs): Limitations ----------- Keyword argument `kwargs` is currently unsupported. + Otherwise ``NotImplementedError`` exception will be raised. Examples -------- @@ -442,31 +443,21 @@ def clip(a, a_min, a_max, *, out=None, order="K", **kwargs): """ - if len(kwargs) != 0: + if kwargs: raise NotImplementedError(f"kwargs={kwargs} is currently not supported") if order is None: order = "K" usm_arr = dpnp.get_usm_ndarray(a) - usm_min = ( - dpnp.get_usm_ndarray_or_scalar(a_min) if a_min is not None else a_min - ) - usm_max = ( - dpnp.get_usm_ndarray_or_scalar(a_max) if a_max is not None else a_max - ) - - if out is not None: - usm_out = dpnp.get_usm_ndarray(out) - usm_res = dpt.clip(usm_arr, usm_min, usm_max, out=usm_out, order=order) - if isinstance(out, dpnp_array): - return out - else: - return dpnp_array._create_from_usm_ndarray(usm_res) - - return dpnp_array._create_from_usm_ndarray( - dpt.clip(usm_arr, usm_min, usm_max, order=order) - ) + usm_min = None if a_min is None else dpnp.get_usm_ndarray_or_scalar(a_min) + usm_max = None if a_max is None else dpnp.get_usm_ndarray_or_scalar(a_max) + + usm_out = None if out is None else dpnp.get_usm_ndarray(out) + usm_res = dpt.clip(usm_arr, usm_min, usm_max, out=usm_out, order=order) + if out is not None and isinstance(out, dpnp_array): + return out + return dpnp_array._create_from_usm_ndarray(usm_res) def conjugate( diff --git a/tests/test_mathematical.py b/tests/test_mathematical.py index 79dcb9bea43a..6aced5f6a8eb 100644 --- a/tests/test_mathematical.py +++ b/tests/test_mathematical.py @@ -13,6 +13,7 @@ ) import dpnp +from dpnp.dpnp_array import dpnp_array from .helper import ( assert_dtype_allclose, @@ -27,6 +28,98 @@ ) +class TestClip: + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) + ) + @pytest.mark.parametrize("order", ["C", "F", "A", "K", None]) + def test_clip(self, dtype, order): + dp_a = dpnp.asarray([[1, 2, 8], [1, 6, 4], [9, 5, 1]], dtype=dtype) + np_a = dpnp.asnumpy(dp_a) + + result = dpnp.clip(dp_a, 2, 6, order=order) + expected = numpy.clip(np_a, 2, 6, order=order) + assert_allclose(expected, result) + assert expected.flags.c_contiguous == result.flags.c_contiguous + assert expected.flags.f_contiguous == result.flags.f_contiguous + + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) + ) + def test_clip_arrays(self, dtype): + dp_a = dpnp.asarray([1, 2, 8, 1, 6, 4, 1], dtype=dtype) + np_a = dpnp.asnumpy(dp_a) + + min_v = dpnp.asarray(2, dtype=dtype) + max_v = dpnp.asarray(6, dtype=dtype) + + result = dpnp.clip(dp_a, min_v, max_v) + expected = numpy.clip(np_a, min_v.asnumpy(), max_v.asnumpy()) + assert_allclose(expected, result) + + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) + ) + @pytest.mark.parametrize("in_dp", [dpnp, dpt]) + @pytest.mark.parametrize("out_dp", [dpnp, dpt]) + def test_clip_out(self, dtype, in_dp, out_dp): + np_a = numpy.array([[1, 2, 8], [1, 6, 4], [9, 5, 1]], dtype=dtype) + dp_a = in_dp.asarray(np_a) + + dp_out = out_dp.ones(dp_a.shape, dtype=dtype) + np_out = numpy.ones(np_a.shape, dtype=dtype) + + result = dpnp.clip(dp_a, 2, 6, out=dp_out) + expected = numpy.clip(np_a, 2, 6, out=np_out) + assert_allclose(expected, result) + assert_allclose(np_out, dp_out) + assert isinstance(result, dpnp_array) + + def test_input_nan(self): + np_a = numpy.array([-2.0, numpy.nan, 0.5, 3.0, 0.25, numpy.nan]) + dp_a = dpnp.array(np_a) + + result = dpnp.clip(dp_a, -1, 1) + expected = numpy.clip(np_a, -1, 1) + assert_array_equal(result, expected) + + # TODO: unmute the test once dpctl resolves the issue + @pytest.mark.skip(reason="dpctl-1489 issue") + @pytest.mark.parametrize( + "kwargs", + [ + {"min": numpy.nan}, + {"max": numpy.nan}, + {"min": numpy.nan, "max": numpy.nan}, + {"min": -2, "max": numpy.nan}, + {"min": numpy.nan, "max": 10}, + ], + ) + def test_nan_edges(self, kwargs): + np_a = numpy.arange(7) + dp_a = dpnp.asarray(np_a) + + result = dp_a.clip(**kwargs) + expected = np_a.clip(**kwargs) + assert_allclose(expected, result) + + @pytest.mark.parametrize( + "kwargs", + [ + {"casting": "same_kind"}, + {"dtype": "i8"}, + {"subok": True}, + {"where": True}, + ], + ) + def test_not_implemented_kwargs(self, kwargs): + a = dpnp.arange(8, dtype="i4") + + numpy.clip(a.asnumpy(), 1, 5, **kwargs) + with pytest.raises(NotImplementedError): + dpnp.clip(a, 1, 5, **kwargs) + + class TestDiff: @pytest.mark.parametrize("n", list(range(0, 3))) @pytest.mark.parametrize("dt", get_integer_dtypes()) @@ -2147,63 +2240,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) -) -@pytest.mark.parametrize("order", ["C", "F", "A", "K", None]) -def test_clip(dtype, order): - dp_array = dpnp.asarray([[1, 2, 8], [1, 6, 4], [9, 5, 1]], dtype=dtype) - np_array = dpnp.asnumpy(dp_array) - - result = dpnp.clip(dp_array, 2, 6, order=order) - expected = numpy.clip(np_array, 2, 6, order=order) - assert_allclose(expected, result) - assert expected.flags.c_contiguous == result.flags.c_contiguous - assert expected.flags.f_contiguous == result.flags.f_contiguous - - -@pytest.mark.parametrize( - "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) -) -def test_clip_arrays(dtype): - dp_array = dpnp.asarray([1, 2, 8, 1, 6, 4, 1], dtype=dtype) - np_array = dpnp.asnumpy(dp_array) - - min_v = dpnp.asarray(2, dtype=dtype) - max_v = dpnp.asarray(6, dtype=dtype) - - result = dpnp.clip(dp_array, min_v, max_v) - expected = numpy.clip(np_array, min_v.asnumpy(), max_v.asnumpy()) - - assert_allclose(expected, result) - - -@pytest.mark.parametrize( - "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) -) -def test_clip_out(dtype): - dp_array = dpnp.asarray([[1, 2, 8], [1, 6, 4], [9, 5, 1]], dtype=dtype) - np_array = dpnp.asnumpy(dp_array) - - out = dpnp.zeros_like(dp_array) - - result = dpnp.clip(dp_array, 2, 6, out=out) - expected = numpy.clip(np_array, 2, 6) - assert_allclose(expected, out) - assert result is out - - -@pytest.mark.parametrize( - "dtype", get_all_dtypes(no_bool=True, no_none=True, no_complex=True) -) -def test_clip_out_dpt(dtype): - dp_array = dpnp.asarray([[1, 2, 8], [1, 6, 4], [9, 5, 1]], dtype=dtype) - np_array = dpnp.asnumpy(dp_array) - - out = dpt.zeros_like(dpnp.get_usm_ndarray(dp_array)) - - dpnp.clip(dp_array, 2, 6, out=out) - expected = numpy.clip(np_array, 2, 6) - assert_allclose(expected, out) diff --git a/tests/third_party/cupy/math_tests/test_misc.py b/tests/third_party/cupy/math_tests/test_misc.py index c05432e36427..241457fbad90 100644 --- a/tests/third_party/cupy/math_tests/test_misc.py +++ b/tests/third_party/cupy/math_tests/test_misc.py @@ -519,7 +519,7 @@ def test_convolve_non_contiguous(self, xp, dtype, mode): return xp.convolve(a[::200], b[10::70], mode=mode) @testing.for_all_dtypes(no_float16=True) - @testing.numpy_cupy_allclose(rtol=1e-4) + @testing.numpy_cupy_allclose(rtol=5e-4) def test_convolve_large_non_contiguous(self, xp, dtype, mode): a = testing.shaped_arange((10000,), xp, dtype) b = testing.shaped_arange((100,), xp, dtype)