Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/scipy/sparse/linalg/_isolve/tfqmr.py: 10%
71 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-14 06:37 +0000
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-14 06:37 +0000
1import numpy as np
2from .iterative import _get_atol_rtol
3from .utils import make_system
4from scipy._lib.deprecation import _NoValue, _deprecate_positional_args
7__all__ = ['tfqmr']
10@_deprecate_positional_args(version="1.14.0")
11def tfqmr(A, b, x0=None, *, tol=_NoValue, maxiter=None, M=None,
12 callback=None, atol=None, rtol=1e-5, show=False):
13 """
14 Use Transpose-Free Quasi-Minimal Residual iteration to solve ``Ax = b``.
16 Parameters
17 ----------
18 A : {sparse matrix, ndarray, LinearOperator}
19 The real or complex N-by-N matrix of the linear system.
20 Alternatively, `A` can be a linear operator which can
21 produce ``Ax`` using, e.g.,
22 `scipy.sparse.linalg.LinearOperator`.
23 b : {ndarray}
24 Right hand side of the linear system. Has shape (N,) or (N,1).
25 x0 : {ndarray}
26 Starting guess for the solution.
27 rtol, atol : float, optional
28 Parameters for the convergence test. For convergence,
29 ``norm(b - A @ x) <= max(rtol*norm(b), atol)`` should be satisfied.
30 The default is ``rtol=1e-5``, the default for ``atol`` is ``rtol``.
32 .. warning::
34 The default value for ``atol`` will be changed to ``0.0`` in
35 SciPy 1.14.0.
36 maxiter : int, optional
37 Maximum number of iterations. Iteration will stop after maxiter
38 steps even if the specified tolerance has not been achieved.
39 Default is ``min(10000, ndofs * 10)``, where ``ndofs = A.shape[0]``.
40 M : {sparse matrix, ndarray, LinearOperator}
41 Inverse of the preconditioner of A. M should approximate the
42 inverse of A and be easy to solve for (see Notes). Effective
43 preconditioning dramatically improves the rate of convergence,
44 which implies that fewer iterations are needed to reach a given
45 error tolerance. By default, no preconditioner is used.
46 callback : function, optional
47 User-supplied function to call after each iteration. It is called
48 as `callback(xk)`, where `xk` is the current solution vector.
49 show : bool, optional
50 Specify ``show = True`` to show the convergence, ``show = False`` is
51 to close the output of the convergence.
52 Default is `False`.
53 tol : float, optional, deprecated
55 .. deprecated:: 1.12.0
56 `tfqmr` keyword argument ``tol`` is deprecated in favor of ``rtol``
57 and will be removed in SciPy 1.14.0.
59 Returns
60 -------
61 x : ndarray
62 The converged solution.
63 info : int
64 Provides convergence information:
66 - 0 : successful exit
67 - >0 : convergence to tolerance not achieved, number of iterations
68 - <0 : illegal input or breakdown
70 Notes
71 -----
72 The Transpose-Free QMR algorithm is derived from the CGS algorithm.
73 However, unlike CGS, the convergence curves for the TFQMR method is
74 smoothed by computing a quasi minimization of the residual norm. The
75 implementation supports left preconditioner, and the "residual norm"
76 to compute in convergence criterion is actually an upper bound on the
77 actual residual norm ``||b - Axk||``.
79 References
80 ----------
81 .. [1] R. W. Freund, A Transpose-Free Quasi-Minimal Residual Algorithm for
82 Non-Hermitian Linear Systems, SIAM J. Sci. Comput., 14(2), 470-482,
83 1993.
84 .. [2] Y. Saad, Iterative Methods for Sparse Linear Systems, 2nd edition,
85 SIAM, Philadelphia, 2003.
86 .. [3] C. T. Kelley, Iterative Methods for Linear and Nonlinear Equations,
87 number 16 in Frontiers in Applied Mathematics, SIAM, Philadelphia,
88 1995.
90 Examples
91 --------
92 >>> import numpy as np
93 >>> from scipy.sparse import csc_matrix
94 >>> from scipy.sparse.linalg import tfqmr
95 >>> A = csc_matrix([[3, 2, 0], [1, -1, 0], [0, 5, 1]], dtype=float)
96 >>> b = np.array([2, 4, -1], dtype=float)
97 >>> x, exitCode = tfqmr(A, b)
98 >>> print(exitCode) # 0 indicates successful convergence
99 0
100 >>> np.allclose(A.dot(x), b)
101 True
102 """
104 # Check data type
105 dtype = A.dtype
106 if np.issubdtype(dtype, np.int64):
107 dtype = float
108 A = A.astype(dtype)
109 if np.issubdtype(b.dtype, np.int64):
110 b = b.astype(dtype)
112 A, M, x, b, postprocess = make_system(A, M, x0, b)
114 # Check if the R.H.S is a zero vector
115 if np.linalg.norm(b) == 0.:
116 x = b.copy()
117 return (postprocess(x), 0)
119 ndofs = A.shape[0]
120 if maxiter is None:
121 maxiter = min(10000, ndofs * 10)
123 if x0 is None:
124 r = b.copy()
125 else:
126 r = b - A.matvec(x)
127 u = r
128 w = r.copy()
129 # Take rstar as b - Ax0, that is rstar := r = b - Ax0 mathematically
130 rstar = r
131 v = M.matvec(A.matvec(r))
132 uhat = v
133 d = theta = eta = 0.
134 # at this point we know rstar == r, so rho is always real
135 rho = np.inner(rstar.conjugate(), r).real
136 rhoLast = rho
137 r0norm = np.sqrt(rho)
138 tau = r0norm
139 if r0norm == 0:
140 return (postprocess(x), 0)
142 # we call this to get the right atol and raise warnings as necessary
143 atol, _ = _get_atol_rtol('tfqmr', r0norm, tol, atol, rtol)
145 for iter in range(maxiter):
146 even = iter % 2 == 0
147 if (even):
148 vtrstar = np.inner(rstar.conjugate(), v)
149 # Check breakdown
150 if vtrstar == 0.:
151 return (postprocess(x), -1)
152 alpha = rho / vtrstar
153 uNext = u - alpha * v # [1]-(5.6)
154 w -= alpha * uhat # [1]-(5.8)
155 d = u + (theta**2 / alpha) * eta * d # [1]-(5.5)
156 # [1]-(5.2)
157 theta = np.linalg.norm(w) / tau
158 c = np.sqrt(1. / (1 + theta**2))
159 tau *= theta * c
160 # Calculate step and direction [1]-(5.4)
161 eta = (c**2) * alpha
162 z = M.matvec(d)
163 x += eta * z
165 if callback is not None:
166 callback(x)
168 # Convergence criterion
169 if tau * np.sqrt(iter+1) < atol:
170 if (show):
171 print("TFQMR: Linear solve converged due to reach TOL "
172 f"iterations {iter+1}")
173 return (postprocess(x), 0)
175 if (not even):
176 # [1]-(5.7)
177 rho = np.inner(rstar.conjugate(), w)
178 beta = rho / rhoLast
179 u = w + beta * u
180 v = beta * uhat + (beta**2) * v
181 uhat = M.matvec(A.matvec(u))
182 v += uhat
183 else:
184 uhat = M.matvec(A.matvec(uNext))
185 u = uNext
186 rhoLast = rho
188 if (show):
189 print("TFQMR: Linear solve not converged due to reach MAXIT "
190 f"iterations {iter+1}")
191 return (postprocess(x), maxiter)