(A, B=None, BH=None,
                    symmetry='hermitian', strength='symmetric',
                    aggregate='standard', smooth='energy',
                    presmoother=('block_gauss_seidel',
                                 {'sweep': 'symmetric'}),
                    postsmoother=('block_gauss_seidel',
                                  {'sweep': 'symmetric'}),
                    improve_candidates=('block_gauss_seidel',
                                        {'sweep': 'symmetric',
                                         'iterations': 4}),
                    max_levels=10, max_coarse=10,
                    diagonal_dominance=False, keep=False, **kwargs)
return ml
Create a multilevel solver using root-node based Smoothed Aggregation (SA).

    See the notes below, for the major differences with the classical-style
    smoothed aggregation solver in aggregation.smoothed_aggregation_solver.

    Parameters
    ----------
    A : csr_matrix, bsr_matrix
        Sparse NxN matrix in CSR or BSR format

    B : None, array_like
        Right near-nullspace candidates stored in the columns of an NxK array.
        K must be >= the blocksize of A (see reference [2011OlScTu]_). The default value
        B=None is equivalent to choosing the constant over each block-variable,
        B=np.kron(np.ones((A.shape[0]/get_blocksize(A), 1)), np.eye(get_blocksize(A)))

    BH : None, array_like
        Left near-nullspace candidates stored in the columns of an NxK array.
        BH is only used if symmetry='nonsymmetric'.  K must be >= the
        blocksize of A (see reference [2011OlScTu]_). The default value B=None is
        equivalent to choosing the constant over each block-variable,
        B=np.kron(np.ones((A.shape[0]/get_blocksize(A), 1)), np.eye(get_blocksize(A)))

    symmetry : string
        'symmetric' refers to both real and complex symmetric
        'hermitian' refers to both complex Hermitian and real Hermitian
        'nonsymmetric' i.e. nonsymmetric in a hermitian sense
        Note that for the strictly real case, symmetric and hermitian are
        the same
        Note that this flag does not denote definiteness of the operator.

    strength : list
        Method used to determine the strength of connection between unknowns of
        the linear system.  Method-specific parameters may be passed in using a
        tuple, e.g. strength=('symmetric',{'theta' : 0.25 }). If strength=None,
        all nonzero entries of the matrix are considered strong.

    aggregate : list
        Method used to aggregate nodes.

    smooth : list
        Method used to smooth the tentative prolongator.  Method-specific
        parameters may be passed in using a tuple, e.g.  smooth=
        ('energy',{'krylov' : 'gmres'}).  Only 'energy' and None are valid
        prolongation smoothing options.

    presmoother : tuple, string, list
        Defines the presmoother for the multilevel cycling.  The default block
        Gauss-Seidel option defaults to point-wise Gauss-Seidel, if the matrix
        is CSR or is a BSR matrix with blocksize of 1.  See notes below for
        varying this parameter on a per level basis.

    postsmoother : tuple, string, list
        Same as presmoother, except defines the postsmoother.

    improve_candidates : tuple, string, list
        The ith entry defines the method used to improve the candidates B on
        level i.  If the list is shorter than max_levels, then the last entry
        will define the method for all levels lower.  If tuple or string, then
        this single relaxation descriptor defines improve_candidates on all
        levels.
        The list elements are relaxation descriptors of the form used for
        presmoother and postsmoother.  A value of None implies no action on B.

    max_levels : integer
        Maximum number of levels to be used in the multilevel solver.

    max_coarse : integer
        Maximum number of variables permitted on the coarse grid.

    diagonal_dominance : bool, tuple
        If True (or the first tuple entry is True), then avoid coarsening
        diagonally dominant rows.  The second tuple entry requires a
        dictionary, where the key value 'theta' is used to tune the diagonal
        dominance threshold.

    keep : bool
        Flag to indicate keeping extra operators in the hierarchy for
        diagnostics.  For example, if True, then strength of connection (C),
        tentative prolongation (T), aggregation (AggOp), and arrays
        storing the C-points (Cpts) and F-points (Fpts) are kept at
        each level.

    Other Parameters
    ----------------
    cycle_type : ['V','W','F']
        Structrure of multigrid cycle
    coarse_solver : ['splu', 'lu', 'cholesky, 'pinv', 'gauss_seidel', ... ]
        Solver used at the coarsest level of the MG hierarchy.
        Optionally, may be a tuple (fn, args), where fn is a string such as
        ['splu', 'lu', ...] or a callable function, and args is a dictionary of
        arguments to be passed to fn.

    Returns
    -------
    ml : MultilevelSolver
        Multigrid hierarchy of matrices and prolongation operators

    See Also
    --------
    MultilevelSolver, aggregation.smoothed_aggregation_solver,
    classical.ruge_stuben_solver

    Notes
    -----
         - Root-node style SA differs from classical SA primarily by preserving
           and identity block in the interpolation operator, P.  Each aggregate
           has a 'root-node' or 'center-node' associated with it, and this
           root-node is injected from the coarse grid to the fine grid.  The
           injection corresponds to the identity block.

         - Only smooth={'energy', None} is supported for prolongation
           smoothing.  See reference [2011OlScTu]_ below for more details on why the
           'energy' prolongation smoother is the natural counterpart to
           root-node style SA.

         - The additional parameters are passed through as arguments to
           MultilevelSolver.  Refer to pyamg.MultilevelSolver for additional
           documentation.

         - At each level, four steps are executed in order to define the coarser
           level operator.

           1. Matrix A is given and used to derive a strength matrix, C.

           2. Based on the strength matrix, indices are grouped or aggregated.

           3. The aggregates define coarse nodes and a tentative prolongation
              operator T is defined by injection

           4. The tentative prolongation operator is smoothed by a relaxation
              scheme to improve the quality and extent of interpolation from the
              aggregates to fine nodes.

         - The parameters smooth, strength, aggregate, presmoother, postsmoother
           can be varied on a per level basis.  For different methods on
           different levels, use a list as input so that the i-th entry defines
           the method at the i-th level.  If there are more levels in the
           hierarchy than list entries, the last entry will define the method
           for all levels lower.

           Examples are:
           smooth=[('jacobi', {'omega':1.0}), None, 'jacobi']
           presmoother=[('block_gauss_seidel', {'sweep':symmetric}), 'sor']
           aggregate=['standard', 'naive']
           strength=[('symmetric', {'theta':0.25}), ('symmetric', {'theta':0.08})]

         - Predefined strength of connection and aggregation schemes can be
           specified.  These options are best used together, but aggregation can
           be predefined while strength of connection is not.

           For predefined strength of connection, use a list consisting of
           tuples of the form ('predefined', {'C' : C0}), where C0 is a
           csr_matrix and each degree-of-freedom in C0 represents a supernode.
           For instance to predefine a three-level hierarchy, use
           [('predefined', {'C' : C0}), ('predefined', {'C' : C1}) ].

           Similarly for predefined aggregation, use a list of tuples.  For
           instance to predefine a three-level hierarchy, use [('predefined',
           {'AggOp' : Agg0}), ('predefined', {'AggOp' : Agg1}) ], where the
           dimensions of A, Agg0 and Agg1 are compatible, i.e.  Agg0.shape[1] ==
           A.shape[0] and Agg1.shape[1] == Agg0.shape[0].  Each AggOp is a
           csr_matrix.

           Because this is a root-nodes solver, if a member of the predefined
           aggregation list is predefined, it must be of the form
           ('predefined', {'AggOp' : Agg, 'Cnodes' : Cnodes}).

    Examples
    --------
    >>> from pyamg import rootnode_solver
    >>> from pyamg.gallery import poisson
    >>> from scipy.sparse.linalg import cg
    >>> import numpy as np
    >>> A = poisson((100, 100), format='csr')           # matrix
    >>> b = np.ones((A.shape[0]))                   # RHS
    >>> ml = rootnode_solver(A)                     # AMG solver
    >>> M = ml.aspreconditioner(cycle='V')             # preconditioner
    >>> x, info = cg(A, b, tol=1e-8, maxiter=30, M=M)   # solve with CG

    References
    ----------
    .. [1996VaMa] Vanek, P. and Mandel, J. and Brezina, M.,
       "Algebraic Multigrid by Smoothed Aggregation for
       Second and Fourth Order Elliptic Problems",
       Computing, vol. 56, no. 3, pp. 179--196, 1996.
       http://citeseer.ist.psu.edu/vanek96algebraic.html
    .. [2011OlScTu] Olson, L. and Schroder, J. and Tuminaro, R.,
       "A general interpolation strategy for algebraic
       multigrid using energy minimization", SIAM Journal
       on Scientific Computing (SISC), vol. 33, pp.
       966--991, 2011.
Create a multilevel solver using root-node based Smoothed Aggregation (SA).
Create a multilevel solver using root - node based Smoothed Aggregation ( SA ) .
def rootnode_solver(A, B=None, BH=None,
                    symmetry='hermitian', strength='symmetric',
                    aggregate='standard', smooth='energy',
                    presmoother=('block_gauss_seidel',
                                 {'sweep': 'symmetric'}),
                    postsmoother=('block_gauss_seidel',
                                  {'sweep': 'symmetric'}),
                    improve_candidates=('block_gauss_seidel',
                                        {'sweep': 'symmetric',
                                         'iterations': 4}),
                    max_levels=10, max_coarse=10,
                    diagonal_dominance=False, keep=False, **kwargs):
    """Create a multilevel solver using root-node based Smoothed Aggregation (SA).

    See the notes below, for the major differences with the classical-style
    smoothed aggregation solver in aggregation.smoothed_aggregation_solver.

    Parameters
    ----------
    A : csr_matrix, bsr_matrix
        Sparse NxN matrix in CSR or BSR format

    B : None, array_like
        Right near-nullspace candidates stored in the columns of an NxK array.
        K must be >= the blocksize of A (see reference [2011OlScTu]_). The default value
        B=None is equivalent to choosing the constant over each block-variable,
        B=np.kron(np.ones((A.shape[0]/get_blocksize(A), 1)), np.eye(get_blocksize(A)))

    BH : None, array_like
        Left near-nullspace candidates stored in the columns of an NxK array.
        BH is only used if symmetry='nonsymmetric'.  K must be >= the
        blocksize of A (see reference [2011OlScTu]_). The default value B=None is
        equivalent to choosing the constant over each block-variable,
        B=np.kron(np.ones((A.shape[0]/get_blocksize(A), 1)), np.eye(get_blocksize(A)))

    symmetry : string
        'symmetric' refers to both real and complex symmetric
        'hermitian' refers to both complex Hermitian and real Hermitian
        'nonsymmetric' i.e. nonsymmetric in a hermitian sense
        Note that for the strictly real case, symmetric and hermitian are
        the same
        Note that this flag does not denote definiteness of the operator.

    strength : list
        Method used to determine the strength of connection between unknowns of
        the linear system.  Method-specific parameters may be passed in using a
        tuple, e.g. strength=('symmetric',{'theta' : 0.25 }). If strength=None,
        all nonzero entries of the matrix are considered strong.

    aggregate : list
        Method used to aggregate nodes.

    smooth : list
        Method used to smooth the tentative prolongator.  Method-specific
        parameters may be passed in using a tuple, e.g.  smooth=
        ('energy',{'krylov' : 'gmres'}).  Only 'energy' and None are valid
        prolongation smoothing options.

    presmoother : tuple, string, list
        Defines the presmoother for the multilevel cycling.  The default block
        Gauss-Seidel option defaults to point-wise Gauss-Seidel, if the matrix
        is CSR or is a BSR matrix with blocksize of 1.  See notes below for
        varying this parameter on a per level basis.

    postsmoother : tuple, string, list
        Same as presmoother, except defines the postsmoother.

    improve_candidates : tuple, string, list
        The ith entry defines the method used to improve the candidates B on
        level i.  If the list is shorter than max_levels, then the last entry
        will define the method for all levels lower.  If tuple or string, then
        this single relaxation descriptor defines improve_candidates on all
        levels.
        The list elements are relaxation descriptors of the form used for
        presmoother and postsmoother.  A value of None implies no action on B.

    max_levels : integer
        Maximum number of levels to be used in the multilevel solver.

    max_coarse : integer
        Maximum number of variables permitted on the coarse grid.

    diagonal_dominance : bool, tuple
        If True (or the first tuple entry is True), then avoid coarsening
        diagonally dominant rows.  The second tuple entry requires a
        dictionary, where the key value 'theta' is used to tune the diagonal
        dominance threshold.

    keep : bool
        Flag to indicate keeping extra operators in the hierarchy for
        diagnostics.  For example, if True, then strength of connection (C),
        tentative prolongation (T), aggregation (AggOp), and arrays
        storing the C-points (Cpts) and F-points (Fpts) are kept at
        each level.

    Other Parameters
    ----------------
    cycle_type : ['V','W','F']
        Structrure of multigrid cycle
    coarse_solver : ['splu', 'lu', 'cholesky, 'pinv', 'gauss_seidel', ... ]
        Solver used at the coarsest level of the MG hierarchy.
        Optionally, may be a tuple (fn, args), where fn is a string such as
        ['splu', 'lu', ...] or a callable function, and args is a dictionary of
        arguments to be passed to fn.

    Returns
    -------
    ml : MultilevelSolver
        Multigrid hierarchy of matrices and prolongation operators

    See Also
    --------
    MultilevelSolver, aggregation.smoothed_aggregation_solver,
    classical.ruge_stuben_solver

    Notes
    -----
         - Root-node style SA differs from classical SA primarily by preserving
           and identity block in the interpolation operator, P.  Each aggregate
           has a 'root-node' or 'center-node' associated with it, and this
           root-node is injected from the coarse grid to the fine grid.  The
           injection corresponds to the identity block.

         - Only smooth={'energy', None} is supported for prolongation
           smoothing.  See reference [2011OlScTu]_ below for more details on why the
           'energy' prolongation smoother is the natural counterpart to
           root-node style SA.

         - The additional parameters are passed through as arguments to
           MultilevelSolver.  Refer to pyamg.MultilevelSolver for additional
           documentation.

         - At each level, four steps are executed in order to define the coarser
           level operator.

           1. Matrix A is given and used to derive a strength matrix, C.

           2. Based on the strength matrix, indices are grouped or aggregated.

           3. The aggregates define coarse nodes and a tentative prolongation
              operator T is defined by injection

           4. The tentative prolongation operator is smoothed by a relaxation
              scheme to improve the quality and extent of interpolation from the
              aggregates to fine nodes.

         - The parameters smooth, strength, aggregate, presmoother, postsmoother
           can be varied on a per level basis.  For different methods on
           different levels, use a list as input so that the i-th entry defines
           the method at the i-th level.  If there are more levels in the
           hierarchy than list entries, the last entry will define the method
           for all levels lower.

           Examples are:
           smooth=[('jacobi', {'omega':1.0}), None, 'jacobi']
           presmoother=[('block_gauss_seidel', {'sweep':symmetric}), 'sor']
           aggregate=['standard', 'naive']
           strength=[('symmetric', {'theta':0.25}), ('symmetric', {'theta':0.08})]

         - Predefined strength of connection and aggregation schemes can be
           specified.  These options are best used together, but aggregation can
           be predefined while strength of connection is not.

           For predefined strength of connection, use a list consisting of
           tuples of the form ('predefined', {'C' : C0}), where C0 is a
           csr_matrix and each degree-of-freedom in C0 represents a supernode.
           For instance to predefine a three-level hierarchy, use
           [('predefined', {'C' : C0}), ('predefined', {'C' : C1}) ].

           Similarly for predefined aggregation, use a list of tuples.  For
           instance to predefine a three-level hierarchy, use [('predefined',
           {'AggOp' : Agg0}), ('predefined', {'AggOp' : Agg1}) ], where the
           dimensions of A, Agg0 and Agg1 are compatible, i.e.  Agg0.shape[1] ==
           A.shape[0] and Agg1.shape[1] == Agg0.shape[0].  Each AggOp is a
           csr_matrix.

           Because this is a root-nodes solver, if a member of the predefined
           aggregation list is predefined, it must be of the form
           ('predefined', {'AggOp' : Agg, 'Cnodes' : Cnodes}).

    Examples
    --------
    >>> from pyamg import rootnode_solver
    >>> from pyamg.gallery import poisson
    >>> from scipy.sparse.linalg import cg
    >>> import numpy as np
    >>> A = poisson((100, 100), format='csr')           # matrix
    >>> b = np.ones((A.shape[0]))                   # RHS
    >>> ml = rootnode_solver(A)                     # AMG solver
    >>> M = ml.aspreconditioner(cycle='V')             # preconditioner
    >>> x, info = cg(A, b, tol=1e-8, maxiter=30, M=M)   # solve with CG

    References
    ----------
    .. [1996VaMa] Vanek, P. and Mandel, J. and Brezina, M.,
       "Algebraic Multigrid by Smoothed Aggregation for
       Second and Fourth Order Elliptic Problems",
       Computing, vol. 56, no. 3, pp. 179--196, 1996.
       http://citeseer.ist.psu.edu/vanek96algebraic.html
    .. [2011OlScTu] Olson, L. and Schroder, J. and Tuminaro, R.,
       "A general interpolation strategy for algebraic
       multigrid using energy minimization", SIAM Journal
       on Scientific Computing (SISC), vol. 33, pp.
       966--991, 2011.

    """
    if not (isspmatrix_csr(A) or isspmatrix_bsr(A)):
        try:
            A = csr_matrix(A)
            warn('Implicit conversion of A to CSR',
                 SparseEfficiencyWarning)
        except BaseException as e:
            raise TypeError('Argument A must have type csr_matrix, '
                            'bsr_matrix, or be convertible to csr_matrix') from e

    A = A.asfptype()

    if symmetry not in ('symmetric', 'hermitian', 'nonsymmetric'):
        raise ValueError('Expected "symmetric", "nonsymmetric" '
                         'or "hermitian" for the symmetry parameter.')
    A.symmetry = symmetry

    if A.shape[0] != A.shape[1]:
        raise ValueError('expected square matrix')
    # Right near nullspace candidates use constant for each variable as default
    if B is None:
        B = np.kron(np.ones((int(A.shape[0]/get_blocksize(A)), 1), dtype=A.dtype),
                    np.eye(get_blocksize(A)))
    else:
        B = np.asarray(B, dtype=A.dtype)
        if len(B.shape) == 1:
            B = B.reshape(-1, 1)
        if B.shape[0] != A.shape[0]:
            raise ValueError('The near null-space modes B have incorrect \
                              dimensions for matrix A')
        if B.shape[1] < get_blocksize(A):
            raise ValueError('B.shape[1] must be >= the blocksize of A')

    # Left near nullspace candidates
    if A.symmetry == 'nonsymmetric':
        if BH is None:
            BH = B.copy()
        else:
            BH = np.asarray(BH, dtype=A.dtype)
            if len(BH.shape) == 1:
                BH = BH.reshape(-1, 1)
            if BH.shape[1] != B.shape[1]:
                raise ValueError('The number of left and right near \
                                  null-space modes B and BH, must be equal')
            if BH.shape[0] != A.shape[0]:
                raise ValueError('The near null-space modes BH have \
                                  incorrect dimensions for matrix A')

    # Levelize the user parameters, so that they become lists describing the
    # desired user option on each level.
    max_levels, max_coarse, strength =\
        levelize_strength_or_aggregation(strength, max_levels, max_coarse)
    max_levels, max_coarse, aggregate =\
        levelize_strength_or_aggregation(aggregate, max_levels, max_coarse)
    improve_candidates =\
        levelize_smooth_or_improve_candidates(improve_candidates, max_levels)
    smooth = levelize_smooth_or_improve_candidates(smooth, max_levels)

    # Construct multilevel structure
    levels = []
    levels.append(MultilevelSolver.Level())
    levels[-1].A = A          # matrix

    # Append near nullspace candidates
    levels[-1].B = B          # right candidates
    if A.symmetry == 'nonsymmetric':
        levels[-1].BH = BH    # left candidates

    while len(levels) < max_levels and \
            int(levels[-1].A.shape[0]/get_blocksize(levels[-1].A)) > max_coarse:
        _extend_hierarchy(levels, strength, aggregate, smooth,
                          improve_candidates, diagonal_dominance, keep)

    ml = MultilevelSolver(levels, **kwargs)
    change_smoothers(ml, presmoother, postsmoother)
    return ml
def rootnode_solver ( A , B = None , BH = None , symmetry = 'hermitian' , strength = 'symmetric' , aggregate = 'standard' , smooth = 'energy' , presmoother = ( 'block_gauss_seidel' , { 'sweep' : 'symmetric' } ) , postsmoother = ( 'block_gauss_seidel' , { 'sweep' : 'symmetric' } ) , improve_candidates = ( 'block_gauss_seidel' , { 'sweep' : 'symmetric' , 'iterations' : 4 } ) , max_levels = 10 , max_coarse = 10 , diagonal_dominance = False , keep = False , * * kwargs ) : if not ( isspmatrix_csr ( A ) or isspmatrix_bsr ( A ) ) : try : A = csr_matrix ( A ) warn ( 'Implicit conversion of A to CSR' , SparseEfficiencyWarning ) except BaseException as e : raise TypeError ( 'Argument A must have type csr_matrix, ' 'bsr_matrix, or be convertible to csr_matrix' ) from e A = A . asfptype ( ) if symmetry not in ( 'symmetric' , 'hermitian' , 'nonsymmetric' ) : raise ValueError ( 'Expected "symmetric", "nonsymmetric" ' 'or "hermitian" for the symmetry parameter.' ) A . symmetry = symmetry if A . shape [ 0 ] != A . shape [ 1 ] : raise ValueError ( 'expected square matrix' ) # Right near nullspace candidates use constant for each variable as default if B is None : B = np . kron ( np . ones ( ( int ( A . shape [ 0 ] / get_blocksize ( A ) ) , 1 ) , dtype = A . dtype ) , np . eye ( get_blocksize ( A ) ) ) else : B = np . asarray ( B , dtype = A . dtype ) if len ( B . shape ) == 1 : B = B . reshape ( - 1 , 1 ) if B . shape [ 0 ] != A . shape [ 0 ] : raise ValueError ( 'The near null-space modes B have incorrect \
                              dimensions for matrix A' ) if B . shape [ 1 ] < get_blocksize ( A ) : raise ValueError ( 'B.shape[1] must be >= the blocksize of A' ) # Left near nullspace candidates if A . symmetry == 'nonsymmetric' : if BH is None : BH = B . copy ( ) else : BH = np . asarray ( BH , dtype = A . dtype ) if len ( BH . shape ) == 1 : BH = BH . reshape ( - 1 , 1 ) if BH . shape [ 1 ] != B . shape [ 1 ] : raise ValueError ( 'The number of left and right near \
                                  null-space modes B and BH, must be equal' ) if BH . shape [ 0 ] != A . shape [ 0 ] : raise ValueError ( 'The near null-space modes BH have \
                                  incorrect dimensions for matrix A' ) # Levelize the user parameters, so that they become lists describing the # desired user option on each level. max_levels , max_coarse , strength = levelize_strength_or_aggregation ( strength , max_levels , max_coarse ) max_levels , max_coarse , aggregate = levelize_strength_or_aggregation ( aggregate , max_levels , max_coarse ) improve_candidates = levelize_smooth_or_improve_candidates ( improve_candidates , max_levels ) smooth = levelize_smooth_or_improve_candidates ( smooth , max_levels ) # Construct multilevel structure levels = [ ] levels . append ( MultilevelSolver . Level ( ) ) levels [ - 1 ] . A = A # matrix # Append near nullspace candidates levels [ - 1 ] . B = B # right candidates if A . symmetry == 'nonsymmetric' : levels [ - 1 ] . BH = BH # left candidates while len ( levels ) < max_levels and int ( levels [ - 1 ] . A . shape [ 0 ] / get_blocksize ( levels [ - 1 ] . A ) ) > max_coarse : _extend_hierarchy ( levels , strength , aggregate , smooth , improve_candidates , diagonal_dominance , keep ) ml = MultilevelSolver ( levels , * * kwargs ) change_smoothers ( ml , presmoother , postsmoother ) return ml