diff options
Diffstat (limited to 'numpy/linalg/linalg.py')
-rw-r--r-- | numpy/linalg/linalg.py | 633 |
1 files changed, 290 insertions, 343 deletions
diff --git a/numpy/linalg/linalg.py b/numpy/linalg/linalg.py index 34fe9b550..ae0da3685 100644 --- a/numpy/linalg/linalg.py +++ b/numpy/linalg/linalg.py @@ -22,9 +22,9 @@ from numpy.core import array, asarray, zeros, empty, transpose, \ intc, single, double, csingle, cdouble, inexact, complexfloating, \ newaxis, ravel, all, Inf, dot, add, multiply, identity, sqrt, \ maximum, flatnonzero, diagonal, arange, fastCopyAndTranspose, sum, \ - isfinite, size, finfo, absolute, log, exp + isfinite, size, finfo, absolute, log, exp, errstate, geterrobj from numpy.lib import triu -from numpy.linalg import lapack_lite +from numpy.linalg import lapack_lite, _umath_linalg from numpy.matrixlib.defmatrix import matrix_power from numpy.compat import asbytes @@ -67,6 +67,40 @@ class LinAlgError(Exception): """ pass +# Dealing with errors in _umath_linalg + +_linalg_error_extobj = None + +def _determine_error_states(): + global _linalg_error_extobj + errobj = geterrobj() + bufsize = errobj[0] + + with errstate(invalid='call', over='ignore', + divide='ignore', under='ignore'): + invalid_call_errmask = geterrobj()[1] + + _linalg_error_extobj = [bufsize, invalid_call_errmask, None] + +_determine_error_states() + +def _raise_linalgerror_singular(err, flag): + raise LinAlgError("Singular matrix") + +def _raise_linalgerror_nonposdef(err, flag): + raise LinAlgError("Matrix is not positive definite") + +def _raise_linalgerror_eigenvalues_nonconvergence(err, flag): + raise LinAlgError("Eigenvalues did not converge") + +def _raise_linalgerror_svd_nonconvergence(err, flag): + raise LinAlgError("SVD did not converge") + +def get_linalg_error_extobj(callback): + extobj = list(_linalg_error_extobj) + extobj[2] = callback + return extobj + def _makearray(a): new = asarray(a) wrap = getattr(a, "__array_prepare__", new.__array_wrap__) @@ -124,6 +158,7 @@ def _commonType(*arrays): t = double return t, result_type + # _fastCopyAndTranpose assumes the input is 2D (as all the calls in here are). _fastCT = fastCopyAndTranspose @@ -158,11 +193,22 @@ def _assertRank2(*arrays): raise LinAlgError('%d-dimensional array given. Array must be ' 'two-dimensional' % len(a.shape)) +def _assertRankAtLeast2(*arrays): + for a in arrays: + if len(a.shape) < 2: + raise LinAlgError('%d-dimensional array given. Array must be ' + 'at least two-dimensional' % len(a.shape)) + def _assertSquareness(*arrays): for a in arrays: if max(a.shape) != min(a.shape): raise LinAlgError('Array must be square') +def _assertNdSquareness(*arrays): + for a in arrays: + if max(a.shape[-2:]) != min(a.shape[-2:]): + raise LinAlgError('Last 2 dimensions of the array must be square') + def _assertFinite(*arrays): for a in arrays: if not (isfinite(a).all()): @@ -254,14 +300,14 @@ def solve(a, b): Parameters ---------- - a : (M, M) array_like + a : (..., M, M) array_like Coefficient matrix. - b : {(M,), (M, N)}, array_like + b : {(..., M,), (..., M, K)}, array_like Ordinate or "dependent variable" values. Returns ------- - x : {(M,), (M, N)} ndarray + x : {(..., M,), (..., M, K)} ndarray Solution to the system a x = b. Returned shape is identical to `b`. Raises @@ -271,15 +317,10 @@ def solve(a, b): Notes ----- - `solve` is a wrapper for the LAPACK routines `dgesv`_ and - `zgesv`_, the former being used if `a` is real-valued, the latter if - it is complex-valued. The solution to the system of linear equations - is computed using an LU decomposition [1]_ with partial pivoting and - row interchanges. - - .. _dgesv: http://www.netlib.org/lapack/double/dgesv.f + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. - .. _zgesv: http://www.netlib.org/lapack/complex16/zgesv.f + The solutions are computed using LAPACK routine _gesv `a` must be square and of full-rank, i.e., all rows (or, equivalently, columns) must be linearly independent; if either is not true, use @@ -308,32 +349,22 @@ def solve(a, b): """ a, _ = _makearray(a) + _assertNonEmpty(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) b, wrap = _makearray(b) - one_eq = len(b.shape) == 1 - if one_eq: - b = b[:, newaxis] - _assertRank2(a, b) - _assertSquareness(a) - n_eq = a.shape[0] - n_rhs = b.shape[1] - if n_eq != b.shape[0]: - raise LinAlgError('Incompatible dimensions') t, result_t = _commonType(a, b) -# lapack_routine = _findLapackRoutine('gesv', t) - if isComplexType(t): - lapack_routine = lapack_lite.zgesv - else: - lapack_routine = lapack_lite.dgesv - a, b = _fastCopyAndTranspose(t, a, b) - a, b = _to_native_byte_order(a, b) - pivots = zeros(n_eq, fortran_int) - results = lapack_routine(n_eq, n_rhs, a, n_eq, pivots, b, n_eq, 0) - if results['info'] > 0: - raise LinAlgError('Singular matrix') - if one_eq: - return wrap(b.ravel().astype(result_t)) + + if len(b.shape) == len(a.shape) - 1: + gufunc = _umath_linalg.solve1 else: - return wrap(b.transpose().astype(result_t)) + gufunc = _umath_linalg.solve + + signature = 'DD->D' if isComplexType(t) else 'dd->d' + extobj = get_linalg_error_extobj(_raise_linalgerror_singular) + r = gufunc(a, b, signature=signature, extobj=extobj) + + return wrap(r.astype(result_t)) def tensorinv(a, ind=2): @@ -414,24 +445,29 @@ def inv(a): Parameters ---------- - a : (M, M) array_like + a : (..., M, M) array_like Matrix to be inverted. Returns ------- - ainv : (M, M) ndarray or matrix + ainv : (..., M, M) ndarray or matrix (Multiplicative) inverse of the matrix `a`. Raises ------ LinAlgError - If `a` is singular or not square. + If `a` is not square or inversion fails. + + Notes + ----- + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. Examples -------- - >>> from numpy import linalg as LA + >>> from numpy.linalg import inv >>> a = np.array([[1., 2.], [3., 4.]]) - >>> ainv = LA.inv(a) + >>> ainv = inv(a) >>> np.allclose(np.dot(a, ainv), np.eye(2)) True >>> np.allclose(np.dot(ainv, a), np.eye(2)) @@ -439,14 +475,30 @@ def inv(a): If a is a matrix object, then the return value is a matrix as well: - >>> ainv = LA.inv(np.matrix(a)) + >>> ainv = inv(np.matrix(a)) >>> ainv matrix([[-2. , 1. ], [ 1.5, -0.5]]) + Inverses of several matrices can be computed at once: + + >>> a = np.array([[[1., 2.], [3., 4.]], [[1, 3], [3, 5]]]) + >>> inv(a) + array([[[-2. , 1. ], + [ 1.5, -0.5]], + [[-5. , 2. ], + [ 3. , -1. ]]]) + """ a, wrap = _makearray(a) - return wrap(solve(a, identity(a.shape[0], dtype=a.dtype))) + _assertNonEmpty(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) + t, result_t = _commonType(a) + signature = 'D->D' if isComplexType(t) else 'd->d' + extobj = get_linalg_error_extobj(_raise_linalgerror_singular) + ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj) + return wrap(ainv.astype(result_t)) # Cholesky decomposition @@ -463,15 +515,15 @@ def cholesky(a): Parameters ---------- - a : (M, M) array_like + a : (..., M, M) array_like Hermitian (symmetric if all elements are real), positive-definite input matrix. Returns ------- - L : {(M, M) ndarray, (M, M) matrix} - Lower-triangular Cholesky factor of `a`. Returns a matrix object - if `a` is a matrix object. + L : (..., M, M) array_like + Upper or lower-triangular Cholesky factor of `a`. Returns a + matrix object if `a` is a matrix object. Raises ------ @@ -481,6 +533,9 @@ def cholesky(a): Notes ----- + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + The Cholesky decomposition is often used as a fast way of solving .. math:: A \\mathbf{x} = \\mathbf{b} @@ -518,26 +573,14 @@ def cholesky(a): [ 0.+2.j, 1.+0.j]]) """ + extobj = get_linalg_error_extobj(_raise_linalgerror_nonposdef) + gufunc = _umath_linalg.cholesky_lo a, wrap = _makearray(a) - _assertRank2(a) - _assertSquareness(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) t, result_t = _commonType(a) - a = _fastCopyAndTranspose(t, a) - a = _to_native_byte_order(a) - m = a.shape[0] - n = a.shape[1] - if isComplexType(t): - lapack_routine = lapack_lite.zpotrf - else: - lapack_routine = lapack_lite.dpotrf - results = lapack_routine(_L, n, a, m, 0) - if results['info'] > 0: - raise LinAlgError('Matrix is not positive definite - ' - 'Cholesky decomposition cannot be computed') - s = triu(a, k=0).transpose() - if (s.dtype != result_t): - s = s.astype(result_t) - return wrap(s) + signature = 'D->D' if isComplexType(t) else 'd->d' + return wrap(gufunc(a, signature=signature, extobj=extobj).astype(result_t)) # QR decompostion @@ -763,12 +806,12 @@ def eigvals(a): Parameters ---------- - a : (M, M) array_like + a : (..., M, M) array_like A complex- or real-valued matrix whose eigenvalues will be computed. Returns ------- - w : (M,) ndarray + w : (..., M,) ndarray The eigenvalues, each repeated according to its multiplicity. They are not necessarily ordered, nor are they necessarily real for real matrices. @@ -786,9 +829,11 @@ def eigvals(a): Notes ----- - This is a simple interface to the LAPACK routines dgeev and zgeev - that sets those routines' flags to return only the eigenvalues of - general real and complex arrays, respectively. + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + This is implemented using the _geev LAPACK routines which compute + the eigenvalues and eigenvectors of general square arrays. Examples -------- @@ -817,49 +862,25 @@ def eigvals(a): """ a, wrap = _makearray(a) - _assertRank2(a) - _assertSquareness(a) + _assertNonEmpty(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) _assertFinite(a) t, result_t = _commonType(a) - real_t = _linalgRealType(t) - a = _fastCopyAndTranspose(t, a) - a = _to_native_byte_order(a) - n = a.shape[0] - dummy = zeros((1,), t) - if isComplexType(t): - lapack_routine = lapack_lite.zgeev - w = zeros((n,), t) - rwork = zeros((n,), real_t) - lwork = 1 - work = zeros((lwork,), t) - results = lapack_routine(_N, _N, n, a, n, w, - dummy, 1, dummy, 1, work, -1, rwork, 0) - lwork = int(abs(work[0])) - work = zeros((lwork,), t) - results = lapack_routine(_N, _N, n, a, n, w, - dummy, 1, dummy, 1, work, lwork, rwork, 0) - else: - lapack_routine = lapack_lite.dgeev - wr = zeros((n,), t) - wi = zeros((n,), t) - lwork = 1 - work = zeros((lwork,), t) - results = lapack_routine(_N, _N, n, a, n, wr, wi, - dummy, 1, dummy, 1, work, -1, 0) - lwork = int(work[0]) - work = zeros((lwork,), t) - results = lapack_routine(_N, _N, n, a, n, wr, wi, - dummy, 1, dummy, 1, work, lwork, 0) - if all(wi == 0.): - w = wr + + extobj = get_linalg_error_extobj( + _raise_linalgerror_eigenvalues_nonconvergence) + signature = 'D->D' if isComplexType(t) else 'd->D' + w = _umath_linalg.eigvals(a, signature=signature, extobj=extobj) + + if not isComplexType(t): + if all(w.imag == 0): + w = w.real result_t = _realType(result_t) else: - w = wr+1j*wi result_t = _complexType(result_t) - if results['info'] > 0: - raise LinAlgError('Eigenvalues did not converge') - return w.astype(result_t) + return w.astype(result_t) def eigvalsh(a, UPLO='L'): """ @@ -869,16 +890,16 @@ def eigvalsh(a, UPLO='L'): Parameters ---------- - a : (M, M) array_like + a : (..., M, M) array_like A complex- or real-valued matrix whose eigenvalues are to be computed. UPLO : {'L', 'U'}, optional - Specifies whether the calculation is done with the lower triangular - part of `a` ('L', default) or the upper triangular part ('U'). + Same as `lower`, wth 'L' for lower and 'U' for upper triangular. + Deprecated. Returns ------- - w : (M,) ndarray + w : (..., M,) ndarray The eigenvalues, not necessarily ordered, each repeated according to its multiplicity. @@ -896,9 +917,10 @@ def eigvalsh(a, UPLO='L'): Notes ----- - This is a simple interface to the LAPACK routines dsyevd and zheevd - that sets those routines' flags to return only the eigenvalues of - real symmetric and complex Hermitian arrays, respectively. + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + The eigenvalues are computed using LAPACK routines _ssyevd, _heevd Examples -------- @@ -908,45 +930,21 @@ def eigvalsh(a, UPLO='L'): array([ 0.17157288+0.j, 5.82842712+0.j]) """ - UPLO = asbytes(UPLO) + + extobj = get_linalg_error_extobj( + _raise_linalgerror_eigenvalues_nonconvergence) + if UPLO == 'L': + gufunc = _umath_linalg.eigvalsh_lo + else: + gufunc = _umath_linalg.eigvalsh_up + a, wrap = _makearray(a) - _assertRank2(a) - _assertSquareness(a) + _assertNonEmpty(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) t, result_t = _commonType(a) - real_t = _linalgRealType(t) - a = _fastCopyAndTranspose(t, a) - a = _to_native_byte_order(a) - n = a.shape[0] - liwork = 5*n+3 - iwork = zeros((liwork,), fortran_int) - if isComplexType(t): - lapack_routine = lapack_lite.zheevd - w = zeros((n,), real_t) - lwork = 1 - work = zeros((lwork,), t) - lrwork = 1 - rwork = zeros((lrwork,), real_t) - results = lapack_routine(_N, UPLO, n, a, n, w, work, -1, - rwork, -1, iwork, liwork, 0) - lwork = int(abs(work[0])) - work = zeros((lwork,), t) - lrwork = int(rwork[0]) - rwork = zeros((lrwork,), real_t) - results = lapack_routine(_N, UPLO, n, a, n, w, work, lwork, - rwork, lrwork, iwork, liwork, 0) - else: - lapack_routine = lapack_lite.dsyevd - w = zeros((n,), t) - lwork = 1 - work = zeros((lwork,), t) - results = lapack_routine(_N, UPLO, n, a, n, w, work, -1, - iwork, liwork, 0) - lwork = int(work[0]) - work = zeros((lwork,), t) - results = lapack_routine(_N, UPLO, n, a, n, w, work, lwork, - iwork, liwork, 0) - if results['info'] > 0: - raise LinAlgError('Eigenvalues did not converge') + signature = 'D->d' if isComplexType(t) else 'd->d' + w = gufunc(a, signature=signature, extobj=extobj) return w.astype(result_t) def _convertarray(a): @@ -964,17 +962,20 @@ def eig(a): Parameters ---------- - a : (M, M) array_like - A square array of real or complex elements. + a : (..., M, M) array + Matrices for which the eigenvalues and right eigenvectors will + be computed Returns ------- - w : (M,) ndarray + w : (..., M) array The eigenvalues, each repeated according to its multiplicity. - The eigenvalues are not necessarily ordered, nor are they - necessarily real for real arrays (though for real arrays - complex-valued eigenvalues should occur in conjugate pairs). - v : (M, M) ndarray + The eigenvalues are not necessarily ordered. The resulting + array will be always be of complex type. When `a` is real + the resulting eigenvalues will be real (0 imaginary part) or + occur in conjugate pairs + + v : (..., M, M) array The normalized (unit "length") eigenvectors, such that the column ``v[:,i]`` is the eigenvector corresponding to the eigenvalue ``w[i]``. @@ -993,9 +994,11 @@ def eig(a): Notes ----- - This is a simple interface to the LAPACK routines dgeev and zgeev - which compute the eigenvalues and eigenvectors of, respectively, - general real- and complex-valued square arrays. + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + This is implemented using the _geev LAPACK routines which compute + the eigenvalues and eigenvectors of general square arrays. The number `w` is an eigenvalue of `a` if there exists a vector `v` such that ``dot(a,v) = w * v``. Thus, the arrays `a`, `w`, and @@ -1066,57 +1069,24 @@ def eig(a): """ a, wrap = _makearray(a) - _assertRank2(a) - _assertSquareness(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) _assertFinite(a) - a, t, result_t = _convertarray(a) # convert to double or cdouble type - a = _to_native_byte_order(a) - real_t = _linalgRealType(t) - n = a.shape[0] - dummy = zeros((1,), t) - if isComplexType(t): - # Complex routines take different arguments - lapack_routine = lapack_lite.zgeev - w = zeros((n,), t) - v = zeros((n, n), t) - lwork = 1 - work = zeros((lwork,), t) - rwork = zeros((2*n,), real_t) - results = lapack_routine(_N, _V, n, a, n, w, - dummy, 1, v, n, work, -1, rwork, 0) - lwork = int(abs(work[0])) - work = zeros((lwork,), t) - results = lapack_routine(_N, _V, n, a, n, w, - dummy, 1, v, n, work, lwork, rwork, 0) + t, result_t = _commonType(a) + + extobj = get_linalg_error_extobj( + _raise_linalgerror_eigenvalues_nonconvergence) + signature = 'D->DD' if isComplexType(t) else 'd->DD' + w, vt = _umath_linalg.eig(a, signature=signature, extobj=extobj) + + if not isComplexType(t) and all(w.imag == 0.0): + w = w.real + vt = vt.real + result_t = _realType(result_t) else: - lapack_routine = lapack_lite.dgeev - wr = zeros((n,), t) - wi = zeros((n,), t) - vr = zeros((n, n), t) - lwork = 1 - work = zeros((lwork,), t) - results = lapack_routine(_N, _V, n, a, n, wr, wi, - dummy, 1, vr, n, work, -1, 0) - lwork = int(work[0]) - work = zeros((lwork,), t) - results = lapack_routine(_N, _V, n, a, n, wr, wi, - dummy, 1, vr, n, work, lwork, 0) - if all(wi == 0.0): - w = wr - v = vr - result_t = _realType(result_t) - else: - w = wr+1j*wi - v = array(vr, w.dtype) - ind = flatnonzero(wi != 0.0) # indices of complex e-vals - for i in range(len(ind)//2): - v[ind[2*i]] = vr[ind[2*i]] + 1j*vr[ind[2*i+1]] - v[ind[2*i+1]] = vr[ind[2*i]] - 1j*vr[ind[2*i+1]] - result_t = _complexType(result_t) + result_t = _complexType(result_t) - if results['info'] > 0: - raise LinAlgError('Eigenvalues did not converge') - vt = v.transpose().astype(result_t) + vt = vt.astype(result_t) return w.astype(result_t), wrap(vt) @@ -1130,17 +1100,18 @@ def eigh(a, UPLO='L'): Parameters ---------- - a : (M, M) array_like - A complex Hermitian or real symmetric matrix. + A : (..., M, M) array + Hermitian/Symmetric matrices whose eigenvalues and + eigenvectors are to be computed. UPLO : {'L', 'U'}, optional Specifies whether the calculation is done with the lower triangular part of `a` ('L', default) or the upper triangular part ('U'). Returns ------- - w : (M,) ndarray + w : (..., M) ndarray The eigenvalues, not necessarily ordered. - v : {(M, M) ndarray, (M, M) matrix} + v : {(..., M, M) ndarray, (..., M, M) matrix} The column ``v[:, i]`` is the normalized eigenvector corresponding to the eigenvalue ``w[i]``. Will return a matrix object if `a` is a matrix object. @@ -1158,9 +1129,11 @@ def eigh(a, UPLO='L'): Notes ----- - This is a simple interface to the LAPACK routines dsyevd and zheevd, - which compute the eigenvalues and eigenvectors of real symmetric and - complex Hermitian arrays, respectively. + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + The eigenvalues/eigenvectors are computed using LAPACK routines _ssyevd, + _heevd The eigenvalues of real symmetric or complex Hermitian matrices are always real. [1]_ The array `v` of (column) eigenvectors is unitary @@ -1202,46 +1175,24 @@ def eigh(a, UPLO='L'): """ UPLO = asbytes(UPLO) + a, wrap = _makearray(a) - _assertRank2(a) - _assertSquareness(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) t, result_t = _commonType(a) - real_t = _linalgRealType(t) - a = _fastCopyAndTranspose(t, a) - a = _to_native_byte_order(a) - n = a.shape[0] - liwork = 5*n+3 - iwork = zeros((liwork,), fortran_int) - if isComplexType(t): - lapack_routine = lapack_lite.zheevd - w = zeros((n,), real_t) - lwork = 1 - work = zeros((lwork,), t) - lrwork = 1 - rwork = zeros((lrwork,), real_t) - results = lapack_routine(_V, UPLO, n, a, n, w, work, -1, - rwork, -1, iwork, liwork, 0) - lwork = int(abs(work[0])) - work = zeros((lwork,), t) - lrwork = int(rwork[0]) - rwork = zeros((lrwork,), real_t) - results = lapack_routine(_V, UPLO, n, a, n, w, work, lwork, - rwork, lrwork, iwork, liwork, 0) + + extobj = get_linalg_error_extobj( + _raise_linalgerror_eigenvalues_nonconvergence) + if 'L' == UPLO: + gufunc = _umath_linalg.eigh_lo else: - lapack_routine = lapack_lite.dsyevd - w = zeros((n,), t) - lwork = 1 - work = zeros((lwork,), t) - results = lapack_routine(_V, UPLO, n, a, n, w, work, -1, - iwork, liwork, 0) - lwork = int(work[0]) - work = zeros((lwork,), t) - results = lapack_routine(_V, UPLO, n, a, n, w, work, lwork, - iwork, liwork, 0) - if results['info'] > 0: - raise LinAlgError('Eigenvalues did not converge') - at = a.transpose().astype(result_t) - return w.astype(_realType(result_t)), wrap(at) + gufunc = _umath_linalg.eigh_up + + signature = 'D->dD' if isComplexType(t) else 'd->dd' + w, vt = gufunc(a, signature=signature, extobj=extobj) + w = w.astype(_realType(result_t)) + vt = vt.astype(result_t) + return w, wrap(vt) # Singular value decomposition @@ -1255,7 +1206,7 @@ def svd(a, full_matrices=1, compute_uv=1): Parameters ---------- - a : array_like + a : (..., M, N) array_like A real or complex matrix of shape (`M`, `N`) . full_matrices : bool, optional If True (default), `u` and `v` have the shapes (`M`, `M`) and @@ -1267,15 +1218,14 @@ def svd(a, full_matrices=1, compute_uv=1): Returns ------- - u : ndarray - Unitary matrix. The shape of `u` is (`M`, `M`) or (`M`, `K`) - depending on value of ``full_matrices``. - s : ndarray - The singular values, sorted so that ``s[i] >= s[i+1]``. `s` is - a 1-d array of length min(`M`, `N`). - v : ndarray - Unitary matrix of shape (`N`, `N`) or (`K`, `N`), depending on - ``full_matrices``. + u : { (..., M, M), (..., M, K) } array + Unitary matrices. The actual shape depends on the value of + ``full_matrices``. Only returned when ``compute_uv`` is True. + s : (..., K) array + The singular values for every matrix, sorted in descending order. + v : { (..., N, N), (..., K, N) } array + Unitary matrices. The actual shape depends on the value of + ``full_matrices``. Only returned when ``compute_uv`` is True. Raises ------ @@ -1284,6 +1234,11 @@ def svd(a, full_matrices=1, compute_uv=1): Notes ----- + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + + The decomposition is performed using LAPACK routine _gesdd + The SVD is commonly written as ``a = U S V.H``. The `v` returned by this function is ``V.H`` and ``u = U``. @@ -1323,63 +1278,41 @@ def svd(a, full_matrices=1, compute_uv=1): """ a, wrap = _makearray(a) - _assertRank2(a) _assertNonEmpty(a) - m, n = a.shape + _assertRankAtLeast2(a) t, result_t = _commonType(a) - real_t = _linalgRealType(t) - a = _fastCopyAndTranspose(t, a) - a = _to_native_byte_order(a) - s = zeros((min(n, m),), real_t) + + extobj = get_linalg_error_extobj(_raise_linalgerror_svd_nonconvergence) + + m = a.shape[-2] + n = a.shape[-1] if compute_uv: if full_matrices: - nu = m - nvt = n - option = _A + if m < n: + gufunc = _umath_linalg.svd_m_f + else: + gufunc = _umath_linalg.svd_n_f else: - nu = min(n, m) - nvt = min(n, m) - option = _S - u = zeros((nu, m), t) - vt = zeros((n, nvt), t) - else: - option = _N - nu = 1 - nvt = 1 - u = empty((1, 1), t) - vt = empty((1, 1), t) + if m < n: + gufunc = _umath_linalg.svd_m_s + else: + gufunc = _umath_linalg.svd_n_s - iwork = zeros((8*min(m, n),), fortran_int) - if isComplexType(t): - lapack_routine = lapack_lite.zgesdd - lrwork = min(m,n)*max(5*min(m,n)+7, 2*max(m,n)+2*min(m,n)+1) - rwork = zeros((lrwork,), real_t) - lwork = 1 - work = zeros((lwork,), t) - results = lapack_routine(option, m, n, a, m, s, u, m, vt, nvt, - work, -1, rwork, iwork, 0) - lwork = int(abs(work[0])) - work = zeros((lwork,), t) - results = lapack_routine(option, m, n, a, m, s, u, m, vt, nvt, - work, lwork, rwork, iwork, 0) - else: - lapack_routine = lapack_lite.dgesdd - lwork = 1 - work = zeros((lwork,), t) - results = lapack_routine(option, m, n, a, m, s, u, m, vt, nvt, - work, -1, iwork, 0) - lwork = int(work[0]) - work = zeros((lwork,), t) - results = lapack_routine(option, m, n, a, m, s, u, m, vt, nvt, - work, lwork, iwork, 0) - if results['info'] > 0: - raise LinAlgError('SVD did not converge') - s = s.astype(_realType(result_t)) - if compute_uv: - u = u.transpose().astype(result_t) - vt = vt.transpose().astype(result_t) + signature = 'D->DdD' if isComplexType(t) else 'd->ddd' + u, s, vt = gufunc(a, signature=signature, extobj=extobj) + u = u.astype(result_t) + s = s.astype(_realType(result_t)) + vt = vt.astype(result_t) return wrap(u), s, wrap(vt) else: + if m < n: + gufunc = _umath_linalg.svd_m + else: + gufunc = _umath_linalg.svd_n + + signature = 'D->d' if isComplexType(t) else 'd->d' + s = gufunc(a, signature=signature, extobj=extobj) + s = s.astype(_realType(result_t)) return s def cond(x, p=None): @@ -1649,16 +1582,16 @@ def slogdet(a): Parameters ---------- - a : array_like + a : (..., M, M) array_like Input array, has to be a square 2-D array. Returns ------- - sign : float or complex + sign : (...) array_like A number representing the sign of the determinant. For a real matrix, this is 1, 0, or -1. For a complex matrix, this is a complex number with absolute value 1 (i.e., it is on the unit circle), or else 0. - logdet : float + logdet : (...) array_like The natural log of the absolute value of the determinant. If the determinant is zero, then `sign` will be 0 and `logdet` will be @@ -1670,6 +1603,9 @@ def slogdet(a): Notes ----- + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + The determinant is computed via LU factorization using the LAPACK routine z/dgetrf. @@ -1686,6 +1622,17 @@ def slogdet(a): >>> sign * np.exp(logdet) -2.0 + Computing log-determinants for a stack of matrices: + + >>> a = np.array([ [[1, 2], [3, 4]], [[1, 2], [2, 1]], [[1, 3], [3, 1]] ]) + >>> a.shape + (3, 2, 2) + >>> sign, logdet = np.linalg.slogdet(a) + >>> (sign, logdet) + (array([-1., -1., -1.]), array([ 0.69314718, 1.09861229, 2.07944154])) + >>> sign * np.exp(logdet) + array([-2., -3., -8.]) + This routine succeeds where ordinary `det` does not: >>> np.linalg.det(np.eye(500) * 0.1) @@ -1695,30 +1642,14 @@ def slogdet(a): """ a = asarray(a) - _assertRank2(a) - _assertSquareness(a) + _assertNonEmpty(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) t, result_t = _commonType(a) - a = _fastCopyAndTranspose(t, a) - a = _to_native_byte_order(a) - n = a.shape[0] - if isComplexType(t): - lapack_routine = lapack_lite.zgetrf - else: - lapack_routine = lapack_lite.dgetrf - pivots = zeros((n,), fortran_int) - results = lapack_routine(n, n, a, n, pivots, 0) - info = results['info'] - if (info < 0): - raise TypeError("Illegal input to Fortran routine") - elif (info > 0): - return (t(0.0), _realType(t)(-Inf)) - sign = 1. - 2. * (add.reduce(pivots != arange(1, n + 1)) % 2) - d = diagonal(a) - absd = absolute(d) - sign *= multiply.reduce(d / absd) - log(absd, absd) - logdet = add.reduce(absd, axis=-1) - return sign, logdet + real_t = _realType(result_t) + signature = 'D->Dd' if isComplexType(t) else 'd->dd' + sign, logdet = _umath_linalg.slogdet(a, signature=signature) + return sign.astype(result_t), logdet.astype(real_t) def det(a): """ @@ -1726,12 +1657,12 @@ def det(a): Parameters ---------- - a : (M, M) array_like - Input array. + a : (..., M, M) array_like + Input array to compute determinants for. Returns ------- - det : float + det : (...) array_like Determinant of `a`. See Also @@ -1741,6 +1672,9 @@ def det(a): Notes ----- + Broadcasting rules apply, see the `numpy.linalg` documentation for + details. + The determinant is computed via LU factorization using the LAPACK routine z/dgetrf. @@ -1752,9 +1686,22 @@ def det(a): >>> np.linalg.det(a) -2.0 + Computing determinants for a stack of matrices: + + >>> a = np.array([ [[1, 2], [3, 4]], [[1, 2], [2, 1]], [[1, 3], [3, 1]] ]) + >>> a.shape + (2, 2, 2 + >>> np.linalg.det(a) + array([-2., -3., -8.]) + """ - sign, logdet = slogdet(a) - return sign * exp(logdet) + a = asarray(a) + _assertNonEmpty(a) + _assertRankAtLeast2(a) + _assertNdSquareness(a) + t, result_t = _commonType(a) + signature = 'D->D' if isComplexType(t) else 'd->d' + return _umath_linalg.det(a, signature=signature).astype(result_t) # Linear Least Squares |