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