Skip to content

Use computation dtype in dpnp.linalg.pinv for default tolerance and empty input - #3090

Merged
antonwolfy merged 3 commits into
masterfrom
align-pinv-empty-dtype-with-numpy
Oct 12, 2026
Merged

antonwolfy merged 3 commits into
masterfrom
align-pinv-empty-dtype-with-numpy

Conversation

@antonwolfy

@antonwolfy antonwolfy commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

This PR updates dpnp.linalg.pinv to take the data type for the default tolerance and for the result of an empty input from the data type the SVD is computed in. This aligns dpnp.linalg.pinv with NumPy 2.6 behavior.

Default tolerance

When rtol=None (the default) and rcond is not given, the cutoff is max(M, N) * eps. Previously eps was taken from dpnp.result_type(a.dtype, dpnp.default_float_type(a.device)), which gives float64:

  • for float32/complex64 input on devices with fp64 support;
  • for integer input on devices without fp64 support, since result_type called with dtypes only does not know the device.

In both cases the SVD runs in single precision, so the cutoff was about 10⁹ times too small. Singular values at the level of single-precision rounding noise were therefore inverted instead of discarded. The tolerance now uses eps of _common_type(a), which also matches the docstring (max(M, N) * dpnp.finfo(a.dtype).eps).

Note that dpnp.linalg.pinv(a) called without a tolerance now uses the larger cutoff for float32/complex64 input on devices with fp64 support.

Empty input

The empty-input shortcut returned an array of the input data type. An empty integer or boolean array therefore produced an integer/boolean result, while a non-empty one produced a floating-point result. The shortcut now returns the computation data type: float64, or float32 on devices without fp64 support.

import dpnp as np

a = np.diag(np.array([1.0, 1e-9], dtype=np.float32))
np.linalg.pinv(a)  # was [[1, 0], [0, 1e9]], now [[1, 0], [0, 0]]

np.linalg.pinv(np.empty((0, 3), dtype=np.int64)).dtype  # was int64, now float64
  • Have you provided a meaningful PR description?
  • Have you added a test, reproducer or referred to an issue with a reproducer?
  • Have you tested your changes locally for CPU and GPU devices?
  • Have you made sure that new changes do not introduce compiler warnings?
  • Have you checked performance impact of proposed changes?
  • Have you added documentation for your changes, if necessary?
  • Have you added your changes to the changelog?

…mpty input

The default tolerance of `dpnp.linalg.pinv` used the machine epsilon of
`result_type(a.dtype, default_float_type)`, which is float64 for
single-precision input on devices with fp64 support and for integer
input on devices without it, while the SVD runs in single precision.
It now uses the epsilon of the dtype the SVD is computed in.

The empty-input shortcut returned the input dtype, so an empty integer
or boolean array gave an integer/boolean result while a non-empty one
gave a floating-point result. It now returns the computation dtype too.

Both changes align `dpnp.linalg.pinv` with NumPy 2.6 behavior.
@antonwolfy antonwolfy added this to the 0.21.0 release milestone Oct 7, 2026
@antonwolfy antonwolfy self-assigned this Oct 7, 2026
@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

View rendered docs @ https://intelpython.github.io/dpnp/index.html

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Array API standard conformance tests for dpnp=0.21.0dev13=np2py314h8d9cdd5_7 ran successfully.
Passed: 1376
Failed: 0
Skipped: 6

@coveralls

coveralls commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Coverage Status

coverage: 78.669%. remained the same — align-pinv-empty-dtype-with-numpy into master

@vlad-perevezentsev vlad-perevezentsev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
Thank you @antonwolfy

@antonwolfy
antonwolfy merged commit c3fdb6c into master Oct 12, 2026
104 of 108 checks passed
@antonwolfy
antonwolfy deleted the align-pinv-empty-dtype-with-numpy branch October 12, 2026 16:18
github-actions Bot added a commit that referenced this pull request Oct 12, 2026
…mpty input (#3090)

This PR updates `dpnp.linalg.pinv` to take the data type for the default
tolerance and for the result of an empty input from the data type the
SVD is computed in. This aligns `dpnp.linalg.pinv` with NumPy 2.6
behavior.

### Default tolerance
When `rtol=None` (the default) and `rcond` is not given, the cutoff is
`max(M, N) * eps`. Previously `eps` was taken from
`dpnp.result_type(a.dtype, dpnp.default_float_type(a.device))`, which
gives `float64`:
- for `float32`/`complex64` input on devices with fp64 support;
- for integer input on devices without fp64 support, since `result_type`
called with dtypes only does not know the device.

In both cases the SVD runs in single precision, so the cutoff was about
10⁹ times too small. Singular values at the level of single-precision
rounding noise were therefore inverted instead of discarded. The
tolerance now uses `eps` of `_common_type(a)`, which also matches the
docstring (`max(M, N) * dpnp.finfo(a.dtype).eps`).

Note that `dpnp.linalg.pinv(a)` called without a tolerance now uses the
larger cutoff for `float32`/`complex64` input on devices with fp64
support.

### Empty input
The empty-input shortcut returned an array of the input data type. An
empty integer or boolean array therefore produced an integer/boolean
result, while a non-empty one produced a floating-point result. The
shortcut now returns the computation data type: `float64`, or `float32`
on devices without fp64 support.

```python
import dpnp as np

a = np.diag(np.array([1.0, 1e-9], dtype=np.float32))
np.linalg.pinv(a)  # was [[1, 0], [0, 1e9]], now [[1, 0], [0, 0]]

np.linalg.pinv(np.empty((0, 3), dtype=np.int64)).dtype  # was int64, now float64
``` c3fdb6c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants