def setUp(self): self.cases = [] # Test 1 A = poisson((5000,), format="csr") Ai = A + 1.0j * scipy.sparse.eye(A.shape[0], A.shape[1]) self.cases.append((Ai, None, 0.12, "symmetric", ("jacobi", {"omega": 4.0 / 3.0}))) self.cases.append((Ai, None, 0.12, "symmetric", ("energy", {"krylov": "gmres"}))) # Test 2 A = poisson((71, 71), format="csr") Ai = A + (0.625 / 0.01) * 1j * scipy.sparse.eye(A.shape[0], A.shape[1]) self.cases.append((Ai, None, 1e-3, "symmetric", ("jacobi", {"omega": 4.0 / 3.0}))) self.cases.append((Ai, None, 1e-3, "symmetric", ("energy", {"krylov": "cgnr"}))) # Test 3 A = poisson((60, 60), format="csr") Ai = 1.0j * A self.cases.append((Ai, None, 0.3, "symmetric", ("jacobi", {"omega": 4.0 / 3.0}))) self.cases.append((Ai, None, 0.6, "symmetric", ("energy", {"krylov": "cgnr", "maxiter": 8}))) self.cases.append((Ai, None, 0.6, "symmetric", ("energy", {"krylov": "gmres", "maxiter": 8}))) # Test 4 # Use an "inherently" imaginary problem, the Gauge Laplacian in 2D from # Quantum Chromodynamics, A = gauge_laplacian(70, spacing=1.0, beta=0.41) self.cases.append((A, None, 0.4, "hermitian", ("jacobi", {"omega": 4.0 / 3.0}))) self.cases.append((A, None, 0.4, "hermitian", ("energy", {"krylov": "cg"})))
def test_coarse_grid_solver(self): cases = [] cases.append(csr_matrix(diag(arange(1, 5, dtype=float)))) cases.append(poisson((4,), format='csr')) cases.append(poisson((4, 4), format='csr')) from pyamg.krylov import cg def fn(A, b): return cg(A, b)[0] # method should be almost exact for small matrices for A in cases: for solver in ['splu', 'pinv', 'pinv2', 'lu', 'cholesky', 'cg', fn]: s = coarse_grid_solver(solver) b = arange(A.shape[0], dtype=A.dtype) x = s(A, b) assert_almost_equal(A*x, b) # subsequent calls use cached data x = s(A, b) assert_almost_equal(A*x, b)
def setUp(self): self.cases = [] A = poisson((5000,), format='csr') self.cases.append((A, None, 0.4, 'symmetric', ('jacobi', {'omega': 4.0 / 3.0}))) self.cases.append((A, None, 0.4, 'symmetric', ('energy', {'krylov': 'cg'}))) self.cases.append((A, None, 0.5, 'symmetric', ('energy', {'krylov': 'gmres'}))) A = poisson((60, 60), format='csr') self.cases.append((A, None, 0.42, 'symmetric', ('jacobi', {'omega': 4.0 / 3.0}))) self.cases.append((A, None, 0.42, 'symmetric', ('energy', {'krylov': 'cg'}))) self.cases.append((A, None, 0.42, 'symmetric', ('energy', {'krylov': 'cgnr'}))) A, B = linear_elasticity((50, 50), format='bsr') self.cases.append((A, B, 0.32, 'symmetric', ('jacobi', {'omega': 4.0 / 3.0}))) self.cases.append((A, B, 0.22, 'symmetric', ('energy', {'krylov': 'cg'}))) self.cases.append((A, B, 0.42, 'symmetric', ('energy', {'krylov': 'cgnr'}))) self.cases.append((A, B, 0.42, 'symmetric', ('energy', {'krylov': 'gmres'})))
def setUp(self): self.cases = [] # Test 1 A = poisson((5000,), format='csr') Ai = A + 1.0j * scipy.sparse.eye(A.shape[0], A.shape[1]) self.cases.append((Ai, None, 0.12, 'symmetric', ('energy', {'krylov': 'gmres'}))) # Test 2 A = poisson((71, 71), format='csr') Ai = A + (0.625 / 0.01) * 1.0j *\ scipy.sparse.eye(A.shape[0], A.shape[1]) self.cases.append((Ai, None, 1e-3, 'symmetric', ('energy', {'krylov': 'cgnr'}))) # Test 3 A = poisson((60, 60), format='csr') Ai = 1.0j * A self.cases.append((Ai, None, 0.35, 'symmetric', ('energy', {'krylov': 'cgnr', 'maxiter': 8}))) self.cases.append((Ai, None, 0.35, 'symmetric', ('energy', {'krylov': 'gmres', 'maxiter': 8}))) # Test 4 Use an "inherently" imaginary problem, the Gauge Laplacian in # 2D from Quantum Chromodynamics, A = gauge_laplacian(70, spacing=1.0, beta=0.41) self.cases.append((A, None, 0.25, 'hermitian', ('energy', {'krylov': 'cg'})))
def setUp(self): self.cases = [] # Consider "Helmholtz" like problems with an imaginary shift so that the operator # should still be SPD in a sense and SA should perform well. # There are better near nullspace vectors than the default, # but a constant should give a convergent solver, nonetheless. A = poisson( (100,), format='csr'); A = A + 1.0j*scipy.sparse.eye(A.shape[0], A.shape[1]) self.cases.append((A, None)) A = poisson( (10,10), format='csr'); A = A + 1.0j*scipy.sparse.eye(A.shape[0], A.shape[1]) self.cases.append((A, None))
def setUp(self): self.cases = [] # Poisson problems in 1D and 2D N = 20 self.cases.append((poisson((2*N,), format='csr'), rand(2*N,))) # 0 self.cases.append((poisson((N, N), format='csr'), rand(N*N,))) # 1 # Boxed examples A = load_example('recirc_flow')['A'].tocsr() # 2 self.cases.append((A, rand(A.shape[0],))) A = load_example('bar')['A'].tobsr(blocksize=(3, 3)) # 3 self.cases.append((A, rand(A.shape[0],)))
def setUp(self): self.cases = [] # Poisson problems in 1D and 2D for N in [2, 3, 5, 7, 10, 11, 19]: self.cases.append(poisson((N,), format='csr')) for N in [2, 3, 7, 9]: self.cases.append(poisson((N, N), format='csr')) for name in ['knot', 'airfoil', 'bar']: ex = load_example(name) self.cases.append(ex['A'].tocsr())
def setUp(self): self.cases = [] # Consider "Helmholtz" like problems with an imaginary shift so that # the operator should still be SPD in a sense and SA should perform # well. There are better near nullspace vectors than the default, but # a constant should give a convergent solver, nonetheless. A = poisson((100,), format='csr') A = A + 1.0j * scipy.sparse.eye(A.shape[0], A.shape[1]) self.cases.append((A, None)) A = poisson((10, 10), format='csr') A = A + 1.0j * scipy.sparse.eye(A.shape[0], A.shape[1]) self.cases.append((A, None))
def setUp(self): self.cases = [] np.random.seed(2828777142) # Poisson problems in 1D and 2D N = 20 self.cases.append((poisson( (2 * N, ), format='csr'), np.random.rand(2 * N, ))) # 0 self.cases.append((poisson( (N, N), format='csr'), np.random.rand(N * N, ))) # 1 # Boxed examples A = load_example('recirc_flow')['A'].tocsr() # 2 self.cases.append((A, np.random.rand(A.shape[0], ))) A = load_example('bar')['A'].tobsr(blocksize=(3, 3)) # 3 self.cases.append((A, np.random.rand(A.shape[0], )))
def setUp(self): self.cases = [] A = poisson((5000,), format="csr") self.cases.append((A, None, 0.4, "symmetric", ("energy", {"krylov": "cg"}))) self.cases.append((A, None, 0.4, "symmetric", ("energy", {"krylov": "gmres"}))) A = poisson((75, 75), format="csr") self.cases.append((A, None, 0.26, "symmetric", ("energy", {"krylov": "cg"}))) self.cases.append((A, None, 0.30, "symmetric", ("energy", {"krylov": "cgnr"}))) A, B = linear_elasticity((50, 50), format="bsr") self.cases.append((A, B, 0.3, "symmetric", ("energy", {"krylov": "cg"}))) self.cases.append((A, B, 0.3, "symmetric", ("energy", {"krylov": "cgnr"}))) self.cases.append((A, B, 0.3, "symmetric", ("energy", {"krylov": "gmres"})))
def setUp(self): self.cases = [] # Test 1 A = poisson((5000, ), format='csr') Ai = A + 1.0j * scipy.sparse.eye(A.shape[0], A.shape[1]) self.cases.append((Ai, None, 0.12, 'symmetric', ('jacobi', { 'omega': 4.0 / 3.0 }))) self.cases.append((Ai, None, 0.12, 'symmetric', ('energy', { 'krylov': 'gmres' }))) # Test 2 A = poisson((71, 71), format='csr') Ai = A + (0.625 / 0.01) * 1j * scipy.sparse.eye(A.shape[0], A.shape[1]) self.cases.append((Ai, None, 1e-3, 'symmetric', ('jacobi', { 'omega': 4.0 / 3.0 }))) self.cases.append((Ai, None, 1e-3, 'symmetric', ('energy', { 'krylov': 'cgnr' }))) # Test 3 A = poisson((60, 60), format='csr') Ai = 1.0j * A self.cases.append((Ai, None, 0.3, 'symmetric', ('jacobi', { 'omega': 4.0 / 3.0 }))) self.cases.append((Ai, None, 0.6, 'symmetric', ('energy', { 'krylov': 'cgnr', 'maxiter': 8 }))) self.cases.append((Ai, None, 0.6, 'symmetric', ('energy', { 'krylov': 'gmres', 'maxiter': 8 }))) # Test 4 # Use an "inherently" imaginary problem, the Gauge Laplacian in 2D from # Quantum Chromodynamics, A = gauge_laplacian(70, spacing=1.0, beta=0.41) self.cases.append((A, None, 0.4, 'hermitian', ('jacobi', { 'omega': 4.0 / 3.0 }))) self.cases.append((A, None, 0.4, 'hermitian', ('energy', { 'krylov': 'cg' })))
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 = sp.rand(A.shape[0]) b = sp.rand(A.shape[0]) D = diag_sparse(1.0 / np.sqrt(10**(12 * sp.rand(A.shape[0]) - 6))).tocsr() D_inv = diag_sparse(1.0 / D.data) # DAD = D * A * D B = np.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_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 improve_candidates in improve_candidates_list: ml = smoothed_aggregation_solver(A, B, max_coarse=10, improve_candidates=improve_candidates) 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 setUp(self): self.cases = [] # Poisson problems in 2D for N in [2,3,5,7,8]: A = poisson( (N,N), format='csr'); A.data = A.data + 0.001j*rand(A.nnz) self.cases.append(A)
def test_solver_parameters(self): A = poisson((50, 50), format='csr') for method in methods: # method = ('richardson', {'omega':4.0/3.0}) ml = smoothed_aggregation_solver(A, presmoother=method, postsmoother=method, max_coarse=10) residuals = profile_solver(ml) assert ((residuals[-1] / residuals[0])**(1.0 / len(residuals)) < 0.95) assert (ml.symmetric_smoothing) for method in methods2: ml = smoothed_aggregation_solver(A, max_coarse=10) change_smoothers(ml, presmoother=method[0], postsmoother=method[1]) residuals = profile_solver(ml) assert ((residuals[-1] / residuals[0])**(1.0 / len(residuals)) < 0.95) assert (not ml.symmetric_smoothing) for method in methods3: ml = smoothed_aggregation_solver(A, max_coarse=10) change_smoothers(ml, presmoother=method[0], postsmoother=method[1]) assert (ml.symmetric_smoothing) for method in methods4: ml = smoothed_aggregation_solver(A, max_coarse=10) change_smoothers(ml, presmoother=method[0], postsmoother=method[1]) assert (not ml.symmetric_smoothing)
def test_accel(self): from pyamg import smoothed_aggregation_solver from pyamg.krylov import cg, bicgstab A = poisson((50, 50), format='csr') b = rand(A.shape[0]) ml = smoothed_aggregation_solver(A) # cg halts based on the preconditioner norm for accel in ['cg', cg]: x = ml.solve(b, maxiter=30, tol=1e-8, accel=accel) assert(precon_norm(b - A*x, ml) < 1e-8*precon_norm(b, ml)) residuals = [] x = ml.solve(b, maxiter=30, tol=1e-8, residuals=residuals, accel=accel) assert(precon_norm(b - A*x, ml) < 1e-8*precon_norm(b, ml)) # print residuals assert_almost_equal(precon_norm(b - A*x, ml), residuals[-1]) # cgs and bicgstab use the Euclidean norm for accel in ['bicgstab', 'cgs', bicgstab]: x = ml.solve(b, maxiter=30, tol=1e-8, accel=accel) assert(norm(b - A*x) < 1e-8*norm(b)) residuals = [] x = ml.solve(b, maxiter=30, tol=1e-8, residuals=residuals, accel=accel) assert(norm(b - A*x) < 1e-8*norm(b)) # print residuals assert_almost_equal(norm(b - A*x), residuals[-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 = 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_solver_parameters(self): A = poisson((50, 50), format='csr') for method in methods: #method = ('richardson', {'omega':4.0/3.0}) ml = smoothed_aggregation_solver(A, presmoother=method, postsmoother=method, max_coarse=10) residuals = profile_solver(ml) #print "method",method #print "residuals",residuals #print "convergence rate:",(residuals[-1]/residuals[0])**(1.0/len(residuals)) assert ((residuals[-1] / residuals[0])**(1.0 / len(residuals)) < 0.95) for method in methods2: ml = smoothed_aggregation_solver(A, max_coarse=10) change_smoothers(ml, presmoother=method[0], postsmoother=method[1]) residuals = profile_solver(ml) #print "method",method #print "residuals",residuals #print "convergence rate:",(residuals[-1]/residuals[0])**(1.0/len(residuals)) assert ((residuals[-1] / residuals[0])**(1.0 / len(residuals)) < 0.95)
def test_poisson(self): cases = [] cases.append((500,)) cases.append((250, 250)) cases.append((25, 25, 25)) for case in cases: A = poisson(case, format='csr') np.random.seed(0) # make tests repeatable x = sp.rand(A.shape[0]) b = A*sp.rand(A.shape[0]) # zeros_like(x) ml = ruge_stuben_solver(A, max_coarse=50) res = [] x_sol = ml.solve(b, x0=x, maxiter=20, tol=1e-12, residuals=res) del x_sol avg_convergence_ratio = (res[-1]/res[0])**(1.0/len(res)) assert(avg_convergence_ratio < 0.20)
def test_solver_parameters(self): A = poisson((50, 50), format='csr') for method in methods: # method = ('richardson', {'omega':4.0/3.0}) ml = smoothed_aggregation_solver(A, presmoother=method, postsmoother=method, max_coarse=10) residuals = profile_solver(ml) assert((residuals[-1]/residuals[0])**(1.0/len(residuals)) < 0.95) assert(ml.symmetric_smoothing) for method in methods2: ml = smoothed_aggregation_solver(A, max_coarse=10) change_smoothers(ml, presmoother=method[0], postsmoother=method[1]) residuals = profile_solver(ml) assert((residuals[-1]/residuals[0])**(1.0/len(residuals)) < 0.95) assert(not ml.symmetric_smoothing) for method in methods3: ml = smoothed_aggregation_solver(A, max_coarse=10) change_smoothers(ml, presmoother=method[0], postsmoother=method[1]) assert(ml.symmetric_smoothing) for method in methods4: ml = smoothed_aggregation_solver(A, max_coarse=10) change_smoothers(ml, presmoother=method[0], postsmoother=method[1]) assert(not ml.symmetric_smoothing)
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) 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_coarse_solver_opts(self): # these tests are meant to test whether coarse solvers are correctly # passed parameters A = poisson((30, 30), format='csr') b = sp.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, max_coarse=500) sa2 = smoothed_aggregation_solver(A, coarse_solver=coarse2, max_coarse=500) x1 = sa1.solve(b, residuals=r1) x2 = sa2.solve(b, residuals=r2) del x1, x2 assert ((len(r1) + 5) < len(r2))
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)), np.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(3849986793) x = np.random.rand(n,) y = np.random.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_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 = rootnode_solver(D * A * D, D_inv * B, **kwargs) residuals = [] x_sol = sa.solve(b, x0=x, maxiter=10, tol=1e-12, residuals=residuals) avg_convergence_ratio =\ (residuals[-1] / residuals[0]) ** (1.0 / len(residuals)) # print "Diagonal Scaling Test: %1.3e, %1.3e" % # (avg_convergence_ratio, 0.4) assert(avg_convergence_ratio < 0.4)
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 = [np.ones((n, 1)), sp.hstack((np.ones((n, 1)), np.arange(1, n + 1, dtype='float').reshape(-1, 1)))] for smoother in smoothers: for B in Bs: ml = rootnode_solver(A, B, max_coarse=10, presmoother=smoother, postsmoother=smoother) P = ml.aspreconditioner() x = sp.rand(n,) y = sp.rand(n,) assert_approx_equal(np.dot(P * x, y), np.dot(x, P * y))
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 = sp.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 = rootnode_solver(A, coarse_solver=coarse1) sa2 = rootnode_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_coarse_solver_opts(self): # these tests are meant to test whether coarse solvers are correctly # passed parameters A = poisson((30, 30), format='csr') b = np.random.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}))) # scipy >= 1.7: pinv takes 'rtol' # scipy < 1.7: pinv takes 'cond' kword = 'rtol' if kword not in sla.pinv.__code__.co_varnames: kword = 'cond' coarse_solver_pairs.append(('pinv', ('pinv', {kword: 1.0}))) for coarse1, coarse2 in coarse_solver_pairs: r1 = [] r2 = [] sa1 = rootnode_solver(A, coarse_solver=coarse1, max_coarse=500) sa2 = rootnode_solver(A, coarse_solver=coarse2, max_coarse=500) x1 = sa1.solve(b, residuals=r1) x2 = sa2.solve(b, residuals=r2) del x1, x2 assert((len(r1) + 5) < len(r2))
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 = rootnode_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_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((75, 75), format="csr"), ones((75 * 75, 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 improve_candidates in improve_candidates_list: ml = rootnode_solver(A, B, max_coarse=10, improve_candidates=improve_candidates) 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 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 = rootnode_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)) #print "Test 1 %1.3e, %1.3e" % (avg_convergence_ratio, 0.7) assert (avg_convergence_ratio < 0.7) # 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)) #print "Test 2 %1.3e, %1.3e" % (avg_convergence_ratio, 0.45) 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 = rootnode_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 = rootnode_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_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 = rootnode_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)) # print "Test 1 %1.3e, %1.3e" % (avg_convergence_ratio, 0.7) assert(avg_convergence_ratio < 0.7) # 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)) # print "Test 2 %1.3e, %1.3e" % (avg_convergence_ratio, 0.45) 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 = rootnode_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 = rootnode_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 setUp(self): self.cases = [] # random matrices np.random.seed(0) for N in [2, 3, 5]: self.cases.append(csr_matrix(np.random.rand(N, N))) # Poisson problems in 1D and 2D for N in [2, 3, 5, 7, 10, 11, 19]: self.cases.append(poisson((N,), format='csr')) for N in [2, 3, 5, 7, 8]: self.cases.append(poisson((N, N), format='csr')) for name in ['knot', 'airfoil', 'bar']: ex = load_example(name) self.cases.append(ex['A'].tocsr())
def setUp(self): self.cases = [] # random matrices np.random.seed(0) for N in [2, 3, 5]: self.cases.append(csr_matrix(rand(N, N))) # Poisson problems in 1D and 2D for N in [2, 3, 5, 7, 10, 11, 19]: self.cases.append(poisson((N, ), format='csr')) for N in [2, 3, 7, 9]: self.cases.append(poisson((N, N), format='csr')) for name in ['knot', 'airfoil', 'bar']: ex = load_example(name) self.cases.append(ex['A'].tocsr())
def setUp(self): self.cases = [] A = poisson((5000,), format="csr") self.cases.append((A, None, 0.4, "symmetric", ("jacobi", {"omega": 4.0 / 3.0}))) self.cases.append((A, None, 0.4, "symmetric", ("energy", {"krylov": "cg"}))) self.cases.append((A, None, 0.5, "symmetric", ("energy", {"krylov": "gmres"}))) A = poisson((60, 60), format="csr") self.cases.append((A, None, 0.42, "symmetric", ("jacobi", {"omega": 4.0 / 3.0}))) self.cases.append((A, None, 0.42, "symmetric", ("energy", {"krylov": "cg"}))) self.cases.append((A, None, 0.42, "symmetric", ("energy", {"krylov": "cgnr"}))) A, B = linear_elasticity((50, 50), format="bsr") self.cases.append((A, B, 0.32, "symmetric", ("jacobi", {"omega": 4.0 / 3.0}))) self.cases.append((A, B, 0.22, "symmetric", ("energy", {"krylov": "cg"}))) self.cases.append((A, B, 0.42, "symmetric", ("energy", {"krylov": "cgnr"}))) self.cases.append((A, B, 0.42, "symmetric", ("energy", {"krylov": "gmres"})))
def setUp(self): self.cases = [] # random matrices numpy.random.seed(0) for N in [2,3,5]: self.cases.append( csr_matrix(rand(N,N)) + csr_matrix(1.0j*rand(N,N))) # Poisson problems in 1D and 2D for N in [2,3,5,7,10,11,19]: A = poisson( (N,), format='csr'); A.data = A.data + 1.0j*A.data; self.cases.append(A) for N in [2,3,7,9]: A = poisson( (N,N), format='csr'); A.data = A.data + 1.0j*rand(A.data.shape[0],); self.cases.append(A) for name in ['knot','airfoil','bar']: ex = load_example(name) A = ex['A'].tocsr(); A.data = A.data + 0.5j*rand(A.data.shape[0],); self.cases.append(A)
def test_precision(self): """Check single precision. Test that x_32 == x_64 up to single precision tolerance """ np.random.seed(3158637515) # make tests repeatable A = poisson((10, 10), dtype=np.float64, format='csr') b = np.random.rand(A.shape[0]).astype(A.dtype) ml = smoothed_aggregation_solver(A) x = np.random.rand(A.shape[0]).astype(A.dtype) x32 = ml.solve(b, x0=x, maxiter=1) np.random.seed(3158637515) # make tests repeatable A = poisson((10, 10), dtype=np.float32, format='csr') b = np.random.rand(A.shape[0]).astype(A.dtype) ml = smoothed_aggregation_solver(A) x = np.random.rand(A.shape[0]).astype(A.dtype) x64 = ml.solve(b, x0=x, maxiter=1) assert_array_almost_equal(x32, x64, decimal=5)
def setUp(self): self.cases = [] # Poisson problems in 1D and 2D for N in [10, 11, 19, 26]: A = poisson((N,), format='csr') tempAgg = standard_aggregation(A) T, B = fit_candidates(tempAgg, np.ones((A.shape[0],)) ) self.cases.append( {'A': A, 'T': T, 'B': B} ) for N in [5, 7, 9]: A = poisson((N,N), format='csr') tempAgg = standard_aggregation(A) T, B = fit_candidates(tempAgg, np.ones((A.shape[0],)) ) self.cases.append( {'A': A, 'T': T, 'B': B} ) for name in ['knot', 'airfoil', 'bar']: A = ex['A'].tocsr() tempAgg = standard_aggregation(A) T, B = fit_candidates(tempAgg, np.ones((A.shape[0],)) ) self.cases.append( {'A': A, 'T': T, 'B': B} )
def setUp(self): self.cases = [] # Poisson problems in 1D and 2D for N in [10, 11, 19, 26]: A = poisson((N, ), format='csr') tempAgg = standard_aggregation(A) T, B = fit_candidates(tempAgg, np.ones((A.shape[0], ))) self.cases.append({'A': A, 'T': T, 'B': B}) for N in [5, 7, 9]: A = poisson((N, N), format='csr') tempAgg = standard_aggregation(A) T, B = fit_candidates(tempAgg, np.ones((A.shape[0], ))) self.cases.append({'A': A, 'T': T, 'B': B}) for name in ['knot', 'airfoil', 'bar']: A = ex['A'].tocsr() tempAgg = standard_aggregation(A) T, B = fit_candidates(tempAgg, np.ones((A.shape[0], ))) self.cases.append({'A': A, 'T': T, 'B': B})
def setUp(self): self.cases = [] # # Random matrices, cases 0-2 np.random.seed(0) for N in [2, 3, 5]: self.cases.append(csr_matrix(np.random.rand(N, N))) # Poisson problems in 1D, cases 3-9 for N in [2, 3, 5, 7, 10, 11, 19]: self.cases.append(poisson((N,), format="csr")) # Poisson problems in 2D, cases 10-15 for N in [2, 3, 5, 7, 10, 11]: self.cases.append(poisson((N, N), format="csr")) for name in ["knot", "airfoil", "bar"]: ex = load_example(name) self.cases.append(ex["A"].tocsr())
def setUp(self): cases = [] np.random.seed(651978631) for i in range(5): A = np.random.rand(8, 8) > 0.5 cases.append(canonical_graph(A + A.T).astype(float)) cases.append(np.zeros((1, 1))) cases.append(np.zeros((2, 2))) cases.append(np.zeros((8, 8))) cases.append(np.ones((2, 2)) - np.eye(2)) cases.append(poisson((5, ))) cases.append(poisson((5, 5))) cases.append(poisson((11, 11))) cases.append(poisson((5, 5, 5))) for name in ['airfoil', 'bar', 'knot']: cases.append(load_example(name)['A']) cases = [canonical_graph(G) for G in cases] self.cases = cases
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 = rootnode_solver(A, max_coarse=10) for AA in cases: sa_new = rootnode_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 setUp(self): cases = [] seed(0) for i in range(5): A = rand(8, 8) > 0.5 cases.append(canonical_graph(A + A.T).astype(float)) cases.append(zeros((1, 1))) cases.append(zeros((2, 2))) cases.append(zeros((8, 8))) cases.append(ones((2, 2)) - eye(2)) cases.append(poisson((5,))) cases.append(poisson((5, 5))) cases.append(poisson((11, 11))) cases.append(poisson((5, 5, 5))) for name in ['airfoil', 'bar', 'knot']: cases.append(load_example(name)['A']) cases = [canonical_graph(G) for G in cases] self.cases = cases
def setUp(self): self.cases = [] A = poisson((5000,), format='csr') self.cases.append((A, None, 0.4, 'symmetric', ('energy', {'krylov': 'cg'}))) self.cases.append((A, None, 0.4, 'symmetric', ('energy', {'krylov': 'gmres'}))) A = poisson((75, 75), format='csr') self.cases.append((A, None, 0.26, 'symmetric', ('energy', {'krylov': 'cg'}))) self.cases.append((A, None, 0.30, 'symmetric', ('energy', {'krylov': 'cgnr'}))) A, B = linear_elasticity((50, 50), format='bsr') self.cases.append((A, B, 0.3, 'symmetric', ('energy', {'krylov': 'cg'}))) self.cases.append((A, B, 0.3, 'symmetric', ('energy', {'krylov': 'cgnr'}))) self.cases.append((A, B, 0.3, 'symmetric', ('energy', {'krylov': 'gmres'})))
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.toarray()) rs_old = ruge_stuben_solver(A, max_coarse=10) for AA in cases: rs_new = ruge_stuben_solver(AA, max_coarse=10) assert(np.abs(np.ravel(rs_old.levels[-1].A.toarray() - rs_new.levels[-1].A.toarray())).max() < 0.01) rs_old = rs_new
def demo(): """Outline basic demo.""" A = poisson((100, 100), format='csr') # 2D FD Poisson problem B = None # no near-null spaces guesses for SA b = sp.rand(A.shape[0], 1) # a random right-hand side # use AMG based on Smoothed Aggregation (SA) and display info mls = smoothed_aggregation_solver(A, B=B) print(mls) # Solve Ax=b with no acceleration ('standalone' solver) standalone_residuals = [] x = mls.solve(b, tol=1e-10, accel=None, residuals=standalone_residuals) # Solve Ax=b with Conjugate Gradient (AMG as a preconditioner to CG) accelerated_residuals = [] x = mls.solve(b, tol=1e-10, accel='cg', residuals=accelerated_residuals) del x # Compute relative residuals standalone_residuals = \ np.array(standalone_residuals) / standalone_residuals[0] accelerated_residuals = \ np.array(accelerated_residuals) / accelerated_residuals[0] # Compute (geometric) convergence factors factor1 = standalone_residuals[-1]**(1.0 / len(standalone_residuals)) factor2 = accelerated_residuals[-1]**(1.0 / len(accelerated_residuals)) print(" MG convergence factor: %g" % (factor1)) print("MG with CG acceleration convergence factor: %g" % (factor2)) # Plot convergence history try: import matplotlib.pyplot as plt plt.figure() plt.title('Convergence History') plt.xlabel('Iteration') plt.ylabel('Relative Residual') plt.semilogy(standalone_residuals, label='Standalone', linestyle='-', marker='o') plt.semilogy(accelerated_residuals, label='Accelerated', linestyle='-', marker='s') plt.legend() plt.show() except ImportError: print("\n\nNote: pylab not available on your system.")
def setUp(self): self.cases = [] A = poisson((5000, ), format='csr') self.cases.append((A, None, 0.4, 'symmetric', ('jacobi', { 'omega': 4.0 / 3.0 }))) self.cases.append((A, None, 0.4, 'symmetric', ('energy', { 'krylov': 'cg' }))) self.cases.append((A, None, 0.5, 'symmetric', ('energy', { 'krylov': 'gmres' }))) A = poisson((60, 60), format='csr') self.cases.append((A, None, 0.42, 'symmetric', ('jacobi', { 'omega': 4.0 / 3.0 }))) self.cases.append((A, None, 0.42, 'symmetric', ('energy', { 'krylov': 'cg' }))) self.cases.append((A, None, 0.42, 'symmetric', ('energy', { 'krylov': 'cgnr' }))) A, B = linear_elasticity((50, 50), format='bsr') self.cases.append((A, B, 0.32, 'symmetric', ('jacobi', { 'omega': 4.0 / 3.0 }))) self.cases.append((A, B, 0.22, 'symmetric', ('energy', { 'krylov': 'cg' }))) self.cases.append((A, B, 0.42, 'symmetric', ('energy', { 'krylov': 'cgnr' }))) self.cases.append((A, B, 0.42, 'symmetric', ('energy', { 'krylov': 'gmres' })))
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 = rootnode_solver(A, max_coarse=10) for AA in cases: sa_new = rootnode_solver(AA, max_coarse=10) dff = sa_old.levels[-1].A.todense() - sa_new.levels[-1].A.todense() assert(np.abs(np.ravel(dff)).max() < 0.01) sa_old = sa_new
def test_matrix_formats(self): warnings.simplefilter('ignore', SparseEfficiencyWarning) # 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.toarray()) sa_old = smoothed_aggregation_solver(A, max_coarse=10) for AA in cases: sa_new = smoothed_aggregation_solver(AA, max_coarse=10) assert(np.abs(np.ravel(sa_old.levels[-1].A.toarray() - sa_new.levels[-1].A.toarray())).max() < 0.01) sa_old = sa_new
def setUp(self): self.cases = [] # random matrices np.random.seed(0) for N in [2, 3, 5]: self.cases.append( csr_matrix(rand(N, N)) + csr_matrix(1.0j * rand(N, N))) # Poisson problems in 1D and 2D for N in [2, 3, 5, 7, 10, 11, 19]: A = poisson((N, ), format='csr') A.data = A.data + 1.0j * A.data self.cases.append(A) for N in [2, 3, 7, 9]: A = poisson((N, N), format='csr') A.data = A.data + 1.0j * rand(A.data.shape[0], ) self.cases.append(A) for name in ['knot', 'airfoil', 'bar']: ex = load_example(name) A = ex['A'].tocsr() A.data = A.data + 0.5j * rand(A.data.shape[0], ) self.cases.append(A)
def test_coarse_grid_solver(self): cases = [] cases.append(csr_matrix(diag(arange(1, 5)))) cases.append(poisson((4, ), format='csr')) cases.append(poisson((4, 4), format='csr')) # Make cases complex cases = [G + 1e-5j * G for G in cases] cases = [0.5 * (G + G.H) for G in cases] # method should be almost exact for small matrices for A in cases: for solver in ['splu', 'pinv', 'pinv2', 'lu', 'cholesky', 'cg']: s = coarse_grid_solver(solver) b = arange(A.shape[0], dtype=A.dtype) x = s(A, b) assert_almost_equal(A * x, b) # subsequent calls use cached data x = s(A, b) assert_almost_equal(A * x, b)
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 np.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'), np.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 = sp.rand(A.shape[0], 1) b = sp.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 topyamg(self): r""" Create a `pyamg` stencil matrix to be used in pyamg This allows retrieving the grid matrix equivalent of the real-space grid. Subsequently the returned matrix may be used in pyamg for solutions etc. The `pyamg` suite is it-self a rather complicated code with many options. For details we refer to `pyamg <pyamg https://github.com/pyamg/pyamg/>`_. Returns ------- A : scipy.sparse.csr_matrix which contains the grid stencil for a `pyamg` solver. b : numpy.ndarray containing RHS of the linear system of equations. Examples -------- This example proves the best method for a variety of cases in regards of the 3D Poisson problem: >>> grid = Grid(0.01) >>> A, b = grid.topyamg() # automatically setups the current boundary conditions >>> # add terms etc. to A and/or b >>> import pyamg >>> from scipy.sparse.linalg import cg >>> ml = pyamg.aggregation.smoothed_aggregation_solver(A, max_levels=1000) >>> M = ml.aspreconditioner(cycle='W') # pre-conditioner >>> x, info = cg(A, b, tol=1e-12, M=M) See Also -------- pyamg_index : convert grid indices into the sparse matrix indices for ``A`` pyamg_fix : fixes stencil for indices and fixes the source for the RHS matrix (uses `pyamg_source`) pyamg_source : fix the RHS matrix ``b`` to a constant value pyamg_boundary_condition : setup the sparse matrix ``A`` to given boundary conditions (called in this routine) """ from pyamg.gallery import poisson # Initially create the CSR matrix A = poisson(self.shape, dtype=self.dtype, format='csr') b = np.zeros(A.shape[0], dtype=A.dtype) # Now apply the boundary conditions self.pyamg_boundary_condition(A, b) return A, b
def test_matrix_formats(self): warnings.filterwarnings('ignore', category=SparseEfficiencyWarning) # 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.toarray()) np.random.seed(111908910) sa_old = adaptive_sa_solver(A, initial_candidates=np.ones((49, 1)), max_coarse=10)[0] for AA in cases: np.random.seed(111908910) sa_new = adaptive_sa_solver(AA, initial_candidates=np.ones((49, 1)), max_coarse=10)[0] assert(abs(np.ravel(sa_old.levels[-1].A.toarray() - sa_new.levels[-1].A.toarray())).max() < 0.01) sa_old = sa_new
def test_poisson(self): cases = [] # perturbed Laplacian A = poisson((50, 50), format='csr') Ai = A.copy() Ai.data = Ai.data + 1e-5j * np.random.rand(Ai.nnz) cases.append((Ai, 0.25)) # imaginary Laplacian Ai = 1.0j * A cases.append((Ai, 0.25)) # JBS: Not sure if this is a valid test case # imaginary shift # Ai = A + 1.1j*sparse.eye(A.shape[0], A.shape[1]) # cases.append((Ai,0.8)) for A, rratio in cases: [asa, work] = adaptive_sa_solver(A, num_candidates=1, symmetry='symmetric') # sa = smoothed_aggregation_solver(A, B = np.ones((A.shape[0],1)) ) b = np.zeros((A.shape[0], )) x0 = (np.random.rand(A.shape[0], ) + 1.0j * np.random.rand(A.shape[0], )) residuals0 = [] sol0 = asa.solve(b, x0=x0, maxiter=20, tol=1e-10, residuals=residuals0) del sol0 conv_asa = \ (residuals0[-1] / residuals0[0]) ** (1.0 / len(residuals0)) assert (conv_asa < rratio)
def test_poisson(self): A = poisson((50, 50), format='csr') [asa, work] = adaptive_sa_solver(A, num_candidates=1) sa = smoothed_aggregation_solver(A, B=np.ones((A.shape[0], 1))) b = sp.rand(A.shape[0]) residuals0 = [] residuals1 = [] sol0 = asa.solve(b, maxiter=20, tol=1e-10, residuals=residuals0) sol1 = sa.solve(b, maxiter=20, tol=1e-10, residuals=residuals1) del sol0, sol1 conv_asa = (residuals0[-1] / residuals0[0])**(1.0 / len(residuals0)) conv_sa = (residuals1[-1] / residuals1[0])**(1.0 / len(residuals1)) # print "ASA convergence (Poisson)",conv_asa # print "SA convergence (Poisson)",conv_sa assert (conv_asa < 1.2 * conv_sa)
def test_aspreconditioner(self): from pyamg import smoothed_aggregation_solver from scipy.sparse.linalg import cg from pyamg.krylov import fgmres A = poisson((50, 50), format='csr') b = rand(A.shape[0]) ml = smoothed_aggregation_solver(A) for cycle in ['V', 'W', 'F']: M = ml.aspreconditioner(cycle=cycle) x, info = cg(A, b, tol=1e-8, maxiter=30, M=M) # cg satisfies convergence in the preconditioner norm assert (precon_norm(b - A * x, ml) < 1e-8 * precon_norm(b, ml)) for cycle in ['AMLI']: M = ml.aspreconditioner(cycle=cycle) x, info = fgmres(A, b, tol=1e-8, maxiter=30, M=M) # fgmres satisfies convergence in the 2-norm assert (norm(b - A * x) < 1e-8 * norm(b))