Coverage for scipy\linalg\_matfuncs_sqrtm.py: 0%

# Coverage for scipy\linalg\_matfuncs_sqrtm.py : 0%

## 85 statements 0 run 85 missing 0 excluded

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | """ Matrix square root for general matrices and for upper triangular matrices. This module exists to avoid cyclic imports. """ from __future__ import division, print_function, absolute_import __all__ = ['sqrtm'] import numpy as np from scipy._lib._util import _asarray_validated # Local imports from .misc import norm from .lapack import ztrsyl, dtrsyl from .decomp_schur import schur, rsf2csf class SqrtmError(np.linalg.LinAlgError): pass def _sqrtm_triu(T, blocksize=64): """ Matrix square root of an upper triangular matrix. This is a helper function for `sqrtm` and `logm`. Parameters ---------- T : (N, N) array_like upper triangular Matrix whose square root to evaluate blocksize : int, optional If the blocksize is not degenerate with respect to the size of the input array, then use a blocked algorithm. (Default: 64) Returns ------- sqrtm : (N, N) ndarray Value of the sqrt function at `T` References ---------- .. [1] Edvin Deadman, Nicholas J. Higham, Rui Ralha (2013) "Blocked Schur Algorithms for Computing the Matrix Square Root, Lecture Notes in Computer Science, 7782. pp. 171-182. """ T_diag = np.diag(T) keep_it_real = np.isrealobj(T) and np.min(T_diag) >= 0 if not keep_it_real: T_diag = T_diag.astype(complex) R = np.diag(np.sqrt(T_diag)) # Compute the number of blocks to use; use at least one block. n, n = T.shape nblocks = max(n // blocksize, 1) # Compute the smaller of the two sizes of blocks that # we will actually use, and compute the number of large blocks. bsmall, nlarge = divmod(n, nblocks) blarge = bsmall + 1 nsmall = nblocks - nlarge if nsmall * bsmall + nlarge * blarge != n: raise Exception('internal inconsistency') # Define the index range covered by each block. start_stop_pairs = [] start = 0 for count, size in ((nsmall, bsmall), (nlarge, blarge)): for i in range(count): start_stop_pairs.append((start, start + size)) start += size # Within-block interactions. for start, stop in start_stop_pairs: for j in range(start, stop): for i in range(j-1, start-1, -1): s = 0 if j - i > 1: s = R[i, i+1: j].dot(R[i+1: j, j]) denom = R[i, i] + R[j, j] num = T[i, j] - s if denom != 0: R[i, j] = (T[i, j] - s) / denom elif denom == 0 and num == 0: R[i, j] = 0 else: raise SqrtmError('failed to find the matrix square root') # Between-block interactions. for j in range(nblocks): jstart, jstop = start_stop_pairs[j] for i in range(j-1, -1, -1): istart, istop = start_stop_pairs[i] S = T[istart: istop, jstart: jstop] if j - i > 1: S = S - R[istart: istop, istop: jstart].dot(R[istop: jstart, jstart: jstop]) # Invoke LAPACK. # For more details, see the solve_sylvester implemention # and the fortran dtrsyl and ztrsyl docs. Rii = R[istart: istop, istart: istop] Rjj = R[jstart: jstop, jstart: jstop] if keep_it_real: x, scale, info = dtrsyl(Rii, Rjj, S) else: x, scale, info = ztrsyl(Rii, Rjj, S) R[istart: istop, jstart: jstop] = x * scale # Return the matrix square root. return R def sqrtm(A, disp=True, blocksize=64): """ Matrix square root. Parameters ---------- A : (N, N) array_like Matrix whose square root to evaluate disp : bool, optional Print warning if error in the result is estimated large instead of returning estimated error. (Default: True) blocksize : integer, optional If the blocksize is not degenerate with respect to the size of the input array, then use a blocked algorithm. (Default: 64) Returns ------- sqrtm : (N, N) ndarray Value of the sqrt function at `A` errest : float (if disp == False) Frobenius norm of the estimated error, ||err||_F / ||A||_F References ---------- .. [1] Edvin Deadman, Nicholas J. Higham, Rui Ralha (2013) "Blocked Schur Algorithms for Computing the Matrix Square Root, Lecture Notes in Computer Science, 7782. pp. 171-182. Examples -------- >>> from scipy.linalg import sqrtm >>> a = np.array([[1.0, 3.0], [1.0, 4.0]]) >>> r = sqrtm(a) >>> r array([[ 0.75592895, 1.13389342], [ 0.37796447, 1.88982237]]) >>> r.dot(r) array([[ 1., 3.], [ 1., 4.]]) """ A = _asarray_validated(A, check_finite=True, as_inexact=True) if len(A.shape) != 2: raise ValueError("Non-matrix input to matrix function.") if blocksize < 1: raise ValueError("The blocksize should be at least 1.") keep_it_real = np.isrealobj(A) 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') failflag = False try: R = _sqrtm_triu(T, blocksize=blocksize) ZH = np.conjugate(Z).T X = Z.dot(R).dot(ZH) except SqrtmError: failflag = True X = np.empty_like(A) X.fill(np.nan) if disp: if failflag: print("Failed to find a square root.") return X else: try: arg2 = norm(X.dot(X) - A, 'fro')**2 / norm(A, 'fro') except ValueError: # NaNs in matrix arg2 = np.inf return X, arg2