Example #1
0
    def test_coarse_solver_opts(self):
        # these tests are meant to test whether coarse solvers are correctly
        # passed parameters

        A = poisson((30, 30), format='csr')
        b = rand(A.shape[0], 1)

        # for each pair, the first entry should yield an SA solver that
        # converges in fewer iterations for a basic Poisson problem
        coarse_solver_pairs = [(('jacobi', {'iterations': 30}), 'jacobi')]
        coarse_solver_pairs.append((('gauss_seidel', {'iterations': 30}),
                                    'gauss_seidel'))
        coarse_solver_pairs.append(('gauss_seidel', 'jacobi'))
        coarse_solver_pairs.append(('cg', ('cg', {'tol': 10.0})))
        coarse_solver_pairs.append(('pinv2', ('pinv2', {'cond': 1.0})))

        for coarse1, coarse2 in coarse_solver_pairs:
            r1 = []
            r2 = []
            sa1 = smoothed_aggregation_solver(A, coarse_solver=coarse1)
            sa2 = smoothed_aggregation_solver(A, coarse_solver=coarse2)
            x1 = sa1.solve(b, residuals=r1)
            x2 = sa2.solve(b, residuals=r2)
            del x1, x2
            assert((len(r1) + 5) < len(r2))
Example #2
0
    def test_nonhermitian(self):
        # problem data
        data = load_example('helmholtz_2D')
        A = data['A'].tocsr()
        B = data['B']
        numpy.random.seed(625)
        x0 = scipy.rand(A.shape[0]) + 1.0j * scipy.rand(A.shape[0])
        b = A * scipy.rand(A.shape[0]) + 1.0j * (A * scipy.rand(A.shape[0]))
        # solver parameters
        smooth = ('energy', {'krylov': 'gmres'})
        SA_build_args = {'max_coarse': 25, 'coarse_solver': 'pinv2',
                         'symmetry': 'symmetric'}
        SA_solve_args = {'cycle': 'V', 'maxiter': 20, 'tol': 1e-8}
        strength = [('evolution', {'k': 2, 'epsilon': 2.0})]
        smoother = ('gauss_seidel_nr', {'sweep': 'symmetric', 'iterations': 1})
        # Construct solver with nonsymmetric parameters
        sa = smoothed_aggregation_solver(A, B=B, smooth=smooth,
                                         strength=strength,
                                         presmoother=smoother,
                                         postsmoother=smoother,
                                         **SA_build_args)
        residuals = []
        # stand-alone solve
        x = sa.solve(b, x0=x0, residuals=residuals, **SA_solve_args)
        residuals = array(residuals)
        avg_convergence_ratio =\
            (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
        assert(avg_convergence_ratio < 0.85)
        # accelerated solve
        residuals = []
        x = sa.solve(b, x0=x0, residuals=residuals, accel='gmres',
                     **SA_solve_args)
        del x
        residuals = array(residuals)
        avg_convergence_ratio =\
            (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
        assert(avg_convergence_ratio < 0.6)

        # test that nonsymmetric parameters give the same result as symmetric
        # parameters for the complex-symmetric matrix A
        strength = 'symmetric'
        SA_build_args['symmetry'] = 'nonsymmetric'
        sa_nonsymm = smoothed_aggregation_solver(A, B=ones((A.shape[0], 1)),
                                                 smooth=smooth,
                                                 strength=strength,
                                                 presmoother=smoother,
                                                 postsmoother=smoother,
                                                 improve_candidates=None,
                                                 **SA_build_args)
        SA_build_args['symmetry'] = 'symmetric'
        sa_symm = smoothed_aggregation_solver(A, B=ones((A.shape[0], 1)),
                                              smooth=smooth,
                                              strength=strength,
                                              presmoother=smoother,
                                              postsmoother=smoother,
                                              improve_candidates=None,
                                              **SA_build_args)
        for (symm_lvl, nonsymm_lvl) in zip(sa_nonsymm.levels, sa_symm.levels):
            assert_array_almost_equal(symm_lvl.A.todense(),
                                      nonsymm_lvl.A.todense())
    def test_nonhermitian(self):
        # problem data
        data = load_example("helmholtz_2D")
        A = data["A"].tocsr()
        B = data["B"]
        numpy.random.seed(625)
        x0 = scipy.rand(A.shape[0]) + 1.0j * scipy.rand(A.shape[0])
        b = A * scipy.rand(A.shape[0]) + 1.0j * (A * scipy.rand(A.shape[0]))
        # solver parameters
        smooth = ("energy", {"krylov": "gmres"})
        SA_build_args = {"max_coarse": 25, "coarse_solver": "pinv2", "symmetry": "symmetric"}
        SA_solve_args = {"cycle": "V", "maxiter": 20, "tol": 1e-8}
        strength = [("evolution", {"k": 2, "epsilon": 2.0})]
        smoother = ("gauss_seidel_nr", {"sweep": "symmetric", "iterations": 1})
        # Construct solver with nonsymmetric parameters
        sa = smoothed_aggregation_solver(
            A, B=B, smooth=smooth, strength=strength, presmoother=smoother, postsmoother=smoother, **SA_build_args
        )
        residuals = []
        # stand-alone solve
        x = sa.solve(b, x0=x0, residuals=residuals, **SA_solve_args)
        residuals = array(residuals)
        avg_convergence_ratio = (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
        assert avg_convergence_ratio < 0.85
        # accelerated solve
        residuals = []
        x = sa.solve(b, x0=x0, residuals=residuals, accel="gmres", **SA_solve_args)
        residuals = array(residuals)
        avg_convergence_ratio = (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
        assert avg_convergence_ratio < 0.6

        # test that nonsymmetric parameters give the same result as symmetric
        # parameters for the complex-symmetric matrix A
        strength = "symmetric"
        SA_build_args["symmetry"] = "nonsymmetric"
        sa_nonsymm = smoothed_aggregation_solver(
            A,
            B=ones((A.shape[0], 1)),
            smooth=smooth,
            strength=strength,
            presmoother=smoother,
            postsmoother=smoother,
            improve_candidates=None,
            **SA_build_args
        )
        SA_build_args["symmetry"] = "symmetric"
        sa_symm = smoothed_aggregation_solver(
            A,
            B=ones((A.shape[0], 1)),
            smooth=smooth,
            strength=strength,
            presmoother=smoother,
            postsmoother=smoother,
            improve_candidates=None,
            **SA_build_args
        )
        for (symm_lvl, nonsymm_lvl) in zip(sa_nonsymm.levels, sa_symm.levels):
            assert_array_almost_equal(symm_lvl.A.todense(), nonsymm_lvl.A.todense())
    def test_matrix_formats(self):

        # Do dense, csr, bsr and csc versions of A all yield the same solver
        A = poisson((7, 7), format="csr")
        cases = [A.tobsr(blocksize=(1, 1))]
        cases.append(A.tocsc())
        cases.append(A.todense())

        sa_old = smoothed_aggregation_solver(A, max_coarse=10)
        for AA in cases:
            sa_new = smoothed_aggregation_solver(AA, max_coarse=10)
            assert abs(ravel(sa_old.levels[-1].A.todense() - sa_new.levels[-1].A.todense())).max() < 0.01
            sa_old = sa_new
    def test_improve_candidates(self):

        # test improve_candidates for the Poisson problem and elasticity, where
        # rho_scale is the amount that each successive improve_candidates
        # option should improve convergence over the previous
        # improve_candidates option.
        improve_candidates_list = [None, [("block_gauss_seidel", {"iterations": 4, "sweep": "symmetric"})]]
        # make tests repeatable
        numpy.random.seed(0)

        cases = []
        A_elas, B_elas = linear_elasticity((60, 60), format="bsr")
        # Matrix, Candidates, rho_scale
        cases.append((poisson((61, 61), format="csr"), ones((61 * 61, 1)), 0.9))
        cases.append((A_elas, B_elas, 0.9))
        for (A, B, rho_scale) in cases:
            last_rho = -1.0
            x0 = rand(A.shape[0], 1)
            b = rand(A.shape[0], 1)
            for ic in improve_candidates_list:
                ml = smoothed_aggregation_solver(A, B, max_coarse=10, improve_candidates=ic)
                residuals = []
                x_sol = ml.solve(b, x0=x0, maxiter=20, tol=1e-10, residuals=residuals)
                rho = (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
                if last_rho == -1.0:
                    last_rho = rho
                else:
                    # each successive improve_candidates option should be an
                    # improvement on the previous print "\nimprove_candidates
                    # Test: %1.3e, %1.3e,
                    # %d\n"%(rho,rho_scale*last_rho,A.shape[0])
                    assert rho < rho_scale * last_rho
                    last_rho = rho
Example #6
0
    def test_symmetry(self):
        # Test that a basic V-cycle yields a symmetric linear operator.  Common
        # reasons for failure are problems with using the same rho for the
        # pres/post-smoothers and using the same block_D_inv for
        # pre/post-smoothers.

        n = 500
        A = poisson((n,), format='csr')
        smoothers = [('gauss_seidel', {'sweep': 'symmetric'}),
                     ('schwarz', {'sweep': 'symmetric'}),
                     ('block_gauss_seidel', {'sweep': 'symmetric'}),
                     'jacobi', 'block_jacobi']
        rng = np.arange(1, n + 1, dtype='float').reshape(-1, 1)
        Bs = [np.ones((n, 1)), sp.hstack((np.ones((n, 1)), rng))]

        # TODO:
        # why does python 3 require significant=6 while python 2 passes
        # why does python 3 yield a different dot() below than python 2
        # only for: ('gauss_seidel', {'sweep': 'symmetric'})
        for smoother in smoothers:
            for B in Bs:
                ml = smoothed_aggregation_solver(A, B, max_coarse=10,
                                                 presmoother=smoother,
                                                 postsmoother=smoother)
                P = ml.aspreconditioner()
                np.random.seed(0)
                x = sp.rand(n,)
                y = sp.rand(n,)
                out = (np.dot(P * x, y), np.dot(x, P * y))
                # print("smoother = %s %g %g" % (smoother, out[0], out[1]))
                assert_approx_equal(out[0], out[1])
    def test_symmetry(self):
        # Test that a basic V-cycle yields a symmetric linear operator.  Common
        # reasons for failure are problems with using the same rho for the
        # pres/post-smoothers and using the same block_D_inv for
        # pre/post-smoothers.

        n = 500
        A = poisson((n,), format="csr")
        smoothers = [
            ("gauss_seidel", {"sweep": "symmetric"}),
            ("schwarz", {"sweep": "symmetric"}),
            ("block_gauss_seidel", {"sweep": "symmetric"}),
            "jacobi",
            "block_jacobi",
        ]
        rng = arange(1, n + 1, dtype="float").reshape(-1, 1)
        Bs = [ones((n, 1)), hstack((ones((n, 1)), rng))]

        for smoother in smoothers:
            for B in Bs:
                ml = smoothed_aggregation_solver(A, B, max_coarse=10, presmoother=smoother, postsmoother=smoother)
                P = ml.aspreconditioner()
                x = rand(n)
                y = rand(n)
                assert_approx_equal(dot(P * x, y), dot(x, P * y))
Example #8
0
    def test_DAD(self):
        A = poisson((50, 50), format='csr')

        x = rand(A.shape[0])
        b = rand(A.shape[0])

        D = diag_sparse(1.0 / sqrt(10 ** (12 * rand(A.shape[0]) - 6))).tocsr()
        D_inv = diag_sparse(1.0 / D.data)

        # DAD = D * A * D

        B = ones((A.shape[0], 1))

        # TODO force 2 level method and check that result is the same
        kwargs = {'max_coarse': 1, 'max_levels': 2, 'coarse_solver': 'splu'}

        sa = smoothed_aggregation_solver(D * A * D, D_inv * B, **kwargs)

        residuals = []
        x_sol = sa.solve(b, x0=x, maxiter=10, tol=1e-12, residuals=residuals)
        del x_sol

        avg_convergence_ratio =\
            (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))

        # print "Diagonal Scaling Test:   %1.3e,  %1.3e" %
        # (avg_convergence_ratio, 0.25)
        assert(avg_convergence_ratio < 0.25)
Example #9
0
    def test_basic(self):
        """check that method converges at a reasonable rate"""

        for A, B, c_factor, symmetry, smooth in self.cases:
            A = csr_matrix(A)

            ml = smoothed_aggregation_solver(A, B, symmetry=symmetry,
                                             smooth=smooth, max_coarse=10)

            numpy.random.seed(0)  # make tests repeatable

            x = rand(A.shape[0]) + 1.0j * rand(A.shape[0])
            b = A * rand(A.shape[0])
            residuals = []

            x_sol = ml.solve(b, x0=x, maxiter=20, tol=1e-10,
                             residuals=residuals)
            del x_sol

            avg_convergence_ratio =\
                (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))

            # print "Complex Test:   %1.3e,  %1.3e,  %d,  %1.3e" % \
            #    (avg_convergence_ratio, c_factor,
            #     len(ml.levels), ml.operator_complexity())
            assert(avg_convergence_ratio < c_factor)
    def run_cases(self, opts):
        for A, B in self.cases:
            ml = smoothed_aggregation_solver(A, B, max_coarse=5, **opts)

            numpy.random.seed(0)  # make tests repeatable

            x = rand(A.shape[0])
            b = A * rand(A.shape[0])

            residuals = []
            x_sol = ml.solve(b, x0=x, maxiter=30, tol=1e-10, residuals=residuals)
            convergence_ratio = (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
            assert convergence_ratio < 0.9
    def test_coarse_solver_opts(self):
        # these tests are meant to test whether coarse solvers are correctly
        # passed parameters

        A = poisson((30, 30), format="csr")
        b = rand(A.shape[0], 1)

        # for each pair, the first entry should yield an SA solver that
        # converges in fewer iterations for a basic Poisson problem
        coarse_solver_pairs = [(("jacobi", {"iterations": 30}), "jacobi")]
        coarse_solver_pairs.append((("gauss_seidel", {"iterations": 30}), "gauss_seidel"))
        coarse_solver_pairs.append(("gauss_seidel", "jacobi"))
        coarse_solver_pairs.append(("cg", ("cg", {"tol": 10.0})))
        coarse_solver_pairs.append(("pinv2", ("pinv2", {"cond": 1.0})))

        for coarse1, coarse2 in coarse_solver_pairs:
            r1 = []
            r2 = []
            sa1 = smoothed_aggregation_solver(A, coarse_solver=coarse1)
            sa2 = smoothed_aggregation_solver(A, coarse_solver=coarse2)
            x1 = sa1.solve(b, residuals=r1)
            x2 = sa2.solve(b, residuals=r2)
            assert (len(r1) + 5) < len(r2)
Example #12
0
    def test_improve_candidates(self):

        # test improve_candidates for the Poisson problem and elasticity, where
        # rho_scale is the amount that each successive improve_candidates
        # option should improve convergence over the previous
        # improve_candidates option.
        improve_candidates_list = [
            None,
            [('block_gauss_seidel', {
                'iterations': 4,
                'sweep': 'symmetric'
            })]
        ]
        # make tests repeatable
        numpy.random.seed(0)

        cases = []
        A_elas, B_elas = linear_elasticity((60, 60), format='bsr')
        # Matrix, Candidates, rho_scale
        cases.append((poisson((61, 61), format='csr'), ones(
            (61 * 61, 1)), 0.9))
        cases.append((A_elas, B_elas, 0.9))
        for (A, B, rho_scale) in cases:
            last_rho = -1.0
            x0 = rand(A.shape[0], 1)
            b = rand(A.shape[0], 1)
            for ic in improve_candidates_list:
                ml = smoothed_aggregation_solver(A,
                                                 B,
                                                 max_coarse=10,
                                                 improve_candidates=ic)
                residuals = []
                x_sol = ml.solve(b,
                                 x0=x0,
                                 maxiter=20,
                                 tol=1e-10,
                                 residuals=residuals)
                del x_sol
                rho = (residuals[-1] / residuals[0])**(1.0 / len(residuals))
                if last_rho == -1.0:
                    last_rho = rho
                else:
                    # each successive improve_candidates option should be an
                    # improvement on the previous print "\nimprove_candidates
                    # Test: %1.3e, %1.3e,
                    # %d\n"%(rho,rho_scale*last_rho,A.shape[0])
                    assert (rho < rho_scale * last_rho)
                    last_rho = rho
    def run_cases(self, opts):
        for A, B in self.cases:
            ml = smoothed_aggregation_solver(A, B, max_coarse=5, **opts)

            np.random.seed(1883275855)  # make tests repeatable

            x = np.random.rand(A.shape[0])
            b = A * np.random.rand(A.shape[0])

            residuals = []
            x_sol = ml.solve(b, x0=x, maxiter=30, tol=1e-10,
                             residuals=residuals)
            del x_sol
            convergence_ratio =\
                (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
            assert(convergence_ratio < 0.9)
Example #14
0
    def test_symmetry(self):
        # Test that a basic V-cycle yields a symmetric linear operator.  Common
        # reasons for failure are problems with using the same rho for the
        # pres/post-smoothers and using the same block_D_inv for
        # pre/post-smoothers.

        n = 500
        A = poisson((n, ), format='csr')
        smoothers = [('gauss_seidel',{'sweep':'symmetric'}), \
                     ('schwarz',{'sweep':'symmetric'}), \
                     ('block_gauss_seidel',{'sweep':'symmetric'}), \
                     'jacobi', 'block_jacobi']
        Bs = [ones((n,1)),  \
             hstack( (ones((n,1)), arange(1,n+1,dtype='float').reshape(-1,1)) ) ]

        for smoother in smoothers:
            for B in Bs:
                ml = smoothed_aggregation_solver(A, B, max_coarse=10, \
                       presmoother=smoother, postsmoother=smoother)
                P = ml.aspreconditioner()
                x = rand(n, )
                y = rand(n, )
                assert_approx_equal(dot(P * x, y), dot(x, P * y))
    def test_basic(self):
        """Check that method converges at a reasonable rate."""
        for A, B, c_factor, symmetry, smooth in self.cases:
            ml = smoothed_aggregation_solver(A, B, symmetry=symmetry,
                                             smooth=smooth, max_coarse=10)

            np.random.seed(3009521727)  # make tests repeatable

            x = np.random.rand(A.shape[0])
            b = A * np.random.rand(A.shape[0])

            residuals = []
            x_sol = ml.solve(b, x0=x, maxiter=20, tol=1e-10,
                             residuals=residuals)
            del x_sol

            avg_convergence_ratio =\
                (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
            # print "Real Test:   %1.3e,  %1.3e,  %d,  %1.3e" % \
            #   (avg_convergence_ratio, c_factor, len(ml.levels),
            #    ml.operator_complexity())

            assert(avg_convergence_ratio < c_factor)
Example #16
0
 def test_symmetry(self):
     # Test that a basic V-cycle yields a symmetric linear operator.  Common
     # reasons for failure are problems with using the same rho for the
     # pres/post-smoothers and using the same block_D_inv for
     # pre/post-smoothers.
     
     n = 500
     A = poisson( (n,),  format='csr')
     smoothers = [('gauss_seidel',{'sweep':'symmetric'}), \
                  ('schwarz',{'sweep':'symmetric'}), \
                  ('block_gauss_seidel',{'sweep':'symmetric'}), \
                  'jacobi', 'block_jacobi']
     Bs = [ones((n,1)),  \
          hstack( (ones((n,1)), arange(1,n+1,dtype='float').reshape(-1,1)) ) ]
     
     for smoother in smoothers:
         for B in Bs:
             ml = smoothed_aggregation_solver(A, B, max_coarse=10, \
                    presmoother=smoother, postsmoother=smoother)
             P = ml.aspreconditioner()
             x = rand(n,)
             y = rand(n,)
             assert_approx_equal( dot(P*x, y), dot(x, P*y) )
Example #17
0
    def test_symmetry(self):
        # Test that a basic V-cycle yields a symmetric linear operator.  Common
        # reasons for failure are problems with using the same rho for the
        # pres/post-smoothers and using the same block_D_inv for
        # pre/post-smoothers.

        n = 500
        A = poisson((n, ), format='csr')
        smoothers = [('gauss_seidel', {
            'sweep': 'symmetric'
        }), ('schwarz', {
            'sweep': 'symmetric'
        }), ('block_gauss_seidel', {
            'sweep': 'symmetric'
        }), 'jacobi', 'block_jacobi']
        rng = np.arange(1, n + 1, dtype='float').reshape(-1, 1)
        Bs = [np.ones((n, 1)), sp.hstack((np.ones((n, 1)), rng))]

        # TODO:
        # why does python 3 require significant=6 while python 2 passes
        # why does python 3 yield a different dot() below than python 2
        # only for: ('gauss_seidel', {'sweep': 'symmetric'})
        for smoother in smoothers:
            for B in Bs:
                ml = smoothed_aggregation_solver(A,
                                                 B,
                                                 max_coarse=10,
                                                 presmoother=smoother,
                                                 postsmoother=smoother)
                P = ml.aspreconditioner()
                np.random.seed(0)
                x = sp.rand(n, )
                y = sp.rand(n, )
                out = (np.dot(P * x, y), np.dot(x, P * y))
                # print("smoother = %s %g %g" % (smoother, out[0], out[1]))
                assert_approx_equal(out[0], out[1])
Example #18
0
    def test_nonsymmetric(self):
        # problem data
        data = load_example('recirc_flow')
        A = data['A'].tocsr()
        B = data['B']
        numpy.random.seed(625)
        x0 = scipy.rand(A.shape[0])
        b = A * scipy.rand(A.shape[0])
        # solver parameters
        smooth = ('energy', {'krylov': 'gmres'})
        SA_build_args = {
            'max_coarse': 25,
            'coarse_solver': 'pinv2',
            'symmetry': 'nonsymmetric'
        }
        SA_solve_args = {'cycle': 'V', 'maxiter': 20, 'tol': 1e-8}
        strength = [('evolution', {'k': 2, 'epsilon': 8.0})]
        smoother = ('gauss_seidel_nr', {'sweep': 'symmetric', 'iterations': 1})
        improve_candidates = [('gauss_seidel_nr', {
            'sweep': 'symmetric',
            'iterations': 4
        }), None]
        # Construct solver with nonsymmetric parameters
        sa = smoothed_aggregation_solver(A,
                                         B=B,
                                         smooth=smooth,
                                         improve_candidates=improve_candidates,
                                         strength=strength,
                                         presmoother=smoother,
                                         postsmoother=smoother,
                                         **SA_build_args)
        residuals = []
        # stand-alone solve
        x = sa.solve(b, x0=x0, residuals=residuals, **SA_solve_args)
        residuals = array(residuals)
        avg_convergence_ratio = (residuals[-1] /
                                 residuals[0])**(1.0 / len(residuals))
        assert (avg_convergence_ratio < 0.65)
        # accelerated solve
        residuals = []
        x = sa.solve(b,
                     x0=x0,
                     residuals=residuals,
                     accel='gmres',
                     **SA_solve_args)
        residuals = array(residuals)
        avg_convergence_ratio = (residuals[-1] /
                                 residuals[0])**(1.0 / len(residuals))
        assert (avg_convergence_ratio < 0.45)

        # test that nonsymmetric parameters give the same result as symmetric parameters
        # for Poisson problem
        A = poisson((15, 15), format='csr')
        strength = 'symmetric'
        SA_build_args['symmetry'] = 'nonsymmetric'
        sa_nonsymm = smoothed_aggregation_solver(A, B=ones((A.shape[0],1)), smooth=smooth, \
         strength=strength, presmoother=smoother, postsmoother=smoother, improve_candidates=None,**SA_build_args)
        SA_build_args['symmetry'] = 'symmetric'
        sa_symm = smoothed_aggregation_solver(A, B=ones((A.shape[0],1)), smooth=smooth, \
         strength=strength, presmoother=smoother, postsmoother=smoother, improve_candidates=None,**SA_build_args)
        for (symm_lvl, nonsymm_lvl) in zip(sa_nonsymm.levels, sa_symm.levels):
            assert_array_almost_equal(symm_lvl.A.todense(),
                                      nonsymm_lvl.A.todense())
Example #19
0
else:
    x0 = np.zeros(vec_size, 1)

# ----------------------------------------------------------------------------- #
# ----------------------------------------------------------------------------- #

# Classical SA solver
# -------------------

start = time.clock()
ml_sa = smoothed_aggregation_solver(A,
                                    B=bad_guy,
                                    strength=strength_connection,
                                    aggregate=aggregation,
                                    smooth=interp_smooth,
                                    max_levels=max_levels,
                                    max_coarse=max_coarse,
                                    presmoother=relaxation,
                                    postsmoother=relaxation,
                                    improve_candidates=improve_candidates,
                                    coarse_solver=coarse_solver,
                                    keep=keep_levels)

sa_sol = ml_sa.solve(b, x0, tol, residuals=sa_residuals)

end = time.clock()
sa_time = end - start
sa_conv_factors = np.zeros((len(sa_residuals) - 1, 1))
for i in range(0, len(sa_residuals) - 1):
    sa_conv_factors[i] = sa_residuals[i] / sa_residuals[i - 1]
sa_eff_conv = (sa_residuals[-1] / sa_residuals[0])**(
    1 / (ml_sa.cycle_complexity() * len(sa_residuals)))
def adaptive_pairwise_solver(A,
                             initial_targets=None,
                             symmetry='hermitian',
                             desired_convergence=0.5,
                             test_iterations=10,
                             test_cycle='V',
                             test_accel=None,
                             strength=None,
                             smooth=None,
                             aggregate=('drake', {
                                 'levels': 2
                             }),
                             presmoother=('block_gauss_seidel', {
                                 'sweep': 'symmetric'
                             }),
                             postsmoother=('block_gauss_seidel', {
                                 'sweep': 'symmetric'
                             }),
                             max_levels=30,
                             max_coarse=100,
                             diagonal_dominance=False,
                             coarse_solver='pinv',
                             keep=False,
                             additive=False,
                             reconstruct=False,
                             max_hierarchies=10,
                             use_ritz=False,
                             improve_candidates=[('block_gauss_seidel', {
                                 'sweep': 'symmetric',
                                 'iterations': 4
                             })],
                             **kwargs):
    def unpack_arg(v):
        if isinstance(v, tuple):
            return v[0], v[1]
        elif v is None:
            return None
        else:
            return v, {}

    if isspmatrix_bsr(A):
        warn("Only currently implemented for CSR matrices.")

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

    if (symmetry != 'symmetric') and (symmetry != 'hermitian') and\
            (symmetry != 'nonsymmetric'):
        raise ValueError('expected \'symmetric\', \'nonsymmetric\' or\
                         \'hermitian\' for the symmetry parameter ')

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

    A = A.asfptype()
    A.symmetry = symmetry
    n = A.shape[0]
    test_rhs = np.zeros((n, 1))

    # SHOULD I START WITH CONSTANT VECTOR OR SMOOTHED RANDOM VECTOR?
    # Right near nullspace candidates
    if initial_targets is None:
        initial_targets = np.kron(
            np.ones((A.shape[0] / blocksize(A), 1), dtype=A.dtype),
            np.eye(blocksize(A)))
    else:
        initial_targets = np.asarray(initial_targets, dtype=A.dtype)
        if len(initial_targets.shape) == 1:
            initial_targets = initial_targets.reshape(-1, 1)
        if initial_targets.shape[0] != A.shape[0]:
            raise ValueError(
                'The near null-space modes initial_targets have incorrect \
                              dimensions for matrix A')
        if initial_targets.shape[1] < blocksize(A):
            raise ValueError(
                'initial_targets.shape[1] must be >= the blocksize of A')

    # Improve near nullspace candidates by relaxing on A B = 0
    if improve_candidates is not None:
        fn, temp_args = unpack_arg(improve_candidates[0])
    else:
        fn = None

    if fn is not None:
        b = np.zeros((A.shape[0], 1), dtype=A.dtype)
        initial_targets = relaxation_as_linear_operator(
            (fn, temp_args), A, b) * initial_targets
        if A.symmetry == "nonsymmetric":
            AH = A.H.asformat(A.format)
            BH = relaxation_as_linear_operator((fn, temp_args), AH, b) * BH

    # Empty set of solver hierarchies
    solvers = multilevel_solver_set()
    target = initial_targets
    B = initial_targets
    cf = 1.0

    # Aggregation process on the finest level is the same each iteration.
    # To prevent repeating processes, we compute it here and provide it to the
    # sovler construction.
    AggOp = get_aggregate(A,
                          strength=strength,
                          aggregate=aggregate,
                          diagonal_dominance=diagonal_dominance,
                          B=initial_targets)
    if isinstance(aggregate, tuple):
        aggregate = [('predefined', {'AggOp': AggOp}), aggregate]
    elif isinstance(aggregate, list):
        aggregate.insert(0, ('predefined', {'AggOp': AggOp}))
    else:
        raise TypeError("Aggregate variable must be list or tuple.")

    # Continue adding hierarchies until desired convergence factor achieved,
    # or maximum number of hierarchies constructed
    it = 0
    while (cf > desired_convergence) and (it < max_hierarchies):

        # pdb.set_trace()
        # Make target vector orthogonal and energy orthonormal and reconstruct hierarchy
        if use_ritz and it > 0:
            B = global_ritz_process(A, B, weak_tol=100)
            reconstruct_hierarchy(solver_set=solvers,
                                  A=A,
                                  new_B=B,
                                  symmetry=symmetry,
                                  aggregate=aggregate,
                                  presmoother=presmoother,
                                  postsmoother=postsmoother,
                                  smooth=smooth,
                                  strength=strength,
                                  max_levels=max_levels,
                                  max_coarse=max_coarse,
                                  coarse_solver=coarse_solver,
                                  diagonal_dominance=diagonal_dominance,
                                  keep=keep,
                                  **kwargs)
            print "Hierarchy reconstructed."
        # Otherwise just add new hierarchy to solver set.
        else:
            solvers.add_hierarchy(
                smoothed_aggregation_solver(
                    A,
                    B=B[:, -1],
                    symmetry=symmetry,
                    aggregate=aggregate,
                    presmoother=presmoother,
                    postsmoother=postsmoother,
                    smooth=smooth,
                    strength=strength,
                    max_levels=max_levels,
                    max_coarse=max_coarse,
                    diagonal_dominance=diagonal_dominance,
                    coarse_solver=coarse_solver,
                    improve_candidates=improve_candidates,
                    keep=keep,
                    **kwargs))
        # Test for convergence factor using new hierarchy.
        x0 = np.random.rand(n, 1)
        residuals = []
        target = solvers.solve(test_rhs,
                               x0=x0,
                               tol=1e-12,
                               maxiter=test_iterations,
                               cycle=test_cycle,
                               accel=test_accel,
                               residuals=residuals,
                               additive=additive)
        cf = residuals[-1] / residuals[-2]
        B = np.hstack((B, target))
        it += 1
        print "Added new hierarchy, convergence factor = ", cf

    B = B[:, :-1]
    # B2 = global_ritz_process(A, B, weak_tol=1.0)
    angles = test_targets(A, B)
    # angles = test_targets(A, B2)

    # -------------------------------------------------------------------------------------- #
    # -------------------------------------------------------------------------------------- #
    # -------------------------------------------------------------------------------------- #

    # b = np.zeros((n,1))
    # asa_residuals = []
    # sol = solvers.solve(b, x0, tol=1e-8, residuals=asa_residuals, accel=None)
    # asa_conv_factors = np.zeros((len(asa_residuals)-1,1))
    # for i in range(0,len(asa_residuals)-1):
    #   asa_conv_factors[i] = asa_residuals[i]/asa_residuals[i-1]

    # print "Original adaptive SA/AMG - ", np.mean(asa_conv_factors[1:])

    # if reconstruct:
    #     reconstruct_hierarchy(solver_set=solvers, A=A, new_B=B2, symmetry=symmetry,
    #                         aggregate=aggregate, presmoother=presmoother,
    #                         postsmoother=postsmoother, smooth=smooth,
    #                         strength=strength, max_levels=max_levels,
    #                         max_coarse=max_coarse, coarse_solver=coarse_solver,
    #                         diagonal_dominance=diagonal_dominance,
    #                         keep=keep, **kwargs)
    #     print "Hierarchy reconstructed."

    # asa_residuals2 = []
    # sol = solvers.solve(b, x0, tol=1e-8, residuals=asa_residuals2, accel=None)
    # asa_conv_factors2 = np.zeros((len(asa_residuals2)-1,1))
    # for i in range(0,len(asa_residuals2)-1):
    #   asa_conv_factors2[i] = asa_residuals2[i]/asa_residuals2[i-1]

    # print "Ritz adaptive SA/AMG - ", np.mean(asa_conv_factors2[1:])

    # if reconstruct:
    #     reconstruct_hierarchy(solver_set=solvers, A=A, new_B=B[:,:-1], symmetry=symmetry,
    #                         aggregate=aggregate, presmoother=presmoother,
    #                         postsmoother=postsmoother, smooth=smooth,
    #                         strength=strength, max_levels=max_levels,
    #                         max_coarse=max_coarse, coarse_solver=coarse_solver,
    #                         diagonal_dominance=diagonal_dominance,
    #                         keep=keep, **kwargs)
    #     print "Hierarchy reconstructed."

    # asa_residuals2 = []
    # sol = solvers.solve(b, x0, tol=1e-8, residuals=asa_residuals2, accel=None)
    # asa_conv_factors2 = np.zeros((len(asa_residuals2)-1,1))
    # for i in range(0,len(asa_residuals2)-1):
    #   asa_conv_factors2[i] = asa_residuals2[i]/asa_residuals2[i-1]

    # print "Original(-1) SA/AMG - ", np.mean(asa_conv_factors2[1:])

    # if reconstruct:
    #     reconstruct_hierarchy(solver_set=solvers, A=A, new_B=B2[:,:-1], symmetry=symmetry,
    #                         aggregate=aggregate, presmoother=presmoother,
    #                         postsmoother=postsmoother, smooth=smooth,
    #                         strength=strength, max_levels=max_levels,
    #                         max_coarse=max_coarse, coarse_solver=coarse_solver,
    #                         diagonal_dominance=diagonal_dominance,
    #                         keep=keep, **kwargs)
    #     print "Hierarchy reconstructed."

    # asa_residuals2 = []
    # sol = solvers.solve(b, x0, tol=1e-8, residuals=asa_residuals2, accel=None)
    # asa_conv_factors2 = np.zeros((len(asa_residuals2)-1,1))
    # for i in range(0,len(asa_residuals2)-1):
    #   asa_conv_factors2[i] = asa_residuals2[i]/asa_residuals2[i-1]

    # print "Ritz(-1) SA/AMG - ", np.mean(asa_conv_factors2[1:])

    # pdb.set_trace()
    # -------------------------------------------------------------------------------------- #
    # -------------------------------------------------------------------------------------- #
    # -------------------------------------------------------------------------------------- #

    return solvers
def reconstruct_hierarchy(solver_set, A, new_B, symmetry, aggregate,
                          presmoother, postsmoother, smooth, strength,
                          max_levels, max_coarse, coarse_solver,
                          diagonal_dominance, keep, **kwargs):

    if not isinstance(solver_set, multilevel_solver_set):
        raise TypeError("Must pass in multilevel solver set.")

    if not isinstance(new_B, np.ndarray):
        raise ValueError(
            "Target vectors must be ndarray of size nxb, for b hierarchies and problem size n."
        )

    num_solvers = solver_set.num_hierarchies
    num_badguys = new_B.shape[1]
    n = new_B.shape[0]
    if (n != A.shape[0]):
        raise ValueError("Target vectors must have same size as matrix.")

    # If less target vectors provided than solvers in set, remove solvers without target
    # vector to reconstruct.
    diff = num_solvers - num_badguys
    if (diff > 0):
        print "Less target vectors provided than hierachies in solver. Removing hierarchies."
        for i in range(0, diff):
            solver_set.remove_hierarchy(num_solvers - 1)
            num_solvers -= 1

    # Reconstruct each solver in hierarchy using new target vectors
    print "Reconstructing hierarchy."
    for i in range(0, num_solvers):
        solver_set.replace_hierarchy(hierarchy=smoothed_aggregation_solver(
            A,
            B=new_B[:, i],
            symmetry=symmetry,
            aggregate=aggregate,
            presmoother=presmoother,
            postsmoother=postsmoother,
            smooth=smooth,
            strength=strength,
            max_levels=max_levels,
            max_coarse=max_coarse,
            coarse_solver=coarse_solver,
            diagonal_dominance=diagonal_dominance,
            improve_candidates=None,
            keep=keep,
            **kwargs),
                                     ind=i)

    # If more bad guys are provided than stored in initial hierarchy
    if diff < 0:
        print "More target vectors provided than hierachies in solver. Adding hierarchies."
        for i in range(num_solvers, num_badguys):
            solver_set.add_hierarchy(hierarchy=smoothed_aggregation_solver(
                A,
                B=new_B[:, i],
                symmetry=symmetry,
                aggregate=aggregate,
                presmoother=presmoother,
                postsmoother=postsmoother,
                smooth=smooth,
                strength=strength,
                max_levels=max_levels,
                max_coarse=max_coarse,
                coarse_solver=coarse_solver,
                diagonal_dominance=diagonal_dominance,
                improve_candidates=None,
                keep=keep,
                **kwargs))
Example #22
0
    def test_nonhermitian(self):
        # problem data
        data = load_example('helmholtz_2D')
        A = data['A'].tocsr()
        B = data['B']
        np.random.seed(625)
        x0 = scipy.rand(A.shape[0]) + 1.0j * scipy.rand(A.shape[0])
        b = A * scipy.rand(A.shape[0]) + 1.0j * (A * scipy.rand(A.shape[0]))
        # solver parameters
        smooth = ('energy', {'krylov': 'gmres'})
        SA_build_args = {
            'max_coarse': 25,
            'coarse_solver': 'pinv2',
            'symmetry': 'symmetric'
        }
        SA_solve_args = {'cycle': 'V', 'maxiter': 20, 'tol': 1e-8}
        strength = [('evolution', {'k': 2, 'epsilon': 2.0})]
        smoother = ('gauss_seidel_nr', {'sweep': 'symmetric', 'iterations': 1})
        # Construct solver with nonsymmetric parameters
        sa = smoothed_aggregation_solver(A,
                                         B=B,
                                         smooth=smooth,
                                         strength=strength,
                                         presmoother=smoother,
                                         postsmoother=smoother,
                                         **SA_build_args)
        residuals = []
        # stand-alone solve
        x = sa.solve(b, x0=x0, residuals=residuals, **SA_solve_args)
        residuals = np.array(residuals)
        avg_convergence_ratio =\
            (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
        assert (avg_convergence_ratio < 0.85)
        # accelerated solve
        residuals = []
        x = sa.solve(b,
                     x0=x0,
                     residuals=residuals,
                     accel='gmres',
                     **SA_solve_args)
        del x
        residuals = np.array(residuals)
        avg_convergence_ratio =\
            (residuals[-1] / residuals[0]) ** (1.0 / len(residuals))
        assert (avg_convergence_ratio < 0.7)

        # test that nonsymmetric parameters give the same result as symmetric
        # parameters for the complex-symmetric matrix A
        strength = 'symmetric'
        SA_build_args['symmetry'] = 'nonsymmetric'
        sa_nonsymm = smoothed_aggregation_solver(A,
                                                 B=np.ones((A.shape[0], 1)),
                                                 smooth=smooth,
                                                 strength=strength,
                                                 presmoother=smoother,
                                                 postsmoother=smoother,
                                                 improve_candidates=None,
                                                 **SA_build_args)
        SA_build_args['symmetry'] = 'symmetric'
        sa_symm = smoothed_aggregation_solver(A,
                                              B=np.ones((A.shape[0], 1)),
                                              smooth=smooth,
                                              strength=strength,
                                              presmoother=smoother,
                                              postsmoother=smoother,
                                              improve_candidates=None,
                                              **SA_build_args)
        for (symm_lvl, nonsymm_lvl) in zip(sa_nonsymm.levels, sa_symm.levels):
            assert_array_almost_equal(symm_lvl.A.todense(),
                                      nonsymm_lvl.A.todense())
Example #23
0
sa_residuals = []

# ----------------------------------------------------------------------------- #
# ----------------------------------------------------------------------------- #

# Classical smoothed aggregation solver
# --------------------------

# Form classical smoothed aggregation multilevel solver object
start = time.clock()
ml_sa = smoothed_aggregation_solver(A,
                                    B=None,
                                    symmetry='symmetric',
                                    strength=strength_connection,
                                    aggregate=aggregation,
                                    smooth=interp_smooth1,
                                    max_levels=max_levels,
                                    max_coarse=max_coarse,
                                    presmoother=relaxation,
                                    postsmoother=relaxation,
                                    improve_candidates=improve_candidates,
                                    keep=keep)

sol = ml_sa.solve(b, x0, tol, residuals=sa_residuals)

# setup = setup_complexity(sa=ml_sa, strength=strength_connection, smooth=interp_smooth1,
# 						improve_candidates=improve_candidates, aggregate=aggregation,
# 						presmoother=relaxation, postsmoother=relaxation, keep=keep,
# 						max_levels=max_levels, max_coarse=max_coarse, coarse_solver=coarse_solver,
# 						symmetry='symmetric')
# cycle = cycle_complexity(solver=ml_sa, presmoothing=relaxation, postsmoothing=relaxation, cycle='V')