def checkAb(A, b, maxcols): if len(A.shape) != 2: raise LinAlgError("Input array should be 2-D.") m, n = A.shape if m == 0 or n == 0: raise LinAlgError("Matrix is empty.") if b.shape[0] != m: raise LinAlgError( "Matrix and RHS do not have the same number of rows.") if maxcols < 2 and len(b.shape) > 1: raise LinAlgError("Right hand side must have only one column.") return
def solve(a, b, overwrite_a=False, overwrite_b=False): """ Solve a linear system ``a x = b`` Parameters ---------- a : (N, N) array_like left-hand-side matrix b : (N, NRHS) array_like right-hand-side matrix overwrite_a : bool, optional whether we are allowed to overwrite the matrix `a` overwrite_b : bool, optional whether we are allowed to overwrite the matrix `b` Returns ------- x : (N, NRHS) ndarray solution matrix """ a1 = atleast_2d(_asarray_validated(a, check_finite=False)) b1 = atleast_1d(_asarray_validated(b, check_finite=False)) n = a1.shape[0] overwrite_a = overwrite_a or _datacopied(a1, a) overwrite_b = overwrite_b or _datacopied(b1, b) if a1.shape[0] != a1.shape[1]: raise ValueError('LHS needs to be a square matrix.') if n != b1.shape[0]: # Last chance to catch 1x1 scalar a and 1D b arrays if not (n == 1 and b1.size != 0): raise ValueError('Input b has to have same number of rows as ' 'input a') # regularize 1D b arrays to 2D if b1.ndim == 1: if n == 1: b1 = b1[None, :] else: b1 = b1[:, None] b_is_1D = True else: b_is_1D = False gesv = get_lapack_funcs('gesv', (a1, b1)) _, _, x, info = gesv(a1, b1, overwrite_a=overwrite_a, overwrite_b=overwrite_b) if info > 0: raise LinAlgError("Singular matrix") if info < 0: raise ValueError('illegal value in %d-th argument of internal ' 'gesv' % -info) if b_is_1D: return x.ravel() return x
def sympos_solve_wrapper(A, b): posv, = get_lapack_funcs(('posv', ), (A, b)) c, rval, info = posv(A, b, lower=False, overwrite_a=False, overwrite_b=False) if info > 0: raise LinAlgError("singular matrix") return rval
def _rvs(self, n, shape, dim, df, C): """ Parameters ---------- n : integer Number of variates to generate shape : iterable Shape of the variates to generate dim : int Dimension of the scale matrix df : int Degrees of freedom C : ndarray Cholesky factorization of the scale matrix, lower triagular. Notes ----- As this function does no argument checking, it should not be called directly; use 'rvs' instead. """ # Get random draws A such that A ~ W(df, I) A = super(invwishart_gen, self)._standard_rvs(n, shape, dim, df) # Calculate SA = (CA)'^{-1} (CA)^{-1} ~ iW(df, scale) eye = np.eye(dim) trtrs = get_lapack_funcs(('trtrs'), (A, )) for index in np.ndindex(A.shape[:-2]): # Calculate CA CA = np.dot(C, A[index]) # Get (C A)^{-1} via triangular solver if dim > 1: CA, info = trtrs(CA, eye, lower=True) if info > 0: raise LinAlgError("Singular matrix.") if info < 0: raise ValueError('Illegal value in %d-th argument of' ' internal trtrs' % -info) else: CA = 1. / CA # Get SA A[index] = np.dot(CA.T, CA) return A
def inv(a, overwrite_a=False): """ Inverts a matrix Parameters ---------- a : (N, N) array_like the matrix to be inverted. overwrite_a : bool, optional whether we are allowed to overwrite the matrix `a` Returns ------- x : (N, N) ndarray The inverted matrix """ a1 = atleast_2d(_asarray_validated(a, check_finite=False)) overwrite_a = overwrite_a or _datacopied(a1, a) if a1.shape[0] != a1.shape[1]: raise ValueError('Input a needs to be a square matrix.') getrf, getri, getri_lwork = get_lapack_funcs( ('getrf', 'getri', 'getri_lwork'), (a1, )) lu, piv, info = getrf(a1, overwrite_a=overwrite_a) if info == 0: lwork = _compute_lwork(getri_lwork, a1.shape[0]) lwork = int(1.01 * lwork) x, info = getri(lu, piv, lwork=lwork, overwrite_lu=True) if info > 0: raise LinAlgError("Singular matrix") if info < 0: raise ValueError('illegal value in %d-th argument of internal ' 'getrf|getri' % -info) return x
def arlsgt(A, b, G, h): """Solves the double linear system of equations Ax = b (least squares) Gx >= h ("greater than" inequality constraints) Both Ax=b and Gx>=h can be underdetermined, square, or over-determined. Arguments b and h must be single columns. Arlsgt() uses arls(), above, as the core solver, and iteratively selects rows of Gx>=h to move to a growing list of equality constraints, choosing first whatever equation in Gx>=h most violates its requirement. Note that "less than" equations can be included by negating both sides of the equation, thus turning it into a "greater than". If either A or b is all zeros then the solution will be all zeros. Parameters ---------- A : (m, n) array_like "Coefficient" matrix, type float. b : (m) array_like column of dependent variables, type float. G : (mg, n) array_like "Coefficient" matrix, type float. b : (mg) array_like column of dependent variables, type float. Returns ------- x : (n) array_like column, type float. Raises ------ LinAlgError If A is not 2-D. If A is empty. If A and b do not have the same row size. If b has more than one column. If G is not 2-D. If G is empty. If G and h do not have the same row size. If h has more than one column. If A and G do not have the same number of columns. If SCIPY's SVD() does not converge. Example ------- Let A = [[1,1,1], [0,1,1], [1,0,1]] and b = [5.9, 5.0, 3.9] Then any least-squares solver would produce x = [0.9, 2., 3.] But if we happen to know that all the answers should be at least 1.0 then we can add inequalites to insure that: x[0] >= 1 x[1] >= 1 x[2] >= 1 This can be expressed in the matrix equation Gx>=h where G = [[1,0,0], [0,1,0], [0,0,1]] h = [1,1,1] Then arlsgt(A,b,G,h) produces x = [1., 2.0375, 2.8508]. The residual vector and its norm would be res = [-0.011, -0.112 -0.049] norm(res) = 0.122 If the user had just forced the least-squares answer of [0.9, 2., 3.] to [1., 2., 3.] without re-solving then the residual vector and its norm would be res = [0.1, 0, 0.1] norm(res) = 0.141 which is significantly larger. """ A = atleast_2d(_asarray_validated(A, check_finite=True)) b = atleast_1d(_asarray_validated(b, check_finite=True)) if np.count_nonzero(A) == 0 or np.count_nonzero(b) == 0: return np.zeros(A.shape[1]) AA = A.copy() bb = b.copy() checkAb(AA, bb, 1) m, n = AA.shape G = atleast_2d(_asarray_validated(G, check_finite=True)) h = atleast_1d(_asarray_validated(h, check_finite=True)) GG = G.copy() hh = h.copy() checkAb(GG, hh, 1) mg, ng = GG.shape if n != ng: raise LinAlgError( "The two matrices do not have the same number of unknowns.") EE = [] ff = [] me = 0 ne = 0 # get initial solution... it might actually be right x = arls(AA, bb) nx = norm(x) if nx <= 0.0: return x # while constraints are not fully satisfied: while True: # assess state of inequalities p = -1 mg = GG.shape[0] rhs = GG @ x worst = 0.0 for i in range(0, mg): if rhs[i] < hh[i]: diff = hh[i] - rhs[i] if p < 0 or diff > worst: p = i worst = diff if p < 0: break # delete row from GGx=hh row = GG[p, :] rhs = hh[p] GG = np.delete(GG, p, 0) hh = np.delete(hh, p, 0) # add row to Ex>=f if me == 0: EE = np.zeros((1, ng)) EE[0, :] = row ff = np.zeros(1) ff[0] = rhs me = 1 ne = ng else: me += 1 EE = np.resize(EE, (me, ne)) for j in range(0, ne): EE[me - 1, j] = row[j] ff = np.resize(ff, me) ff[me - 1] = rhs # re-solve modified system x = arlseq(AA, bb, EE, ff) return x
def arlseq(A, b, E, f): """Solves the double linear system of equations Ax = b (least squares) Ex = f (exact) Both Ax=b and Ex=f system can be underdetermined, square, or over-determined. Arguments b and f must be single columns. Ax=b is handled as a least-squares problem, using arls() above, after an appropriate othogonalization process removes the projection of each row of Ax=b onto the set of equality constraints in Ex=f. The solution to the equality constraints is then added back to the solution of the reduced Ax=b system. Ex=f is treated as a set of equality constraints. These constraints are usually few in number and well behaved. But clearly the caller can easily provide equations in Ex=f that are impossible to satisfy as a group... for example, by one equation requiring x[0]=0, and another requiring x[0]=1. So the solution process will either solve each equation in Ex=f exactly (within roundoff) or if that is impossible, arlseq() will discard one or more equations until the remaining equations are solvable. In the event that Ex=f is actually ill-conditioned in the manner that arls() is expected to handle, then arlseq() will delete offending rows of Ex=f. If either A or b is all zeros then the solution will be all zeros. Parameters ---------- A : (m, n) array_like "Coefficient" matrix, type float. b : (m) array_like column of dependent variables, type float. E : (me, n) array_like "Coefficient" matrix, type float. f : (me) array_like column of dependent variables, type float. Returns ------- x : (n) array_like column, type float. Raises ------ LinAlgError If A is not 2-D. If A is empty. If A and b do not have the same row size. If b has more than one column. If E is not 2-D. If E is empty. If E and f do not have the same row size. If f has more than one column. If A and E do not have the same number of columns. If SCIPY's SVD() does not converge. Examples -------- Here is a tiny example of a problem which has an "unknown" amount of error in the right hand side, but for which the user knows that the correct SUM of the unknowns must be 3: x + 2 y = 5.3 (Least Squares) 2 x + 3 y = 7.8 x + y = 3 ( Exact ) Then the arrays for arlseq are: A = array([[ 1., 2.0], [ 2., 3.0]]) b = array([5.3, 7.8]) E = array([[ 1., 1.0]]) f = array([3.0]) Without using the equality constraint we are given here, standard solvers will return [x,y] = [-.3 , 2.8]. Even arls() will return the same [x,y] = [-.3 , 2.8]. Arlsnn() could help here by disallowing presumably unacceptable negative values, producing [x,y] = [0. , 2.615]. If we solve with arlseq(A,b,E,f) then we get [x,y] = [1.00401 1.99598]. This answer is very close to the correct answer of [x,y] = [1.0 , 2.0] if the right hand side had been the correct [5.,8.] instead of [5.3,7.8]. It is constructive to look at residuals to understand more about the problem: For [x,y] = [-.3 , 2.8], the residual is [0.0 , 0.0] (exact). But of course x + y = 2.5, not the 3.0 we really want. For [x,y] = [0. , 2.615], the residual is [0.07 , 0.045], which is of course an increase from zero, but this is natural since we have forced the solution away from being the "exact" result, for good reason. Note that x + y = 2.615, which is a little better. For [x,y] = [1.00401 1.99598], the residual is [0.004 , 0.196] which is even larger. Again, by adding extra information to the problem the residual typically increases, but the solution becomes more acceptable. Note the arlseq() achieved x + y = 3 within output format limits. Notes: ----- See arls() above for notes and references. """ A = atleast_2d(_asarray_validated(A, check_finite=True)) b = atleast_1d(_asarray_validated(b, check_finite=True)) if np.count_nonzero(A) == 0 or np.count_nonzero(b) == 0: return np.zeros(A.shape[1]) AA = A.copy() bb = b.copy() checkAb(AA, bb, 1) m, n = AA.shape rnmax = find_max_row_norm(AA) neglect = rnmax * myepsilon() E = atleast_2d(_asarray_validated(E, check_finite=True)) f = atleast_1d(_asarray_validated(f, check_finite=True)) EE = E.copy() ff = f.copy() checkAb(EE, ff, 1) me, ne = EE.shape if n != ne: raise LinAlgError( "The two matrices do not have the same number of unknowns.") EE, ff = prepeq(EE, ff, neglect) mEE = EE.shape[0] # decouple AAx=bb from EEx=ff i = 0 while i < m: for j in range(0, mEE): d = np.dot(AA[i, :], EE[j, :]) AA[i, :] -= d * EE[j, :] bb[i] -= d * ff[j] nm = norm(AA[i, :]) if nm < neglect: AA = np.delete(AA, i, 0) bb = np.delete(bb, i, 0) m = AA.shape[0] else: AA[i, :] = AA[i, :] / nm bb[i] = bb[i] / nm i += 1 # final solution xe = np.transpose(EE) @ ff if AA.shape[0] > 0: xt = arls(AA, bb) else: xt = np.zeros(n) return xt + xe
def tri_inv(c, lower=False, unit_diagonal=False, overwrite_c=False, check_finite=True): """ Compute the inverse of a triangular matrix. Parameters ---------- c : array_like A triangular matrix to be inverted lower : bool, optional Use only data contained in the lower triangle of `c`. Default is to use upper triangle. unit_diagonal : bool, optional If True, diagonal elements of `c` are assumed to be 1 and will not be referenced. overwrite_c : bool, optional Allow overwriting data in `c` (may improve performance). check_finite : bool, optional Whether to check that the input matrix contains only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- inv_c : ndarray Inverse of the matrix `c`. Raises ------ LinAlgError If `c` is singular ValueError If `c` is not square, or not 2-dimensional. Examples -------- >>> c = numpy.array([(1., 2.), (0., 4.)]) >>> tri_inv(c) array([[ 1. , -0.5 ], [ 0. , 0.25]]) >>> numpy.dot(c, tri_inv(c)) array([[ 1., 0.], [ 0., 1.]]) """ if check_finite: c1 = numpy.asarray_chkfinite(c) else: c1 = numpy.asarray(c) if len(c1.shape) != 2 or c1.shape[0] != c1.shape[1]: raise ValueError('expected square matrix') overwrite_c = overwrite_c or _datacopied(c1, c) trtri, = get_lapack_funcs(('trtri', ), (c1, )) inv_c, info = trtri(c1, overwrite_c=overwrite_c, lower=lower, unitdiag=unit_diagonal) if info > 0: raise LinAlgError("singular matrix") if info < 0: raise ValueError("illegal value in %d-th argument of internal trtri" % -info) return inv_c
def svd(a, full_matrices=True, compute_uv=True, overwrite_a=False, check_finite=True, lapack_driver='gesdd'): """ Singular Value Decomposition. Factorizes the matrix `a` into two unitary matrices ``U`` and ``Vh``, and a 1-D array ``s`` of singular values (real, non-negative) such that ``a == U @ S @ Vh``, where ``S`` is a suitably shaped matrix of zeros with main diagonal ``s``. Parameters ---------- a : (M, N) array_like Matrix to decompose. full_matrices : bool, optional If True (default), `U` and `Vh` are of shape ``(M, M)``, ``(N, N)``. If False, the shapes are ``(M, K)`` and ``(K, N)``, where ``K = min(M, N)``. compute_uv : bool, optional Whether to compute also ``U`` and ``Vh`` in addition to ``s``. Default is True. overwrite_a : bool, optional Whether to overwrite `a`; may improve performance. Default is False. check_finite : bool, optional Whether to check that the input matrix contains only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. lapack_driver : {'gesdd', 'gesvd'}, optional Whether to use the more efficient divide-and-conquer approach (``'gesdd'``) or general rectangular approach (``'gesvd'``) to compute the SVD. MATLAB and Octave use the ``'gesvd'`` approach. Default is ``'gesdd'``. .. versionadded:: 0.18 Returns ------- U : ndarray Unitary matrix having left singular vectors as columns. Of shape ``(M, M)`` or ``(M, K)``, depending on `full_matrices`. s : ndarray The singular values, sorted in non-increasing order. Of shape (K,), with ``K = min(M, N)``. Vh : ndarray Unitary matrix having right singular vectors as rows. Of shape ``(N, N)`` or ``(K, N)`` depending on `full_matrices`. For ``compute_uv=False``, only ``s`` is returned. Raises ------ LinAlgError If SVD computation does not converge. See also -------- svdvals : Compute singular values of a matrix. diagsvd : Construct the Sigma matrix, given the vector s. Examples -------- >>> from scipy import linalg >>> m, n = 9, 6 >>> a = np.random.randn(m, n) + 1.j*np.random.randn(m, n) >>> U, s, Vh = linalg.svd(a) >>> U.shape, s.shape, Vh.shape ((9, 9), (6,), (6, 6)) Reconstruct the original matrix from the decomposition: >>> sigma = np.zeros((m, n)) >>> for i in range(min(m, n)): ... sigma[i, i] = s[i] >>> a1 = np.dot(U, np.dot(sigma, Vh)) >>> np.allclose(a, a1) True Alternatively, use ``full_matrices=False`` (notice that the shape of ``U`` is then ``(m, n)`` instead of ``(m, m)``): >>> U, s, Vh = linalg.svd(a, full_matrices=False) >>> U.shape, s.shape, Vh.shape ((9, 6), (6,), (6, 6)) >>> S = np.diag(s) >>> np.allclose(a, np.dot(U, np.dot(S, Vh))) True >>> s2 = linalg.svd(a, compute_uv=False) >>> np.allclose(s, s2) True """ a1 = _asarray_validated(a, check_finite=check_finite) if len(a1.shape) != 2: raise ValueError('expected matrix') m, n = a1.shape overwrite_a = overwrite_a or (_datacopied(a1, a)) if not isinstance(lapack_driver, string_types): raise TypeError('lapack_driver must be a string') if lapack_driver not in ('gesdd', 'gesvd'): raise ValueError('lapack_driver must be "gesdd" or "gesvd", not "%s"' % (lapack_driver, )) funcs = (lapack_driver, lapack_driver + '_lwork') gesXd, gesXd_lwork = get_lapack_funcs(funcs, (a1, )) # compute optimal lwork lwork = _compute_lwork(gesXd_lwork, a1.shape[0], a1.shape[1], compute_uv=compute_uv, full_matrices=full_matrices) # perform decomposition u, s, v, info = gesXd(a1, compute_uv=compute_uv, lwork=lwork, full_matrices=full_matrices, overwrite_a=overwrite_a) if info > 0: raise LinAlgError("SVD did not converge") if info < 0: raise ValueError('illegal value in %d-th argument of internal gesdd' % -info) if compute_uv: return u, s, v else: return s
def arlseq(A, b, E, f): """Solves the double linear system of equations Ax = b (least squares) Ex = f (exact) Both Ax=b and Ex=f system can be underdetermined, square, or over-determined. Arguments b and f must be single columns. Ex=f is treated as a set of equality constraints. These constraints are usually few in number and well behaved. But clearly the caller can easily provide equations in Ex=f that are impossible to satisfy as a group. For example, there could be one equation requiring x[0]=0, and another requiring x[0]=1. And, the solver must deal with there being redundant or other pathological situations within the E matrix. So the solution process will either solve each equation in Ex=f exactly (within roundoff) or if that is impossible, arlseq() will discard one or more equations until the remaining equations are solvable exactly (within roundoff). We will refer below to the solution of this reduced system as "xe". After Ex=f is processed as above, the rows of Ax=b will have their projections onto every row of Ex=f subtracted from them. We will call this reduced set of equations A'x = b'. (Thus, the rows of A' will all be orthogonal to the rows of E.) This reduced problem A'x = b', will then be solved with arls(). We will refer to the solution of this system as "xt". The final solution will be x = xe + xt. (Since E and A' are mutually orthogonal matrices.) If A'x = b' is NOT ill-conditioned (or singular) then x = xe + xt will satisfy all the equality constraints that were not rejected. However, if A'x = b' is ill-conditioned, then xt will be a regularized solution, not an exact solution, and thus x = xe + xt will not in general satisfy the equality constraints exactly. Parameters ---------- A : (m, n) array_like "Coefficient" matrix, type float. b : (m) array_like column of dependent variables, type float. E : (me, n) array_like "Coefficient" matrix, type float. f : (me) array_like column of dependent variables, type float. Returns ------- x : (n) array_like column, type float. nr : int The numerical rank of the matrix, A, after its projection onto the rows of E are subtracted. ur : int The "usable" rank of the "reduced" problem, Ax=b, after its projection onto the rows of Ex=f are subtracted. Note that "numerical rank" is an attribute of a matrix but the "usable rank" that arls computes is an attribute of the problem, Ax=b. sigma : float The estimated right-hand-side root-mean-square error. lambda : float The estimated Tikhonov regularization. Raises ------ LinAlgError If A is not 2-D. If A is empty. If A and b do not have the same row size. If b has more than one column. If E is not 2-D. If E is empty. If E and f do not have the same row size. If f has more than one column. If A and E do not have the same number of columns. If SCIPY's SVD() does not converge. Examples -------- Here is a tiny example of a problem which has an "unknown" amount of error in the right hand side, but for which the user knows that the correct SUM of the unknowns must be 3: x + 2 y = 5.3 (Least Squares) 2 x + 3 y = 7.8 x + y = 3 ( Exact ) Then the arrays for arlseq are: A = array([[ 1., 2.0], [ 2., 3.0]]) b = array([5.3, 7.8]) E = array([[ 1.0, 1.0]]) f = array([3.0]) Without using the equality constraint we are given here, standard solvers will return [x,y] = [-.3 , 2.8]. Even arls() will return the same [x,y] = [-.3 , 2.8]. The residual for this solution is [0.0 , 0.0] (within roundoff). But of course x + y = 2.5, not the 3.0 we really want. Arlsnn() could help here by disallowing presumably unacceptable negative values, producing [x,y] = [0. , 2.6]. The residual for this solution is [-0.1 , 0.] which is of course an increase from zero, but this is natural since we have forced the solution away from being the "exact" result, for good reason. Note that x + y = 2.6, which is a little better. If we solve with arlseq(A,b,E,f) then we get [x,y] = [1.004, 1.996]. This answer is close to the "correct" answer of [x,y] = [1.0 , 2.0] if the right hand side had been the correct [5.,8.] instead of [5.3,7.8]. The residual for this solution is [-0.3 , 0.2] which is yet larger. Again, when adding constraints to the problem the residual typically increases, but the solution becomes more acceptable. Note that x + y = 3 exactly. Notes: ----- See arls() above for notes and references. """ A = atleast_2d(_asarray_validated(A, check_finite=True)) b = atleast_1d(_asarray_validated(b, check_finite=True)) if np.count_nonzero(A) == 0 or np.count_nonzero(b) == 0: return np.zeros(A.shape[1]), 0, 0, 0.0, 0.0 AA = A.copy() bb = b.copy() checkAb(AA, bb, 1) m, n = AA.shape rnmax = find_max_row_norm(AA) neglect = rnmax * 0.00000001 # see Note 6. for arls() E = atleast_2d(_asarray_validated(E, check_finite=True)) f = atleast_1d(_asarray_validated(f, check_finite=True)) EE = E.copy() ff = f.copy() checkAb(EE, ff, 1) me, ne = EE.shape if n != ne: raise LinAlgError( "The two matrices do not have the same number of unknowns.") EE, ff = prepeq(EE, ff, neglect) mEE = EE.shape[0] # decouple AAx=bb from EEx=ff i = 0 while i < m: for j in range(0, mEE): d = np.dot(AA[i, :], EE[j, :]) AA[i, :] -= d * EE[j, :] bb[i] -= d * ff[j] nm = mynorm(AA[i, :]) if nm < neglect: AA = np.delete(AA, i, 0) bb = np.delete(bb, i, 0) m = AA.shape[0] else: AA[i, :] = AA[i, :] / nm bb[i] = bb[i] / nm i += 1 # final solution xe = np.transpose(EE) @ ff if AA.shape[0] > 0: xt, nr, ur, sigma, lambdah = arls(AA, bb) return xt + xe, nr, ur, sigma, lambdah else: return xe, 0, 0, 0., 0.
def lstsq(a, b, cond=None, overwrite_a=False, overwrite_b=False, check_finite=True, lapack_driver=None): """ Compute least-squares solution to equation Ax = b. Compute a vector x such that the 2-norm ``|b - A x|`` is minimized. This code was adapted from the Scipy distribution: https://github.com/scipy/scipy/blob/v1.2.1/scipy/linalg/basic.py#L1047-L1264 Parameters ---------- a : (M, N) array_like Left hand side matrix (2-D array). b : (M,) or (M, K) array_like Right hand side matrix or vector (1-D or 2-D array). cond : float, optional Cutoff for 'small' singular values; used to determine effective rank of a. Singular values smaller than ``rcond * largest_singular_value`` are considered zero. overwrite_a : bool, optional Discard data in `a` (may enhance performance). Default is False. overwrite_b : bool, optional Discard data in `b` (may enhance performance). Default is False. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. lapack_driver : str, optional Which LAPACK driver is used to solve the least-squares problem. Options are ``'gelsd'``, ``'gelsy'``, ``'gelss'``. Default (``'gelsd'``) is a good choice. However, ``'gelsy'`` can be slightly faster on many problems. ``'gelss'`` was used historically. It is generally slow but uses less memory. .. versionadded:: 0.17.0 Returns ------- x : (N,) or (N, K) ndarray Least-squares solution. Return shape matches shape of `b`. residues : (0,) or () or (K,) ndarray Sums of residues, squared 2-norm for each column in ``b - a x``. If rank of matrix a is ``< N`` or ``N > M``, or ``'gelsy'`` is used, this is a length zero array. If b was 1-D, this is a () shape array (numpy scalar), otherwise the shape is (K,). rank : int Effective rank of matrix `a`. s : (min(M,N),) ndarray or None Singular values of `a`. The condition number of a is ``abs(s[0] / s[-1])``. None is returned when ``'gelsy'`` is used. Raises ------ LinAlgError If computation does not converge. ValueError When parameters are wrong. See Also -------- optimize.nnls : linear least squares with non-negativity constraint Examples -------- >>> from scipy.linalg import lstsq >>> import matplotlib.pyplot as plt Suppose we have the following data: >>> x = np.array([1, 2.5, 3.5, 4, 5, 7, 8.5]) >>> y = np.array([0.3, 1.1, 1.5, 2.0, 3.2, 6.6, 8.6]) We want to fit a quadratic polynomial of the form ``y = a + b*x**2`` to this data. We first form the "design matrix" M, with a constant column of 1s and a column containing ``x**2``: >>> M = x[:, np.newaxis]**[0, 2] >>> M array([[ 1. , 1. ], [ 1. , 6.25], [ 1. , 12.25], [ 1. , 16. ], [ 1. , 25. ], [ 1. , 49. ], [ 1. , 72.25]]) We want to find the least-squares solution to ``M.dot(p) = y``, where ``p`` is a vector with length 2 that holds the parameters ``a`` and ``b``. >>> p, res, rnk, s = lstsq(M, y) >>> p array([ 0.20925829, 0.12013861]) Plot the data and the fitted curve. >>> plt.plot(x, y, 'o', label='data') >>> xx = np.linspace(0, 9, 101) >>> yy = p[0] + p[1]*xx**2 >>> plt.plot(xx, yy, label='least squares fit, $y = a + bx^2$') >>> plt.xlabel('x') >>> plt.ylabel('y') >>> plt.legend(framealpha=1, shadow=True) >>> plt.grid(alpha=0.25) >>> plt.show() """ a1 = _asarray_validated(a, check_finite=check_finite) b1 = _asarray_validated(b, check_finite=check_finite) if len(a1.shape) != 2: raise ValueError('expected matrix') m, n = a1.shape if len(b1.shape) == 2: nrhs = b1.shape[1] else: nrhs = 1 if m != b1.shape[0]: raise ValueError('incompatible dimensions') if m == 0 or n == 0: # Zero-sized problem, confuses LAPACK x = np.zeros((n, ) + b1.shape[1:], dtype=np.common_type(a1, b1)) if n == 0: residues = np.linalg.norm(b1, axis=0)**2 else: residues = np.empty((0, )) return x, residues, 0, np.empty((0, )) driver = lapack_driver if driver is None: global default_lapack_driver driver = default_lapack_driver if driver not in ('gelsd', 'gelsy', 'gelss'): raise ValueError('LAPACK driver "%s" is not found' % driver) lapack_func, lapack_lwork = get_lapack_funcs( (driver, '%s_lwork' % driver), (a1, b1)) real_data = True if (lapack_func.dtype.kind == 'f') else False if m < n: # need to extend b matrix as it will be filled with # a larger solution matrix if len(b1.shape) == 2: b2 = np.zeros((n, nrhs), dtype=lapack_func.dtype) b2[:m, :] = b1 else: b2 = np.zeros(n, dtype=lapack_func.dtype) b2[:m] = b1 b1 = b2 overwrite_a = overwrite_a or _datacopied(a1, a) overwrite_b = overwrite_b or _datacopied(b1, b) if cond is None: cond = np.finfo(lapack_func.dtype).eps a1_wrk = np.copy(a1) b1_wrk = np.copy(b1) lwork, iwork = _compute_lwork(lapack_lwork, m, n, nrhs, cond) x_check, s_check, rank_check, info = lapack_func( a1_wrk, b1_wrk, lwork, iwork, cond, False, False) driver = 'gelss' if driver in ('gelss', 'gelsd'): if driver == 'gelss': if not context: a1_wrk = np.copy(a1) b1_wrk = np.copy(b1) lwork, iwork = _compute_lwork(lapack_lwork, m, n, nrhs, cond) x, s, rank, info = lapack_func(a1_wrk, b1_wrk, lwork, iwork, cond, False, False) else: try: # Check that we aren't dealing with an underconstrained problem ... if m < n: pkg.log.error( Exception( "Underconstrained problems not yet supported by Magma." )) # Initialize a1_trans = np.copy(a1, order='F') a1_gpu = gpuarray.to_gpu(a1_trans) # Note that the result for 'x' gets written to the vector inputted for b x_trans = np.copy(b1, order='F') x_gpu = gpuarray.to_gpu(x_trans) # Init singular-value decomposition (SVD) output & buffer arrays s = np.zeros(min(m, n), np.float32) u = np.zeros((m, m), np.float32) vh = np.zeros((n, n), np.float32) # Query and allocate optimal workspace # n.b.: - the result for 'x' gets written to the input vector for b, so we just label b->x # - assume magma variables lda=ldb=m throughout here lwork_SVD = magma.magma_sgesvd_buffersize( 'A', 'A', m, n, a1_trans.ctypes.data, m, s.ctypes.data, u.ctypes.data, m, vh.ctypes.data, n) # For some reason, magma_sgels_buffersize() does not return the right value for large problems, so # we compute the values used for the validation check (see Magma SGELS documentation) directly and use that #lwork_LS = magma.magma_sgels_buffersize('n', m, n, nrhs, a1_trans.ctypes.data, m, x_trans.ctypes.data, m) nb = magma.magma_get_sgeqrf_nb(m, n) check = (m - n + nb) * (nrhs + nb) + nrhs * nb lwork_LS = check # Allocate workspaces hwork_SVD = np.zeros(lwork_SVD, np.float32, order='F') hwork_LS = np.zeros(lwork_LS, np.float32) # Compute SVD timer.start("SVD") magma.magma_sgesvd('A', 'A', m, n, a1_trans.ctypes.data, m, s.ctypes.data, u.ctypes.data, m, vh.ctypes.data, n, hwork_SVD.ctypes.data, lwork_SVD) timer.stop("SVD") # Note, the use of s_i>rcond here; this is meant to select # values that are effectively non-zero. Results will depend # somewhat on the choice for this value. This criterion was # adopted from that utilized by scipy.linalg.basic.lstsq() rcond = np.finfo(lapack_func.dtype).eps * s[0] rank = sum(1 for s_i in s if s_i > rcond) # Run LS solver timer.start("LS") magma.magma_sgels_gpu('n', m, n, nrhs, a1_gpu.gpudata, m, x_gpu.gpudata, m, hwork_LS.ctypes.data, lwork_LS) timer.stop("LS") # Unload result from GPU x = x_gpu.get() except magma.MagmaError as e: info = e._status else: info = 0 elif driver == 'gelsd': if real_data: if not context: raise Exception( "For some reason, the CUDA implementation of fit() is being called when context is False." ) else: raise Exception( "gelsd not supported using Cuda yet") else: # complex data raise LinAlgError( "driver=%s not yet supported for complex data" % (driver)) if info > 0: raise LinAlgError( "SVD did not converge in Linear Least Squares") if info < 0: raise ValueError( 'illegal value in %d-th argument of internal %s' % (-info, lapack_driver)) resids = np.asarray([], dtype=x.dtype) if m > n: x1 = x[:n] if rank == n: resids = np.sum(np.abs(x[n:])**2, axis=0) x = x1 elif driver == 'gelsy': raise LinAlgError("driver=%s not yet supported" % (driver)) #pkg.log.close("Done", time_elapsed=True) return x, resids, rank, s
def _cho_inv_batch(a, check_finite=True): """ Invert the matrices a_i, using a Cholesky factorization of A, where a_i resides in the last two dimensions of a and the other indices describe the index i. Overwrites the data in a. Parameters ---------- a : array Array of matrices to invert, where the matrices themselves are stored in the last two dimensions. check_finite : boolean, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- x : array Array of inverses of the matrices a_i See also -------- scipy.linalg.cholesky : Cholesky factorization of a matrix """ if check_finite: a1 = asarray_chkfinite(a) else: a1 = asarray(a) if len(a1.shape) < 2 or a1.shape[-2] != a1.shape[-1]: raise ValueError('expected square matrix in last two dimensions') potrf, potri = get_lapack_funcs(('potrf', 'potri'), (a1, )) tril_idx = np.tril_indices(a.shape[-2], k=-1) triu_idx = np.triu_indices(a.shape[-2], k=1) for index in np.ndindex(a1.shape[:-2]): # Cholesky decomposition a1[index], info = potrf(a1[index], lower=True, overwrite_a=False, clean=False) if info > 0: raise LinAlgError("%d-th leading minor not positive definite" % info) if info < 0: raise ValueError('illegal value in %d-th argument of internal' ' potrf' % -info) # Inversion a1[index], info = potri(a1[index], lower=True, overwrite_c=False) if info > 0: raise LinAlgError("the inverse could not be computed") if info < 0: raise ValueError('illegal value in %d-th argument of internal' ' potrf' % -info) # Make symmetric (dpotri only fills in the lower triangle) a1[index][triu_idx] = a1[index][tril_idx] return a1