Grid 0.7.0
QuasiMinimalResidual.h
Go to the documentation of this file.
1/*************************************************************************************
2
3Grid physics library, www.github.com/paboyle/Grid
4
5Source file: ./lib/algorithmsf/iterative/QuasiMinimalResidual.h
6
7Copyright (C) 2019
8
9Author: Peter Boyle <paboyle@ph.ed.ac.uk>
10
11This program is free software; you can redistribute it and/or modify
12it under the terms of the GNU General Public License as published by
13the Free Software Foundation; either version 2 of the License, or
14(at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License along
22with this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24
25See the full license in the file "LICENSE" in the top level distribution
26directory
27*************************************************************************************/
28/* END LEGAL */
29#pragma once
30
32
33template<class Field>
34RealD innerG5ProductReal(Field &l, Field &r)
35{
36 Gamma G5(Gamma::Algebra::Gamma5);
37 Field tmp(l.Grid());
38 // tmp = G5*r;
39 G5R5(tmp,r);
40 ComplexD ip =innerProduct(l,tmp);
41 std::cout << "innerProductRealG5R5 "<<ip<<std::endl;
42 return ip.real();
43}
44
45template<class Field>
47 public:
48 using OperatorFunction<Field>::operator();
49
54
56 Integer maxit,
57 bool err_on_no_conv = true)
58 : Tolerance(tol)
59 , MaxIterations(maxit)
60 , ErrorOnNoConverge(err_on_no_conv)
61 {};
62
63#if 1
64 void operator()(LinearOperatorBase<Field> &LinOp, const Field &b, Field &x)
65 {
66 RealD resid;
68
69 RealD rho, rho_1, xi, gamma, gamma_1, theta, theta_1;
70 RealD eta, delta, ep, beta;
71
72 GridBase *Grid = b.Grid();
73 Field r(Grid), d(Grid), s(Grid);
74 Field v(Grid), w(Grid), y(Grid), z(Grid);
75 Field v_tld(Grid), w_tld(Grid), y_tld(Grid), z_tld(Grid);
76 Field p(Grid), q(Grid), p_tld(Grid);
77
78 Real normb = norm2(b);
79
80 LinOp.Op(x,r); r = b - r;
81
82 assert(normb> 0.0);
83
84 resid = norm2(r)/normb;
85 if (resid <= Tolerance) {
86 return;
87 }
88
89 v_tld = r;
90 y = v_tld;
91 rho = norm2(y);
92
93 // Take Gamma5 conjugate
94 // Gamma G5(Gamma::Algebra::Gamma5);
95 // G5R5(w_tld,r);
96 // w_tld = G5* v_tld;
97 w_tld=v_tld;
98 z = w_tld;
99 xi = norm2(z);
100
101 gamma = 1.0;
102 eta = -1.0;
103 theta = 0.0;
104
105 for (int i = 1; i <= MaxIterations; i++) {
106
107 // Breakdown tests
108 assert( rho != 0.0);
109 assert( xi != 0.0);
110
111 v = (1. / rho) * v_tld;
112 y = (1. / rho) * y;
113
114 w = (1. / xi) * w_tld;
115 z = (1. / xi) * z;
116
117 ComplexD Zdelta = innerProduct(z, y); // Complex?
118 std::cout << "Zdelta "<<Zdelta<<std::endl;
119 delta = Zdelta.real();
120
121 y_tld = y;
122 z_tld = z;
123
124 if (i > 1) {
125 p = y_tld - (xi * delta / ep) * p;
126 q = z_tld - (rho * delta / ep) * q;
127 } else {
128 p = y_tld;
129 q = z_tld;
130 }
131
132 LinOp.Op(p,p_tld); // p_tld = A * p;
133 ComplexD Zep = innerProduct(q, p_tld);
134 ep=Zep.real();
135 std::cout << "Zep "<<Zep <<std::endl;
136 // Complex Audit
137 assert(abs(ep)>0);
138
139 beta = ep / delta;
140 assert(abs(beta)>0);
141
142 v_tld = p_tld - beta * v;
143 y = v_tld;
144
145 rho_1 = rho;
146 rho = norm2(y);
147 LinOp.AdjOp(q,w_tld);
148 w_tld = w_tld - beta * w;
149 z = w_tld;
150
151 xi = norm2(z);
152
153 gamma_1 = gamma;
154 theta_1 = theta;
155
156 theta = rho / (gamma_1 * beta);
157 gamma = 1.0 / sqrt(1.0 + theta * theta);
158 std::cout << "theta "<<theta<<std::endl;
159 std::cout << "gamma "<<gamma<<std::endl;
160
161 assert(abs(gamma)> 0.0);
162
163 eta = -eta * rho_1 * gamma* gamma / (beta * gamma_1 * gamma_1);
164
165 if (i > 1) {
166 d = eta * p + (theta_1 * theta_1 * gamma * gamma) * d;
167 s = eta * p_tld + (theta_1 * theta_1 * gamma * gamma) * s;
168 } else {
169 d = eta * p;
170 s = eta * p_tld;
171 }
172
173 x =x+d; // update approximation vector
174 r =r-s; // compute residual
175
176 if ((resid = norm2(r) / normb) <= Tolerance) {
177 return;
178 }
179 std::cout << "Iteration "<<i<<" resid " << resid<<std::endl;
180 }
181 assert(0);
182 return; // no convergence
183 }
184#else
185 // QMRg5 SMP thesis
186 void operator()(LinearOperatorBase<Field> &LinOp, const Field &b, Field &x)
187 {
188 // Real scalars
189 GridBase *grid = b.Grid();
190
191 Field r(grid);
192 Field p_m(grid), p_m_minus_1(grid), p_m_minus_2(grid);
193 Field v_m(grid), v_m_minus_1(grid), v_m_plus_1(grid);
194 Field tmp(grid);
195
196 RealD w;
197 RealD z1, z2;
198 RealD delta_m, delta_m_minus_1;
199 RealD c_m_plus_1, c_m, c_m_minus_1;
200 RealD s_m_plus_1, s_m, s_m_minus_1;
201 RealD alpha, beta, gamma, epsilon;
202 RealD mu, nu, rho, theta, xi, chi;
203 RealD mod2r, mod2b;
204 RealD tau2, target2;
205
206 mod2b=norm2(b);
207
209 // Initial residual
211 LinOp.Op(x,tmp);
212 r = b - tmp;
213
215 // \mu = \rho = |r_0|
217 mod2r = norm2(r);
218 rho = sqrt( mod2r);
219 mu=rho;
220
221 std::cout << "QuasiMinimalResidual rho "<< rho<<std::endl;
223 // Zero negative history
225 v_m_plus_1 = Zero();
226 v_m_minus_1 = Zero();
227 p_m_minus_1 = Zero();
228 p_m_minus_2 = Zero();
229
230 // v0
231 v_m = (1.0/rho)*r;
232
234 // Initial coeffs
236 delta_m_minus_1 = 1.0;
237 c_m_minus_1 = 1.0;
238 c_m = 1.0;
239 s_m_minus_1 = 0.0;
240 s_m = 0.0;
241
243 // Set up convergence check
245 tau2 = mod2r;
246 target2 = mod2b * Tolerance*Tolerance;
247
248 for(int iter = 0 ; iter < MaxIterations; iter++){
249
251 // \delta_m = (v_m, \gamma_5 v_m)
253 delta_m = innerG5ProductReal(v_m,v_m);
254 std::cout << "QuasiMinimalResidual delta_m "<< delta_m<<std::endl;
255
257 // tmp = A v_m
259 LinOp.Op(v_m,tmp);
260
262 // \alpha = (v_m, \gamma_5 temp) / \delta_m
264 alpha = innerG5ProductReal(v_m,tmp);
265 alpha = alpha/delta_m ;
266 std::cout << "QuasiMinimalResidual alpha "<< alpha<<std::endl;
267
269 // \beta = \rho \delta_m / \delta_{m-1}
271 beta = rho * delta_m / delta_m_minus_1;
272 std::cout << "QuasiMinimalResidual beta "<< beta<<std::endl;
273
275 // \tilde{v}_{m+1} = temp - \alpha v_m - \beta v_{m-1}
277 v_m_plus_1 = tmp - alpha*v_m - beta*v_m_minus_1;
278
280 // \rho = || \tilde{v}_{m+1} ||
282 rho = sqrt( norm2(v_m_plus_1) );
283 std::cout << "QuasiMinimalResidual rho "<< rho<<std::endl;
284
286 // v_{m+1} = \tilde{v}_{m+1}
288 v_m_plus_1 = (1.0 / rho) * v_m_plus_1;
289
291 // QMR recurrence coefficients.
293 theta = s_m_minus_1 * beta;
294 gamma = c_m_minus_1 * beta;
295 epsilon = c_m * gamma + s_m * alpha;
296 xi = -s_m * gamma + c_m * alpha;
297 nu = sqrt( xi*xi + rho*rho );
298 c_m_plus_1 = fabs(xi) / nu;
299 if ( xi == 0.0 ) {
300 s_m_plus_1 = 1.0;
301 } else {
302 s_m_plus_1 = c_m_plus_1 * rho / xi;
303 }
304 chi = c_m_plus_1 * xi + s_m_plus_1 * rho;
305
306 std::cout << "QuasiMinimalResidual coeffs "<< theta <<" "<<gamma<<" "<< epsilon<<" "<< xi<<" "<< nu<<std::endl;
307 std::cout << "QuasiMinimalResidual coeffs "<< chi <<std::endl;
308
310 //p_m=(v_m - \epsilon p_{m-1} - \theta p_{m-2}) / \chi
312 p_m = (1.0/chi) * v_m - (epsilon/chi) * p_m_minus_1 - (theta/chi) * p_m_minus_2;
313
315 // \psi = \psi + c_{m+1} \mu p_m
317 x = x + ( c_m_plus_1 * mu ) * p_m;
318
320 //
322 mu = -s_m_plus_1 * mu;
323 delta_m_minus_1 = delta_m;
324 c_m_minus_1 = c_m;
325 c_m = c_m_plus_1;
326 s_m_minus_1 = s_m;
327 s_m = s_m_plus_1;
328
330 // Could use pointer swizzle games.
332 v_m_minus_1 = v_m;
333 v_m = v_m_plus_1;
334 p_m_minus_2 = p_m_minus_1;
335 p_m_minus_1 = p_m;
336
337
339 // Convergence checks
341 z1 = RealD(iter+1.0);
342 z2 = z1 + 1.0;
343 tau2 = tau2 *( z2 / z1 ) * s_m * s_m;
344 std::cout << " QuasiMinimumResidual iteration "<< iter<<std::endl;
345 std::cout << " QuasiMinimumResidual tau bound "<< tau2<<std::endl;
346
347 // Compute true residual
348 mod2r = tau2;
349 if ( 1 || (tau2 < (100.0 * target2)) ) {
350 LinOp.Op(x,tmp);
351 r = b - tmp;
352 mod2r = norm2(r);
353 std::cout << " QuasiMinimumResidual true residual is "<< mod2r<<std::endl;
354 }
355
356
357 if ( mod2r < target2 ) {
358
359 std::cout << " QuasiMinimumResidual has converged"<<std::endl;
360 return;
361
362 }
363
364 }
365
366
367 }
368#endif
369};
370
constexpr Real delta(int a, int b)
accelerator_inline Grid_simd< S, V > abs(const Grid_simd< S, V > &r)
accelerator_inline Grid_simd< S, V > sqrt(const Grid_simd< S, V > &r)
ComplexD innerProduct(const Lattice< vobj > &left, const Lattice< vobj > &right)
RealD norm2(const Lattice< vobj > &arg)
void G5R5(Lattice< vobj > &z, const Lattice< vobj > &x)
#define NAMESPACE_BEGIN(A)
Definition Namespace.h:35
#define NAMESPACE_END(A)
Definition Namespace.h:36
RealD innerG5ProductReal(Field &l, Field &r)
uint32_t Integer
Definition Simd.h:58
RealF Real
Definition Simd.h:65
std::complex< RealD > ComplexD
Definition Simd.h:79
double RealD
Definition Simd.h:61
Definition Gamma.h:10
virtual void Op(const Field &in, Field &out)=0
virtual void AdjOp(const Field &in, Field &out)=0
QuasiMinimalResidual(RealD tol, Integer maxit, bool err_on_no_conv=true)
void operator()(LinearOperatorBase< Field > &LinOp, const Field &b, Field &x)
Definition Simd.h:194