From ef6df2f976e4c264854a256102712523dd49167c Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 3 Feb 2025 17:05:38 -0800 Subject: [PATCH] add explicit shape comparison --- dpnp/dpnp_iface_linearalgebra.py | 36 ++++++++++----- dpnp/dpnp_utils/dpnp_utils_linearalgebra.py | 2 +- dpnp/tests/helper.py | 40 ++++++++++++----- dpnp/tests/test_arraycreation.py | 4 -- dpnp/tests/test_arraypad.py | 11 ++--- dpnp/tests/test_fill.py | 14 +++--- dpnp/tests/test_histogram.py | 43 +++++++++++++----- dpnp/tests/test_indexing.py | 2 +- dpnp/tests/test_linalg.py | 8 ++-- dpnp/tests/test_logic.py | 10 ++++- dpnp/tests/test_mathematical.py | 7 +-- dpnp/tests/test_nanfunctions.py | 5 ++- dpnp/tests/test_random_state.py | 44 +++++++++---------- dpnp/tests/test_statistics.py | 2 - dpnp/tests/test_strides.py | 2 +- dpnp/tests/test_sum.py | 3 +- dpnp/tests/test_umath.py | 6 ++- dpnp/tests/testing/array.py | 28 ++++++++++++ dpnp/tests/third_party/cupy/testing/_array.py | 5 +++ 19 files changed, 176 insertions(+), 96 deletions(-) diff --git a/dpnp/dpnp_iface_linearalgebra.py b/dpnp/dpnp_iface_linearalgebra.py index fa2cb6136d67..8c381f9ec854 100644 --- a/dpnp/dpnp_iface_linearalgebra.py +++ b/dpnp/dpnp_iface_linearalgebra.py @@ -69,16 +69,31 @@ # TODO: implement a specific scalar-array kernel -def _call_multiply(a, b, out=None): - """Call multiply function for special cases of scalar-array dots.""" +def _call_multiply(a, b, out=None, outer_calc=False): + """ + Call multiply function for special cases of scalar-array dots. + + if `sc` is an scalar and `a` is an array of type float32, we have + dpnp.multiply(a, sc).dtype == dpnp.float32 and + numpy.multiply(a, sc).dtype == dpnp.float32. + + However, for scalar-array dots such as dot function we have + dpnp.dot(a, sc).dtype == dpnp.float32 while + numpy.dot(a, sc).dtype == dpnp.float64. + + We need to adjust the behavior of the multiply function when it is + used for special cases of scalar-array dots. + + """ sc, arr = (a, b) if dpnp.isscalar(a) else (b, a) sc_dtype = map_dtype_to_device(type(sc), arr.sycl_device) res_dtype = dpnp.result_type(sc_dtype, arr) + multiply_func = dpnp.multiply.outer if outer_calc else dpnp.multiply if out is not None and out.dtype == arr.dtype: - res = dpnp.multiply(a, b, out=out) + res = multiply_func(a, b, out=out) else: - res = dpnp.multiply(a, b, dtype=res_dtype) + res = multiply_func(a, b, dtype=res_dtype) return dpnp.get_result_array(res, out, casting="no") @@ -1109,16 +1124,15 @@ def outer(a, b, out=None): dpnp.check_supported_arrays_type(a, b, scalar_type=True, all_scalars=False) if dpnp.isscalar(a): - x1 = a x2 = dpnp.ravel(b)[None, :] + result = _call_multiply(a, x2, out=out, outer_calc=True) elif dpnp.isscalar(b): x1 = dpnp.ravel(a)[:, None] - x2 = b + result = _call_multiply(x1, b, out=out, outer_calc=True) else: - x1 = dpnp.ravel(a) - x2 = dpnp.ravel(b) + result = dpnp.multiply.outer(dpnp.ravel(a), dpnp.ravel(b), out=out) - return dpnp.multiply.outer(x1, x2, out=out) + return result def tensordot(a, b, axes=2): @@ -1288,13 +1302,13 @@ def vdot(a, b): if b.size != 1: raise ValueError("The second array should be of size one.") a_conj = numpy.conj(a) - return _call_multiply(a_conj, b) + return dpnp.squeeze(_call_multiply(a_conj, b)) if dpnp.isscalar(b): if a.size != 1: raise ValueError("The first array should be of size one.") a_conj = dpnp.conj(a) - return _call_multiply(a_conj, b) + return dpnp.squeeze(_call_multiply(a_conj, b)) if a.ndim == 1 and b.ndim == 1: return dpnp_dot(a, b, out=None, conjugate=True) diff --git a/dpnp/dpnp_utils/dpnp_utils_linearalgebra.py b/dpnp/dpnp_utils/dpnp_utils_linearalgebra.py index 71314c90272c..60a4375843fb 100644 --- a/dpnp/dpnp_utils/dpnp_utils_linearalgebra.py +++ b/dpnp/dpnp_utils/dpnp_utils_linearalgebra.py @@ -1108,7 +1108,7 @@ def dpnp_multiplication( result = dpnp.moveaxis(result, (-2, -1), axes_res) elif len(axes_res) == 1: result = dpnp.moveaxis(result, (-1,), axes_res) - return dpnp.ascontiguousarray(result) + return result return dpnp.asarray(result, order=order) diff --git a/dpnp/tests/helper.py b/dpnp/tests/helper.py index 56d8dd5ac2d2..a98310b3a0c1 100644 --- a/dpnp/tests/helper.py +++ b/dpnp/tests/helper.py @@ -10,13 +10,28 @@ from . import config +def _assert_dtype(a_dt, b_dt, check_only_type_kind=False): + if check_only_type_kind: + assert a_dt.kind == b_dt.kind, f"{a_dt.kind} != {b_dt.kind}" + else: + assert a_dt == b_dt, f"{a_dt} != {b_dt}" + + +def _assert_shape(a, b): + if hasattr(b, "shape"): + assert a.shape == b.shape, f"{a.shape} != {b.shape}" + else: + # numpy output is scalar, then dpnp is 0-D array + assert a.shape == (), f"{a.shape} != ()" + + def assert_dtype_allclose( dpnp_arr, numpy_arr, check_type=True, check_only_type_kind=False, factor=8, - relative_factor=None, + check_shape=True, ): """ Assert DPNP and NumPy array based on maximum dtype resolution of input arrays @@ -37,10 +52,13 @@ def assert_dtype_allclose( for all data types supported by DPNP when set to True. It is effective only when 'check_type' is also set to True. The parameter `factor` scales the resolution used for comparing the arrays. + The parameter `check_shape`, when True (default), asserts the shape of input arrays is the same. """ - list_64bit_types = [numpy.float64, numpy.complex128] + if check_shape: + _assert_shape(dpnp_arr, numpy_arr) + is_inexact = lambda x: hasattr(x, "dtype") and dpnp.issubdtype( x.dtype, dpnp.inexact ) @@ -57,34 +75,32 @@ def assert_dtype_allclose( else -dpnp.inf ) tol = factor * max(tol_dpnp, tol_numpy) - assert_allclose(dpnp_arr.asnumpy(), numpy_arr, atol=tol, rtol=tol) + assert_allclose(dpnp_arr, numpy_arr, atol=tol, rtol=tol, strict=False) if check_type: + list_64bit_types = [numpy.float64, numpy.complex128] numpy_arr_dtype = numpy_arr.dtype dpnp_arr_dtype = dpnp_arr.dtype dpnp_arr_dev = dpnp_arr.sycl_device if check_only_type_kind: - assert dpnp_arr_dtype.kind == numpy_arr_dtype.kind + _assert_dtype(dpnp_arr_dtype, numpy_arr_dtype, True) else: is_np_arr_f2 = numpy_arr_dtype == numpy.float16 if is_np_arr_f2: if has_support_aspect16(dpnp_arr_dev): - assert dpnp_arr_dtype == numpy_arr_dtype + _assert_dtype(dpnp_arr_dtype, numpy_arr_dtype) elif ( numpy_arr_dtype not in list_64bit_types or has_support_aspect64(dpnp_arr_dev) ): - assert dpnp_arr_dtype == numpy_arr_dtype + _assert_dtype(dpnp_arr_dtype, numpy_arr_dtype) else: - assert dpnp_arr_dtype.kind == numpy_arr_dtype.kind + _assert_dtype(dpnp_arr_dtype, numpy_arr_dtype, True) else: - assert_array_equal(dpnp_arr.asnumpy(), numpy_arr) + assert_array_equal(dpnp_arr, numpy_arr, strict=False) if check_type and hasattr(numpy_arr, "dtype"): - if check_only_type_kind: - assert dpnp_arr.dtype.kind == numpy_arr.dtype.kind - else: - assert dpnp_arr.dtype == numpy_arr.dtype + _assert_dtype(dpnp_arr.dtype, numpy_arr.dtype, check_only_type_kind) def generate_random_numpy_array( diff --git a/dpnp/tests/test_arraycreation.py b/dpnp/tests/test_arraycreation.py index 36a320c8cfd5..c801b769a7e2 100644 --- a/dpnp/tests/test_arraycreation.py +++ b/dpnp/tests/test_arraycreation.py @@ -952,7 +952,6 @@ def test_ascontiguousarray1(data): result = dpnp.ascontiguousarray(data) expected = numpy.ascontiguousarray(data) assert_dtype_allclose(result, expected) - assert result.shape == expected.shape @pytest.mark.parametrize("data", [(), 1, (2, 3), [4]]) @@ -960,7 +959,6 @@ def test_ascontiguousarray2(data): result = dpnp.ascontiguousarray(dpnp.array(data)) expected = numpy.ascontiguousarray(numpy.array(data)) assert_dtype_allclose(result, expected) - assert result.shape == expected.shape @pytest.mark.parametrize( @@ -970,7 +968,6 @@ def test_asfortranarray1(data): result = dpnp.asfortranarray(data) expected = numpy.asfortranarray(data) assert_dtype_allclose(result, expected) - assert result.shape == expected.shape @pytest.mark.parametrize("data", [(), 1, (2, 3), [4]]) @@ -978,7 +975,6 @@ def test_asfortranarray2(data): result = dpnp.asfortranarray(dpnp.array(data)) expected = numpy.asfortranarray(numpy.array(data)) assert_dtype_allclose(result, expected) - assert result.shape == expected.shape def test_meshgrid_raise_error(): diff --git a/dpnp/tests/test_arraypad.py b/dpnp/tests/test_arraypad.py index 16b7c23c75ef..795311105562 100644 --- a/dpnp/tests/test_arraypad.py +++ b/dpnp/tests/test_arraypad.py @@ -42,7 +42,6 @@ def test_basic(self, mode): result = dpnp.pad(a_dp, (25, 20), mode=mode) if mode == "empty": # omit uninitialized "empty" boundary from the comparison - assert result.shape == expected.shape assert_equal(result[25:-20], expected[25:-20]) else: assert_array_equal(result, expected) @@ -70,7 +69,6 @@ def test_non_contiguous_array(self, mode): result = dpnp.pad(a_dp, (2, 3), mode=mode) if mode == "empty": # omit uninitialized "empty" boundary from the comparison - assert result.shape == expected.shape assert_equal(result[2:-3, 2:-3], expected[2:-3, 2:-3]) else: assert_array_equal(result, expected) @@ -287,10 +285,10 @@ def test_linear_ramp_end_values(self): """Ensure that end values are exact.""" a_dp = dpnp.ones(10).reshape(2, 5) a = dpnp.pad(a_dp, (223, 123), mode="linear_ramp") - assert_equal(a[:, 0], 0.0) - assert_equal(a[:, -1], 0.0) - assert_equal(a[0, :], 0.0) - assert_equal(a[-1, :], 0.0) + assert_equal(a[:, 0], 0.0, strict=False) + assert_equal(a[:, -1], 0.0, strict=False) + assert_equal(a[0, :], 0.0, strict=False) + assert_equal(a[-1, :], 0.0, strict=False) @pytest.mark.parametrize( "dtype", [numpy.uint32, numpy.uint64] + get_all_dtypes(no_none=True) @@ -426,7 +424,6 @@ def test_empty(self): expected = numpy.pad(a_np, [(2, 3), (3, 1)], "empty") result = dpnp.pad(a_dp, [(2, 3), (3, 1)], "empty") # omit uninitialized "empty" boundary from the comparison - assert result.shape == expected.shape assert_equal(result[2:-3, 3:-1], expected[2:-3, 3:-1]) # Check how padding behaves on arrays with an empty dimension. diff --git a/dpnp/tests/test_fill.py b/dpnp/tests/test_fill.py index b5b82e4cf052..3102de395d93 100644 --- a/dpnp/tests/test_fill.py +++ b/dpnp/tests/test_fill.py @@ -38,7 +38,7 @@ def test_fill_strided_array(): expected = dpnp.tile(dpnp.asarray([0, 1], dtype=a.dtype), 50) b.fill(1) - assert_array_equal(b, 1) + assert_array_equal(b, 1, strict=False) assert_array_equal(a, expected) @@ -51,7 +51,7 @@ def test_fill_strided_2d_array(order): expected[::-2, ::2] = 1 b.fill(1) - assert_array_equal(b, 1) + assert_array_equal(b, 1, strict=False) assert_array_equal(a, expected) @@ -60,27 +60,27 @@ def test_fill_memset(order): a = dpnp.ones((10, 10), dtype="i4", order=order) a.fill(0) - assert_array_equal(a, 0) + assert_array_equal(a, 0, strict=False) def test_fill_float_complex_to_int(): a = dpnp.ones((10, 10), dtype="i4") a.fill(complex(2, 0)) - assert_array_equal(a, 2) + assert_array_equal(a, 2, strict=False) a.fill(float(3)) - assert_array_equal(a, 3) + assert_array_equal(a, 3, strict=False) def test_fill_complex_to_float(): a = dpnp.ones((10, 10), dtype="f4") a.fill(complex(2, 0)) - assert_array_equal(a, 2) + assert_array_equal(a, 2, strict=False) def test_fill_bool(): a = dpnp.full(5, fill_value=7, dtype="i4") a.fill(True) - assert_array_equal(a, 1) + assert_array_equal(a, 1, strict=False) diff --git a/dpnp/tests/test_histogram.py b/dpnp/tests/test_histogram.py index 06ec6f3fde67..a00312af3a5a 100644 --- a/dpnp/tests/test_histogram.py +++ b/dpnp/tests/test_histogram.py @@ -733,7 +733,8 @@ def test_bins(self, bins): expected_hist, expected_edges = numpy.histogramdd(v, bins) result_hist, result_edges = dpnp.histogramdd(iv, bins_dpnp) assert_allclose(result_hist, expected_hist) - assert_allclose(result_edges, expected_edges) + for x, y in zip(result_edges, expected_edges): + assert_allclose(x, y) def test_no_side_effects(self): v = dpnp.array([[1.3, 2.5, 2.3]]) @@ -752,7 +753,8 @@ def test_01d(self, data): result_hist, result_edges = dpnp.histogramdd(ia) assert_allclose(result_hist, expected_hist) - assert_allclose(result_edges, expected_edges) + for x, y in zip(result_edges, expected_edges): + assert_allclose(x, y) def test_3d(self): a = dpnp.ones((10, 10, 10)) @@ -822,7 +824,10 @@ def test_nan_values(self): ) result_hist, result_edges = dpnp.histogramdd(ione_nan, bins=[[0, 1]]) assert_allclose(result_hist, expected_hist) - assert_allclose(result_edges, expected_edges) + # dpnp returns both result_hist and result_edges as float64 while + # numpy returns result_hist as float64 but result_edges as int64 + for x, y in zip(result_edges, expected_edges): + assert_allclose(x, y, strict=False) # NaN is not counted expected_hist, expected_edges = numpy.histogramdd( @@ -830,7 +835,10 @@ def test_nan_values(self): ) result_hist, result_edges = dpnp.histogramdd(iall_nan, bins=[[0, 1]]) assert_allclose(result_hist, expected_hist) - assert_allclose(result_edges, expected_edges) + # dpnp returns both result_hist and result_edges as float64 while + # numpy returns result_hist as float64 but result_edges as int64 + for x, y in zip(result_edges, expected_edges): + assert_allclose(x, y, strict=False) def test_bins_another_sycl_queue(self): v = dpnp.arange(7, 12, sycl_queue=dpctl.SyclQueue()) @@ -866,7 +874,10 @@ def test_different_bins_amount(self, bins_count): expected_hist, expected_edges = numpy.histogramdd(v, bins=[bins_count]) result_hist, result_edges = dpnp.histogramdd(iv, bins=[bins_count]) assert_array_equal(result_hist, expected_hist) - assert_allclose(result_edges, expected_edges) + # dpnp returns both result_hist and result_edges as float64 while + # numpy returns result_hist as float64 but result_edges as float32 + for x, y in zip(result_edges, expected_edges): + assert_allclose(x, y, strict=False) class TestHistogram2d: @@ -1045,8 +1056,10 @@ def test_nan_values(self): ione_nan, ione_nan, bins=[[0, 1]] * 2 ) assert_allclose(result_hist, expected_hist) - assert_allclose(result_edges_x, expected_edges_x) - assert_allclose(result_edges_y, expected_edges_y) + # dpnp returns both result_hist and result_edges as float64 while + # numpy returns result_hist as float64 but result_edges as int64 + assert_allclose(result_edges_x, expected_edges_x, strict=False) + assert_allclose(result_edges_y, expected_edges_y, strict=False) # NaN is not counted expected_hist, expected_edges_x, expected_edges_y = numpy.histogram2d( @@ -1056,8 +1069,10 @@ def test_nan_values(self): iall_nan, iall_nan, bins=[[0, 1]] * 2 ) assert_allclose(result_hist, expected_hist) - assert_allclose(result_edges_x, expected_edges_x) - assert_allclose(result_edges_y, expected_edges_y) + # dpnp returns both result_hist and result_edges as float64 while + # numpy returns result_hist as float64 but result_edges as int64 + assert_allclose(result_edges_x, expected_edges_x, strict=False) + assert_allclose(result_edges_y, expected_edges_y, strict=False) def test_bins_another_sycl_queue(self): x = y = dpnp.arange(7, 12, sycl_queue=dpctl.SyclQueue()) @@ -1107,5 +1122,11 @@ def test_different_bins_amount(self, bins_count): ix, iy, bins=bins_count ) assert_array_equal(result_hist, expected_hist) - assert_allclose(result_edges_x, expected_edges_x, rtol=1e-6) - assert_allclose(result_edges_y, expected_edges_y, rtol=1e-6) + # dpnp returns both result_hist and result_edges as float64 while + # numpy returns result_hist as float64 but result_edges as float32 + assert_allclose( + result_edges_x, expected_edges_x, rtol=1e-6, strict=False + ) + assert_allclose( + result_edges_y, expected_edges_y, rtol=1e-6, strict=False + ) diff --git a/dpnp/tests/test_indexing.py b/dpnp/tests/test_indexing.py index 5439b4dc484e..7c69319f31b8 100644 --- a/dpnp/tests/test_indexing.py +++ b/dpnp/tests/test_indexing.py @@ -292,7 +292,7 @@ def test_indexing_array_negative_strides(self): slices = (slice(None), dpnp.array([0, 1, 2, 3])) arr[slices] = 10 - assert_array_equal(arr, 10.0) + assert_equal(arr, 10.0, strict=False) class TestIx: diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index 600a1b658514..33652c8cf5f7 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -2114,7 +2114,7 @@ def test_empty(self, shape, ord, axis, keepdims): # TODO: when similar changes in numpy are available, instead # of assert_equal with zero, we should compare with numpy # ord in [None, 1, 2] - assert_equal(dpnp.linalg.norm(ia, **kwarg), 0) + assert_equal(dpnp.linalg.norm(ia, **kwarg), 0.0) assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) else: result = dpnp.linalg.norm(ia, **kwarg) @@ -2323,7 +2323,8 @@ def test_matrix_norm(self, ord, keepdims): @pytest.mark.parametrize("ord", [None, "fro", "nuc", 1, 2, dpnp.inf]) def test_matrix_norm_empty(self, xp, dtype, shape, axis, ord): x = xp.zeros(shape, dtype=dtype) - assert_equal(xp.linalg.norm(x, axis=axis, ord=ord), 0) + sc = dtype(0.0) if dtype == dpnp.float32 else 0.0 + assert_equal(xp.linalg.norm(x, axis=axis, ord=ord), sc) @pytest.mark.parametrize( "xp", @@ -2343,7 +2344,8 @@ def test_matrix_norm_empty(self, xp, dtype, shape, axis, ord): @pytest.mark.parametrize("ord", [None, 1, 2, dpnp.inf]) def test_vector_norm_empty(self, xp, dtype, axis, ord): x = xp.zeros(0, dtype=dtype) - assert_equal(xp.linalg.vector_norm(x, axis=axis, ord=ord), 0) + sc = dtype(0.0) if dtype == dpnp.float32 else 0.0 + assert_equal(xp.linalg.vector_norm(x, axis=axis, ord=ord), sc) @testing.with_requires("numpy>=2.0") @pytest.mark.parametrize( diff --git a/dpnp/tests/test_logic.py b/dpnp/tests/test_logic.py index 3e6f88ee4442..4281279da450 100644 --- a/dpnp/tests/test_logic.py +++ b/dpnp/tests/test_logic.py @@ -1,6 +1,11 @@ import numpy import pytest -from numpy.testing import assert_allclose, assert_equal, assert_raises +from numpy.testing import ( + assert_allclose, + assert_array_equal, + assert_equal, + assert_raises, +) import dpnp @@ -36,7 +41,8 @@ def test_all_any_out(self, func, a_dtype, out_dtype): out = dpnp.empty(expected.shape, dtype=out_dtype) result = getattr(dpnp, func)(dp_array, out=out) assert out is result - assert_allclose(result, expected) + # out kwarg is not used with NumPy, dtype may differ + assert_array_equal(result, expected, strict=False) @pytest.mark.parametrize("func", ["all", "any"]) @pytest.mark.parametrize("axis", [None, 0, 1, (0, 1)]) diff --git a/dpnp/tests/test_mathematical.py b/dpnp/tests/test_mathematical.py index 7e917b665ee0..ee875823b6e4 100644 --- a/dpnp/tests/test_mathematical.py +++ b/dpnp/tests/test_mathematical.py @@ -353,13 +353,10 @@ def test_dtype(self, func, in_dt, dt): result = getattr(ia, func)(dtype=dt) assert_dtype_allclose(result, expected) - # TODO: include boolean dtype when dpctl-0.20.0 is being used in Internal CI @pytest.mark.usefixtures("suppress_complex_warning") @pytest.mark.parametrize("func", ["cumprod", "cumsum"]) @pytest.mark.parametrize("in_dt", get_all_dtypes(no_none=True)) - @pytest.mark.parametrize( - "out_dt", get_all_dtypes(no_none=True, no_bool=True) - ) + @pytest.mark.parametrize("out_dt", get_all_dtypes(no_none=True)) def test_out(self, func, in_dt, out_dt): a = generate_random_numpy_array(5, dtype=in_dt, low=-5, high=5) out = numpy.zeros_like(a, dtype=out_dt) @@ -1370,8 +1367,6 @@ def test_basic(self, axis, keepdims, dtype): expected = numpy.prod(a, axis=axis, keepdims=keepdims) result = dpnp.prod(ia, axis=axis, keepdims=keepdims) - - assert result.shape == expected.shape assert_dtype_allclose(result, expected) @pytest.mark.parametrize("axis", [None, 0, 1, -1, 2, -2, (1, 2), (0, -2)]) diff --git a/dpnp/tests/test_nanfunctions.py b/dpnp/tests/test_nanfunctions.py index ed0d95d2c7af..d92cee045a72 100644 --- a/dpnp/tests/test_nanfunctions.py +++ b/dpnp/tests/test_nanfunctions.py @@ -110,7 +110,9 @@ def test_allnans(self, func, dtype, array): result = getattr(dpnp, func)(ia) expected = getattr(numpy, func)(a) - assert_dtype_allclose(result, expected) + # for "0d" case, dpnp returns 0D array, numpy returns 1D array + # Array API indicates that the behavior is unspecified + assert_dtype_allclose(result, expected, check_shape=False) @pytest.mark.parametrize("axis", [None, 0, 1]) def test_empty(self, func, axis): @@ -511,7 +513,6 @@ def test_basic(self, func, axis, keepdims, dtype): expected = getattr(numpy, func)(a, axis=axis, keepdims=keepdims) result = getattr(dpnp, func)(ia, axis=axis, keepdims=keepdims) - assert result.shape == expected.shape assert_allclose(result, expected, rtol=1e-5) @pytest.mark.usefixtures("suppress_complex_warning") diff --git a/dpnp/tests/test_random_state.py b/dpnp/tests/test_random_state.py index fb483692a49a..ecc76611377a 100644 --- a/dpnp/tests/test_random_state.py +++ b/dpnp/tests/test_random_state.py @@ -100,7 +100,7 @@ def test_distr(self, dtype, usm_type): @pytest.mark.parametrize("dtype", [dpnp.float32, dpnp.float64, None]) @pytest.mark.parametrize("usm_type", list_of_usm_types) def test_scale(self, dtype, usm_type): - mean = 7.0 + mean = dtype(7.0) if dtype == dpnp.float32 else 7.0 rs = RandomState(39567) func = lambda scale: rs.normal( loc=mean, scale=scale, dtype=dtype, usm_type=usm_type @@ -135,7 +135,7 @@ def test_scale(self, dtype, usm_type): ) def test_inf_loc(self, loc): a = RandomState(6531).normal(loc=loc, scale=1, size=1000) - assert_equal(a, get_default_floating()(loc)) + assert_equal(a, get_default_floating()(loc), strict=False) def test_inf_scale(self): a = RandomState().normal(0, numpy.inf, size=1000) @@ -427,8 +427,8 @@ def test_negative_interval(self): assert -5 <= rs.randint(-5, -1) < -1 x = rs.randint(-7, -1, 5) - assert_equal(-7 <= x, True) - assert_equal(x < -1, True) + assert_equal(-7 <= x, True, strict=False) + assert_equal(x < -1, True, strict=False) def test_bounds_checking(self): dtype = dpnp.int32 @@ -466,13 +466,13 @@ def test_rng_zero_and_extremes(self): ) tgt = high - 1 - assert_equal(func(tgt, tgt + 1, size=1000), tgt) + assert_equal(func(tgt, tgt + 1, size=1000), tgt, strict=False) tgt = low - assert_equal(func(tgt, tgt + 1, size=1000), tgt) + assert_equal(func(tgt, tgt + 1, size=1000), tgt, strict=False) tgt = (low + high) // 2 - assert_equal(func(tgt, tgt + 1, size=1000), tgt) + assert_equal(func(tgt, tgt + 1, size=1000), tgt, strict=False) def test_full_range(self): dtype = dpnp.int32 @@ -972,31 +972,29 @@ def test_distr(self, bounds, dtype, usm_type): dtype = get_default_floating() if dtype is None else dtype if sycl_queue.sycl_device.is_cpu: if dtype != dpnp.int32: - expected = numpy.array( - [ - [4.023770128630567, 8.87456423597643], - [2.888630247435067, 4.823004481580574], - [2.030351535445079, 4.533497077834326], - ] - ) + data = [ + [4.023770128630567, 8.87456423597643], + [2.888630247435067, 4.823004481580574], + [2.030351535445079, 4.533497077834326], + ] + expected = numpy.array(data, dtype=dtype) precision = dpnp.finfo(dtype).precision assert_array_almost_equal(actual, expected, decimal=precision) else: - expected = numpy.array([[3, 8], [2, 4], [1, 4]]) + expected = numpy.array([[3, 8], [2, 4], [1, 4]], dtype=dtype) assert_array_equal(actual, expected) else: if dtype != dpnp.int32: - expected = numpy.array( - [ - [1.230000000452886, 4.889115418092382], - [6.084098950993071, 1.682066500463302], - [3.316473517549554, 8.428297791221597], - ] - ) + data = [ + [1.230000000452886, 4.889115418092382], + [6.084098950993071, 1.682066500463302], + [3.316473517549554, 8.428297791221597], + ] + expected = numpy.array(data, dtype=dtype) precision = dpnp.finfo(dtype).precision assert_array_almost_equal(actual, expected, decimal=precision) else: - expected = numpy.array([[1, 4], [5, 1], [3, 7]]) + expected = numpy.array([[1, 4], [5, 1], [3, 7]], dtype=dtype) assert_array_equal(actual, expected) # check if compute follows data isn't broken diff --git a/dpnp/tests/test_statistics.py b/dpnp/tests/test_statistics.py index efcc0ae20437..cf436087b607 100644 --- a/dpnp/tests/test_statistics.py +++ b/dpnp/tests/test_statistics.py @@ -348,7 +348,6 @@ def test_corrcoef_dtype(self, dt_in, dt_out): expected = numpy.corrcoef(a, dtype=dt_out) result = dpnp.corrcoef(ia, dtype=dt_out) - assert expected.dtype == result.dtype assert_allclose(result, expected, rtol=1e-6) @pytest.mark.usefixtures( @@ -1132,7 +1131,6 @@ def test_dtype(self, func, dt_in, dt_out): expected = getattr(numpy, func)(a, dtype=dt_out) result = getattr(dpnp, func)(ia, dtype=dt_out) - assert expected.dtype == result.dtype assert_allclose(result, expected, rtol=1e-6) @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) diff --git a/dpnp/tests/test_strides.py b/dpnp/tests/test_strides.py index 3665fb05c069..712bc7c91df3 100644 --- a/dpnp/tests/test_strides.py +++ b/dpnp/tests/test_strides.py @@ -251,7 +251,7 @@ def test_bitwise(func, dtype): result = getattr(dpnp, func)(ia, ib) expected = getattr(numpy, func)(a, b) - assert_array_equal(result, expected, strict=True) + assert_array_equal(result, expected) @pytest.mark.parametrize("dtype", get_integer_float_dtypes()) diff --git a/dpnp/tests/test_sum.py b/dpnp/tests/test_sum.py index 68dd14ab7fdf..eaee7efae8e1 100644 --- a/dpnp/tests/test_sum.py +++ b/dpnp/tests/test_sum.py @@ -126,7 +126,8 @@ def test_sum_out(dtype, axis): expected = numpy.sum(a_np, axis=axis) res = dpnp.empty(expected.shape, dtype=dtype) a.sum(axis=axis, out=res) - assert_array_equal(expected, res) + # NumPy result is without out keyword, dtype may differ + assert_array_equal(res, expected, strict=False) @pytest.mark.usefixtures("suppress_complex_warning") diff --git a/dpnp/tests/test_umath.py b/dpnp/tests/test_umath.py index 53a5d8d37bc9..56f55de2f1c7 100644 --- a/dpnp/tests/test_umath.py +++ b/dpnp/tests/test_umath.py @@ -264,7 +264,8 @@ def test_negative_base_value(self, dt): result = dpnp.float_power(ia, 1.5) expected = numpy.float_power(a, 1.5) - assert_allclose(result, expected) + # numpy and dpnp promote the result differently + assert_allclose(result, expected, strict=False) @pytest.mark.parametrize( "dt", get_all_dtypes(no_none=True, no_unsigned=True) @@ -290,7 +291,8 @@ def test_nan_infs_base(self, exp_val, dtype): result = dpnp.float_power(ia, exp_val) expected = numpy.float_power(a, exp_val) - assert_allclose(result, expected) + # numpy and dpnp promote the result differently + assert_allclose(result, expected, strict=False) class TestLogAddExp: diff --git a/dpnp/tests/testing/array.py b/dpnp/tests/testing/array.py index df4db0855dd2..cd6f53e3260c 100644 --- a/dpnp/tests/testing/array.py +++ b/dpnp/tests/testing/array.py @@ -24,6 +24,7 @@ # THE POSSIBILITY OF SUCH DAMAGE. # ***************************************************************************** +import dpctl import numpy from dpnp.dpnp_utils import convert_item @@ -39,6 +40,33 @@ def _assert(assert_func, result, expected, *args, **kwargs): result = convert_item(result) expected = convert_item(expected) + # original versions of assert_equal, assert_array_equal, and assert_allclose + # (since NumPy 2.0) have `strict` parameter. Added here for + # assert_almost_equal, assert_array_almost_equal + flag = assert_func in [ + assert_almost_equal_orig, + assert_array_almost_equal_orig, + ] + # For numpy < 2.0, some tests will fail for dtype mismatch + dev = dpctl.select_default_device() + if numpy.__version__ >= "2.0.0" and dev.has_aspect_fp64: + kwargs.setdefault("strict", True) + if flag: + if kwargs.get("strict"): + if hasattr(expected, "dtype"): + assert ( + result.dtype == expected.dtype + ), f"{result.dtype} != {expected.dtype}" + assert ( + result.shape == expected.shape + ), f"{result.shape} != {expected.shape}" + else: + # numpy output is scalar, then dpnp is 0-D array + assert result.shape == (), f"{result.shape} != ()" + kwargs.pop("strict") + else: + kwargs.pop("strict", None) + assert_func(result, expected, *args, **kwargs) diff --git a/dpnp/tests/third_party/cupy/testing/_array.py b/dpnp/tests/third_party/cupy/testing/_array.py index bda9ac22eedb..c290b0bc7707 100644 --- a/dpnp/tests/third_party/cupy/testing/_array.py +++ b/dpnp/tests/third_party/cupy/testing/_array.py @@ -29,6 +29,7 @@ def assert_allclose( atol=atol, err_msg=err_msg, verbose=verbose, + strict=False, ) @@ -51,6 +52,7 @@ def assert_array_almost_equal(x, y, decimal=6, err_msg="", verbose=True): decimal=decimal, err_msg=err_msg, verbose=verbose, + strict=False, ) @@ -105,11 +107,14 @@ def assert_array_equal( .. seealso:: :func:`numpy.testing.assert_array_equal` """ + + strict = kwargs.get("strict", False) numpy.testing.assert_array_equal( cupy.asnumpy(x), cupy.asnumpy(y), err_msg=err_msg, verbose=verbose, + strict=strict, **kwargs, )