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