Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ This release is compatible with NumPy 2.5.
* Updated the implementation of `dpnp.putmask` by adding dedicated contiguous and strided SYCL kernels [#3014](https://github.com/IntelPython/dpnp/pull/3014)
* Changed `dpnp.sort`, `dpnp.argsort`, and their `dpnp.ndarray`/`dpnp.tensor` counterparts to place `NaN` values last instead of first when sorting in descending order [#3066](https://github.com/IntelPython/dpnp/pull/3066)
* Documented and made explicit support for `copy=None` ("copy only if needed") in `dpnp.nan_to_num` [#3083](https://github.com/IntelPython/dpnp/pull/3083)
* Changed `dpnp.linalg.pinv` to compute the default tolerance from the machine epsilon of the data type used for the computation, and to return a floating-point result for an empty integer or boolean array [#3090](https://github.com/IntelPython/dpnp/pull/3090)

### Deprecated

Expand Down
8 changes: 5 additions & 3 deletions dpnp/linalg/dpnp_utils_linalg.py
Original file line number Diff line number Diff line change
Expand Up @@ -2402,10 +2402,12 @@ def dpnp_pinv(a, rcond=None, hermitian=False, rtol=None):

"""

# dtype the SVD is computed in
res_type = _common_type(a)

if rcond is None:
if rtol is None:
dtype = dpnp.result_type(a.dtype, dpnp.default_float_type(a.device))
rcond = max(a.shape[-2:]) * dpnp.finfo(dtype).eps
rcond = max(a.shape[-2:]) * dpnp.finfo(res_type).eps
else:
rcond = rtol
elif rtol is not None:
Expand All @@ -2414,7 +2416,7 @@ def dpnp_pinv(a, rcond=None, hermitian=False, rtol=None):
if _is_empty_2d(a):
m, n = a.shape[-2:]
sh = a.shape[:-2] + (n, m)
return dpnp.empty_like(a, shape=sh)
return dpnp.empty_like(a, shape=sh, dtype=res_type)

if dpnp.is_supported_array_type(rcond):
# Check that `a` and `rcond` are allocated on the same device
Expand Down
28 changes: 27 additions & 1 deletion dpnp/tests/test_linalg.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
generate_random_numpy_array,
get_all_dtypes,
get_float_complex_dtypes,
get_integer_dtypes,
get_integer_float_dtypes,
has_support_aspect64,
numpy_version,
Expand Down Expand Up @@ -4370,7 +4371,29 @@ def test_pinv_rtol(self):
result = dpnp.linalg.pinv(a_dp, rtol=1e-15)
assert_dtype_allclose(result, expected)

@pytest.mark.parametrize("dtype", get_all_dtypes(no_bool=True))
@testing.with_requires("numpy>=2.0")
@pytest.mark.parametrize("dtype", get_float_complex_dtypes())
def test_pinv_rtol_none(self, dtype):
# singular value 1e-9 is cut off for single precision only
a = numpy.diag([1.0, 1e-9]).astype(dtype)
a_dp = dpnp.array(a)

expected = numpy.linalg.pinv(a, rtol=None)
result = dpnp.linalg.pinv(a_dp, rtol=None)
assert_dtype_allclose(result, expected)

@testing.with_requires("numpy>=2.0")
@pytest.mark.parametrize("dtype", get_integer_dtypes() + [dpnp.bool])
def test_pinv_rtol_none_non_inexact(self, dtype):
a = numpy.array([[1, 2, 3], [4, 1, 1], [2, 3, 1]]).astype(dtype)
a_dp = dpnp.array(a)

# NumPy < 2.6.0 raises ValueError for non-inexact input
expected = numpy.linalg.pinv(a.astype(numpy.float64), rtol=None)
result = dpnp.linalg.pinv(a_dp, rtol=None)
assert_dtype_allclose(result, expected)

@pytest.mark.parametrize("dtype", get_all_dtypes())
@pytest.mark.parametrize(
"shape",
[(0, 0), (0, 2), (2, 0), (2, 0, 3), (2, 3, 0), (0, 2, 3)],
Expand All @@ -4388,6 +4411,9 @@ def test_pinv_empty(self, dtype, shape):
a_dp = dpnp.array(a)

B = numpy.linalg.pinv(a)
if numpy_version() < "2.6.0" and a.dtype.kind in "biu":
# NumPy < 2.6.0 returns the input dtype for empty int/bool input
B = B.astype(numpy.float64)
B_dp = dpnp.linalg.pinv(a_dp)

assert_dtype_allclose(B_dp, B)
Expand Down
4 changes: 4 additions & 0 deletions dpnp/tests/third_party/cupy/linalg_tests/test_solve.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from dpnp.tests.helper import (
assert_dtype_allclose,
has_support_aspect64,
numpy_version,
)
from dpnp.tests.third_party.cupy import testing
from dpnp.tests.third_party.cupy.testing import _condition
Expand Down Expand Up @@ -247,6 +248,9 @@ def check_x(self, a_shape, rcond, dtype):
if not isinstance(rcond, float):
rcond = numpy.asarray(rcond)
result_cpu = numpy.linalg.pinv(a_cpu, rcond=rcond)
if numpy_version() < "2.6.0" and a_cpu.dtype.kind in "biu":
# NumPy < 2.6.0 returns the input dtype for empty int/bool input
result_cpu = result_cpu.astype(numpy.float64)
if not isinstance(rcond, float):
rcond = cupy.asarray(rcond)
result_gpu = cupy.linalg.pinv(a_gpu, rcond=rcond)
Expand Down
Loading