From 19c56be7a3aa336b8b3ca3e8416f1744f0b89d32 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 03:42:50 -0700 Subject: [PATCH 01/13] Correct dev_info size assertion in lapack batch error --- dpnp/backend/extensions/lapack/getrf_batch.cpp | 5 +++-- dpnp/backend/extensions/lapack/getri_batch.cpp | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dpnp/backend/extensions/lapack/getrf_batch.cpp b/dpnp/backend/extensions/lapack/getrf_batch.cpp index 049d89acb02c..dad0f10aed71 100644 --- a/dpnp/backend/extensions/lapack/getrf_batch.cpp +++ b/dpnp/backend/extensions/lapack/getrf_batch.cpp @@ -115,8 +115,9 @@ static sycl::event getrf_batch_impl(sycl::queue &exec_q, auto error_matrices_ids_size = error_matrices_ids.size(); auto dev_info_size = static_cast(py::len(dev_info)); - if (error_matrices_ids_size != dev_info_size) { - throw py::value_error("The size of `dev_info` must be equal to " + + if (error_matrices_ids_size > dev_info_size) { + throw py::value_error("The size of `dev_info` must be greater than" + " or equal to " + std::to_string(error_matrices_ids_size) + ", but currently it is " + std::to_string(dev_info_size) + "."); diff --git a/dpnp/backend/extensions/lapack/getri_batch.cpp b/dpnp/backend/extensions/lapack/getri_batch.cpp index 53e9059afeaf..081b3925324d 100644 --- a/dpnp/backend/extensions/lapack/getri_batch.cpp +++ b/dpnp/backend/extensions/lapack/getri_batch.cpp @@ -113,8 +113,9 @@ static sycl::event getri_batch_impl(sycl::queue &exec_q, auto error_matrices_ids_size = error_matrices_ids.size(); auto dev_info_size = static_cast(py::len(dev_info)); - if (error_matrices_ids_size != dev_info_size) { - throw py::value_error("The size of `dev_info` must be equal to " + + if (error_matrices_ids_size > dev_info_size) { + throw py::value_error("The size of `dev_info` must be greater than" + " or equal to " + std::to_string(error_matrices_ids_size) + ", but currently it is " + std::to_string(dev_info_size) + "."); From 3b5e9fcd23d564d28a6348fd6aabc9e9f65a9036 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 04:40:44 -0700 Subject: [PATCH 02/13] Revise batch_error handling for getrf/getri_batch --- dpnp/backend/extensions/lapack/getrf_batch.cpp | 17 ++++++++++++----- dpnp/backend/extensions/lapack/getri_batch.cpp | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/dpnp/backend/extensions/lapack/getrf_batch.cpp b/dpnp/backend/extensions/lapack/getrf_batch.cpp index dad0f10aed71..b639ea90b0e8 100644 --- a/dpnp/backend/extensions/lapack/getrf_batch.cpp +++ b/dpnp/backend/extensions/lapack/getrf_batch.cpp @@ -110,8 +110,9 @@ static sycl::event getrf_batch_impl(sycl::queue &exec_q, // Get the indices of matrices within the batch that encountered an // error auto error_matrices_ids = be.ids(); - // Get the indices of the first zero diagonal elements of these matrices - auto error_info = be.exceptions(); + // List of exception pointers corresponding to + // each failed matrix in the batch. + auto error_exceptions = be.exceptions(); auto error_matrices_ids_size = error_matrices_ids.size(); auto dev_info_size = static_cast(py::len(dev_info)); @@ -123,10 +124,16 @@ static sycl::event getrf_batch_impl(sycl::queue &exec_q, std::to_string(dev_info_size) + "."); } + // MKL returns an empty exception list (MKLD-17226) + // which makes it impossible to extract specific error types. + // Workaround: mark the failed matrices in dev_info with 1 + // to indicate a failure (singular matrix). + + // TODO: Once be.exceptions() returns a valid list, + // fill dev_info only based on the caught exception type + // mkl_lapack::computation_error -> dev_info = any positive values for (size_t i = 0; i < error_matrices_ids.size(); ++i) { - // Assign the index of the first zero diagonal element in each - // error matrix to the corresponding index in 'dev_info' - dev_info[error_matrices_ids[i]] = error_info[i]; + dev_info[error_matrices_ids[i]] = 1; } } catch (mkl_lapack::exception const &e) { is_exception_caught = true; diff --git a/dpnp/backend/extensions/lapack/getri_batch.cpp b/dpnp/backend/extensions/lapack/getri_batch.cpp index 081b3925324d..de73e5991313 100644 --- a/dpnp/backend/extensions/lapack/getri_batch.cpp +++ b/dpnp/backend/extensions/lapack/getri_batch.cpp @@ -108,8 +108,9 @@ static sycl::event getri_batch_impl(sycl::queue &exec_q, // Get the indices of matrices within the batch that encountered an // error auto error_matrices_ids = be.ids(); - // Get the indices of the first zero diagonal elements of these matrices - auto error_info = be.exceptions(); + // List of exception pointers corresponding to + // each failed matrix in the batch. + auto error_exceptions = be.exceptions(); auto error_matrices_ids_size = error_matrices_ids.size(); auto dev_info_size = static_cast(py::len(dev_info)); @@ -121,10 +122,16 @@ static sycl::event getri_batch_impl(sycl::queue &exec_q, std::to_string(dev_info_size) + "."); } + // MKL returns an empty exception list (MKLD-17226) + // which makes it impossible to extract specific error types. + // Workaround: mark the failed matrices in dev_info with 1 + // to indicate a failure (singular matrix). + + // TODO: Once be.exceptions() returns a valid list, + // fill dev_info only based on the caught exception type + // mkl_lapack::computation_error -> dev_info = any positive values for (size_t i = 0; i < error_matrices_ids.size(); ++i) { - // Assign the index of the first zero diagonal element in each - // error matrix to the corresponding index in 'dev_info' - dev_info[error_matrices_ids[i]] = error_info[i]; + dev_info[error_matrices_ids[i]] = 1; } } catch (mkl_lapack::exception const &e) { is_exception_caught = true; From f7f3467710fb5119655ae45443985530cbbef8fc Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 05:01:52 -0700 Subject: [PATCH 03/13] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f44dcdb0eab1..258241eb21c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ This release achieves 100% compliance with Python Array API specification (revis * Updated `conda create` commands build and install instructions of `Quick start guide` to avoid a compilation error [#2395](https://github.com/IntelPython/dpnp/pull/2395) * Added handling of empty string passed to a test env variable defining data type scope as a `False` value [#2415](https://github.com/IntelPython/dpnp/pull/2415) * Resolved build issues on non-Intel targets in `dpnp.i0` and `dpnp.kaiser` [#2439](https://github.com/IntelPython/dpnp/pull/2439) +* Ensure consistent `dpnp.linalg.LinAlgError` on singular matrices for both non-batched and batched cases in `dpnp.linalg.inv` [#2458] (https://github.com/IntelPython/dpnp/pull/2458) ## [0.17.0] - 02/26/2025 From a046ab94f469a136fb5e7eca3c9e8967b324f9f9 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 05:29:23 -0700 Subject: [PATCH 04/13] Unskip singular matrix tests for linalg functions --- dpnp/tests/test_linalg.py | 11 ----------- .../tests/third_party/cupy/linalg_tests/test_norms.py | 4 ---- .../tests/third_party/cupy/linalg_tests/test_solve.py | 3 --- 3 files changed, 18 deletions(-) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index fe8f79312401..6664c60cd257 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -460,10 +460,6 @@ def test_det_singular_matrix(self, matrix): assert_allclose(result, expected) - # TODO: remove skipif when MKLD-13852 is resolved - # _getrf_batch does not raise an error with singular matrices. - # Skip running on cpu because dpnp uses _getrf_batch only on cpu. - @pytest.mark.skipif(is_cpu_device(), reason="MKLD-13852") def test_det_singular_matrix_3D(self): a_np = numpy.array( [[[1, 2], [3, 4]], [[1, 2], [1, 2]], [[1, 3], [3, 1]]] @@ -1761,9 +1757,6 @@ def test_inv_singular_matrix(self, matrix): assert_raises(numpy.linalg.LinAlgError, numpy.linalg.inv, a_np) assert_raises(dpnp.linalg.LinAlgError, dpnp.linalg.inv, a_dp) - # TODO: remove skip when MKLD-13852 is resolved - # _getrf_batch does not raise an error with singular matrices. - @pytest.mark.skip("MKLD-13852") def test_inv_singular_matrix_3D(self): a_np = numpy.array( [[[1, 2], [3, 4]], [[1, 2], [1, 2]], [[1, 3], [3, 1]]] @@ -2815,10 +2808,6 @@ def test_slogdet_singular_matrix(self, matrix): assert_allclose(sign_result, sign_expected) assert_allclose(logdet_result, logdet_expected) - # TODO: remove skipif when MKLD-13852 is resolved - # _getrf_batch does not raise an error with singular matrices. - # Skip running on cpu because dpnp uses _getrf_batch only on cpu. - @pytest.mark.skipif(is_cpu_device(), reason="MKLD-13852") def test_slogdet_singular_matrix_3D(self): a_np = numpy.array( [[[1, 2], [3, 4]], [[1, 2], [1, 2]], [[1, 3], [3, 1]]] diff --git a/dpnp/tests/third_party/cupy/linalg_tests/test_norms.py b/dpnp/tests/third_party/cupy/linalg_tests/test_norms.py index 105dc2184a82..297ce282928a 100644 --- a/dpnp/tests/third_party/cupy/linalg_tests/test_norms.py +++ b/dpnp/tests/third_party/cupy/linalg_tests/test_norms.py @@ -170,10 +170,6 @@ def test_det_zero_dim(self, dtype): with pytest.raises(xp.linalg.LinAlgError): xp.linalg.det(a) - # TODO: remove skipif when MKLD-13852 is resolved - # _getrf_batch does not raise an error with singular matrices. - # Skip running on cpu because dpnp uses _getrf_batch only on cpu. - @pytest.mark.skipif(is_cpu_device(), reason="MKLD-13852") @testing.for_float_dtypes(no_float16=True) @testing.numpy_cupy_allclose(rtol=1e-3, atol=1e-4) def test_det_singular(self, xp, dtype): 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 d0c0f5c61c20..bac6591bb7f0 100644 --- a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py +++ b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py @@ -213,9 +213,6 @@ def test_inv(self, dtype): ): xp.linalg.inv(a) - # TODO: remove skip when MKLD-13852 is resolved - # _getrf_batch does not raise an error with singular matrices. - @pytest.mark.skip("MKLD-13852") @testing.for_dtypes("ifdFD") def test_batched_inv(self, dtype): for xp in (numpy, cupy): From c0344e366b6fe152ce8aaaeb2fff63f97d9bd40d Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 05:33:31 -0700 Subject: [PATCH 05/13] Update TestCond::test_nan skip condition --- dpnp/tests/test_linalg.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index 6664c60cd257..3cbc03a94bef 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -334,11 +334,7 @@ def test_nan(self, p): # while OneMKL returns nans if is_cuda_device() and p in [-dpnp.inf, -1, 1, dpnp.inf, "fro"]: pytest.skip("Different behavior on CUDA") - elif ( - is_gpu_device() - and is_win_platform() - and p in [-dpnp.inf, -1, 1, dpnp.inf, "fro"] - ): + elif p in [-dpnp.inf, -1, 1, dpnp.inf, "fro"]: pytest.skip("SAT-7966") a = generate_random_numpy_array((2, 2, 2, 2)) a[0, 0] = 0 From 4707999f6be7de37e3ae202e9431f61e9e09c42a Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 07:48:04 -0700 Subject: [PATCH 06/13] Add get_intel_mkl_version() to helper.py --- dpnp/tests/helper.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dpnp/tests/helper.py b/dpnp/tests/helper.py index 1f5365220595..cee238a22b78 100644 --- a/dpnp/tests/helper.py +++ b/dpnp/tests/helper.py @@ -372,6 +372,24 @@ def not_excluded(dtype): return dtypes +def get_intel_mkl_version(): + """ + Return the version of Intel MKL used by NumPy during testing. + + The check is based on MKL backend name stored in Build Dependencies + and only applies if Intel NumPy is detected. + The version is extracted from the BLAS section of NumPy's build + information. + + Return None if Intel MKL is not used. + """ + if not is_intel_numpy(): + return None + + build_deps = numpy.show_config(mode="dicts")["Build Dependencies"] + return build_deps["blas"]["version"] + + def has_support_aspect16(device=None): """ Return True if the device supports 16-bit precision floating point operations, From db869f0965bae603907e9e51228b34ed79e5f490 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 08:08:16 -0700 Subject: [PATCH 07/13] Skip test if mkl<2025.2 --- dpnp/tests/test_linalg.py | 11 +++++++++-- .../tests/third_party/cupy/linalg_tests/test_solve.py | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index 3cbc03a94bef..e921670ef979 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -21,11 +21,10 @@ get_all_dtypes, get_float_complex_dtypes, get_integer_float_dtypes, + get_intel_mkl_version, has_support_aspect64, is_cpu_device, is_cuda_device, - is_gpu_device, - is_win_platform, numpy_version, ) from .third_party.cupy import testing @@ -1753,6 +1752,8 @@ def test_inv_singular_matrix(self, matrix): assert_raises(numpy.linalg.LinAlgError, numpy.linalg.inv, a_np) assert_raises(dpnp.linalg.LinAlgError, dpnp.linalg.inv, a_dp) + # TODO: remove skipif when Intel MKL 2025.2 is released + @pytest.mark.skipif(get_intel_mkl_version < "2025.2", reason="mkl<2025.2") def test_inv_singular_matrix_3D(self): a_np = numpy.array( [[[1, 2], [3, 4]], [[1, 2], [1, 2]], [[1, 3], [3, 1]]] @@ -2774,6 +2775,12 @@ def test_slogdet_strides(self): assert_allclose(sign_result, sign_expected) assert_allclose(logdet_result, logdet_expected) + # TODO: remove skipif when Intel MKL 2025.2 is released + # Skip running on cpu because dpnp uses _getrf_batch only on cpu. + @pytest.mark.skipif( + is_cpu_device() and get_intel_mkl_version < "2025.2", + reason="mkl<2025.2", + ) @pytest.mark.parametrize( "matrix", [ 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 bac6591bb7f0..3e8f23360fee 100644 --- a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py +++ b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py @@ -6,6 +6,7 @@ import dpnp as cupy from dpnp.tests.helper import ( assert_dtype_allclose, + get_intel_mkl_version, has_support_aspect64, ) from dpnp.tests.third_party.cupy import testing @@ -213,6 +214,8 @@ def test_inv(self, dtype): ): xp.linalg.inv(a) + # TODO: remove skipif when Intel MKL 2025.2 is released + @pytest.mark.skipif(get_intel_mkl_version < "2025.2", reason="mkl<2025.2") @testing.for_dtypes("ifdFD") def test_batched_inv(self, dtype): for xp in (numpy, cupy): From 1f490a5f32ced046735871a0080c3cf273f47c35 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 08:32:13 -0700 Subject: [PATCH 08/13] A small fix --- dpnp/tests/test_linalg.py | 4 ++-- dpnp/tests/third_party/cupy/linalg_tests/test_solve.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index e921670ef979..a57042845278 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -1753,7 +1753,7 @@ def test_inv_singular_matrix(self, matrix): assert_raises(dpnp.linalg.LinAlgError, dpnp.linalg.inv, a_dp) # TODO: remove skipif when Intel MKL 2025.2 is released - @pytest.mark.skipif(get_intel_mkl_version < "2025.2", reason="mkl<2025.2") + @pytest.mark.skipif(get_intel_mkl_version() < "2025.2", reason="mkl<2025.2") def test_inv_singular_matrix_3D(self): a_np = numpy.array( [[[1, 2], [3, 4]], [[1, 2], [1, 2]], [[1, 3], [3, 1]]] @@ -2778,7 +2778,7 @@ def test_slogdet_strides(self): # TODO: remove skipif when Intel MKL 2025.2 is released # Skip running on cpu because dpnp uses _getrf_batch only on cpu. @pytest.mark.skipif( - is_cpu_device() and get_intel_mkl_version < "2025.2", + is_cpu_device() and get_intel_mkl_version() < "2025.2", reason="mkl<2025.2", ) @pytest.mark.parametrize( 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 3e8f23360fee..d8da6b5e7504 100644 --- a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py +++ b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py @@ -215,7 +215,7 @@ def test_inv(self, dtype): xp.linalg.inv(a) # TODO: remove skipif when Intel MKL 2025.2 is released - @pytest.mark.skipif(get_intel_mkl_version < "2025.2", reason="mkl<2025.2") + @pytest.mark.skipif(get_intel_mkl_version() < "2025.2", reason="mkl<2025.2") @testing.for_dtypes("ifdFD") def test_batched_inv(self, dtype): for xp in (numpy, cupy): From 6bd9a64b32aa85a1bd3df2d846be9fce540e37f4 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 09:58:49 -0700 Subject: [PATCH 09/13] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f333e8ea3c6..f7ac517e1221 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,7 +47,7 @@ This release achieves 100% compliance with Python Array API specification (revis * Updated `conda create` commands build and install instructions of `Quick start guide` to avoid a compilation error [#2395](https://github.com/IntelPython/dpnp/pull/2395) * Added handling of empty string passed to a test env variable defining data type scope as a `False` value [#2415](https://github.com/IntelPython/dpnp/pull/2415) * Resolved build issues on non-Intel targets in `dpnp.i0` and `dpnp.kaiser` [#2439](https://github.com/IntelPython/dpnp/pull/2439) -* Ensure consistent `dpnp.linalg.LinAlgError` on singular matrices for both non-batched and batched cases in `dpnp.linalg.inv` [#2458] (https://github.com/IntelPython/dpnp/pull/2458) +* Ensure consistency in the `dpnp.linalg.LinAlgError` exception raised on singular input matrices for both non-batched and batched cases in `dpnp.linalg.inv` [#2458] (https://github.com/IntelPython/dpnp/pull/2458) ## [0.17.0] - 02/26/2025 From f1052ec2843fced62b14122a5ac95462d3d4b925 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 10:10:45 -0700 Subject: [PATCH 10/13] Add requires_intel_mkl_version() to helper.py --- dpnp/tests/helper.py | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/dpnp/tests/helper.py b/dpnp/tests/helper.py index cee238a22b78..7bf6f156e9eb 100644 --- a/dpnp/tests/helper.py +++ b/dpnp/tests/helper.py @@ -372,24 +372,6 @@ def not_excluded(dtype): return dtypes -def get_intel_mkl_version(): - """ - Return the version of Intel MKL used by NumPy during testing. - - The check is based on MKL backend name stored in Build Dependencies - and only applies if Intel NumPy is detected. - The version is extracted from the BLAS section of NumPy's build - information. - - Return None if Intel MKL is not used. - """ - if not is_intel_numpy(): - return None - - build_deps = numpy.show_config(mode="dicts")["Build Dependencies"] - return build_deps["blas"]["version"] - - def has_support_aspect16(device=None): """ Return True if the device supports 16-bit precision floating point operations, @@ -461,3 +443,20 @@ def is_win_platform(): def numpy_version(): return numpy.lib.NumpyVersion(numpy.__version__) + + +def requires_intel_mkl_version(version): + """ + Check if Intel MKL is used and its version is greater than or + equal to the specified one. + + The check is based on MKL backend name stored in Build Dependencies + and only applies if Intel NumPy is detected. + The version is extracted from the BLAS section of NumPy's build + information and compared to the given version string. + """ + if not is_intel_numpy(): + return False + + build_deps = numpy.show_config(mode="dicts")["Build Dependencies"] + return build_deps["blas"]["version"] >= version From 74cd4283d54eb1f8fab99c02184d14cabc9607da Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 11:17:39 -0700 Subject: [PATCH 11/13] Address remarks --- dpnp/tests/test_linalg.py | 19 ++++++++++++++----- .../cupy/linalg_tests/test_solve.py | 6 ++++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index a57042845278..c9ab83064855 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -21,11 +21,11 @@ get_all_dtypes, get_float_complex_dtypes, get_integer_float_dtypes, - get_intel_mkl_version, has_support_aspect64, is_cpu_device, is_cuda_device, numpy_version, + requires_intel_mkl_version, ) from .third_party.cupy import testing @@ -333,7 +333,13 @@ def test_nan(self, p): # while OneMKL returns nans if is_cuda_device() and p in [-dpnp.inf, -1, 1, dpnp.inf, "fro"]: pytest.skip("Different behavior on CUDA") - elif p in [-dpnp.inf, -1, 1, dpnp.inf, "fro"]: + elif requires_intel_mkl_version("2025.2") and p in [ + -dpnp.inf, + -1, + 1, + dpnp.inf, + "fro", + ]: pytest.skip("SAT-7966") a = generate_random_numpy_array((2, 2, 2, 2)) a[0, 0] = 0 @@ -1753,7 +1759,9 @@ def test_inv_singular_matrix(self, matrix): assert_raises(dpnp.linalg.LinAlgError, dpnp.linalg.inv, a_dp) # TODO: remove skipif when Intel MKL 2025.2 is released - @pytest.mark.skipif(get_intel_mkl_version() < "2025.2", reason="mkl<2025.2") + @pytest.mark.skipif( + not requires_intel_mkl_version("2025.2"), reason="mkl<2025.2" + ) def test_inv_singular_matrix_3D(self): a_np = numpy.array( [[[1, 2], [3, 4]], [[1, 2], [1, 2]], [[1, 3], [3, 1]]] @@ -2776,9 +2784,10 @@ def test_slogdet_strides(self): assert_allclose(logdet_result, logdet_expected) # TODO: remove skipif when Intel MKL 2025.2 is released - # Skip running on cpu because dpnp uses _getrf_batch only on cpu. + # Skip running on CPU because dpnp uses _getrf_batch only on CPU + # for dpnp.linalg.det/slogdet. @pytest.mark.skipif( - is_cpu_device() and get_intel_mkl_version() < "2025.2", + is_cpu_device() and not requires_intel_mkl_version("2025.2"), reason="mkl<2025.2", ) @pytest.mark.parametrize( 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 d8da6b5e7504..f43559e1c077 100644 --- a/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py +++ b/dpnp/tests/third_party/cupy/linalg_tests/test_solve.py @@ -6,8 +6,8 @@ import dpnp as cupy from dpnp.tests.helper import ( assert_dtype_allclose, - get_intel_mkl_version, has_support_aspect64, + requires_intel_mkl_version, ) from dpnp.tests.third_party.cupy import testing from dpnp.tests.third_party.cupy.testing import _condition @@ -215,7 +215,9 @@ def test_inv(self, dtype): xp.linalg.inv(a) # TODO: remove skipif when Intel MKL 2025.2 is released - @pytest.mark.skipif(get_intel_mkl_version() < "2025.2", reason="mkl<2025.2") + @pytest.mark.skipif( + not requires_intel_mkl_version("2025.2"), reason="mkl<2025.2" + ) @testing.for_dtypes("ifdFD") def test_batched_inv(self, dtype): for xp in (numpy, cupy): From 44232c62b21dae1a545e8977fbbaf6299e7663cd Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 11:59:14 -0700 Subject: [PATCH 12/13] Update comments for batch_error handling --- dpnp/backend/extensions/lapack/getrf_batch.cpp | 16 +++++----------- dpnp/backend/extensions/lapack/getri_batch.cpp | 16 +++++----------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/dpnp/backend/extensions/lapack/getrf_batch.cpp b/dpnp/backend/extensions/lapack/getrf_batch.cpp index b639ea90b0e8..83d06816fce4 100644 --- a/dpnp/backend/extensions/lapack/getrf_batch.cpp +++ b/dpnp/backend/extensions/lapack/getrf_batch.cpp @@ -110,9 +110,6 @@ static sycl::event getrf_batch_impl(sycl::queue &exec_q, // Get the indices of matrices within the batch that encountered an // error auto error_matrices_ids = be.ids(); - // List of exception pointers corresponding to - // each failed matrix in the batch. - auto error_exceptions = be.exceptions(); auto error_matrices_ids_size = error_matrices_ids.size(); auto dev_info_size = static_cast(py::len(dev_info)); @@ -124,14 +121,11 @@ static sycl::event getrf_batch_impl(sycl::queue &exec_q, std::to_string(dev_info_size) + "."); } - // MKL returns an empty exception list (MKLD-17226) - // which makes it impossible to extract specific error types. - // Workaround: mark the failed matrices in dev_info with 1 - // to indicate a failure (singular matrix). - - // TODO: Once be.exceptions() returns a valid list, - // fill dev_info only based on the caught exception type - // mkl_lapack::computation_error -> dev_info = any positive values + // OneMKL batched functions throw a single `batch_error` + // instead of per-matrix exceptions or an info array. + // This is interpreted as a computation_error (singular matrix), + // consistent with non-batched LAPACK behavior. + // Set dev_info[...] to any positive value for each failed index. for (size_t i = 0; i < error_matrices_ids.size(); ++i) { dev_info[error_matrices_ids[i]] = 1; } diff --git a/dpnp/backend/extensions/lapack/getri_batch.cpp b/dpnp/backend/extensions/lapack/getri_batch.cpp index de73e5991313..a59e7e3ae606 100644 --- a/dpnp/backend/extensions/lapack/getri_batch.cpp +++ b/dpnp/backend/extensions/lapack/getri_batch.cpp @@ -108,9 +108,6 @@ static sycl::event getri_batch_impl(sycl::queue &exec_q, // Get the indices of matrices within the batch that encountered an // error auto error_matrices_ids = be.ids(); - // List of exception pointers corresponding to - // each failed matrix in the batch. - auto error_exceptions = be.exceptions(); auto error_matrices_ids_size = error_matrices_ids.size(); auto dev_info_size = static_cast(py::len(dev_info)); @@ -122,14 +119,11 @@ static sycl::event getri_batch_impl(sycl::queue &exec_q, std::to_string(dev_info_size) + "."); } - // MKL returns an empty exception list (MKLD-17226) - // which makes it impossible to extract specific error types. - // Workaround: mark the failed matrices in dev_info with 1 - // to indicate a failure (singular matrix). - - // TODO: Once be.exceptions() returns a valid list, - // fill dev_info only based on the caught exception type - // mkl_lapack::computation_error -> dev_info = any positive values + // OneMKL batched functions throw a single `batch_error` + // instead of per-matrix exceptions or an info array. + // This is interpreted as a computation_error (singular matrix), + // consistent with non-batched LAPACK behavior. + // Set dev_info[...] to any positive value for each failed index. for (size_t i = 0; i < error_matrices_ids.size(); ++i) { dev_info[error_matrices_ids[i]] = 1; } From 3dc2164d3a426de2caea65a85c28f153c2d45efe Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 19 May 2025 12:17:17 -0700 Subject: [PATCH 13/13] Skip test_slogdet_singular_matrix_3D for mkl<2025.2 --- dpnp/tests/test_linalg.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index c9ab83064855..65cd3bbc70d1 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -2820,6 +2820,13 @@ def test_slogdet_singular_matrix(self, matrix): assert_allclose(sign_result, sign_expected) assert_allclose(logdet_result, logdet_expected) + # TODO: remove skipif when Intel MKL 2025.2 is released + # Skip running on CPU because dpnp uses _getrf_batch only on CPU + # for dpnp.linalg.det/slogdet. + @pytest.mark.skipif( + is_cpu_device() and not requires_intel_mkl_version("2025.2"), + reason="mkl<2025.2", + ) def test_slogdet_singular_matrix_3D(self): a_np = numpy.array( [[[1, 2], [3, 4]], [[1, 2], [1, 2]], [[1, 3], [3, 1]]]