From e8b51383c37c5039ee7336ca64be8ea966965175 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 6 Oct 2025 03:35:30 -0700 Subject: [PATCH 1/5] Remove a wildcard import for linalg submodule --- dpnp/dpnp_iface.py | 1 - dpnp/linalg/__init__.py | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/dpnp/dpnp_iface.py b/dpnp/dpnp_iface.py index 4b354d547025..f7f4f470be48 100644 --- a/dpnp/dpnp_iface.py +++ b/dpnp/dpnp_iface.py @@ -52,7 +52,6 @@ from dpnp.dpnp_algo import * from dpnp.dpnp_array import dpnp_array from dpnp.fft import * -from dpnp.linalg import * from dpnp.memory import * from dpnp.random import * from dpnp.special import * diff --git a/dpnp/linalg/__init__.py b/dpnp/linalg/__init__.py index fd315e5ed434..3dc01c297c03 100644 --- a/dpnp/linalg/__init__.py +++ b/dpnp/linalg/__init__.py @@ -34,7 +34,39 @@ """ -from dpnp.linalg.dpnp_iface_linalg import * -from dpnp.linalg.dpnp_iface_linalg import __all__ as __all__linalg +from .dpnp_iface_linalg import __all__ as __all__linalg +from .dpnp_iface_linalg import ( + cholesky, + cond, + cross, + det, + diagonal, + eig, + eigh, + eigvals, + eigvalsh, + inv, + lstsq, + matmul, + matrix_norm, + matrix_power, + matrix_rank, + matrix_transpose, + multi_dot, + norm, + outer, + pinv, + qr, + slogdet, + solve, + svd, + svdvals, + tensordot, + tensorinv, + tensorsolve, + trace, + vecdot, + vector_norm, +) __all__ = __all__linalg From c98fa8bc8aed3faa0180775f4f53d12cc2cd2134 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 6 Oct 2025 04:02:46 -0700 Subject: [PATCH 2/5] Add explicit import of linalg submodule to dpnp/__init__.py --- dpnp/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dpnp/__init__.py b/dpnp/__init__.py index 744200ca13f6..4fbac978ec99 100644 --- a/dpnp/__init__.py +++ b/dpnp/__init__.py @@ -70,10 +70,14 @@ from .dpnp_iface_utils import * from .dpnp_iface_utils import __all__ as _ifaceutils__all__ from ._version import get_versions +from . import linalg as linalg __all__ = _iface__all__ __all__ += _ifaceutils__all__ +# add submodules +__all__ += ["linalg"] + __version__ = get_versions()["version"] del get_versions From 01fc3a73d04658a80e8ef2cf565f1570878ce34f Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 6 Oct 2025 05:13:11 -0700 Subject: [PATCH 3/5] Make LinAlgError exception to be exposed by LAPACK pybind11 extension --- dpnp/backend/extensions/lapack/lapack_py.cpp | 7 +++---- dpnp/linalg/__init__.py | 3 +++ dpnp/linalg/dpnp_iface_linalg.py | 8 +++++++- dpnp/linalg/dpnp_utils_linalg.py | 21 ++++++++++---------- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/dpnp/backend/extensions/lapack/lapack_py.cpp b/dpnp/backend/extensions/lapack/lapack_py.cpp index 46471cc2f366..5e072bfeac84 100644 --- a/dpnp/backend/extensions/lapack/lapack_py.cpp +++ b/dpnp/backend/extensions/lapack/lapack_py.cpp @@ -83,10 +83,9 @@ PYBIND11_MODULE(_lapack_impl, m) .value("C", oneapi::mkl::transpose::C) .export_values(); // Optional, allows access like `Transpose.N` - // Register a custom LinAlgError exception in the dpnp.linalg submodule - py::module_ linalg_module = py::module_::import("dpnp.linalg"); - py::register_exception( - linalg_module, "LinAlgError", PyExc_ValueError); + // Register a LinAlgError exception in the current submodule + py::register_exception(m, "LinAlgError", + PyExc_ValueError); init_dispatch_vectors(); init_dispatch_tables(); diff --git a/dpnp/linalg/__init__.py b/dpnp/linalg/__init__.py index 3dc01c297c03..e3f0bdc6fe25 100644 --- a/dpnp/linalg/__init__.py +++ b/dpnp/linalg/__init__.py @@ -34,6 +34,9 @@ """ +from .dpnp_iface_linalg import ( + LinAlgError, +) from .dpnp_iface_linalg import __all__ as __all__linalg from .dpnp_iface_linalg import ( cholesky, diff --git a/dpnp/linalg/dpnp_iface_linalg.py b/dpnp/linalg/dpnp_iface_linalg.py index f73443229c49..c31a56c24957 100644 --- a/dpnp/linalg/dpnp_iface_linalg.py +++ b/dpnp/linalg/dpnp_iface_linalg.py @@ -38,6 +38,7 @@ # pylint: disable=invalid-name # pylint: disable=no-member +# pylint: disable=no-name-in-module from typing import NamedTuple @@ -45,6 +46,7 @@ from dpctl.tensor._numpy_helper import normalize_axis_tuple import dpnp +from dpnp.backend.extensions.lapack._lapack_impl import LinAlgError from .dpnp_utils_linalg import ( assert_2d, @@ -70,6 +72,7 @@ ) __all__ = [ + "LinAlgError", "cholesky", "cond", "cross", @@ -105,6 +108,9 @@ "vector_norm", ] +# Need to set the module explicitly, since exposed by LAPACK pybind11 extension +LinAlgError.__module__ = "dpnp.linalg" + # pylint:disable=missing-class-docstring class EigResult(NamedTuple): @@ -2330,7 +2336,7 @@ def tensorsolve(a, b, axes=None): prod = numpy.prod(old_shape) if a.size != prod**2: - raise dpnp.linalg.LinAlgError( + raise LinAlgError( "Input arrays must satisfy the requirement " "prod(a.shape[b.ndim:]) == prod(a.shape[:b.ndim])" ) diff --git a/dpnp/linalg/dpnp_utils_linalg.py b/dpnp/linalg/dpnp_utils_linalg.py index 44a3816cc165..ce36b39f86a7 100644 --- a/dpnp/linalg/dpnp_utils_linalg.py +++ b/dpnp/linalg/dpnp_utils_linalg.py @@ -50,7 +50,6 @@ import dpnp import dpnp.backend.extensions.lapack._lapack_impl as li from dpnp.dpnp_utils import get_usm_allocations -from dpnp.linalg import LinAlgError as LinAlgError __all__ = [ "assert_2d", @@ -943,7 +942,7 @@ def _check_lapack_dev_info(dev_info, error_msg=None): if any(dev_info): error_msg = error_msg or "Singular matrix" - raise LinAlgError(error_msg) + raise li.LinAlgError(error_msg) def _common_type(*arrays): @@ -1879,7 +1878,7 @@ def assert_2d(*arrays): for a in arrays: if a.ndim != 2: - raise LinAlgError( + raise li.LinAlgError( f"{a.ndim}-dimensional array given. The input " "array must be exactly two-dimensional" ) @@ -1906,7 +1905,7 @@ def assert_stacked_2d(*arrays): for a in arrays: if a.ndim < 2: - raise LinAlgError( + raise li.LinAlgError( f"{a.ndim}-dimensional array given. The input " "array must be at least two-dimensional" ) @@ -1942,7 +1941,7 @@ def assert_stacked_square(*arrays): for a in arrays: m, n = a.shape[-2:] if m != n: - raise LinAlgError( + raise li.LinAlgError( "Last 2 dimensions of the input array must be square" ) @@ -2086,7 +2085,7 @@ def dpnp_cond(x, p=None): """Compute the condition number of a matrix.""" if _is_empty_2d(x): - raise LinAlgError("cond is not defined on empty arrays") + raise li.LinAlgError("cond is not defined on empty arrays") if p is None or p == 2 or p == -2: s = dpnp.linalg.svd(x, compute_uv=False) if p == -2: @@ -2340,7 +2339,7 @@ def dpnp_lstsq(a, b, rcond=None): """ if b.ndim > 2: - raise LinAlgError( + raise li.LinAlgError( f"{b.ndim}-dimensional array given. The input " "array must be exactly two-dimensional" ) @@ -2348,7 +2347,7 @@ def dpnp_lstsq(a, b, rcond=None): m, n = a.shape[-2:] m2 = b.shape[0] if m != m2: - raise LinAlgError("Incompatible dimensions") + raise li.LinAlgError("Incompatible dimensions") u, s, vh = dpnp_svd(a, full_matrices=False, related_arrays=[b]) @@ -2669,20 +2668,20 @@ def dpnp_multi_dot(n, arrays, out=None): """Compute dot product of two or more arrays in a single function call.""" if not arrays[0].ndim in [1, 2]: - raise LinAlgError( + raise li.LinAlgError( f"{arrays[0].ndim}-dimensional array given. " "First array must be 1-D or 2-D." ) if not arrays[-1].ndim in [1, 2]: - raise LinAlgError( + raise li.LinAlgError( f"{arrays[-1].ndim}-dimensional array given. " "Last array must be 1-D or 2-D." ) for arr in arrays[1:-1]: if arr.ndim != 2: - raise LinAlgError( + raise li.LinAlgError( f"{arr.ndim}-dimensional array given. Inner arrays must be 2-D." ) From 4554ce799ff7c85f0a2296731e5519bd1b4e5bb2 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 6 Oct 2025 05:36:27 -0700 Subject: [PATCH 4/5] Add lu_factor and lu_solve to be exposed as a part of linalg submodule --- dpnp/linalg/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dpnp/linalg/__init__.py b/dpnp/linalg/__init__.py index e3f0bdc6fe25..3139f5dfb84e 100644 --- a/dpnp/linalg/__init__.py +++ b/dpnp/linalg/__init__.py @@ -50,6 +50,8 @@ eigvalsh, inv, lstsq, + lu_factor, + lu_solve, matmul, matrix_norm, matrix_power, From cd1619988d2d4efe1916d14e42823795037f7919 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 6 Oct 2025 05:53:05 -0700 Subject: [PATCH 5/5] Add PR to the changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9efb9fba777d..ab144efcf8c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,7 @@ This release is compatible with NumPy 2.3.3. * Fixed tests for the rounding functions to depend on minimum required numpy version [#2589](https://github.com/IntelPython/dpnp/pull/2589) * Fixed tests for the ufuncs to depend on minimum required numpy version [#2590](https://github.com/IntelPython/dpnp/pull/2590) * Added missing permission definition in `Autoupdate pre-commit` GitHub workflow [#2591](https://github.com/IntelPython/dpnp/pull/2591) +* Resolved issue with the cyclic import in `linalg` submodule [#2608](https://github.com/IntelPython/dpnp/pull/2608) ### Security