summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Wieser <wieser.eric@gmail.com>2017-03-07 01:04:22 +0000
committerEric Wieser <wieser.eric@gmail.com>2018-06-27 09:49:59 -0700
commitb80d360e2b82cd52ad69548cc292c2bab95de6ce (patch)
tree4bfd5904997294a7741fc30d627ebe1a64a90762
parent65f15a5e881817d8646571d36ab9a0bc39a6667e (diff)
downloadnumpy-b80d360e2b82cd52ad69548cc292c2bab95de6ce.tar.gz
ENH: Allow use of svd on empty arrays
part of #8654
-rw-r--r--numpy/linalg/linalg.py2
-rw-r--r--numpy/linalg/tests/test_linalg.py26
-rw-r--r--numpy/linalg/umath_linalg.c.src14
3 files changed, 25 insertions, 17 deletions
diff --git a/numpy/linalg/linalg.py b/numpy/linalg/linalg.py
index 90dc2e657..8e7ad70cd 100644
--- a/numpy/linalg/linalg.py
+++ b/numpy/linalg/linalg.py
@@ -1527,7 +1527,6 @@ def svd(a, full_matrices=True, compute_uv=True):
"""
a, wrap = _makearray(a)
- _assertNoEmpty2d(a)
_assertRankAtLeast2(a)
t, result_t = _commonType(a)
@@ -1644,6 +1643,7 @@ def cond(x, p=None):
"""
x = asarray(x) # in case we have a matrix
+ _assertNoEmpty2d(x)
if p is None or p == 2 or p == -2:
s = svd(x, compute_uv=False)
with errstate(all='ignore'):
diff --git a/numpy/linalg/tests/test_linalg.py b/numpy/linalg/tests/test_linalg.py
index 87dfe988a..1c24f1e04 100644
--- a/numpy/linalg/tests/test_linalg.py
+++ b/numpy/linalg/tests/test_linalg.py
@@ -644,10 +644,6 @@ class TestEig(EigCases):
class SVDCases(LinalgSquareTestCase, LinalgGeneralizedSquareTestCase):
def do(self, a, b, tags):
- if 'size-0' in tags:
- assert_raises(LinAlgError, linalg.svd, a, 0)
- return
-
u, s, vt = linalg.svd(a, 0)
assert_allclose(a, dot_generalized(np.asarray(u) * np.asarray(s)[..., None, :],
np.asarray(vt)),
@@ -670,15 +666,19 @@ class TestSVD(SVDCases):
for dtype in [single, double, csingle, cdouble]:
check(dtype)
- def test_0_size(self):
- # These raise errors currently
- # (which does not mean that it may not make sense)
- a = np.zeros((0, 0), dtype=np.complex64)
- assert_raises(linalg.LinAlgError, linalg.svd, a)
- a = np.zeros((0, 1), dtype=np.complex64)
- assert_raises(linalg.LinAlgError, linalg.svd, a)
- a = np.zeros((1, 0), dtype=np.complex64)
- assert_raises(linalg.LinAlgError, linalg.svd, a)
+ def test_empty_identity(self):
+ """ Empty input should put an identity matrix in u or vh """
+ x = np.empty((4, 0))
+ u, s, vh = linalg.svd(x, compute_uv=True)
+ assert_equal(u.shape, (4, 4))
+ assert_equal(vh.shape, (0, 0))
+ assert_equal(u, np.eye(4))
+
+ x = np.empty((0, 4))
+ u, s, vh = linalg.svd(x, compute_uv=True)
+ assert_equal(u.shape, (0, 0))
+ assert_equal(vh.shape, (4, 4))
+ assert_equal(vh, np.eye(4))
class CondCases(LinalgSquareTestCase, LinalgGeneralizedSquareTestCase):
diff --git a/numpy/linalg/umath_linalg.c.src b/numpy/linalg/umath_linalg.c.src
index 7dc1cb0cb..9fc68a7aa 100644
--- a/numpy/linalg/umath_linalg.c.src
+++ b/numpy/linalg/umath_linalg.c.src
@@ -2735,19 +2735,18 @@ static NPY_INLINE void
(fortran_int)dimensions[0],
(fortran_int)dimensions[1])) {
LINEARIZE_DATA_t a_in, u_out, s_out, v_out;
+ fortran_int min_m_n = params.M < params.N ? params.M : params.N;
init_linearize_data(&a_in, params.N, params.M, steps[1], steps[0]);
if ('N' == params.JOBZ) {
/* only the singular values are wanted */
- fortran_int min_m_n = params.M < params.N? params.M : params.N;
init_linearize_data(&s_out, 1, min_m_n, 0, steps[2]);
} else {
fortran_int u_columns, v_rows;
- fortran_int min_m_n = params.M < params.N? params.M : params.N;
if ('S' == params.JOBZ) {
u_columns = min_m_n;
v_rows = min_m_n;
- } else {
+ } else { /* JOBZ == 'A' */
u_columns = params.M;
v_rows = params.N;
}
@@ -2771,6 +2770,15 @@ static NPY_INLINE void
if ('N' == params.JOBZ) {
delinearize_@REALTYPE@_matrix(args[1], params.S, &s_out);
} else {
+ if ('A' == params.JOBZ && min_m_n == 0) {
+ /* Lapack has betrayed us and left these uninitialized,
+ * so produce an identity matrix for whichever of u
+ * and v is not empty.
+ */
+ identity_@TYPE@_matrix(params.U, params.M);
+ identity_@TYPE@_matrix(params.VT, params.N);
+ }
+
delinearize_@TYPE@_matrix(args[1], params.U, &u_out);
delinearize_@REALTYPE@_matrix(args[2], params.S, &s_out);
delinearize_@TYPE@_matrix(args[3], params.VT, &v_out);