CHROMA
fgmres_dr_tests.cc
Go to the documentation of this file.
1 #include "gtest/gtest.h"
2 #include "chromabase.h"
3 #include "qdp-lapack.h"
7 //using namespace std;
8 using namespace Chroma;
9 
11  "<?xml version='1.0'?> \
12  <Params> \
13  <FermionAction> \
14  <FermAct>CLOVER</FermAct> \
15  <Kappa>0.115</Kappa> \
16  <clovCoeff>1.17</clovCoeff> \
17  <clovCoeffR>0.91</clovCoeffR> \
18  <clovCoeffT>1.07</clovCoeffT> \
19  <AnisoParam> \
20  <anisoP>true</anisoP> \
21  <t_dir>3</t_dir> \
22  <xi_0>2.464</xi_0> \
23  <nu>0.95</nu> \
24  </AnisoParam> \
25  <FermState> \
26  <Name>STOUT_FERM_STATE</Name> \
27  <rho>0.22</rho> \
28  <n_smear>2</n_smear> \
29  <orthog_dir>3</orthog_dir> \
30  <FermionBC> \
31  <FermBC>SIMPLE_FERMBC</FermBC> \
32  <boundary>1 1 1 -1</boundary> \
33  </FermionBC> \
34  </FermState> \
35  </FermionAction> \
36  <InvertParam> \
37  <invType>FGMRESDR_INVERTER</invType> \
38  <RsdTarget>1.0e-7</RsdTarget> \
39  <NKrylov>5</NKrylov> \
40  <NDefl>3</NDefl> \
41  <MaxIter>130</MaxIter> \
42  <PrecondParams> \
43  <invType>MR_INVERTER</invType> \
44  <RsdMR>0.1</RsdMR> \
45  <MaxMR>10</MaxMR> \
46  </PrecondParams> \
47  </InvertParam> \
48  </Params>";
49 
50 
52 public:
53 
54  // Type aliases should be visible to all tests
55  using T = LatticeFermion;
56  using Q = multi1d<LatticeColorMatrix>;
57  using P = multi1d<LatticeColorMatrix>;
58 
59 
61  {
62  u.resize(Nd);
63  for(int mu=0; mu < Nd; ++mu) {
64  gaussian(u[mu]);
65  reunit(u[mu]);
66  }
67 
68  std::istringstream input(xml_for_param);
69  XMLReader xml_in(input);
70 
71  S_f = dynamic_cast<FermAct4D<T,P,Q>*>(TheFermionActionFactory::Instance().createObject("CLOVER",
72  xml_in,
73  "FermionAction")
74  );
75  state = S_f->createState(u);
76  linop = S_f->linOp(state);
77 
78  }
79 
80  void TearDown()
81  {
82 
83  }
84 
85  // Virtual destructor
86  virtual
88 
89 
90  multi1d<LatticeColorMatrix> u;
94 };
95 
97  public ::testing::WithParamInterface<float>
98 {
99 
100 };
101 
102 TEST_F(FGMRESDRTests, canConstructDefault)
103 {
105  ASSERT_EQ(p.NKrylov, 0);
106  ASSERT_EQ(p.NDefl, 0);
107  ASSERT_EQ(p.MaxIter, 0);
108  ASSERT_EQ(p.PrecondParams.path, "/PrecondParams");
109 }
110 
111 
112 TEST_F(FGMRESDRTests, canReadXML)
113 {
114  std::istringstream input(xml_for_param);
115  XMLReader xml_in(input);
116  SysSolverFGMRESDRParams p( xml_in, "/Params/InvertParam" );
117  ASSERT_EQ(p.NKrylov, 5);
118  ASSERT_EQ(p.NDefl, 3);
119  ASSERT_EQ(p.MaxIter, 130);
120  ASSERT_EQ(p.PrecondParams.path, "/PrecondParams");
121  ASSERT_EQ(p.PrecondParams.id, "MR_INVERTER");
122 }
123 
124 TEST_F(FGMRESDRTests, canCreateFGMRESDRClassFromParam)
125 {
126  std::istringstream input(xml_for_param);
127  XMLReader xml_in(input);
128  SysSolverFGMRESDRParams p( xml_in, "/Params/InvertParam" );
129  LinOpSysSolverFGMRESDR fgmres_dr_solver(linop,state,p);
130 }
131 
132 TEST_F(FGMRESDRTests, canCreateFGMRESDRClassFromFactory)
133 {
134  std::istringstream input(xml_for_param);
135  XMLReader xml_in(input);
136  Handle< LinOpSystemSolver<T> > solver_handle = TheLinOpFermSystemSolverFactory::Instance().createObject( "FGMRESDR_INVERTER", xml_in, std::string("/Params/InvertParam"), state, linop);
137 }
138 
140 {
141  int n_krylov = 5;
142  int rows=n_krylov+1;
143  int cols=n_krylov;
144  multi2d<DComplex> H(cols,rows);
145 
146  for(int col=0; col < n_krylov; ++col) {
147  for(int row=0; row < n_krylov+1; ++row) {
148  H(col,row) = DComplex(0);
149  }
150  }
151 
152  int dim = n_krylov;
153  for(int row=0; row < dim+1; ++row) {
154  QDPIO::cout << "[ ";
155  for(int col=0; col < dim; ++col) {
156  QDPIO::cout << H(col, row) << " ";
157  }
158  QDPIO::cout << " ] " << std::endl;
159  }
160 }
161 
163 {
164  std::istringstream input(xml_for_param);
165  XMLReader xml_in(input);
166  SysSolverFGMRESDRParams p( xml_in, "/Params/InvertParam" );
167  LinOpSysSolverFGMRESDR sol(linop,state,p);
168 
169 
170  const Subset& s = sol.subset();
171 
172 
173  // Create a gaussian source
174  LatticeFermion rhs;
175  gaussian(rhs, s);
176 
177 
178  Real rsd_target(1.0e-6);
179  rsd_target*=sqrt(norm2(rhs,s));
180  int n_krylov=5;
181  int n_deflate=0;
182  multi2d<DComplex> H(n_krylov,n_krylov+1); // The H matrix
183  multi2d<DComplex> R(n_krylov,n_krylov+1); // R = H diagonalized with Givens rotations
184  multi1d<T> V(n_krylov+1); // K(A)
185  multi1d<T> Z(n_krylov+1); // K(MA)
186  multi1d< Handle<Givens> > givens_rots(n_krylov+1);
187  multi1d<DComplex> g(n_krylov+1);
188  multi2d<DComplex> Qk_Hk;
189  multi1d<DComplex> Qk_Hk_taus;
190 
191  for(int col=0; col < n_krylov; ++col) {
192  for(int row=0; row < n_krylov+1; ++row) {
193  H(col,row) = DComplex(0);
194  R(col,row) = DComplex(0);
195  }
196  }
197 
198 
199  Double beta=sqrt(norm2(rhs, s));
200  for(int j=0; j < g.size(); ++j) {
201  g[j] = DComplex(0);
202  }
203  g[0] = beta;
204  // Set up initial V[0] = rhs / || r^2 || --
205  Double beta_inv = Double(1)/beta;
206  V[0][s] = beta_inv * rhs;
207  int dim;
208 
209  sol.FlexibleArnoldi(n_krylov, n_deflate,
210  rsd_target,
211  V,
212  Z,
213  H,
214  R,
215  givens_rots,
216  g,
217  Qk_Hk,
218  Qk_Hk_taus,
219  dim);
220 
221  ASSERT_EQ(dim,n_krylov);
222 
223  // Instead of printing, Assert that Upper Hessenberg
224  for(int row=0; row < dim+1; ++row) {
225  for(int col = 0; col < row-1; ++col) {
226 
227  // These are below the row below the diagonal -- should be 0
228 
229  double re = toDouble( real( H(col,row) ) );
230  double im = toDouble( imag( H(col,row) ) );
231  EXPECT_DOUBLE_EQ( re, 0);
232  EXPECT_DOUBLE_EQ( im, 0);
233  }
234 
235  }
236 
237 
238 
239  // Now the various V's should be orthonormal. Check this.
240  for(int j=0; j < dim; ++j) {
241  EXPECT_DOUBLE_EQ( toDouble(sqrt(norm2(V[j],s))), 1.0);
242  }
243 
244  for(int j=0; j < dim; ++j) {
245  for(int i=j+1; i < dim; ++i) {
246  ASSERT_NEAR( 0, toDouble(norm2(innerProduct(V[i],V[j],s))),1.0e-16);
247  }
248  }
249 }
250 
251 TEST_F(FGMRESDRTests, GivensF0G0)
252 {
253  multi2d<DComplex> H(1,2);
254  // Fill both 'f' and 'g' with 0
255  for(int row=0; row < 2; ++row) {
256  H(0,row) = DComplex(0);
257  }
258  Givens g(0,H);
259 
260  // Apply Givens to col 0.
261  g(0,H);
262 
263 
264  // H(1,0) should be 0
265  EXPECT_DOUBLE_EQ( 0, toDouble( real(H(0,1)) ) );
266  EXPECT_DOUBLE_EQ( 0, toDouble( imag(H(0,1)) ) );
267 
268 
269  EXPECT_DOUBLE_EQ( 0, toDouble( real(H(0,0)) ) );
270  EXPECT_DOUBLE_EQ( 0, toDouble( imag(H(0,0)) ) );
271 }
272 
273 TEST_F(FGMRESDRTests, GivensF0GNot0)
274 {
275  multi2d<DComplex> H(1,2);
276  // Fill both 'f' and 'g' with 0
277  for(int row=0; row < 2; ++row) {
278  H(0,row) = DComplex(0);
279  }
280 
281  DComplex g;
282  random(g);
283 
284 
285  H(0,1) = g; // Nonzero 'g'
286 
287  // Compute Givens
288  Givens G(0,H);
289 
290  // Apply Givens to col 0.
291  G(0,H);
292  // H(1,0) should be 0
293  EXPECT_DOUBLE_EQ( 0, toDouble( real(H(0,1)) ) );
294  EXPECT_DOUBLE_EQ( 0, toDouble( imag(H(0,1)) ) );
295 
296  EXPECT_DOUBLE_EQ( toDouble(real(g)), toDouble( real(H(0,0)) ) );
297  EXPECT_DOUBLE_EQ( toDouble(imag(g)), toDouble( imag(H(0,0)) ) );
298 }
299 
300 TEST_F(FGMRESDRTests, GivensFNot0G0)
301 {
302  multi2d<DComplex> H(1,2);
303  // Fill both 'f' and 'g' with 0
304  for(int row=0; row < 2; ++row) {
305  H(0,row) = DComplex(0);
306  }
307 
308  DComplex f;
309  random(f);
310 
311 
312  H(0,0) = f; // Nonzero 'f'
313 
314  // Compute Givens
315  Givens G(0,H);
316 
317  // Apply Givens to col 0.
318  G(0,H);
319  // H(1,0) should be 0
320  EXPECT_DOUBLE_EQ( 0, toDouble( real(H(0,1)) ) );
321  EXPECT_DOUBLE_EQ( 0, toDouble( imag(H(0,1)) ) );
322 
323  EXPECT_DOUBLE_EQ( toDouble(real(sqrt(norm2(f)))), toDouble( real(H(0,0)) ) );
324  EXPECT_DOUBLE_EQ( toDouble(imag(sqrt(norm2(f)))), toDouble( imag(H(0,0)) ) );
325 }
326 
327 TEST_F(FGMRESDRTests, GivensFNot0GNot0)
328 {
329  multi2d<DComplex> H(2,2);
330  // Fill both 'f' and 'g' with 0
331  for(int row=0; row < 2; ++row) {
332  H(0,row) = DComplex(0);
333  }
334 
335  DComplex f,g;
336  random(f);
337  random(g);
338 
339 
340  H(0,0) = f; // Nonzero f& g
341  H(0,1) = g;
342 
343  H(1,0) = f;
344  H(1,1) = g;
345 
346  // Compute Givens
347  Givens G(0,H); // Col 0 -- same as used to compute (get r automatically)
348 
349  G(0,H); // Col 0 -- same as used to compute (get r automatically)
350  G(1,H); // Col 1 -- same as used to compute (get r automatically)
351 
352  // H(0,1) should be 0
353  EXPECT_DOUBLE_EQ( 0, toDouble( real(H(0,1)) ) );
354  EXPECT_DOUBLE_EQ( 0, toDouble( imag(H(0,1)) ) );
355 
356  // H(1,1) should be 0
357  EXPECT_DOUBLE_EQ( 0, toDouble( real(H(1,1)) ) );
358  EXPECT_DOUBLE_EQ( 0, toDouble( imag(H(1,1)) ) );
359 
360  // H(0,0) and H(1,0) should be the same
361  EXPECT_DOUBLE_EQ( toDouble( real(H(0,0)) ) , toDouble( real(H(1,0)) ) );
362  //EXPECT_DOUBLE_EQ( toDouble( imag(H(0,0)) ) , toDouble( imag(H(1,0)) ) );
363 
364 
365 
366 }
367 
368 
369 
370 // TODO:!!!!
371 // Get rid of original arnoldi test.
372 // Fold its elements into this test
373 // Parameterize the tests on nkrylov, and rsd_target
374 // So we can engineer situations where we converge in the cycle,
375 // and ones where we do not.
376 
377 TEST_P(FGMRESDRTestsFloatParams, arnoldi5GivensRot)
378 {
379  std::istringstream input(xml_for_param);
380  XMLReader xml_in(input);
381  SysSolverFGMRESDRParams p( xml_in, "/Params/InvertParam" );
382  LinOpSysSolverFGMRESDR sol(linop,state,p);
383 
384 
385  const Subset& s = sol.subset();
386 
387 
388  // Create a gaussian source
389  LatticeFermion rhs;
390  gaussian(rhs, s);
391 
392  double rsd_target_in=GetParam();
393  Real rsd_target(rsd_target_in);
394  rsd_target *= sqrt(norm2(rhs,s));
395 
396  int n_krylov=5;
397  int n_deflate=0;
398 
399  // Work spaces
400  multi2d<DComplex> H(n_krylov, n_krylov+1); // The H matrix
401  multi2d<DComplex> R(n_krylov, n_krylov+1); // R = H diagonalized with Givens rotations
402  for(int col = 0; col < n_krylov; ++col) {
403  for(int row = 0; row < n_krylov+1; ++row) {
404 
405  H(col,row) = DComplex(0);
406  R(col,row) = DComplex(0);
407  }
408  }
409  multi1d<T> V(n_krylov+1); // K(A)
410  multi1d<T> Z(n_krylov+1); // K(MA)
411  multi1d< Handle<Givens> > givens_rots(n_krylov+1);
412  multi1d<DComplex> g(n_krylov+1);
413  multi2d<DComplex> Qk;
414  multi1d<DComplex> Qk_tau;
415 
416  // Assume zero initial guess
417  Double beta=sqrt(norm2(rhs, s));
418 
419  for(int j=0; j < g.size(); ++j) {
420  g[j] = DComplex(0);
421  }
422  g[0] = beta;
423  // Set up initial V[0] = rhs / || r^2 || --
424  Double beta_inv = Double(1)/beta;
425  V[0][s] = beta_inv * rhs;
426 
427  int dim;
428  sol.FlexibleArnoldi(n_krylov,
429  n_deflate,
430  rsd_target,
431  V,
432  Z,
433  H,
434  R,
435  givens_rots,
436  g,
437  Qk,
438  Qk_tau,
439  dim);
440 
441  ASSERT_LE(dim,n_krylov);
442 
443 
444 
445  // Instead of printing, Assert that Upper Hessenberg
446  for(int row=0; row < dim+1; ++row) {
447  // These are below the row below the diagonal -- should be 0
448  for(int col = 0; col < row-1; ++col) {
449  double re = toDouble( real( H(col,row) ) );
450  double im = toDouble( imag( H(col,row) ) );
451  EXPECT_DOUBLE_EQ( re, 0);
452  EXPECT_DOUBLE_EQ( im, 0);
453  }
454 
455  }
456 
457 
458 
459  // Now the various V's should be orthonormal. Check this.
460  for(int j=0; j < dim+1; ++j) {
461  EXPECT_DOUBLE_EQ( toDouble(sqrt(norm2(V[j],s))), 1.0);
462  }
463 
464  for(int j=0; j < dim+1; ++j) {
465  for(int i=j+1; i < dim+1; ++i) {
466  ASSERT_NEAR( 0, toDouble(norm2(innerProduct(V[i],V[j],s))),1.0e-16);
467  }
468  }
469 
470  multi1d< Handle<Givens> > GivensRots(dim+1);
471 
472  multi1d< DComplex > resvec(dim+1);
473  for(int row=0; row < dim+1; ++row) {
474  resvec[row] = DComplex(0);
475  }
476  resvec[0] = beta;
477 
478  // For each column
479  for(int j=0; j < dim; ++j) {
480 
481  // For column 0 this would apply 0 rotations
482  // For column 1 this would apply that of column 0 etc.
483  // For column 2 this would apply that of col 0 & 1
484  for(int i=0; i < j; ++i) {
485  (*GivensRots[i])(j, H);
486  }
487  // Make a givens rotation for my column
488  GivensRots[j] = new Givens(j, H);
489  (*GivensRots[j])(j,H);
490  (*GivensRots[j])(resvec); // Apply also to g
491  }
492 
493  // At this point H should be Upper Triangular
494  for(int row=1; row < dim+1; ++row) {
495  for(int col=0; col < row; ++col) {
496  EXPECT_DOUBLE_EQ( 0, toDouble(real(H(col,row))));
497  EXPECT_DOUBLE_EQ( 0, toDouble(imag(H(col,row))));
498  }
499  }
500 
501 #if 0
502  // R is not computed anymore
503  // The transformed H should agree with R
504  for(int row=0; row < dim+1; ++row) {
505  for(int col=row; col < dim; ++col) {
506  EXPECT_DOUBLE_EQ( toDouble(real(R(col,row))), toDouble(real(H(col,row))));
507  EXPECT_DOUBLE_EQ( toDouble(imag(R(col,row))), toDouble(imag(H(col,row))));
508  }
509  }
510 #endif
511 
512  // The resvec we generated should agree with what
513  for(int col=0; col < dim+1; ++col) {
514  QDPIO::cout << "col = " << col << " g=" <<g[col] << " resvec" << resvec[col] << std::endl;
515  EXPECT_DOUBLE_EQ(toDouble( real(g[col]) ), toDouble( real(resvec[col])) );
516  EXPECT_DOUBLE_EQ(toDouble( imag(g[col]) ), toDouble( imag(resvec[col])) );
517 
518  }
519 
520 
521 }
522 
523 
524 
525 
526 
527 TEST_F(FGMRESDRTests, testLeastSquares)
528 {
529  std::istringstream input(xml_for_param);
530  XMLReader xml_in(input);
531  SysSolverFGMRESDRParams p( xml_in, "/Params/InvertParam" );
532  LinOpSysSolverFGMRESDR sol(linop,state,p);
533 
534  int n_rows=4;
535  int n_cols=3;
536 
537  multi2d<DComplex> R(n_cols,n_rows);
538  multi1d<DComplex> b(n_rows);
539  multi1d<DComplex> x(n_rows);
540  for(int row=0; row < n_rows; ++row) {
541  for(int col=0; col < n_cols; ++col) {
542  R(col,row)=DComplex(0);
543  }
544  random(b[row]);
545  x[row] = zero;
546  }
547 
548  // Fill upper triangular with Random junk
549  for(int row=0; row < n_rows-1; ++row) {
550  for(int col=row; col < n_cols; ++col) {
551  random(R(col,row));
552  }
553  }
554 
555  sol.LeastSquaresSolve(R,b,x,n_cols);
556 
557 
558  for(int row=0; row < n_cols; ++row) {
559  DComplex prod=DComplex(0);
560  for(int col=row; col < n_cols; ++col) {
561  prod += R(col,row)*x[col];
562  }
563  EXPECT_DOUBLE_EQ( toDouble(real(prod)), toDouble(real(b[row])));
564  EXPECT_DOUBLE_EQ( toDouble(imag(prod)), toDouble(imag(b[row])));
565  }
566 }
567 
568 
569 TEST_P(FGMRESDRTestsFloatParams, testFullSolverNoDeflate)
570 {
571  std::istringstream input(xml_for_param);
572  XMLReader xml_in(input);
573  SysSolverFGMRESDRParams p( xml_in, "/Params/InvertParam" );
574  p.NDefl = 0;
575  // Reset target residuum as per input
576  float rsd_target_in = GetParam();
577  p.RsdTarget = Real(rsd_target_in);
578 
579  // Construct the solver
580  LinOpSysSolverFGMRESDR sol(linop,state,p);
581 
582  // Grab the subset
583  const Subset& s = linop->subset();
584 
585  // Gaussian RHS
586  LatticeFermion rhs;
587  gaussian(rhs,s);
588 
589  // zero initial guess
590  LatticeFermion x = zero;
591 
592  // Solve system
593  (sol)(x,rhs);
594 
595  // Compute residuum
596 
597  LatticeFermion r= zero;
598  (*linop)(r,x,PLUS); // r = Ax
599  r[s]-=rhs; // r = Ax - b = -(b-Ax);
600 
601  Double resid_rel = sqrt( norm2(r,s)/norm2(rhs,s) ); // sqrt( || r ||^2/||b||^2 )
602  ASSERT_LE( toDouble(resid_rel), toDouble(p.RsdTarget) );
603 
604 }
605 
606 
607 TEST_P(FGMRESDRTestsFloatParams, testFullSolverDeflate)
608 {
609  std::istringstream input(xml_for_param);
610  XMLReader xml_in(input);
611  SysSolverFGMRESDRParams p( xml_in, "/Params/InvertParam" );
612  p.NDefl = 3;
613  p.NKrylov = 6;
614  // Reset target residuum as per input
615  float rsd_target_in = GetParam();
616  p.RsdTarget = Real(rsd_target_in);
617 
618  // Construct the solver
619  LinOpSysSolverFGMRESDR sol(linop,state,p);
620 
621  // Grab the subset
622  const Subset& s = linop->subset();
623 
624  // Gaussian RHS
625  LatticeFermion rhs;
626  gaussian(rhs,s);
627 
628  // zero initial guess
629  LatticeFermion x = zero;
630 
631  // Solve system
632  (sol)(x,rhs);
633 
634  // Compute residuum
635 
636  LatticeFermion r= zero;
637  (*linop)(r,x,PLUS); // r = Ax
638  r[s]-=rhs; // r = Ax - b = -(b-Ax);
639 
640  Double resid_rel = sqrt( norm2(r,s)/norm2(rhs,s) ); // sqrt( || r ||^2/||b||^2 )
641  ASSERT_LE( toDouble(resid_rel), toDouble(p.RsdTarget) );
642 
643 }
644 
645 
646 
647 
650  testing::Values(1.0e-3,1.0e-9));
651 
652 
653 TEST_F(FGMRESDRTests, testQDPLapackZGETRFZGETRS)
654 {
655  std::istringstream input(xml_for_param);
656  XMLReader xml_in(input);
657  SysSolverFGMRESDRParams p( xml_in, "/Params/InvertParam" );
658  LinOpSysSolverFGMRESDR sol(linop,state,p);
659 
660 
661  const Subset& s = sol.subset();
662 
663 
664  // Create a gaussian source
665  LatticeFermion rhs;
666  gaussian(rhs, s);
667 
668  Real rsd_target(1.0e-9);
669  rsd_target *= sqrt(norm2(rhs,s));
670 
671  int n_krylov=5;
672  int n_deflate=0;
673 
674  // Work spaces
675  multi2d<DComplex> H(n_krylov,n_krylov+1); // The H matrix
676  multi2d<DComplex> R(n_krylov,n_krylov+1); // R = H diagonalized with Givens rotations
677  for(int row = 0; row < n_krylov+1; ++row) {
678  for(int col = 0; col < n_krylov; ++col) {
679  H(col,row) = DComplex(0);
680  R(col,row) = DComplex(0);
681  }
682  }
683  multi1d<T> V(n_krylov+1); // K(A)
684  multi1d<T> Z(n_krylov+1); // K(MA)
685  multi1d< Handle<Givens> > givens_rots(n_krylov+1);
686  multi1d<DComplex> g(n_krylov+1);
687  multi2d<DComplex> Qk;
688  multi1d<DComplex> Qk_tau;
689  // Assume zero initial guess
690  Double beta=sqrt(norm2(rhs, s));
691 
692  for(int j=0; j < g.size(); ++j) {
693  g[j] = DComplex(0);
694  }
695  g[0] = beta;
696  // Set up initial V[0] = rhs / || r^2 || --
697  Double beta_inv = Double(1)/beta;
698  V[0][s] = beta_inv * rhs;
699 
700  int dim;
701  sol.FlexibleArnoldi(n_krylov,
702  n_deflate,
703  rsd_target,
704  V,
705  Z,
706  H,
707  R,
708  givens_rots,
709  g,
710  Qk,
711  Qk_tau,
712  dim);
713 
714  // NOw want to solve System H^\dagger f_m = h_m
715  multi1d<DComplex> f_m(n_krylov);
716  multi1d<DComplex> h_m(n_krylov);
717  multi2d<DComplex> h1(n_krylov, n_krylov);
718 
719  // h1 is the copy I will pass to LAPACK
720  // I actually want to solve with the dagger of H
721  // so I should transpose as well as conjugate
722  // however LAPACK expects Fortran order: rows run fastest, columns slower
723  // multi2d has Fortran like indexing (row first, column second)
724  // but underneath the hood, columns still run fastest.
725  // So in principle we need to transpose in and out of Fortran
726  // however as I want to solve with the Transpose conjugate
727  // all I have to do is leave the indices untransposed, and just conjugate
728  for(int col=0; col < n_krylov; ++col) {
729  for(int row =0; row < n_krylov; ++row) {
730  h1(col,row) = H(col,row);
731  }
732  }
733 
734  for(int col=0; col < n_krylov; ++col) {
735  h_m[col] = conj(H(col, n_krylov)); // Keeping this for checking
736  f_m[col] = h_m[col]; // Solution will overwrite f_m
737  }
738 
739  multi1d<int> ipiv(n_krylov);
740  int info;
741 
742  // Factor H
743  QDPIO::cout << "CALLING ZGETRF to factor H" << std::endl;
744  QDPLapack::zgetrf(n_krylov,n_krylov,h1,n_krylov,ipiv,info);
745  ASSERT_EQ(info,0);
746 
747  // Now solve using ZGETRS
748  QDPIO::cout << "CALLING ZGETRS to solve for f" << std::endl;
749  char trans='C'; // Decompose the Hermitian Conjugate
750 
751  QDPLapack::zgetrs(trans, n_krylov,1,h1,n_krylov,ipiv,f_m,n_krylov,info);
752  ASSERT_EQ(info,0);
753 
754  // Check Solution
755  multi1d<DComplex> diff(n_krylov);
756 
757  for(int row=0; row < n_krylov; ++row) {
758  diff[row] = zero;
759  }
760 
761  // Check by multiplying back with H^H
762  trans='C'; // Hermitian conjugate H, Leading Dimension of H is n_krylov+1
763  // since now we are storing column major order. (Rows run fastest)
764  QDPLapack::zgemv(trans,n_krylov, n_krylov, H, n_krylov+1, f_m, diff);
765  for(int row=0; row < n_krylov; ++row) {
766  diff[row] -= h_m[row];
767  EXPECT_LT( toDouble(real(diff[row])), 1.0e-14 );
768  EXPECT_LT( toDouble(imag(diff[row])), 1.0e-14 );
769  }
770 
771  for(int row=0; row < n_krylov;++row) {
772  QDPIO::cout << "diff["<<row<<"] = " << diff[row] << std::endl;
773  }
774 
775  // Now form Hm + f_m h_m^H
776  // We will send this to Fortran, and we don't want to transpose
777  // or conjugate. So just transpose indices on H_tilde now, to ensure
778  // correct column major order for Fortran
779  multi2d<DComplex> H_tilde(n_krylov,n_krylov);
780  for(int row=0; row < n_krylov;++row) {
781  for(int col=0; col< n_krylov; ++col) {
782  H_tilde(col,row) = H(col,row) + f_m[row]*conj(h_m[col]);
783  }
784  }
785 
786  // Space for eigenvectors and eivenvalues
787  multi1d<DComplex> evals(n_krylov); // Evalues come back in this
788  multi2d<DComplex> evecs(n_krylov, n_krylov); // Evecs come back in this in Fortran order
789 
790  QDPIO::cout << "CALLING ZGEEV" << std::endl;
791  QDPLapack::zgeev(n_krylov, H_tilde, evals, evecs);
792  QDPIO::cout << "Checking evecs" << std::endl;
793 
794  // Recreate H_tilde as the evec routine overwrites it
795  for(int row=0; row < n_krylov;++row) {
796  for(int col=0; col< n_krylov; ++col) {
797  H_tilde(col,row) = H(col,row) + f_m[row]*conj(h_m[col]);
798  }
799  }
800 
801  // For each evec check H_tilde v - lambda v is small
802  //
803  for(int evec=0; evec < n_krylov; ++evec) {
804 
805  // Extract evec from 'evecs'
806  multi1d<DComplex> my_evec(n_krylov);
807  for(int row=0; row<n_krylov; ++row) {
808  my_evec[row] = evecs(evec,row);
809  }
810 
811  // Multiply: H_tilde my_evec -> diff
812  trans='N';
813  QDPLapack::zgemv(trans, n_krylov, n_krylov, H_tilde, n_krylov, my_evec, diff);
814 
815  // Subtract lambda my_evec
816  for(int row=0; row < n_krylov; ++row) {
817  diff[row] -= evals[evec]*evecs(evec,row);
818 
819  // check result is small
820  EXPECT_LT( toDouble(real(diff[row])), 1.0e-14 );
821  EXPECT_LT( toDouble(imag(diff[row])), 1.0e-14 );
822 
823  QDPIO::cout << "eigenvec: " << evec << " diff[" << row <<"]=" << diff[row] << " lambda=" << evals[evec] << std::endl;
824  }
825  }
826 }
827 
828 TEST_F(FGMRESDRTests, testGetEigenvector)
829 {
830  std::istringstream input(xml_for_param);
831  XMLReader xml_in(input);
832  SysSolverFGMRESDRParams p( xml_in, "/Params/InvertParam" );
833  LinOpSysSolverFGMRESDR sol(linop,state,p);
834 
835 
836  const Subset& s = sol.subset();
837 
838 
839  // Create a gaussian source
840  LatticeFermion rhs;
841  gaussian(rhs, s);
842 
843  Real rsd_target(1.0e-9);
844  rsd_target *= sqrt(norm2(rhs,s));
845 
846  int n_krylov=5;
847  int n_deflate=0;
848 
849  // Work spaces
850  multi2d<DComplex> H(n_krylov,n_krylov+1); // The H matrix
851  multi2d<DComplex> R(n_krylov,n_krylov+1); // R = H diagonalized with Givens rotations
852  for(int row = 0; row < n_krylov+1; ++row) {
853  for(int col = 0; col < n_krylov; ++col) {
854  H(col,row) = DComplex(0);
855  R(col,row) = DComplex(0);
856  }
857  }
858  multi1d<T> V(n_krylov+1); // K(A)
859  multi1d<T> Z(n_krylov+1); // K(MA)
860  multi1d< Handle<Givens> > givens_rots(n_krylov+1);
861  multi1d<DComplex> g(n_krylov+1);
862  multi2d<DComplex> Qk;
863  multi1d<DComplex> Qk_tau;
864  // Assume zero initial guess
865  Double beta=sqrt(norm2(rhs, s));
866 
867  for(int j=0; j < g.size(); ++j) {
868  g[j] = DComplex(0);
869  }
870  g[0] = beta;
871  // Set up initial V[0] = rhs / || r^2 || --
872  Double beta_inv = Double(1)/beta;
873  V[0][s] = beta_inv * rhs;
874 
875  int dim;
876  sol.FlexibleArnoldi(n_krylov,
877  n_deflate,
878  rsd_target,
879  V,
880  Z,
881  H,
882  R,
883  givens_rots,
884  g,
885  Qk,
886  Qk_tau,
887  dim);
888 
889  // NOw want to solve System H^\dagger f_m = h_m
890  multi1d<DComplex> f_m(n_krylov);
891  multi2d<DComplex> evecs(n_krylov,n_krylov);
892  multi1d<DComplex> evals(n_krylov);
893  multi1d<int> order_array(n_krylov);
894 
895  sol.GetEigenvectors(n_krylov,
896  H,
897  f_m,
898  evecs,
899  evals,
900  order_array);
901 
902  // Check that the order array is correct:
903  DComplex prev_eval=evals[order_array[0]];
904  QDPIO::cout << "evals[0] = " << prev_eval << " || evals[0] || = " << norm2(prev_eval) << std::endl;
905  for(int i=1; i < n_krylov; i++) {
906  DComplex curr_eval=evals[order_array[i]];
907  QDPIO::cout << "evals["<<i<<"] = " << curr_eval << " ||evals["<<i<<"] || = " << norm2(curr_eval) <<std::endl;
908 
909  ASSERT_LE( toDouble(norm2(prev_eval)), toDouble(norm2(curr_eval)));
910  prev_eval = curr_eval;
911  }
912 
913  // Check the eigenvalue stuff
914  multi1d<DComplex> h_m(n_krylov);
915 
916  // h1 is the copy I will pass to LAPACK
917  // I actually want to solve with the dagger of H
918  // so I should transpose as well as conjugate
919  // however LAPACK expects Fortran order: rows run fastest, columns slower
920  // multi2d has Fortran like indexing (row first, column second)
921  // but underneath the hood, columns still run fastest.
922  // So in principle we need to transpose in and out of Fortran
923  // however as I want to solve with the Transpose conjugate
924  // all I have to do is leave the indices untransposed, and just conjugate
925  for(int col=0; col < n_krylov; ++col) {
926  h_m[col] = conj(H(col, n_krylov)); // Keeping this for checking
927  }
928  // Now form Hm + f_m h_m^H
929  // We will send this to Fortran, and we don't want to transpose
930  // or conjugate. So just transpose indices on H_tilde now, to ensure
931  // correct column major order for Fortran
932  multi2d<DComplex> H_tilde(n_krylov,n_krylov);
933  for(int row=0; row < n_krylov;++row) {
934  for(int col=0; col< n_krylov; ++col) {
935  H_tilde(col,row) = H(col,row) + f_m[row]*conj(h_m[col]);
936  }
937  }
938 
939  // For each evec check H_tilde v - lambda v is small
940  multi1d<DComplex> diff(n_krylov);
941  for(int evec=0; evec < n_krylov; ++evec) {
942 
943  // Extract evec from 'evecs'
944  multi1d<DComplex> my_evec(n_krylov);
945  for(int row=0; row<n_krylov; ++row) {
946  my_evec[row] = evecs(evec,row);
947  }
948 
949  // Multiply: H_tilde my_evec -> diff
950  char trans='N';
951  QDPLapack::zgemv(trans, n_krylov, n_krylov, H_tilde, n_krylov, my_evec, diff);
952 
953  // Subtract lambda my_evec
954  for(int row=0; row < n_krylov; ++row) {
955  diff[row] -= evals[evec]*evecs(evec,row);
956 
957  // check result is small
958  EXPECT_LT( toDouble(real(diff[row])), 1.0e-14 );
959  EXPECT_LT( toDouble(imag(diff[row])), 1.0e-14 );
960 
961  QDPIO::cout << "eigenvec: " << evec << " diff[" << row <<"]=" << diff[row] << " lambda=" << evals[evec] << std::endl;
962  }
963  }
964 }
965 
966 
968 {
969  std::istringstream input(xml_for_param);
970  XMLReader xml_in(input);
971  SysSolverFGMRESDRParams p( xml_in, "/Params/InvertParam" );
972  LinOpSysSolverFGMRESDR sol(linop,state,p);
973 
974 
975  const Subset& s = sol.subset();
976 
977 
978  // Create a gaussian source
979  LatticeFermion rhs;
980  gaussian(rhs, s);
981 
982  Real rsd_target(1.0e-9);
983  rsd_target *= sqrt(norm2(rhs,s));
984 
985  int n_krylov=p.NKrylov;
986  int n_deflate=p.NDefl;
987  int total_dim = n_krylov+n_deflate;
988 
989  // Work spaces
990  multi2d<DComplex> H(total_dim, total_dim + 1); // The H matrix
991  multi2d<DComplex> R(total_dim, total_dim + 1); // R = H diagonalized with Givens rotations
992 
993  for(int col = 0; col < total_dim; ++col) {
994  for(int row = 0; row < total_dim+1; ++row) {
995  H(col,row) = DComplex(0);
996  R(col,row) = DComplex(0);
997  }
998  }
999 
1000  multi1d<T> V(total_dim+1); // K(A)
1001  multi1d<T> Z(total_dim+1); // K(MA)
1002  multi1d< Handle<Givens> > givens_rots(total_dim+1);
1003  multi1d<DComplex> g(total_dim + 1);
1004  multi1d<DComplex> c(total_dim + 1);
1005  multi2d<DComplex> Qk;
1006  multi1d<DComplex> Qk_tau;
1007  // Assume zero initial guess
1008  Double beta=sqrt(norm2(rhs, s));
1009 
1010  for(int j=0; j < g.size(); ++j) {
1011  g[j] = DComplex(0);
1012  c[j] = DComplex(0);
1013  }
1014  g[0] = beta;
1015  c[0] = beta;
1016 
1017  // Set up initial V[0] = rhs / || r^2 || --
1018  Double beta_inv = Double(1)/beta;
1019  V[0][s] = beta_inv * rhs;
1020 
1021  int dim;
1022  sol.FlexibleArnoldi(n_krylov,
1023  0, // Guaranteed no deflation
1024  rsd_target,
1025  V,
1026  Z,
1027  H,
1028  R,
1029  givens_rots,
1030  g,
1031  Qk,
1032  Qk_tau,
1033  dim);
1034 
1035 
1036  multi1d<DComplex> eta(n_krylov);
1037  sol.LeastSquaresSolve(R,g,eta,dim); // Now we can form c - H \eta
1038 
1039 
1040  // NOw want to solve System H^\dagger f_m = h_m
1041  multi1d<DComplex> f_m(n_krylov);
1042  multi2d<DComplex> evecs(n_krylov,n_krylov);
1043  multi1d<DComplex> evals(n_krylov);
1044  multi1d<int> order_array(n_krylov);
1045 
1046  // Get the EVs
1047  sol.GetEigenvectors(n_krylov,
1048  H,
1049  f_m,
1050  evecs,
1051  evals,
1052  order_array);
1053 
1054 
1055 
1056  // This is where we will store G_{k} = [ g_1 | .. | g_k ]
1057  //
1058  // G_{k+1} = [ G_k c - H \eta ]
1059  // [ 0 ]
1060  QDPIO::cout << "Setting up G_k and G_{k+1}" << std::endl << std::flush;
1061  multi2d<DComplex> Qkplus1(n_deflate+1, n_krylov+1);
1062 
1063  // First copy in the eigenvectors
1064  for(int col=0; col < n_deflate; ++col) {
1065  for(int row=0; row < n_krylov; ++row) {
1066  // Copy in the ones corresponding to the lowest k
1067  // eigenvectors
1068  Qkplus1(col,row) = evecs( order_array[col], row);
1069  }
1070  Qkplus1(col,n_krylov) = zero;
1071  }
1072 
1073  for(int row=0; row < n_krylov+1; ++row) {
1074  Qkplus1(n_deflate,row) = c[row];
1075  for(int col=0; col < n_krylov; ++col) {
1076  Qkplus1(n_deflate,row) -= H(col,row)*eta(col);
1077  }
1078  }
1079 
1080  // NB: Lapack will overwrite both G_{k} and G_{k+1} with the factorizations.
1081 
1082  // QR reflection coefficients.
1083  multi1d<DComplex> tau_kplus1;
1084  QDPIO::cout << "QR Decomposing Gk+1" << std::endl;
1085  QDPLapack::zgeqrf(n_krylov+1, n_deflate+1, Qkplus1, tau_kplus1);
1086 
1087  // Now I want to compute H^{pr}_m Q_k
1088  // I can do this using ZUNMQR but it will overwrite the 'H' I use,
1089  // which at this point is OK in the algorithm, however, here, I will make a copy.
1090  // to check my tests.
1091 
1092  multi2d<DComplex> H_copy(n_krylov, n_krylov+1);
1093  multi2d<DComplex> H_copy2(n_krylov, n_krylov+1);
1094  for(int col=0; col < n_krylov; ++col) {
1095  for(int row=0; row < n_krylov+1; ++row) {
1096  H_copy(col,row) = H(col,row);
1097  H_copy2(col,row) = H(col,row);
1098  }
1099  }
1100 
1101  // Now the total dim here is actually n_krylov the other data in H is invalid
1102  // So first lets Hit H_copy1 from the right with Q_k from G_k
1103  char side='R';
1104  char trans='N';
1105  QDPIO::cout << "Post multiplying with Q_k using ZUNMQR 1" << std::endl;
1106 
1107  // Here, M and N are the dimensions of the final storage. and 'K' is the order of the decomposition,
1108  // E.g. to right Multiply by Q I can just set it to n_deflate rather than n_deflate+1
1109 
1110  // !!!! NB: The dimensions here are still the original dimensions of H_copy2,
1111  // !!!! even tho at the end of this result only the (rows=n_krylov+1)x(cols=n_deflate) portion is
1112  // !!!! valid
1113  QDPLapack::zunmqr2(side,trans, n_krylov+1, n_krylov, n_deflate, Qkplus1, tau_kplus1, H_copy);
1114 
1115 
1116  QDPIO::cout << "Pre multiply with Q^{H}_{k+1} usign ZUNMQR2" << std::endl;
1117  trans='C'; // Multiply with Herm Conjugate
1118  side='L'; // Multiply from Left
1119 
1120  // !!!! NB: The dimensions here are still the original dimensions of H_copy2
1121  // !!!! Even tho when we are done here, really only the (rows=k+1)x(cols=k) portion of it
1122  // !!!! is what is relevant
1123  QDPLapack::zunmqr2(side,trans, n_krylov+1, n_krylov, n_deflate+1, Qkplus1, tau_kplus1, H_copy);
1124 
1125  // Now we should check this. One way is by explicitly forming Q_plus_1 -- I need this
1126  // anyhow for transforming the V's and the Z's.
1127 
1128  // Recover Q_plus1 -- this reconstructs it explicitly. We will need Qkplus1
1129  // and Qk to reconstruct V_{k+1} and Z_{k}
1130  QDPLapack::zungqr(n_krylov+1,n_deflate+1,n_deflate+1, Qkplus1, tau_kplus1);
1131 
1132 
1133  // NOw try and form H_k Q_k using ZGEMM
1134  //
1135  // H_k has n_krylov+1 rows, and n_krylov columns
1136  // Q_k has n_krylov rows, and n_deflate columns
1137  //
1138  // so H_k Q_k has n_krylov+1 rows and n_deflate columns
1139  multi2d<DComplex> HKQK(n_deflate, n_krylov+1);
1140 
1141  char transa = 'N';
1142  char transb = 'N';
1143  DComplex calpha(1);
1144  DComplex cbeta = zero;
1145  int m = n_krylov+1;
1146  int k = n_krylov;
1147  int n = n_deflate;
1148 
1149  // This will evaluate: H_m Q_k
1150  // by beating it into the form alpha * H_m * Q_k + 0 * H_copy1 => H_copy1
1151  // NB: I don't form Q_k, but just use Q_{k+1}, and take care of the fact
1152  // that it is bigger than I want by using the leading dimension of Q
1153  // and by setting the m,n,k dimensions appropriately.
1154  QDPLapack::zgemm(transa, transb,
1155  m,n,k,
1156  calpha,
1157  H_copy2,
1158  m,
1159  Qkplus1,
1160  m, // The leading dimension of Qkplus1 is n_krylov+1 i.e. 'm' even if we multiply only with the kxn portion
1161  cbeta,
1162  HKQK,
1163  m);
1164 
1165  multi2d<DComplex> QK1HKQK(n_deflate, n_deflate+1);
1166 
1167  transa = 'C';
1168  transb = 'N';
1169 
1170  m = n_deflate+1; // rows of Q_{k+1}^H
1171  k = n_krylov+1; // cols of Q_{k+1}^H
1172  n = n_deflate; // cols of Q^{H}_{k+1} H_{k} Q_{k}
1173 
1174  // This will evaluate: H_m Q_k
1175  // by beating it into the form alpha * H_m * Q_k + 0 * H_copy1 => H_copy1
1176  // NB: I don't form Q_k, but just use Q_{k+1}, and take care of the fact
1177  // that it is bigger than I want by using the leading dimension of Q
1178  // and by setting the m,n,k dimensions appropriately.
1179  QDPLapack::zgemm(transa, transb,
1180  m,n,k,
1181  calpha,
1182  Qkplus1,
1183  k,
1184  HKQK,
1185  k, // The leading dimension of Qkplus1 is n_krylov+1 i.e. 'm' even if we multiply only with the kxn portion
1186  cbeta,
1187  QK1HKQK,
1188  m);
1189 
1190  QDPIO::cout << "QK1HKQK - H_copy" << std::endl;
1191 
1192  for(int row = 0; row < n_deflate+1; ++row) {
1193  for(int col=0; col < n_deflate; ++col) {
1194  QK1HKQK(col,row) -= H_copy(col,row);
1195  QDPIO::cout << QK1HKQK(col,row) << "\t" ;
1196  EXPECT_LT( toDouble(sqrt(norm2(QK1HKQK(col,row)))), 1.0e-15 );
1197  }
1198  QDPIO::cout << std::endl;
1199  }
1200 
1201  // OK Now I need to form: V_{k+1} = V^{pr}_{m+1} Q_{k+1}
1202  multi1d<LatticeFermion> new_V(n_deflate+1);
1203  for(int i=0; i < n_deflate+1; ++i) {
1204  new_V[i] = zero;
1205  for(int j=0; j < n_krylov+1; ++j) {
1206  new_V[i] += V[j]*Qkplus1(i,j);
1207  }
1208  }
1209 
1210  // Check Columns are Orthonormal
1211  for(int i=0; i < n_deflate+1; ++i) {
1212  for(int j=0; j < n_deflate+1; ++j ) {
1213  DComplex iprod = innerProduct(new_V[i], new_V[j], s);
1214  QDPIO::cout << "< V[" << i <<"],V["<<j<<"] > = " << iprod ;
1215 
1216  if ( i==j ) {
1217  // iprod should be 1
1218  Double diff_r = Double(1) - sqrt(real(iprod));
1219  Double diff_i = fabs(imag(iprod));
1220  QDPIO::cout << " ABS DIFF=" << fabs(diff_r) << " ABS DIFF IM=" << diff_i << std::endl;
1221  EXPECT_LT( toDouble(diff_r), 1.0e-11);
1222  EXPECT_LT( toDouble(diff_i), 1.0e-12);
1223 
1224  }
1225  else {
1226  Double diff_r = fabs(real(iprod));
1227  Double diff_i = fabs(imag(iprod));
1228  QDPIO::cout << " ABS DIFF RE=" << diff_r << " ABS DIFF IM=" << diff_i << std::endl;
1229  EXPECT_LT( toDouble(diff_r), 1.0e-9);
1230  EXPECT_LT( toDouble(diff_i), 1.0e-9);
1231  }
1232  }
1233  }
1234 
1235  //
1236  multi1d<LatticeFermion> new_Z(n_deflate);
1237  for(int i=0; i < n_deflate; ++i) {
1238  new_Z[i] = zero;
1239  for(int j=0; j < n_krylov; ++j) {
1240  new_Z[i] += Z[j]*Qkplus1(i,j);
1241  }
1242  }
1243 
1244 
1245 
1246 }
Primary include file for CHROMA library code.
Base class for quadratic matter actions (e.g., fermions)
Definition: fermact.h:176
Class for counted reference semantics.
Definition: handle.h:33
Solve a M*psi=chi linear system by FGMRESDR.
const Subset & subset() const
Return the subset on which the operator acts.
void LeastSquaresSolve(const multi2d< DComplex > &R, const multi1d< DComplex > &rhs, multi1d< DComplex > &eta, int dim) const
void FlexibleArnoldi(int n_krylov, int n_deflate, const Real &rsd_target, multi1d< T > &V, multi1d< T > &Z, multi2d< DComplex > &H, multi2d< DComplex > &R, multi1d< Handle< Givens > > &givens_rots, multi1d< DComplex > &g, multi2d< DComplex > &Qk, multi1d< DComplex > &Qk_tau, int &ndim_cycle) const
void GetEigenvectors(int total_dim, const multi2d< DComplex > &H, multi1d< DComplex > &f_m, multi2d< DComplex > &evecs, multi1d< DComplex > &evals, multi1d< int > &order_array) const
static T & Instance()
Definition: singleton.h:432
Handle< FermAct4D< T, P, Q > > S_f
multi1d< LatticeColorMatrix > P
Handle< FermState< T, P, Q > > state
LatticeFermion T
multi1d< LatticeColorMatrix > Q
multi1d< LatticeColorMatrix > u
Handle< LinearOperator< T > > linop
virtual ~FGMRESDRTests()
int mu
Definition: cool.cc:24
Fermion action factories.
INSTANTIATE_TEST_CASE_P(FGMRESDRTests, FGMRESDRTestsFloatParams, testing::Values(1.0e-3, 1.0e-9))
const std::string xml_for_param
TEST_P(FGMRESDRTestsFloatParams, arnoldi5GivensRot)
TEST_F(FGMRESDRTests, canConstructDefault)
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:19781
#define EXPECT_DOUBLE_EQ(expected, actual)
Definition: gtest.h:19856
#define ASSERT_NEAR(val1, val2, abs_error)
Definition: gtest.h:19872
#define ASSERT_LE(val1, val2)
Definition: gtest.h:19789
#define EXPECT_LT(val1, val2)
Definition: gtest.h:19755
unsigned j
Definition: ldumul_w.cc:35
unsigned n
Definition: ldumul_w.cc:36
static int m[4]
Definition: make_seeds.cc:16
int x
Definition: meslate.cc:34
Nd
Definition: meslate.cc:74
BinaryReturn< C1, C2, FnInnerProduct >::Type_t innerProduct(const QDPSubType< T1, C1 > &s1, const QDPType< T2, C2 > &s2)
static const LatticeInteger & beta(const int dim)
Definition: stag_phases_s.h:47
multi1d< LatticeColorMatrix > G
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
gaussian(aux)
static multi1d< LatticeColorMatrix > u
Double c
Definition: invbicg.cc:108
int i
Definition: pbg5p_w.cc:55
@ PLUS
Definition: chromabase.h:45
void reunit(LatticeColorMatrixF3 &xa)
Definition: reunit.cc:467
LatticeFermion eta
Definition: mespbg5p_w.cc:37
Complex b
Definition: invbicg.cc:96
const WilsonTypeFermAct< multi1d< LatticeFermion > > Handle< const ConnectState > state
Definition: pbg5p_w.cc:28
static QOP_info_t info
const WilsonTypeFermAct< multi1d< LatticeFermion > > & S_f
Definition: pbg5p_w.cc:27
Double zero
Definition: invbicg.cc:106
int k
Definition: invbicg.cc:119
multi1d< LatticeFermion > s(Ncb)
FloatingPoint< double > Double
Definition: gtest.h:7351
::std::string string
Definition: gtest.h:1979
internal::ValueArray1< T1 > Values(T1 v1)
Definition: gtest.h:15914
Solve an FGMRESR-DR system.
Solve a M*psi=chi linear system by FGMRES_DR.