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
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
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
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
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