G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsMinResQLP.hpp
Go to the documentation of this file.
1 
14 namespace gismo
15 {
16 
17 //A stable way of finding radius, cosinus and sinus (r,c,s) from a and b
18 //That is: r = sqrt(a*a + b*b), c = a/r, s= b/r
19 //Rewritten from PETSc minres
20 template<class T>
21 void MinResQLPSymOrtho(T const a, T const b, T &c, T &s, T &r)
22 {
23  if (b == 0.0)
24  {
25  if (a == 0.0)
26  c = 1.0;
27  else
28  c = math::getSign(a);
29  s = 0.0;
30  r = math::abs(a);
31  }
32  else if (a == 0.0)
33  {
34  c = 0.0;
35  s = math::getSign(b);
36  r = math::abs(b);
37  }
38  else if (math::abs(b) > math::abs(a))
39  {
40  T t = a / b;
41 
42  s = math::getSign(b) / math::sqrt(1.0 + t * t);
43  c = s * t;
44  r = b / s;
45  }
46  else
47  {
48  T t = b / a;
49  c = math::getSign(a) / math::sqrt(1.0 + t * t);
50  s = c * t;
51  r = a / c;
52  }
53 }
54 
55 
56 template<class T>
58 {
59  m_rhs = rhs;
60  Base::initIteration(rhs,x);
61  index_t n = m_mat->cols();
62  index_t m = 1; // = rhs.cols();
63 
64  resvec.setZero(m_max_iters+1,1);
65  Aresvec.setZero(m_max_iters+1,1);
66 
67  //r2 = rhs;
68  m_mat->apply(x,r2); //erex
69  xnorm = x.norm();
70  Axnorm = r2.norm();
71  r2 = rhs-r2;
72  //y = x + beta y.
73  //VecAYPX(Vec y, PetscScalar beta, Vec x)
74  r3.setZero(n,m);
75  m_precond->apply(r2, r3);
76  beta1 = r2.col(0).dot(r3.col(0));
77  GISMO_ASSERT(beta1 > 0, "Preconditioner is indefinite");
78  beta1 = math::sqrt(beta1);
79  beta = 0;
80  tau = 0; taul = 0; gmin = 0;
81  phi = beta1; betan = beta1;
82  cs = -1; cr1 = -1; cr2 = -1;
83  sn = 0; sr1 = 0; sr2 = 0;
84  deltan = 0; epsilonn = 0;
85  gamma = 0; gammal = 0; gammal2 = 0;
86  eta = 0; etal = 0; etal2 = 0;
87  vepln = 0; veplnl = 0; veplnl2 = 0; ul3= 0;
88  ul2 = 0; ul = 0; u = 0; rnorm = betan;
89  xl2norm = 0;
90  Anorm = 0; Acond = 1;
91  relres = 1;
92  QLPiter = 0;
93 
94  x.setZero(n,m); w.setZero(n,m); wl.setZero(n,m);
95  resvec(0,0) = beta1;
96 
97  //NB User input
98  maxxnorm = 1e7;
99 
100 
101  m_error = r2.norm() / m_rhs_norm;
102  if (m_error < m_tol)
103  return true;
104 
105  return false;
106 }
107 
108 template<class T>
110 {
111  betal = beta;
112  beta= betan;
113  v = (1.0/beta)*r3;
114  m_mat->apply(v,r3);
115  //Assume that m_num_iter starts at 1 (at this point in the code)
116  //TODO check assumption
117  if (m_num_iter > 1)
118  r3 = r3 - (beta/betal)*r1;
119 
120  alpha = T (r3.col(0).dot(v.col(0)));
121  r3 = r3 - (alpha/beta)*r2;
122  r1.swap(r2);
123  r2.swap(r3);
124 
125  m_precond->apply(r2,r3);
126  betan = r2.col(0).dot(r3.col(0));
127  GISMO_ASSERT(betan > 0, "Preconditioner is indefinite");
128  betan = math::sqrt(betan);
129 
130  //pnorm = rho
131  pnorm = math::sqrt(alpha*alpha + betal*betal + betan*betan);
132 
133  dbar = deltan;
134  delta = cs*dbar + sn*alpha;
135  epsilon = epsilonn;
136  gbar = sn*dbar - cs*alpha;
137  epsilonn= sn*betan;
138  deltan = -cs*betan;
139 
140  gammal3 = gammal2;
141  gammal2 = gammal;
142  gammal = gamma;
143  MinResQLPSymOrtho(gbar, betan, cs, sn, gamma);
144  //real_t gammaTmp = gamma; used for (normal) minres update
145  taul2 = taul;
146  taul = tau;
147  tau = cs*phi;
148  Axnorm = math::sqrt(Axnorm*Axnorm + tau*tau);
149  phi = sn*phi;
150 
151 
152  if (m_num_iter > 2)
153  {
154  veplnl2 = veplnl;
155  etal2 = etal;
156  etal = eta;
157  real_t delta_tmp = sr2*vepln - cr2*delta;
158  veplnl = cr2*vepln + sr2*delta;
159  delta = delta_tmp;
160  eta = sr2*gamma;
161  gamma = -cr2*gamma;
162  }
163  if (m_num_iter > 1)
164  {
165  MinResQLPSymOrtho(gammal, delta, cr1, sr1, gammal);
166  vepln = sr1*gamma;
167  gamma = -cr1*gamma;
168  }
169 
170 
171  real_t ul4 = ul3;
172  ul3 = ul2;
173  if (m_num_iter > 2)
174  {
175  ul2 = (taul2 - etal2*ul4 - veplnl2*ul3) / gammal2;
176  }
177  if (m_num_iter > 1)
178  {
179  ul = ( taul - etal *ul3 - veplnl *ul2) / gammal;
180  }
181  real_t xnorm_tmp = math::sqrt(xl2norm*xl2norm + ul2*ul2 + ul*ul);
182  if ( math::abs(gamma) > std::numeric_limits<real_t>::min() && xnorm_tmp < maxxnorm)
183  {
184  u = (tau - eta*ul2 - vepln*ul) / gamma;
185  if ( math::sqrt(xnorm_tmp*xnorm_tmp + u*u) > maxxnorm)
186  {
187  u = 0; //NB flag = 6 LINE 374
188  }
189  }
190  else
191  {
192  u = 0; //NB flag = 9 LINE 379
193  }
194  xl2norm = math::sqrt(xl2norm*xl2norm + ul2*ul2);
195 
196  xnorm = math::sqrt(xl2norm*xl2norm + ul*ul + u*u);
197 
198  //MINRES-QLP updates
199  //TODO: add IF/ELSE if we want to integrate
200  // normal MINRES with MINRES-QLP
201  QLPiter += 1;
202  if (QLPiter == 1)
203  {
204  xl2.setZero(m_mat->cols(),1);
205  if (m_num_iter > 1)
206  {
207  if (m_num_iter > 3)
208  {
209  wl2 = gammal3*wl2 + veplnl2*wl + etal*w;
210  }
211  if (m_num_iter > 2)
212  {
213  wl = gammal_QLP*wl + vepln_QLP*w;
214  }
215  w = gamma_QLP*w;
216  xl2 = x - wl*ul_QLP - w*u_QLP;
217  }
218  }
219  if (m_num_iter == 1)
220  {
221  wl2.swap(wl);
222  wl = v*sr1;
223  w = -v*cr1;
224  }
225  else if (m_num_iter ==2)
226  {
227  wl2.swap(wl);
228  wl = w*cr1 + v*sr1;
229  w = w*sr1 - v*cr1;
230  }
231  else
232  {
233  wl2.swap(wl);
234  wl.swap(w);
235  w = wl2*sr2 - v*cr2;
236  wl2 = wl2*cr2 + v*sr2;
237  v = wl *cr1 + w*sr1;
238  w = wl *sr1 - w*cr1;
239  wl.swap(v);
240  }
241  xl2 = xl2 + wl2*ul2;
242  x = xl2 + wl *ul + w*u;
243 
244  real_t gammal_tmp = gammal;
245  MinResQLPSymOrtho(gammal, epsilonn, cr2, sr2, gammal);
246 
247  gammal_QLP = gammal_tmp;
248  vepln_QLP = vepln;
249  gamma_QLP = gamma;
250  ul_QLP = ul;
251  u_QLP = u;
252 
253  abs_gamma = math::abs(gamma);
254 
255  real_t tmp_max = std::max(gammal, abs_gamma);
256  Anorm = std::max(Anorm, pnorm);
257  Anorm = std::max(Anorm, tmp_max);
258  if (m_num_iter == 1)
259  {
260  gmin = gamma;
261  gminl = gmin;
262  }
263  else if (m_num_iter > 1)
264  {
265  gminl2 = gminl;
266  gminl = gmin;
267 
268  gmin = std::min(gminl2, gammal);
269  gmin = std::min(gmin, abs_gamma);
270  }
271 
272 
273  Acond = Anorm/gmin;
274  rnorml = rnorm;
275  if (phi != 0.0) //LINE 441
276  rnorm = phi; //NB if flag != 9;
277  relres = rnorm / (Anorm*xnorm + beta1);
278  rootl = math::sqrt(gbar*gbar + deltan*deltan);
279  Arnorml = rnorml*rootl;
280  relAresl = rootl / Anorm;
281 
282 
283  // Test for convergence
284  if (m_inexact_residual)
285  {
286  m_error = relres;
287  }
288  else
289  {
290  m_mat->apply(x,negResidual);
291  gsMatrix<T> r1_tmp = m_rhs - negResidual;
292  m_error = r1_tmp.norm()/m_rhs_norm;
293  }
294  if (m_error < m_tol)
295  return true;
296 
297 
298  resvec(m_num_iter, 0) = rnorm;
299  Aresvec(m_num_iter-1, 0) = Arnorml;
300 
301  return false;
302 
303 }
304 
305 template<class T>
307 {
308  m_mat->apply(x,negResidual);
309  r1 = m_rhs - negResidual;
310  rnorm = r1.norm();
311  m_mat->apply(r1, negResidual);
312  Arnorm = negResidual.norm();
313  xnorm = x.norm();
314  relres = rnorm/(Anorm*xnorm + beta1);
315  m_error = relres;
316  relAres = 0;
317  if(rnorm > std::numeric_limits<real_t>::min())
318  {
319  relAres = Arnorm / (Anorm*rnorm);
320  }
321  Aresvec(m_num_iter, 0) = Arnorm;
322  Aresvec.conservativeResize(m_num_iter+1,1);
323  resvec.conservativeResize(m_num_iter+1,1);
324  r1.clear(); r2.clear(); r3.clear();
325 
326  negResidual.clear(); v.clear();
327  xl2.clear();
328  wl.clear(); w.clear();
329  wl2.clear();
330 }
331 
332 
333 }
bool step(VectorType &x)
Perform one step, requires initIteration.
Definition: gsMinResQLP.hpp:109
void finalizeIteration(VectorType &x)
Some post-processing might be required.
Definition: gsMinResQLP.hpp:306
int getSign(T val)
Returns the sign of val.
Definition: gsMath.h:325
#define index_t
Definition: gsConfig.h:32
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
bool initIteration(const VectorType &rhs, VectorType &x)
Init the iteration.
Definition: gsMinResQLP.hpp:57
EIGEN_STRONG_INLINE abs_expr< E > abs(const E &u)
Absolute value.
Definition: gsExpressions.h:4488