comparison scripts/sparse/bicg.m @ 13073:51bc892d5cf8

Move bicg.m to scripts/sparse for uniformity * bicg.m : Move to scripts/sparse where the other iterative solvers are.
author Carlo de Falco <kingcrimson@tiscali.it>
date Sat, 03 Sep 2011 21:51:26 +0200
parents scripts/linear-algebra/bicg.m@a0d854f079d2
children e5aaba072d2b
comparison
equal deleted inserted replaced
13072:39814ef3278b 13073:51bc892d5cf8
1 ## Copyright (C) 2006 Sylvain Pelissier <sylvain.pelissier@gmail.com>
2 ## Copyright (C) 2011 Carlo de Falco
3 ##
4 ## This program is free software; you can redistribute it and/or modify
5 ## it under the terms of the GNU General Public License as published by
6 ## the Free Software Foundation; either version 2 of the License, or
7 ## (at your option) any later version.
8 ##
9 ## This program is distributed in the hope that it will be useful,
10 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ## GNU General Public License for more details.
13 ##
14 ## You should have received a copy of the GNU General Public License
15 ## along with this program; If not, see <http://www.gnu.org/licenses/>.
16
17 ## -*- texinfo -*-
18 ##
19 ## @deftypefn {Function File} {@var{x} =} bicg (@var{A}, @var{b}, @var{rtol}, @var{maxit}, @var{M1}, @var{M2}, @var{x0})
20 ## @deftypefnx {Function File} {@var{x} =} bicg (@var{A}, @var{b}, @var{rtol}, @var{maxit}, @var{P})
21 ## @deftypefnx {Function File} {[@var{x}, @var{flag}, @var{relres}, @var{iter}, @var{resvec}] =} bicg (@var{A}, @var{b}, ...)
22 ##
23 ## Solve @code{A x = b} using the Bi-conjugate gradient iterative method.
24 ##
25 ## @itemize @minus
26 ## @item @var{rtol} is the relative tolerance, if not given or set to [] the default value 1e-6 is used.
27 ## @item @var{maxit} the maximum number of outer iterations, if not given or set to [] the default value @code{min (20, numel (b))} is used.
28 ## @item @var{x0} the initial guess, if not given or set to [] the default value @code{zeros (size (b))} is used.
29 ## @end itemize
30 ##
31 ## @var{A} can be passed as a matrix or as a function handle or
32 ## inline function @code{f} such that @code{f(x, "notransp") = A*x} and @code{f(x, "transp") = A'*x}.
33 ##
34 ## The preconditioner @var{P} is given as @code{P = M1 * M2}.
35 ## Both @var{M1} and @var{M2} can be passed as a matrix or as a function handle or
36 ## inline function @code{g} such that @code{g(x, 'notransp') = M1 \ x} or @code{g(x, 'notransp') = M2 \ x} and
37 ## @code{g(x, 'transp') = M1' \ x} or @code{g(x, 'transp') = M2' \ x}.
38 ##
39 ## If colled with more than one output parameter
40 ##
41 ## @itemize @minus
42 ## @item @var{flag} indicates the exit status:
43 ## @itemize @minus
44 ## @item 0: iteration converged to the within the chosen tolerance
45 ## @item 1: the maximum number of iterations was reached before convergence
46 ## @item 3: the algorithm reached stagnation
47 ## @end itemize
48 ## (the value 2 is unused but skipped for compatibility).
49 ## @item @var{relres} is the final value of the relative residual.
50 ## @item @var{iter} is the number of iterations performed.
51 ## @item @var{resvec} is a vector containing the relative residual at each iteration.
52 ## @end itemize
53 ##
54 ## @seealso{pcg,cgs,bicgstab,gmres}
55 ##
56 ## @end deftypefn
57
58
59 function [x, flag, res1, k, resvec] = bicg (A, b, tol, maxit, M1, M2, x0)
60
61 if ((nargin >= 2) && isvector (full (b)))
62
63 if (ischar (A))
64 fun = str2func (A);
65 Ax = @(x) feval (fun, x, "notransp");
66 Atx = @(x) feval (fun, x, "transp");
67 elseif (ismatrix (A))
68 Ax = @(x) A * x;
69 Atx = @(x) A' * x;
70 elseif (isa (A, "function_handle"))
71 Ax = @(x) feval (A, x, "notransp");
72 Atx = @(x) feval (A, x, "transp");
73 else
74 error (["bicg: first argument is expected to " ...
75 "be a function or a square matrix"]);
76 endif
77
78 if ((nargin < 3) || (isempty (tol)))
79 tol = 1e-6;
80 endif
81
82 if ((nargin < 4) || (isempty (maxit)))
83 maxit = min (rows (b), 20);
84 endif
85
86 if ((nargin < 5) || isempty (M1))
87 M1m1x = @(x, ignore) x;
88 M1tm1x = M1m1x;
89 elseif (ischar (M1))
90 fun = str2func (M1);
91 M1m1x = @(x) feval (fun, x, "notransp");
92 M1tm1x = @(x) feval (fun, x, "transp");
93 elseif (ismatrix (M1))
94 M1m1x = @(x) M1 \ x;
95 M1tm1x = @(x) M1' \ x;
96 elseif (isa (M1, "function_handle"))
97 M1m1x = @(x) feval (M1, x, "notransp");
98 M1tm1x = @(x) feval (M1, x, "transp");
99 else
100 error (["bicg: preconditioner is expected to " ...
101 "be a function or matrix"]);
102 endif
103
104 if ((nargin < 6) || isempty (M2))
105 M2m1x = @(x, ignore) x;
106 M2tm1x = M2m1x;
107 elseif (ischar (M2))
108 fun = str2func (M2);
109 M2m1x = @(x) feval (fun, x, "notransp");
110 M2tm1x = @(x) feval (fun, x, "transp");
111 elseif (ismatrix (M2))
112 M2m1x = @(x) M2 \ x;
113 M2tm1x = @(x) M2' \ x;
114 elseif (isa (M2, "function_handle"))
115 M2m1x = @(x) feval (M2, x, "notransp");
116 M2tm1x = @(x) feval (M2, x, "transp");
117 else
118 error (["bicg: preconditioner is expected to " ...
119 "be a function or matrix"]);
120 endif
121
122 Pm1x = @(x) M2m1x (M1m1x (x));
123 Ptm1x = @(x) M1tm1x (M2tm1x (x));
124
125 if ((nargin < 7) || (isempty (x0)))
126 x0 = zeros (size (b));
127 endif
128
129 y = x = x0;
130 c = b;
131
132 r0 = b - Ax (x);
133 s0 = c - Atx (y);
134
135 d = Pm1x (r0);
136 f = Ptm1x (s0);
137
138 bnorm = norm (b);
139 res0 = Inf;
140
141 if (any (r0 != 0))
142
143 for k = 1:maxit
144
145 a = (s0' * Pm1x (r0)) ./ (f' * Ax (d));
146
147 x += a * d;
148 y += conj (a) * f;
149
150 r1 = r0 - a * Ax (d);
151 s1 = s0 - conj (a) * Atx (f);
152
153 beta = (s1' * Pm1x (r1)) ./ (s0' * Pm1x (r0));
154
155 d = Pm1x (r1) + beta * d;
156 f = Ptm1x (s1) + conj (beta) * f;
157
158 r0 = r1;
159 s0 = s1;
160
161 res1 = norm (b - Ax (x)) / bnorm;
162 if (res1 < tol)
163 flag = 0;
164 if (nargout < 2)
165 printf ("bicg converged at iteration %i ", k);
166 printf ("to a solution with relative residual %e\n", res1);
167 endif
168 break;
169 endif
170
171 if (res0 <= res1)
172 flag = 3;
173 printf ("bicg stopped at iteration %i ", k);
174 printf ("without converging to the desired tolerance %e\n", tol);
175 printf ("because the method stagnated.\n");
176 printf ("The iterate returned (number %i) ", k-1);
177 printf ("has relative residual %e\n", res0);
178 break
179 endif
180 res0 = res1;
181 if (nargout > 4)
182 resvec(k) = res0;
183 endif
184 endfor
185
186 if (k == maxit)
187 flag = 1;
188 printf ("bicg stopped at iteration %i ", maxit);
189 printf ("without converging to the desired tolerance %e\n", tol);
190 printf ("because the maximum number of iterations was reached. ");
191 printf ("The iterate returned (number %i) has ", maxit);
192 printf ("relative residual %e\n", res1);
193 endif
194
195 else
196 flag = 0;
197 if (nargout < 2)
198 printf ("bicg converged after 0 interations\n");
199 endif
200 endif
201
202 else
203 print_usage ();
204 endif
205
206 endfunction;
207
208
209 %!test
210 %! n = 100;
211 %! A = spdiags ([-2*ones(n,1) 4*ones(n,1) -ones(n,1)], -1:1, n, n);
212 %! b = sum (A, 2);
213 %! tol = 1e-8;
214 %! maxit = 15;
215 %! M1 = spdiags ([ones(n,1)/(-2) ones(n,1)],-1:0, n, n);
216 %! M2 = spdiags ([4*ones(n,1) -ones(n,1)], 0:1, n, n);
217 %! [x, flag, relres, iter, resvec] = bicg (A, b, tol, maxit, M1, M2);
218 %! assert (x, ones (size (b)), 1e-7);
219 %!
220 %!test
221 %! n = 100;
222 %! A = spdiags ([-2*ones(n,1) 4*ones(n,1) -ones(n,1)], -1:1, n, n);
223 %! b = sum (A, 2);
224 %! tol = 1e-8;
225 %! maxit = 15;
226 %! M1 = spdiags ([ones(n,1)/(-2) ones(n,1)],-1:0, n, n);
227 %! M2 = spdiags ([4*ones(n,1) -ones(n,1)], 0:1, n, n);
228 %!
229 %! function y = afun (x, t, a)
230 %! switch t
231 %! case "notransp"
232 %! y = a * x;
233 %! case "transp"
234 %! y = a' * x;
235 %! endswitch
236 %! endfunction
237 %!
238 %! [x, flag, relres, iter, resvec] = bicg (@(x, t) afun (x, t, A),
239 %! b, tol, maxit, M1, M2);
240 %! assert (x, ones (size (b)), 1e-7);
241
242 %!test
243 %! n = 100;
244 %! tol = 1e-8;
245 %! a = sprand (n, n, .1);
246 %! A = a' * a + 100 * eye (n);
247 %! b = sum (A, 2);
248 %! [x, flag, relres, iter, resvec] = bicg (A, b, tol, [], diag (diag (A)));
249 %! assert (x, ones (size (b)), 1e-7);