Skip to content
This repository was archived by the owner on Nov 17, 2023. It is now read-only.
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
27 changes: 26 additions & 1 deletion python/mxnet/numpy/linalg.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

__all__ = ['norm', 'svd', 'cholesky', 'qr', 'inv', 'det', 'slogdet', 'solve', 'tensorinv', 'tensorsolve',
'pinv', 'eigvals', 'eig', 'eigvalsh', 'eigh', 'lstsq', 'matrix_rank', 'cross', 'diagonal', 'outer',
'tensordot', 'trace', 'matrix_transpose', 'vecdot']
'tensordot', 'trace', 'matrix_transpose', 'vecdot', 'svdvals']
__all__ += fallback_linalg.__all__


Expand Down Expand Up @@ -703,6 +703,31 @@ def svd(a):
return _mx_nd_np.linalg.svd(a)


def svdvals(a):
r"""
Computes the singular values of a matrix (or a stack of matrices) `x`.

Parameters
----------
a : (..., M, N) ndarray
A real array with ``a.ndim >= 2`` and ``M <= N``.

Returns
-------
out : (..., M) ndarray
Vector(s) with the singular values, within each vector sorted in
descending order. The first ``a.ndim - 2`` dimensions have the same
size as those of the input `a`.

.. note::
`svdvals` is a standard api in
https://data-apis.org/array-api/latest/extensions/linear_algebra_functions.html#linalg-svdvals-x
instead of an official NumPy operator.
"""
_, s, _ = _mx_nd_np.linalg.svd(a)
return s


def cholesky(a):
r"""
Cholesky decomposition.
Expand Down
45 changes: 45 additions & 0 deletions tests/python/unittest/test_numpy_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -5928,6 +5928,51 @@ def check_svd(UT, L, V, data_np):
check_svd(UT, L, V, data_np)


@use_np
@pytest.mark.parametrize('shape', [
(3, 3),
(3, 5),
(4, 4),
(4, 5),
(5, 5),
(5, 6),
(6, 6),
(0, 1),
(6, 5, 6),
(2, 3, 3, 4),
(4, 2, 1, 2),
(0, 5, 3, 3),
(5, 0, 3, 3),
(3, 3, 0, 0),
])
@pytest.mark.parametrize('dtype', ['float32', 'float64'])
@pytest.mark.parametrize('hybridize', [False, True])
def test_np_linalg_svdvals(shape, dtype, hybridize):
class TestSVD(HybridBlock):
def __init__(self):
super(TestSVD, self).__init__()

def forward(self, data):
return np.linalg.svdvals(data)

rtol = atol = 0.01
test_svd = TestSVD()
if hybridize:
test_svd.hybridize()
data_np = onp.random.uniform(-10.0, 10.0, shape)
data_np = onp.array(data_np, dtype=dtype)
data = np.array(data_np, dtype=dtype)
if effective_dtype(data) == onp.dtype(np.float16):
pytest.skip()
mx_out = test_svd(data)
np_out = onp.linalg.svd(data, compute_uv=False)
# check svdvals validity
assert_almost_equal(mx_out.asnumpy(), np_out, rtol=rtol, atol=atol)
# Test imperative once again
mx_out = np.linalg.svdvals(data)
assert_almost_equal(mx_out.asnumpy(), np_out, rtol=rtol, atol=atol)


@use_np
def test_np_linalg_qr():
class TestQR(HybridBlock):
Expand Down