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