Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/scipy/sparse/linalg/_isolve/tfqmr.py: 6%

70 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-12 06:31 +0000

1import numpy as np 

2from .utils import make_system 

3 

4 

5__all__ = ['tfqmr'] 

6 

7 

8def tfqmr(A, b, x0=None, tol=1e-5, maxiter=None, M=None, 

9 callback=None, atol=None, show=False): 

10 """ 

11 Use Transpose-Free Quasi-Minimal Residual iteration to solve ``Ax = b``. 

12 

13 Parameters 

14 ---------- 

15 A : {sparse matrix, ndarray, LinearOperator} 

16 The real or complex N-by-N matrix of the linear system. 

17 Alternatively, `A` can be a linear operator which can 

18 produce ``Ax`` using, e.g., 

19 `scipy.sparse.linalg.LinearOperator`. 

20 b : {ndarray} 

21 Right hand side of the linear system. Has shape (N,) or (N,1). 

22 x0 : {ndarray} 

23 Starting guess for the solution. 

24 tol, atol : float, optional 

25 Tolerances for convergence, ``norm(residual) <= max(tol*norm(b-Ax0), atol)``. 

26 The default for `tol` is 1.0e-5. 

27 The default for `atol` is ``tol * norm(b-Ax0)``. 

28 

29 .. warning:: 

30 

31 The default value for `atol` will be changed in a future release. 

32 For future compatibility, specify `atol` explicitly. 

33 maxiter : int, optional 

34 Maximum number of iterations. Iteration will stop after maxiter 

35 steps even if the specified tolerance has not been achieved. 

36 Default is ``min(10000, ndofs * 10)``, where ``ndofs = A.shape[0]``. 

37 M : {sparse matrix, ndarray, LinearOperator} 

38 Inverse of the preconditioner of A. M should approximate the 

39 inverse of A and be easy to solve for (see Notes). Effective 

40 preconditioning dramatically improves the rate of convergence, 

41 which implies that fewer iterations are needed to reach a given 

42 error tolerance. By default, no preconditioner is used. 

43 callback : function, optional 

44 User-supplied function to call after each iteration. It is called 

45 as `callback(xk)`, where `xk` is the current solution vector. 

46 show : bool, optional 

47 Specify ``show = True`` to show the convergence, ``show = False`` is 

48 to close the output of the convergence. 

49 Default is `False`. 

50 

51 Returns 

52 ------- 

53 x : ndarray 

54 The converged solution. 

55 info : int 

56 Provides convergence information: 

57 

58 - 0 : successful exit 

59 - >0 : convergence to tolerance not achieved, number of iterations 

60 - <0 : illegal input or breakdown 

61 

62 Notes 

63 ----- 

64 The Transpose-Free QMR algorithm is derived from the CGS algorithm. 

65 However, unlike CGS, the convergence curves for the TFQMR method is 

66 smoothed by computing a quasi minimization of the residual norm. The 

67 implementation supports left preconditioner, and the "residual norm" 

68 to compute in convergence criterion is actually an upper bound on the 

69 actual residual norm ``||b - Axk||``. 

70 

71 References 

72 ---------- 

73 .. [1] R. W. Freund, A Transpose-Free Quasi-Minimal Residual Algorithm for 

74 Non-Hermitian Linear Systems, SIAM J. Sci. Comput., 14(2), 470-482, 

75 1993. 

76 .. [2] Y. Saad, Iterative Methods for Sparse Linear Systems, 2nd edition, 

77 SIAM, Philadelphia, 2003. 

78 .. [3] C. T. Kelley, Iterative Methods for Linear and Nonlinear Equations, 

79 number 16 in Frontiers in Applied Mathematics, SIAM, Philadelphia, 

80 1995. 

81 

82 Examples 

83 -------- 

84 >>> import numpy as np 

85 >>> from scipy.sparse import csc_matrix 

86 >>> from scipy.sparse.linalg import tfqmr 

87 >>> A = csc_matrix([[3, 2, 0], [1, -1, 0], [0, 5, 1]], dtype=float) 

88 >>> b = np.array([2, 4, -1], dtype=float) 

89 >>> x, exitCode = tfqmr(A, b) 

90 >>> print(exitCode) # 0 indicates successful convergence 

91 0 

92 >>> np.allclose(A.dot(x), b) 

93 True 

94 """ 

95 

96 # Check data type 

97 dtype = A.dtype 

98 if np.issubdtype(dtype, np.int64): 

99 dtype = float 

100 A = A.astype(dtype) 

101 if np.issubdtype(b.dtype, np.int64): 

102 b = b.astype(dtype) 

103 

104 A, M, x, b, postprocess = make_system(A, M, x0, b) 

105 

106 # Check if the R.H.S is a zero vector 

107 if np.linalg.norm(b) == 0.: 

108 x = b.copy() 

109 return (postprocess(x), 0) 

110 

111 ndofs = A.shape[0] 

112 if maxiter is None: 

113 maxiter = min(10000, ndofs * 10) 

114 

115 if x0 is None: 

116 r = b.copy() 

117 else: 

118 r = b - A.matvec(x) 

119 u = r 

120 w = r.copy() 

121 # Take rstar as b - Ax0, that is rstar := r = b - Ax0 mathematically 

122 rstar = r 

123 v = M.matvec(A.matvec(r)) 

124 uhat = v 

125 d = theta = eta = 0. 

126 rho = np.inner(rstar.conjugate(), r) 

127 rhoLast = rho 

128 r0norm = np.sqrt(rho) 

129 tau = r0norm 

130 if r0norm == 0: 

131 return (postprocess(x), 0) 

132 

133 if atol is None: 

134 atol = tol * r0norm 

135 else: 

136 atol = max(atol, tol * r0norm) 

137 

138 for iter in range(maxiter): 

139 even = iter % 2 == 0 

140 if (even): 

141 vtrstar = np.inner(rstar.conjugate(), v) 

142 # Check breakdown 

143 if vtrstar == 0.: 

144 return (postprocess(x), -1) 

145 alpha = rho / vtrstar 

146 uNext = u - alpha * v # [1]-(5.6) 

147 w -= alpha * uhat # [1]-(5.8) 

148 d = u + (theta**2 / alpha) * eta * d # [1]-(5.5) 

149 # [1]-(5.2) 

150 theta = np.linalg.norm(w) / tau 

151 c = np.sqrt(1. / (1 + theta**2)) 

152 tau *= theta * c 

153 # Calculate step and direction [1]-(5.4) 

154 eta = (c**2) * alpha 

155 z = M.matvec(d) 

156 x += eta * z 

157 

158 if callback is not None: 

159 callback(x) 

160 

161 # Convergence criteron 

162 if tau * np.sqrt(iter+1) < atol: 

163 if (show): 

164 print("TFQMR: Linear solve converged due to reach TOL " 

165 "iterations {}".format(iter+1)) 

166 return (postprocess(x), 0) 

167 

168 if (not even): 

169 # [1]-(5.7) 

170 rho = np.inner(rstar.conjugate(), w) 

171 beta = rho / rhoLast 

172 u = w + beta * u 

173 v = beta * uhat + (beta**2) * v 

174 uhat = M.matvec(A.matvec(u)) 

175 v += uhat 

176 else: 

177 uhat = M.matvec(A.matvec(uNext)) 

178 u = uNext 

179 rhoLast = rho 

180 

181 if (show): 

182 print("TFQMR: Linear solve not converged due to reach MAXIT " 

183 "iterations {}".format(iter+1)) 

184 return (postprocess(x), maxiter)