def callback(x): if np.isscalar(x): residuals.append(x) else: residuals.append(residual_norm(A, x, b)) if cb is not None: cb(x)
def callback(x): if sp.isscalar(x): residuals.append(x) else: residuals.append(residual_norm(A, x, b)) if cb is not None: cb(x)
def solve(self, b, x0=None, tol=1e-5, maxiter=100, cycle='V', accel=None, callback=None, residuals=None, return_residuals=False): """Execute multigrid cycling. Parameters ---------- b : array Right hand side. x0 : array Initial guess. tol : float Stopping criteria: relative residual r[k]/r[0] tolerance. maxiter : int Stopping criteria: maximum number of allowable iterations. cycle : {'V','W','F','AMLI'} Type of multigrid cycle to perform in each iteration. accel : string, function Defines acceleration method. Can be a string such as 'cg' or 'gmres' which is the name of an iterative solver in pyamg.krylov (preferred) or scipy.sparse.linalg.isolve. If accel is not a string, it will be treated like a function with the same interface provided by the iterative solvers in SciPy. callback : function User-defined function called after each iteration. It is called as callback(xk) where xk is the k-th iterate vector. residuals : list List to contain residual norms at each iteration. Returns ------- x : array Approximate solution to Ax=b See Also -------- aspreconditioner Examples -------- >>> from numpy import ones >>> from pyamg import ruge_stuben_solver >>> from pyamg.gallery import poisson >>> A = poisson((100, 100), format='csr') >>> b = A * ones(A.shape[0]) >>> ml = ruge_stuben_solver(A, max_coarse=10) >>> residuals = [] >>> x = ml.solve(b, tol=1e-12, residuals=residuals) # standalone solver """ from pyamg.util.linalg import residual_norm, norm if x0 is None: x = np.zeros_like(b) else: x = np.array(x0) # copy cycle = str(cycle).upper() # AMLI cycles require hermitian matrix if (cycle == 'AMLI') and hasattr(self.levels[0].A, 'symmetry'): if self.levels[0].A.symmetry != 'hermitian': raise ValueError('AMLI cycles require \ symmetry to be hermitian') if accel is not None: # Check for symmetric smoothing scheme when using CG if (accel == 'cg') and (not self.symmetric_smoothing): warn('Incompatible non-symmetric multigrid preconditioner ' 'detected, due to presmoother/postsmoother combination. ' 'CG requires SPD preconditioner, not just SPD matrix.') # Check for AMLI compatability if (accel != 'fgmres') and (cycle == 'AMLI'): raise ValueError('AMLI cycles require acceleration (accel) ' 'to be fgmres, or no acceleration') # py23 compatibility: try: basestring except NameError: basestring = str # Acceleration is being used kwargs = {} if isinstance(accel, basestring): from pyamg import krylov from scipy.sparse.linalg import isolve kwargs = {} if hasattr(krylov, accel): accel = getattr(krylov, accel) else: accel = getattr(isolve, accel) kwargs['atol'] = 'legacy' A = self.levels[0].A M = self.aspreconditioner(cycle=cycle) try: # try PyAMG style interface which has a residuals parameter return accel(A, b, x0=x0, tol=tol, maxiter=maxiter, M=M, callback=callback, residuals=residuals, **kwargs)[0] except BaseException: # try the scipy.sparse.linalg.isolve style interface, # which requires a call back function if a residual # history is desired cb = callback if residuals is not None: residuals[:] = [residual_norm(A, x, b)] def callback(x): if np.isscalar(x): residuals.append(x) else: residuals.append(residual_norm(A, x, b)) if cb is not None: cb(x) return accel(A, b, x0=x0, tol=tol, maxiter=maxiter, M=M, callback=callback, **kwargs)[0] else: # Scale tol by normb # Don't scale tol earlier. The accel routine should also scale tol normb = norm(b) if normb != 0: tol = tol * normb if return_residuals: warn('return_residuals is deprecated. Use residuals instead') residuals = [] if residuals is None: residuals = [] else: residuals[:] = [] # Create uniform types for A, x and b # Clearly, this logic doesn't handle the case of real A and complex b from scipy.sparse.sputils import upcast from pyamg.util.utils import to_type tp = upcast(b.dtype, x.dtype, self.levels[0].A.dtype) [b, x] = to_type(tp, [b, x]) b = np.ravel(b) x = np.ravel(x) A = self.levels[0].A residuals.append(residual_norm(A, x, b)) self.first_pass = True while len(residuals) <= maxiter and residuals[-1] > tol: if len(self.levels) == 1: # hierarchy has only 1 level x = self.coarse_solver(A, b) else: self.__solve(0, x, b, cycle) residuals.append(residual_norm(A, x, b)) self.first_pass = False if callback is not None: callback(x) if return_residuals: return x, residuals else: return x
def solve(self, b, x0=None, tol=1e-5, maxiter=100, cycle='V', accel=None, callback=None, residuals=None, return_residuals=False): """Execute multigrid cycling. Parameters ---------- b : array Right hand side. x0 : array Initial guess. tol : float Stopping criteria: relative residual r[k]/r[0] tolerance. maxiter : int Stopping criteria: maximum number of allowable iterations. cycle : {'V','W','F','AMLI'} Type of multigrid cycle to perform in each iteration. accel : string, function Defines acceleration method. Can be a string such as 'cg' or 'gmres' which is the name of an iterative solver in pyamg.krylov (preferred) or scipy.sparse.linalg.isolve. If accel is not a string, it will be treated like a function with the same interface provided by the iterative solvers in SciPy. callback : function User-defined function called after each iteration. It is called as callback(xk) where xk is the k-th iterate vector. residuals : list List to contain residual norms at each iteration. Returns ------- x : array Approximate solution to Ax=b See Also -------- aspreconditioner Examples -------- >>> from numpy import ones >>> from pyamg import ruge_stuben_solver >>> from pyamg.gallery import poisson >>> A = poisson((100, 100), format='csr') >>> b = A * ones(A.shape[0]) >>> ml = ruge_stuben_solver(A, max_coarse=10) >>> residuals = [] >>> x = ml.solve(b, tol=1e-12, residuals=residuals) # standalone solver """ from pyamg.util.linalg import residual_norm, norm if x0 is None: x = np.zeros_like(b) else: x = np.array(x0) # copy cycle = str(cycle).upper() # AMLI cycles require hermitian matrix if (cycle == 'AMLI') and hasattr(self.levels[0].A, 'symmetry'): if self.levels[0].A.symmetry != 'hermitian': raise ValueError('AMLI cycles require \ symmetry to be hermitian') if accel is not None: # Check for symmetric smoothing scheme when using CG if (accel is 'cg') and (not self.symmetric_smoothing): warn('Incompatible non-symmetric multigrid preconditioner ' 'detected, due to presmoother/postsmoother combination. ' 'CG requires SPD preconditioner, not just SPD matrix.') # Check for AMLI compatability if (accel != 'fgmres') and (cycle == 'AMLI'): raise ValueError('AMLI cycles require acceleration (accel) ' 'to be fgmres, or no acceleration') # py23 compatibility: try: basestring except NameError: basestring = str # Acceleration is being used kwargs = {} if isinstance(accel, basestring): from pyamg import krylov from scipy.sparse.linalg import isolve kwargs = {} if hasattr(krylov, accel): accel = getattr(krylov, accel) else: accel = getattr(isolve, accel) kwargs['atol'] = 'legacy' A = self.levels[0].A M = self.aspreconditioner(cycle=cycle) try: # try PyAMG style interface which has a residuals parameter return accel(A, b, x0=x0, tol=tol, maxiter=maxiter, M=M, callback=callback, residuals=residuals, **kwargs)[0] except BaseException: # try the scipy.sparse.linalg.isolve style interface, # which requires a call back function if a residual # history is desired cb = callback if residuals is not None: residuals[:] = [residual_norm(A, x, b)] def callback(x): if sp.isscalar(x): residuals.append(x) else: residuals.append(residual_norm(A, x, b)) if cb is not None: cb(x) return accel(A, b, x0=x0, tol=tol, maxiter=maxiter, M=M, callback=callback, **kwargs)[0] else: # Scale tol by normb # Don't scale tol earlier. The accel routine should also scale tol normb = norm(b) if normb != 0: tol = tol * normb if return_residuals: warn('return_residuals is deprecated. Use residuals instead') residuals = [] if residuals is None: residuals = [] else: residuals[:] = [] # Create uniform types for A, x and b # Clearly, this logic doesn't handle the case of real A and complex b from scipy.sparse.sputils import upcast from pyamg.util.utils import to_type tp = upcast(b.dtype, x.dtype, self.levels[0].A.dtype) [b, x] = to_type(tp, [b, x]) b = np.ravel(b) x = np.ravel(x) A = self.levels[0].A residuals.append(residual_norm(A, x, b)) self.first_pass = True while len(residuals) <= maxiter and residuals[-1] > tol: if len(self.levels) == 1: # hierarchy has only 1 level x = self.coarse_solver(A, b) else: self.__solve(0, x, b, cycle) residuals.append(residual_norm(A, x, b)) self.first_pass = False if callback is not None: callback(x) if return_residuals: return x, residuals else: return x
def solve(self, b, x0=None, tol=1e-5, maxiter=100, cycle='V', accel=None, callback=None, residuals=None, return_residuals=False, additive=False): if self.num_hierarchies == 0: raise ValueError("Cannot solve - zero hierarchies stored.") from pyamg.util.linalg import residual_norm, norm if x0 is None: x = np.zeros_like(b) else: x = np.array(x0) # copy cycle = str(cycle).upper() # AMLI cycles require hermitian matrix if (cycle == 'AMLI') and hasattr(self.levels[0].A, 'symmetry'): if self.levels[0].A.symmetry != 'hermitian': raise ValueError('AMLI cycles require \ symmetry to be hermitian') # Create uniform types for A, x and b # Clearly, this logic doesn't handle the case of real A and complex b from scipy.sparse.sputils import upcast from pyamg.util.utils import to_type A = self.hierarchy_set[0].levels[0].A tp = upcast(b.dtype, x.dtype, A.dtype) [b, x] = to_type(tp, [b, x]) b = np.ravel(b) x = np.ravel(x) if accel is not None: # Check for AMLI compatability if (accel != 'fgmres') and (cycle == 'AMLI'): raise ValueError('AMLI cycles require acceleration (accel) \ to be fgmres, or no acceleration') # Acceleration is being used if isinstance(accel, basestring): from pyamg import krylov from scipy.sparse.linalg import isolve if hasattr(krylov, accel): accel = getattr(krylov, accel) else: accel = getattr(isolve, accel) M = self.aspreconditioner(cycle=cycle) n = x.shape[0] try: # try PyAMG style interface which has a residuals parameter return accel(A, b, x0=x0, tol=tol, maxiter=maxiter, M=M, callback=callback, residuals=residuals)[0].reshape((n,1)) except: # try the scipy.sparse.linalg.isolve style interface, # which requires a call back function if a residual # history is desired cb = callback if residuals is not None: residuals[:] = [residual_norm(A, x, b)] def callback(x): if sp.isscalar(x): residuals.append(x) else: residuals.append(residual_norm(A, x, b)) if cb is not None: cb(x) return accel(A, b, x0=x0, tol=tol, maxiter=maxiter, M=M, callback=callback)[0].reshape((n,1)) else: # Scale tol by normb # Don't scale tol earlier. The accel routine should also scale tol normb = norm(b) if normb != 0: tol = tol * normb if return_residuals: warn('return_residuals is deprecated. Use residuals instead') residuals = [] if residuals is None: residuals = [] else: residuals[:] = [] residuals.append(residual_norm(A, x, b)) iter_num = 0 while iter_num < maxiter and residuals[-1] > tol: # ----------- Additive solve ----------- # # ------ This doesn't really work ------ # if additive: x_copy = deepcopy(x) for hierarchy in self.hierarchy_set: this_x = deepcopy(x_copy) if len(hierarchy.levels) == 1: this_x = hierarchy.coarse_solver(A, b) else: temp = hierarchy.test_solve(0, this_x, b, cycle) x += temp # ----------- Normal solve ----------- # else: # One solve for each hierarchy in set for hierarchy in self.hierarchy_set: # hierarchy has only 1 level if len(hierarchy.levels) == 1: x = hierarchy.coarse_solver(A, b) else: hierarchy.test_solve(0, x, b, cycle) residuals.append(residual_norm(A, x, b)) iter_num += 1 if callback is not None: callback(x) n = x.shape[0] if return_residuals: return x.reshape((n,1)), residuals else: return x.reshape((n,1))