Example 6: The Second Householder Implementation With Preconditioning
The coefficient matrix in this example corresponds to the five-point discretization of the 2-d Poisson equation with the Dirichlet boundary condition. Assuming the natural ordering of the unknowns, and moving all boundary terms to the right hand side, we obtain a block tridiagonal matrix. (Consider the tridiagonal matrix T which has the value 4.0 down the main diagonal and -1.0 along the upper and lower co-diagonals. Then the coefficient matrix is the block tridiagonal matrix consisting of T's down the main diagonal and -I along the upper and lower codiagonals where I is the identity matrix.) Discretizing on a 20 x 20 grid implies that the coefficient matrix is 400 x 400. In the solution, the second Householder implementation is selected and we choose to update the residual vector by direct evaluation. Preconditioning is used with the preconditioning matrix being a diagonal matrix with 4.0 down the main diagonal and -1.0 along the upper and lower co-diagonals. This preconditioner
method solves this tridiagonal matrix.
import com.imsl.math.*;
public class GenMinResEx6 implements GenMinRes.Preconditioner {
private double precondA[], precondB[], precondC[];
// Creates a new instance of GenMinResEx6
public GenMinResEx6(int n) throws Exception {
precondA = new double[n];
precondB = new double[n];
precondC = new double[n];
// Define the preconditioning matrix
for(int i = 0; i < n; i++) {
precondA[i] = 4.0;
precondB[i] = -1.0;
precondC[i] = -1.0;
}
}
public void amultp(double p[], double z[]) {
int m = z.length;
int n = (int)Math.sqrt(m);
// Multiply by diagonal blocks
for (int i = 0; i < m; i++) {
z[i] = 4.0 * p[i];
}
for (int i = 0; i < m-2; i++) {
z[i] -= p[i+1];
}
for (int i = 0; i < m-2; i++) {
z[i+1] -= p[i];
}
// Correct for terms not properly in block diagonal
for (int i = n-1; i < m-n; i=i+n) {
z[i] += p[i+1];
z[i+1] += p[i];
}
// Do the super and subdiagonal blocks, the -I's
for (int i = 0; i < m-n; i++) {
z[i] -= p[i+n];
}
for (int i = 0; i < m-n; i++) {
z[i+n] -= p[i];
}
}
/**
* Solve the tridiagonal preconditioning matrix problem for z.
*/
public void preconditioner(double r[], double z[]) {
int n = z.length;
double w[] = new double[n];
double v[] = new double[n];
double u[] = new double[n];
w[0] = precondA[0];
v[0] = precondC[0] / w[0];
u[0] = r[0] / w[0];
for (int i = 1; i < n; i++) {
w[i] = precondA[i] - precondB[i]*v[i-1];
v[i] = precondC[i] / w[i];
u[i] = (r[i]-precondB[i]*u[i-1]) / w[i];
}
z[n-1] = u[n-1];
for (int j = n-2; j >= 0; j--) {
z[j] = u[j] - v[j]*z[j+1];
}
}
public static void main(String args[]) throws Exception {
int n = 400;
double b[] = new double[n];
double xguess[] = new double[n];
GenMinResEx6 atp = new GenMinResEx6(n);
// Construct a GenMinRes object
GenMinRes gnmnrs = new GenMinRes(n, atp);
// Set right hand side and initial guess to ones
for(int i = 0; i < n; i++){
b[i] = 1.0;
xguess[i] = 1.0;
}
gnmnrs.setGuess(xguess);
gnmnrs.setMethod(gnmnrs.SECOND_HOUSEHOLDER);
gnmnrs.setResidualUpdating(gnmnrs.DIRECT_AT_RESTART_ONLY);
// Solve Ax = b
gnmnrs.solve(b);
int iterations = gnmnrs.getIterations();
System.out.println("The number of iterations used = "+iterations);
double resnorm = gnmnrs.getResidualNorm();
System.out.println("The final residual norm is "+resnorm);
}
}
Output
The number of iterations used = 60
The final residual norm is 2.841414917241539E-7
Link to Java source.