Source code for pyamg.krylov._minimal_residual

"""Minimum Residual projection method."""

import warnings
from warnings import warn
import numpy as np
from ..util.linalg import norm
from ..util import make_system


[docs] def minimal_residual(A, b, x0=None, tol=1e-5, maxiter=None, M=None, callback=None, residuals=None): """Minimal residual (MR) algorithm. 1D projection method. Solves the linear system Ax = b. Left preconditioning is supported. Parameters ---------- A : array, matrix, sparse matrix, LinearOperator n x n, linear system to solve b : array, matrix right hand side, shape is (n,) or (n,1) x0 : array, matrix initial guess, default is a vector of zeros tol : float Tolerance for stopping criteria, let r=r_k ||M r|| < tol ||M b|| if ||b||=0, then set ||M b||=1 for these tests. maxiter : int maximum number of iterations allowed M : array, matrix, sparse matrix, LinearOperator n x n, inverted preconditioner, i.e. solve M A x = M b. callback : function User-supplied function is called after each iteration as callback(xk), where xk is the current solution vector residuals : list preconditioned residual history in the 2-norm, including the initial preconditioned residual Returns ------- (xk, info) xk : an updated guess after k iterations to the solution of Ax = b info : halting status == ======================================= 0 successful exit >0 convergence to tolerance not achieved, return iteration count instead. <0 numerical breakdown, or illegal input == ======================================= Notes ----- The LinearOperator class is in scipy.sparse.linalg. Use this class if you prefer to define A or M as a mat-vec routine as opposed to explicitly constructing the matrix. .. minimal residual algorithm: Preconditioned version: r = b - A x r = b - A x, z = M r while not converged: while not converged: p = A r p = M A z alpha = (p,r) / (p,p) alpha = (p, z) / (p, p) x = x + alpha r x = x + alpha z r = r - alpha p z = z - alpha p See Also -------- _steepest_descent Examples -------- >>> from pyamg.krylov import minimal_residual >>> from pyamg.util.linalg import norm >>> import numpy as np >>> from pyamg.gallery import poisson >>> A = poisson((10,10)) >>> b = np.ones((A.shape[0],)) >>> (x,flag) = minimal_residual(A,b, maxiter=2, tol=1e-8) >>> print(f'{norm(b - A*x):.6}') 7.26369 References ---------- .. [1] Yousef Saad, "Iterative Methods for Sparse Linear Systems, Second Edition", SIAM, pp. 137--142, 2003 http://www-users.cs.umn.edu/~saad/books.html """ A, M, x, b, postprocess = make_system(A, M, x0, b) # Ensure that warnings are always reissued from this function warnings.filterwarnings('always', module='pyamg.krylov._minimal_residual') # determine maxiter if maxiter is None: maxiter = int(1.3*len(b)) + 2 elif maxiter < 1: raise ValueError('Number of iterations must be positive') # setup method r = b - A @ x z = M @ r normr = norm(z) # store initial residual if residuals is not None: residuals[:] = [normr] # Check initial guess if b != 0, normb = norm(b) if normb == 0.0: normMb = 1.0 # reset so that tol is unscaled else: normMb = norm(M @ b) # set the stopping criteria (see the docstring) if normr < tol * normMb: return (postprocess(x), 0) # How often should r be recomputed recompute_r = 50 it = 0 while True: p = M @ (A @ z) # (p, z) = (M A M r, M r) = (M A z, z) pz = np.inner(p.conjugate(), z) # check curvature of M^-1 A if pz < 0.0: warn('\nIndefinite matrix detected in minimal residual, stopping.\n') return (postprocess(x), -1) alpha = pz / np.inner(p.conjugate(), p) x = x + alpha * z it += 1 if np.mod(it, recompute_r) and it > 0: r = b - A @ x z = M @ r else: z = z - alpha * p normr = norm(z) if residuals is not None: residuals.append(normr) if callback is not None: callback(x) # set the stopping criteria (see the docstring) if normr < tol * normMb: return (postprocess(x), 0) if it == maxiter: return (postprocess(x), it)