(solver)
return GenericSolver()
Return a coarse grid solver suitable for MultilevelSolver.

    Parameters
    ----------
    solver : string, callable, tuple
        The solver method is either (1) a string such as 'splu' or 'pinv' of a
        callable object which receives only parameters (A, b) and returns an
        (approximate or exact) solution to the linear system Ax = b, or (2) a
        callable object that takes parameters (A,b) and returns an (approximate
        or exact) solution to Ax = b, or (3) a tuple of the form
        (string|callable, args), where args is a dictionary of arguments to
        be passed to the function denoted by string or callable.

        The set of valid string arguments is:
            - Sparse direct methods:
                + splu : sparse LU solver
            - Sparse iterative methods:
                + the name of any method in scipy.sparse.linalg.isolve or
                  pyamg.krylov (e.g. 'cg').
                  Methods in pyamg.krylov take precedence.
                + relaxation method, such as 'gauss_seidel' or 'jacobi',
                  present in pyamg.relaxation
            - Dense methods:
                + pinv     : pseudoinverse (SVD)
                + lu       : LU factorization
                + cholesky : Cholesky factorization

    Returns
    -------
    ptr : GenericSolver
        A class for use as a standalone or coarse grids solver

    Examples
    --------
    >>> import numpy as np
    >>> from scipy.sparse import spdiags
    >>> from pyamg.gallery import poisson
    >>> from pyamg import coarse_grid_solver
    >>> A = poisson((10, 10), format='csr')
    >>> b = A * np.ones(A.shape[0])
    >>> cgs = coarse_grid_solver('lu')
    >>> x = cgs(A, b)
Return a coarse grid solver suitable for MultilevelSolver.
Return a coarse grid solver suitable for MultilevelSolver .
def coarse_grid_solver(solver):
    """Return a coarse grid solver suitable for MultilevelSolver.

    Parameters
    ----------
    solver : string, callable, tuple
        The solver method is either (1) a string such as 'splu' or 'pinv' of a
        callable object which receives only parameters (A, b) and returns an
        (approximate or exact) solution to the linear system Ax = b, or (2) a
        callable object that takes parameters (A,b) and returns an (approximate
        or exact) solution to Ax = b, or (3) a tuple of the form
        (string|callable, args), where args is a dictionary of arguments to
        be passed to the function denoted by string or callable.

        The set of valid string arguments is:
            - Sparse direct methods:
                + splu : sparse LU solver
            - Sparse iterative methods:
                + the name of any method in scipy.sparse.linalg.isolve or
                  pyamg.krylov (e.g. 'cg').
                  Methods in pyamg.krylov take precedence.
                + relaxation method, such as 'gauss_seidel' or 'jacobi',
                  present in pyamg.relaxation
            - Dense methods:
                + pinv     : pseudoinverse (SVD)
                + lu       : LU factorization
                + cholesky : Cholesky factorization

    Returns
    -------
    ptr : GenericSolver
        A class for use as a standalone or coarse grids solver

    Examples
    --------
    >>> import numpy as np
    >>> from scipy.sparse import spdiags
    >>> from pyamg.gallery import poisson
    >>> from pyamg import coarse_grid_solver
    >>> A = poisson((10, 10), format='csr')
    >>> b = A * np.ones(A.shape[0])
    >>> cgs = coarse_grid_solver('lu')
    >>> x = cgs(A, b)

    """

    def unpack_arg(v):
        if isinstance(v, tuple):
            return v[0], v[1]
        return v, {}

    solver, kwargs = unpack_arg(solver)

    if solver in ['pinv', 'pinv2']:
        def solve(self, A, b):
            if not hasattr(self, 'P'):
                self.P = pinv(A.toarray(), **kwargs)
            return np.dot(self.P, b)

    elif solver == 'lu':
        def solve(self, A, b):
            if not hasattr(self, 'LU'):
                self.LU = sp.linalg.lu_factor(A.toarray(), **kwargs)
            return sp.linalg.lu_solve(self.LU, b)

    elif solver == 'cholesky':
        def solve(self, A, b):
            if not hasattr(self, 'L'):
                self.L = sp.linalg.cho_factor(A.toarray(), **kwargs)
            return sp.linalg.cho_solve(self.L, b)

    elif solver == 'splu':
        def solve(self, A, b):
            if not hasattr(self, 'LU'):
                # for multiple candidates in B, A will often have a couple zero
                # rows/columns that must be removed
                Acsc = A.tocsc()
                Acsc.eliminate_zeros()
                diffptr = Acsc.indptr[:-1] - Acsc.indptr[1:]
                nonzero_cols = (diffptr != 0).nonzero()[0]
                Map = sp.sparse.eye(Acsc.shape[0], Acsc.shape[1], format='csc')
                Map = Map[:, nonzero_cols]
                Acsc = Map.T.tocsc() * Acsc * Map
                self.LU = sp.sparse.linalg.splu(Acsc, **kwargs)
                self.LU_Map = Map

            return self.LU_Map * self.LU.solve(np.ravel(self.LU_Map.T * b))

    elif solver in ['bicg', 'bicgstab', 'cg', 'cgs', 'gmres', 'qmr', 'minres']:
        if hasattr(krylov, solver):
            fn = getattr(krylov, solver)
        else:
            fn = getattr(sp.sparse.linalg.isolve, solver)

        def solve(_, A, b):
            if 'tol' not in kwargs:
                kwargs['tol'] = set_tol(A.dtype)

            return fn(A, b, **kwargs)[0]

    elif solver in ['gauss_seidel', 'jacobi', 'block_gauss_seidel', 'schwarz',
                    'block_jacobi', 'richardson', 'sor', 'chebyshev',
                    'jacobi_ne', 'gauss_seidel_ne', 'gauss_seidel_nr']:

        if 'iterations' not in kwargs:
            kwargs['iterations'] = 10

        def solve(_, A, b):

            lvl = MultilevelSolver.Level()
            lvl.A = A
            fn = getattr(smoothing, 'setup_' + str(solver))
            relax = fn(lvl, **kwargs)
            x = np.zeros_like(b)
            relax(A, x, b)

            return x

    elif solver is None:
        # No coarse grid solve
        def solve(_, __, b):
            return 0 * b  # should this return b instead?

    elif callable(solver):
        def solve(_, A, b):
            return solver(A, b, **kwargs)

    else:
        raise ValueError(f'unknown solver: {solver}')

    class GenericSolver:
        """Generic solver class."""

        def __call__(self, A, b):
            # make sure x is same dimensions and type as b
            b = np.asanyarray(b)

            if A.nnz == 0:
                # if A.nnz = 0, then we expect no correction
                x = np.zeros(b.shape)
            else:
                x = solve(self, A, b)

            if isinstance(b, np.ndarray):
                x = np.asarray(x)
            elif isinstance(b, np.matrix):
                # convert to ndarray
                b = np.asarray(b)
                x = np.asarray(x)
            else:
                raise ValueError('unrecognized type')

            return x.reshape(b.shape)

        def __repr__(self):
            return 'coarse_grid_solver(' + repr(solver) + ')'

        @classmethod
        def name(cls):
            """Return the coarse solver name."""
            return repr(solver)

    return GenericSolver()
def coarse_grid_solver ( solver ) : def unpack_arg ( v ) : if isinstance ( v , tuple ) : return v [ 0 ] , v [ 1 ] return v , { } solver , kwargs = unpack_arg ( solver ) if solver in [ 'pinv' , 'pinv2' ] : def solve ( self , A , b ) : if not hasattr ( self , 'P' ) : self . P = pinv ( A . toarray ( ) , * * kwargs ) return np . dot ( self . P , b ) elif solver == 'lu' : def solve ( self , A , b ) : if not hasattr ( self , 'LU' ) : self . LU = sp . linalg . lu_factor ( A . toarray ( ) , * * kwargs ) return sp . linalg . lu_solve ( self . LU , b ) elif solver == 'cholesky' : def solve ( self , A , b ) : if not hasattr ( self , 'L' ) : self . L = sp . linalg . cho_factor ( A . toarray ( ) , * * kwargs ) return sp . linalg . cho_solve ( self . L , b ) elif solver == 'splu' : def solve ( self , A , b ) : if not hasattr ( self , 'LU' ) : # for multiple candidates in B, A will often have a couple zero # rows/columns that must be removed Acsc = A . tocsc ( ) Acsc . eliminate_zeros ( ) diffptr = Acsc . indptr [ : - 1 ] - Acsc . indptr [ 1 : ] nonzero_cols = ( diffptr != 0 ) . nonzero ( ) [ 0 ] Map = sp . sparse . eye ( Acsc . shape [ 0 ] , Acsc . shape [ 1 ] , format = 'csc' ) Map = Map [ : , nonzero_cols ] Acsc = Map . T . tocsc ( ) * Acsc * Map self . LU = sp . sparse . linalg . splu ( Acsc , * * kwargs ) self . LU_Map = Map return self . LU_Map * self . LU . solve ( np . ravel ( self . LU_Map . T * b ) ) elif solver in [ 'bicg' , 'bicgstab' , 'cg' , 'cgs' , 'gmres' , 'qmr' , 'minres' ] : if hasattr ( krylov , solver ) : fn = getattr ( krylov , solver ) else : fn = getattr ( sp . sparse . linalg . isolve , solver ) def solve ( _ , A , b ) : if 'tol' not in kwargs : kwargs [ 'tol' ] = set_tol ( A . dtype ) return fn ( A , b , * * kwargs ) [ 0 ] elif solver in [ 'gauss_seidel' , 'jacobi' , 'block_gauss_seidel' , 'schwarz' , 'block_jacobi' , 'richardson' , 'sor' , 'chebyshev' , 'jacobi_ne' , 'gauss_seidel_ne' , 'gauss_seidel_nr' ] : if 'iterations' not in kwargs : kwargs [ 'iterations' ] = 10 def solve ( _ , A , b ) : lvl = MultilevelSolver . Level ( ) lvl . A = A fn = getattr ( smoothing , 'setup_' + str ( solver ) ) relax = fn ( lvl , * * kwargs ) x = np . zeros_like ( b ) relax ( A , x , b ) return x elif solver is None : # No coarse grid solve def solve ( _ , __ , b ) : return 0 * b # should this return b instead? elif callable ( solver ) : def solve ( _ , A , b ) : return solver ( A , b , * * kwargs ) else : raise ValueError ( f'unknown solver: {solver}' ) class GenericSolver : """Generic solver class.""" def __call__ ( self , A , b ) : # make sure x is same dimensions and type as b b = np . asanyarray ( b ) if A . nnz == 0 : # if A.nnz = 0, then we expect no correction x = np . zeros ( b . shape ) else : x = solve ( self , A , b ) if isinstance ( b , np . ndarray ) : x = np . asarray ( x ) elif isinstance ( b , np . matrix ) : # convert to ndarray b = np . asarray ( b ) x = np . asarray ( x ) else : raise ValueError ( 'unrecognized type' ) return x . reshape ( b . shape ) def __repr__ ( self ) : return 'coarse_grid_solver(' + repr ( solver ) + ')' @ classmethod def name ( cls ) : """Return the coarse solver name.""" return repr ( solver ) return GenericSolver ( )