sym-ildl  1.2
Incomplete LDL' factorizations of indefinite symmetric and skew-symmetric matrices.
solver_sqmr.h
1 //-*- mode: c++ -*-
2 #ifndef _SOLVER_SQMR_H_
3 #define _SOLVER_SQMR_H_
4 
5 #include <string>
6 #include <algorithm>
7 #include <cmath>
8 
9 template<class el_type, class mat_type >
10 void solver<el_type, mat_type> :: sqmr(int max_iter, double stop_tol) {
11  //Zero out solution vector
12  int n = A.n_rows();
13  sol_vec.resize(n, 0);
14 
15  // ---------- set initial values and allocate memory for variables ---------//
16 
17  // temporary vectors for calcluations
18  vector<el_type> x(n), q(n), t(n), r(n), tmp(n);
19 
20  // residual = b - A*x0
21  r = rhs;
22 
23  // search direction
24  vector<el_type> d(n);
25 
26  // set up initial values for variables above
27  double eps = A.eps;
28  double norm_rhs = norm(rhs, 2.0);
29 
30  double res = norm_rhs;
31  double resmin = res;
32 
33  // Our preconditioner M = LDL'.
34  auto Minv = [&](vector<el_type>& in, vector<el_type>& out) {
35  L.backsolve(in, out);
36  D.solve(out, tmp);
37  L.forwardsolve(tmp, out);
38  };
39 
40  // compute t = M^(-1) * r
41  Minv(r, t);
42  double tau = norm(t, 2.0);
43 
44  q = t;
45  double thet = 0;
46  double rho = dot_product(r, q);
47 
48  double sigma, alpha, thet1, c2, rho1, beta;
49 
50  // -------------- begin sqmr iterations --------------//
51  int k = 1; // iteration number
52  while (res/norm_rhs > stop_tol && k <= max_iter) {
53  // t = A * q
54  // sigma = q'*t
55  A.multiply(q, t);
56  sigma = dot_product(q, t);
57  alpha = rho/sigma;
58 
59  // r = r - alpha * t
60  vector_sum(1, r, -alpha, t, r);
61 
62  // t = Minv(r)
63  Minv(r, t);
64 
65  thet1 = thet;
66  thet = norm(t, 2.0)/tau;
67 
68  c2 = 1.0/(1 + thet*thet);
69 
70  tau = tau * thet * sqrt(c2);
71  if (k == 1) {
72  // d = c^2 * alpha * q
73  for (int i = 0; i < n; i++) {
74  d[i] = c2 * alpha * q[i];
75  }
76  } else {
77  // d = c^2 * thet1^2 * d + c^2 * alpha * q
78  vector_sum(c2 * thet1 * thet1, d, c2 * alpha, q, d);
79  }
80 
81  // update x
82  vector_sum(1, x, 1, d, x);
83 
84  // update residual and norms
85  res = norm(r, 2.0);
86  /*
87  // the true residual
88  A.multiply(x, tmp);
89  vector_sum(1, rhs, -1, tmp, tmp);
90  res = norm(tmp, 2.0);
91  */
92 
93  if (res < resmin) {
94  resmin = res;
95  sol_vec = x;
96  }
97 
98  rho1 = rho;
99  rho = dot_product(r, t);
100  beta = rho/rho1;
101  vector_sum(1, t, beta, q, q);
102 
103  k++;
104  // ------------- end update ------------- //
105  }
106 
107  std::string iter_str = "iterations";
108  if (k-1 == 1) iter_str = "iteration";
109 
110  if (msg_lvl) printf("SQMR took %i %s and got down to relative residual %e.\n", k-1, iter_str.c_str(), resmin/norm_rhs);
111  return;
112 }
113 
114 #endif // _SOLVER_SQMR_H_