Exemplo n.º 1
0
def lstsq(a, b, rcond=-1):
    """
    Return the least-squares solution to an equation.

    Solves the equation `a x = b` by computing a vector `x` that minimizes
    the norm `|| b - a x ||`.

    Parameters
    ----------
    a : array_like, shape (M, N)
        Input equation coefficients.
    b : array_like, shape (M,) or (M, K)
        Equation target values.  If `b` is two-dimensional, the least
        squares solution is calculated for each of the `K` target sets.
    rcond : float, optional
        Cutoff for ``small`` singular values of `a`.
        Singular values smaller than `rcond` times the largest singular
        value are  considered zero.

    Returns
    -------
    x : ndarray, shape(N,) or (N, K)
         Least squares solution.  The shape of `x` depends on the shape of
         `b`.
    residues : ndarray, shape(), (1,), or (K,)
        Sums of residues; squared Euclidian norm for each column in
        `b - a x`.
        If the rank of `a` is < N or > M, this is an empty array.
        If `b` is 1-dimensional, this is a (1,) shape array.
        Otherwise the shape is (K,).
    rank : integer
        Rank of matrix `a`.
    s : ndarray, shape(min(M,N),)
        Singular values of `a`.

    Raises
    ------
    LinAlgError
        If computation does not converge.

    Notes
    -----
    If `b` is a matrix, then all array results returned as
    matrices.

    Examples
    --------
    Fit a line, ``y = mx + c``, through some noisy data-points:

    >>> x = np.array([0, 1, 2, 3])
    >>> y = np.array([-1, 0.2, 0.9, 2.1])

    By examining the coefficients, we see that the line should have a
    gradient of roughly 1 and cuts the y-axis at more-or-less -1.

    We can rewrite the line equation as ``y = Ap``, where ``A = [[x 1]]``
    and ``p = [[m], [c]]``.  Now use `lstsq` to solve for `p`:

    >>> A = np.vstack([x, np.ones(len(x))]).T
    >>> A
    array([[ 0.,  1.],
           [ 1.,  1.],
           [ 2.,  1.],
           [ 3.,  1.]])

    >>> m, c = np.linalg.lstsq(A, y)[0]
    >>> print m, c
    1.0 -0.95

    Plot the data along with the fitted line:

    >>> import matplotlib.pyplot as plt
    >>> plt.plot(x, y, 'o', label='Original data', markersize=10)
    >>> plt.plot(x, m*x + c, 'r', label='Fitted line')
    >>> plt.legend()
    >>> plt.show()

    """
    import math
    a, _ = _makearray(a)
    b, wrap = _makearray(b)
    is_1d = len(b.shape) == 1
    if is_1d:
        b = b[:, newaxis]
    _assertRank2(a, b)
    m  = a.shape[0]
    n  = a.shape[1]
    n_rhs = b.shape[1]
    ldb = max(n, m)
    if m != b.shape[0]:
        raise LinAlgError, 'Incompatible dimensions'
    t, result_t = _commonType(a, b)
    real_t = _linalgRealType(t)
    bstar = zeros((ldb, n_rhs), t)
    bstar[:b.shape[0],:n_rhs] = b.copy()
    a, bstar = _fastCopyAndTranspose(t, a, bstar)
    s = zeros((min(m, n),), real_t)
    nlvl = max( 0, int( math.log( float(min(m, n))/2. ) ) + 1 )
    iwork = zeros((3*min(m, n)*nlvl+11*min(m, n),), fortran_int)
    if isComplexType(t):
        lapack_routine = lapack_lite.zgelsd
        lwork = 1
        rwork = zeros((lwork,), real_t)
        work = zeros((lwork,), t)
        results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond,
                                 0, work, -1, rwork, iwork, 0)
        lwork = int(abs(work[0]))
        rwork = zeros((lwork,), real_t)
        a_real = zeros((m, n), real_t)
        bstar_real = zeros((ldb, n_rhs,), real_t)
        results = lapack_lite.dgelsd(m, n, n_rhs, a_real, m,
                                     bstar_real, ldb, s, rcond,
                                     0, rwork, -1, iwork, 0)
        lrwork = int(rwork[0])
        work = zeros((lwork,), t)
        rwork = zeros((lrwork,), real_t)
        results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond,
                                 0, work, lwork, rwork, iwork, 0)
    else:
        lapack_routine = lapack_lite.dgelsd
        lwork = 1
        work = zeros((lwork,), t)
        results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond,
                                 0, work, -1, iwork, 0)
        lwork = int(work[0])
        work = zeros((lwork,), t)
        results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond,
                                 0, work, lwork, iwork, 0)
    if results['info'] > 0:
        raise LinAlgError, 'SVD did not converge in Linear Least Squares'
    resids = array([], t)
    if is_1d:
        x = array(ravel(bstar)[:n], dtype=result_t, copy=True)
        if results['rank'] == n and m > n:
            resids = array([np.linalg.norm(ravel(bstar)[n:], 2)**2])
    else:
        x = array(transpose(bstar)[:n,:], dtype=result_t, copy=True)
        if results['rank'] == n and m > n:
            resids = array([np.linalg.norm(v[n:], 2)**2 for v in bstar])
    st = s[:min(n, m)].copy().astype(_realType(result_t))
    return wrap(x), wrap(resids), results['rank'], st
Exemplo n.º 2
0
def svd_gesvd(a, full_matrices=True, compute_uv=True, check_finite=True):
    """svd with LAPACK's '#gesvd' (with # = d/z for float/complex).

    Similar as :func:`numpy.linalg.svd`, but use LAPACK 'gesvd' driver.
    Works only with 2D arrays.
    Outer part is based on the code of `numpy.linalg.svd`.

    Parameters
    ----------
    a, full_matrices, compute_uv :
        See :func:`numpy.linalg.svd` for details.
    check_finite :
        check whether input arrays contain 'NaN' or 'inf'.

    Returns
    -------
    U, S, Vh : ndarray
        See :func:`numpy.linalg.svd` for details.
    """
    a, wrap = _makearray(a)  # uses order='C'
    if a.ndim != 2:
        raise LinAlgError("array must be 2D!")
    if a.size == 0 or np.product(a.shape) == 0:
        raise LinAlgError("array cannot be empty")
    if check_finite:
        if not isfinite(a).all():
            raise LinAlgError("Array must not contain infs or NaNs")
    M, N = a.shape
    # determine types
    t, result_t = _commonType(a)
    # t = type for calculation, (for my numpy version) actually always one of {double, cdouble}
    # result_t = one of {single, double, csingle, cdouble}
    is_complex = isComplexType(t)
    real_t = _realType(t)  # real version of t with same precision
    # copy: the array is destroyed
    a = _fastCopyAndTranspose(
        t, a)  # casts a to t, copy and transpose (=change to order='F')

    lapack_routine = _get_gesvd(t)
    # allocate output space & options
    if compute_uv:
        if full_matrices:
            nu = M
            lvt = N
            option = b'A'
        else:
            nu = min(N, M)
            lvt = min(N, M)
            option = b'S'
        u = np.zeros((M, nu), t, order='F')
        vt = np.zeros((lvt, N), t, order='F')
    else:
        option = b'N'
        nu = 1
        u = np.empty((1, 1), t, order='F')
        vt = np.empty((1, 1), t, order='F')
    s = np.zeros((min(N, M), ), real_t, order='F')
    INFO = c_int(0)
    m = c_int(M)
    n = c_int(N)
    lu = c_int(u.shape[0])
    lvt = c_int(vt.shape[0])
    work = np.zeros((1, ), t)
    lwork = c_int(-1)  # first call with lwork=-1
    args = [option, option, m, n, a, m, s, u, lu, vt, lvt, work, lwork, INFO]
    if is_complex:
        # differnt call signature: additional array 'rwork' of fixed size
        rwork = np.zeros((5 * min(N, M), ), real_t)
        args.insert(-1, rwork)
    lapack_routine(
        *args)  # first call: just calculate the required `work` size
    if INFO.value < 0:
        raise Exception('%d-th argument had an illegal value' % INFO.value)
    if is_complex:
        lwork = int(work[0].real)
    else:
        lwork = int(work[0])
    work = np.zeros((lwork, ), t, order='F')
    args[11] = work
    args[12] = c_int(lwork)

    lapack_routine(*args)  # second call: the actual calculation

    if INFO.value < 0:
        raise Exception('%d-th argument had an illegal value' % INFO.value)
    if INFO.value > 0:
        raise LinAlgError("SVD did not converge with 'gesvd'")
    s = s.astype(_realType(result_t))
    if compute_uv:
        u = u.astype(result_t)  # no repeated transpose: used fortran order
        vt = vt.astype(result_t)
        return wrap(u), s, wrap(vt)
    else:
        return s
Exemplo n.º 3
0
def lstsq(a, b, rcond=-1):
    """
    Return the least-squares solution to an equation.

    Solves the equation `a x = b` by computing a vector `x` that minimizes
    the norm `|| b - a x ||`.

    Parameters
    ----------
    a : array_like, shape (M, N)
        Input equation coefficients.
    b : array_like, shape (M,) or (M, K)
        Equation target values.  If `b` is two-dimensional, the least
        squares solution is calculated for each of the `K` target sets.
    rcond : float, optional
        Cutoff for ``small`` singular values of `a`.
        Singular values smaller than `rcond` times the largest singular
        value are  considered zero.

    Returns
    -------
    x : ndarray, shape(N,) or (N, K)
         Least squares solution.  The shape of `x` depends on the shape of
         `b`.
    residues : ndarray, shape(), (1,), or (K,)
        Sums of residues; squared Euclidian norm for each column in
        `b - a x`.
        If the rank of `a` is < N or > M, this is an empty array.
        If `b` is 1-dimensional, this is a (1,) shape array.
        Otherwise the shape is (K,).
    rank : integer
        Rank of matrix `a`.
    s : ndarray, shape(min(M,N),)
        Singular values of `a`.

    Raises
    ------
    LinAlgError
        If computation does not converge.

    Notes
    -----
    If `b` is a matrix, then all array results returned as
    matrices.

    Examples
    --------
    Fit a line, ``y = mx + c``, through some noisy data-points:

    >>> x = np.array([0, 1, 2, 3])
    >>> y = np.array([-1, 0.2, 0.9, 2.1])

    By examining the coefficients, we see that the line should have a
    gradient of roughly 1 and cuts the y-axis at more-or-less -1.

    We can rewrite the line equation as ``y = Ap``, where ``A = [[x 1]]``
    and ``p = [[m], [c]]``.  Now use `lstsq` to solve for `p`:

    >>> A = np.vstack([x, np.ones(len(x))]).T
    >>> A
    array([[ 0.,  1.],
           [ 1.,  1.],
           [ 2.,  1.],
           [ 3.,  1.]])

    >>> m, c = np.linalg.lstsq(A, y)[0]
    >>> print m, c
    1.0 -0.95

    Plot the data along with the fitted line:

    >>> import matplotlib.pyplot as plt
    >>> plt.plot(x, y, 'o', label='Original data', markersize=10)
    >>> plt.plot(x, m*x + c, 'r', label='Fitted line')
    >>> plt.legend()
    >>> plt.show()

    """
    import math
    a, _ = _makearray(a)
    b, wrap = _makearray(b)
    is_1d = len(b.shape) == 1
    if is_1d:
        b = b[:, newaxis]
    _assertRank2(a, b)
    m = a.shape[0]
    n = a.shape[1]
    n_rhs = b.shape[1]
    ldb = max(n, m)
    if m != b.shape[0]:
        raise LinAlgError, 'Incompatible dimensions'
    t, result_t = _commonType(a, b)
    real_t = _linalgRealType(t)
    bstar = zeros((ldb, n_rhs), t)
    bstar[:b.shape[0], :n_rhs] = b.copy()
    a, bstar = _fastCopyAndTranspose(t, a, bstar)
    s = zeros((min(m, n), ), real_t)
    nlvl = max(0, int(math.log(float(min(m, n)) / 2.)) + 1)
    iwork = zeros((3 * min(m, n) * nlvl + 11 * min(m, n), ), fortran_int)
    if isComplexType(t):
        lapack_routine = lapack_lite.zgelsd
        lwork = 1
        rwork = zeros((lwork, ), real_t)
        work = zeros((lwork, ), t)
        results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond, 0,
                                 work, -1, rwork, iwork, 0)
        lwork = int(abs(work[0]))
        rwork = zeros((lwork, ), real_t)
        a_real = zeros((m, n), real_t)
        bstar_real = zeros((
            ldb,
            n_rhs,
        ), real_t)
        results = lapack_lite.dgelsd(m, n, n_rhs, a_real, m, bstar_real, ldb,
                                     s, rcond, 0, rwork, -1, iwork, 0)
        lrwork = int(rwork[0])
        work = zeros((lwork, ), t)
        rwork = zeros((lrwork, ), real_t)
        results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond, 0,
                                 work, lwork, rwork, iwork, 0)
    else:
        lapack_routine = lapack_lite.dgelsd
        lwork = 1
        work = zeros((lwork, ), t)
        results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond, 0,
                                 work, -1, iwork, 0)
        lwork = int(work[0])
        work = zeros((lwork, ), t)
        results = lapack_routine(m, n, n_rhs, a, m, bstar, ldb, s, rcond, 0,
                                 work, lwork, iwork, 0)
    if results['info'] > 0:
        raise LinAlgError, 'SVD did not converge in Linear Least Squares'
    resids = array([], t)
    if is_1d:
        x = array(ravel(bstar)[:n], dtype=result_t, copy=True)
        if results['rank'] == n and m > n:
            resids = array([np.linalg.norm(ravel(bstar)[n:], 2)**2])
    else:
        x = array(transpose(bstar)[:n, :], dtype=result_t, copy=True)
        if results['rank'] == n and m > n:
            resids = array([np.linalg.norm(v[n:], 2)**2 for v in bstar])
    st = s[:min(n, m)].copy().astype(_realType(result_t))
    return wrap(x), wrap(resids), results['rank'], st