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