def hierarchy_spectrum(mg, filter=True, plot=False):
    """Examine a multilevel hierarchy's spectrum.

    Parameters
    ----------
    mg { pyamg multilevel hierarchy }
        e.g. generated with smoothed_aggregation_solver(...) or
        ruge_stuben_solver(...)

    Returns
    -------
    (1) table to standard out detailing the spectrum of each level in mg
    (2) if plot==True, a sequence of plots in the complex plane of the
        spectrum at each level

    Notes
    -----
    This can be useful for troubleshooting and when examining how your
    problem's nature changes from level to level

    Examples
    --------
    >>> from pyamg import smoothed_aggregation_solver
    >>> from pyamg.gallery import poisson
    >>> from pyamg.util.utils import hierarchy_spectrum
    >>> A = poisson( (1,), format='csr' )
    >>> ml = smoothed_aggregation_solver(A)
    >>> hierarchy_spectrum(ml)
    <BLANKLINE>
     Level min(re(eig)) max(re(eig)) num re(eig) < 0 num re(eig) > 0 cond_2(A)
    ---------------------------------------------------------------------------
       0      2.000        2.000            0               1         1.00e+00
    <BLANKLINE>
    <BLANKLINE>
     Level min(im(eig)) max(im(eig)) num im(eig) < 0 num im(eig) > 0 cond_2(A)
    ---------------------------------------------------------------------------
       0      0.000        0.000            0               0         1.00e+00
    <BLANKLINE>

    """
    real_table = [['Level', 'min(re(eig))', 'max(re(eig))', 'num re(eig) < 0',
                   'num re(eig) > 0', 'cond_2(A)']]
    imag_table = [['Level', 'min(im(eig))', 'max(im(eig))', 'num im(eig) < 0',
                   'num im(eig) > 0', 'cond_2(A)']]

    for i in range(len(mg.levels)):
        A = mg.levels[i].A.tocsr()

        if filter is True:
            # Filter out any zero rows and columns of A
            A.eliminate_zeros()
            nnz_per_row = A.indptr[0:-1] - A.indptr[1:]
            nonzero_rows = (nnz_per_row != 0).nonzero()[0]
            A = A.tocsc()
            nnz_per_col = A.indptr[0:-1] - A.indptr[1:]
            nonzero_cols = (nnz_per_col != 0).nonzero()[0]
            nonzero_rowcols = sp.union1d(nonzero_rows, nonzero_cols)
            A = np.mat(A.todense())
            A = A[nonzero_rowcols, :][:, nonzero_rowcols]
        else:
            A = np.mat(A.todense())

        e = eigvals(A)
        c = cond(A)
        lambda_min = min(sp.real(e))
        lambda_max = max(sp.real(e))
        num_neg = max(e[sp.real(e) < 0.0].shape)
        num_pos = max(e[sp.real(e) > 0.0].shape)
        real_table.append([str(i), ('%1.3f' % lambda_min),
                           ('%1.3f' % lambda_max),
                           str(num_neg), str(num_pos), ('%1.2e' % c)])

        lambda_min = min(sp.imag(e))
        lambda_max = max(sp.imag(e))
        num_neg = max(e[sp.imag(e) < 0.0].shape)
        num_pos = max(e[sp.imag(e) > 0.0].shape)
        imag_table.append([str(i), ('%1.3f' % lambda_min),
                           ('%1.3f' % lambda_max),
                           str(num_neg), str(num_pos), ('%1.2e' % c)])

        if plot:
            import pylab
            pylab.figure(i+1)
            pylab.plot(sp.real(e), sp.imag(e), 'kx')
            handle = pylab.title('Level %d Spectrum' % i)
            handle.set_fontsize(19)
            handle = pylab.xlabel('real(eig)')
            handle.set_fontsize(17)
            handle = pylab.ylabel('imag(eig)')
            handle.set_fontsize(17)

    print(print_table(real_table))
    print(print_table(imag_table))

    if plot:
        pylab.show()
Examine a multilevel hierarchy's spectrum.

    Parameters
    ----------
    mg { pyamg multilevel hierarchy }
        e.g. generated with smoothed_aggregation_solver(...) or
        ruge_stuben_solver(...)

    Returns
    -------
    (1) table to standard out detailing the spectrum of each level in mg
    (2) if plot==True, a sequence of plots in the complex plane of the
        spectrum at each level

    Notes
    -----
    This can be useful for troubleshooting and when examining how your
    problem's nature changes from level to level

    Examples
    --------
    >>> from pyamg import smoothed_aggregation_solver
    >>> from pyamg.gallery import poisson
    >>> from pyamg.util.utils import hierarchy_spectrum
    >>> A = poisson( (1,), format='csr' )
    >>> ml = smoothed_aggregation_solver(A)
    >>> hierarchy_spectrum(ml)
    <BLANKLINE>
     Level min(re(eig)) max(re(eig)) num re(eig) < 0 num re(eig) > 0 cond_2(A)
    ---------------------------------------------------------------------------
       0      2.000        2.000            0               1         1.00e+00
    <BLANKLINE>
    <BLANKLINE>
     Level min(im(eig)) max(im(eig)) num im(eig) < 0 num im(eig) > 0 cond_2(A)
    ---------------------------------------------------------------------------
       0      0.000        0.000            0               0         1.00e+00
    <BLANKLINE>