1 ## Copyright (C) 2009-2012 Carlo de Falco
3 ## This file is part of Octave.
5 ## Octave is free software; you can redistribute it and/or modify it
6 ## under the terms of the GNU General Public License as published by the
7 ## Free Software Foundation; either version 3 of the License, or (at your
8 ## option) any later version.
10 ## Octave is distributed in the hope that it will be useful, but WITHOUT
11 ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 ## You should have received a copy of the GNU General Public License
16 ## along with Octave; see the file COPYING. If not, see
17 ## <http://www.gnu.org/licenses/>.
20 ## @deftypefn {Function File} {@var{x} =} gmres (@var{A}, @var{b}, @var{m}, @var{rtol}, @var{maxit}, @var{M1}, @var{M2}, @var{x0})
21 ## @deftypefnx {Function File} {@var{x} =} gmres (@var{A}, @var{b}, @var{m}, @var{rtol}, @var{maxit}, @var{P})
22 ## @deftypefnx {Function File} {[@var{x}, @var{flag}, @var{relres}, @var{iter}, @var{resvec}] =} gmres (@dots{})
23 ## Solve @code{A x = b} using the Preconditioned GMRES iterative method
24 ## with restart, a.k.a. PGMRES(m).
27 ## @item @var{rtol} is the relative tolerance,
28 ## if not given or set to [] the default value 1e-6 is used.
30 ## @item @var{maxit} is the maximum number of outer iterations,
31 ## if not given or set to [] the default value
32 ## @code{min (10, numel (b) / restart)} is used.
34 ## @item @var{x0} is the initial guess,
35 ## if not given or set to [] the default value @code{zeros(size (b))} is used.
37 ## @item @var{m} is the restart parameter,
38 ## if not given or set to [] the default value @code{numel (b)} is used.
41 ## Argument @var{A} can be passed as a matrix, function handle, or
42 ## inline function @code{f} such that @code{f(x) = A*x}.
44 ## The preconditioner @var{P} is given as @code{P = M1 * M2}.
45 ## Both @var{M1} and @var{M2} can be passed as a matrix, function handle, or
46 ## inline function @code{g} such that @code{g(x) = M1\x} or @code{g(x) = M2\x}.
48 ## Besides the vector @var{x}, additional outputs are:
51 ## @item @var{flag} indicates the exit status:
53 ## @item 0 : iteration converged to within the specified tolerance
55 ## @item 1 : maximum number of iterations exceeded
57 ## @item 2 : unused, but skipped for compatibility
59 ## @item 3 : algorithm reached stagnation
62 ## @item @var{relres} is the final value of the relative residual.
64 ## @item @var{iter} is a vector containing the number of outer iterations and
65 ## total iterations performed.
67 ## @item @var{resvec} is a vector containing the relative residual at each
71 ## @seealso{bicg, bicgstab, cgs, pcg}
74 function [x, flag, presn, it, resids] = gmres (A, b, restart, rtol, maxit, M1, M2, x0)
76 if (nargin < 2 || nargin > 8)
84 elseif (isa (A, "function_handle"))
87 error ("gmres: A must be a function or matrix");
90 if (nargin < 3 || isempty (restart))
94 if (nargin < 4 || isempty (rtol))
98 if (nargin < 5 || isempty (maxit))
99 maxit = min (rows (b)/restart, 10);
102 if (nargin < 6 || isempty (M1))
105 M1m1x = str2func (M1);
106 elseif (ismatrix (M1))
108 elseif (isa (M1, "function_handle"))
111 error ("gmres: preconditioner M1 must be a function or matrix");
114 if (nargin < 7 || isempty (M2))
117 M2m1x = str2func (M2);
118 elseif (ismatrix (M2))
120 elseif (isa (M2, "function_handle"))
123 error ("gmres: preconditioner M2 must be a function or matrix");
126 Pm1x = @(x) M2m1x (M1m1x (x));
128 if (nargin < 8 || isempty (x0))
129 x0 = zeros (size (b));
134 prec_res = Pm1x (b - Ax (x_old));
135 presn = norm (prec_res, 2);
137 B = zeros (restart + 1, 1);
138 V = zeros (rows (x), restart);
139 H = zeros (restart + 1, restart);
143 restart_it = restart + 1;
144 resids = zeros (maxit, 1);
146 prec_b_norm = norm (Pm1x (b), 2);
149 while (iter <= maxit * restart && presn > rtol * prec_b_norm)
152 if (restart_it > restart)
155 prec_res = Pm1x (b - Ax (x_old));
156 presn = norm (prec_res, 2);
159 V(:, 1) = prec_res / presn;
163 tmp = Pm1x (Ax (V(:, restart_it)));
164 [V(:,restart_it+1), H(1:restart_it+1, restart_it)] = ...
165 mgorth (tmp, V(:,1:restart_it));
167 Y = (H(1:restart_it+1, 1:restart_it) \ B (1:restart_it+1));
169 little_res = B(1:restart_it+1) - ...
170 H(1:restart_it+1, 1:restart_it) * Y(1:restart_it);
172 presn = norm (little_res, 2);
174 x = x_old + V(:, 1:restart_it) * Y(1:restart_it);
176 resids(iter) = presn;
177 if (norm (x - x_old, inf) <= eps)
186 if (presn > rtol * prec_b_norm)
190 resids = resids(1:iter-1);
191 it = [ceil(iter / restart), rem(iter, restart)];
199 %! A = spdiags ([-ones(dim,1) 2*ones(dim,1) ones(dim,1)], [-1:1], dim, dim);
201 %! x = gmres (A, b, 10, 1e-10, dim, @(x) x./diag(A), [], b);
202 %! assert(x, A\b, 1e-9*norm(x,inf));
205 %! x = gmres (A, b, dim, 1e-10, 1e4, @(x) diag(diag(A))\x, [], b);
206 %! assert(x, A\b, 1e-7*norm(x,inf));
209 %! A = spdiags ([[1./(2:2:2*(dim-1)) 0]; 1./(1:2:2*dim-1); [0 1./(2:2:2*(dim-1))]]', -1:1, dim, dim);
211 %! b = rand (dim, 1);
212 %! [x, resids] = gmres (@(x) A*x, b, dim, 1e-10, dim, @(x) x./diag(A), [], []);
213 %! assert(x, A\b, 1e-9*norm(x,inf))
214 %! x = gmres (@(x) A*x, b, dim, 1e-10, 1e6, @(x) diag(diag(A))\x, [], []);
215 %! assert(x, A\b, 1e-9*norm(x,inf));
217 %! x = gmres (@(x) A*x, b, dim, 1e-10, 1e6, @(x) x./diag(A), [], []);
218 %! assert(x, A\b, 1e-7*norm(x,inf));