From 2ebe7eb1f53868d1fe6aa8f74537603ae10021dc Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 26 Nov 2024 07:19:05 -0800 Subject: [PATCH 01/10] Update solve with broadcasting to align numpy 2.0 --- dpnp/linalg/dpnp_iface_linalg.py | 55 +++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/dpnp/linalg/dpnp_iface_linalg.py b/dpnp/linalg/dpnp_iface_linalg.py index 51b64b4bc37..0249a23e784 100644 --- a/dpnp/linalg/dpnp_iface_linalg.py +++ b/dpnp/linalg/dpnp_iface_linalg.py @@ -1612,12 +1612,12 @@ def solve(a, b): ---------- a : (..., M, M) {dpnp.ndarray, usm_ndarray} Coefficient matrix. - b : {(…, M,), (…, M, K)} {dpnp.ndarray, usm_ndarray} + b : {(M,), (..., M, K)} {dpnp.ndarray, usm_ndarray} Ordinate or "dependent variable" values. Returns ------- - out : {(…, M,), (…, M, K)} dpnp.ndarray + out : {(..., M,), (..., M, K)} dpnp.ndarray Solution to the system `ax = b`. Returned shape is identical to `b`. See Also @@ -1644,14 +1644,53 @@ def solve(a, b): assert_stacked_2d(a) assert_stacked_square(a) - if not ( - a.ndim in [b.ndim, b.ndim + 1] and a.shape[:-1] == b.shape[: a.ndim - 1] - ): - raise dpnp.linalg.LinAlgError( - "a must have (..., M, M) shape and b must have (..., M) " - "or (..., M, K)" + a_ndim = a.ndim + b_ndim = b.ndim + + a_shape = a.shape + b_shape = b.shape + + if numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0": + if not ( + a_ndim in [b_ndim, b_ndim + 1] + and a_shape[:-1] == b_shape[: a_ndim - 1] + ): + raise dpnp.linalg.LinAlgError( + "a must have (..., M, M) shape and b must have (..., M) " + "or (..., M, K)" + ) + + else: # compatible with numpy>=2.0 + if b_ndim == 0: + raise ValueError("b must have at least one dimension") + if b_ndim == 1: + if a_shape[-1] != b.size: + raise ValueError( + "a must have (..., M, M) shape and b must have (M,) " + "for one-dimensional b" + ) + b = dpnp.broadcast_to(b, a_shape[:-1]) + return dpnp_solve(a, b) + + if a_shape[-1] != b_shape[-2]: + raise ValueError( + "a must have (..., M, M) shape and b must have " + "(..., M, K) shape" + ) + + # Use dpnp.broadcast_shapes() to align the resulting batch shapes + broadcasted_batch_shape = dpnp.broadcast_shapes( + a_shape[:-2], b_shape[:-2] ) + a_broadcasted_shape = broadcasted_batch_shape + a_shape[-2:] + b_broadcasted_shape = broadcasted_batch_shape + b_shape[-2:] + + if a_shape != a_broadcasted_shape: + a = dpnp.broadcast_to(a, a_broadcasted_shape) + if b_shape != b_broadcasted_shape: + b = dpnp.broadcast_to(b, b_broadcasted_shape) + return dpnp_solve(a, b) From c03ba5ccec852774149b1faa0925fc4960342092 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 26 Nov 2024 07:20:42 -0800 Subject: [PATCH 02/10] Update and add more tests for solve() --- dpnp/tests/test_linalg.py | 30 ++++++++++++++++ .../cupy/linalg_tests/test_solve.py | 34 +++++++++++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index 76ce7989c8c..03225c04f47 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -2694,6 +2694,36 @@ def test_solve(self, dtype): assert_allclose(expected, result, rtol=1e-06) + @testing.with_requires("numpy>=2.0") + @pytest.mark.parametrize("dtype", get_float_complex_dtypes()) + @pytest.mark.parametrize( + "a_shape, b_shape", + [ + ((4, 4), (2, 2, 4, 3)), + ((2, 5, 5), (1, 5, 3)), + ((2, 4, 4), (2, 2, 4, 2)), + ((3, 2, 2), (3, 1, 2, 1)), + ((2, 2, 2, 2, 2), (2,)), + ((2, 2, 2, 2, 2), (2, 3)), + ], + ) + def test_solve_broadcast(self, a_shape, b_shape, dtype): + # Set seed_value=81 to prevent + # random generation of the input singular matrix + a_np = generate_random_numpy_array(a_shape, dtype, seed_value=81) + + # Set seed_value=76 to prevent + # random generation of the input singular matrix + b_np = generate_random_numpy_array(b_shape, dtype, seed_value=76) + + a_dp = inp.array(a_np) + b_dp = inp.array(b_np) + + expected = numpy.linalg.solve(a_np, b_np) + result = inp.linalg.solve(a_dp, b_dp) + + assert_dtype_allclose(result, expected) + @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) def test_solve_nrhs_greater_n(self, dtype): # Test checking the case when nrhs > n for diff --git a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py index 697a977a648..742016f9a61 100644 --- a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py +++ b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py @@ -64,6 +64,9 @@ def test_solve(self): self.check_x((2, 4, 4), (2, 4)) self.check_x((2, 3, 2, 2), (2, 3, 2)) self.check_x((0, 2, 2), (0, 2)) + else: # Allowed since numpy 2.0 + self.check_x((2, 3, 3), (3,)) + self.check_x((2, 5, 3, 3), (3,)) def check_shape(self, a_shape, b_shape, error_types): for xp, error_type in error_types.items(): @@ -96,11 +99,38 @@ def test_invalid_shape(self): self.check_shape((3, 3), (2,), value_errors) self.check_shape((3, 3), (2, 2), value_errors) self.check_shape((3, 3, 4), (3,), linalg_errors) + self.check_shape((3, 3), (0,), value_errors) + self.check_shape((0, 3, 4), (3,), linalg_errors) # Since numpy >= 2.0, this case does not raise an error if numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0": self.check_shape((2, 3, 3), (3,), value_errors) - self.check_shape((3, 3), (0,), value_errors) - self.check_shape((0, 3, 4), (3,), linalg_errors) + else: + # Not allowed since numpy 2 + self.check_shape( + (0, 2, 2), + ( + 0, + 2, + ), + value_errors, + ) + self.check_shape( + (2, 4, 4), + ( + 2, + 4, + ), + value_errors, + ) + self.check_shape( + (2, 3, 2, 2), + ( + 2, + 3, + 2, + ), + value_errors, + ) @testing.parameterize( From 5157356fbc59c3153d39c8faa83e8417c43c243e Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 26 Nov 2024 07:37:14 -0800 Subject: [PATCH 03/10] A small update cupy tests --- .../cupy/linalg_tests/test_solve.py | 28 ++----------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py index 742016f9a61..a8b11d6d3da 100644 --- a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py +++ b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py @@ -106,31 +106,9 @@ def test_invalid_shape(self): self.check_shape((2, 3, 3), (3,), value_errors) else: # Not allowed since numpy 2 - self.check_shape( - (0, 2, 2), - ( - 0, - 2, - ), - value_errors, - ) - self.check_shape( - (2, 4, 4), - ( - 2, - 4, - ), - value_errors, - ) - self.check_shape( - (2, 3, 2, 2), - ( - 2, - 3, - 2, - ), - value_errors, - ) + self.check_shape((0, 2, 2), (0, 2), value_errors) + self.check_shape((2, 4, 4), (2, 4), value_errors) + self.check_shape((2, 3, 2, 2), (2, 3, 2), value_errors) @testing.parameterize( From c2b3450ef33e53c91800c79cc2e99b018ebf3f13 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 27 Nov 2024 02:32:10 -0800 Subject: [PATCH 04/10] Keep only solve() logic for numpy 2.0 compatibility --- dpnp/linalg/dpnp_iface_linalg.py | 59 ++++++++++++-------------------- 1 file changed, 22 insertions(+), 37 deletions(-) diff --git a/dpnp/linalg/dpnp_iface_linalg.py b/dpnp/linalg/dpnp_iface_linalg.py index 0249a23e784..0a5b714c66a 100644 --- a/dpnp/linalg/dpnp_iface_linalg.py +++ b/dpnp/linalg/dpnp_iface_linalg.py @@ -1644,52 +1644,37 @@ def solve(a, b): assert_stacked_2d(a) assert_stacked_square(a) - a_ndim = a.ndim - b_ndim = b.ndim - a_shape = a.shape b_shape = b.shape + b_ndim = b.ndim - if numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0": - if not ( - a_ndim in [b_ndim, b_ndim + 1] - and a_shape[:-1] == b_shape[: a_ndim - 1] - ): - raise dpnp.linalg.LinAlgError( - "a must have (..., M, M) shape and b must have (..., M) " - "or (..., M, K)" - ) - - else: # compatible with numpy>=2.0 - if b_ndim == 0: - raise ValueError("b must have at least one dimension") - if b_ndim == 1: - if a_shape[-1] != b.size: - raise ValueError( - "a must have (..., M, M) shape and b must have (M,) " - "for one-dimensional b" - ) - b = dpnp.broadcast_to(b, a_shape[:-1]) - return dpnp_solve(a, b) - - if a_shape[-1] != b_shape[-2]: + # compatible with numpy>=2.0 + if b_ndim == 0: + raise ValueError("b must have at least one dimension") + if b_ndim == 1: + if a_shape[-1] != b.size: raise ValueError( - "a must have (..., M, M) shape and b must have " - "(..., M, K) shape" + "a must have (..., M, M) shape and b must have (M,) " + "for one-dimensional b" ) + b = dpnp.broadcast_to(b, a_shape[:-1]) + return dpnp_solve(a, b) - # Use dpnp.broadcast_shapes() to align the resulting batch shapes - broadcasted_batch_shape = dpnp.broadcast_shapes( - a_shape[:-2], b_shape[:-2] + if a_shape[-1] != b_shape[-2]: + raise ValueError( + "a must have (..., M, M) shape and b must have (..., M, K) shape" ) - a_broadcasted_shape = broadcasted_batch_shape + a_shape[-2:] - b_broadcasted_shape = broadcasted_batch_shape + b_shape[-2:] + # Use dpnp.broadcast_shapes() to align the resulting batch shapes + broadcasted_batch_shape = dpnp.broadcast_shapes(a_shape[:-2], b_shape[:-2]) + + a_broadcasted_shape = broadcasted_batch_shape + a_shape[-2:] + b_broadcasted_shape = broadcasted_batch_shape + b_shape[-2:] - if a_shape != a_broadcasted_shape: - a = dpnp.broadcast_to(a, a_broadcasted_shape) - if b_shape != b_broadcasted_shape: - b = dpnp.broadcast_to(b, b_broadcasted_shape) + if a_shape != a_broadcasted_shape: + a = dpnp.broadcast_to(a, a_broadcasted_shape) + if b_shape != b_broadcasted_shape: + b = dpnp.broadcast_to(b, b_broadcasted_shape) return dpnp_solve(a, b) From f80fa9b5340a12d71d37f31498978f7b66117919 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 27 Nov 2024 02:32:43 -0800 Subject: [PATCH 05/10] Update cupy tests for solve() --- .../third_party/cupy/linalg_tests/test_solve.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py index a8b11d6d3da..44cf27712d8 100644 --- a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py +++ b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py @@ -60,11 +60,7 @@ def test_solve(self): # for other cases this signature must be followed # (..., m, m), (..., m, n) -> (..., m, n) # https://github.com/numpy/numpy/pull/25914 - if numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0": - self.check_x((2, 4, 4), (2, 4)) - self.check_x((2, 3, 2, 2), (2, 3, 2)) - self.check_x((0, 2, 2), (0, 2)) - else: # Allowed since numpy 2.0 + if numpy.lib.NumpyVersion(numpy.__version__) >= "2.0.0": self.check_x((2, 3, 3), (3,)) self.check_x((2, 5, 3, 3), (3,)) @@ -101,11 +97,8 @@ def test_invalid_shape(self): self.check_shape((3, 3, 4), (3,), linalg_errors) self.check_shape((3, 3), (0,), value_errors) self.check_shape((0, 3, 4), (3,), linalg_errors) - # Since numpy >= 2.0, this case does not raise an error - if numpy.lib.NumpyVersion(numpy.__version__) < "2.0.0": - self.check_shape((2, 3, 3), (3,), value_errors) - else: - # Not allowed since numpy 2 + # Not allowed since numpy 2.0 + if numpy.lib.NumpyVersion(numpy.__version__) >= "2.0.0": self.check_shape((0, 2, 2), (0, 2), value_errors) self.check_shape((2, 4, 4), (2, 4), value_errors) self.check_shape((2, 3, 2, 2), (2, 3, 2), value_errors) From d140f5604675a37fd150f9d7ba9acd64e93befe0 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 27 Nov 2024 06:02:41 -0800 Subject: [PATCH 06/10] Update test_solve --- dpnp/tests/test_sycl_queue.py | 30 ++++++++++++------------------ dpnp/tests/test_usm_type.py | 30 ++++++++++++++++-------------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/dpnp/tests/test_sycl_queue.py b/dpnp/tests/test_sycl_queue.py index 359f99de048..74ec14c1b82 100644 --- a/dpnp/tests/test_sycl_queue.py +++ b/dpnp/tests/test_sycl_queue.py @@ -2392,40 +2392,34 @@ def test_where(device): ids=[device.filter_string for device in valid_devices], ) @pytest.mark.parametrize( - "matrix, vector", + "matrix, rhs", [ ([[1, 2], [3, 5]], numpy.empty((2, 0))), ([[1, 2], [3, 5]], [1, 2]), ( [ - [[1, 1, 1], [0, 2, 5], [2, 5, -1]], - [[3, -1, 1], [1, 2, 3], [2, 3, 1]], - [[1, 4, 1], [1, 2, -2], [4, 1, 2]], + [[1, 1], [0, 2]], + [[3, -1], [1, 2]], + ], + [ + [[6, -4], [9, -6]], + [[15, 1], [15, 1]], ], - [[6, -4, 27], [9, -6, 15], [15, 1, 11]], ), ], ids=[ - "2D_Matrix_Empty_Vector", - "2D_Matrix_1D_Vector", - "3D_Matrix_and_Vectors", + "2D_Matrix_Empty_RHS", + "2D_Matrix_1D_RHS", + "3D_Matrix_and_3D_RHS", ], ) -def test_solve(matrix, vector, device): +def test_solve(matrix, rhs, device): a_np = numpy.array(matrix) - b_np = numpy.array(vector) + b_np = numpy.array(rhs) a_dp = dpnp.array(a_np, device=device) b_dp = dpnp.array(b_np, device=device) - # In numpy 2.0 the broadcast ambiguity has been removed and now - # b is treaded as a single vector if and only if it is 1-dimensional; - # for other cases this signature must be followed - # (..., m, m), (..., m, n) -> (..., m, n) - # https://github.com/numpy/numpy/pull/25914 - if a_dp.ndim > 2 and numpy.lib.NumpyVersion(numpy.__version__) >= "2.0.0": - pytest.skip("SAT-6928") - result = dpnp.linalg.solve(a_dp, b_dp) expected = numpy.linalg.solve(a_np, b_np) assert_dtype_allclose(result, expected) diff --git a/dpnp/tests/test_usm_type.py b/dpnp/tests/test_usm_type.py index d14604be725..8e06639a97c 100644 --- a/dpnp/tests/test_usm_type.py +++ b/dpnp/tests/test_usm_type.py @@ -1285,37 +1285,39 @@ def test_fftshift(self, func, usm_type): "usm_type_matrix", list_of_usm_types, ids=list_of_usm_types ) @pytest.mark.parametrize( - "usm_type_vector", list_of_usm_types, ids=list_of_usm_types + "usm_type_rhs", list_of_usm_types, ids=list_of_usm_types ) @pytest.mark.parametrize( - "matrix, vector", + "matrix, rhs", [ - ([[1, 2], [3, 5]], dp.empty((2, 0))), + ([[1, 2], [3, 5]], numpy.empty((2, 0))), ([[1, 2], [3, 5]], [1, 2]), ( [ - [[1, 1, 1], [0, 2, 5], [2, 5, -1]], - [[3, -1, 1], [1, 2, 3], [2, 3, 1]], - [[1, 4, 1], [1, 2, -2], [4, 1, 2]], + [[1, 1], [0, 2]], + [[3, -1], [1, 2]], + ], + [ + [[6, -4], [9, -6]], + [[15, 1], [15, 1]], ], - [[6, -4, 27], [9, -6, 15], [15, 1, 11]], ), ], ids=[ - "2D_Matrix_Empty_Vector", - "2D_Matrix_1D_Vector", - "3D_Matrix_and_Vectors", + "2D_Matrix_Empty_RHS", + "2D_Matrix_1D_RHS", + "3D_Matrix_and_3D_RHS", ], ) -def test_solve(matrix, vector, usm_type_matrix, usm_type_vector): +def test_solve(matrix, rhs, usm_type_matrix, usm_type_rhs): x = dp.array(matrix, usm_type=usm_type_matrix) - y = dp.array(vector, usm_type=usm_type_vector) + y = dp.array(rhs, usm_type=usm_type_rhs) z = dp.linalg.solve(x, y) assert x.usm_type == usm_type_matrix - assert y.usm_type == usm_type_vector + assert y.usm_type == usm_type_rhs assert z.usm_type == du.get_coerced_usm_type( - [usm_type_matrix, usm_type_vector] + [usm_type_matrix, usm_type_rhs] ) From e6e66ad997dc8167ee3c23636d30dbfb9f0295be Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 27 Nov 2024 06:13:16 -0800 Subject: [PATCH 07/10] Align TestSolve with cupy tests --- .../cupy/linalg_tests/test_solve.py | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py index 44cf27712d8..5fb6533be33 100644 --- a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py +++ b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py @@ -47,6 +47,7 @@ def check_x(self, a_shape, b_shape, xp, dtype): testing.assert_array_equal(b_copy, b) return result + @testing.with_requires("numpy>=2.0") def test_solve(self): self.check_x((4, 4), (4,)) self.check_x((5, 5), (5, 2)) @@ -55,14 +56,9 @@ def test_solve(self): self.check_x((0, 0), (0,)) self.check_x((0, 0), (0, 2)) self.check_x((0, 2, 2), (0, 2, 3)) - # In numpy 2.0 the broadcast ambiguity has been removed and now - # b is treaded as a single vector if and only if it is 1-dimensional; - # for other cases this signature must be followed - # (..., m, m), (..., m, n) -> (..., m, n) - # https://github.com/numpy/numpy/pull/25914 - if numpy.lib.NumpyVersion(numpy.__version__) >= "2.0.0": - self.check_x((2, 3, 3), (3,)) - self.check_x((2, 5, 3, 3), (3,)) + # Allowed since numpy 2 + self.check_x((2, 3, 3), (3,)) + self.check_x((2, 5, 3, 3), (3,)) def check_shape(self, a_shape, b_shape, error_types): for xp, error_type in error_types.items(): @@ -81,6 +77,7 @@ def test_solve_singular_empty(self, xp): # LinAlgError("Singular matrix") is not raised return xp.linalg.solve(a, b) + @testing.with_requires("numpy>=2.0") def test_invalid_shape(self): linalg_errors = { numpy: numpy.linalg.LinAlgError, @@ -98,10 +95,9 @@ def test_invalid_shape(self): self.check_shape((3, 3), (0,), value_errors) self.check_shape((0, 3, 4), (3,), linalg_errors) # Not allowed since numpy 2.0 - if numpy.lib.NumpyVersion(numpy.__version__) >= "2.0.0": - self.check_shape((0, 2, 2), (0, 2), value_errors) - self.check_shape((2, 4, 4), (2, 4), value_errors) - self.check_shape((2, 3, 2, 2), (2, 3, 2), value_errors) + self.check_shape((0, 2, 2), (0, 2), value_errors) + self.check_shape((2, 4, 4), (2, 4), value_errors) + self.check_shape((2, 3, 2, 2), (2, 3, 2), value_errors) @testing.parameterize( From c1cd0f6dd13d4c42e9cdded222672ecfa7bedd57 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 27 Nov 2024 06:23:29 -0800 Subject: [PATCH 08/10] Cover case b.ndim==0 --- dpnp/tests/test_linalg.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index 03225c04f47..a0ce71b8208 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -2830,6 +2830,10 @@ def test_solve_errors(self): inp.linalg.LinAlgError, inp.linalg.solve, a_dp_ndim_1, b_dp ) + # b.ndim == 0 + b_dp_ndim_0 = inp.array(2) + assert_raises(ValueError, inp.linalg.solve, a_dp, b_dp_ndim_0) + class TestSlogdet: @pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True)) From f7cfc2a508d1cdcaa57c30c0e701334b82888710 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 27 Nov 2024 06:52:11 -0800 Subject: [PATCH 09/10] Add notes for solve() --- dpnp/linalg/dpnp_iface_linalg.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dpnp/linalg/dpnp_iface_linalg.py b/dpnp/linalg/dpnp_iface_linalg.py index 0a5b714c66a..042cae150b8 100644 --- a/dpnp/linalg/dpnp_iface_linalg.py +++ b/dpnp/linalg/dpnp_iface_linalg.py @@ -1624,6 +1624,13 @@ def solve(a, b): -------- :obj:`dpnp.dot` : Returns the dot product of two arrays. + Notes + ----- + The `b` array is only treated as a shape (M,) column vector if it is + exactly 1-dimensional. In all other instances it is treated as a stack + of (M, K) matrices. Previously `b` would be treated as a stack of (M,) + vectors if ``b.ndim`` was equal to ``a.ndim - 1``. + Examples -------- >>> import dpnp as dp From bbdcdbc3c681b176ae73d0d9ea8bc8e1cd208204 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Thu, 28 Nov 2024 02:32:01 -0800 Subject: [PATCH 10/10] Apply comment --- dpnp/linalg/dpnp_iface_linalg.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dpnp/linalg/dpnp_iface_linalg.py b/dpnp/linalg/dpnp_iface_linalg.py index 042cae150b8..3a5c1a2abaf 100644 --- a/dpnp/linalg/dpnp_iface_linalg.py +++ b/dpnp/linalg/dpnp_iface_linalg.py @@ -1628,8 +1628,7 @@ def solve(a, b): ----- The `b` array is only treated as a shape (M,) column vector if it is exactly 1-dimensional. In all other instances it is treated as a stack - of (M, K) matrices. Previously `b` would be treated as a stack of (M,) - vectors if ``b.ndim`` was equal to ``a.ndim - 1``. + of (M, K) matrices. Examples --------