From 2b1ac6df065ee1afc35397936a813a7eea1de2d2 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Tue, 18 Feb 2025 10:37:54 -0800 Subject: [PATCH 1/6] fix_issue-2319 --- dpnp/linalg/dpnp_utils_linalg.py | 7 ++ dpnp/tests/test_linalg.py | 140 +++++++++++++++++-------------- 2 files changed, 83 insertions(+), 64 deletions(-) diff --git a/dpnp/linalg/dpnp_utils_linalg.py b/dpnp/linalg/dpnp_utils_linalg.py index c5fafa7f342f..6edd2d10c260 100644 --- a/dpnp/linalg/dpnp_utils_linalg.py +++ b/dpnp/linalg/dpnp_utils_linalg.py @@ -2401,10 +2401,17 @@ def dpnp_norm(x, ord=None, axis=None, keepdims=False): axis = (axis,) if len(axis) == 1: + if x.shape[axis[0]] == 0 and ord in [1, 2, dpnp.inf]: + x = dpnp.moveaxis(x, axis, -1) + return dpnp.zeros_like(x, shape=x.shape[:-1]) axis = normalize_axis_index(axis[0], ndim) return _norm_int_axis(x, ord, axis, keepdims) if len(axis) == 2: + flag = x.shape[axis[0]] == 0 or x.shape[axis[1]] == 0 + if flag and ord in ["fro", "nuc", 1, 2, dpnp.inf]: + x = dpnp.moveaxis(x, axis, (-2, -1)) + return dpnp.zeros_like(x, shape=x.shape[:-2]) row_axis, col_axis = axis row_axis = normalize_axis_index(row_axis, ndim) col_axis = normalize_axis_index(col_axis, ndim) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index 46fbad6dcb9b..4ae3ce580c13 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -8,6 +8,7 @@ assert_allclose, assert_almost_equal, assert_array_equal, + assert_equal, assert_raises, assert_raises_regex, suppress_warnings, @@ -2087,29 +2088,29 @@ def setup_method(self): def test_empty(self, shape, ord, axis, keepdims): a = numpy.empty(shape) ia = dpnp.array(a) + kwarg = {"ord": ord, "axis": axis, "keepdims": keepdims} + if axis is None and a.ndim > 1 and ord in [0, 3]: # Invalid norm order for matrices (a.ndim == 2) or # Improper number of dimensions to norm (a.ndim>2) - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) + assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) elif axis is None and a.ndim > 2 and ord is not None: # Improper number of dimensions to norm - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) + assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) elif ( axis is None - and ord is not None + and ord in [-2, -1, 0, 3] and a.ndim != 1 and a.shape[-1] == 0 ): # reduction cannot be performed over zero-size axes - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) + assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) else: - result = dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) - expected = numpy.linalg.norm( - a, ord=ord, axis=axis, keepdims=keepdims - ) + result = dpnp.linalg.norm(ia, **kwarg) + expected = numpy.linalg.norm(a, **kwarg) assert_dtype_allclose(result, expected) @pytest.mark.parametrize( @@ -2121,11 +2122,11 @@ def test_0D(self, ord, axis): ia = dpnp.array(a) if axis is None and ord is not None: # Improper number of dimensions to norm - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, ord=ord, axis=axis) + assert_raises(ValueError, dpnp.linalg.norm, ia, ord=ord, axis=axis) + assert_raises(ValueError, numpy.linalg.norm, a, ord=ord, axis=axis) elif axis is not None: - with pytest.raises(AxisError): - dpnp.linalg.norm(ia, ord=ord, axis=axis) + assert_raises(IndexError, dpnp.linalg.norm, ia, ord=ord, axis=axis) + assert_raises(AxisError, numpy.linalg.norm, a, ord=ord, axis=axis) else: result = dpnp.linalg.norm(ia, ord=ord, axis=axis) expected = numpy.linalg.norm(a, ord=ord, axis=axis) @@ -2158,24 +2159,21 @@ def test_1D(self, dtype, ord, axis, keepdims): def test_2D(self, dtype, ord, axis, keepdims): a = generate_random_numpy_array((3, 5), dtype) ia = dpnp.array(a) + kwarg = {"ord": ord, "axis": axis, "keepdims": keepdims} + if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( (isinstance(axis, tuple) or axis is None) and ord == 3 ): # Invalid norm order for vectors - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) + assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) else: - result = dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) - expected = numpy.linalg.norm( - a, ord=ord, axis=axis, keepdims=keepdims - ) + result = dpnp.linalg.norm(ia, **kwarg) + expected = numpy.linalg.norm(a, **kwarg) assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") - @pytest.mark.parametrize( - "dtype", - get_all_dtypes(no_none=True), - ) + @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) @pytest.mark.parametrize( "ord", [None, -dpnp.inf, -2, -1, 1, 2, 3, dpnp.inf, "fro", "nuc"] ) @@ -2188,21 +2186,21 @@ def test_2D(self, dtype, ord, axis, keepdims): def test_ND(self, dtype, ord, axis, keepdims): a = generate_random_numpy_array((2, 3, 4, 5), dtype) ia = dpnp.array(a) + kwarg = {"ord": ord, "axis": axis, "keepdims": keepdims} + if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( isinstance(axis, tuple) and ord == 3 ): # Invalid norm order for vectors - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) + assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) elif axis is None and ord is not None: # Improper number of dimensions to norm - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) + assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) else: - result = dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) - expected = numpy.linalg.norm( - a, ord=ord, axis=axis, keepdims=keepdims - ) + result = dpnp.linalg.norm(ia, **kwarg) + expected = numpy.linalg.norm(a, **kwarg) assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_divide_numpy_warnings") @@ -2219,21 +2217,21 @@ def test_ND(self, dtype, ord, axis, keepdims): def test_usm_ndarray(self, dtype, ord, axis, keepdims): a = generate_random_numpy_array((2, 3, 4, 5), dtype) ia = dpt.asarray(a) + kwarg = {"ord": ord, "axis": axis, "keepdims": keepdims} + if (axis in [-1, 0, 1] and ord in ["nuc", "fro"]) or ( isinstance(axis, tuple) and ord == 3 ): # Invalid norm order for vectors - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) + assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) elif axis is None and ord is not None: # Improper number of dimensions to norm - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) + assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) + assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) else: - result = dpnp.linalg.norm(ia, ord=ord, axis=axis, keepdims=keepdims) - expected = numpy.linalg.norm( - a, ord=ord, axis=axis, keepdims=keepdims - ) + result = dpnp.linalg.norm(ia, **kwarg) + expected = numpy.linalg.norm(a, **kwarg) assert_dtype_allclose(result, expected) @pytest.mark.parametrize("stride", [3, -1, -5]) @@ -2257,8 +2255,7 @@ def test_strided_2D(self, axis, stride): A = numpy.random.rand(20, 30) B = dpnp.asarray(A) slices = tuple(slice(None, None, stride[i]) for i in range(A.ndim)) - a = A[slices] - b = B[slices] + a, b = A[slices], B[slices] result = dpnp.linalg.norm(b, axis=axis) expected = numpy.linalg.norm(a, axis=axis) @@ -2278,8 +2275,7 @@ def test_strided_ND(self, axis, stride): A = numpy.random.rand(12, 16, 20, 24) B = dpnp.asarray(A) slices = tuple(slice(None, None, stride[i]) for i in range(A.ndim)) - a = A[slices] - b = B[slices] + a, b = A[slices], B[slices] result = dpnp.linalg.norm(b, axis=axis) expected = numpy.linalg.norm(a, axis=axis) @@ -2299,6 +2295,28 @@ def test_matrix_norm(self, ord, keepdims): expected = numpy.linalg.matrix_norm(a, ord=ord, keepdims=keepdims) assert_dtype_allclose(result, expected) + @pytest.mark.parametrize("dtype", [dpnp.float32, dpnp.int32]) + @pytest.mark.parametrize( + "shape_axis", [[(2, 0), None], [(2, 0, 3), (0, 1)]] + ) + def test_matrix_norm_empty(self, dtype, shape_axis): + shape, axis = shape_axis[0], shape_axis[1] + x = dpnp.zeros(shape, dtype=dtype) + + assert_equal(dpnp.linalg.norm(x, axis=axis, ord="fro"), 0) + assert_equal(dpnp.linalg.norm(x, axis=axis, ord="nuc"), 0) + assert_equal(dpnp.linalg.norm(x, axis=axis, ord=2), 0) + assert_equal(dpnp.linalg.norm(x, axis=axis, ord=1), 0) + assert_equal(dpnp.linalg.norm(x, axis=axis, ord=dpnp.inf), 0) + + @pytest.mark.parametrize("dtype", [dpnp.float32, dpnp.int32]) + @pytest.mark.parametrize("axis", [None, 0]) + def test_vector_norm_empty(self, dtype, axis): + x = dpnp.zeros(0, dtype=dtype) + assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=1), 0) + assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=2), 0) + assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=dpnp.inf), 0) + @testing.with_requires("numpy>=2.0") @pytest.mark.parametrize( "ord", [None, -dpnp.inf, -2, -1, 0, 1, 2, 3.5, dpnp.inf] @@ -2320,13 +2338,10 @@ def test_vector_norm_0D(self, ord): def test_vector_norm_1D(self, ord, axis, keepdims): a = generate_random_numpy_array(10) ia = dpnp.array(a) + kwarg = {"ord": ord, "axis": axis, "keepdims": keepdims} - result = dpnp.linalg.vector_norm( - ia, ord=ord, axis=axis, keepdims=keepdims - ) - expected = numpy.linalg.vector_norm( - a, ord=ord, axis=axis, keepdims=keepdims - ) + result = dpnp.linalg.vector_norm(ia, **kwarg) + expected = numpy.linalg.vector_norm(a, **kwarg) assert_dtype_allclose(result, expected) @testing.with_requires("numpy>=2.0") @@ -2343,29 +2358,26 @@ def test_vector_norm_1D(self, ord, axis, keepdims): def test_vector_norm_ND(self, ord, axis, keepdims): a = numpy.arange(120).reshape(2, 3, 4, 5) ia = dpnp.array(a) + kwarg = {"ord": ord, "axis": axis, "keepdims": keepdims} - result = dpnp.linalg.vector_norm( - ia, ord=ord, axis=axis, keepdims=keepdims - ) - expected = numpy.linalg.vector_norm( - a, ord=ord, axis=axis, keepdims=keepdims - ) + result = dpnp.linalg.vector_norm(ia, **kwarg) + expected = numpy.linalg.vector_norm(a, **kwarg) assert_dtype_allclose(result, expected) def test_error(self): - ia = dpnp.arange(120).reshape(2, 3, 4, 5) + a = numpy.arange(120).reshape(2, 3, 4, 5) + ia = dpnp.array(a) # Duplicate axes given - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, axis=(2, 2)) + assert_raises(ValueError, dpnp.linalg.norm, ia, axis=(2, 2)) + assert_raises(ValueError, numpy.linalg.norm, a, axis=(2, 2)) #'axis' must be None, an integer or a tuple of integers - with pytest.raises(TypeError): - dpnp.linalg.norm(ia, axis=[2]) + assert_raises(TypeError, dpnp.linalg.norm, ia, axis=[2]) + assert_raises(TypeError, numpy.linalg.norm, a, axis=[2]) # Invalid norm order for vectors - with pytest.raises(ValueError): - dpnp.linalg.norm(ia, axis=1, ord=[3]) + assert_raises(ValueError, dpnp.linalg.norm, ia, axis=1, ord=[3]) class TestQr: From 79aca8f52e741fca63eaaf2e8055fa21971c4eca Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 17 Mar 2025 09:29:12 -0700 Subject: [PATCH 2/6] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8edbfe38d09..400901d4160d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * Allowed input array of `uint64` dtype in `dpnp.bincount` [#2361](https://github.com/IntelPython/dpnp/pull/2361) +* The vector norms `ord={1, 2, inf}` and the matrix norms `ord={1, 2, inf, "fro", "nuc"}` now consistently return zero for empty arrays, which are arrays with at least one axis of size zero. This change affects `dpnp.linalg.norm`, `dpnp.linalg.vector_norm`, and `dpnp.linalg.matrix_norm`. Previously, dpnp would either raise errors or return zero depending on the parameters provided [#2371](https://github.com/IntelPython/dpnp/pull/2371) ### Fixed From 1d360addf7d2cbe1a87f19f8bacd5da26139fc34 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Mon, 17 Mar 2025 10:57:17 -0700 Subject: [PATCH 3/6] add a workaround --- dpnp/tests/test_linalg.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index 4ae3ce580c13..ccd8ea4d5813 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -2075,9 +2075,6 @@ def test_matrix_transpose(): class TestNorm: - def setup_method(self): - numpy.random.seed(42) - @pytest.mark.usefixtures("suppress_divide_numpy_warnings") @pytest.mark.parametrize( "shape", [(0,), (5, 0), (2, 0, 3)], ids=["(0,)", "(5, 0)", "(2, 0, 3)"] @@ -2099,15 +2096,16 @@ def test_empty(self, shape, ord, axis, keepdims): # Improper number of dimensions to norm assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) - elif ( - axis is None - and ord in [-2, -1, 0, 3] - and a.ndim != 1 - and a.shape[-1] == 0 - ): - # reduction cannot be performed over zero-size axes - assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) - assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) + elif axis is None and a.ndim != 1 and a.shape[-1] == 0: + # TODO: when similar changes in numpy are available, + # instead of assert_equal with zero, we should compare with numpy + if ord in [-2, -1, 0, 3]: + # reduction cannot be performed over zero-size axes + assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) + assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) + else: + # ord in [None, 1, 2] + assert_equal(dpnp.linalg.norm(ia, **kwarg), 0) else: result = dpnp.linalg.norm(ia, **kwarg) expected = numpy.linalg.norm(a, **kwarg) @@ -2303,6 +2301,8 @@ def test_matrix_norm_empty(self, dtype, shape_axis): shape, axis = shape_axis[0], shape_axis[1] x = dpnp.zeros(shape, dtype=dtype) + # TODO: when similar changes in numpy are available, + # instead of assert_equal with zero, we should compare with numpy assert_equal(dpnp.linalg.norm(x, axis=axis, ord="fro"), 0) assert_equal(dpnp.linalg.norm(x, axis=axis, ord="nuc"), 0) assert_equal(dpnp.linalg.norm(x, axis=axis, ord=2), 0) @@ -2313,6 +2313,8 @@ def test_matrix_norm_empty(self, dtype, shape_axis): @pytest.mark.parametrize("axis", [None, 0]) def test_vector_norm_empty(self, dtype, axis): x = dpnp.zeros(0, dtype=dtype) + # TODO: when similar changes in numpy are available, + # instead of assert_equal with zero, we should compare with numpy assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=1), 0) assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=2), 0) assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=dpnp.inf), 0) From fb57ef25ae3aacf5393a3cea61198dbb05a3966e Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Tue, 18 Mar 2025 13:25:28 -0700 Subject: [PATCH 4/6] address comments --- CHANGELOG.md | 2 +- dpnp/linalg/dpnp_utils_linalg.py | 14 +++++++------- dpnp/tests/test_linalg.py | 8 +++++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 400901d4160d..8fb9bc8029df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * Allowed input array of `uint64` dtype in `dpnp.bincount` [#2361](https://github.com/IntelPython/dpnp/pull/2361) -* The vector norms `ord={1, 2, inf}` and the matrix norms `ord={1, 2, inf, "fro", "nuc"}` now consistently return zero for empty arrays, which are arrays with at least one axis of size zero. This change affects `dpnp.linalg.norm`, `dpnp.linalg.vector_norm`, and `dpnp.linalg.matrix_norm`. Previously, dpnp would either raise errors or return zero depending on the parameters provided [#2371](https://github.com/IntelPython/dpnp/pull/2371) +* The vector norms `ord={None, 1, 2, inf}` and the matrix norms `ord={None, 1, 2, inf, "fro", "nuc"}` now consistently return zero for empty arrays, which are arrays with at least one axis of size zero. This change affects `dpnp.linalg.norm`, `dpnp.linalg.vector_norm`, and `dpnp.linalg.matrix_norm`. Previously, dpnp would either raise errors or return zero depending on the parameters provided [#2371](https://github.com/IntelPython/dpnp/pull/2371) ### Fixed diff --git a/dpnp/linalg/dpnp_utils_linalg.py b/dpnp/linalg/dpnp_utils_linalg.py index 6edd2d10c260..5cd9832cff9d 100644 --- a/dpnp/linalg/dpnp_utils_linalg.py +++ b/dpnp/linalg/dpnp_utils_linalg.py @@ -1185,6 +1185,9 @@ def _norm_int_axis(x, ord, axis, keepdims): """ if ord == dpnp.inf: + if x.shape[axis] == 0: + x = dpnp.moveaxis(x, axis, -1) + return dpnp.zeros_like(x, shape=x.shape[:-1]) return dpnp.abs(x).max(axis=axis, keepdims=keepdims) if ord == -dpnp.inf: return dpnp.abs(x).min(axis=axis, keepdims=keepdims) @@ -1220,6 +1223,10 @@ def _norm_tuple_axis(x, ord, row_axis, col_axis, keepdims): """ axis = (row_axis, col_axis) + flag = x.shape[row_axis] == 0 or x.shape[col_axis] == 0 + if flag and ord in [1, 2, dpnp.inf]: + x = dpnp.moveaxis(x, axis, (-2, -1)) + return dpnp.zeros_like(x, shape=x.shape[:-2]) if row_axis == col_axis: raise ValueError("Duplicate axes given.") if ord == 2: @@ -2401,17 +2408,10 @@ def dpnp_norm(x, ord=None, axis=None, keepdims=False): axis = (axis,) if len(axis) == 1: - if x.shape[axis[0]] == 0 and ord in [1, 2, dpnp.inf]: - x = dpnp.moveaxis(x, axis, -1) - return dpnp.zeros_like(x, shape=x.shape[:-1]) axis = normalize_axis_index(axis[0], ndim) return _norm_int_axis(x, ord, axis, keepdims) if len(axis) == 2: - flag = x.shape[axis[0]] == 0 or x.shape[axis[1]] == 0 - if flag and ord in ["fro", "nuc", 1, 2, dpnp.inf]: - x = dpnp.moveaxis(x, axis, (-2, -1)) - return dpnp.zeros_like(x, shape=x.shape[:-2]) row_axis, col_axis = axis row_axis = normalize_axis_index(row_axis, ndim) col_axis = normalize_axis_index(col_axis, ndim) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index ccd8ea4d5813..b7b9066a4d37 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -2097,13 +2097,13 @@ def test_empty(self, shape, ord, axis, keepdims): assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) elif axis is None and a.ndim != 1 and a.shape[-1] == 0: - # TODO: when similar changes in numpy are available, - # instead of assert_equal with zero, we should compare with numpy if ord in [-2, -1, 0, 3]: # reduction cannot be performed over zero-size axes assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) else: + # 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) else: @@ -2295,7 +2295,7 @@ def test_matrix_norm(self, ord, keepdims): @pytest.mark.parametrize("dtype", [dpnp.float32, dpnp.int32]) @pytest.mark.parametrize( - "shape_axis", [[(2, 0), None], [(2, 0, 3), (0, 1)]] + "shape_axis", [[(2, 0), None], [(2, 0), (0, 1)], [(0, 2), (0, 1)]] ) def test_matrix_norm_empty(self, dtype, shape_axis): shape, axis = shape_axis[0], shape_axis[1] @@ -2303,6 +2303,7 @@ def test_matrix_norm_empty(self, dtype, shape_axis): # TODO: when similar changes in numpy are available, # instead of assert_equal with zero, we should compare with numpy + assert_equal(dpnp.linalg.norm(x, axis=axis), 0) assert_equal(dpnp.linalg.norm(x, axis=axis, ord="fro"), 0) assert_equal(dpnp.linalg.norm(x, axis=axis, ord="nuc"), 0) assert_equal(dpnp.linalg.norm(x, axis=axis, ord=2), 0) @@ -2315,6 +2316,7 @@ def test_vector_norm_empty(self, dtype, axis): x = dpnp.zeros(0, dtype=dtype) # TODO: when similar changes in numpy are available, # instead of assert_equal with zero, we should compare with numpy + assert_equal(dpnp.linalg.vector_norm(x, axis=axis), 0) assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=1), 0) assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=2), 0) assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=dpnp.inf), 0) From 63fc17887228142053c5f24088fbfb32db0b71d0 Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Wed, 19 Mar 2025 07:15:23 -0700 Subject: [PATCH 5/6] update tests --- dpnp/tests/test_linalg.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index b7b9066a4d37..c1b4194daa88 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -2096,7 +2096,12 @@ def test_empty(self, shape, ord, axis, keepdims): # Improper number of dimensions to norm assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) - elif axis is None and a.ndim != 1 and a.shape[-1] == 0: + elif ( + axis is None + and ord is not None + and a.ndim != 1 + and a.shape[-1] == 0 + ): if ord in [-2, -1, 0, 3]: # reduction cannot be performed over zero-size axes assert_raises(ValueError, dpnp.linalg.norm, ia, **kwarg) @@ -2106,6 +2111,7 @@ def test_empty(self, shape, ord, axis, keepdims): # of assert_equal with zero, we should compare with numpy # ord in [None, 1, 2] assert_equal(dpnp.linalg.norm(ia, **kwarg), 0) + assert_raises(ValueError, numpy.linalg.norm, a, **kwarg) else: result = dpnp.linalg.norm(ia, **kwarg) expected = numpy.linalg.norm(a, **kwarg) @@ -2297,29 +2303,23 @@ def test_matrix_norm(self, ord, keepdims): @pytest.mark.parametrize( "shape_axis", [[(2, 0), None], [(2, 0), (0, 1)], [(0, 2), (0, 1)]] ) - def test_matrix_norm_empty(self, dtype, shape_axis): + @pytest.mark.parametrize("ord", [None, "fro", "nuc", 1, 2, dpnp.inf]) + def test_matrix_norm_empty(self, dtype, shape_axis, ord): shape, axis = shape_axis[0], shape_axis[1] x = dpnp.zeros(shape, dtype=dtype) # TODO: when similar changes in numpy are available, # instead of assert_equal with zero, we should compare with numpy - assert_equal(dpnp.linalg.norm(x, axis=axis), 0) - assert_equal(dpnp.linalg.norm(x, axis=axis, ord="fro"), 0) - assert_equal(dpnp.linalg.norm(x, axis=axis, ord="nuc"), 0) - assert_equal(dpnp.linalg.norm(x, axis=axis, ord=2), 0) - assert_equal(dpnp.linalg.norm(x, axis=axis, ord=1), 0) - assert_equal(dpnp.linalg.norm(x, axis=axis, ord=dpnp.inf), 0) + assert_equal(dpnp.linalg.norm(x, axis=axis, ord=ord), 0) @pytest.mark.parametrize("dtype", [dpnp.float32, dpnp.int32]) @pytest.mark.parametrize("axis", [None, 0]) - def test_vector_norm_empty(self, dtype, axis): + @pytest.mark.parametrize("ord", [None, 1, 2, dpnp.inf]) + def test_vector_norm_empty(self, dtype, axis, ord): x = dpnp.zeros(0, dtype=dtype) # TODO: when similar changes in numpy are available, # instead of assert_equal with zero, we should compare with numpy - assert_equal(dpnp.linalg.vector_norm(x, axis=axis), 0) - assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=1), 0) - assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=2), 0) - assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=dpnp.inf), 0) + assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=ord), 0) @testing.with_requires("numpy>=2.0") @pytest.mark.parametrize( From 3001a9e8e4133402d722b053f2a56a7db87f7b3b Mon Sep 17 00:00:00 2001 From: Vahid Tavanashad Date: Wed, 19 Mar 2025 10:37:13 -0700 Subject: [PATCH 6/6] add parametrize xp --- dpnp/tests/test_linalg.py | 44 +++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index c1b4194daa88..07533f159d76 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -25,6 +25,7 @@ has_support_aspect64, is_cpu_device, is_cuda_device, + numpy_version, ) from .third_party.cupy import testing @@ -2299,27 +2300,48 @@ def test_matrix_norm(self, ord, keepdims): expected = numpy.linalg.matrix_norm(a, ord=ord, keepdims=keepdims) assert_dtype_allclose(result, expected) + @pytest.mark.parametrize( + "xp", + [ + dpnp, + pytest.param( + numpy, + marks=pytest.mark.skipif( + numpy_version() < "2.3.0", + reason="numpy raises an error", + ), + ), + ], + ) @pytest.mark.parametrize("dtype", [dpnp.float32, dpnp.int32]) @pytest.mark.parametrize( "shape_axis", [[(2, 0), None], [(2, 0), (0, 1)], [(0, 2), (0, 1)]] ) @pytest.mark.parametrize("ord", [None, "fro", "nuc", 1, 2, dpnp.inf]) - def test_matrix_norm_empty(self, dtype, shape_axis, ord): + def test_matrix_norm_empty(self, xp, dtype, shape_axis, ord): shape, axis = shape_axis[0], shape_axis[1] - x = dpnp.zeros(shape, dtype=dtype) - - # TODO: when similar changes in numpy are available, - # instead of assert_equal with zero, we should compare with numpy - assert_equal(dpnp.linalg.norm(x, axis=axis, ord=ord), 0) + x = xp.zeros(shape, dtype=dtype) + assert_equal(xp.linalg.norm(x, axis=axis, ord=ord), 0) + @pytest.mark.parametrize( + "xp", + [ + dpnp, + pytest.param( + numpy, + marks=pytest.mark.skipif( + numpy_version() < "2.3.0", + reason="numpy raises an error", + ), + ), + ], + ) @pytest.mark.parametrize("dtype", [dpnp.float32, dpnp.int32]) @pytest.mark.parametrize("axis", [None, 0]) @pytest.mark.parametrize("ord", [None, 1, 2, dpnp.inf]) - def test_vector_norm_empty(self, dtype, axis, ord): - x = dpnp.zeros(0, dtype=dtype) - # TODO: when similar changes in numpy are available, - # instead of assert_equal with zero, we should compare with numpy - assert_equal(dpnp.linalg.vector_norm(x, axis=axis, ord=ord), 0) + 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) @testing.with_requires("numpy>=2.0") @pytest.mark.parametrize(