예제 #1
0
def mnorm(A, p=1):
    r"""
    Gives the matrix (operator) `p`-norm of A. Currently ``p=1`` and ``p=inf``
    are supported:

    ``p=1`` gives the 1-norm (maximal column sum)

    ``p=inf`` gives the `\infty`-norm (maximal row sum).
    You can use the string 'inf' as well as float('inf') or mpf('inf')

    ``p=2`` (not implemented) for a square matrix is the usual spectral
    matrix norm, i.e. the largest singular value.

    ``p='f'`` (or 'F', 'fro', 'Frobenius, 'frobenius') gives the
    Frobenius norm, which is the elementwise 2-norm. The Frobenius norm is an
    approximation of the spectral norm and satisfies

    .. math ::

        \frac{1}{\sqrt{\mathrm{rank}(A)}} \|A\|_F \le \|A\|_2 \le \|A\|_F

    The Frobenius norm lacks some mathematical properties that might
    be expected of a norm.

    For general elementwise `p`-norms, use :func:`norm` instead.

    **Examples**

        >>> from mpmath import *
        >>> mp.dps = 15
        >>> A = matrix([[1, -1000], [100, 50]])
        >>> mnorm(A, 1)
        mpf('1050.0')
        >>> mnorm(A, inf)
        mpf('1001.0')
        >>> mnorm(A, 'F')
        mpf('1006.2310867787777')

    """
    A = matrix(A)
    if type(p) is not int:
        if type(p) is str and 'frobenius'.startswith(p.lower()):
            return norm(A, 2)
        p = mpmathify(p)
    m, n = A.rows, A.cols
    if p == 1:
        return max(
            fsum((A[i, j] for i in xrange(m)), absolute=1) for j in xrange(n))
    elif p == inf:
        return max(
            fsum((A[i, j] for j in xrange(n)), absolute=1) for i in xrange(m))
    else:
        raise NotImplementedError("matrix p-norm for arbitrary p")
예제 #2
0
def mnorm(A, p=1):
    r"""
    Gives the matrix (operator) `p`-norm of A. Currently ``p=1`` and ``p=inf``
    are supported:

    ``p=1`` gives the 1-norm (maximal column sum)

    ``p=inf`` gives the `\infty`-norm (maximal row sum).
    You can use the string 'inf' as well as float('inf') or mpf('inf')

    ``p=2`` (not implemented) for a square matrix is the usual spectral
    matrix norm, i.e. the largest singular value.

    ``p='f'`` (or 'F', 'fro', 'Frobenius, 'frobenius') gives the
    Frobenius norm, which is the elementwise 2-norm. The Frobenius norm is an
    approximation of the spectral norm and satisfies

    .. math ::

        \frac{1}{\sqrt{\mathrm{rank}(A)}} \|A\|_F \le \|A\|_2 \le \|A\|_F

    The Frobenius norm lacks some mathematical properties that might
    be expected of a norm.

    For general elementwise `p`-norms, use :func:`norm` instead.

    **Examples**

        >>> from mpmath import *
        >>> mp.dps = 15
        >>> A = matrix([[1, -1000], [100, 50]])
        >>> mnorm(A, 1)
        mpf('1050.0')
        >>> mnorm(A, inf)
        mpf('1001.0')
        >>> mnorm(A, 'F')
        mpf('1006.2310867787777')

    """
    A = matrix(A)
    if type(p) is not int:
        if type(p) is str and 'frobenius'.startswith(p.lower()):
            return norm(A, 2)
        p = mpmathify(p)
    m, n = A.rows, A.cols
    if p == 1:
        return max(fsum((A[i,j] for i in xrange(m)), absolute=1) for j in xrange(n))
    elif p == inf:
        return max(fsum((A[i,j] for j in xrange(n)), absolute=1) for i in xrange(m))
    else:
        raise NotImplementedError("matrix p-norm for arbitrary p")
예제 #3
0
def norm(x, p=2):
    r"""
    Gives the entrywise `p`-norm of an iterable *x*, i.e. the vector norm
    `\left(\sum_k |x_k|^p\right)^{1/p}`, for any given `1 \le p \le \infty`.

    Special cases:

    If *x* is not iterable, this just returns ``absmax(x)``.

    ``p=1`` gives the sum of absolute values.

    ``p=2`` is the standard Euclidean vector norm.

    ``p=inf`` gives the magnitude of the largest element.

    For *x* a matrix, ``p=2`` is the Frobenius norm.
    For operator matrix norms, use :func:`mnorm` instead.

    You can use the string 'inf' as well as float('inf') or mpf('inf')
    to specify the infinity norm.

    **Examples**

        >>> from mpmath import *
        >>> mp.dps = 15
        >>> x = matrix([-10, 2, 100])
        >>> norm(x, 1)
        mpf('112.0')
        >>> norm(x, 2)
        mpf('100.5186549850325')
        >>> norm(x, inf)
        mpf('100.0')

    """
    try:
        iter(x)
    except TypeError:
        return absmax(x)
    if type(p) is not int:
        p = mpmathify(p)
    if p == inf:
        return max(absmax(i) for i in x)
    elif p == 1:
        return fsum(x, absolute=1)
    elif p == 2:
        return sqrt(fsum(x, absolute=1, squared=1))
    elif p > 1:
        return nthroot(fsum(abs(i)**p for i in x), p)
    else:
        raise ValueError('p has to be >= 1')
예제 #4
0
def norm(x, p=2):
    r"""
    Gives the entrywise `p`-norm of an iterable *x*, i.e. the vector norm
    `\left(\sum_k |x_k|^p\right)^{1/p}`, for any given `1 \le p \le \infty`.

    Special cases:

    If *x* is not iterable, this just returns ``absmax(x)``.

    ``p=1`` gives the sum of absolute values.

    ``p=2`` is the standard Euclidean vector norm.

    ``p=inf`` gives the magnitude of the largest element.

    For *x* a matrix, ``p=2`` is the Frobenius norm.
    For operator matrix norms, use :func:`mnorm` instead.

    You can use the string 'inf' as well as float('inf') or mpf('inf')
    to specify the infinity norm.

    **Examples**

        >>> from mpmath import *
        >>> mp.dps = 15
        >>> x = matrix([-10, 2, 100])
        >>> norm(x, 1)
        mpf('112.0')
        >>> norm(x, 2)
        mpf('100.5186549850325')
        >>> norm(x, inf)
        mpf('100.0')

    """
    try:
        iter(x)
    except TypeError:
        return absmax(x)
    if type(p) is not int:
        p = mpmathify(p)
    if p == inf:
        return max(absmax(i) for i in x)
    elif p == 1:
        return fsum(x, absolute=1)
    elif p == 2:
        return sqrt(fsum(x, absolute=1, squared=1))
    elif p > 1:
        return nthroot(fsum(abs(i)**p for i in x), p)
    else:
        raise ValueError('p has to be >= 1')
예제 #5
0
def norm_p(x, p=2):
    """
    Calculate the p-norm of a vector.
    0 < p <= oo

    Note: you may want to use float('inf') or mpmath's equivalent to specify oo.
    """
    if p == inf:
        return max(absmax(i) for i in x)
    elif p > 1:
        return nthroot(fsum(abs(i)**p for i in x), p)
    elif p == 1:
        return fsum(abs(i) for i in x)
    else:
        raise ValueError('p has to be an integer greater than 0')
예제 #6
0
def cholesky_solve(A, b, **kwargs):
    """
    Ax = b => x

    Solve a symmetric positive-definite linear equation system.
    This is twice as efficient as lu_solve.

    Typical use cases:
    * A.T*A
    * Hessian matrix
    * differential equations
    """
    # do not overwrite A nor b
    A, b = matrix(A, **kwargs).copy(), matrix(b, **kwargs).copy()
    if A.rows !=  A.cols:
        raise ValueError('can only solve determined system')
    # Cholesky factorization
    L = cholesky(A)
    # solve
    n = L.rows
    assert len(b) == n
    for i in xrange(n):
        b[i] -= fsum(L[i,j] * b[j] for j in xrange(i))
        b[i] /= L[i,i]
    x = U_solve(L.T, b)
    return x
예제 #7
0
def mnorm_oo(A):
    """
    Calculate the oo-norm (maximal row sum) of a matrix.
    """
    assert isinstance(A, matrix)
    m, n = A.rows, A.cols
    return max(fsum(absmax(A[i,j]) for j in xrange(n)) for i in xrange(m))
예제 #8
0
def cholesky_solve(A, b, **kwargs):
    """
    Ax = b => x

    Solve a symmetric positive-definite linear equation system.
    This is twice as efficient as lu_solve.

    Typical use cases:
    * A.T*A
    * Hessian matrix
    * differential equations
    """
    # do not overwrite A nor b
    A, b = matrix(A, **kwargs).copy(), matrix(b, **kwargs).copy()
    if A.rows !=  A.cols:
        raise ValueError('can only solve determined system')
    # Cholesky factorization
    L = cholesky(A)
    # solve
    n = L.rows
    assert len(b) == n
    for i in xrange(n):
        b[i] -= fsum(L[i,j] * b[j] for j in xrange(i))
        b[i] /= L[i,i]
    x = U_solve(L.T, b)
    return x
예제 #9
0
def householder(A):
    """
    (A|b) -> H, p, x, res

    (A|b) is the coefficient matrix with left hand side of an optionally
    overdetermined linear equation system.
    H and p contain all information about the transformation matrices.
    x is the solution, res the residual.
    """
    assert isinstance(A, matrix)
    m = A.rows
    n = A.cols
    assert m >= n - 1
    # calculate Householder matrix
    p = []
    for j in xrange(0, n - 1):
        s = fsum((A[i,j])**2 for i in xrange(j, m))
        if not abs(s) > eps:
            raise ValueError('matrix is numerically singular')
        p.append(-sign(A[j,j]) * sqrt(s))
        kappa = s - p[j] * A[j,j]
        A[j,j] -= p[j]
        for k in xrange(j+1, n):
            y = fsum(A[i,j] * A[i,k] for i in xrange(j, m)) /  kappa
            for i in xrange(j, m):
                A[i,k] -= A[i,j] * y
    # solve Rx = c1
    x = [A[i,n - 1] for i in xrange(n - 1)]
    for i in xrange(n - 2, -1, -1):
        x[i] -= fsum(A[i,j] * x[j] for j in xrange(i + 1, n - 1))
        x[i] /= p[i]
    # calculate residual
    if not m == n - 1:
        r = [A[m-1-i, n-1] for i in xrange(m - n + 1)]
    else:
        # determined system, residual should be 0
        r = [0]*m # maybe a bad idea, changing r[i] will change all elements
    return A, p, x, r
예제 #10
0
def householder(A):
    """
    (A|b) -> H, p, x, res

    (A|b) is the coefficient matrix with left hand side of an optionally
    overdetermined linear equation system.
    H and p contain all information about the transformation matrices.
    x is the solution, res the residual.
    """
    assert isinstance(A, matrix)
    m = A.rows
    n = A.cols
    assert m >= n - 1
    # calculate Householder matrix
    p = []
    for j in xrange(0, n - 1):
        s = fsum((A[i,j])**2 for i in xrange(j, m))
        if not abs(s) > eps:
            raise ValueError('matrix is numerically singular')
        p.append(-sign(A[j,j]) * sqrt(s))
        kappa = s - p[j] * A[j,j]
        A[j,j] -= p[j]
        for k in xrange(j+1, n):
            y = fsum(A[i,j] * A[i,k] for i in xrange(j, m)) /  kappa
            for i in xrange(j, m):
                A[i,k] -= A[i,j] * y
    # solve Rx = c1
    x = [A[i,n - 1] for i in xrange(n - 1)]
    for i in xrange(n - 2, -1, -1):
        x[i] -= fsum(A[i,j] * x[j] for j in xrange(i + 1, n - 1))
        x[i] /= p[i]
    # calculate residual
    if not m == n - 1:
        r = [A[m-1-i, n-1] for i in xrange(m - n + 1)]
    else:
        # determined system, residual should be 0
        r = [0]*m # maybe a bad idea, changing r[i] will change all elements
    return A, p, x, r
예제 #11
0
def cholesky(A):
    """
    Cholesky decompositon of a symmetric positive-definite matrix.

    Can be used to solve linear equation systems twice as efficient compared
    to LU decomposition or to test whether A is positive-definite.

    A = L * L.T
    Only L (the lower part) is returned.
    """
    assert isinstance(A, matrix)
    if not A.rows == A.cols:
        raise ValueError('need n*n matrix')
    n = A.rows
    L = matrix(n)
    for j in xrange(n):
        s = A[j,j] - fsum(L[j,k]**2 for k in xrange(j))
        if s < eps:
            raise ValueError('matrix not positive-definite')
        L[j,j] = sqrt(s)
        for i in xrange(j, n):
            L[i,j] = (A[i,j] - fsum(L[i,k] * L[j,k] for k in xrange(j))) \
                     / L[j,j]
    return L
예제 #12
0
def cholesky(A):
    """
    Cholesky decomposition of a symmetric positive-definite matrix.

    Can be used to solve linear equation systems twice as efficient compared
    to LU decomposition or to test whether A is positive-definite.

    A = L * L.T
    Only L (the lower part) is returned.
    """
    assert isinstance(A, matrix)
    if not A.rows == A.cols:
        raise ValueError('need n*n matrix')
    n = A.rows
    L = matrix(n)
    for j in xrange(n):
        s = A[j,j] - fsum(L[j,k]**2 for k in xrange(j))
        if s < eps:
            raise ValueError('matrix not positive-definite')
        L[j,j] = sqrt(s)
        for i in xrange(j, n):
            L[i,j] = (A[i,j] - fsum(L[i,k] * L[j,k] for k in xrange(j))) \
                     / L[j,j]
    return L
예제 #13
0
def LU_decomp(A, overwrite=False, use_cache=True):
    """
    LU-factorization of a n*n matrix using the Gauss algorithm.
    Returns L and U in one matrix and the pivot indices.

    Use overwrite to specify whether A will be overwritten with L and U.
    """
    if not A.rows == A.cols:
        raise ValueError('need n*n matrix')
    # get from cache if possible
    if use_cache and isinstance(A, matrix) and A._LU:
        return A._LU
    if not overwrite:
        orig = A
        A = A.copy()
    tol = absmin(mnorm(A,1) * eps) # each pivot element has to be bigger
    n = A.rows
    p = [None]*(n - 1)
    for j in xrange(n - 1):
        # pivoting, choose max(abs(reciprocal row sum)*abs(pivot element))
        biggest = 0
        for k in xrange(j, n):
            s = fsum([absmin(A[k,l]) for l in xrange(j, n)])
            if absmin(s) <= tol:
                raise ZeroDivisionError('matrix is numerically singular')
            current = 1/s * absmin(A[k,j])
            if current > biggest: # TODO: what if equal?
                biggest = current
                p[j] = k
        # swap rows according to p
        swap_row(A, j, p[j])
        if absmin(A[j,j]) <= tol:
            raise ZeroDivisionError('matrix is numerically singular')
        # calculate elimination factors and add rows
        for i in xrange(j + 1, n):
            A[i,j] /= A[j,j]
            for k in xrange(j + 1, n):
                A[i,k] -= A[i,j]*A[j,k]
    if absmin(A[n - 1,n - 1]) <= tol:
        raise ZeroDivisionError('matrix is numerically singular')
    # cache decomposition
    if not overwrite and isinstance(orig, matrix):
        orig._LU = (A, p)
    return A, p
예제 #14
0
def LU_decomp(A, overwrite=False, use_cache=True):
    """
    LU-factorization of a n*n matrix using the Gauss algorithm.
    Returns L and U in one matrix and the pivot indices.

    Use overwrite to specify whether A will be overwritten with L and U.
    """
    if not A.rows == A.cols:
        raise ValueError('need n*n matrix')
    # get from cache if possible
    if use_cache and isinstance(A, matrix) and A._LU:
        return A._LU
    if not overwrite:
        orig = A
        A = A.copy()
    tol = absmin(mnorm(A,1) * eps) # each pivot element has to be bigger
    n = A.rows
    p = [None]*(n - 1)
    for j in xrange(n - 1):
        # pivoting, choose max(abs(reciprocal row sum)*abs(pivot element))
        biggest = 0
        for k in xrange(j, n):
            s = fsum([absmin(A[k,l]) for l in xrange(j, n)])
            if absmin(s) <= tol:
                raise ZeroDivisionError('matrix is numerically singular')
            current = 1/s * absmin(A[k,j])
            if current > biggest: # TODO: what if equal?
                biggest = current
                p[j] = k
        # swap rows according to p
        swap_row(A, j, p[j])
        if absmin(A[j,j]) <= tol:
            raise ZeroDivisionError('matrix is numerically singular')
        # calculate elimination factors and add rows
        for i in xrange(j + 1, n):
            A[i,j] /= A[j,j]
            for k in xrange(j + 1, n):
                A[i,k] -= A[i,j]*A[j,k]
    if absmin(A[n - 1,n - 1]) <= tol:
        raise ZeroDivisionError('matrix is numerically singular')
    # cache decomposition
    if not overwrite and isinstance(orig, matrix):
        orig._LU = (A, p)
    return A, p