CHROMA
eig_spec_array.cc
Go to the documentation of this file.
1 /*! \file
2  * \brief Compute low lying eigenvalues of the hermitian H
3  */
4 
5 
6 #include "chromabase.h"
7 
8 #include <sstream>
9 
11 #include "meas/eig/ritz_array.h"
13 
14 namespace Chroma {
15 
16 //! Compute low lying eigenvalues of the hermitian H
17 /*!
18  * \ingroup eig
19  *
20  * Compute low lying eigenvalues of the hermitian H
21  * using the Ritz functional minimization routine,
22  * if desired in the Kalkreuter-Simma algorithm
23  * H The operator (Read)
24  * lambda_H Eigenvalues (Modify)
25  * psi Eigenvectors (Modify)
26  * N_eig No of eigenvalues (Read)
27  * N_min Minimal CG iterations (Read)
28  * N_max Maximal CG iterations (Read)
29  * Kalk_Sim Use Kalkreuter-Simma criterion (Read)
30  * n_renorm Renormalize every n_renorm iter. (Read)
31  * N_KS_max Max number of Kalkreuter-Simma iterations (Read)
32  * RsdR_r (relative) residue (Read)
33  * Cv_fact "Convergence factor" required (Read)
34  * NCG_tot Total number of CG iter (Write)
35  * n_KS total number of Kalkreuter-Simma iterations (Write)
36  * n_valid number of valid eigenvalues (Write)
37  * ProjApsiP flag for projecting A.psi (Read)
38  */
39 
40 
41 void EigSpecRitzCG(const LinearOperatorArray<LatticeFermion>& M, // Herm pos def operator
42  multi1d<Real>& lambda_H, // E-values
43  multi2d<LatticeFermion>& psi, // E-vectors
44  int n_eig, // No of e-values to find
45  int n_renorm, // renorm frequency
46  int n_min, // minimum iters / e_value
47  int MaxCG, // Max no of CG iters
48  const Real& Rsd_r, // relative residuum of each
49  // e-value
50  const Real& Rsd_a, // absolute residuum
51  const Real& zero_cutoff, // if ev slips below this
52  // we consider it zero
53  const bool ProjApsiP, // Project in Ritz?
54 
55  int& n_cg_tot, // Total no of CG iters
56  XMLWriter& xml_out // Diagnostics
57  )
58 {
59  QDPIO::cout << "EigSpecArray" << std::endl;
60 
61  START_CODE();
62 
63  const Subset& sub = M.subset(); // Subset over which M acts
64 
65  push(xml_out, "EigSpecRitzCG");
66 
67  n_cg_tot = 0;
68  int n_count = 0;
69  int n_max = MaxCG+1;
70 
71  int n, i;
72  Real final_grad;
73 
74  multi1d<Real> resid_rel(n_eig);
75  for(n = 1, i = 0; n <= n_eig; n++, i++)
76  {
77  // Initialise lambda[i] = 1
78  lambda_H[i] = Real(1);
79 
80  QDPIO::cout << "Call ritz n=" << n << std::endl;
81 
82  // Do the Ritz
83  Ritz(M, lambda_H[i], psi, n, Rsd_r, Rsd_a, zero_cutoff, n_renorm, n_min,
84  n_max, MaxCG, ProjApsiP, n_count, final_grad, false, Real(1),
85  Real(1));
86 
87  // Add n_count
88  n_cg_tot += n_count;
89 
90  // Check e-value
91  std::ostringstream s;
92  s << "eval" << n;
93  push(xml_out, s.str());
94  write(xml_out, "n_count", n_count);
95  pop(xml_out);
96 
97  if( toBool( fabs(lambda_H[i]) < zero_cutoff ) ) {
98  QDPIO::cout << "Evalue["<< n << "] = " << lambda_H[i] << " is considered zero" << std::endl;
99  }
100  else
101  {
102  multi1d<LatticeFermion> D_e(M.size());
103  multi1d<LatticeFermion> lambda_e(M.size());
104 
105  M(D_e, psi[i], PLUS);
106 
107  for(int j=0; j < M.size(); ++j)
108  {
109  lambda_e[j][sub] = lambda_H[i]*psi[i][j];
110  D_e[j][sub] -= lambda_e[j];
111  }
112  Double r_norm = sqrt(norm2(D_e,sub));
113  resid_rel[i] = Real(r_norm)/lambda_H[i];
114  QDPIO::cout << "Evalue["<<n<<"]: eigen_norm = " << r_norm << " resid_rel = " << resid_rel[i] << std::endl << std::endl;
115  }
116  }
117 
118  // All EV-s done. Dump-em
119  push(xml_out, "eValues");
120  write(xml_out, "lambda", lambda_H);
121  pop(xml_out);
122  write(xml_out, "n_cg_tot", n_cg_tot);
123 
124  pop(xml_out); // EigSpecRitz
125 
126 
127  END_CODE();
128 }
129 
130 
131 void EigSpecRitzKS(const LinearOperatorArray<LatticeFermion>& M, // Herm pos def operator
132  multi1d<Real>& lambda_H, // E-values
133  multi2d<LatticeFermion>& psi, // E-vectors
134  int n_eig, // no of eig wanted
135  int n_dummy, // No of Dummy e-vals to use
136 
137  int n_renorm, // renorm frequency
138  int n_min, // minimum iters / e_value
139  int n_max, // max iters / e_value
140  int n_max_KS, // max KS cycles
141  const Real& gamma_factor, // the KS gamma factor
142 
143  int MaxCG, // Max no of CG iters
144  const Real& Rsd_r, // relative residuum of each
145  // e-value
146  const Real& Rsd_a, // Absolute residuum
147  const Real& zero_cutoff, // if e-value slips below this, we
148  // consider it zero
149  const bool ProjApsiP, // Project in Ritz?
150 
151  int& n_cg_tot, // Total no of CG iters
152  int& n_KS, // Total no of KS cycles
153  int& n_jacob_tot,
154  XMLWriter& xml_out // Diagnostics
155  )
156 {
157  START_CODE();
158 
159  const Subset& s = M.subset(); // Subset over which M acts
160 
161  // Sanity Checks:
162  // Make sure lambda_H is large enough
163  if( lambda_H.size() < (n_eig+n_dummy) ) {
164  QDP_error_exit("lambda_H is too small to hold n_eig + n_dummy values\n");
165  }
166 
167  // Make sure psi is large enough
168  if( psi.size2() < (n_eig + n_dummy) ) {
169  QDP_error_exit("psi is too small to hold n_eig + n_dummy values\n");
170  }
171 
172  if( n_eig <=0 ) {
173  QDP_error_exit("n_eig must be > 0. it is %d\n", n_eig);
174  }
175 
176  int N5 = psi.size1();
177 
178  if( n_eig ==1 ) {
179  // if n_eig is one, KS algorithm is not applicable. We revert to the
180  // Normal CG method
181  EigSpecRitzCG(M, lambda_H, psi, n_eig, n_renorm, n_min, MaxCG, Rsd_r,
182  Rsd_a, zero_cutoff, ProjApsiP, n_cg_tot, xml_out);
183  return;
184  }
185 
186  // Internal lambda's
187  // lambda_H holds initial guesses. Copy these over.
188  int n_working_eig = n_eig+n_dummy;
189  multi1d<Real> lambda_intern(n_working_eig);
190  multi1d<Real> lambda_previous(n_working_eig);
191  multi1d<Real> delta_cycle(n_working_eig);
192  int i;
193  for(i = 0; i < n_working_eig; i++) {
194  lambda_intern[i] = lambda_H[i];
195  lambda_previous[i] = Real(1);
196  delta_cycle[i] = Real(1);
197  }
198 
199  // Off diag elements of hermitian matrix to diagonalise
200  multi1d<Complex> off_diag((n_working_eig)*(n_working_eig-1)/2);
201 
202 
203  multi1d<Real> final_grad(n_working_eig);
204 
205  int n_count = 0;
206  n_cg_tot = 0;
207  n_KS = 0;
208  n_jacob_tot = 0;
209 
210  int ev, j, ij;
211  int n_jacob;
212 
213  push(xml_out, "EigSpecRitzKS");
214 
215 
216  for( int KS_iter = 0; KS_iter < n_max_KS; KS_iter++)
217  {
218  n_KS++;
219 
220  push(xml_out, "KS_iter");
221 
222  // KS Step 1: for each k=0, n-1 in succession compute
223  // approximations to the eigenvectors of M by performing
224  // only a certain number of CG iterations (governed by gamma_factor)
225  for(ev = 1, i=0; ev <= n_working_eig; ev++, i++) {
226 
227  // Do the Ritz for all working eigenvalues
228  Ritz(M, lambda_intern[i], psi, ev, Rsd_r, Rsd_a, zero_cutoff, n_renorm,
229  n_min, n_max, MaxCG, ProjApsiP, n_count, final_grad[i], true,
230  Real(1), gamma_factor);
231 
232  // Count the CG cycles
233  n_cg_tot += n_count;
234  push(xml_out, "ev");
235  write(xml_out, "n_count", n_count);
236  write(xml_out, "final_grad", final_grad[i]);
237  pop(xml_out);
238 
239  }
240 
241  // Construct the hermitian matrix M to diagonalise.
242  // Note only the off diagonal elements are needed
243  // the lambda_intern[i] are the diagonal elements
244 
245  // M_ij = (psi_j, M psi_i )
246  //
247  multi1d<LatticeFermion> tmp(N5);
248  for(i=0, ij=0; i < n_working_eig; i++) {
249  M(tmp, psi[i], PLUS);
250  for(j=0; j < i; j++) {
251  off_diag[ij] = innerProduct(psi[j][0], tmp[0], s);
252  for(int n = 1; n < N5; n++) {
253  off_diag[ij] += innerProduct(psi[j][n], tmp[n], s);
254  }
255  ij++;
256  }
257  }
258 
259 
260 
261  // Now diagonalise it, rotate evecs, and sort
262  //
263  // Jacobi at the moment works with the absolute error
264  n_jacob = SN_Jacob_Array(psi, n_working_eig, lambda_intern, off_diag, Rsd_a, 50, s);
265  n_jacob_tot += n_jacob;
266 
267  write(xml_out, "n_jacob", n_jacob);
268 
269 
270  // Now we should check convergence
271  // Pessimistic but safe criterion || g ||/lambda < omega
272  // but can also be converged if we consider something to have a zero ev
273  // we only check convergence of the wanted n_eig
274  bool convP = true;
275  for(i=0; i < n_eig; i++) {
276  bool zeroReachedP = toBool( fabs(lambda_intern[i]) < zero_cutoff );
277 
278  // This ev is converged if either
279  // i) Pessimistic absolute error is reached
280  // ii) Pessimistic relative error is reached
281  // iii) if the ev is below the zero cutoff
282  //
283  convP &= ( toBool( final_grad[i] < Rsd_a )
284  || toBool( final_grad[i] < Rsd_r*fabs(lambda_intern[i]) )
285  || zeroReachedP );
286  }
287 
288  pop(xml_out); // KS_iter
289 
290  // All the wanted e-values converged
291  if( convP ) {
292 
293  // Do final Jacobi without the dummies.
294  // Make the matrix
295  for(i=0, ij=0; i < n_eig; i++) {
296  M(tmp, psi[i], PLUS);
297  for(j=0; j < i; j++) {
298  off_diag[ij] = innerProduct(psi[j][0], tmp[0], s);
299  for(int n=1; n < N5; n++) {
300  off_diag[ij] += innerProduct(psi[j][n], tmp[n], s);
301  }
302  ij++;
303  }
304  }
305 
306  // Diagonalise, rotate, sort
307  n_jacob = SN_Jacob_Array(psi, n_eig, lambda_intern, off_diag, Rsd_a, 50, s);
308  write(xml_out, "final_n_jacob", n_jacob);
309  write(xml_out, "n_cg_tot", n_cg_tot);
310  write(xml_out, "n_KS", n_KS);
311 
312 
313  // Copy lambda_intern back into lambda_H and return
314  for(i=0; i < n_eig; i++) {
315  lambda_H[i] = lambda_intern[i];
316  }
317 
318  write(xml_out, "lambda_H", lambda_H);
319  pop(xml_out); // EigSpecRitzKS
320  END_CODE();
321  return;
322  }
323 
324  }
325 
326  write(xml_out, "n_cg_tot", n_cg_tot);
327  write(xml_out, "n_KS", n_KS);
328  pop(xml_out); //EigSpecRitzKS
329 
330  // If we reached here then we have done more than n_max KS
331  QDP_error_exit("n_max_KS reached with no convergence");
332  END_CODE();
333 }
334 
335 
336 void fixMMev2Mev(const LinearOperatorArray<LatticeFermion>& M, // The Op to fix to
337  multi1d<Real>& lambda, // The Evals of M^{dag}M on input
338  // The Evals of M on output
339  multi2d<LatticeFermion>& ev_psi, // The Evecs
340  const int n_eig, // The no of evals/evecs
341  const Real& Rsd_r, // Relative error for validity
342  const Real& Rsd_a, // Absolute error for validity
343  const Real& zero_cutoff, // Zero cutoff
344  multi1d<bool>& valid_eig, // Validity mask (Write)
345  int& n_valid, // No of valids (Write)
346  int& n_jacob // How many Jacobis were done
347  )
348 {
349  START_CODE();
350 
351  const Subset& s = M.subset(); // Subset over which M acts
352 
353 
354  // Sanity checking
355  if( n_eig > lambda.size() ) {
356  QDP_error_exit("n_eig greater than size of lambda array\n");
357  }
358 
359  if( lambda.size() != ev_psi.size2() ) {
360  QDP_error_exit("lambda and ev_psi arrays must have same size\n");
361  }
362 
363  // Make the valid eig the right size
364  valid_eig.resize(n_eig);
365 
366  int N5 = ev_psi.size1();
367 
368  // Temporaries
369  multi1d<LatticeFermion> tmp(N5);
370  Double lambda_H_sq;
371  Double delta_lambda;
372  bool convP;
373  // We are all set -- lets do it
374 
375  if( n_eig == 1 ) { // only one eigenvalue
376  M(tmp, ev_psi[0], PLUS);
377  Double lambda_fix_single = innerProductReal(ev_psi[0][0], tmp[0], s);
378  for(int n=1; n < N5; n++) {
379  lambda_fix_single += innerProductReal(ev_psi[0][n], tmp[n], s);
380  }
381  // No diagonalisation needed -- only 1 eval
382 
383  // We square lambda_fix_single.
384  lambda_H_sq = lambda_fix_single*lambda_fix_single;
385 
386 
387  // Different validity criteria, depending on whether lambda_fix_single^2
388  // is less than our zero cutoff
389  if( toBool( lambda_H_sq < zero_cutoff ) )
390  {
391  // Yes, the square of our estimate for lambda is less than the cutoff
392  // Check whether the original lambda was also less than the cutoff
393  // if so, our ev is considered a valid zero e-value
394  if( toBool( lambda[0] < zero_cutoff ) ) {
395  valid_eig[0] = true;
396  n_valid = 1;
397  }
398  else {
399  // No, the square of our estimate was not zero. Mismatch
400  // BTW what else can we do here?
401  valid_eig[0] = false;
402  n_valid = 1;
403  }
404  }
405  else {
406  // Check relative error or absolute error is satisfied
407  delta_lambda = fabs( lambda_H_sq - Double( lambda[0] ) );
408 
409  convP = toBool( delta_lambda < Double(Rsd_a) )
410  || toBool( delta_lambda < Double(Rsd_r)*fabs(Double(lambda[0])) );
411 
412  if ( convP ) {
413  // Condition is satisfied
414  valid_eig[0] = true;
415  n_valid = 1;
416  } else {
417  // Condition is not satisfied
418  valid_eig[0] = false;
419  n_valid = 0;
420  }
421  }
422 
423  // Whatever happened lambda_fix_single is our estimate for
424  // lambda[0]
425  lambda[0] = Real(lambda_fix_single);
426  return;
427  } // end if (n_eig == 1)
428 
429 
430  // Interesting case multiple ev-s
431  // Construct new ev-s and off diagonal matrix
432  multi1d<Complex> off_diag(n_eig*(n_eig-1)/2 );
433  multi1d<Real> lambda_fix(n_eig);
434  for(int i = 0; i < n_eig; i++) {
435  valid_eig[i] = false;
436  }
437 
438  for(int i=0, ij=0; i < n_eig; i++) {
439  M(tmp, ev_psi[i], PLUS);
440  lambda_fix[i] = innerProductReal(ev_psi[i][0], tmp[0], s);
441  for(int n=1; n < N5; n++) {
442  lambda_fix[i] += innerProductReal(ev_psi[i][n], tmp[n], s);
443  }
444 
445  for(int j=0; j < i; j++) {
446  off_diag[ij] = innerProduct(ev_psi[j][0], tmp[0], s);
447  for(int n=1; n < N5; n++) {
448  off_diag[ij] += innerProduct(ev_psi[j][n], tmp[n], s);
449  }
450  ij++;
451  }
452  }
453 
454  // Diagonalise and sort according to size
455  n_jacob = SN_Jacob_Array(ev_psi, n_eig, lambda_fix, off_diag, Rsd_a, 50, s);
456 
457  // Now the tricky business of matching up with ev-s of H^2
458  n_valid = 0;
459 
460  for(int i=0; i < n_eig; i++)
461  {
462  lambda_H_sq = Double(lambda_fix[i])*Double(lambda_fix[i]);
463 
464  if( toBool(lambda_H_sq < zero_cutoff ) )
465  {
466  // Now compare with all the invalid ev-s
467  for(int j = n_valid; ( j < n_eig ) && ( valid_eig[i] == false ); j++ )
468  {
469  // If we find an original zero lambda, we match it with this
470  // and consider this matched
471  if( toBool( lambda[j] < zero_cutoff ) ) {
472 
473  // lambda_fix[i] matches lambda[j]
474  valid_eig[i] = true;
475 
476  // swap lambda[j] with lambda[valid_eig];
477  // so we don't search it again
478  Real tmp = lambda[j];
479  lambda[j] = lambda[n_valid];
480  lambda[n_valid] = tmp;
481 
482  // Increase the validity count
483  n_valid++;
484  }
485 
486  // Else compare with next j
487  }
488  // At this point either valid_eig[i] is true, or we were unable to match
489  // in which case valid_eig[i] is false from initialisation
490  // in any case time for next_eig
491 
492  }
493  else
494  {
495  // Now compare with all the invalid ev-s
496  for(int j = n_valid; ( j < n_eig ) && ( valid_eig[i] == false ); j++ )
497  {
498  delta_lambda = fabs( lambda_H_sq - Double(lambda[j]) );
499 
500  convP = toBool( delta_lambda < Double(Rsd_a) )
501  || toBool( delta_lambda < Double(Rsd_r) * fabs( Double(lambda[j]) ) );
502  if( convP )
503  {
504  // lambda_fix[i] matches lambda[j]
505  valid_eig[i] = true;
506 
507  // swap lambda[j] with lambda[valid_eig];
508  // so we don't search it again
509  Real ftmp = lambda[j];
510  lambda[j] = lambda[n_valid];
511  lambda[n_valid] = ftmp;
512 
513  // Increase the validity count
514  n_valid++;
515  }
516 
517  // Else compare with next j
518  }
519  // At this point either valid_eig[i] is true, or we were unable to match
520  // in which case valid_eig[i] is false from initialisation
521  // in any case time for next_eig
522  }
523  } // We are done
524 
525  // Now we can overwrite lambda with lambda_fix
526  // A desirable feature would be to move the invalid ev-s to the end
527  // but I cannot be bothered
528  for(int i = 0; i < n_eig; i++ ) {
529  lambda[i] = lambda_fix[i];
530  }
531 
532  END_CODE();
533 
534  // we are done
535  return;
536 }
537 
538 } // end namespace Chroma
Primary include file for CHROMA library code.
Linear Operator to arrays.
Definition: linearop.h:61
virtual int size() const =0
Expected length of array index.
virtual const Subset & subset() const =0
Return the subset on which the operator acts.
int SN_Jacob_Array(multi2d< LatticeFermion > &psi, const int N_eig, multi1d< Real > &lambda, multi1d< Complex > &off_diag, Real tolerance, int N_max, const Subset &sub)
Single-node Jacobi rotation.
void EigSpecRitzCG(const LinearOperator< LatticeFermion > &M, multi1d< Real > &lambda_H, multi1d< LatticeFermion > &psi, int n_eig, int n_renorm, int n_min, int MaxCG, const Real &Rsd_r, const Real &Rsd_a, const Real &zero_cutoff, const bool ProjApsiP, int &n_cg_tot, XMLWriter &xml_out)
Compute low lying eigenvalues of the hermitian H.
Definition: eig_spec.cc:41
void write(XMLWriter &xml, const std::string &path, const AsqtadFermActParams &param)
Writer parameters.
unsigned j
Definition: ldumul_w.cc:35
unsigned n
Definition: ldumul_w.cc:36
BinaryReturn< C1, C2, FnInnerProduct >::Type_t innerProduct(const QDPSubType< T1, C1 > &s1, const QDPType< T2, C2 > &s2)
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
void fixMMev2Mev(const LinearOperator< LatticeFermion > &M, multi1d< Real > &lambda, multi1d< LatticeFermion > &ev_psi, const int n_eig, const Real &Rsd_r, const Real &Rsd_a, const Real &zero_cutoff, multi1d< bool > &valid_eig, int &n_valid, int &n_jacob)
Definition: eig_spec.cc:321
void EigSpecRitzKS(const LinearOperator< LatticeFermion > &M, multi1d< Real > &lambda_H, multi1d< LatticeFermion > &psi, int n_eig, int n_dummy, int n_renorm, int n_min, int n_max, int n_max_KS, const Real &gamma_factor, int MaxCG, const Real &Rsd_r, const Real &Rsd_a, const Real &zero_cutoff, const bool ProjApsiP, int &n_cg_tot, int &n_KS, int &n_jacob_tot, XMLWriter &xml_out)
Definition: eig_spec.cc:124
QDP_error_exit("too many BiCG iterations", n_count, rsd_sq, cp, c, re_rvr, im_rvr, re_a, im_a, re_b, im_b)
int n_count
Definition: invbicg.cc:78
LatticeFermion tmp
Definition: mespbg5p_w.cc:36
push(xml_out,"Condensates")
const WilsonTypeFermAct< multi1d< LatticeFermion > > Handle< const ConnectState > const multi1d< Real > enum InvType invType const multi1d< Real > int MaxCG
Definition: pbg5p_w.cc:32
int i
Definition: pbg5p_w.cc:55
@ PLUS
Definition: chromabase.h:45
void Ritz(const LinearOperator< LatticeFermion > &A, Real &lambda, multi1d< LatticeFermion > &psi_all, int N_eig, const Real &Rsd_r, const Real &Rsd_a, const Real &zero_cutoff, int n_renorm, int n_min, int n_max, int MaxCG, bool ProjApsiP, int &n_count, Real &final_grad, bool Kalk_Sim, const Real &delta_cycle, const Real &gamma_factor)
Definition: ritz.cc:559
LatticeFermion psi
Definition: mespbg5p_w.cc:35
pop(xml_out)
START_CODE()
multi1d< LatticeFermion > s(Ncb)
FloatingPoint< double > Double
Definition: gtest.h:7351
Double r_norm
Definition: pade_trln_w.cc:86