Esempio n. 1
0
def logm(A):
    """
    Compute matrix logarithm.

    The matrix logarithm is the inverse of
    expm: expm(logm(`A`)) == `A`

    Parameters
    ----------
    A : (N, N) array_like
        Matrix whose logarithm to evaluate

    Returns
    -------
    logm : (N, N) ndarray
        Matrix logarithm of `A`

    References
    ----------
    .. [1] Awad H. Al-Mohy and Nicholas J. Higham (2012)
           "Improved Inverse Scaling and Squaring Algorithms
           for the Matrix Logarithm."
           SIAM Journal on Scientific Computing, 34 (4). C152-C169.
           ISSN 1095-7197

    .. [2] Nicholas J. Higham (2008)
           "Functions of Matrices: Theory and Computation"
           ISBN 978-0-898716-46-7

    .. [3] Nicholas J. Higham and Lijing lin (2011)
           "A Schur-Pade Algorithm for Fractional Powers of a Matrix."
           SIAM Journal on Matrix Analysis and Applications,
           32 (3). pp. 1056-1078. ISSN 0895-4798

    """
    A = np.asarray(A)
    if len(A.shape) != 2 or A.shape[0] != A.shape[1]:
        raise ValueError('expected a square matrix')
    n, n = A.shape
    keep_it_real = not _has_complex_dtype_char(A)
    try:
        if np.array_equal(A, np.triu(A)):
            A_diag = np.diag(A)
            if np.count_nonzero(A_diag) != n:
                raise LogmError('cannot find logm of a singular matrix')
            if np.min(A_diag) < 0:
                A = A.astype(complex)
            return _logm_triu(A)
        else:
            if keep_it_real:
                T, Z = schur(A)
                if not np.array_equal(T, np.triu(T)):
                    T, Z = rsf2csf(T,Z)
            else:
                T, Z = schur(A, output='complex')
            if np.count_nonzero(np.diag(T)) != n:
                raise LogmError('cannot find logm of a singular matrix')
            U = _logm_triu(T)
            U, Z = all_mat(U, Z)
            X = (Z * U * Z.H)
            return X.A
    except (SqrtmError, LogmError) as e:
        X = np.empty_like(A)
        X.fill(np.nan)
        return X
Esempio n. 2
0
def _remainder_matrix_power(A, t):
    """
    Compute the fractional power of a matrix, for fractions -1 < t < 1.

    This uses algorithm (3.1) of [1]_.
    The Pade approximation itself uses algorithm (4.1) of [2]_.

    Parameters
    ----------
    A : (N, N) array_like
        Matrix whose fractional power to evaluate.
    t : float
        Fractional power between -1 and 1 exclusive.

    Returns
    -------
    X : (N, N) array_like
        The fractional power of the matrix.

    References
    ----------
    .. [1] Nicholas J. Higham and Lijing Lin (2013)
           "An Improved Schur-Pade Algorithm for Fractional Powers
           of a Matrix and their Frechet Derivatives."

    .. [2] Nicholas J. Higham and Lijing lin (2011)
           "A Schur-Pade Algorithm for Fractional Powers of a Matrix."
           SIAM Journal on Matrix Analysis and Applications,
           32 (3). pp. 1056-1078. ISSN 0895-4798

    """
    A = np.asarray(A)
    if len(A.shape) != 2 or A.shape[0] != A.shape[1]:
        raise ValueError('expected a square matrix')
    n, n = A.shape

    # Triangularize the matrix if necessary,
    # attempting to preserve dtype if possible.
    if np.array_equal(A, np.triu(A)):
        Z = None
        T = A
    else:
        if not _has_complex_dtype_char(A):
            T, Z = schur(A)
            if not np.array_equal(T, np.triu(T)):
                T, Z = rsf2csf(T, Z)
        else:
            T, Z = schur(A, output='complex')

    # Zeros on the diagonal of the triangular matrix are forbidden,
    # because the inverse scaling and squaring cannot deal with it.
    T_diag = np.diag(T)
    if np.count_nonzero(T_diag) != n:
        raise FractionalMatrixPowerError(
                'cannot use inverse scaling and squaring to find '
                'the fractional matrix power of a singular matrix')

    # If the triangular matrix is real and has a negative
    # entry on the diagonal, then force the matrix to be complex.
    if not _has_complex_dtype_char(T):
        if np.min(T_diag) < 0:
            T = T.astype(complex)

    # Get the fractional power of the triangular matrix,
    # and de-triangularize it if necessary.
    U = _remainder_matrix_power_triu(T, t)
    if Z is not None:
        U, Z = all_mat(U, Z)
        X = (Z * U * Z.H)
        return X.A
    else:
        return U
Esempio n. 3
0
def _remainder_matrix_power(A, t):
    """
    Compute the fractional power of a matrix, for fractions -1 < t < 1.

    This uses algorithm (3.1) of [1]_.
    The Pade approximation itself uses algorithm (4.1) of [2]_.

    Parameters
    ----------
    A : (N, N) array_like
        Matrix whose fractional power to evaluate.
    t : float
        Fractional power between -1 and 1 exclusive.

    Returns
    -------
    X : (N, N) array_like
        The fractional power of the matrix.

    References
    ----------
    .. [1] Nicholas J. Higham and Lijing Lin (2013)
           "An Improved Schur-Pade Algorithm for Fractional Powers
           of a Matrix and their Frechet Derivatives."

    .. [2] Nicholas J. Higham and Lijing lin (2011)
           "A Schur-Pade Algorithm for Fractional Powers of a Matrix."
           SIAM Journal on Matrix Analysis and Applications,
           32 (3). pp. 1056-1078. ISSN 0895-4798

    """
    # This code block is copied from numpy.matrix_power().
    A = np.asarray(A)
    if len(A.shape) != 2 or A.shape[0] != A.shape[1]:
        raise ValueError('input must be a square array')

    # Get the number of rows and columns.
    n, n = A.shape

    # Triangularize the matrix if necessary,
    # attempting to preserve dtype if possible.
    if np.array_equal(A, np.triu(A)):
        Z = None
        T = A
    else:
        if not _has_complex_dtype_char(A):
            T, Z = schur(A)
            if not np.array_equal(T, np.triu(T)):
                T, Z = rsf2csf(T, Z)
        else:
            T, Z = schur(A, output='complex')

    # Zeros on the diagonal of the triangular matrix are forbidden,
    # because the inverse scaling and squaring cannot deal with it.
    T_diag = np.diag(T)
    if _count_nonzero(T_diag) != n:
        raise FractionalMatrixPowerError(
            'cannot use inverse scaling and squaring to find '
            'the fractional matrix power of a singular matrix')

    # If the triangular matrix is real and has a negative
    # entry on the diagonal, then force the matrix to be complex.
    if not _has_complex_dtype_char(T):
        if np.min(T_diag) < 0:
            T = T.astype(complex)

    # Get the fractional power of the triangular matrix,
    # and de-triangularize it if necessary.
    U = _remainder_matrix_power_triu(T, t)
    if Z is not None:
        U, Z = all_mat(U, Z)
        X = (Z * U * Z.H)
        return X.A
    else:
        return U
Esempio n. 4
0
def logm(A):
    """
    Compute matrix logarithm.

    The matrix logarithm is the inverse of
    expm: expm(logm(`A`)) == `A`

    Parameters
    ----------
    A : (N, N) array_like
        Matrix whose logarithm to evaluate

    Returns
    -------
    logm : (N, N) ndarray
        Matrix logarithm of `A`

    References
    ----------
    .. [1] Awad H. Al-Mohy and Nicholas J. Higham (2012)
           "Improved Inverse Scaling and Squaring Algorithms
           for the Matrix Logarithm."
           SIAM Journal on Scientific Computing, 34 (4). C152-C169.
           ISSN 1095-7197

    .. [2] Nicholas J. Higham (2008)
           "Functions of Matrices: Theory and Computation"
           ISBN 978-0-898716-46-7

    .. [3] Nicholas J. Higham and Lijing lin (2011)
           "A Schur-Pade Algorithm for Fractional Powers of a Matrix."
           SIAM Journal on Matrix Analysis and Applications,
           32 (3). pp. 1056-1078. ISSN 0895-4798

    """
    A = np.asarray(A)
    if len(A.shape) != 2 or A.shape[0] != A.shape[1]:
        raise ValueError('expected a square matrix')
    n, n = A.shape
    keep_it_real = not _has_complex_dtype_char(A)
    try:
        if np.array_equal(A, np.triu(A)):
            A_diag = np.diag(A)
            if _count_nonzero(A_diag) != n:
                raise LogmError('cannot find logm of a singular matrix')
            if np.min(A_diag) < 0:
                A = A.astype(complex)
            return _logm_triu(A)
        else:
            if keep_it_real:
                T, Z = schur(A)
                if not np.array_equal(T, np.triu(T)):
                    T, Z = rsf2csf(T, Z)
            else:
                T, Z = schur(A, output='complex')
            if _count_nonzero(np.diag(T)) != n:
                raise LogmError('cannot find logm of a singular matrix')
            U = _logm_triu(T)
            U, Z = all_mat(U, Z)
            X = (Z * U * Z.H)
            return X.A
    except (SqrtmError, LogmError) as e:
        X = np.empty_like(A)
        X.fill(np.nan)
        return X
Esempio n. 5
0
def logm(A):
    """
    Compute matrix logarithm.

    The matrix logarithm is the inverse of
    expm: expm(logm(`A`)) == `A`

    Parameters
    ----------
    A : (N, N) array_like
        Matrix whose logarithm to evaluate

    Returns
    -------
    logm : (N, N) ndarray
        Matrix logarithm of `A`

    References
    ----------
    .. [1] Awad H. Al-Mohy and Nicholas J. Higham (2012)
           "Improved Inverse Scaling and Squaring Algorithms
           for the Matrix Logarithm."
           SIAM Journal on Scientific Computing, 34 (4). C152-C169.
           ISSN 1095-7197

    .. [2] Nicholas J. Higham (2008)
           "Functions of Matrices: Theory and Computation"
           ISBN 978-0-898716-46-7

    .. [3] Nicholas J. Higham and Lijing lin (2011)
           "A Schur-Pade Algorithm for Fractional Powers of a Matrix."
           SIAM Journal on Matrix Analysis and Applications,
           32 (3). pp. 1056-1078. ISSN 0895-4798

    """
    # In this function we look at triangular matrices that are similar
    # to the input matrix.  If any diagonal entry of such a triangular matrix
    # is exactly zero then the original matrix is singular.
    # The matrix logarithm does not exist for such matrices,
    # but in such cases we will pretend that the diagonal entries that are zero
    # are actually slightly positive by an ad-hoc amount, in the interest
    # of returning something more useful than NaN.  This will cause a warning.

    A = np.asarray(A)
    if len(A.shape) != 2 or A.shape[0] != A.shape[1]:
        raise ValueError('expected a square matrix')
    n = A.shape[0]

    # If the input matrix dtype is integer then copy to a float dtype matrix.
    if issubclass(A.dtype.type, np.integer):
        A = np.asarray(A, dtype=float)

    keep_it_real = np.isrealobj(A)
    try:
        if np.array_equal(A, np.triu(A)):
            A = _logm_force_nonsingular_triangular_matrix(A)
            if np.min(np.diag(A)) < 0:
                A = A.astype(complex)
            return _logm_triu(A)
        else:
            if keep_it_real:
                T, Z = schur(A)
                if not np.array_equal(T, np.triu(T)):
                    T, Z = rsf2csf(T,Z)
            else:
                T, Z = schur(A, output='complex')
            T = _logm_force_nonsingular_triangular_matrix(T, inplace=True)
            U = _logm_triu(T)
            U, Z = all_mat(U, Z)
            X = (Z * U * Z.H)
            return X.A
    except (SqrtmError, LogmError) as e:
        X = np.empty_like(A)
        X.fill(np.nan)
        return X