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))
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
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))
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)
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)
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)
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)
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_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_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())
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))
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())
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')