Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
    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
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
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.

    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
Beispiel #8
0
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
Beispiel #9
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
Beispiel #10
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.
        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
Beispiel #12
0
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