Solve the linear system of equations A * x = b by
means of the Preconditioned Conjugate Residuals iterative method.
The input arguments are
A * x. In principle A should be
symmetric and non-singular; if pcr finds A to be numerically
singular, you will get a warning message and the flag output
parameter will be set.
b - A * x. The iteration stops if
norm (b - A * x) <=
tol * norm (b - A * x0).
If tol is empty or is omitted, the function sets
tol = 1e-6 by default.
[] is
supplied for maxit, or pcr has less arguments, a default
value equal to 20 is used.
pcr P * x = m \ b, with
P = m \ A. Note that a proper choice of the
preconditioner may dramatically improve the overall performance of the
method. Instead of matrix m, the user may pass a function which
returns the results of applying the inverse of m to a vector
(usually this is the preferred way of using the preconditioner). If
[] is supplied for m, or m is omitted, no
preconditioning is applied.
The arguments which follow x0 are treated as parameters, and passed
in a proper way to any of the functions (A or m) which are
passed to pcr. See the examples below for further details.
The output arguments are
A * x = b.
flag = 0 means the
solution converged and the tolerance criterion given by tol is
satisfied. flag = 1 means that the maxit limit for the
iteration count was reached. flag = 3 reports a pcr
breakdown, see [1] for details.
resvec (i) contains the Euclidean norms of the residual after
the (i-1)-th iteration, i = 1,2, …, iter+1.
Let us consider a trivial problem with a diagonal matrix (we exploit the sparsity of A)
n = 10; A = sparse (diag (1:n)); b = rand (N, 1);
EXAMPLE 1: Simplest use of pcr
x = pcr (A, b)
EXAMPLE 2: pcr with a function which computes
A * x.
function y = apply_a (x)
y = [1:10]' .* x;
endfunction
x = pcr ("apply_a", b)
EXAMPLE 3: Preconditioned iteration, with full diagnostics. The preconditioner (quite strange, because even the original matrix A is trivial) is defined as a function
function y = apply_m (x)
k = floor (length (x) - 2);
y = x;
y(1:k) = x(1:k) ./ [1:k]';
endfunction
[x, flag, relres, iter, resvec] = ...
pcr (A, b, [], [], "apply_m")
semilogy ([1:iter+1], resvec);
EXAMPLE 4: Finally, a preconditioner which depends on a parameter k.
function y = apply_m (x, varargin)
k = varargin{1};
y = x;
y(1:k) = x(1:k) ./ [1:k]';
endfunction
[x, flag, relres, iter, resvec] = ...
pcr (A, b, [], [], "apply_m"', [], 3)
References:
[1] W. Hackbusch, Iterative Solution of Large Sparse Systems of Equations, section 9.5.4; Springer, 1994
See also: sparse, pcg.
The following code
## Simplest usage of PCR (see also 'help pcr')
N = 20;
A = diag (linspace (-3.1,3,N)); b = rand (N,1);
y = A \ b; # y is the true solution
x = pcr (A,b);
printf ("The solution relative error is %g\n", norm (x-y) / norm (y));
## You shouldn't be afraid if PCR issues some warning messages in this
## example: watch out in the second example, why it takes N iterations
## of PCR to converge to (a very accurate, by the way) solution.
Produces the following output
warning: pcr: maximum number of iterations (20) reached warning: pcr: the initial residual norm was reduced 1.75488e+10 times The solution relative error is 2.1769e-11
The following code
## Full output from PCR
## We use this output to plot the convergence history
N = 20;
A = diag (linspace (-3.1,30,N)); b = rand (N,1);
X = A \ b; # X is the true solution
[x, flag, relres, iter, resvec] = pcr (A,b);
printf ("The solution relative error is %g\n", norm (x-X) / norm (X));
clf;
title ("Convergence history");
xlabel ("Iteration"); ylabel ("log(||b-Ax||/||b||)");
semilogy ([0:iter], resvec/resvec(1), "o-g;relative residual;");
Produces the following output
The solution relative error is 5.17225e-15
and the following figure
| Figure 1 |
|---|
![]() |
The following code
## Full output from PCR
## We use indefinite matrix based on the Hilbert matrix, with one
## strongly negative eigenvalue
## Hilbert matrix is extremely ill conditioned, so is ours,
## and that's why PCR WILL have problems
N = 10;
A = hilb (N); A(1,1) = -A(1,1); b = rand (N,1);
X = A \ b; # X is the true solution
printf ("Condition number of A is %g\n", cond (A));
[x, flag, relres, iter, resvec] = pcr (A,b,[],200);
if (flag == 3)
printf ("PCR breakdown. System matrix is [close to] singular\n");
endif
clf;
title ("Convergence history");
xlabel ("Iteration"); ylabel ("log(||b-Ax||)");
semilogy ([0:iter], resvec, "o-g;absolute residual;");
Produces the following output
Condition number of A is 8.64595e+12 PCR breakdown. System matrix is [close to] singular
and the following figure
| Figure 1 |
|---|
![]() |
The following code
## Full output from PCR
## We use an indefinite matrix based on the 1-D Laplacian matrix for A,
## and here we have cond(A) = O(N^2)
## That's the reason we need some preconditioner; here we take
## a very simple and not powerful Jacobi preconditioner,
## which is the diagonal of A.
## Note that we use here indefinite preconditioners!
N = 100;
A = zeros (N,N);
for i=1:N-1 # form 1-D Laplacian matrix
A(i:i+1,i:i+1) = [2 -1; -1 2];
endfor
A = [A, zeros(size(A)); zeros(size(A)), -A];
b = rand (2*N,1);
X = A \ b; # X is the true solution
maxit = 80;
printf ("System condition number is %g\n", cond (A));
## No preconditioner: the convergence is very slow!
[x, flag, relres, iter, resvec] = pcr (A,b,[],maxit);
clf;
title ("Convergence history");
xlabel ("Iteration"); ylabel ("log(||b-Ax||)");
semilogy ([0:iter], resvec, "o-g;NO preconditioning: absolute residual;");
pause (1);
## Test Jacobi preconditioner: it will not help much!!!
M = diag (diag (A)); # Jacobi preconditioner
[x, flag, relres, iter, resvec] = pcr (A,b,[],maxit,M);
hold on;
semilogy ([0:iter],resvec,"o-r;JACOBI preconditioner: absolute residual;");
pause (1);
## Test nonoverlapping block Jacobi preconditioner: this one should give
## some convergence speedup!
M = zeros (N,N); k = 4;
for i=1:k:N # get k x k diagonal blocks of A
M(i:i+k-1,i:i+k-1) = A(i:i+k-1,i:i+k-1);
endfor
M = [M, zeros(size (M)); zeros(size(M)), -M];
[x, flag, relres, iter, resvec] = pcr (A,b,[],maxit,M);
semilogy ([0:iter], resvec, "o-b;BLOCK JACOBI preconditioner: absolute residual;");
hold off;
Produces the following output
System condition number is 4133.64
and the following figure
| Figure 1 |
|---|
![]() |
Package: octave