package com.imsl.test.example.math; import com.imsl.math.*; /** *

* Solves a sparse linear system using the conjugate gradient method with * preconditioning.

* * In this example, two different preconditioners are used to find the solution * of a sparse positive definite linear system. The system occurs in a finite * difference solution of Laplace's equation on a regular \(c \times c\) grid, * where we use \(c = 50\). * * The matrix is $$ A = E(c^2, c) $$. For the * first solution, Jacobi preconditioning with preconditioner * \(M={\rm{diag}}(A)\) is used. The required iteration number and maximum * absolute error are printed. Next, a more complicated preconditioning matrix, * consisting of the symmetric tridiagonal part of A, is used. Again, the * iteration number and the maximum absolute error are printed. The iteration * number is substantially reduced. * * @see Code * @see Output * */ public class ConjugateGradientEx2 implements ConjugateGradient.Preconditioner { private SparseMatrix A; private SparseCholesky M; public ConjugateGradientEx2(int n, int c) throws SparseCholesky.NotSPDException { // Create matrix E(n,c), n>1, 1= 0) { A.set(j, j - c, -1.0); } if (j - 1 >= 0) { A.set(j, j - 1, -1.0); } A.set(j, j, 4.0); if (j + 1 < n) { A.set(j, j + 1, -1.0); } if (j + c < n) { A.set(j, j + c, -1.0); } } // Create and factor preconditioning matrix SparseMatrix C = new SparseMatrix(n, n); for (int j = 0; j < n; j++) { if (j - 1 >= 0) { C.set(j, j - 1, -1.0); } C.set(j, j, 4.0); if (j + 1 < n) { C.set(j, j + 1, -1.0); } } M = new SparseCholesky(C); M.factorSymbolically(); M.factorNumerically(); } public void amultp(double[] p, double[] z) { double w[] = A.multiply(p); System.arraycopy(w, 0, z, 0, w.length); } public void preconditioner(double[] r, double[] z) { try { double w[] = M.solve(r); System.arraycopy(w, 0, z, 0, w.length); } catch (SparseCholesky.NotSPDException e) { // No danger of NotSPDException because the system is only // solved here for given Cholesky factor. This exception // would have been thrown in the constructor already. } } public static void main(String args[]) throws Exception { int n = 2500; int c = 50; ConjugateGradientEx2 atp = new ConjugateGradientEx2(n, c); // Set a predetermined answer and diagonal double[] expected = new double[n]; double[] diagonal = new double[n]; for (int i = 0; i < n; i++) { expected[i] = (double) (i % 5); diagonal[i] = 4.0; } // Get right-hand side double[] b = new double[n]; atp.amultp(expected, b); // Solve system with Jacobi preconditioning ConjugateGradient cgJacobi = new ConjugateGradient(n, atp); cgJacobi.setJacobi(diagonal); double solution[] = cgJacobi.solve(b); // Compute inf-norm of computed solution - exact solution, // print results double norm = 0.0; for (int i = 0; i < n; i++) { norm = Math.max(norm, Math.abs(solution[i] - expected[i])); } System.out.println("Jacobi preconditioning"); System.out.println("Iterations= " + cgJacobi.getIterations() + ", norm= " + norm); System.out.println(); /* * Solve the same system, with Cholesky preconditioner */ ConjugateGradient cgCholesky = new ConjugateGradient(n, atp); solution = cgCholesky.solve(b); norm = 0.0; for (int i = 0; i < n; i++) { norm = Math.max(norm, Math.abs(solution[i] - expected[i])); } System.out.println("More general preconditioning"); System.out.println("Iterations= " + cgCholesky.getIterations() + ", norm= " + norm); } }