Bridge++  Ver. 2.0.2
aeigensolver_IRArnoldi-tmpl.h
Go to the documentation of this file.
1 
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 using std::string;
24 
25 template<typename FIELD, typename FOPR>
26 const std::string AEigensolver_IRArnoldi<FIELD, FOPR>::
27 class_name = "AEigensolver_IRArnoldi";
28 
29 //====================================================================
30 template<typename FIELD, typename FOPR>
32 {
33  if (m_sorter) delete m_sorter;
34 }
35 
36 
37 //====================================================================
38 template<typename FIELD, typename FOPR>
40  const Parameters& params)
41 {
42  std::string vlevel;
43  if (!params.fetch_string("verbose_level", vlevel)) {
44  m_vl = vout.set_verbose_level(vlevel);
45  }
46 
47  //- fetch and check input parameters
48  string str_sortfield_type;
49  int Nk, Np;
50  int Niter_eigen;
51  double Enorm_eigen, Vthreshold;
52 
53  int err = 0;
54  err += params.fetch_string("eigensolver_mode", str_sortfield_type);
55  err += params.fetch_int("number_of_wanted_eigenvectors", Nk);
56  err += params.fetch_int("number_of_working_eigenvectors", Np);
57  err += params.fetch_int("maximum_number_of_iteration", Niter_eigen);
58  err += params.fetch_double("convergence_criterion_squared", Enorm_eigen);
59  err += params.fetch_double("threshold_value", Vthreshold);
60 
61  if (err) {
62  vout.crucial(m_vl, "Error at %s: input parameter not found.\n",
63  class_name.c_str());
64  exit(EXIT_FAILURE);
65  }
66 
67  set_parameters(str_sortfield_type, Nk, Np, Niter_eigen, Enorm_eigen,
68  Vthreshold);
69 }
70 
71 
72 //====================================================================
73 template<typename FIELD, typename FOPR>
75 {
76  params.set_string("eigensolver_mode", m_sort_type);
77  params.set_int("number_of_wanted_eigenvectors", m_Nk);
78  params.set_int("number_of_working_eigenvectors", m_Np);
79  params.set_int("maximum_number_of_iteration", m_Niter_eigen);
80  params.set_double("convergence_criterion_squared", m_Enorm_eigen);
81  params.set_double("threshold_value", m_Vthreshold);
82 
83  params.set_string("verbose_level", vout.get_verbose_level(m_vl));
84 }
85 
86 
87 //====================================================================
88 template<typename FIELD, typename FOPR>
90  const std::string& sort_type,
91  int Nk, int Np,
92  int Niter_eigen,
93  double Enorm_eigen,
94  double Vthreshold)
95 {
96  if (m_sorter) delete m_sorter;
97 
98  m_sort_type = sort_type;
99  m_sorter = new Sorter<complex_t>(sort_type);
100 
101  set_parameters(Nk, Np, Niter_eigen, Enorm_eigen, Vthreshold);
102 }
103 
104 
105 //====================================================================
106 template<typename FIELD, typename FOPR>
108  int Nk, int Np,
109  int Niter_eigen,
110  double Enorm_eigen,
111  double Vthreshold)
112 {
113  //- range check
114  int err = 0;
115  err += ParameterCheck::non_negative(Nk);
116  err += ParameterCheck::non_negative(Np);
117  err += ParameterCheck::non_negative(Niter_eigen);
118  err += ParameterCheck::square_non_zero(Enorm_eigen);
119  // NB. Vthreshold == 0 is allowed.
120 
121  if (err) {
122  vout.crucial(m_vl, "Error at %s: parameter range check failed.\n",
123  class_name.c_str());
124  exit(EXIT_FAILURE);
125  }
126 
127  //- store values
128  m_Nk = Nk;
129  m_Np = Np;
130  m_Nm = m_Nk + m_Np;
131  m_Niter_eigen = Niter_eigen;
132  m_Enorm_eigen = real_t(Enorm_eigen);
133  m_Vthreshold = real_t(Vthreshold);
134 
135  //- print input parameters
136  vout.general(m_vl, "%s:\n", class_name.c_str());
137  vout.general(m_vl, " Nk = %d\n", m_Nk);
138  vout.general(m_vl, " Np = %d\n", m_Np);
139  vout.general(m_vl, " Niter_eigen = %d\n", m_Niter_eigen);
140  vout.general(m_vl, " Enorm_eigen = %16.8e\n", m_Enorm_eigen);
141  vout.general(m_vl, " Vthreshold = %16.8e\n", m_Vthreshold);
142 
143  int Nm = m_Nk + m_Np;
144 
145  m_TDa2.resize(Nm);
146 
147  m_Qt.resize(Nm * Nm);
148  m_Iconv.resize(Nm);
149 
150  m_Ht.resize((Nm + 1) * Nm); // (Nm+1) * Nm matrix
151  m_Ht2.resize((Nm + 1) * Nm);
152  m_Yt.resize(Nm * Nm);
153 
154  int Nin = m_fopr->field_nin();
155  int Nvol = m_fopr->field_nvol();
156  int Nex = m_fopr->field_nex();
157 
158  m_B.resize(Nm);
159  for (int k = 0; k < Nm; ++k) {
160  m_B[k].reset(Nin, Nvol, Nex);
161  }
162 
163  m_f.reset(Nin, Nvol, Nex);
164  m_v.reset(Nin, Nvol, Nex);
165 }
166 
167 
168 //====================================================================
169 template<typename FIELD, typename FOPR>
171  std::vector<complex_t>& TDa,
172  std::vector<FIELD>& vk,
173  int& Nsbt, int& Nconv, const FIELD& b)
174 {
175  int Nk = m_Nk;
176  int Np = m_Np;
177  int Niter_eigen = m_Niter_eigen;
178  real_t Enorm_eigen = m_Enorm_eigen;
179  real_t Vthreshold = m_Vthreshold;
180 
181  real_t Enorm_almost = 1.e-12; // this is an experimental value
182 
183  int Nm = Nk + Np;
184 
185  if (Nk + Np > TDa.size()) {
186  vout.crucial(m_vl, "Error at %s: std::vector TDa is too small.\n",
187  class_name.c_str());
188  exit(EXIT_FAILURE);
189  } else if (Nk + Np > vk.size()) {
190  vout.crucial(m_vl, "Error at %s: std::vector vk is too small.\n",
191  class_name.c_str());
192  exit(EXIT_FAILURE);
193  }
194 
195  vout.general(m_vl, "Implicitly Restarted Arnoldi algorithm start\n");
196  vout.general(m_vl, " Nk = %d Np = %d\n", Nk, Np);
197  vout.general(m_vl, " Nm = %d\n", Nm);
198  vout.general(m_vl, " size of TDa = %d\n", TDa.size());
199  vout.general(m_vl, " size of vk = %d\n", vk.size());
200  vout.general(m_vl, " Enorm_eigen = %e\n", Enorm_eigen);
201  vout.general(m_vl, " Enorm_almost = %e\n", Enorm_almost);
202 
203  Nconv = -1;
204  Nsbt = 0;
205 
206  int k1 = 0;
207  int k2 = Nk;
208 
209  int Kdis = 0;
210  int Kthreshold = 0;
211  int Kalmost = 0;
212 
213  int nconv;
214 
215 #pragma omp parallel
216  {
217  //- set initial vector
218  real_t bnorm2 = b.norm2();
219  if (bnorm2 > 1.e-12) { // b is regarded as a nonzero vector
220  copy(vk[0], b);
221  } else {
222  vk[0].set(1.0); // start with a uniform vector
223  }
224 
225  real_t vnorm = vk[0].norm2();
226  vnorm = 1.0 / sqrt(vnorm);
227  scal(vk[0], vnorm);
228 
229 #pragma omp master
230  {
231  for (int j = 0; j < Nm; ++j) {
232  for (int k = 0; k < Nm + 1; ++k) {
233  m_Ht[index(k, j)] = cmplx(real_t(0.0), real_t(0.0));
234  m_Ht2[index(k, j)] = cmplx(real_t(0.0), real_t(0.0));
235  }
236  }
237  }
238 #pragma omp barrier
239 
240  //- initial Nk steps
241  for (int k = 0; k < k2; ++k) {
242  step(Nm, k, vk, m_f);
243  }
244 
245 #pragma omp barrier
246 
247  //- restarting loop begins
248  for (int iter = 0; iter < Niter_eigen; ++iter) {
249  vout.detailed(m_vl, "\n iter = %d\n", iter);
250 
251  // Convergence test
252 
253  complex_t beta = cmplx(real_t(0.0), real_t(0.0));
254 
255 #pragma omp master
256  {
257  // here size Nk eigenproblem is solved.
258  beta = m_Ht[index(k2, k2 - 1)];
259  m_Ht[index(k2, k2 - 1)] = cmplx(real_t(0.0), real_t(0.0));
260 
261  m_Ht2 = m_Ht;
262  setUnit_Qt(Nm, m_Qt);
263 
264  tqri(m_Ht2, k1, Nk, Nm, m_Qt, nconv);
265 
266  for (int j = k1; j < Nk; ++j) {
267  TDa[j] = m_Ht2[index(j, j)];
268  }
269 
270  // here small eigenvalue problem should be checked for confirmation
271  std::vector<complex_t> Xt(Nm * Nm);
272 
273  eigenvector_Ht(Xt, m_Ht2, Nk, Nm);
274  mult_Qt(m_Yt, m_Qt, Xt, Nk, Nm);
275  check_eigen_Ht(m_Ht, TDa, m_Yt, Nk, Nm);
276  // now m_Yt is eigenvectors of Ht
277 
278  Kdis = 0;
279  Kthreshold = 0;
280  Kalmost = 0;
281  }
282 #pragma omp barrier
283 
284  // convergenece test
285  vout.general(m_vl, " TDa "
286  " abs diff2\n");
287 
288  for (int j = 0; j < k1; ++j) {
289  m_fopr->mult(m_v, m_B[j]);
290  axpy(m_v, -TDa[j], m_B[j]);
291  real_t bnorm = m_B[j].norm2();
292  real_t vv = m_v.norm2() / bnorm;
293  vout.general(m_vl, " %4d* (%12.8f, %12.8f) %12.8f %12.4e\n",
294  j, real(TDa[j]), imag(TDa[j]), abs(TDa[j]), vv);
295  }
296 
297  for (int j = k1; j < Nk; ++j) {
298  m_B[j].set(0.0);
299  for (int k = 0; k < Nk; ++k) {
300  axpy(m_B[j], m_Yt[index(k, j)], vk[k]);
301  }
302  m_fopr->mult(m_v, m_B[j]);
303  axpy(m_v, -TDa[j], m_B[j]);
304  real_t bnorm = m_B[j].norm2();
305  real_t vv = m_v.norm2() / bnorm;
306  vout.general(m_vl, " %4d (%12.8f, %12.8f) %12.8f %12.4e\n",
307  j, real(TDa[j]), imag(TDa[j]), abs(TDa[j]), vv);
308 
309 #pragma omp master
310  {
311  m_TDa2[j] = TDa[j];
312 
313  if (vv < Enorm_eigen) {
314  m_Iconv[Kdis] = j;
315  ++Kdis;
316  if (!m_sorter->comp(m_TDa2[j], Vthreshold)) {
317  ++Kthreshold;
318  }
319  } else if ((vv < Enorm_almost) &&
320  m_sorter->comp(m_TDa2[j], Vthreshold)) {
321  ++Kalmost;
322  }
323  } // omp master
324 #pragma omp barrier
325  } // j-loop end
326 
327  vout.detailed(m_vl, " #modes already converged: %4d\n", k1);
328  vout.detailed(m_vl, " #modes newly converged: %4d\n", Kdis);
329  vout.detailed(m_vl, " #modes almost converged: %4d\n", Kalmost);
330 
331  if ((Kthreshold > 0) && (Kalmost == 0)) {
332 #pragma omp master
333  {
334  // (there is a converged eigenvalue larger than Vthreshold.)
335 
336  //- Sorting
337  for (int i = k1; i < Kdis; ++i) {
338  TDa[i] = m_TDa2[m_Iconv[i]];
339  }
340  Nsbt = Kdis - Kthreshold;
341  Nconv = iter;
342  }
343 #pragma omp barrier
344 
345  // break;
346  iter = Niter_eigen;
347  }
348 
349  // deflation - this does not work yet
350 
351  /*
352  if(Kdis > 0){
353  deflation(k1, k2, Kdis, TDa, vk, beta);
354  k1 += Kdis;
355  }
356  */
357 
358 #pragma omp master
359  {
360  m_Ht[index(k2, k2 - 1)] = beta;
361  }
362 #pragma omp barrier
363 
364  // if not converged, Krylov subspace is extended
365 
366 
367  for (int k = k2 - 1; k < Nm; ++k) {
368  step(Nm, k, vk, m_f);
369  }
370 
371 #pragma omp master
372  {
373  for (int j = 0; j < Nm; ++j) {
374  for (int k = 0; k < Nm; ++k) {
375  m_Ht2[index(k, j)] = m_Ht[index(k, j)];
376  }
377  }
378 
379  //- getting eigenvalues
380  setUnit_Qt(Nm, m_Qt);
381 
382  // vout.detailed(m_vl, "QR transformation\n");
383 
384  tqri(m_Ht2, k1, Nm, Nm, m_Qt, nconv);
385 
386  for (int j = 0; j < Nm; ++j) {
387  m_TDa2[j] = m_Ht2[index(j, j)];
388  }
389 
390  // here small eigenvalue problem should be checked for confirmation
391  std::vector<complex_t> Xt(Nm * Nm);
392 
393  eigenvector_Ht(Xt, m_Ht2, Nm, Nm);
394  mult_Qt(m_Yt, m_Qt, Xt, Nm, Nm);
395  check_eigen_Ht(m_Ht, m_TDa2, m_Yt, Nm, Nm);
396  // now m_Yt is eigenvectors of Ht
397 
398  //- sorting
399  m_sorter->sort(m_TDa2, Nm);
400  // CAUTION: if already converged eigenvalues become the
401  // i >= k2 range, the following algorithm may fail.
402  // Some care is necessary.
403 
404  // m_Ht2 = m_Ht;
405 
406  setUnit_Qt(Nm, m_Qt);
407 
408  //- implicitly shifted QR transformations
409  for (int ip = k2; ip < Nm; ++ip) {
410  complex_t Dsh = m_TDa2[ip];
411  int kmin = k1 + 1;
412  int kmax = Nm;
413  // vout.general(m_vl, "ip = %d Dsh = (%f, %f)\n",
414  // ip, real(Dsh), imag(Dsh));
415  qrtrf(m_Ht, Nm, Nm, m_Qt, Dsh, kmin, kmax);
416  // check_Qt(Nm, Nm, m_Qt, m_Ht, m_Ht2);
417  }
418  }
419 #pragma omp barrier
420 
421  for (int j = k1; j <= k2; ++j) {
422  m_B[j].set(0.0);
423  //for (int k = 0; k < Nm; ++k) {
424  for (int k = k1; k < Nm; ++k) {
425  axpy(m_B[j], m_Qt[index(k, j)], vk[k]);
426  }
427  }
428 
429  for (int j = k1; j <= k2; ++j) {
430  copy(vk[j], m_B[j]);
431  }
432 
433  schmidt(k2, vk);
434 
435  //- Compressed vector f and beta(k2)
436  copy(m_f, m_B[k2]);
437 
438  real_t ff = m_f.norm2();
439  // vout.detailed(m_vl, " ff = %20.14f\n", ff);
440 
441  scal(m_f, m_Ht[index(k2, k2 - 1)]);
442 
443  real_t beta_k = m_f.norm2();
444  beta_k = sqrt(beta_k);
445 
446  vout.detailed(m_vl, " beta(k) = %20.14f\n", beta_k);
447 
448  // reconstructing Hessenberg matrix
449  reconst_Ht(m_Ht2, m_Qt, beta, vk, Nk);
450 
451 #pragma omp master
452  {
453  real_t diff = 0.0;
454  for (int i = 0; i < Nk; ++i) {
455  for (int j = 0; j < Nk; ++j) {
456  real_t diff1 = abs(m_Ht[index(i, j)] - m_Ht2[index(i, j)]);
457  diff += diff1 * diff1;
458  }
459  }
460  diff = diff / real_t(Nk * Nk);
461  vout.general(m_vl, " difference of Hessenberg = %e\n", diff);
462 
463  /*
464  if(diff > 1.0e-16){
465  for(int i1 = 0; i1 < Nk; ++i1){
466  for(int i2 = 0; i2 < Nk; ++i2){
467  vout.general(m_vl, " Ht[%d,%d] = (%e,%e) (%e,%e)\n", i2, i1,
468  real(m_Ht[index(i2,i1)]), imag(m_Ht[index(i2,i1)]),
469  real(m_Ht2[index(i2,i1)]), imag(m_Ht2[index(i2,i1)]));
470  }
471  }
472  }
473  */
474 
475  m_Ht = m_Ht2;
476  }
477 #pragma omp barrier
478  } // end of iter loop
479  } // omp parallel
480 
481  std::vector<int> idx = m_sorter->sort_index(TDa, Kdis);
482  for (int i = 0; i < Kdis; ++i) {
483  copy(vk[i], m_B[m_Iconv[idx[i]]]);
484 
485  /*
486  real_t vv = vk[i].norm2();
487  vv = 1.0/sqrt(vv);
488  scal(vk[i], vv);
489  vv = vk[i].norm2();
490  vout.paranoiac(m_vl, " vk[%d]: norm2 = %22.14e\n", i, vv);
491  */
492  }
493 
494  if (Nconv == -1) {
495  vout.crucial(m_vl, "Error at %s: NOT converged.\n", class_name.c_str());
496  exit(EXIT_FAILURE);
497  } else {
498  vout.general(m_vl, "\n Converged:\n");
499  vout.general(m_vl, " Nconv = %d\n", Nconv);
500  // vout.general(m_vl, " beta(k) = %20.14e\n", beta_k);
501  vout.general(m_vl, " Kdis = %d\n", Kdis);
502  vout.general(m_vl, " Nsbt = %d\n", Nsbt);
503  vout.general(m_vl, "%s: solve finished.\n\n", class_name.c_str());
504  }
505 }
506 
507 
508 //====================================================================
509 template<typename FIELD, typename FOPR>
511  int k1, int k2, int Kdis,
512  std::vector<complex_t>& TDa,
513  std::vector<FIELD>& vk,
514  complex_t& beta)
515 {
516  for (int i = k2 - 1; i >= k1 + Kdis; --i) {
517  copy(vk[i], vk[i - Kdis]);
518  }
519 
520  for (int i = 0; i < Kdis; ++i) {
521  copy(vk[k1 + i], m_B[m_Iconv[i]]);
522  if ((k1 + i) != m_Iconv[i]) copy(m_B[k1 + i], m_B[m_Iconv[i]]);
523 #pragma omp master
524  {
525  TDa[k1 + i] = m_TDa2[m_Iconv[i]];
526  }
527 #pragma omp barrier
528  }
529 
530  schmidt(k2, vk);
531  reconst_Ht(m_Ht, m_Qt, beta, vk, k2);
532 
533 #pragma omp master
534  {
535  for (int i = 0; i < k1 + Kdis; ++i) {
536  m_Ht[index(i + 1, i)] = cmplx(0.0, 0.0);
537  }
538  }
539 #pragma omp barrier
540 }
541 
542 
543 //====================================================================
544 template<typename FIELD, typename FOPR>
546  std::vector<FIELD>& vk,
547  FIELD& w)
548 {
549  if (k >= Nm) {
550  vout.crucial(m_vl, "Error at %s: k is larger than Nm.\n",
551  class_name.c_str());
552  exit(EXIT_FAILURE);
553  }
554 
555  m_fopr->mult(w, vk[k]);
556 
557  for (int j = 0; j <= k; ++j) {
558  complex_t alph = dotc(vk[j], w);
559  axpy(w, -alph, vk[j]);
560 #pragma omp master
561  m_Ht[index(j, k)] = alph;
562 #pragma omp barrier
563  }
564 
565  real_t beta = w.norm2();
566  beta = sqrt(beta);
567 
568  if (k < Nm - 1) {
569  real_t beta_r = 1.0 / beta;
570  copy(vk[k + 1], w);
571  scal(vk[k + 1], beta_r);
572  }
573 
574 #pragma omp master
575  m_Ht[index(k + 1, k)] = cmplx(beta, real_t(0.0));
576 #pragma omp barrier
577 }
578 
579 
580 //====================================================================
581 template<typename FIELD, typename FOPR>
583  int Nk,
584  std::vector<FIELD>& vk)
585 {
586  for (int j = 0; j < Nk; ++j) {
587  for (int i = 0; i < j; ++i) {
588  complex_t vv = dotc(vk[i], vk[j]);
589  axpy(vk[j], -vv, vk[i]);
590  }
591  real_t vv = vk[j].norm2();
592  vv = 1.0 / sqrt(vv);
593  scal(vk[j], vv);
594  }
595 }
596 
597 
598 //====================================================================
599 template<typename FIELD, typename FOPR>
601  int Nm, std::vector<complex_t>& Qt)
602 {
603  for (int i = 0; i < Qt.size(); ++i) {
604  Qt[i] = cmplx(0.0, 0.0);
605  }
606 
607  for (int k = 0; k < Nm; ++k) {
608  Qt[index(k, k)] = cmplx(1.0, 0.0);
609  }
610 }
611 
612 
613 //====================================================================
614 template<typename FIELD, typename FOPR>
616  std::vector<complex_t>& Ht, int k1,
617  int Nk, int Nm, std::vector<complex_t>& Qt, int& nconv)
618 {
619  int Niter = 100 * Nm;
620  int kmin = k1 + 1;
621  int kmax = Nk;
622  // (these parameters should be tuned)
623  // vout.general("tqri: k1 = %d\n", k1);
624 
625  nconv = -1;
626 
627  std::vector<complex_t> Hr(Nm * Nm);
628  for (int i = 0; i < Nm; ++i) {
629  for (int j = 0; j < Nm; ++j) {
630  Hr[index(i, j)] = Ht[(index(i, j))];
631  }
632  }
633 
634  for (int iter = 0; iter < Niter; ++iter) {
635  complex_t Dsh; // shift
636  if (kmax > kmin) {
637  shift_wilkinson(Dsh, Ht[index(kmax - 2, kmax - 2)],
638  Ht[index(kmax - 2, kmax - 1)],
639  Ht[index(kmax - 1, kmax - 2)],
640  Ht[index(kmax - 1, kmax - 1)]);
641  } else {
642  Dsh = Ht[index(kmax - 1, kmax - 1)];
643  }
644 
645 
646  //- transformation
647  qrtrf(Ht, Nk, Nm, Qt, Dsh, kmin, kmax);
648 
649  check_Qt(Nk, Nm, Qt, Ht, Hr);
650 
651  //- Convergence criterion (redef of kmin and kmax)
652  for (int j = kmax - 1; j >= kmin; --j) {
653  real_t dds = abs(Ht[index(j - 1, j - 1)]) + abs(Ht[index(j, j)]);
654  if (abs(Ht[index(j, j - 1)]) + dds > dds) {
655  kmax = j + 1;
656  for (int i = 0; i < kmax - 1; ++i) {
657  real_t dds = abs(Ht[index(j, j)]) + abs(Ht[index(j + 1, j + 1)]);
658  if (abs(Ht[index(i + 1, i)]) + dds > dds) {
659  kmin = i + 1;
660  break;
661  }
662  }
663  break;
664  }
665 
666  if (j == kmin) {
667  nconv = iter;
668  vout.detailed(m_vl, " tqri: converged at iter = %d\n", nconv);
669  reunit_Qt(Qt, Nk); // reunitarization of Qt
670  return;
671  }
672  } // end of j loop
673  } // end of iter loop
674 
675  if (nconv == -1) {
676  vout.crucial(m_vl, "Error at %s: QR method NOT converged, Niter = %d.\n",
677  class_name.c_str(), Niter);
678  exit(EXIT_FAILURE);
679  }
680 }
681 
682 
683 //====================================================================
684 template<typename FIELD, typename FOPR>
686  std::vector<complex_t>& Ht,
687  int Nk, int Nm, std::vector<complex_t>& Qt,
688  complex_t Dsh, int kmin, int kmax)
689 {
690  int k = kmin - 1;
691 
692  real_t f1 = abs(Ht[index(k, k)] - Dsh);
693  real_t f2 = abs(Ht[index(k + 1, k)]);
694  real_t Fden = 1.0 / sqrt(f1 * f1 + f2 * f2);
695  complex_t c = cmplx(f1 * Fden, real_t(0.0));
696  complex_t s = cmplx(-f2 * Fden, real_t(0.0));
697  complex_t beta = (Ht[index(k, k)] - Dsh) / f1;
698 
699  for (int j = 0; j < Nk; ++j) {
700  complex_t tmp1 = Ht[index(k, j)];
701  complex_t tmp2 = Ht[index(k + 1, j)];
702  Ht[index(k, j)] = c * tmp1 - beta * s * tmp2;
703  Ht[index(k + 1, j)] = s * tmp1 + beta * c * tmp2;
704  }
705  for (int j = 0; j < Nk; ++j) {
706  complex_t tmp1 = Ht[index(j, k)];
707  complex_t tmp2 = Ht[index(j, k + 1)];
708  Ht[index(j, k)] = tmp1 * c - tmp2 * conj(beta) * s;
709  Ht[index(j, k + 1)] = tmp1 * s + tmp2 * conj(beta) * c;
710  }
711 
712  for (int j = 0; j < Nk; ++j) {
713  complex_t tmp1 = Qt[index(j, k)];
714  complex_t tmp2 = Qt[index(j, k + 1)];
715  Qt[index(j, k)] = c * tmp1 - conj(beta) * s * tmp2;
716  Qt[index(j, k + 1)] = s * tmp1 + conj(beta) * c * tmp2;
717  }
718 
719  //- Givens transformations
720  for (int k = kmin; k < kmax - 1; ++k) {
721  real_t f1 = abs(Ht[index(k, k - 1)]);
722  real_t f2 = abs(Ht[index(k + 1, k - 1)]);
723  real_t Fden = 1.0 / sqrt(f1 * f1 + f2 * f2);
724  complex_t alph = conj(Ht[index(k, k - 1)]) / f1;
725  complex_t beta = conj(Ht[index(k + 1, k - 1)]) / f2;
726  complex_t c = cmplx(f1 * Fden, real_t(0.0));
727  complex_t s = cmplx(-f2 * Fden, real_t(0.0));
728 
729  for (int j = 0; j < Nk; ++j) {
730  complex_t tmp1 = Ht[index(k, j)];
731  complex_t tmp2 = Ht[index(k + 1, j)];
732  Ht[index(k, j)] = alph * c * tmp1 - beta * s * tmp2;
733  Ht[index(k + 1, j)] = alph * s * tmp1 + beta * c * tmp2;
734  }
735  for (int j = 0; j < Nk; ++j) {
736  complex_t tmp1 = Ht[index(j, k)];
737  complex_t tmp2 = Ht[index(j, k + 1)];
738  complex_t alphc = conj(alph);
739  complex_t betac = conj(beta);
740  Ht[index(j, k)] = tmp1 * alphc * c - tmp2 * betac * s;
741  Ht[index(j, k + 1)] = tmp1 * alphc * s + tmp2 * betac * c;
742  }
743 
744  if (k < kmax - 2) {
745  Ht[index(k + 1, k - 1)] = cmplx(real_t(0.0), real_t(0.0));
746  }
747 
748  for (int j = 0; j < Nk; ++j) {
749  complex_t tmp1 = Qt[index(j, k)];
750  complex_t tmp2 = Qt[index(j, k + 1)];
751  Qt[index(j, k)] = conj(alph) * c * tmp1 - conj(beta) * s * tmp2;
752  Qt[index(j, k + 1)] = conj(alph) * s * tmp1 + conj(beta) * c * tmp2;
753  }
754  }
755 
756  k = kmax - 1;
757  complex_t tmp1 = Ht[index(k, k - 1)];
758  complex_t tmpd = abs(Ht[index(k, k)]);
759 
760  if (abs(tmp1) + abs(tmpd) != abs(tmpd)) {
761  complex_t tmp2 = abs(tmp1);
762  complex_t alph = conj(tmp1) / tmp2;
763 
764  for (int j = 0; j < Nk; ++j) {
765  Ht[index(k, j)] *= alph;
766  }
767 
768  for (int j = 0; j < Nk; ++j) {
769  Ht[index(j, k)] *= conj(alph);
770  }
771 
772  for (int j = 0; j < Nk; ++j) {
773  Qt[index(j, k)] *= conj(alph);
774  }
775  }
776 
777  // enforce Hessenberg form to Ht
778  for (int j = 0; j < Nk; ++j) {
779  for (int k = j + 2; k < Nk; ++k) {
780  Ht[index(k, j)] = cmplx(0.0, 0.0);
781  }
782  }
783 
784  // enforce Hessenberg form to Ht
785  for (int j = 0; j < Nk - 1; ++j) {
786  int k = j + 1;
787  Ht[index(k, j)] = cmplx(real(Ht[index(k, j)]), real_t(0.0));
788  }
789 
790  // reunitarization of Qt
791  reunit_Qt(Qt, Nk);
792 }
793 
794 
795 //====================================================================
796 template<typename FIELD, typename FOPR>
798  const int Nk, const int Nm,
799  std::vector<complex_t>& Qt,
800  std::vector<complex_t>& Ht,
801  std::vector<complex_t>& At)
802 { // confirm At = Qt * Ht * Qt^\dag
803  std::vector<complex_t> Bt(Nm * Nm);
804  std::vector<complex_t> Ct(Nm * Nm);
805 
806  for (int i = 0; i < Nk; ++i) {
807  for (int j = 0; j < Nk; ++j) {
808  Bt[index(i, j)] = cmplx(0.0, 0.0);
809  for (int k = 0; k < Nk; ++k) {
810  Bt[index(i, j)] += Ht[index(i, k)] * conj(Qt[index(j, k)]);
811  }
812  }
813  }
814 
815  for (int i = 0; i < Nk; ++i) {
816  for (int j = 0; j < Nk; ++j) {
817  Ct[index(i, j)] = cmplx(0.0, 0.0);
818  for (int k = 0; k < Nk; ++k) {
819  Ct[index(i, j)] += Qt[index(i, k)] * Bt[index(k, j)];
820  }
821  }
822  }
823 
824  real_t res = 0.0;
825  for (int i = 0; i < Nk; ++i) {
826  for (int j = 0; j < Nk; ++j) {
827  Ct[index(i, j)] -= At[index(i, j)];
828  res += abs(Ct[index(i, j)]) * abs(Ct[index(i, j)]);
829  }
830  }
831 
832  // vout.detailed(m_vl, " check A = Q^dag H Q: res = %e\n", res);
833  if (res > 1.e-24) {
834  vout.crucial(m_vl, "%s: check A = Q^d H Q: too large res = %e\n",
835  class_name.c_str(), res);
836  }
837 }
838 
839 
840 //====================================================================
841 template<typename FIELD, typename FOPR>
843  complex_t& kappa,
844  const complex_t a, const complex_t b,
845  const complex_t c, const complex_t d)
846 {
847  real_t s = abs(a) + abs(b) + abs(c) + abs(d);
848 
849  complex_t p = cmplx(real_t(0.5), real_t(0.0)) * (a - d);
850  complex_t q = b * c;
851  complex_t r = sqrt(p * p + q);
852 
853  real_t abst1 = abs(p) * abs(p) + abs(r) * abs(r);
854  real_t abst2 = 2.0 * real(p * conj(r));
855 
856  real_t absr1 = abst1 + abst2;
857  real_t absr2 = abst1 - abst2;
858 
859  complex_t rmax, rmin;
860  if (absr1 > absr2) {
861  rmax = p + r;
862  } else {
863  rmax = p - r;
864  }
865  rmin = -q / rmax;
866 
867  kappa = rmin + d;
868 
869  // check
870  complex_t res1 = rmax * rmax - (a - d) * rmax - b * c;
871  complex_t res2 = rmin * rmin - (a - d) * rmin - b * c;
872  real_t res = (abs(res1) + abs(res2)) / s;
873 
874  /*
875  vout.detailed(m_vl, " rmax = (%e, %e)\n", real(rmax), imag(rmax));
876  vout.detailed(m_vl, " rmim = (%e, %e)\n", real(rmin), imag(rmin));
877  vout.detailed(m_vl, " res = %e s = %e\n", res, s);
878  vout.detailed(m_vl, " shift = (%e, %e)\n", real(kappa), imag(kappa));
879  */
880 }
881 
882 
883 //====================================================================
884 template<typename FIELD, typename FOPR>
886  std::vector<complex_t>& Yt,
887  std::vector<complex_t>& Ht,
888  int km, int Nm)
889 {
890  int i = 0;
891  Yt[index(0, i)] = cmplx(1.0, 0.0);
892  for (int j = 1; j < Nm; ++j) {
893  Yt[index(j, i)] = cmplx(0.0, 0.0);
894  }
895 
896  for (int i = 1; i < km; ++i) {
897  complex_t lambda = Ht[index(i, i)];
898 
899  Yt[index(i, i)] = cmplx(1.0, 0.0);
900 
901  for (int j = i + 1; j < Nm; ++j) {
902  Yt[index(j, i)] = cmplx(0.0, 0.0);
903  }
904 
905  Yt[index(i - 1, i)] = -Ht[index(i - 1, i)] / (Ht[index(i - 1, i - 1)] - lambda);
906 
907  for (int j = i - 2; j >= 0; --j) {
908  Yt[index(j, i)] = -Ht[index(j, i)];
909  for (int k = j + 1; k < i; ++k) {
910  Yt[index(j, i)] += -Ht[index(j, k)] * Yt[index(k, i)];
911  }
912  Yt[index(j, i)] *= real_t(1.0) / (Ht[index(j, j)] - lambda);
913  }
914  }
915 }
916 
917 
918 //====================================================================
919 template<typename FIELD, typename FOPR>
921  std::vector<complex_t>& Yt,
922  std::vector<complex_t>& Qt,
923  std::vector<complex_t>& Xt,
924  int km, int Nm)
925 { // Yt = Qt * Xt.
926  for (int j = 0; j < km; ++j) {
927  for (int i = 0; i < Nm; ++i) {
928  Yt[index(i, j)] = cmplx(0.0, 0.0);
929  for (int k = 0; k < Nm; ++k) {
930  Yt[index(i, j)] += Qt[index(i, k)] * Xt[index(k, j)];
931  }
932  }
933  }
934 }
935 
936 
937 //====================================================================
938 template<typename FIELD, typename FOPR>
940  std::vector<complex_t>& Ht,
941  std::vector<complex_t>& TDa,
942  std::vector<complex_t>& Xt,
943  int km, int Nm)
944 {
945  real_t crit = 1.0e-20;
946 
947  real_t diff = 0.0;
948  for (int i = 0; i < km; ++i) {
949  real_t diff1 = 0.0;
950  for (int j = 0; j < Nm; ++j) {
951  complex_t diff2 = -TDa[i] * Xt[index(j, i)];
952  for (int k = 0; k < km; ++k) {
953  diff2 += Ht[index(j, k)] * Xt[index(k, i)];
954  }
955  diff1 += abs(diff2) * abs(diff2);
956  }
957 
958  diff += diff1;
959  }
960 
961  diff = diff / real_t(km * Nm);
962 
963  vout.detailed(m_vl, " eigenrelation of Ht: diff2 = %e\n", diff);
964  if (diff > crit) {
965  exit(EXIT_FAILURE);
966  }
967 }
968 
969 
970 //====================================================================
971 template<typename FIELD, typename FOPR>
973  std::vector<complex_t>& Qt,
974  int Nk)
975 {
976  for (int j = 0; j < Nk; ++j) {
977  for (int i = 0; i < j; ++i) {
978  complex_t qq = cmplx(real_t(0.0), real_t(0.0));
979  for (int k = 0; k < Nk; ++k) {
980  //qq += conj(Qt[index(k,j)]) * Qt[index(k,i)];
981  qq += conj(Qt[index(j, k)]) * Qt[index(i, k)];
982  }
983 
984  for (int k = 0; k < Nk; ++k) {
985  //Qt[index(k,i)] -= qq * Qt[index(k,j)];
986  Qt[index(i, k)] -= qq * Qt[index(j, k)];
987  }
988  }
989 
990  real_t qq = 0.0;
991  for (int k = 0; k < Nk; ++k) {
992  //real_t qq1 = abs(Qt[index(k,j)]);
993  real_t qq1 = abs(Qt[index(j, k)]);
994  qq += qq1 * qq1;
995  }
996  qq = 1.0 / sqrt(qq);
997  for (int k = 0; k < Nk; ++k) {
998  //Qt[index(k,j)] *= qq;
999  Qt[index(j, k)] *= qq;
1000  }
1001  }
1002 }
1003 
1004 
1005 //====================================================================
1006 template<typename FIELD, typename FOPR>
1008  std::vector<complex_t>& Ht,
1009  std::vector<complex_t>& Qt,
1010  complex_t& beta,
1011  std::vector<FIELD>& vk,
1012  int Nk)
1013 {
1014  std::vector<complex_t> u(Nk);
1015  std::vector<complex_t> x(Nk);
1016 
1017  for (int j = 0; j < Nk; ++j) {
1018  m_fopr->mult(m_v, vk[j]);
1019  for (int i = 0; i < Nk; ++i) {
1020  complex_t Htmp = dotc(vk[i], m_v);
1021 #pragma omp master
1022  Ht[index(i, j)] = Htmp;
1023 #pragma omp barrier
1024  }
1025  }
1026  // now m_v = A * vk[Nk-1]
1027  int j = Nk - 1;
1028  for (int i = 0; i < Nk; ++i) {
1029  axpy(m_v, -Ht[index(i, j)], vk[i]);
1030  }
1031  real_t vv = m_v.norm2();
1032 #pragma omp master
1033  {
1034  beta = cmplx(real_t(sqrt(vv)), real_t(0.0));
1035 
1036  // enforce Hessenberg form to Ht
1037  for (int j = 0; j < Nk; ++j) {
1038  for (int k = j + 2; k < Nk; ++k) {
1039  Ht[index(k, j)] = cmplx(real_t(0.0), real_t(0.0));
1040  }
1041  }
1042 
1043  for (int j = 0; j < Nk - 1; ++j) {
1044  int k = j + 1;
1045  Ht[index(k, j)] = cmplx(real(Ht[index(k, j)]), real_t(0.0));
1046  }
1047  }
1048 #pragma omp barrier
1049 
1050  // The following code intends to apply Householder transformation
1051  // to enforce the Hessenberg form to Ht.
1052  // This code is not used in current version of algorithm,
1053  // since it seems not appropriate for present situation.
1054  // Nevertheless the code is retained for potential use in future.
1055  // Note that it may contain unfound bugs.
1056  // [24 Feb 2020 H.Matsufuru]
1057 
1058  // Householder
1059 
1060  /*
1061  for(int j = 0; j < Nk-1; ++j){
1062 
1063  u[j] = cmplx(0.0, 0.0);
1064  x[j] = cmplx(0.0, 0.0);
1065 
1066  complex_t asd = Ht[index(j+1,j)];
1067  real_t asd2 = abs(asd) * abs(asd);
1068 
1069  real_t x2 = 0.0;
1070  for(int k = j+2; k < Nk; ++k){
1071  real_t x1 = abs(Ht[index(k,j)]);
1072  x2 += x1 * x1;
1073  u[k] = Ht[index(k,j)];
1074  }
1075 
1076  real_t sqx2 = 0.0;
1077  if(x2 > 0.0) sqx2 = sqrt(x2);
1078 
1079  if(Ht[index(j,j)] + sqx2 == Ht[index(j,j)]){
1080  // in this case, deflation is better.
1081  continue;
1082  }
1083 
1084  real_t zabs = abs(asd) - sqrt(asd2 + x2);
1085  complex_t ph = cmplx(1.0, 0.0);
1086  if(abs(asd) > 1.e-12) ph = asd/abs(asd);
1087  complex_t zeta = ph * cmplx(zabs, 0.0);
1088  real_t uabs2 = zabs * zabs + x2;
1089 
1090  vout.general(m_vl, " j = %d uabs2 = %e x2 = %e\n",j, uabs2, x2);
1091 
1092  u[j+1] = zeta;
1093  Ht[index(j+1,j)] = asd - zeta;
1094 
1095  for(int k = j+2; k < Nk; ++k){
1096  Ht[index(k,j)] = cmplx(0.0, 0.0);
1097  }
1098 
1099  // mult H(u) to H from left
1100  for(int i = j+1; i < Nk; ++i){
1101 
1102  complex_t prod = cmplx(0.0, 0.0);
1103  for(int k = j+1; k < Nk; ++k){
1104  prod += conj(u[k]) * Ht[index(k,i)];
1105  }
1106  prod = prod * 2.0/uabs2;
1107 
1108  for(int k = j+1; k < Nk; ++k){
1109  Ht[index(k,i)] -= prod * u[k];
1110  }
1111 
1112  }
1113 
1114  // mult H(u) to H from right
1115  for(int i = 0; i < Nk; ++i){
1116 
1117  complex_t prod = cmplx(0.0, 0.0);
1118  for(int k = j+1; k < Nk; ++k){
1119  prod += conj(Ht[index(i,k)]) * u[k];
1120  }
1121  prod = prod * 2.0/uabs2;
1122 
1123  for(int k = j+1; k < Nk; ++k){
1124  Ht[index(i,k)] -= prod * conj(u[k]);
1125  }
1126 
1127  }
1128 
1129  // mult H(u) to Q from left
1130  for(int i = j+1; i < Nk; ++i){
1131 
1132  complex_t prod = cmplx(0.0, 0.0);
1133  for(int k = j+1; k < Nk; ++k){
1134  prod += conj(u[k]) * Qt[index(k,i)];
1135  }
1136  prod = prod * 2.0/uabs2;
1137  for(int k = j+1; k < Nk; ++k){
1138  Qt[index(k,i)] -= prod * u[k];
1139  }
1140 
1141  }
1142 
1143  // mult phase factor to H
1144  Ht[index(j+1,j)] *= conj(ph);
1145  for(int k = j+1; k < Nk; ++k){
1146  Ht[index(j+1,k)] *= ph;
1147  }
1148 
1149  // mult phase factor to Q
1150  for(int k = 0; k < Nk; ++k){
1151  Qt[index(j,k)] *= ph;
1152  }
1153 
1154  } // j-loop
1155 
1156  // mult Qt^d to V from right
1157  for(int j = 0; j < Nk; ++j){
1158  m_B[j].set(0.0);
1159  for (int k = 0; k < Nk; ++k) {
1160  axpy(m_B[j], conj(Qt[index(j,k)]), vk[k]);
1161  }
1162  }
1163  */
1164 }
1165 
1166 
1167 //====================================================================
1168 //============================================================END=====
Parameters::set_string
void set_string(const string &key, const string &value)
Definition: parameters.cpp:39
aeigensolver_IRArnoldi.h
Parameters
Class for parameters.
Definition: parameters.h:46
AEigensolver_IRArnoldi::reconst_Ht
void reconst_Ht(std::vector< complex_t > &Ht, std::vector< complex_t > &Qt, complex_t &beta, std::vector< FIELD > &vk, int Nk)
Definition: aeigensolver_IRArnoldi-tmpl.h:1007
Parameters::set_double
void set_double(const string &key, const double value)
Definition: parameters.cpp:33
AEigensolver_IRArnoldi::solve
void solve(std::vector< complex_t > &TDa, std::vector< FIELD > &vk, int &Nsbt, int &Nconv, const FIELD &b)
complex version of solve.
Definition: aeigensolver_IRArnoldi-tmpl.h:170
Bridge::BridgeIO::detailed
void detailed(const char *format,...)
Definition: bridgeIO.cpp:219
AEigensolver_IRArnoldi::get_parameters
void get_parameters(Parameters &params) const
Definition: aeigensolver_IRArnoldi-tmpl.h:74
AEigensolver::real_t
FIELD::real_t real_t
Definition: aeigensolver.h:45
AEigensolver_IRArnoldi::set_parameters
void set_parameters(const Parameters &params)
Definition: aeigensolver_IRArnoldi-tmpl.h:39
AEigensolver::complex_t
ComplexTraits< real_t >::complex_t complex_t
Definition: aeigensolver.h:46
AEigensolver_IRArnoldi::qrtrf
void qrtrf(std::vector< complex_t > &Ht, int Nk, int Nm, std::vector< complex_t > &Qt, complex_t Dsh, int kmin, int kmax)
Definition: aeigensolver_IRArnoldi-tmpl.h:685
axpy
void axpy(Field &y, const double a, const Field &x)
axpy(y, a, x): y := a * x + y
Definition: field.cpp:380
AEigensolver_IRArnoldi::check_eigen_Ht
void check_eigen_Ht(std::vector< complex_t > &Ht, std::vector< complex_t > &TDa, std::vector< complex_t > &Xt, int km, int Nm)
Definition: aeigensolver_IRArnoldi-tmpl.h:939
real_t
double real_t
Definition: bridgeQXS_Clover_coarse_double.cpp:16
ParameterCheck::non_negative
int non_negative(const int v)
Definition: parameterCheck.cpp:21
copy
void copy(Field &y, const Field &x)
copy(y, x): y = x
Definition: field.cpp:212
AEigensolver_IRArnoldi::tqri
void tqri(std::vector< complex_t > &Ht, int k1, int Nk, int Nm, std::vector< complex_t > &Qt, int &nconv)
Definition: aeigensolver_IRArnoldi-tmpl.h:615
AEigensolver_IRArnoldi::shift_wilkinson
void shift_wilkinson(complex_t &kappa, const complex_t a, const complex_t b, const complex_t c, const complex_t d)
Definition: aeigensolver_IRArnoldi-tmpl.h:842
AEigensolver_IRArnoldi::reunit_Qt
void reunit_Qt(std::vector< complex_t > &Qt, int Nk)
Definition: aeigensolver_IRArnoldi-tmpl.h:972
AEigensolver_IRArnoldi::check_Qt
void check_Qt(const int Nk, const int Nm, std::vector< complex_t > &Qt, std::vector< complex_t > &Ht, std::vector< complex_t > &At)
Definition: aeigensolver_IRArnoldi-tmpl.h:797
AIndex_eo_qxs::idx
int idx(const int in, const int Nin, const int ist, const int Nx2, const int Ny, const int leo, const int Nvol2, const int ex)
Definition: aindex_eo.h:27
ParameterCheck::square_non_zero
int square_non_zero(const double v)
Definition: parameterCheck.cpp:43
AEigensolver_IRArnoldi::~AEigensolver_IRArnoldi
~AEigensolver_IRArnoldi()
Definition: aeigensolver_IRArnoldi-tmpl.h:31
dotc
dcomplex dotc(const Field &y, const Field &x)
Definition: field.cpp:712
AEigensolver_IRArnoldi::step
void step(int Nm, int k, std::vector< FIELD > &vk, FIELD &f)
Definition: aeigensolver_IRArnoldi-tmpl.h:545
Bridge::BridgeIO::set_verbose_level
static VerboseLevel set_verbose_level(const std::string &str)
Definition: bridgeIO.cpp:133
Parameters::set_int
void set_int(const string &key, const int value)
Definition: parameters.cpp:36
AEigensolver_IRArnoldi::deflation
void deflation(int k1, int k2, int Kdis, std::vector< complex_t > &TDa, std::vector< FIELD > &vk, complex_t &beta)
deflation of converged eigenvectors.
Definition: aeigensolver_IRArnoldi-tmpl.h:510
scal
void scal(Field &x, const double a)
scal(x, a): x = a * x
Definition: field.cpp:261
Parameters::fetch_string
int fetch_string(const string &key, string &value) const
Definition: parameters.cpp:378
Parameters::fetch_double
int fetch_double(const string &key, double &value) const
Definition: parameters.cpp:327
AEigensolver_IRArnoldi::schmidt
void schmidt(int Nk, std::vector< FIELD > &vk)
Definition: aeigensolver_IRArnoldi-tmpl.h:582
AEigensolver_IRArnoldi::eigenvector_Ht
void eigenvector_Ht(std::vector< complex_t > &Yt, std::vector< complex_t > &St, int km, int Nm)
Definition: aeigensolver_IRArnoldi-tmpl.h:885
Bridge::BridgeIO::crucial
void crucial(const char *format,...)
Definition: bridgeIO.cpp:180
Sorter< complex_t >
AEigensolver_IRArnoldi::mult_Qt
void mult_Qt(std::vector< complex_t > &Yt, std::vector< complex_t > &Qt, std::vector< complex_t > &Xt, int km, int Nm)
Yt = Qt * Xt.
Definition: aeigensolver_IRArnoldi-tmpl.h:920
Parameters::fetch_int
int fetch_int(const string &key, int &value) const
Definition: parameters.cpp:346
Bridge::BridgeIO::general
void general(const char *format,...)
Definition: bridgeIO.cpp:200
AEigensolver_IRArnoldi::setUnit_Qt
void setUnit_Qt(int Nm, std::vector< complex_t > &Qt)
Definition: aeigensolver_IRArnoldi-tmpl.h:600
Bridge::vout
BridgeIO vout
Definition: bridgeIO.cpp:512
Bridge::BridgeIO::get_verbose_level
static std::string get_verbose_level(const VerboseLevel vl)
Definition: bridgeIO.cpp:154
AEigensolver_IRArnoldi
Eigenvalue solver with Implicitly Restarted Arnoldi algorithm.
Definition: aeigensolver_IRArnoldi.h:36