(A, initial_candidates=None, symmetry='hermitian',
                       pdef=True, num_candidates=1, candidate_iters=5,
                       improvement_iters=0, epsilon=0.1,
                       max_levels=10, max_coarse=10, aggregate='standard',
                       prepostsmoother=('gauss_seidel',
                                        {'sweep': 'symmetric'}),
                       smooth=('jacobi', {}), strength='symmetric',
                       coarse_solver='pinv',
                       eliminate_local=(False, {'thresh': 1.0}), keep=False,
                       **kwargs)
return [smoothed_aggregation_solver(A, B=B, symmetry=symmetry,
                                        presmoother=prepostsmoother,
                                        postsmoother=prepostsmoother,
                                        smooth=smooth,
                                        coarse_solver=coarse_solver,
                                        aggregate=aggregate, strength=strength,
                                        improve_candidates=None, keep=keep,
                                        **kwargs),
            work[0]/A.nnz]
Create a multilevel solver using Adaptive Smoothed Aggregation (aSA).

    Parameters
    ----------
    A : csr_matrix, bsr_matrix
        Square matrix in CSR or BSR format
    initial_candidates : None, n x m dense matrix
        If a matrix, then this forms the basis for the first m candidates.
        Also in this case, the initial setup stage is skipped, because this
        provides the first candidate(s).  If None, then a random initial guess
        and relaxation are used to inform the initial candidate.
    symmetry : string
        'symmetric' refers to both real and complex symmetric
        'hermitian' refers to both complex Hermitian and real Hermitian
        Note that for the strictly real case, these two options are the same
        Note that this flag does not denote definiteness of the operator
    pdef : bool
        True or False, whether A is known to be positive definite.
    num_candidates : integer
        Number of near-nullspace candidates to generate
    candidate_iters : integer
        Number of smoothing passes/multigrid cycles used at each level of
        the adaptive setup phase
    improvement_iters : integer
        Number of times each candidate is improved
    epsilon : float
        Target convergence factor
    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.
    prepostsmoother : string or dict
        Pre- and post-smoother used in the adaptive method
    strength : ['symmetric', 'classical', 'evolution', None]
        Method used to determine the strength of connection between unknowns of
        the linear system.  See smoothed_aggregation_solver(...) documentation.
        Predefined strength may be used with ('predefined', {'C': csr_matrix}).
    aggregate : ['standard', 'lloyd', 'naive', ('predefined', {'AggOp': csr_matrix})]
        Method used to aggregate nodes.  See smoothed_aggregation_solver(...)
        documentation.
    smooth : ['jacobi', 'richardson', 'energy', None]
        Method used used to smooth the tentative prolongator.  See
        smoothed_aggregation_solver(...) documentation
    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.
    eliminate_local : tuple
        Length 2 tuple.  If the first entry is True, then eliminate candidates
        where they aren't needed locally, using the second entry of the tuple
        to contain arguments to local elimination routine.  Given the rigid
        sparse data structures, this doesn't help much, if at all, with
        complexity.  Its more of a diagnostic utility.
    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), and aggregation (AggOp) are kept.

    Returns
    -------
    MultilevelSolver : MultilevelSolver
        Smoothed aggregation solver with adaptively generated candidates

    Notes
    -----
    - Floating point value representing the 'work' required to generate
      the solver.  This value is the total cost of just relaxation, relative
      to the fine grid.  The relaxation method used is assumed to symmetric
      Gauss-Seidel.

    - Unlike the standard Smoothed Aggregation (SA) method, adaptive SA does
      not require knowledge of near-nullspace candidate vectors.  Instead, an
      adaptive procedure computes one or more candidates 'from scratch'.  This
      approach is useful when no candidates are known or the candidates have
      been invalidated due to changes to matrix A.

    Examples
    --------
    >>> from pyamg.gallery import stencil_grid
    >>> from pyamg.aggregation import adaptive_sa_solver
    >>> import numpy as np
    >>> A=stencil_grid([[-1,-1,-1],[-1,8.0,-1],[-1,-1,-1]], (31,31),format='csr')
    >>> [asa,work] = adaptive_sa_solver(A,num_candidates=1)
    >>> res=[]
    >>> x=asa.solve(b=np.ones((A.shape[0],)), x0=np.ones((A.shape[0],)), residuals=res)

    References
    ----------
    .. [1] Brezina, Falgout, MacLachlan, Manteuffel, McCormick, and Ruge
       "Adaptive Smoothed Aggregation (alpha SA) Multigrid"
       SIAM Review Volume 47,  Issue 2  (2005)
Create a multilevel solver using Adaptive Smoothed Aggregation (aSA).
Create a multilevel solver using Adaptive Smoothed Aggregation ( aSA ) .
def adaptive_sa_solver(A, initial_candidates=None, symmetry='hermitian',
                       pdef=True, num_candidates=1, candidate_iters=5,
                       improvement_iters=0, epsilon=0.1,
                       max_levels=10, max_coarse=10, aggregate='standard',
                       prepostsmoother=('gauss_seidel',
                                        {'sweep': 'symmetric'}),
                       smooth=('jacobi', {}), strength='symmetric',
                       coarse_solver='pinv',
                       eliminate_local=(False, {'thresh': 1.0}), keep=False,
                       **kwargs):
    """Create a multilevel solver using Adaptive Smoothed Aggregation (aSA).

    Parameters
    ----------
    A : csr_matrix, bsr_matrix
        Square matrix in CSR or BSR format
    initial_candidates : None, n x m dense matrix
        If a matrix, then this forms the basis for the first m candidates.
        Also in this case, the initial setup stage is skipped, because this
        provides the first candidate(s).  If None, then a random initial guess
        and relaxation are used to inform the initial candidate.
    symmetry : string
        'symmetric' refers to both real and complex symmetric
        'hermitian' refers to both complex Hermitian and real Hermitian
        Note that for the strictly real case, these two options are the same
        Note that this flag does not denote definiteness of the operator
    pdef : bool
        True or False, whether A is known to be positive definite.
    num_candidates : integer
        Number of near-nullspace candidates to generate
    candidate_iters : integer
        Number of smoothing passes/multigrid cycles used at each level of
        the adaptive setup phase
    improvement_iters : integer
        Number of times each candidate is improved
    epsilon : float
        Target convergence factor
    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.
    prepostsmoother : string or dict
        Pre- and post-smoother used in the adaptive method
    strength : ['symmetric', 'classical', 'evolution', None]
        Method used to determine the strength of connection between unknowns of
        the linear system.  See smoothed_aggregation_solver(...) documentation.
        Predefined strength may be used with ('predefined', {'C': csr_matrix}).
    aggregate : ['standard', 'lloyd', 'naive', ('predefined', {'AggOp': csr_matrix})]
        Method used to aggregate nodes.  See smoothed_aggregation_solver(...)
        documentation.
    smooth : ['jacobi', 'richardson', 'energy', None]
        Method used used to smooth the tentative prolongator.  See
        smoothed_aggregation_solver(...) documentation
    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.
    eliminate_local : tuple
        Length 2 tuple.  If the first entry is True, then eliminate candidates
        where they aren't needed locally, using the second entry of the tuple
        to contain arguments to local elimination routine.  Given the rigid
        sparse data structures, this doesn't help much, if at all, with
        complexity.  Its more of a diagnostic utility.
    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), and aggregation (AggOp) are kept.

    Returns
    -------
    MultilevelSolver : MultilevelSolver
        Smoothed aggregation solver with adaptively generated candidates

    Notes
    -----
    - Floating point value representing the 'work' required to generate
      the solver.  This value is the total cost of just relaxation, relative
      to the fine grid.  The relaxation method used is assumed to symmetric
      Gauss-Seidel.

    - Unlike the standard Smoothed Aggregation (SA) method, adaptive SA does
      not require knowledge of near-nullspace candidate vectors.  Instead, an
      adaptive procedure computes one or more candidates 'from scratch'.  This
      approach is useful when no candidates are known or the candidates have
      been invalidated due to changes to matrix A.

    Examples
    --------
    >>> from pyamg.gallery import stencil_grid
    >>> from pyamg.aggregation import adaptive_sa_solver
    >>> import numpy as np
    >>> A=stencil_grid([[-1,-1,-1],[-1,8.0,-1],[-1,-1,-1]], (31,31),format='csr')
    >>> [asa,work] = adaptive_sa_solver(A,num_candidates=1)
    >>> res=[]
    >>> x=asa.solve(b=np.ones((A.shape[0],)), x0=np.ones((A.shape[0],)), residuals=res)

    References
    ----------
    .. [1] Brezina, Falgout, MacLachlan, Manteuffel, McCormick, and Ruge
       "Adaptive Smoothed Aggregation (alpha SA) Multigrid"
       SIAM Review Volume 47,  Issue 2  (2005)

    """
    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 or '
                            'bsr_matrix, or be convertible to csr_matrix') from e

    A = A.asfptype()
    if A.shape[0] != A.shape[1]:
        raise ValueError('expected square matrix')

    # Track work in terms of relaxation
    work = np.zeros((1,))

    # 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)
    smooth = levelize_smooth_or_improve_candidates(smooth, max_levels)

    # Develop initial candidate(s).  Note that any predefined aggregation is
    # preserved.
    if initial_candidates is None:
        B, aggregate, strength =\
            initial_setup_stage(A, symmetry, pdef, candidate_iters, epsilon,
                                max_levels, max_coarse, aggregate,
                                prepostsmoother, smooth, strength, work)
        # Normalize B
        B = (1.0/norm(B, 'inf')) * B
        num_candidates -= 1
    else:
        # Otherwise, use predefined candidates
        B = initial_candidates
        num_candidates -= B.shape[1]
        # Generate Aggregation and Strength Operators (the brute force way)
        sa = smoothed_aggregation_solver(A, B=B, symmetry=symmetry,
                                         presmoother=prepostsmoother,
                                         postsmoother=prepostsmoother,
                                         smooth=smooth, strength=strength,
                                         max_levels=max_levels,
                                         max_coarse=max_coarse,
                                         aggregate=aggregate,
                                         coarse_solver=coarse_solver,
                                         improve_candidates=None, keep=True,
                                         **kwargs)
        if len(sa.levels) > 1:
            # Set strength-of-connection and aggregation
            aggregate = [('predefined', {'AggOp': sa.levels[i].AggOp.tocsr()})
                         for i in range(len(sa.levels) - 1)]
            strength = [('predefined', {'C': sa.levels[i].C.tocsr()})
                        for i in range(len(sa.levels) - 1)]

    # Develop additional candidates
    for i in range(num_candidates):
        x = general_setup_stage(
            smoothed_aggregation_solver(A, B=B, symmetry=symmetry,
                                        presmoother=prepostsmoother,
                                        postsmoother=prepostsmoother,
                                        smooth=smooth,
                                        coarse_solver=coarse_solver,
                                        aggregate=aggregate,
                                        strength=strength,
                                        improve_candidates=None,
                                        keep=True, **kwargs),
            symmetry, candidate_iters, prepostsmoother, smooth,
            eliminate_local, coarse_solver, work)

        # Normalize x and add to candidate list
        x = x/norm(x, 'inf')
        if np.isinf(x[0]) or np.isnan(x[0]):
            raise ValueError(f'The {i}th adaptive candidate is all 0.')
        B = np.hstack((B, x.reshape(-1, 1)))

    # Improve candidates
    if B.shape[1] > 1 and improvement_iters > 0:
        b = np.zeros((A.shape[0], 1), dtype=A.dtype)
        for _i in range(improvement_iters):
            for j in range(B.shape[1]):
                # Run a V-cycle built on everything except candidate j, while
                # using candidate j as the initial guess
                x0 = B[:, 0]
                B = B[:, 1:]
                sa_temp =\
                    smoothed_aggregation_solver(A, B=B, symmetry=symmetry,
                                                presmoother=prepostsmoother,
                                                postsmoother=prepostsmoother,
                                                smooth=smooth,
                                                coarse_solver=coarse_solver,
                                                aggregate=aggregate,
                                                strength=strength,
                                                improve_candidates=None,
                                                keep=True, **kwargs)
                x = sa_temp.solve(b, x0=x0,
                                  tol=1e-20,
                                  maxiter=candidate_iters, cycle='V')
                work[:] += 2 * sa_temp.operator_complexity() *\
                    sa_temp.levels[0].A.nnz * candidate_iters

                # Apply local elimination
                elim, elim_kwargs = unpack_arg(eliminate_local)
                if elim is True:
                    x = x/norm(x, 'inf')
                    eliminate_local_candidates(x, sa_temp.levels[0].AggOp, A,
                                               sa_temp.levels[0].T,
                                               **elim_kwargs)

                # Normalize x and add to candidate list
                x = x/norm(x, 'inf')
                if np.isinf(x[0]) or np.isnan(x[0]):
                    raise ValueError(f'The {j}th improved adaptive candidate is all 0.')
                B = np.hstack((B, x.reshape(-1, 1)))

    elif improvement_iters > 0:
        # Special case for improving a single candidate
        max_levels = len(aggregate) + 1
        max_coarse = 0
        for _i in range(improvement_iters):
            B, aggregate, strength =\
                initial_setup_stage(A, symmetry, pdef, candidate_iters,
                                    epsilon, max_levels, max_coarse,
                                    aggregate, prepostsmoother, smooth,
                                    strength, work, initial_candidate=B)
            # Normalize B
            B = (1.0/norm(B, 'inf'))*B

    return [smoothed_aggregation_solver(A, B=B, symmetry=symmetry,
                                        presmoother=prepostsmoother,
                                        postsmoother=prepostsmoother,
                                        smooth=smooth,
                                        coarse_solver=coarse_solver,
                                        aggregate=aggregate, strength=strength,
                                        improve_candidates=None, keep=keep,
                                        **kwargs),
            work[0]/A.nnz]
def adaptive_sa_solver ( A , initial_candidates = None , symmetry = 'hermitian' , pdef = True , num_candidates = 1 , candidate_iters = 5 , improvement_iters = 0 , epsilon = 0.1 , max_levels = 10 , max_coarse = 10 , aggregate = 'standard' , prepostsmoother = ( 'gauss_seidel' , { 'sweep' : 'symmetric' } ) , smooth = ( 'jacobi' , { } ) , strength = 'symmetric' , coarse_solver = 'pinv' , eliminate_local = ( False , { 'thresh' : 1.0 } ) , 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 or ' 'bsr_matrix, or be convertible to csr_matrix' ) from e A = A . asfptype ( ) if A . shape [ 0 ] != A . shape [ 1 ] : raise ValueError ( 'expected square matrix' ) # Track work in terms of relaxation work = np . zeros ( ( 1 , ) ) # 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 ) smooth = levelize_smooth_or_improve_candidates ( smooth , max_levels ) # Develop initial candidate(s).  Note that any predefined aggregation is # preserved. if initial_candidates is None : B , aggregate , strength = initial_setup_stage ( A , symmetry , pdef , candidate_iters , epsilon , max_levels , max_coarse , aggregate , prepostsmoother , smooth , strength , work ) # Normalize B B = ( 1.0 / norm ( B , 'inf' ) ) * B num_candidates -= 1 else : # Otherwise, use predefined candidates B = initial_candidates num_candidates -= B . shape [ 1 ] # Generate Aggregation and Strength Operators (the brute force way) sa = smoothed_aggregation_solver ( A , B = B , symmetry = symmetry , presmoother = prepostsmoother , postsmoother = prepostsmoother , smooth = smooth , strength = strength , max_levels = max_levels , max_coarse = max_coarse , aggregate = aggregate , coarse_solver = coarse_solver , improve_candidates = None , keep = True , * * kwargs ) if len ( sa . levels ) > 1 : # Set strength-of-connection and aggregation aggregate = [ ( 'predefined' , { 'AggOp' : sa . levels [ i ] . AggOp . tocsr ( ) } ) for i in range ( len ( sa . levels ) - 1 ) ] strength = [ ( 'predefined' , { 'C' : sa . levels [ i ] . C . tocsr ( ) } ) for i in range ( len ( sa . levels ) - 1 ) ] # Develop additional candidates for i in range ( num_candidates ) : x = general_setup_stage ( smoothed_aggregation_solver ( A , B = B , symmetry = symmetry , presmoother = prepostsmoother , postsmoother = prepostsmoother , smooth = smooth , coarse_solver = coarse_solver , aggregate = aggregate , strength = strength , improve_candidates = None , keep = True , * * kwargs ) , symmetry , candidate_iters , prepostsmoother , smooth , eliminate_local , coarse_solver , work ) # Normalize x and add to candidate list x = x / norm ( x , 'inf' ) if np . isinf ( x [ 0 ] ) or np . isnan ( x [ 0 ] ) : raise ValueError ( f'The {i}th adaptive candidate is all 0.' ) B = np . hstack ( ( B , x . reshape ( - 1 , 1 ) ) ) # Improve candidates if B . shape [ 1 ] > 1 and improvement_iters > 0 : b = np . zeros ( ( A . shape [ 0 ] , 1 ) , dtype = A . dtype ) for _i in range ( improvement_iters ) : for j in range ( B . shape [ 1 ] ) : # Run a V-cycle built on everything except candidate j, while # using candidate j as the initial guess x0 = B [ : , 0 ] B = B [ : , 1 : ] sa_temp = smoothed_aggregation_solver ( A , B = B , symmetry = symmetry , presmoother = prepostsmoother , postsmoother = prepostsmoother , smooth = smooth , coarse_solver = coarse_solver , aggregate = aggregate , strength = strength , improve_candidates = None , keep = True , * * kwargs ) x = sa_temp . solve ( b , x0 = x0 , tol = 1e-20 , maxiter = candidate_iters , cycle = 'V' ) work [ : ] += 2 * sa_temp . operator_complexity ( ) * sa_temp . levels [ 0 ] . A . nnz * candidate_iters # Apply local elimination elim , elim_kwargs = unpack_arg ( eliminate_local ) if elim is True : x = x / norm ( x , 'inf' ) eliminate_local_candidates ( x , sa_temp . levels [ 0 ] . AggOp , A , sa_temp . levels [ 0 ] . T , * * elim_kwargs ) # Normalize x and add to candidate list x = x / norm ( x , 'inf' ) if np . isinf ( x [ 0 ] ) or np . isnan ( x [ 0 ] ) : raise ValueError ( f'The {j}th improved adaptive candidate is all 0.' ) B = np . hstack ( ( B , x . reshape ( - 1 , 1 ) ) ) elif improvement_iters > 0 : # Special case for improving a single candidate max_levels = len ( aggregate ) + 1 max_coarse = 0 for _i in range ( improvement_iters ) : B , aggregate , strength = initial_setup_stage ( A , symmetry , pdef , candidate_iters , epsilon , max_levels , max_coarse , aggregate , prepostsmoother , smooth , strength , work , initial_candidate = B ) # Normalize B B = ( 1.0 / norm ( B , 'inf' ) ) * B return [ smoothed_aggregation_solver ( A , B = B , symmetry = symmetry , presmoother = prepostsmoother , postsmoother = prepostsmoother , smooth = smooth , coarse_solver = coarse_solver , aggregate = aggregate , strength = strength , improve_candidates = None , keep = keep , * * kwargs ) , work [ 0 ] / A . nnz ]