Skip to content

Update docstrings for linalg functions #2373

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 19, 2025
Merged
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
4 changes: 2 additions & 2 deletions dpnp/backend/extensions/lapack/gesvd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ static sycl::event gesvd_impl(sycl::queue &exec_q,
exec_q,
jobu, // Character specifying how to compute the matrix U:
// 'A' computes all columns of U,
// 'S' computes the first min(m,n) columns of U,
// 'S' computes the first min(m, n) columns of U,
// 'O' overwrites A with the columns of U,
// 'N' does not compute U.
jobvt, // Character specifying how to compute the matrix VT:
// 'A' computes all rows of VT,
// 'S' computes the first min(m,n) rows of VT,
// 'S' computes the first min(m, n) rows of VT,
// 'O' overwrites A with the rows of VT,
// 'N' does not compute VT.
m, // The number of rows in the input matrix A (0 <= m).
Expand Down
4 changes: 2 additions & 2 deletions dpnp/backend/extensions/lapack/gesvd_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,12 @@ static sycl::event gesvd_batch_impl(sycl::queue &exec_q,
exec_q,
jobu, // Character specifying how to compute the matrix U:
// 'A' computes all columns of U,
// 'S' computes the first min(m,n) columns of U,
// 'S' computes the first min(m, n) columns of U,
// 'O' overwrites A with the columns of U,
// 'N' does not compute U.
jobvt, // Character specifying how to compute the matrix VT:
// 'A' computes all rows of VT,
// 'S' computes the first min(m,n) rows of VT,
// 'S' computes the first min(m, n) rows of VT,
// 'O' overwrites A with the rows of VT,
// 'N' does not compute VT.
m, // The number of rows in the input batch matrix A (0 <= m).
Expand Down
2 changes: 1 addition & 1 deletion dpnp/dpnp_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,7 @@ def diagonal(self, offset=0, axis1=0, axis2=1):
Examples
--------
>>> import dpnp as np
>>> a = np.arange(4).reshape(2,2)
>>> a = np.arange(4).reshape(2, 2)
>>> a.diagonal()
array([0, 3])

Expand Down
4 changes: 2 additions & 2 deletions dpnp/dpnp_iface_arraycreation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3127,7 +3127,7 @@ def meshgrid(*xi, copy=True, sparse=False, indexing="xy"):
>>> y = np.arange(-5, 5, 0.1)
>>> xx, yy = np.meshgrid(x, y, sparse=True)
>>> z = np.sin(xx**2 + yy**2) / (xx**2 + yy**2)
>>> h = plt.contourf(x,y,z)
>>> h = plt.contourf(x, y, z)
>>> plt.show()

"""
Expand Down Expand Up @@ -3202,7 +3202,7 @@ class MGridClass:
Examples
--------
>>> import dpnp as np
>>> np.mgrid[0:5,0:5]
>>> np.mgrid[0:5, 0:5]
array([[[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
Expand Down
2 changes: 1 addition & 1 deletion dpnp/dpnp_iface_histograms.py
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ def histogram2d(x, y, bins=10, range=None, density=None, weights=None):
is the number of bins and array is the bin edges.

Default: ``10``.
range : {None, dpnp.ndarray, usm_ndarray} of shape (2,2), optional
range : {None, dpnp.ndarray, usm_ndarray} of shape (2, 2), optional
The leftmost and rightmost edges of the bins along each dimension
If ``None`` the ranges are
``[[x.min(), x.max()], [y.min(), y.max()]]``. All values outside
Expand Down
8 changes: 4 additions & 4 deletions dpnp/dpnp_iface_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ def diagonal(a, offset=0, axis1=0, axis2=1):
Examples
--------
>>> import dpnp as np
>>> a = np.arange(4).reshape(2,2)
>>> a = np.arange(4).reshape(2, 2)
>>> a
array([[0, 1],
[2, 3]])
Expand All @@ -676,7 +676,7 @@ def diagonal(a, offset=0, axis1=0, axis2=1):

A 3-D example:

>>> a = np.arange(8).reshape(2,2,2)
>>> a = np.arange(8).reshape(2, 2, 2)
>>> a
array([[[0, 1],
[2, 3]],
Expand Down Expand Up @@ -1234,8 +1234,8 @@ def ix_(*args):
N dimensions.

Using :obj:`dpnp.ix_` one can quickly construct index arrays that will
index the cross product. ``a[dpnp.ix_([1,3],[2,5])]`` returns the array
``[[a[1,2] a[1,5]], [a[3,2] a[3,5]]]``.
index the cross product. ``a[dpnp.ix_([1, 3],[2, 5])]`` returns the array
``[[a[1, 2] a[1, 5]], [a[3, 2] a[3, 5]]]``.

Parameters
----------
Expand Down
70 changes: 41 additions & 29 deletions dpnp/dpnp_iface_linearalgebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ def dot(a, b, out=None):
C-contiguous. If these conditions are not met, an exception is
raised, instead of attempting to be flexible.

Default: ``None``.

Returns
-------
out : dpnp.ndarray
Expand Down Expand Up @@ -207,15 +209,19 @@ def einsum(
These are the arrays for the operation.
out : {dpnp.ndarrays, usm_ndarray, None}, optional
If provided, the calculation is done into this array.

Default: ``None``.
dtype : {None, str, dtype object}, optional
If provided, forces the calculation to use the data type specified.

Default: ``None``.
order : {"C", "F", "A", "K"}, optional
Controls the memory layout of the output. ``"C"`` means it should be
C-contiguous. ``"F"`` means it should be F-contiguous, ``"A"`` means
it should be ``"F"`` if the inputs are all ``"F"``, ``"C"`` otherwise.
``"K"`` means it should be as close to the layout as the inputs as
is possible, including arbitrarily permuted axes.

Default: ``"K"``.
casting : {"no", "equiv", "safe", "same_kind", "unsafe"}, optional
Controls what kind of data casting may occur. Setting this to
Expand All @@ -233,12 +239,14 @@ def einsum(
``"same_kind"``. This is to prevent errors that may occur when data
needs to be converted to `float64`, but the device does not support it.
In such cases, the data is instead converted to `float32`.

Default: ``"same_kind"``.
optimize : {False, True, "greedy", "optimal"}, optional
Controls if intermediate optimization should occur. No optimization
will occur if ``False`` and ``True`` will default to the ``"greedy"``
algorithm. Also accepts an explicit contraction list from the
:obj:`dpnp.einsum_path` function.

Default: ``False``.

Returns
Expand All @@ -259,15 +267,15 @@ def einsum(
Examples
--------
>>> import dpnp as np
>>> a = np.arange(25).reshape(5,5)
>>> a = np.arange(25).reshape(5, 5)
>>> b = np.arange(5)
>>> c = np.arange(6).reshape(2,3)
>>> c = np.arange(6).reshape(2, 3)

Trace of a matrix:

>>> np.einsum("ii", a)
array(60)
>>> np.einsum(a, [0,0])
>>> np.einsum(a, [0, 0])
array(60)
>>> np.trace(a)
array(60)
Expand Down Expand Up @@ -323,14 +331,14 @@ def einsum(
array(30)
>>> np.einsum(b, [0], b, [0])
array(30)
>>> np.inner(b,b)
>>> np.inner(b, b)
array(30)

Matrix vector multiplication:

>>> np.einsum("ij,j", a, b)
array([ 30, 80, 130, 180, 230])
>>> np.einsum(a, [0,1], b, [1])
>>> np.einsum(a, [0, 1], b, [1])
array([ 30, 80, 130, 180, 230])
>>> np.dot(a, b)
array([ 30, 80, 130, 180, 230])
Expand Down Expand Up @@ -412,22 +420,26 @@ def einsum(
Basic `einsum`: 119 ms ± 26 ms per loop (evaluated on 12th
Gen Intel\u00AE Core\u2122 i7 processor)

>>> %timeit np.einsum("ijk,ilm,njm,nlk,abc->",a,a,a,a,a)
>>> %timeit np.einsum("ijk,ilm,njm,nlk,abc->",a, a, a, a, a)

Sub-optimal `einsum`: 32.9 ms ± 5.1 ms per loop

>>> %timeit np.einsum("ijk,ilm,njm,nlk,abc->",a,a,a,a,a, optimize="optimal")
>>> %timeit np.einsum(
"ijk,ilm,njm,nlk,abc->", a, a, a, a, a, optimize="optimal"
)

Greedy `einsum`: 28.6 ms ± 4.8 ms per loop

>>> %timeit np.einsum("ijk,ilm,njm,nlk,abc->",a,a,a,a,a, optimize="greedy")
>>> %timeit np.einsum(
"ijk,ilm,njm,nlk,abc->", a, a, a, a, a, optimize="greedy"
)

Optimal `einsum`: 26.9 ms ± 6.3 ms per loop

>>> path = np.einsum_path(
"ijk,ilm,njm,nlk,abc->",a,a,a,a,a, optimize="optimal"
"ijk,ilm,njm,nlk,abc->", a, a, a, a, a, optimize="optimal"
)[0]
>>> %timeit np.einsum("ijk,ilm,njm,nlk,abc->",a,a,a,a,a, optimize=path)
>>> %timeit np.einsum("ijk,ilm,njm,nlk,abc->", a, a, a, a, a, optimize=path)

"""

Expand Down Expand Up @@ -509,10 +521,9 @@ def einsum_path(*operands, optimize="greedy", einsum_call=False):
Examples
--------
We can begin with a chain dot example. In this case, it is optimal to
contract the ``b`` and ``c`` tensors first as represented by the first
element of the path ``(1, 2)``. The resulting tensor is added to the end
of the contraction and the remaining contraction ``(0, 1)`` is then
completed.
contract the `b` and `c` tensors first as represented by the first element
of the path ``(1, 2)``. The resulting tensor is added to the end of the
contraction and the remaining contraction ``(0, 1)`` is then completed.

>>> import dpnp as np
>>> np.random.seed(123)
Expand Down Expand Up @@ -622,7 +633,7 @@ def inner(a, b):

# Some multidimensional examples

>>> a = np.arange(24).reshape((2,3,4))
>>> a = np.arange(24).reshape((2, 3, 4))
>>> b = np.arange(4)
>>> c = np.inner(a, b)
>>> c.shape
Expand All @@ -631,8 +642,8 @@ def inner(a, b):
array([[ 14, 38, 62],
[86, 110, 134]])

>>> a = np.arange(2).reshape((1,1,2))
>>> b = np.arange(6).reshape((3,2))
>>> a = np.arange(2).reshape((1, 1, 2))
>>> b = np.arange(6).reshape((3, 2))
>>> c = np.inner(a, b)
>>> c.shape
(1, 1, 3)
Expand Down Expand Up @@ -704,19 +715,19 @@ def kron(a, b):
>>> np.kron(b, a)
array([ 5, 50, 500, ..., 7, 70, 700])

>>> np.kron(np.eye(2), np.ones((2,2)))
>>> np.kron(np.eye(2), np.ones((2, 2)))
array([[1., 1., 0., 0.],
[1., 1., 0., 0.],
[0., 0., 1., 1.],
[0., 0., 1., 1.]])

>>> a = np.arange(100).reshape((2,5,2,5))
>>> b = np.arange(24).reshape((2,3,4))
>>> c = np.kron(a,b)
>>> a = np.arange(100).reshape((2, 5, 2, 5))
>>> b = np.arange(24).reshape((2, 3, 4))
>>> c = np.kron(a, b)
>>> c.shape
(2, 10, 6, 20)
>>> I = (1,3,0,2)
>>> J = (0,2,1)
>>> I = (1, 3, 0, 2)
>>> J = (0, 2, 1)
>>> J1 = (0,) + J # extend to ndim=4
>>> S1 = (1,) + b.shape
>>> K = tuple(np.array(I) * np.array(S1) + np.array(J1))
Expand Down Expand Up @@ -869,7 +880,7 @@ def matmul(

>>> a = np.arange(2 * 2 * 4).reshape((2, 2, 4))
>>> b = np.arange(2 * 2 * 4).reshape((2, 4, 2))
>>> np.matmul(a,b).shape
>>> np.matmul(a, b).shape
(2, 2, 2)
>>> np.matmul(a, b)[0, 1, 1]
array(98)
Expand Down Expand Up @@ -1042,6 +1053,7 @@ def outer(a, b, out=None):
Second input vector. Input is flattened if not already 1-dimensional.
out : {None, dpnp.ndarray, usm_ndarray}, optional
A location where the result is stored.

Default: ``None``.

Returns
Expand Down Expand Up @@ -1176,9 +1188,9 @@ def tensordot(a, b, axes=2):
>>> np.tensordot(a, b, 1)
array([14, 32, 50])

>>> a = np.arange(60.).reshape(3,4,5)
>>> b = np.arange(24.).reshape(4,3,2)
>>> c = np.tensordot(a,b, axes=([1,0],[0,1]))
>>> a = np.arange(60.).reshape(3, 4, 5)
>>> b = np.arange(24.).reshape(4, 3, 2)
>>> c = np.tensordot(a, b, axes=([1, 0], [0, 1]))
>>> c.shape
(5, 2)
>>> c
Expand All @@ -1190,12 +1202,12 @@ def tensordot(a, b, axes=2):

A slower but equivalent way of computing the same...

>>> d = np.zeros((5,2))
>>> d = np.zeros((5, 2))
>>> for i in range(5):
... for j in range(2):
... for k in range(3):
... for n in range(4):
... d[i,j] += a[k,n,i] * b[n,k,j]
... d[i, j] += a[k, n, i] * b[n, k, j]
>>> c == d
array([[ True, True],
[ True, True],
Expand Down
16 changes: 8 additions & 8 deletions dpnp/dpnp_iface_manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ def atleast_1d(*arys):
>>> np.atleast_1d(x, y)
[array([1.]), array([3, 4])]

>>> x = np.arange(9.0).reshape(3,3)
>>> x = np.arange(9.0).reshape(3, 3)
>>> np.atleast_1d(x)
array([[0., 1., 2.],
[3., 4., 5.],
Expand Down Expand Up @@ -3342,7 +3342,7 @@ def rollaxis(x, axis, start=0):
Examples
--------
>>> import dpnp as np
>>> a = np.ones((3,4,5,6))
>>> a = np.ones((3, 4, 5, 6))
>>> np.rollaxis(a, 3, 1).shape
(3, 6, 4, 5)
>>> np.rollaxis(a, 2).shape
Expand Down Expand Up @@ -3405,11 +3405,11 @@ def rot90(m, k=1, axes=(0, 1)):

Notes
-----
``rot90(m, k=1, axes=(1,0))`` is the reverse of
``rot90(m, k=1, axes=(0,1))``.
``rot90(m, k=1, axes=(1, 0))`` is the reverse of
``rot90(m, k=1, axes=(0, 1))``.

``rot90(m, k=1, axes=(1,0))`` is equivalent to
``rot90(m, k=-1, axes=(0,1))``.
``rot90(m, k=1, axes=(1, 0))`` is equivalent to
``rot90(m, k=-1, axes=(0, 1))``.

Examples
--------
Expand Down Expand Up @@ -3837,13 +3837,13 @@ def swapaxes(a, axis1, axis2):
[2],
[3]])

>>> x = np.array([[[0,1],[2,3]],[[4,5],[6,7]]])
>>> x = np.array([[[0, 1],[2, 3]],[[4, 5],[6, 7]]])
>>> x
array([[[0, 1],
[2, 3]],
[[4, 5],
[6, 7]]])
>>> np.swapaxes(x,0,2)
>>> np.swapaxes(x, 0, 2)
array([[[0, 4],
[2, 6]],
[[1, 5],
Expand Down
8 changes: 4 additions & 4 deletions dpnp/dpnp_iface_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ def corrcoef(x, y=None, rowvar=True, *, dtype=None):
out /= stddev[None, :]

# Clip real and imaginary parts to [-1, 1]. This does not guarantee
# abs(a[i,j]) <= 1 for complex arrays, but is the best we can do without
# abs(a[i, j]) <= 1 for complex arrays, but is the best we can do without
# excessive work.
dpnp.clip(out.real, -1, 1, out=out.real)
if dpnp.iscomplexobj(out):
Expand Down Expand Up @@ -851,7 +851,7 @@ def cov(
array([[ 1., -1.],
[-1., 1.]])

Note that element :math:`C_{0,1}`, which shows the correlation between
Note that element :math:`C_{0, 1}`, which shows the correlation between
:math:`x_0` and :math:`x_1`, is negative.

Further, note how `x` and `y` are combined:
Expand Down Expand Up @@ -974,7 +974,7 @@ def max(a, axis=None, out=None, keepdims=False, initial=None, where=True):
Examples
--------
>>> import dpnp as np
>>> a = np.arange(4).reshape((2,2))
>>> a = np.arange(4).reshape((2, 2))
>>> a
array([[0, 1],
[2, 3]])
Expand Down Expand Up @@ -1251,7 +1251,7 @@ def min(a, axis=None, out=None, keepdims=False, initial=None, where=True):
Examples
--------
>>> import dpnp as np
>>> a = np.arange(4).reshape((2,2))
>>> a = np.arange(4).reshape((2, 2))
>>> a
array([[0, 1],
[2, 3]])
Expand Down
Loading
Loading