コード例 #1
0
ファイル: autosol.py プロジェクト: rejones7/scipy
def arlsnn(A, b):
    """Solves Ax = b in the least squares sense, with the solution
       constrained to be non-negative.
       
       For a nonpositive solution, use
          x = -arlsnn(A,-b,0)

    Parameters
    ----------
    A : (m, n) array_like "Coefficient" matrix, type float.
    b : (m) 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 SCIPY's SVD() does not converge.

    Example
    -------
    Let A = [[2., 2., 1.],
             [2., 1., 0.],
             [1., 1., 0.]]
    and b =  [3.9, 3., 2.]
    Then any least-squares solver will produce
       x =  [1. ,1., -0.1]
    But arlsnn() produces  x = [ 1.0322, 0.9093, 0.].

    arlsnn() tries to produce a small residual for the final solution,
    while being based toward making the fewest changes feasible
    to the problem. Most older solvers try to minimize the residual
    at the expense of extra interference with the user's model.
    Arls, arlsgt, and arlsnn seek a better balance.
    """
    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])
    checkAb(A, b, 1)
    n = A.shape[1]
    AA = A.copy()
    bb = b.copy()
    G = np.eye(n)
    h = np.zeros(n)
    x = arlsgt(AA, bb, G, h)
    return x
コード例 #2
0
ファイル: autosol.py プロジェクト: rejones7/scipy
def prepeq(E, f, neglect):
    """ a utility routine for arlseq() below that prepares the equality
    constraints for use"""
    E = atleast_2d(_asarray_validated(E, check_finite=True))
    f = atleast_1d(_asarray_validated(f, check_finite=True))
    EE = E.copy()
    ff = f.copy()
    m, n = EE.shape

    for i in range(0, m):
        # determine new best row and put it next
        if i == 0:
            imax = find_max_sense(EE, ff)
        else:
            rnmax = -1.0
            imax = -1
            for k in range(i, m):
                rn = norm(EE[k, :])
                if imax < 0 or rn > rnmax:
                    rnmax = rn
                    imax = k
        EE[[i, imax], :] = EE[[imax, i], :]
        ff[[i, imax]] = ff[[imax, i]]

        # normalize
        rin = norm(EE[i, :])
        if rin > 0.0:
            EE[i, :] /= rin
            ff[i] /= rin
        else:
            EE[i, :] = 0.0  # will be culled below
            ff[i] = 0.0

        # subtract projections onto EE[i,:]
        for k in range(i + 1, m):
            d = np.dot(EE[k, :], EE[i, :])
            EE[k, :] -= d * EE[i, :]
            ff[k] -= d * ff[i]

    # reject ill-conditioned rows
    if m > 2:
        g = np.zeros(m)
        for k in range(0, m):
            g[k] = abs(ff[k])
        m1 = splita(m, g)
        mm = splitb(m1, g)
        if mm < m:
            EE = np.resize(EE, (mm, n))
            ff = np.resize(ff, mm)

    return EE, ff
コード例 #3
0
def arlsqr(A, b):
    """Solves the linear system of equation, Ax = b, for any shape matrix.

    Arlsqr() is called exactly like arls() above, and the returns are
    exactly the same.

    The difference is that if b is only one column then arlsqr()
    first performs a quick assessment of the system to see if it appears
    to be ill-conditioned. If not, qr() is called for a solution.
    If the resulting solution from qr() appears to be good, then it
    is returned. Otherwise, arls() continues itself to to get a solution
    based on the SVD.

    The purpose of this difference is to execute signficantly faster than
    arlsqr() does if the problems given to it are usually well behaved.
    """
    A = atleast_2d(_asarray_validated(A, check_finite=True))
    b = atleast_1d(_asarray_validated(b, check_finite=True))
    nz = np.count_nonzero(A)
    if nz == 0 or np.count_nonzero(b) == 0:
        return np.zeros(A.shape[1]), 0, 0, 0.0, 0.0
    checkAb(A, b, 2)
    m, n = A.shape
    nr = min(m, n)
    # is b a single column?
    if len(b.shape) > 1:
        return arls(A, b)
    odd, maxnorm = strange(A, b)
    if not odd or nz < int(
        (m * n) / 2):  # max norm tests fails for sparse-like
        if (m >= n):
            Q, R = qr(A, mode='economic')
            Qb = Q.T @ b
            try:
                x = solve_triangular(R, Qb)
            except LinAlgError:
                return arls(A, b)
        else:
            Q, R = qr(A.T, mode='economic')
            try:
                y = solve_triangular(R, b, 'T')
            except LinAlgError:
                return arls(A, b)
            x = Q @ y
        if mynorm(x) < maxnorm or nz < int((m * n) / 2):
            return x, nr, nr, 0.0, 0.0
    return arls(A, b)
コード例 #4
0
ファイル: autosol.py プロジェクト: rejones7/scipy
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
コード例 #5
0
ファイル: autosol.py プロジェクト: rejones7/scipy
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
コード例 #6
0
ファイル: autosol.py プロジェクト: rejones7/scipy
def arls(A, b):
    """Solves the linear system of equation, Ax = b, for any shape matrix.

    The system can be underdetermined, square, or over-determined.
    That is, A(m,n) can be such that m < n, m = n, or m > n.
    Argument b is a matrix of size(n,p) of p right-hand-side columns.
    This solver automatically detects if each system is ill-conditioned or not.

    Then
     -- If the equations are consistent then the solution will usually be
        exact within round-off error.
     -- If the equations are inconsistent then the the solution will be
        by least-squares. That is, it solves ``min ||b - Ax||_2``.
     -- If the equations are inconsistent and diagnosable as ill-conditioned
        using the principles of the first reference below, the system will be
        automatically regularized and the residual will be larger than minimum.
     -- 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, p) array_like Set of columns of dependent variables, type float.

    Returns
    -------
    x : (n, p) array_like set of columns, type float.
        Each column will be the solution corresponding to the same column of b.

    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 SCIPY's SVD() does not converge.

    Examples
    --------
    Arls() will behave like any good least-squares solver when the system
    is well conditioned.
    Here is a tiny example of an ill-conditioned system as handled by arls(),

       x + y = 2
       x + 1.01 y =3

    Then A = array([[ 1., 1.],
                    [ 1., 1.01.]])
    and  b = array([2.0, 3.0])

    Then standard solvers will return:
       x = [-98. , 100.]

    But arls() will see the violation of the Picard Condition and return
       x = [1.12216 , 1.12779]

    Notes:
    -----
    1. When the system is ill-conditioned, the process works best when the rows
       of A are scaled so that the elements of b have similar estimated errors.
    2. Arls() occasionally may produce a smoother (i.e., more regularized)
       solution than desired. In this case please try scipy routine lsmr.
    3. With any linear equation solver, check that the solution is reasonable.
       In particular, you should check the residual vector, Ax - b.
    4. Arls() neither needs nor accepts optional parameters such as iteration
       limits, error estimates, variable bounds, condition number limits, etc.
       It also does not return any error flags as there are no error states.
       As long as the SVD converges (and SVD failure is remarkably rare)
       then arls() and other routines in this package will complete normally.
    5. Arls()'s intent (and the intent of all routines in this module)
       is to find a reasonable solution even in the midst of excessive
       inaccuracy, ill-conditioning, singularities, duplicated data, etc.
       Its performance is often very like that of lsmr, but from a completely
       different approach.
    6. In view of note 5, arls() is not appropriate for situations
       where the requirements are more for high accuracy rather than
       robustness. So, we assume, in the coding, where needed, that no data
       needs to be considered more accurate than 8 significant figures.

    References
    ----------
    About the Picard Condition: "The discrete picard condition for discrete
    ill-posed problems", Per Christian Hansen, 1990.
    https://link.springer.com/article/10.1007/BF01933214

    About Nonnegative solutions: "Solving Least Squares Problems",
    by Charles L. Lawson and Richard J. Hanson. Prentice-Hall 1974

    About our algorithm: "Solving Linear Algebraic Systems Arising in the
    Solution of Integral Equations of the First Kind",
    Dissertation by Rondall E. Jones, 1985, U. of N.M.
    Advisor: Cleve B. Moler, creator of MatLab and co-founder of MathWorks.

    For further information on the Picard Condition please see
    http://www.rejones7.net/autorej/What_Is_The_Picard_Condition.htm
    """
    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, 2)
    n = AA.shape[1]

    if len(bb.shape) == 2:
        nrhs = bb.shape[1]
    else:
        nrhs = 1

    # call for each solution
    U, S, Vt = np.linalg.svd(AA, full_matrices=False)
    xx = np.zeros((n, nrhs))
    if nrhs == 1:
        return arlsusv(AA, bb, U, S, Vt)[0]
    for p in range(0, nrhs):
        xx[:, p] = arlsusv(AA, bb[:, p], U, S, Vt)[0]
    return xx
コード例 #7
0
def subspace_angles(A, B):
    r"""
    Compute the subspace angles between two matrices.
    Parameters
    ----------
    A : (M, N) array_like
        The first input array.
    B : (M, K) array_like
        The second input array.
    Returns
    -------
    angles : ndarray, shape (min(N, K),)
        The subspace angles between the column spaces of `A` and `B`.
    See Also
    --------
    orth
    svd
    Notes
    -----
    This computes the subspace angles according to the formula
    provided in [1]_. For equivalence with MATLAB and Octave behavior,
    use ``angles[0]``.
    .. versionadded:: 1.0
    References
    ----------
    .. [1] Knyazev A, Argentati M (2002) Principal Angles between Subspaces
           in an A-Based Scalar Product: Algorithms and Perturbation
           Estimates. SIAM J. Sci. Comput. 23:2008-2040.
    Examples
    --------
    A Hadamard matrix, which has orthogonal columns, so we expect that
    the suspace angle to be :math:`\frac{\pi}{2}`:
    >>> from scipy.linalg import hadamard, subspace_angles
    >>> H = hadamard(4)
    >>> print(H)
    [[ 1  1  1  1]
     [ 1 -1  1 -1]
     [ 1  1 -1 -1]
     [ 1 -1 -1  1]]
    >>> np.rad2deg(subspace_angles(H[:, :2], H[:, 2:]))
    array([ 90.,  90.])
    And the subspace angle of a matrix to itself should be zero:
    >>> subspace_angles(H[:, :2], H[:, :2]) <= 2 * np.finfo(float).eps
    array([ True,  True], dtype=bool)
    The angles between non-orthogonal subspaces are in between these extremes:
    >>> x = np.random.RandomState(0).randn(4, 3)
    >>> np.rad2deg(subspace_angles(x[:, :2], x[:, [2]]))
    array([ 55.832])
    """
    # Steps here omit the U and V calculation steps from the paper

    # 1. Compute orthonormal bases of column-spaces
    A = _asarray_validated(A, check_finite=True)
    if len(A.shape) != 2:
        raise ValueError('expected 2D array, got shape %s' % (A.shape, ))
    QA = orth(A)
    del A

    B = _asarray_validated(B, check_finite=True)
    if len(B.shape) != 2:
        raise ValueError('expected 2D array, got shape %s' % (B.shape, ))
    if len(B) != len(QA):
        raise ValueError('A and B must have the same number of rows, got '
                         '%s and %s' % (QA.shape[0], B.shape[0]))
    QB = orth(B)
    del B

    # 2. Compute SVD for cosine
    QA_T_QB = dot(QA.T, QB)
    sigma = svdvals(QA_T_QB)

    # 3. Compute matrix B
    if QA.shape[1] >= QB.shape[1]:
        B = QB - dot(QA, QA_T_QB)
    else:
        B = QA - dot(QB, QA_T_QB.T)
    del QA, QB, QA_T_QB

    # 4. Compute SVD for sine
    mask = sigma**2 >= 0.5
    if mask.any():
        mu_arcsin = arcsin(clip(svdvals(B, overwrite_a=True), -1., 1.))
    else:
        mu_arcsin = 0.

    # 5. Compute the principal angles
    theta = where(mask, mu_arcsin, arccos(clip(sigma, -1., 1.)))
    return theta
コード例 #8
0
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
コード例 #9
0
def svdvals(a, overwrite_a=False, check_finite=True):
    """
    Compute singular values of a matrix.
    Parameters
    ----------
    a : (M, N) array_like
        Matrix to decompose.
    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.
    Returns
    -------
    s : (min(M, N),) ndarray
        The singular values, sorted in decreasing order.
    Raises
    ------
    LinAlgError
        If SVD computation does not converge.
    Notes
    -----
    ``svdvals(a)`` only differs from ``svd(a, compute_uv=False)`` by its
    handling of the edge case of empty ``a``, where it returns an
    empty sequence:
    >>> a = np.empty((0, 2))
    >>> from scipy.linalg import svdvals
    >>> svdvals(a)
    array([], dtype=float64)
    See Also
    --------
    svd : Compute the full singular value decomposition of a matrix.
    diagsvd : Construct the Sigma matrix, given the vector s.
    Examples
    --------
    >>> from scipy.linalg import svdvals
    >>> m = np.array([[1.0, 0.0],
    ...               [2.0, 3.0],
    ...               [1.0, 1.0],
    ...               [0.0, 2.0],
    ...               [1.0, 0.0]])
    >>> svdvals(m)
    array([ 4.28091555,  1.63516424])
    We can verify the maximum singular value of `m` by computing the maximum
    length of `m.dot(u)` over all the unit vectors `u` in the (x,y) plane.
    We approximate "all" the unit vectors with a large sample.  Because
    of linearity, we only need the unit vectors with angles in [0, pi].
    >>> t = np.linspace(0, np.pi, 2000)
    >>> u = np.array([np.cos(t), np.sin(t)])
    >>> np.linalg.norm(m.dot(u), axis=0).max()
    4.2809152422538475
    `p` is a projection matrix with rank 1.  With exact arithmetic,
    its singular values would be [1, 0, 0, 0].
    >>> v = np.array([0.1, 0.3, 0.9, 0.3])
    >>> p = np.outer(v, v)
    >>> svdvals(p)
    array([  1.00000000e+00,   2.02021698e-17,   1.56692500e-17,
             8.15115104e-34])
    The singular values of an orthogonal matrix are all 1.  Here we
    create a random orthogonal matrix by using the `rvs()` method of
    `scipy.stats.ortho_group`.
    >>> from scipy.stats import ortho_group
    >>> np.random.seed(123)
    >>> orth = ortho_group.rvs(4)
    >>> svdvals(orth)
    array([ 1.,  1.,  1.,  1.])
    """
    a = _asarray_validated(a, check_finite=check_finite)
    if a.size:
        return svd(a,
                   compute_uv=0,
                   overwrite_a=overwrite_a,
                   check_finite=False)
    elif len(a.shape) != 2:
        raise ValueError('expected matrix')
    else:
        return numpy.empty(0)
コード例 #10
0
def arlsnn(A, b):
    """Solves Ax = b in the least squares sense, with the solution
       constrained to be non-negative.

       For a nonpositive solution, use
          x = -arlsnn(A,-b)

    Parameters
    ----------
    A : (m, n) array_like "Coefficient" matrix, type float.
    b : (m) 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.
    ur : int
        The usable rank of the problem, Ax=b.
        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 SCIPY's SVD() does not converge.

    Example
    -------
    Let A = [[2., 2., 1.],
             [2., 1., 0.],
             [1., 1., 0.]]
    and b =  [3.9, 3., 2.]
    Then any least-squares solver will produce
       x =  [1. ,1., -0.1]
    But arlsnn() produces  x = [ 1.0322, 0.9093, 0.].

    Arlsnn() tries to produce a small residual for the final solution,
    while being based toward making the fewest changes feasible
    to the problem. Most older solvers try to minimize the residual
    at the expense of extra interference with the user's model.
    Arls, arlsgt, and arlsnn seek a better balance.
    """
    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
    checkAb(A, b, 1)
    n = A.shape[1]
    G = np.eye(n)
    h = np.zeros(n)
    return arlsgt(A, b, G, h)
コード例 #11
0
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.
コード例 #12
0
def arls(A, b):
    """Solves the linear system of equation, Ax = b, for any shape matrix.

    The system can be underdetermined, square, or over-determined.
    That is, A(m,n) can be such that m < n, m = n, or m > n.
    Argument b is a matrix of size(m,p) of p right-hand-side columns.
    This solver automatically detects if each system is ill-conditioned or not.

    Then
     -- If the equations are consistent then the solution will usually be
        exact within round-off error.
     -- If the equations are inconsistent then the the solution will be
        by least-squares. That is, it solves ``min ||b - Ax||_2``.
     -- If the equations are inconsistent and diagnosable as ill-conditioned
        using the principles of the first reference below, the system will be
        automatically regularized and the residual will be larger than minimum.
     -- If either A or b is all zeros then the solution will be all zeros.

    Parameters
    ----------
    A : (m, n) array_like
        Coefficient matrix
    b : (m, p) array_like
        Set of columns of dependent variables.

    Returns
    -------
    x : (n, p) array_like set of columns, type float.
        Each column will be the solution corresponding to a column of b.
    nr : int
        The Numerical Rank of A.
    mur : int
        The Minimum Usable Rank seen in solving all the problems.
        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.
    msigma : float
        The largest estimated right-hand-side root-mean-square error seen.
    mlambda : float
        The largest estimated Tikhonov regularization parameter seen.

    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 SCIPY's SVD() does not converge.

    Examples
    --------
    Arls() will behave like any good least-squares solver when the system
    is well conditioned.
    Here is a tiny example of an ill-conditioned system as handled by arls(),

       x + y = 2
       x + 1.01 y =3

    Then A = array([[ 1., 1.],
                    [ 1., 1.01.]])
    and  b = array([2.0, 3.0])

    Then standard solvers will return:
       x = [-98. , 100.]

    But arls() will see the violation of the Picard Condition and return
       x = [1.12216 , 1.12779]

    Notes:
    -----
    1. When the system is ill-conditioned, the process works best when the rows
       of A are scaled so that the elements of b have similar estimated errors.
    2. Arls() occasionally may produce a smoother (i.e., more regularized)
       solution than desired. In this case please try scipy routine lsmr.
    3. With any linear equation solver, check that the solution is reasonable.
       In particular, you should check the residual vector, Ax - b.
    4. Arls() neither needs nor accepts optional parameters such as iteration
       limits, error estimates, variable bounds, condition number limits, etc.
       It also does not return any error flags as there are no error states.
       As long as the SVD converges (and SVD failure is remarkably rare)
       then arls() and other routines in this package will complete normally.
    5. Arls()'s intent (and the intent of all routines in this module)
       is to find a reasonable solution even in the midst of excessive
       inaccuracy, ill-conditioning, singularities, duplicated data, etc.
       Its performance is often very like that of lsmr, but from a completely
       different approach.
    6. In view of note 5, arls() is not appropriate for situations
       where the requirements are more for high accuracy rather than
       robustness. So, we assume, in the coding, where needed, that no data
       needs to be considered more accurate than 8 significant figures.

    References
    ----------
    The auto-regularization algorithm in this software arose from the research
    for my dissertation, "Solving Linear Algebraic Systems Arising in the
    Solution of Integral Equations of the First Kind", University of
    New Mexico, Albuquerque, NM, 1985.

    Many thanks to Cleve B. Moler, MatLab creater and co-founder of MathWorks
    for his energy and insights in guiding my dissertation research.

    My thanks also to Richard Hanson (deceased), co-author of the classic
    "Solving Least Squares Problems", co-creater of BLAS, and co-advisor
    for the last year of my dissertation work.

    My thanks also to Per Christian Hansen for reviewing an early version
    of this software which resulted in my creating the crucial two-phase
    matrix "split" process.

    And my thanks to the central computing department at Sandia National Labs
    where I had the opportunity to contribute to the "MATHLIB" Fortran library
    in the 1960's and 1970's. MATLIB evolved into part of the
    Fortran "SLATEC" library.
    See http://www.netlib.org/slatec/src/

    For for a short presentation on the Picard Condition which is at the heart
    of this package's algorithms, please see
    See www.rejones7.net/Arls/What_Is_The_Picard_Condition.htm

    For a complete description, see "The Discrete Picard Condition for Discrete
    Ill-posed Problems", Per Christian Hansen, 1990.
    See link.springer.com/article/10.1007/BF01933214

    For discussion of incorporating equality and inequality constraints
    (including nonnegativity) in solving linear algebraic problems, see
    "Solving Least Squares Problems", by Charles L. Lawson and
    Richard J. Hanson, Prentice-Hall 1974.
    My implementation of these features has evolved somewhat
    from that fine book, but is based on those algorithms.

    Rondall E. Jones, Ph.D.
    [email protected]
    """
    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
    checkAb(A, b, 2)
    m, n = A.shape
    nrhs = 1
    if len(b.shape) == 2:
        nrhs = b.shape[1]

    U, S, Vt = np.linalg.svd(A, full_matrices=False)

    # one right hand side
    if nrhs == 1:
        return arlsusv(A, b, U, S, Vt)

    # multiple right hand sides
    xx = np.zeros((n, nrhs))
    nr = min(A.shape)
    mur = nr  # track minimum usable rank
    msigma = 0.0  # track maximum estimated RHS error
    mlamda = 0.0  # track maximum Tikhonov parameter
    for p in range(0, nrhs):
        xx[:, p], nr, ur, sigma, lambdah = arlsusv(A, b[:, p], U, S, Vt)
        mur = min(mur, ur)
        msigma = max(msigma, sigma)
        mlamda = max(mlamda, lambdah)
    return xx, nr, mur, msigma, mlamda
コード例 #13
0
ファイル: pinv.py プロジェクト: xiaoyanh/autoNSO
def pinv2(a,
          rank=None,
          cond=None,
          rcond=None,
          return_rank=False,
          check_finite=True):
    """
    Compute the (Moore-Penrose) pseudo-inverse of a matrix.
    Calculate a generalized inverse of a matrix using its
    singular-value decomposition and including all 'large' singular
    values.
    Parameters
    ----------
    a : (M, N) array_like
        Matrix to be pseudo-inverted.
    cond, rcond : float or None
        Cutoff for 'small' singular values; singular values smaller than this
        value are considered as zero. If both are omitted, the default value
        ``max(M,N)*largest_singular_value*eps`` is used where ``eps`` is the
        machine precision value of the datatype of ``a``.
        .. versionchanged:: 1.3.0
            Previously the default cutoff value was just ``eps*f`` where ``f``
            was ``1e3`` for single precision and ``1e6`` for double precision.
    return_rank : bool, optional
        If True, return the effective rank of the matrix.
    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
    -------
    B : (N, M) ndarray
        The pseudo-inverse of matrix `a`.
    rank : int
        The effective rank of the matrix. Returned if `return_rank` is True.
    Raises
    ------
    LinAlgError
        If SVD computation does not converge.
    Examples
    --------
    >>> from scipy import linalg
    >>> a = np.random.randn(9, 6)
    >>> B = linalg.pinv2(a)
    >>> np.allclose(a, np.dot(a, np.dot(B, a)))
    True
    >>> np.allclose(B, np.dot(B, np.dot(a, B)))
    True
    """
    a = _asarray_validated(a, check_finite=check_finite)
    u, s, vh = decomp_svd.svd(a, full_matrices=False, check_finite=False)

    if rank is None:
        if rcond is not None:
            cond = np.max(s) * rcond
        if cond in [None, -1]:
            t = u.dtype.char.lower()
            cond = np.max(s) * max(a.shape) * np.finfo(t).eps
        rank = np.sum(s > cond)
    elif rank == float('inf'):
        assert (cond is not None)
        rank = len(s)
        s[s < cond] = cond

    print(rank, flush='True')
    u = u[:, :rank]
    u /= s[:rank]
    B = np.transpose(np.conjugate(np.dot(u, vh[:rank])))

    if return_rank:
        return B, rank
    else:
        return B
コード例 #14
0
ファイル: _scipy_linalg.py プロジェクト: rpuegue/CoursA61
def pinvh(a,
          cond=None,
          rcond=None,
          lower=True,
          return_rank=False,
          check_finite=True):
    """
    Compute the (Moore-Penrose) pseudo-inverse of a Hermitian matrix.

    Copied in from scipy==1.2.2, in order to preserve the default choice of the
    `cond` and `above_cutoff` values which determine which values of the matrix
    inversion lie below threshold and are so set to zero. Changes in scipy 1.3
    resulted in a smaller default threshold and thus slower convergence of
    dependent algorithms in some cases (see Sklearn github issue #14055).

    Calculate a generalized inverse of a Hermitian or real symmetric matrix
    using its eigenvalue decomposition and including all eigenvalues with
    'large' absolute value.

    Parameters
    ----------
    a : (N, N) array_like
        Real symmetric or complex hermetian matrix to be pseudo-inverted
    cond, rcond : float or None
        Cutoff for 'small' eigenvalues.
        Singular values smaller than rcond * largest_eigenvalue are considered
        zero.

        If None or -1, suitable machine precision is used.
    lower : bool, optional
        Whether the pertinent array data is taken from the lower or upper
        triangle of a. (Default: lower)
    return_rank : bool, optional
        if True, return the effective rank of the matrix
    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
    -------
    B : (N, N) ndarray
        The pseudo-inverse of matrix `a`.
    rank : int
        The effective rank of the matrix.  Returned if return_rank == True

    Raises
    ------
    LinAlgError
        If eigenvalue does not converge

    Examples
    --------
    >>> from scipy.linalg import pinvh
    >>> a = np.random.randn(9, 6)
    >>> a = np.dot(a, a.T)
    >>> B = pinvh(a)
    >>> np.allclose(a, np.dot(a, np.dot(B, a)))
    True
    >>> np.allclose(B, np.dot(B, np.dot(a, B)))
    True

    """
    a = decomp._asarray_validated(a, check_finite=check_finite)
    s, u = decomp.eigh(a, lower=lower, check_finite=False)

    if rcond is not None:
        cond = rcond
    if cond in [None, -1]:
        t = u.dtype.char.lower()
        factor = {'f': 1E3, 'd': 1E6}
        cond = factor[t] * np.finfo(t).eps

    # For Hermitian matrices, singular values equal abs(eigenvalues)
    above_cutoff = (abs(s) > cond * np.max(abs(s)))
    psigma_diag = 1.0 / s[above_cutoff]
    u = u[:, above_cutoff]

    B = np.dot(u * psigma_diag, np.conjugate(u).T)

    if return_rank:
        return B, len(psigma_diag)
    else:
        return B
コード例 #15
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