def bicg(A, b, x0=None, tol=1e-5, maxiter=None, xtype=None, M=None, callback=None): A,M,x,b,postprocess = make_system(A,M,x0,b,xtype) n = len(b) if maxiter is None: maxiter = n*10 matvec, rmatvec = A.matvec, A.rmatvec psolve, rpsolve = M.matvec, M.rmatvec ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'bicgrevcom') stoptest = getattr(_iterative, ltr + 'stoptest2') resid = tol ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros(6*n,dtype=x.dtype) ijob = 1 info = 0 ftflag = True bnrm2 = -1.0 iter_ = maxiter while True: olditer = iter_ x, iter_, resid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, work, iter_, resid, info, ndx1, ndx2, ijob) if callback is not None and iter_ > olditer: callback(x) slice1 = slice(ndx1-1, ndx1-1+n) slice2 = slice(ndx2-1, ndx2-1+n) if (ijob == -1): if callback is not None: callback(x) break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1*matvec(work[slice1]) elif (ijob == 2): work[slice2] *= sclr2 work[slice2] += sclr1*rmatvec(work[slice1]) elif (ijob == 3): work[slice1] = psolve(work[slice2]) elif (ijob == 4): work[slice1] = rpsolve(work[slice2]) elif (ijob == 5): work[slice2] *= sclr2 work[slice2] += sclr1*matvec(x) elif (ijob == 6): if ftflag: info = -1 ftflag = False bnrm2, resid, info = stoptest(work[slice1], b, bnrm2, tol, info) ijob = 2 if info > 0 and iter_ == maxiter and resid > tol: # info isn't set appropriately otherwise info = iter_ return postprocess(x), info
def bicgstab(A, b, x0=None, tol=1e-5, maxiter=None, M=None, callback=None, atol=None): A, M, x, b, postprocess = make_system(A, M, x0, b) n = len(b) if maxiter is None: maxiter = n*10 matvec = A.matvec psolve = M.matvec ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'bicgstabrevcom') get_residual = lambda: np.linalg.norm(matvec(x) - b) atol = _get_atol(tol, atol, np.linalg.norm(b), get_residual, 'bicgstab') if atol == 'exit': return postprocess(x), 0 resid = atol ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros(7*n,dtype=x.dtype) ijob = 1 info = 0 ftflag = True iter_ = maxiter while True: olditer = iter_ x, iter_, resid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, work, iter_, resid, info, ndx1, ndx2, ijob) if callback is not None and iter_ > olditer: callback(x) slice1 = slice(ndx1-1, ndx1-1+n) slice2 = slice(ndx2-1, ndx2-1+n) if (ijob == -1): if callback is not None: callback(x) break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1*matvec(work[slice1]) elif (ijob == 2): work[slice1] = psolve(work[slice2]) elif (ijob == 3): work[slice2] *= sclr2 work[slice2] += sclr1*matvec(x) elif (ijob == 4): if ftflag: info = -1 ftflag = False resid, info = _stoptest(work[slice1], atol) ijob = 2 if info > 0 and iter_ == maxiter and not (resid <= atol): # info isn't set appropriately otherwise info = iter_ return postprocess(x), info
def check(shape, dtype, order, align): err_msg = repr((shape, dtype, order, align)) x = _aligned_zeros(shape, dtype, order, align=align) if align is None: align = np.dtype(dtype).alignment assert_equal(x.__array_interface__['data'][0] % align, 0) if hasattr(shape, '__len__'): assert_equal(x.shape, shape, err_msg) else: assert_equal(x.shape, (shape,), err_msg) assert_equal(x.dtype, dtype) if order == "C": assert_(x.flags.c_contiguous, err_msg) elif order == "F": if x.size > 0: # Size-0 arrays get invalid flags on Numpy 1.5 assert_(x.flags.f_contiguous, err_msg) elif order is None: assert_(x.flags.c_contiguous, err_msg) else: raise ValueError()
def check(shape, dtype, order, align): err_msg = repr((shape, dtype, order, align)) x = _aligned_zeros(shape, dtype, order, align=align) if align is None: align = np.dtype(dtype).alignment assert_equal(x.__array_interface__['data'][0] % align, 0) if hasattr(shape, '__len__'): assert_equal(x.shape, shape, err_msg) else: assert_equal(x.shape, (shape, ), err_msg) assert_equal(x.dtype, dtype) if order == "C": assert_(x.flags.c_contiguous, err_msg) elif order == "F": if x.size > 0: # Size-0 arrays get invalid flags on Numpy 1.5 assert_(x.flags.f_contiguous, err_msg) elif order is None: assert_(x.flags.c_contiguous, err_msg) else: raise ValueError()
def gmres(A, b, x0=None, tol=1e-5, restart=None, maxiter=None, M=None, callback=None, restrt=None, atol=None, callback_type=None): """ Use Generalized Minimal RESidual iteration to solve ``Ax = b``. Parameters ---------- A : {sparse matrix, dense matrix, LinearOperator} The real or complex N-by-N matrix of the linear system. Alternatively, ``A`` can be a linear operator which can produce ``Ax`` using, e.g., ``scipy.sparse.linalg.LinearOperator``. b : {array, matrix} Right hand side of the linear system. Has shape (N,) or (N,1). Returns ------- x : {array, matrix} The converged solution. info : int Provides convergence information: * 0 : successful exit * >0 : convergence to tolerance not achieved, number of iterations * <0 : illegal input or breakdown Other parameters ---------------- x0 : {array, matrix} Starting guess for the solution (a vector of zeros by default). tol, atol : float, optional Tolerances for convergence, ``norm(residual) <= max(tol*norm(b), atol)``. The default for ``atol`` is ``'legacy'``, which emulates a different legacy behavior. .. warning:: The default value for `atol` will be changed in a future release. For future compatibility, specify `atol` explicitly. restart : int, optional Number of iterations between restarts. Larger values increase iteration cost, but may be necessary for convergence. Default is 20. maxiter : int, optional Maximum number of iterations (restart cycles). Iteration will stop after maxiter steps even if the specified tolerance has not been achieved. M : {sparse matrix, dense matrix, LinearOperator} Inverse of the preconditioner of A. M should approximate the inverse of A and be easy to solve for (see Notes). Effective preconditioning dramatically improves the rate of convergence, which implies that fewer iterations are needed to reach a given error tolerance. By default, no preconditioner is used. callback : function User-supplied function to call after each iteration. It is called as `callback(args)`, where `args` are selected by `callback_type`. callback_type : {'x', 'pr_norm', 'legacy'}, optional Callback function argument requested: - ``x``: current iterate (ndarray), called on every restart - ``pr_norm``: relative (preconditioned) residual norm (float), called on every inner iteration - ``legacy`` (default): same as ``pr_norm``, but also changes the meaning of 'maxiter' to count inner iterations instead of restart cycles. restrt : int, optional DEPRECATED - use `restart` instead. See Also -------- LinearOperator Notes ----- A preconditioner, P, is chosen such that P is close to A but easy to solve for. The preconditioner parameter required by this routine is ``M = P^-1``. The inverse should preferably not be calculated explicitly. Rather, use the following template to produce M:: # Construct a linear operator that computes P^-1 * x. import scipy.sparse.linalg as spla M_x = lambda x: spla.spsolve(P, x) M = spla.LinearOperator((n, n), M_x) Examples -------- >>> from scipy.sparse import csc_matrix >>> from scipy.sparse.linalg import gmres >>> A = csc_matrix([[3, 2, 0], [1, -1, 0], [0, 5, 1]], dtype=float) >>> b = np.array([2, 4, -1], dtype=float) >>> x, exitCode = gmres(A, b) >>> print(exitCode) # 0 indicates successful convergence 0 >>> np.allclose(A.dot(x), b) True """ # Change 'restrt' keyword to 'restart' if restrt is None: restrt = restart elif restart is not None: raise ValueError("Cannot specify both restart and restrt keywords. " "Preferably use 'restart' only.") if callback is not None and callback_type is None: # Warn about 'callback_type' semantic changes. # Probably should be removed only in far future, Scipy 2.0 or so. warnings.warn( "scipy.sparse.linalg.gmres called without specifying `callback_type`. " "The default value will be changed in a future release. " "For compatibility, specify a value for `callback_type` explicitly, e.g., " "``{name}(..., callback_type='pr_norm')``, or to retain the old behavior " "``{name}(..., callback_type='legacy')``", category=DeprecationWarning, stacklevel=3) if callback_type is None: callback_type = 'legacy' if callback_type not in ('x', 'pr_norm', 'legacy'): raise ValueError("Unknown callback_type: {!r}".format(callback_type)) if callback is None: callback_type = 'none' A, M, x, b, postprocess = make_system(A, M, x0, b) n = len(b) if maxiter is None: maxiter = n * 10 if restrt is None: restrt = 20 restrt = min(restrt, n) matvec = A.matvec psolve = M.matvec ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'gmresrevcom') bnrm2 = np.linalg.norm(b) Mb_nrm2 = np.linalg.norm(psolve(b)) get_residual = lambda: np.linalg.norm(matvec(x) - b) atol = _get_atol(tol, atol, bnrm2, get_residual, 'gmres') if atol == 'exit': return postprocess(x), 0 if bnrm2 == 0: return postprocess(b), 0 # Tolerance passed to GMRESREVCOM applies to the inner iteration # and deals with the left-preconditioned residual. ptol_max_factor = 1.0 ptol = Mb_nrm2 * min(ptol_max_factor, atol / bnrm2) resid = np.nan presid = np.nan ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros((6 + restrt) * n, dtype=x.dtype) work2 = _aligned_zeros((restrt + 1) * (2 * restrt + 2), dtype=x.dtype) ijob = 1 info = 0 ftflag = True iter_ = maxiter old_ijob = ijob first_pass = True resid_ready = False iter_num = 1 while True: olditer = iter_ x, iter_, presid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, restrt, work, work2, iter_, presid, info, ndx1, ndx2, ijob, ptol) if callback_type == 'x' and iter_ != olditer: callback(x) slice1 = slice(ndx1 - 1, ndx1 - 1 + n) slice2 = slice(ndx2 - 1, ndx2 - 1 + n) if (ijob == -1): # gmres success, update last residual if callback_type in ('pr_norm', 'legacy'): if resid_ready: callback(presid / bnrm2) elif callback_type == 'x': callback(x) break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1 * matvec(x) elif (ijob == 2): work[slice1] = psolve(work[slice2]) if not first_pass and old_ijob == 3: resid_ready = True first_pass = False elif (ijob == 3): work[slice2] *= sclr2 work[slice2] += sclr1 * matvec(work[slice1]) if resid_ready: if callback_type in ('pr_norm', 'legacy'): callback(presid / bnrm2) resid_ready = False iter_num = iter_num + 1 elif (ijob == 4): if ftflag: info = -1 ftflag = False resid, info = _stoptest(work[slice1], atol) # Inner loop tolerance control if info or presid > ptol: ptol_max_factor = min(1.0, 1.5 * ptol_max_factor) else: # Inner loop tolerance OK, but outer loop not. ptol_max_factor = max(1e-16, 0.25 * ptol_max_factor) if resid != 0: ptol = presid * min(ptol_max_factor, atol / resid) else: ptol = presid * ptol_max_factor old_ijob = ijob ijob = 2 if callback_type == 'legacy': # Legacy behavior if iter_num > maxiter: info = maxiter break if info >= 0 and not (resid <= atol): # info isn't set appropriately otherwise info = maxiter return postprocess(x), info
def cgs(A, b, x0=None, tol=1e-5, maxiter=None, M=None, callback=None, atol=None): A, M, x, b, postprocess = make_system(A, M, x0, b) n = len(b) if maxiter is None: maxiter = n * 10 matvec = A.matvec psolve = M.matvec ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'cgsrevcom') get_residual = lambda: np.linalg.norm(matvec(x) - b) atol = _get_atol(tol, atol, np.linalg.norm(b), get_residual, 'cgs') if atol == 'exit': return postprocess(x), 0 resid = atol ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros(7 * n, dtype=x.dtype) ijob = 1 info = 0 ftflag = True iter_ = maxiter while True: olditer = iter_ x, iter_, resid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, work, iter_, resid, info, ndx1, ndx2, ijob) if callback is not None and iter_ > olditer: callback(x) slice1 = slice(ndx1 - 1, ndx1 - 1 + n) slice2 = slice(ndx2 - 1, ndx2 - 1 + n) if (ijob == -1): if callback is not None: callback(x) break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1 * matvec(work[slice1]) elif (ijob == 2): work[slice1] = psolve(work[slice2]) elif (ijob == 3): work[slice2] *= sclr2 work[slice2] += sclr1 * matvec(x) elif (ijob == 4): if ftflag: info = -1 ftflag = False resid, info = _stoptest(work[slice1], atol) if info == 1 and iter_ > 1: # recompute residual and recheck, to avoid # accumulating rounding error work[slice1] = b - matvec(x) resid, info = _stoptest(work[slice1], atol) ijob = 2 if info == -10: # termination due to breakdown: check for convergence resid, ok = _stoptest(b - matvec(x), atol) if ok: info = 0 if info > 0 and iter_ == maxiter and not (resid <= atol): # info isn't set appropriately otherwise info = iter_ return postprocess(x), info
def bicg(A, b, x0=None, tol=1e-5, maxiter=None, M=None, callback=None, atol=None): A, M, x, b, postprocess = make_system(A, M, x0, b) n = len(b) if maxiter is None: maxiter = n * 10 matvec, rmatvec = A.matvec, A.rmatvec psolve, rpsolve = M.matvec, M.rmatvec ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'bicgrevcom') get_residual = lambda: np.linalg.norm(matvec(x) - b) atol = _get_atol(tol, atol, np.linalg.norm(b), get_residual, 'bicg') if atol == 'exit': return postprocess(x), 0 resid = atol ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros(6 * n, dtype=x.dtype) ijob = 1 info = 0 ftflag = True iter_ = maxiter while True: olditer = iter_ x, iter_, resid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, work, iter_, resid, info, ndx1, ndx2, ijob) if callback is not None and iter_ > olditer: callback(x) slice1 = slice(ndx1 - 1, ndx1 - 1 + n) slice2 = slice(ndx2 - 1, ndx2 - 1 + n) if (ijob == -1): if callback is not None: callback(x) break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1 * matvec(work[slice1]) elif (ijob == 2): work[slice2] *= sclr2 work[slice2] += sclr1 * rmatvec(work[slice1]) elif (ijob == 3): work[slice1] = psolve(work[slice2]) elif (ijob == 4): work[slice1] = rpsolve(work[slice2]) elif (ijob == 5): work[slice2] *= sclr2 work[slice2] += sclr1 * matvec(x) elif (ijob == 6): if ftflag: info = -1 ftflag = False resid, info = _stoptest(work[slice1], atol) ijob = 2 if info > 0 and iter_ == maxiter and not (resid <= atol): # info isn't set appropriately otherwise info = iter_ return postprocess(x), info
def qmr(A, b, x0=None, tol=1e-5, maxiter=None, xtype=None, M1=None, M2=None, callback=None): """Use Quasi-Minimal Residual iteration to solve A x = b Parameters ---------- A : {sparse matrix, dense matrix, LinearOperator} The real-valued N-by-N matrix of the linear system. It is required that the linear operator can produce ``Ax`` and ``A^T x``. b : {array, matrix} Right hand side of the linear system. Has shape (N,) or (N,1). Returns ------- x : {array, matrix} The converged solution. info : integer Provides convergence information: 0 : successful exit >0 : convergence to tolerance not achieved, number of iterations <0 : illegal input or breakdown Other Parameters ---------------- x0 : {array, matrix} Starting guess for the solution. tol : float Tolerance to achieve. The algorithm terminates when either the relative or the absolute residual is below `tol`. maxiter : integer Maximum number of iterations. Iteration will stop after maxiter steps even if the specified tolerance has not been achieved. M1 : {sparse matrix, dense matrix, LinearOperator} Left preconditioner for A. M2 : {sparse matrix, dense matrix, LinearOperator} Right preconditioner for A. Used together with the left preconditioner M1. The matrix M1*A*M2 should have better conditioned than A alone. callback : function User-supplied function to call after each iteration. It is called as callback(xk), where xk is the current solution vector. xtype : {'f','d','F','D'} This parameter is DEPRECATED -- avoid using it. The type of the result. If None, then it will be determined from A.dtype.char and b. If A does not have a typecode method then it will compute A.matvec(x0) to get a typecode. To save the extra computation when A does not have a typecode attribute use xtype=0 for the same type as b or use xtype='f','d','F',or 'D'. This parameter has been superseded by LinearOperator. See Also -------- LinearOperator """ A_ = A A,M,x,b,postprocess = make_system(A,None,x0,b,xtype) if M1 is None and M2 is None: if hasattr(A_,'psolve'): def left_psolve(b): return A_.psolve(b,'left') def right_psolve(b): return A_.psolve(b,'right') def left_rpsolve(b): return A_.rpsolve(b,'left') def right_rpsolve(b): return A_.rpsolve(b,'right') M1 = LinearOperator(A.shape, matvec=left_psolve, rmatvec=left_rpsolve) M2 = LinearOperator(A.shape, matvec=right_psolve, rmatvec=right_rpsolve) else: def id(b): return b M1 = LinearOperator(A.shape, matvec=id, rmatvec=id) M2 = LinearOperator(A.shape, matvec=id, rmatvec=id) n = len(b) if maxiter is None: maxiter = n*10 ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'qmrrevcom') stoptest = getattr(_iterative, ltr + 'stoptest2') resid = tol ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros(11*n,x.dtype) ijob = 1 info = 0 ftflag = True bnrm2 = -1.0 iter_ = maxiter while True: olditer = iter_ x, iter_, resid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, work, iter_, resid, info, ndx1, ndx2, ijob) if callback is not None and iter_ > olditer: callback(x) slice1 = slice(ndx1-1, ndx1-1+n) slice2 = slice(ndx2-1, ndx2-1+n) if (ijob == -1): if callback is not None: callback(x) break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1*A.matvec(work[slice1]) elif (ijob == 2): work[slice2] *= sclr2 work[slice2] += sclr1*A.rmatvec(work[slice1]) elif (ijob == 3): work[slice1] = M1.matvec(work[slice2]) elif (ijob == 4): work[slice1] = M2.matvec(work[slice2]) elif (ijob == 5): work[slice1] = M1.rmatvec(work[slice2]) elif (ijob == 6): work[slice1] = M2.rmatvec(work[slice2]) elif (ijob == 7): work[slice2] *= sclr2 work[slice2] += sclr1*A.matvec(x) elif (ijob == 8): if ftflag: info = -1 ftflag = False bnrm2, resid, info = stoptest(work[slice1], b, bnrm2, tol, info) ijob = 2 if info > 0 and iter_ == maxiter and resid > tol: # info isn't set appropriately otherwise info = iter_ return postprocess(x), info
def gmres(A, b, x0=None, tol=1e-5, restart=None, maxiter=None, xtype=None, M=None, callback=None, restrt=None): """ Use Generalized Minimal RESidual iteration to solve A x = b. Parameters ---------- A : {sparse matrix, dense matrix, LinearOperator} The real or complex N-by-N matrix of the linear system. b : {array, matrix} Right hand side of the linear system. Has shape (N,) or (N,1). Returns ------- x : {array, matrix} The converged solution. info : int Provides convergence information: * 0 : successful exit * >0 : convergence to tolerance not achieved, number of iterations * <0 : illegal input or breakdown Other parameters ---------------- x0 : {array, matrix} Starting guess for the solution (a vector of zeros by default). tol : float Tolerance to achieve. The algorithm terminates when either the relative or the absolute residual is below `tol`. restart : int, optional Number of iterations between restarts. Larger values increase iteration cost, but may be necessary for convergence. Default is 20. maxiter : int, optional Maximum number of iterations (restart cycles). Iteration will stop after maxiter steps even if the specified tolerance has not been achieved. xtype : {'f','d','F','D'} This parameter is DEPRECATED --- avoid using it. The type of the result. If None, then it will be determined from A.dtype.char and b. If A does not have a typecode method then it will compute A.matvec(x0) to get a typecode. To save the extra computation when A does not have a typecode attribute use xtype=0 for the same type as b or use xtype='f','d','F',or 'D'. This parameter has been superseded by LinearOperator. M : {sparse matrix, dense matrix, LinearOperator} Inverse of the preconditioner of A. M should approximate the inverse of A and be easy to solve for (see Notes). Effective preconditioning dramatically improves the rate of convergence, which implies that fewer iterations are needed to reach a given error tolerance. By default, no preconditioner is used. callback : function User-supplied function to call after each iteration. It is called as callback(rk), where rk is the current residual vector. restrt : int, optional DEPRECATED - use `restart` instead. See Also -------- LinearOperator Notes ----- A preconditioner, P, is chosen such that P is close to A but easy to solve for. The preconditioner parameter required by this routine is ``M = P^-1``. The inverse should preferably not be calculated explicitly. Rather, use the following template to produce M:: # Construct a linear operator that computes P^-1 * x. import scipy.sparse.linalg as spla M_x = lambda x: spla.spsolve(P, x) M = spla.LinearOperator((n, n), M_x) """ # Change 'restrt' keyword to 'restart' if restrt is None: restrt = restart elif restart is not None: raise ValueError("Cannot specify both restart and restrt keywords. " "Preferably use 'restart' only.") A,M,x,b,postprocess = make_system(A,M,x0,b,xtype) n = len(b) if maxiter is None: maxiter = n*10 if restrt is None: restrt = 20 restrt = min(restrt, n) matvec = A.matvec psolve = M.matvec ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'gmresrevcom') stoptest = getattr(_iterative, ltr + 'stoptest2') resid = tol ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros((6+restrt)*n,dtype=x.dtype) work2 = _aligned_zeros((restrt+1)*(2*restrt+2),dtype=x.dtype) ijob = 1 info = 0 ftflag = True bnrm2 = -1.0 iter_ = maxiter old_ijob = ijob first_pass = True resid_ready = False iter_num = 1 while True: olditer = iter_ x, iter_, resid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, restrt, work, work2, iter_, resid, info, ndx1, ndx2, ijob) # if callback is not None and iter_ > olditer: # callback(x) slice1 = slice(ndx1-1, ndx1-1+n) slice2 = slice(ndx2-1, ndx2-1+n) if (ijob == -1): # gmres success, update last residual if resid_ready and callback is not None: callback(resid) resid_ready = False break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1*matvec(x) elif (ijob == 2): work[slice1] = psolve(work[slice2]) if not first_pass and old_ijob == 3: resid_ready = True first_pass = False elif (ijob == 3): work[slice2] *= sclr2 work[slice2] += sclr1*matvec(work[slice1]) if resid_ready and callback is not None: callback(resid) resid_ready = False iter_num = iter_num+1 elif (ijob == 4): if ftflag: info = -1 ftflag = False bnrm2, resid, info = stoptest(work[slice1], b, bnrm2, tol, info) old_ijob = ijob ijob = 2 if iter_num > maxiter: break if info >= 0 and resid > tol: # info isn't set appropriately otherwise info = maxiter return postprocess(x), info
def __init__(self, n, k, tp, matvec, mode=1, M_matvec=None, Minv_matvec=None, sigma=None, ncv=None, v0=None, maxiter=None, which="LM", tol=0): # The following modes are supported: # mode = 1: # Solve the standard eigenvalue problem: # A*x = lambda*x : # A - symmetric # Arguments should be # matvec = left multiplication by A # M_matvec = None [not used] # Minv_matvec = None [not used] # # mode = 2: # Solve the general eigenvalue problem: # A*x = lambda*M*x # A - symmetric # M - symmetric positive definite # Arguments should be # matvec = left multiplication by A # M_matvec = left multiplication by M # Minv_matvec = left multiplication by M^-1 # # mode = 3: # Solve the general eigenvalue problem in shift-invert mode: # A*x = lambda*M*x # A - symmetric # M - symmetric positive semi-definite # Arguments should be # matvec = None [not used] # M_matvec = left multiplication by M # or None, if M is the identity # Minv_matvec = left multiplication by [A-sigma*M]^-1 # # mode = 4: # Solve the general eigenvalue problem in Buckling mode: # A*x = lambda*AG*x # A - symmetric positive semi-definite # AG - symmetric indefinite # Arguments should be # matvec = left multiplication by A # M_matvec = None [not used] # Minv_matvec = left multiplication by [A-sigma*AG]^-1 # # mode = 5: # Solve the general eigenvalue problem in Cayley-transformed mode: # A*x = lambda*M*x # A - symmetric # M - symmetric positive semi-definite # Arguments should be # matvec = left multiplication by A # M_matvec = left multiplication by M # or None, if M is the identity # Minv_matvec = left multiplication by [A-sigma*M]^-1 if mode == 1: if matvec is None: raise ValueError("matvec must be specified for mode=1") if M_matvec is not None: raise ValueError("M_matvec cannot be specified for mode=1") if Minv_matvec is not None: raise ValueError("Minv_matvec cannot be specified for mode=1") self.OP = matvec self.B = lambda x: x self.bmat = "I" elif mode == 2: if matvec is None: raise ValueError("matvec must be specified for mode=2") if M_matvec is None: raise ValueError("M_matvec must be specified for mode=2") if Minv_matvec is None: raise ValueError("Minv_matvec must be specified for mode=2") self.OP = lambda x: Minv_matvec(matvec(x)) self.OPa = Minv_matvec self.OPb = matvec self.B = M_matvec self.bmat = "G" elif mode == 3: if matvec is not None: raise ValueError("matvec must not be specified for mode=3") if Minv_matvec is None: raise ValueError("Minv_matvec must be specified for mode=3") if M_matvec is None: self.OP = Minv_matvec self.OPa = Minv_matvec self.B = lambda x: x self.bmat = "I" else: self.OP = lambda x: Minv_matvec(M_matvec(x)) self.OPa = Minv_matvec self.B = M_matvec self.bmat = "G" elif mode == 4: if matvec is None: raise ValueError("matvec must be specified for mode=4") if M_matvec is not None: raise ValueError("M_matvec must not be specified for mode=4") if Minv_matvec is None: raise ValueError("Minv_matvec must be specified for mode=4") self.OPa = Minv_matvec self.OP = lambda x: self.OPa(matvec(x)) self.B = matvec self.bmat = "G" elif mode == 5: if matvec is None: raise ValueError("matvec must be specified for mode=5") if Minv_matvec is None: raise ValueError("Minv_matvec must be specified for mode=5") self.OPa = Minv_matvec self.A_matvec = matvec if M_matvec is None: self.OP = lambda x: Minv_matvec(matvec(x) + sigma * x) self.B = lambda x: x self.bmat = "I" else: self.OP = lambda x: Minv_matvec(matvec(x) + sigma * M_matvec(x)) self.B = M_matvec self.bmat = "G" else: raise ValueError("mode=%i not implemented" % mode) if which not in _SEUPD_WHICH: raise ValueError("which must be one of %s" % " ".join(_SEUPD_WHICH)) if k >= n: raise ValueError("k must be less than ndim(A), k=%d" % k) _ArpackParams.__init__(self, n, k, tp, mode, sigma, ncv, v0, maxiter, which, tol) if self.ncv > n or self.ncv <= k: raise ValueError("ncv must be k<ncv<=n, ncv=%s" % self.ncv) # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 self.workd = _aligned_zeros(3 * n, self.tp) self.workl = _aligned_zeros(self.ncv * (self.ncv + 8), self.tp) ltr = _type_conv[self.tp] if ltr not in ["s", "d"]: raise ValueError("Input matrix is not real-valued.") self._arpack_solver = _arpack.__dict__[ltr + "saupd"] self._arpack_extract = _arpack.__dict__[ltr + "seupd"] self.iterate_infodict = _SAUPD_ERRORS[ltr] self.extract_infodict = _SEUPD_ERRORS[ltr] self.ipntr = np.zeros(11, "int")
def gmres(A, b, x0=None, tol=1e-5, restart=None, maxiter=None, M=None, callback=None, restrt=None, atol=None): """ Use Generalized Minimal RESidual iteration to solve ``Ax = b``. Parameters ---------- A : {sparse matrix, dense matrix, LinearOperator} The real or complex N-by-N matrix of the linear system. b : {array, matrix} Right hand side of the linear system. Has shape (N,) or (N,1). Returns ------- x : {array, matrix} The converged solution. info : int Provides convergence information: * 0 : successful exit * >0 : convergence to tolerance not achieved, number of iterations * <0 : illegal input or breakdown Other parameters ---------------- x0 : {array, matrix} Starting guess for the solution (a vector of zeros by default). tol, atol : float, optional Tolerances for convergence, ``norm(residual) <= max(tol*norm(b), atol)``. The default for ``atol`` is ``'legacy'``, which emulates a different legacy behavior. .. warning:: The default value for `atol` will be changed in a future release. For future compatibility, specify `atol` explicitly. restart : int, optional Number of iterations between restarts. Larger values increase iteration cost, but may be necessary for convergence. Default is 20. maxiter : int, optional Maximum number of iterations (restart cycles). Iteration will stop after maxiter steps even if the specified tolerance has not been achieved. M : {sparse matrix, dense matrix, LinearOperator} Inverse of the preconditioner of A. M should approximate the inverse of A and be easy to solve for (see Notes). Effective preconditioning dramatically improves the rate of convergence, which implies that fewer iterations are needed to reach a given error tolerance. By default, no preconditioner is used. callback : function User-supplied function to call after each iteration. It is called as callback(rk), where rk is the current residual vector. restrt : int, optional DEPRECATED - use `restart` instead. See Also -------- LinearOperator Notes ----- A preconditioner, P, is chosen such that P is close to A but easy to solve for. The preconditioner parameter required by this routine is ``M = P^-1``. The inverse should preferably not be calculated explicitly. Rather, use the following template to produce M:: # Construct a linear operator that computes P^-1 * x. import scipy.sparse.linalg as spla M_x = lambda x: spla.spsolve(P, x) M = spla.LinearOperator((n, n), M_x) Examples -------- >>> from scipy.sparse import csc_matrix >>> from scipy.sparse.linalg import gmres >>> A = csc_matrix([[3, 2, 0], [1, -1, 0], [0, 5, 1]], dtype=float) >>> b = np.array([2, 4, -1], dtype=float) >>> x, exitCode = gmres(A, b) >>> print(exitCode) # 0 indicates successful convergence 0 >>> np.allclose(A.dot(x), b) True """ # Change 'restrt' keyword to 'restart' if restrt is None: restrt = restart elif restart is not None: raise ValueError("Cannot specify both restart and restrt keywords. " "Preferably use 'restart' only.") A, M, x, b,postprocess = make_system(A, M, x0, b) n = len(b) if maxiter is None: maxiter = n*10 if restrt is None: restrt = 20 restrt = min(restrt, n) matvec = A.matvec psolve = M.matvec ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'gmresrevcom') bnrm2 = np.linalg.norm(b) Mb_nrm2 = np.linalg.norm(psolve(b)) get_residual = lambda: np.linalg.norm(matvec(x) - b) atol = _get_atol(tol, atol, bnrm2, get_residual, 'gmres') if atol == 'exit': return postprocess(x), 0 if bnrm2 == 0: return postprocess(b), 0 # Tolerance passed to GMRESREVCOM applies to the inner iteration # and deals with the left-preconditioned residual. ptol_max_factor = 1.0 ptol = Mb_nrm2 * min(ptol_max_factor, atol / bnrm2) resid = np.nan presid = np.nan ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros((6+restrt)*n,dtype=x.dtype) work2 = _aligned_zeros((restrt+1)*(2*restrt+2),dtype=x.dtype) ijob = 1 info = 0 ftflag = True iter_ = maxiter old_ijob = ijob first_pass = True resid_ready = False iter_num = 1 while True: x, iter_, presid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, restrt, work, work2, iter_, presid, info, ndx1, ndx2, ijob, ptol) slice1 = slice(ndx1-1, ndx1-1+n) slice2 = slice(ndx2-1, ndx2-1+n) if (ijob == -1): # gmres success, update last residual if resid_ready and callback is not None: callback(presid / bnrm2) resid_ready = False break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1*matvec(x) elif (ijob == 2): work[slice1] = psolve(work[slice2]) if not first_pass and old_ijob == 3: resid_ready = True first_pass = False elif (ijob == 3): work[slice2] *= sclr2 work[slice2] += sclr1*matvec(work[slice1]) if resid_ready and callback is not None: callback(presid / bnrm2) resid_ready = False iter_num = iter_num+1 elif (ijob == 4): if ftflag: info = -1 ftflag = False resid, info = _stoptest(work[slice1], atol) # Inner loop tolerance control if info or presid > ptol: ptol_max_factor = min(1.0, 1.5 * ptol_max_factor) else: # Inner loop tolerance OK, but outer loop not. ptol_max_factor = max(1e-16, 0.25 * ptol_max_factor) if resid != 0: ptol = presid * min(ptol_max_factor, atol / resid) else: ptol = presid * ptol_max_factor old_ijob = ijob ijob = 2 if iter_num > maxiter: info = maxiter break if info >= 0 and not (resid <= atol): # info isn't set appropriately otherwise info = maxiter return postprocess(x), info
def qmr(A, b, x0=None, tol=1e-5, maxiter=None, xtype=None, M1=None, M2=None, callback=None): """Use Quasi-Minimal Residual iteration to solve ``Ax = b``. Parameters ---------- A : {sparse matrix, dense matrix, LinearOperator} The real-valued N-by-N matrix of the linear system. It is required that the linear operator can produce ``Ax`` and ``A^T x``. b : {array, matrix} Right hand side of the linear system. Has shape (N,) or (N,1). Returns ------- x : {array, matrix} The converged solution. info : integer Provides convergence information: 0 : successful exit >0 : convergence to tolerance not achieved, number of iterations <0 : illegal input or breakdown Other Parameters ---------------- x0 : {array, matrix} Starting guess for the solution. tol : float Tolerance to achieve. The algorithm terminates when either the relative or the absolute residual is below `tol`. maxiter : integer Maximum number of iterations. Iteration will stop after maxiter steps even if the specified tolerance has not been achieved. M1 : {sparse matrix, dense matrix, LinearOperator} Left preconditioner for A. M2 : {sparse matrix, dense matrix, LinearOperator} Right preconditioner for A. Used together with the left preconditioner M1. The matrix M1*A*M2 should have better conditioned than A alone. callback : function User-supplied function to call after each iteration. It is called as callback(xk), where xk is the current solution vector. xtype : {'f','d','F','D'} This parameter is DEPRECATED -- avoid using it. The type of the result. If None, then it will be determined from A.dtype.char and b. If A does not have a typecode method then it will compute A.matvec(x0) to get a typecode. To save the extra computation when A does not have a typecode attribute use xtype=0 for the same type as b or use xtype='f','d','F',or 'D'. This parameter has been superseded by LinearOperator. See Also -------- LinearOperator Examples -------- >>> from scipy.sparse import csc_matrix >>> from scipy.sparse.linalg import qmr >>> A = csc_matrix([[3, 2, 0], [1, -1, 0], [0, 5, 1]], dtype=float) >>> b = np.array([2, 4, -1], dtype=float) >>> x, exitCode = qmr(A, b) >>> print(exitCode) # 0 indicates successful convergence 0 >>> np.allclose(A.dot(x), b) True """ A_ = A A,M,x,b,postprocess = make_system(A,None,x0,b,xtype) if M1 is None and M2 is None: if hasattr(A_,'psolve'): def left_psolve(b): return A_.psolve(b,'left') def right_psolve(b): return A_.psolve(b,'right') def left_rpsolve(b): return A_.rpsolve(b,'left') def right_rpsolve(b): return A_.rpsolve(b,'right') M1 = LinearOperator(A.shape, matvec=left_psolve, rmatvec=left_rpsolve) M2 = LinearOperator(A.shape, matvec=right_psolve, rmatvec=right_rpsolve) else: def id(b): return b M1 = LinearOperator(A.shape, matvec=id, rmatvec=id) M2 = LinearOperator(A.shape, matvec=id, rmatvec=id) n = len(b) if maxiter is None: maxiter = n*10 ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'qmrrevcom') stoptest = getattr(_iterative, ltr + 'stoptest2') resid = tol ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros(11*n,x.dtype) ijob = 1 info = 0 ftflag = True bnrm2 = -1.0 iter_ = maxiter while True: olditer = iter_ x, iter_, resid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, work, iter_, resid, info, ndx1, ndx2, ijob) if callback is not None and iter_ > olditer: callback(x) slice1 = slice(ndx1-1, ndx1-1+n) slice2 = slice(ndx2-1, ndx2-1+n) if (ijob == -1): if callback is not None: callback(x) break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1*A.matvec(work[slice1]) elif (ijob == 2): work[slice2] *= sclr2 work[slice2] += sclr1*A.rmatvec(work[slice1]) elif (ijob == 3): work[slice1] = M1.matvec(work[slice2]) elif (ijob == 4): work[slice1] = M2.matvec(work[slice2]) elif (ijob == 5): work[slice1] = M1.rmatvec(work[slice2]) elif (ijob == 6): work[slice1] = M2.rmatvec(work[slice2]) elif (ijob == 7): work[slice2] *= sclr2 work[slice2] += sclr1*A.matvec(x) elif (ijob == 8): if ftflag: info = -1 ftflag = False bnrm2, resid, info = stoptest(work[slice1], b, bnrm2, tol, info) ijob = 2 if info > 0 and iter_ == maxiter and resid > tol: # info isn't set appropriately otherwise info = iter_ return postprocess(x), info
def gmres(A, b, x0=None, tol=1e-5, restart=None, maxiter=None, xtype=None, M=None, callback=None, restrt=None): """ Use Generalized Minimal RESidual iteration to solve ``Ax = b``. Parameters ---------- A : {sparse matrix, dense matrix, LinearOperator} The real or complex N-by-N matrix of the linear system. b : {array, matrix} Right hand side of the linear system. Has shape (N,) or (N,1). Returns ------- x : {array, matrix} The converged solution. info : int Provides convergence information: * 0 : successful exit * >0 : convergence to tolerance not achieved, number of iterations * <0 : illegal input or breakdown Other parameters ---------------- x0 : {array, matrix} Starting guess for the solution (a vector of zeros by default). tol : float Tolerance to achieve. The algorithm terminates when either the relative or the absolute residual is below `tol`. restart : int, optional Number of iterations between restarts. Larger values increase iteration cost, but may be necessary for convergence. Default is 20. maxiter : int, optional Maximum number of iterations (restart cycles). Iteration will stop after maxiter steps even if the specified tolerance has not been achieved. xtype : {'f','d','F','D'} This parameter is DEPRECATED --- avoid using it. The type of the result. If None, then it will be determined from A.dtype.char and b. If A does not have a typecode method then it will compute A.matvec(x0) to get a typecode. To save the extra computation when A does not have a typecode attribute use xtype=0 for the same type as b or use xtype='f','d','F',or 'D'. This parameter has been superseded by LinearOperator. M : {sparse matrix, dense matrix, LinearOperator} Inverse of the preconditioner of A. M should approximate the inverse of A and be easy to solve for (see Notes). Effective preconditioning dramatically improves the rate of convergence, which implies that fewer iterations are needed to reach a given error tolerance. By default, no preconditioner is used. callback : function User-supplied function to call after each iteration. It is called as callback(rk), where rk is the current residual vector. restrt : int, optional DEPRECATED - use `restart` instead. See Also -------- LinearOperator Notes ----- A preconditioner, P, is chosen such that P is close to A but easy to solve for. The preconditioner parameter required by this routine is ``M = P^-1``. The inverse should preferably not be calculated explicitly. Rather, use the following template to produce M:: # Construct a linear operator that computes P^-1 * x. import scipy.sparse.linalg as spla M_x = lambda x: spla.spsolve(P, x) M = spla.LinearOperator((n, n), M_x) Examples -------- >>> from scipy.sparse import csc_matrix >>> from scipy.sparse.linalg import gmres >>> A = csc_matrix([[3, 2, 0], [1, -1, 0], [0, 5, 1]], dtype=float) >>> b = np.array([2, 4, -1], dtype=float) >>> x, exitCode = gmres(A, b) >>> print(exitCode) # 0 indicates successful convergence 0 >>> np.allclose(A.dot(x), b) True """ # Change 'restrt' keyword to 'restart' if restrt is None: restrt = restart elif restart is not None: raise ValueError("Cannot specify both restart and restrt keywords. " "Preferably use 'restart' only.") A,M,x,b,postprocess = make_system(A,M,x0,b,xtype) n = len(b) if maxiter is None: maxiter = n*10 if restrt is None: restrt = 20 restrt = min(restrt, n) matvec = A.matvec psolve = M.matvec ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'gmresrevcom') stoptest = getattr(_iterative, ltr + 'stoptest2') resid = tol ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros((6+restrt)*n,dtype=x.dtype) work2 = _aligned_zeros((restrt+1)*(2*restrt+2),dtype=x.dtype) ijob = 1 info = 0 ftflag = True bnrm2 = -1.0 iter_ = maxiter old_ijob = ijob first_pass = True resid_ready = False iter_num = 1 while True: olditer = iter_ x, iter_, resid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, restrt, work, work2, iter_, resid, info, ndx1, ndx2, ijob) # if callback is not None and iter_ > olditer: # callback(x) slice1 = slice(ndx1-1, ndx1-1+n) slice2 = slice(ndx2-1, ndx2-1+n) if (ijob == -1): # gmres success, update last residual if resid_ready and callback is not None: callback(resid) resid_ready = False break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1*matvec(x) elif (ijob == 2): work[slice1] = psolve(work[slice2]) if not first_pass and old_ijob == 3: resid_ready = True first_pass = False elif (ijob == 3): work[slice2] *= sclr2 work[slice2] += sclr1*matvec(work[slice1]) if resid_ready and callback is not None: callback(resid) resid_ready = False iter_num = iter_num+1 elif (ijob == 4): if ftflag: info = -1 ftflag = False bnrm2, resid, info = stoptest(work[slice1], b, bnrm2, tol, info) old_ijob = ijob ijob = 2 if iter_num > maxiter: break if info >= 0 and resid > tol: # info isn't set appropriately otherwise info = maxiter return postprocess(x), info
def bicg(A, b, x0=None, tol=1e-5, maxiter=None, xtype=None, M=None, callback=None): A, M, x, b, postprocess = make_system(A, M, x0, b, xtype) n = len(b) if maxiter is None: maxiter = n * 10 matvec, rmatvec = A.matvec, A.rmatvec psolve, rpsolve = M.matvec, M.rmatvec ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'bicgrevcom') stoptest = getattr(_iterative, ltr + 'stoptest2') resid = tol ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros(6 * n, dtype=x.dtype) ijob = 1 info = 0 ftflag = True bnrm2 = -1.0 iter_ = maxiter while True: olditer = iter_ x, iter_, resid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, work, iter_, resid, info, ndx1, ndx2, ijob) if callback is not None and iter_ > olditer: callback(x) slice1 = slice(ndx1 - 1, ndx1 - 1 + n) slice2 = slice(ndx2 - 1, ndx2 - 1 + n) if (ijob == -1): if callback is not None: callback(x) break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1 * matvec(work[slice1]) elif (ijob == 2): work[slice2] *= sclr2 work[slice2] += sclr1 * rmatvec(work[slice1]) elif (ijob == 3): work[slice1] = psolve(work[slice2]) elif (ijob == 4): work[slice1] = rpsolve(work[slice2]) elif (ijob == 5): work[slice2] *= sclr2 work[slice2] += sclr1 * matvec(x) elif (ijob == 6): if ftflag: info = -1 ftflag = False bnrm2, resid, info = stoptest(work[slice1], b, bnrm2, tol, info) ijob = 2 if info > 0 and iter_ == maxiter and resid > tol: # info isn't set appropriately otherwise info = iter_ return postprocess(x), info
def presid_gmres(A, b, verbose, x0=None, tol=1e-05, restart=None, maxiter=None, M=None): callback = gmres_counter(verbose) A, M, x, b, postprocess = make_system(A, M, x0, b) n = len(b) if maxiter is None: maxiter = n * 10 if restart is None: restart = 20 restart = min(restart, n) matvec = A.matvec psolve = M.matvec ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'gmresrevcom') bnrm2 = np.linalg.norm(b) Mb_nrm2 = np.linalg.norm(psolve(b)) get_residual = lambda: np.linalg.norm(matvec(x) - b) atol = tol if bnrm2 == 0: return postprocess(b), 0 # Tolerance passed to GMRESREVCOM applies to the inner iteration # and deals with the left-preconditioned residual. ptol_max_factor = 1.0 ptol = Mb_nrm2 * min(ptol_max_factor, atol / bnrm2) resid = np.nan presid = np.nan ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros((6 + restart) * n, dtype=x.dtype) work2 = _aligned_zeros((restart + 1) * (2 * restart + 2), dtype=x.dtype) ijob = 1 info = 0 ftflag = True iter_ = maxiter old_ijob = ijob first_pass = True resid_ready = False iter_num = 1 while True: ### begin my modifications if presid / bnrm2 < atol: resid = presid / bnrm2 info = 1 if info: ptol = 10000 ### end my modifications x, iter_, presid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, restart, work, work2, iter_, presid, info, ndx1, ndx2, ijob, ptol) slice1 = slice(ndx1 - 1, ndx1 - 1 + n) slice2 = slice(ndx2 - 1, ndx2 - 1 + n) if (ijob == -1): # gmres success, update last residual if resid_ready and callback is not None: callback(presid / bnrm2) resid_ready = False break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1 * matvec(x) elif (ijob == 2): work[slice1] = psolve(work[slice2]) if not first_pass and old_ijob == 3: resid_ready = True first_pass = False elif (ijob == 3): work[slice2] *= sclr2 work[slice2] += sclr1 * matvec(work[slice1]) if resid_ready and callback is not None: callback(presid / bnrm2) resid_ready = False iter_num = iter_num + 1 elif (ijob == 4): if ftflag: info = -1 ftflag = False resid, info = _stoptest(work[slice1], atol) # Inner loop tolerance control if info or presid > ptol: ptol_max_factor = min(1.0, 1.5 * ptol_max_factor) else: # Inner loop tolerance OK, but outer loop not. ptol_max_factor = max(1e-16, 0.25 * ptol_max_factor) if resid != 0: ptol = presid * min(ptol_max_factor, atol / resid) else: ptol = presid * ptol_max_factor old_ijob = ijob ijob = 2 if iter_num > maxiter: info = maxiter break if info >= 0 and not (resid <= atol): # info isn't set appropriately otherwise info = maxiter return postprocess(x), info, mydict['resnorms']
def qmr(A, b, x0=None, tol=1e-5, maxiter=None, M1=None, M2=None, callback=None, atol=None): """Use Quasi-Minimal Residual iteration to solve ``Ax = b``. Parameters ---------- A : {sparse matrix, dense matrix, LinearOperator} The real-valued N-by-N matrix of the linear system. Alternatively, ``A`` can be a linear operator which can produce ``Ax`` and ``A^T x`` using, e.g., ``scipy.sparse.linalg.LinearOperator``. b : {array, matrix} Right hand side of the linear system. Has shape (N,) or (N,1). Returns ------- x : {array, matrix} The converged solution. info : integer Provides convergence information: 0 : successful exit >0 : convergence to tolerance not achieved, number of iterations <0 : illegal input or breakdown Other Parameters ---------------- x0 : {array, matrix} Starting guess for the solution. tol, atol : float, optional Tolerances for convergence, ``norm(residual) <= max(tol*norm(b), atol)``. The default for ``atol`` is ``'legacy'``, which emulates a different legacy behavior. .. warning:: The default value for `atol` will be changed in a future release. For future compatibility, specify `atol` explicitly. maxiter : integer Maximum number of iterations. Iteration will stop after maxiter steps even if the specified tolerance has not been achieved. M1 : {sparse matrix, dense matrix, LinearOperator} Left preconditioner for A. M2 : {sparse matrix, dense matrix, LinearOperator} Right preconditioner for A. Used together with the left preconditioner M1. The matrix M1*A*M2 should have better conditioned than A alone. callback : function User-supplied function to call after each iteration. It is called as callback(xk), where xk is the current solution vector. See Also -------- LinearOperator Examples -------- >>> from scipy.sparse import csc_matrix >>> from scipy.sparse.linalg import qmr >>> A = csc_matrix([[3, 2, 0], [1, -1, 0], [0, 5, 1]], dtype=float) >>> b = np.array([2, 4, -1], dtype=float) >>> x, exitCode = qmr(A, b) >>> print(exitCode) # 0 indicates successful convergence 0 >>> np.allclose(A.dot(x), b) True """ A_ = A A, M, x, b, postprocess = make_system(A, None, x0, b) if M1 is None and M2 is None: if hasattr(A_, 'psolve'): def left_psolve(b): return A_.psolve(b, 'left') def right_psolve(b): return A_.psolve(b, 'right') def left_rpsolve(b): return A_.rpsolve(b, 'left') def right_rpsolve(b): return A_.rpsolve(b, 'right') M1 = LinearOperator(A.shape, matvec=left_psolve, rmatvec=left_rpsolve) M2 = LinearOperator(A.shape, matvec=right_psolve, rmatvec=right_rpsolve) else: def id(b): return b M1 = LinearOperator(A.shape, matvec=id, rmatvec=id) M2 = LinearOperator(A.shape, matvec=id, rmatvec=id) n = len(b) if maxiter is None: maxiter = n * 10 ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'qmrrevcom') get_residual = lambda: np.linalg.norm(A.matvec(x) - b) atol = _get_atol(tol, atol, np.linalg.norm(b), get_residual, 'qmr') if atol == 'exit': return postprocess(x), 0 resid = atol ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros(11 * n, x.dtype) ijob = 1 info = 0 ftflag = True iter_ = maxiter while True: olditer = iter_ x, iter_, resid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, work, iter_, resid, info, ndx1, ndx2, ijob) if callback is not None and iter_ > olditer: callback(x) slice1 = slice(ndx1 - 1, ndx1 - 1 + n) slice2 = slice(ndx2 - 1, ndx2 - 1 + n) if (ijob == -1): if callback is not None: callback(x) break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1 * A.matvec(work[slice1]) elif (ijob == 2): work[slice2] *= sclr2 work[slice2] += sclr1 * A.rmatvec(work[slice1]) elif (ijob == 3): work[slice1] = M1.matvec(work[slice2]) elif (ijob == 4): work[slice1] = M2.matvec(work[slice2]) elif (ijob == 5): work[slice1] = M1.rmatvec(work[slice2]) elif (ijob == 6): work[slice1] = M2.rmatvec(work[slice2]) elif (ijob == 7): work[slice2] *= sclr2 work[slice2] += sclr1 * A.matvec(x) elif (ijob == 8): if ftflag: info = -1 ftflag = False resid, info = _stoptest(work[slice1], atol) ijob = 2 if info > 0 and iter_ == maxiter and not (resid <= atol): # info isn't set appropriately otherwise info = iter_ return postprocess(x), info
def qmr(A, b, x0=None, tol=1e-5, maxiter=None, M1=None, M2=None, callback=None, atol=None): """Use Quasi-Minimal Residual iteration to solve ``Ax = b``. Parameters ---------- A : {sparse matrix, dense matrix, LinearOperator} The real-valued N-by-N matrix of the linear system. It is required that the linear operator can produce ``Ax`` and ``A^T x``. b : {array, matrix} Right hand side of the linear system. Has shape (N,) or (N,1). Returns ------- x : {array, matrix} The converged solution. info : integer Provides convergence information: 0 : successful exit >0 : convergence to tolerance not achieved, number of iterations <0 : illegal input or breakdown Other Parameters ---------------- x0 : {array, matrix} Starting guess for the solution. tol, atol : float, optional Tolerances for convergence, ``norm(residual) <= max(tol*norm(b), atol)``. The default for ``atol`` is ``'legacy'``, which emulates a different legacy behavior. .. warning:: The default value for `atol` will be changed in a future release. For future compatibility, specify `atol` explicitly. maxiter : integer Maximum number of iterations. Iteration will stop after maxiter steps even if the specified tolerance has not been achieved. M1 : {sparse matrix, dense matrix, LinearOperator} Left preconditioner for A. M2 : {sparse matrix, dense matrix, LinearOperator} Right preconditioner for A. Used together with the left preconditioner M1. The matrix M1*A*M2 should have better conditioned than A alone. callback : function User-supplied function to call after each iteration. It is called as callback(xk), where xk is the current solution vector. See Also -------- LinearOperator Examples -------- >>> from scipy.sparse import csc_matrix >>> from scipy.sparse.linalg import qmr >>> A = csc_matrix([[3, 2, 0], [1, -1, 0], [0, 5, 1]], dtype=float) >>> b = np.array([2, 4, -1], dtype=float) >>> x, exitCode = qmr(A, b) >>> print(exitCode) # 0 indicates successful convergence 0 >>> np.allclose(A.dot(x), b) True """ A_ = A A, M, x, b, postprocess = make_system(A, None, x0, b) if M1 is None and M2 is None: if hasattr(A_,'psolve'): def left_psolve(b): return A_.psolve(b,'left') def right_psolve(b): return A_.psolve(b,'right') def left_rpsolve(b): return A_.rpsolve(b,'left') def right_rpsolve(b): return A_.rpsolve(b,'right') M1 = LinearOperator(A.shape, matvec=left_psolve, rmatvec=left_rpsolve) M2 = LinearOperator(A.shape, matvec=right_psolve, rmatvec=right_rpsolve) else: def id(b): return b M1 = LinearOperator(A.shape, matvec=id, rmatvec=id) M2 = LinearOperator(A.shape, matvec=id, rmatvec=id) n = len(b) if maxiter is None: maxiter = n*10 ltr = _type_conv[x.dtype.char] revcom = getattr(_iterative, ltr + 'qmrrevcom') get_residual = lambda: np.linalg.norm(A.matvec(x) - b) atol = _get_atol(tol, atol, np.linalg.norm(b), get_residual, 'qmr') if atol == 'exit': return postprocess(x), 0 resid = atol ndx1 = 1 ndx2 = -1 # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work = _aligned_zeros(11*n,x.dtype) ijob = 1 info = 0 ftflag = True iter_ = maxiter while True: olditer = iter_ x, iter_, resid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, work, iter_, resid, info, ndx1, ndx2, ijob) if callback is not None and iter_ > olditer: callback(x) slice1 = slice(ndx1-1, ndx1-1+n) slice2 = slice(ndx2-1, ndx2-1+n) if (ijob == -1): if callback is not None: callback(x) break elif (ijob == 1): work[slice2] *= sclr2 work[slice2] += sclr1*A.matvec(work[slice1]) elif (ijob == 2): work[slice2] *= sclr2 work[slice2] += sclr1*A.rmatvec(work[slice1]) elif (ijob == 3): work[slice1] = M1.matvec(work[slice2]) elif (ijob == 4): work[slice1] = M2.matvec(work[slice2]) elif (ijob == 5): work[slice1] = M1.rmatvec(work[slice2]) elif (ijob == 6): work[slice1] = M2.rmatvec(work[slice2]) elif (ijob == 7): work[slice2] *= sclr2 work[slice2] += sclr1*A.matvec(x) elif (ijob == 8): if ftflag: info = -1 ftflag = False resid, info = _stoptest(work[slice1], atol) ijob = 2 if info > 0 and iter_ == maxiter and not (resid <= atol): # info isn't set appropriately otherwise info = iter_ return postprocess(x), info
def presid_gmres(A, M, b, verbose, x0=None, tol=1e-05, restart=None, maxiter=None): matvec = A psolve = M comm = A.comm rank = A.rank n = A.n dtype = A.dtype isMaster = rank == 0 callback = gmres_counter(verbose) if isMaster else None x = np.zeros(n, dtype=dtype) if x0 is None else x0 if maxiter is None: maxiter = n * 10 if restart is None: restart = 20 restart = min(restart, n) ltr = _type_conv[np.dtype(dtype).char] revcom = getattr(_iterative, ltr + 'gmresrevcom') pb = psolve(b) mb = matvec(b) if rank == 0: bnrm2 = np.linalg.norm(b) Mb_nrm2 = np.linalg.norm(pb) get_residual = lambda: np.linalg.norm(mb - b) atol = tol else: bnrm2 = None bnrm2 = comm.bcast(bnrm2, root=0) if bnrm2 == 0: return postprocess(b), 0 if rank == 0: # Tolerance passed to GMRESREVCOM applies to the inner iteration # and deals with the left-preconditioned residual. ptol_max_factor = 1.0 ptol = Mb_nrm2 * min(ptol_max_factor, atol / bnrm2) resid = np.nan presid = np.nan # Use _aligned_zeros to work around a f2py bug in Numpy 1.9.1 work2 = _aligned_zeros((restart + 1) * (2 * restart + 2), dtype=dtype) info = 0 ftflag = True iter_ = maxiter first_pass = True resid_ready = False ndx1 = 1 ndx2 = -1 ijob = 1 old_ijob = ijob work = _aligned_zeros((6 + restart) * n, dtype=dtype) iter_num = 1 while True: if rank == 0: ### begin my modifications if presid / bnrm2 < atol: resid = presid / bnrm2 info = 1 if info: ptol = 10000 ### end my modifications x, iter_, presid, info, ndx1, ndx2, sclr1, sclr2, ijob = \ revcom(b, x, restart, work, work2, iter_, presid, info, ndx1, ndx2, ijob, ptol) ijob = comm.bcast(ijob, root=0) ndx1 = comm.bcast(ndx1, root=0) ndx2 = comm.bcast(ndx2, root=0) slice1 = slice(ndx1 - 1, ndx1 - 1 + n) slice2 = slice(ndx2 - 1, ndx2 - 1 + n) if (ijob == -1): # gmres success, update last residual if rank == 0: if resid_ready and callback is not None: callback(presid / bnrm2) resid_ready = False break elif (ijob == 1): upd = matvec(x) if rank == 0: work[slice2] *= sclr2 work[slice2] += sclr1 * upd elif (ijob == 2): upd = psolve(work[slice2]) if rank == 0: work[slice1] = upd if not first_pass and old_ijob == 3: resid_ready = True first_pass = False elif (ijob == 3): upd = matvec(work[slice1]) if rank == 0: work[slice2] *= sclr2 work[slice2] += sclr1 * upd if resid_ready and callback is not None: callback(presid / bnrm2) resid_ready = False iter_num = iter_num + 1 elif (ijob == 4): if rank == 0: if ftflag: info = -1 ftflag = False resid, info = _stoptest(work[slice1], atol) # Inner loop tolerance control if info or presid > ptol: ptol_max_factor = min(1.0, 1.5 * ptol_max_factor) else: # Inner loop tolerance OK, but outer loop not. ptol_max_factor = max(1e-16, 0.25 * ptol_max_factor) if resid != 0: ptol = presid * min(ptol_max_factor, atol / resid) else: ptol = presid * ptol_max_factor if rank == 0: old_ijob = ijob ijob = 2 # need to set ijob according to the master rank ijob = comm.bcast(ijob, root=0) iter_num = comm.bcast(iter_num, root=0) if iter_num > maxiter: info = maxiter break if rank == 0: if info >= 0 and not (resid <= atol): # info isn't set appropriately otherwise info = maxiter return x, info, mydict['resnorms'] else: return None