Bridge++  Version 1.6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
eigensolver_IRLanczos.cpp
Go to the documentation of this file.
1 
14 #include "eigensolver_IRLanczos.h"
15 
16 #ifdef __PGI
17 #pragma global opt=1
18 // This is becaouse for PGI compiler on some environment,
19 // compilation with optimization level higher than O2 fails.
20 // [12 Feb 2021 H.Matsufuru]
21 #endif
22 
23 const std::string Eigensolver_IRLanczos::class_name = "Eigensolver_IRLanczos";
24 
25 //====================================================================
27 {
28  if (m_sorter) delete m_sorter;
29 }
30 
31 
32 //====================================================================
34 {
35  const std::string str_vlevel = params.get_string("verbose_level");
36 
37  m_vl = vout.set_verbose_level(str_vlevel);
38 
39  //- fetch and check input parameters
40  std::string str_sortfield_type;
41  int Nk, Np;
42  int Niter_eigen;
43  double Enorm_eigen, Vthreshold;
44 
45  int err = 0;
46  err += params.fetch_string("eigensolver_mode", str_sortfield_type);
47  err += params.fetch_int("number_of_wanted_eigenvectors", Nk);
48  err += params.fetch_int("number_of_working_eigenvectors", Np);
49  err += params.fetch_int("maximum_number_of_iteration", Niter_eigen);
50  err += params.fetch_double("convergence_criterion_squared", Enorm_eigen);
51  err += params.fetch_double("threshold_value", Vthreshold);
52 
53  if (err) {
54  vout.crucial(m_vl, "Error at %s: input parameter not found.\n",
55  class_name.c_str());
56  exit(EXIT_FAILURE);
57  }
58 
59  set_parameters(str_sortfield_type, Nk, Np, Niter_eigen, Enorm_eigen, Vthreshold);
60 }
61 
62 
63 //====================================================================
64 void Eigensolver_IRLanczos::set_parameters(const std::string& sort_type,
65  const int Nk, const int Np,
66  const int Niter_eigen, const double Enorm_eigen,
67  const double Vthreshold)
68 {
69  if (m_sorter) delete m_sorter;
70 
71  m_sorter = new Sorter(sort_type);
72 
73  set_parameters(Nk, Np, Niter_eigen, Enorm_eigen, Vthreshold);
74 }
75 
76 
77 //====================================================================
78 void Eigensolver_IRLanczos::set_parameters(const int Nk, const int Np,
79  const int Niter_eigen, double Enorm_eigen,
80  double Vthreshold)
81 {
82  //- print input parameters
83  vout.general(m_vl, "%s:\n", class_name.c_str());
84  vout.general(m_vl, " Nk = %d\n", Nk);
85  vout.general(m_vl, " Np = %d\n", Np);
86  vout.general(m_vl, " Niter_eigen = %d\n", Niter_eigen);
87  vout.general(m_vl, " Enorm_eigen = %16.8e\n", Enorm_eigen);
88  vout.general(m_vl, " Vthreshold = %16.8e\n", Vthreshold);
89 
90  //- range check
91  int err = 0;
94  err += ParameterCheck::non_negative(Niter_eigen);
95  err += ParameterCheck::square_non_zero(Enorm_eigen);
96  // NB. Vthreshold == 0 is allowed.
97 
98  if (err) {
99  vout.crucial(m_vl, "Error at %s: parameter range check failed.\n", class_name.c_str());
100  exit(EXIT_FAILURE);
101  }
102 
103  //- store values
104  m_Nk = Nk;
105  m_Np = Np;
106  m_Niter_eigen = Niter_eigen;
107  m_Enorm_eigen = Enorm_eigen;
108  m_Vthreshold = Vthreshold;
109 }
110 
111 
112 //====================================================================
113 void Eigensolver_IRLanczos::solve(std::vector<double>& TDa, std::vector<Field>& vk,
114  int& Nsbt, int& Nconv, const Field& b)
115 {
116  const int Nk = m_Nk;
117  const int Np = m_Np;
118  const int Niter_eigen = m_Niter_eigen;
119  const double Enorm_eigen = m_Enorm_eigen;
120  const double Vthreshold = m_Vthreshold;
121 
122  Nconv = -1;
123  Nsbt = 0;
124 
125  const int Nm = Nk + Np;
126 
127  if (Nk + Np > TDa.size()) {
128  vout.crucial(m_vl, "Error at %s: std::vector TDa is too small.\n", class_name.c_str());
129  exit(EXIT_FAILURE);
130  } else if (Nk + Np > vk.size()) {
131  vout.crucial(m_vl, "Error at %s: std::vector vk is too small.\n", class_name.c_str());
132  exit(EXIT_FAILURE);
133  }
134 
135  std::vector<double> TDb(Nm);
136  std::vector<double> TDa2(Nm);
137  std::vector<double> TDb2(Nm);
138  std::vector<double> Qt(Nm * Nm);
139  std::vector<int> Iconv(Nm);
140 
141  const int Nin = vk[0].nin();
142  const int Nvol = vk[0].nvol();
143  const int Nex = vk[0].nex();
144  std::vector<Field> B(Nm);
145  for (int k = 0; k < Nm; ++k) {
146  B[k].reset(Nin, Nvol, Nex);
147  }
148 
149  Field f(vk[0]);
150  Field v(vk[0]);
151 
152  vout.general(m_vl, " Nk = %d Np = %d\n", Nk, Np);
153  vout.general(m_vl, " Nm = %d\n", Nm);
154  vout.general(m_vl, " size of TDa = %d\n", TDa.size());
155  vout.general(m_vl, " size of vk = %d\n", vk.size());
156 
157  int k1 = 1;
158  int k2 = Nk;
159  int kconv = 0;
160 
161  int Kdis = 0;
162  int Kthreshold = 0;
163 
164  //- Set initial vector
165  vk[0].set(1.0);
166  const double vnorm = dot(vk[0], vk[0]);
167  vk[0].set(1.0 / sqrt(vnorm));
168  // (uniform vector)
169 
170  //- Initial Nk steps
171  for (int k = 0; k < k2; ++k) {
172  step(Nm, k, TDa, TDb, vk, f);
173  }
174 
175  //- Restarting loop begins
176  for (int iter = 0; iter < Niter_eigen; ++iter) {
177  vout.detailed(m_vl, "\n iter=%d\n", iter);
178 
179  int Nm2 = Nm - kconv;
180 
181  for (int k = k2; k < Nm; ++k) {
182  step(Nm, k, TDa, TDb, vk, f);
183  }
184 
185  //f *= TDb[Nm - 1];
186  scal(f, TDb[Nm - 1]);
187 
188  //- getting eigenvalues
189  for (int k = 0; k < Nm2; ++k) {
190  TDa2[k] = TDa[k + k1 - 1];
191  TDb2[k] = TDb[k + k1 - 1];
192  }
193  setUnit_Qt(Nm, Qt);
194  tqri(TDa2, TDb2, Nm2, Nm, Qt);
195 
196  //- sorting
197  m_sorter->sort(TDa2, Nm);
198 
199  //- Implicitly shifted QR transformations
200  setUnit_Qt(Nm, Qt);
201  for (int ip = k2; ip < Nm; ++ip) {
202  double Dsh = TDa2[ip - kconv];
203  int kmin = k1;
204  int kmax = Nm;
205  qrtrf(TDa, TDb, Nm, Nm, Qt, Dsh, kmin, kmax);
206  }
207 
208  for (int i = 0; i < (Nk + 1); ++i) {
209  B[i].set(0.0);
210  }
211 
212  for (int j = k1 - 1; j < k2 + 1; ++j) {
213  for (int k = 0; k < Nm; ++k) {
214  axpy(B[j], Qt[k + Nm * j], vk[k]);
215  }
216  }
217 
218  for (int j = k1 - 1; j < k2 + 1; ++j) {
219  vk[j] = B[j];
220  }
221 
222  //- Compressed vector f and beta(k2)
223  scal(f, Qt[Nm - 1 + Nm * (k2 - 1)]);
224  axpy(f, TDb[k2 - 1], vk[k2]);
225 
226  double beta_k = dot(f, f);
227  beta_k = sqrt(beta_k);
228 
229  vout.detailed(m_vl, " beta(k) = %20.14f\n", beta_k);
230 
231 
232  const double beta_r = 1.0 / beta_k;
233  vk[k2] = f;
234  scal(vk[k2], beta_r);
235  TDb[k2 - 1] = beta_k;
236 
237  //- Convergence test
238  TDa2 = TDa;
239  TDb2 = TDb;
240  setUnit_Qt(Nm, Qt);
241 
242  tqri(TDa2, TDb2, Nk, Nm, Qt);
243  for (int k = 0; k < Nk; ++k) {
244  B[k].set(0.0);
245  }
246 
247  for (int j = 0; j < Nk; ++j) {
248  for (int k = 0; k < Nk; ++k) {
249  axpy(B[j], Qt[k + j * Nm], vk[k]);
250  }
251  }
252 
253  Kdis = 0;
254  Kthreshold = 0;
255 
256  for (int i = 0; i < Nk; ++i) {
257  m_fopr->mult(v, B[i]);
258  const double vnum = dot(B[i], v);
259  const double vden = dot(B[i], B[i]);
260 
261  // vout.paranoiac(m_vl, " vden = %20.14e\n",vden);
262 
263  TDa2[i] = vnum / vden;
264  axpy(v, -TDa2[i], B[i]);
265 
266  const double vv = dot(v, v);
267 
268  vout.detailed(m_vl, " %4d %18.14f %18.14e\n", i, TDa2[i], vv);
269 
270  if (vv < Enorm_eigen) {
271  Iconv[Kdis] = i;
272  ++Kdis;
273 
274  if (!m_sorter->comp(TDa2[i], Vthreshold)) {
275  ++Kthreshold;
276  }
277  }
278  } // i-loop end
279 
280 
281  vout.detailed(m_vl, " #modes converged: %d\n", Kdis);
282 
283 
284  if (Kthreshold > 0) {
285  // (there is a converged eigenvalue larger than Vthreshold.)
286  Nconv = iter;
287 
288  //- Sorting
289  for (int i = 0; i < Kdis; ++i) {
290  TDa[i] = TDa2[Iconv[i]];
291  }
292 
293  std::vector<int> idx = m_sorter->sort_index(TDa, Kdis);
294 
295  for (int i = 0; i < Kdis; ++i) {
296  vk[i] = B[Iconv[idx[i]]];
297  }
298 
299  Nsbt = Kdis - Kthreshold;
300 
301  vout.general(m_vl, "\n Converged:\n");
302  vout.general(m_vl, " Nconv = %d\n", Nconv);
303  vout.general(m_vl, " beta(k) = %20.14e\n", beta_k);
304  vout.general(m_vl, " Kdis = %d\n", Kdis);
305  vout.general(m_vl, " Nsbt = %d\n", Nsbt);
306 
307  return;
308  }
309  } // end of iter loop
310 
311 
312  if (Nconv == -1) {
313  vout.crucial(m_vl, "Error at %s: NOT converged.\n", class_name.c_str());
314  exit(EXIT_FAILURE);
315  }
316 }
317 
318 
319 //====================================================================
320 void Eigensolver_IRLanczos::step(const int Nm, const int k,
321  std::vector<double>& TDa, std::vector<double>& TDb,
322  std::vector<Field>& vk, Field& w)
323 {
324  if (k >= Nm) {
325  vout.crucial(m_vl, "Error at %s: k is larger than Nm.\n", class_name.c_str());
326  exit(EXIT_FAILURE);
327  } else if (k == 0) { // Initial step
328  m_fopr->mult(w, vk[k]);
329  const double alph = dot(vk[k], w);
330 
331  axpy(w, -alph, vk[k]);
332 
333  double beta = dot(w, w);
334  beta = sqrt(beta);
335 
336  const double beta_r = 1.0 / beta;
337  vk[k + 1] = w;
338  scal(vk[k + 1], beta_r);
339 
340  TDa[k] = alph;
341  TDb[k] = beta;
342  } else { // Iteration step
343  m_fopr->mult(w, vk[k]);
344  axpy(w, -TDb[k - 1], vk[k - 1]);
345 
346  const double alph = dot(vk[k], w);
347 
348  axpy(w, -alph, vk[k]);
349 
350  double beta = dot(w, w);
351  beta = sqrt(beta);
352 
353  const double beta_r = 1.0 / beta;
354  scal(w, beta_r);
355 
356  TDa[k] = alph;
357  TDb[k] = beta;
358 
359  schmidt_orthogonalization(w, vk, k);
360 
361  if (k < Nm - 1) vk[k + 1] = w;
362  }
363 }
364 
365 
366 //====================================================================
368  const std::vector<Field>& vk, const int k)
369 {
370  for (int j = 0; j < k; ++j) {
371  dcomplex prod = dotc(vk[j], w);
372  prod *= cmplx(-1.0, 0.0);
373  axpy(w, prod, vk[j]);
374  }
375 }
376 
377 
378 //====================================================================
379 void Eigensolver_IRLanczos::setUnit_Qt(const int Nm, std::vector<double>& Qt)
380 {
381  for (int i = 0; i < Qt.size(); ++i) {
382  Qt[i] = 0.0;
383  }
384 
385  for (int k = 0; k < Nm; ++k) {
386  Qt[k + k * Nm] = 1.0;
387  }
388 }
389 
390 
391 //====================================================================
392 void Eigensolver_IRLanczos::tqri(std::vector<double>& TDa,
393  std::vector<double>& TDb,
394  const int Nk, const int Nm, std::vector<double>& Qt)
395 {
396  const int Niter = 100 * Nm;
397  int kmin = 1;
398  int kmax = Nk;
399  // (these parameters should be tuned)
400 
401 
402  int Nconv = -1;
403 
404  for (int iter = 0; iter < Niter; ++iter) {
405  //- determination of 2x2 leading submatrix
406  double dsub = TDa[kmax - 1] - TDa[kmax - 2];
407  double dd = sqrt(dsub * dsub + 4.0 * TDb[kmax - 2] * TDb[kmax - 2]);
408  double Dsh = 0.5 * (TDa[kmax - 2] + TDa[kmax - 1]
409  + fabs(dd) * (dsub / fabs(dsub)));
410  // (Dsh: shift)
411 
412  //- transformation
413  qrtrf(TDa, TDb, Nk, Nm, Qt, Dsh, kmin, kmax);
414 
415  //- Convergence criterion (redef of kmin and kmax)
416  for (int j = kmax - 1; j >= kmin; --j) {
417  double dds = fabs(TDa[j - 1]) + fabs(TDa[j]);
418  if (fabs(TDb[j - 1]) + dds > dds) {
419  kmax = j + 1;
420 
421  for (int j = 0; j < kmax - 1; ++j) {
422  double dds = fabs(TDa[j]) + fabs(TDa[j + 1]);
423 
424  if (fabs(TDb[j]) + dds > dds) {
425  kmin = j + 1;
426 
427  break;
428  }
429  }
430 
431  break;
432  }
433 
434  if (j == kmin) {
435  Nconv = iter;
436  vout.paranoiac(m_vl, " converged at iter = %d\n", Nconv);
437 
438  return;
439  }
440  } // end of j loop
441  } // end of iter loop
442 
443  if (Nconv == -1) {
444  vout.crucial(m_vl, "Error at %s: QL method NOT converged, Niter = %d.\n", class_name.c_str(), Niter);
445  exit(EXIT_FAILURE);
446  }
447 }
448 
449 
450 //====================================================================
451 void Eigensolver_IRLanczos::qrtrf(std::vector<double>& TDa,
452  std::vector<double>& TDb,
453  const int Nk, const int Nm, std::vector<double>& Qt,
454  const double Dsh, const int kmin, const int kmax)
455 {
456  const int k = kmin - 1;
457 
458  const double Fden = 1.0 / sqrt((TDa[k] - Dsh) * (TDa[k] - Dsh)
459  + TDb[k] * TDb[k]);
460  const double c = (TDa[k] - Dsh) * Fden;
461  const double s = -TDb[k] * Fden;
462 
463  const double tmpa1 = TDa[k];
464  const double tmpa2 = TDa[k + 1];
465  const double tmpb = TDb[k];
466 
467  TDa[k] = c * c * tmpa1 + s * s * tmpa2 - 2.0 * c * s * tmpb;
468  TDa[k + 1] = s * s * tmpa1 + c * c * tmpa2 + 2.0 * c * s * tmpb;
469  TDb[k] = c * s * (tmpa1 - tmpa2) + (c * c - s * s) * tmpb;
470  double x = -s * TDb[k + 1];
471  TDb[k + 1] = c * TDb[k + 1];
472 
473  for (int i = 0; i < Nk; ++i) {
474  double Qtmp1 = Qt[i + Nm * k];
475  double Qtmp2 = Qt[i + Nm * (k + 1)];
476  Qt[i + Nm * k] = c * Qtmp1 - s * Qtmp2;
477  Qt[i + Nm * (k + 1)] = s * Qtmp1 + c * Qtmp2;
478  }
479 
480  //- Givens transformations
481  for (int k = kmin; k < kmax - 1; ++k) {
482  double Fden = 1.0 / sqrt(x * x + TDb[k - 1] * TDb[k - 1]);
483  double c = TDb[k - 1] * Fden;
484  double s = -x * Fden;
485 
486  double tmpa1 = TDa[k];
487  double tmpa2 = TDa[k + 1];
488  double tmpb = TDb[k];
489  TDa[k] = c * c * tmpa1 + s * s * tmpa2 - 2.0 * c * s * tmpb;
490  TDa[k + 1] = s * s * tmpa1 + c * c * tmpa2 + 2.0 * c * s * tmpb;
491  TDb[k] = c * s * (tmpa1 - tmpa2) + (c * c - s * s) * tmpb;
492  TDb[k - 1] = c * TDb[k - 1] - s * x;
493  if (k != kmax - 2) {
494  x = -s * TDb[k + 1];
495  TDb[k + 1] = c * TDb[k + 1];
496  }
497 
498  for (int i = 0; i < Nk; ++i) {
499  double Qtmp1 = Qt[i + Nm * k];
500  double Qtmp2 = Qt[i + Nm * (k + 1)];
501  Qt[i + Nm * k] = c * Qtmp1 - s * Qtmp2;
502  Qt[i + Nm * (k + 1)] = s * Qtmp1 + c * Qtmp2;
503  }
504  }
505 }
506 
507 
508 //====================================================================
509 //============================================================END=====
void scal(Field &x, const double a)
scal(x, a): x = a * x
Definition: field.cpp:433
Bridge::VerboseLevel m_vl
Definition: eigensolver.h:51
void setUnit_Qt(const int Nm, std::vector< double > &Qt)
BridgeIO vout
Definition: bridgeIO.cpp:503
void detailed(const char *format,...)
Definition: bridgeIO.cpp:216
Definition: sorter.h:38
double dot(const Field &y, const Field &x)
Definition: field.cpp:46
void general(const char *format,...)
Definition: bridgeIO.cpp:197
void sort(std::vector< double > &v)
sort an array of values; v is sorted on exit.
Definition: sorter.cpp:117
Container of Field-type object.
Definition: field.h:46
int fetch_double(const string &key, double &value) const
Definition: parameters.cpp:327
void solve(std::vector< double > &TDa, std::vector< Field > &vk, int &Nsbt, int &Nconv, const Field &b)
Class for parameters.
Definition: parameters.h:46
int fetch_string(const string &key, string &value) const
Definition: parameters.cpp:378
static const std::string class_name
int square_non_zero(const double v)
void set_parameters(const Parameters &params)
std::vector< int > sort_index(std::vector< double > &v)
sort an array and return list of index; v is sorted on exit.
Definition: sorter.cpp:137
dcomplex dotc(const Field &y, const Field &x)
Definition: field.cpp:156
int fetch_int(const string &key, int &value) const
Definition: parameters.cpp:346
void paranoiac(const char *format,...)
Definition: bridgeIO.cpp:235
void qrtrf(std::vector< double > &TDa, std::vector< double > &TDb, const int Nk, const int Nm, std::vector< double > &Qt, const double Dsh, const int kmin, const int kmax)
void axpy(Field &y, const double a, const Field &x)
axpy(y, a, x): y := a * x + y
Definition: field.cpp:320
void crucial(const char *format,...)
Definition: bridgeIO.cpp:178
virtual void mult(Field &, const Field &)=0
multiplies fermion operator to a given field (2nd argument)
int non_negative(const int v)
void step(const int Nm, const int k, std::vector< double > &TDa, std::vector< double > &TDb, std::vector< Field > &vk, Field &f)
void tqri(std::vector< double > &TDa, std::vector< double > &TDb, const int Nk, const int Nm, std::vector< double > &Qt)
string get_string(const string &key) const
Definition: parameters.cpp:221
bool comp(const double lhs, const double rhs)
call sort condition.
Definition: sorter.cpp:189
static VerboseLevel set_verbose_level(const std::string &str)
Definition: bridgeIO.cpp:131
void schmidt_orthogonalization(Field &w, const std::vector< Field > &vk, const int k)