CHROMA
syssolver_linop_fgmres_dr.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /*! \file
3  * \brief Solve a M*psi=chi linear system by FGMRES_DR
4  */
5 
6 #ifndef __syssolver_linop_fgmres_dr_h__
7 #define __syssolver_linop_fgmres_dr_h__
8 
9 #include "chroma_config.h"
10 #include "handle.h"
11 #include "state.h"
12 #include "syssolver.h"
13 #include "linearop.h"
14 
15 #include "util/gauge/reunit.h"
19 
20 namespace Chroma
21 {
22 
23  //! FGMRESDR system solver namespace
24  namespace LinOpSysSolverFGMRESDREnv
25  {
26  //! Register the syssolver
27  bool registerAll();
28  }
29 
30 
31  class Givens {
32  public:
33 
34  // Givens rotation.
35  // There are a variety of ways to choose the rotations
36  // which can do the job. I employ the method given by Saad
37  // in Iterative Methods (Sec. 6.5.9 (eq. 6.80)
38  //
39  // [ conj(c) conj(s) ] [ h_jj ] = [ r ]
40  // [ -s c ] [ h_j+1,j ] [ 0 ]
41  //
42  // We know that h_j+1,j is a vector norm so imag(h_{j+1,j} = 0)
43  //
44  // we have: s = h_{j+1,j} / t
45  // c = h_jj / t
46  //
47  // t=sqrt( norm2(h_jj) + h_{j+1,j}^2 ) is real and nonnegative
48  //
49  // so in this case s, is REAL and nonnegative (since t is and h_{j+1,j} is
50  // but c is in general complex valued.
51  //
52  //
53  // using this we find r = conj(c) h_jj + conj(s) h_{j+1,j}
54  // = (1/t)* [ conj(h_jj)*h_jj + h_{j+1,j}*h_{j+1,h} ]
55  // = (1/t)* [ norm2(h_jj) + h_{j+1,j}^2 ]
56  // = (1/t)* [ t^2 ] = t
57  //
58  // Applying this to a general 2 vector
59  //
60  // [ conj(c) conj(s) ] [ a ] = [ r_1 ]
61  // [ -s c ] [ b ] [ r_2 ]
62  //
63  // we have r_1 = conj(c)*a + conj(s)*b = conj(c)*a + s*b since s is real, nonnegative
64  // and r_2 = -s*a + c*b
65  //
66  // NB: In this setup we choose the sine 's' to be real in the rotation.
67  // This is in contradistinction from LAPACK which typically chooses the cosine 'c' to be real
68  //
69  //
70  // There are some special cases:
71  // if h_jj and h_{j+1,j} are both zero we can choose any s and c as long as |c|^2 + |s|^2 =1
72  // Keeping with the notation that s is real and nonnegative we choose
73  // if h_jj != 0 and h_{j+1,h) == 0 => c = sgn(conj(h_jj)), s = 0, r = | h_jj |
74  // if h_jj == 0 and h_{j+1,j} == 0 => c = 0, s = 1, r = 0 = h_{j+1,j}
75  // if h_jj == 0 and h_{j+1,j} != 0 => c = 0, s = 1, r = h_{j+1,j} = h_{j+1,j}
76  // else the formulae we computed.
77 
78  /*! Given a marix H, construct the rotator so that H(row,col) = r and H(row+1,col) = 0
79  *
80  * \param col the column Input
81  * \param H the Matrix Input
82  */
83 
84  Givens(int col, const multi2d<DComplex>& H) : col_(col)
85  {
86  DComplex f = H(col_,col_);
87  DComplex g = H(col_,col_+1);
88 
89  if( toBool( real(f) == Double(0) && imag(f) == Double(0) ) ) {
90 
91  // h_jj is 0
92  c_ = DComplex(0);
93  s_ = DComplex(1);
94  r_ = g; // Handles the case when g is also zero
95  }
96  else {
97  if( toBool( real(g) == Double(0) && imag(g) == Double(0) ) ) {
98  s_ = DComplex(0);
99  c_ = conj(f)/sqrt( norm2(f) ); // sgn( conj(f) ) = conj(f) / | conj(f) | = conj(f) / | f |
100  r_ = DComplex( sqrt(norm2(f)) );
101  }
102  else {
103  // Revisit this with
104  Double t = sqrt( norm2(f) + norm2(g) );
105  r_ = t;
106  c_ = f/t;
107  s_ = g/t;
108  }
109  }
110  }
111 
112  /*! Apply the rotation to column col of the matrix H. The
113  * routine affects col and col+1.
114  *
115  * \param col the columm
116  * \param H the matrix
117  */
118 
119  void operator()(int col, multi2d<DComplex>& H) {
120  if ( col == col_ ) {
121  // We've already done this column and know the answer
122  H(col_,col_) = r_;
123  H(col_,col_+1) = 0;
124  }
125  else {
126  int row = col_; // The row on which the rotation was defined
127  DComplex a = H(col,row);
128  DComplex b = H(col,row+1);
129  H(col,row) = conj(c_)*a + conj(s_)*b;
130  H(col,row+1) = -s_*a + c_*b;
131  }
132  }
133 
134  /*! Apply rotation to Column Vector v */
135  void operator()(multi1d<DComplex>& v) {
136  DComplex a = v(col_);
137  DComplex b = v(col_+1);
138  v(col_) = conj(c_)*a + conj(s_)*b;
139  v(col_+1) = -s_*a + c_*b;
140 
141  }
142 
143  private:
144  int col_;
145  DComplex s_;
146  DComplex c_;
147  DComplex r_;
148  };
149 
150 
151  //! Solve a M*psi=chi linear system by FGMRESDR
152  /*! \ingroup invert
153  */
154 
155  class LinOpSysSolverFGMRESDR : public LinOpSystemSolver<LatticeFermion>
156  {
157  public:
158  using T = LatticeFermion;
159  using U = LatticeColorMatrix;
160  using Q = multi1d<U>;
161 
162  //! Constructor
163  /*!
164  * \param A_ Linear operator ( Read )
165  * \param invParam inverter parameters ( Read )
166  */
169  const SysSolverFGMRESDRParams& invParam) :
170  A_(A), state_(state), invParam_(invParam)
171  {
172 
173  // Use factory to construct preconditioner
174  // The preconditioner has to look like a system solver for now.
175  try {
176  std::istringstream precond_xml(invParam_.PrecondParams.xml );
177  XMLReader precond_xml_reader(precond_xml);
178 
180  }
181  catch(...) {
182  QDPIO::cout << "Unable to create Preconditioner" << std::endl;
183  QDP_abort(1);
184  }
185 
186 #ifndef BUILD_LAPACK
187  QDPIO::cout << "WARNING: LAPACK Is not built!!!" << std::endl;
188  QDPIO::cout << "WARNING: SUBSPACE Augmentation requires it!!!!" << std::endl;
189  QDPIO::cout << "WARNING: Using the solver with NDefl > 0 will fail!!! " << std::endl;
190  QDPIO::cout << "WARNING: Run this version with NDefl = 0 only!!!!" << std::endl;
191  QDPIO::cout << "WARNING: OR reconfigure with --enable-lapack=lapack" << std::endl;
192 
193  if( invParam_.NDefl > 0 ) {
194  QDPIO::cout << " invParam.NDefl > 0: This mode is not supported without LAPACK" <<std::endl;
195  QDP_abort(1);
196  }
197 #endif
198 
199 
200  // Initialize stuff
201  InitMatrices();
202 
203 
204  }
205 
206 
207  //! Initialize the internal matrices
208  void InitMatrices();
209 
210 
211  //! Destructor is automatic
213 
214  //! Return the subset on which the operator acts
215  const Subset& subset() const {return A_->subset();}
216 
217  //! Solver the linear system
218  /*!
219  * \param psi solution ( Modify )
220  * \param chi source ( Read )
221  * \return syssolver results
222  */
223  SystemSolverResults_t operator() (T& psi, const T& chi) const;
224 
225 
226  void FlexibleArnoldi(int n_krylov,
227  int n_deflate,
228  const Real& rsd_target,
229  multi1d<T>& V,
230  multi1d<T>& Z,
231  multi2d<DComplex>& H,
232  multi2d<DComplex>& R,
233  multi1d< Handle<Givens> >& givens_rots,
234  multi1d<DComplex>& g,
235  multi2d<DComplex>& Qk,
236  multi1d<DComplex>& Qk_tau,
237  int& ndim_cycle) const;
238 
239  void LeastSquaresSolve(const multi2d<DComplex>& R,
240  const multi1d<DComplex>& rhs,
241  multi1d<DComplex>& eta,
242  int dim) const;
243 
244  void GetEigenvectors(int total_dim,
245  const multi2d<DComplex>& H,
246  multi1d<DComplex>& f_m,
247  multi2d<DComplex>& evecs,
248  multi1d<DComplex>& evals,
249  multi1d<int>& order_array) const;
250 
251  private:
252  // Hide default constructor
258 
259  // These can become state variables, as they will need to be
260  // handed around
261  mutable multi2d<DComplex> H_; // The H matrix
262  mutable multi2d<DComplex> R_; // R = H diagonalized with Givens rotations
263  mutable multi1d<T> V_; // K(A)
264  mutable multi1d<T> Z_; // K(MA)
265  mutable multi1d< Handle<Givens> > givens_rots_;
266 
267  // This is the c = V^H_{k+1} r vector (c is frommers Notation)
268  // For regular FGMRES I need to keep only the basis transformed
269  // version of it, for rotating by the Q's (I call this 'g')
270  // However, for FGMRES-DR I need this because I need
271  // || c - H eta || to extend the G_k matrix to form V_{k+1}
272  // it is made of the previous v_{k+1} by explicitly evaluating c
273  // except at the end of the first cycle when the V_{k+1} are not
274  // yet available
275 
276  // Once G_k+1 is available, I can form the QR decomposition
277  // and set my little g = Q^H and then as I do the Arnoldi
278  // I can then work it with the Givens rotations...
279 
280  mutable multi1d<DComplex> c_;
281  mutable multi1d<DComplex> eta_;
282  mutable multi1d<DComplex> g_;
283  mutable multi2d<DComplex> Hk_QR_;
284  mutable multi1d<DComplex> Hk_QR_taus_;
285 
286 
287  };
288 
289 } // End namespace
290 
291 #endif
292 
Support class for fermion actions and linear operators.
Definition: state.h:94
void operator()(multi1d< DComplex > &v)
Givens(int col, const multi2d< DComplex > &H)
void operator()(int col, multi2d< DComplex > &H)
Class for counted reference semantics.
Definition: handle.h:33
Solve a M*psi=chi linear system by FGMRESDR.
Handle< FermState< T, Q, Q > > state_
const Subset & subset() const
Return the subset on which the operator acts.
LinOpSysSolverFGMRESDR(Handle< LinearOperator< T > > A, Handle< FermState< T, Q, Q > > state, const SysSolverFGMRESDRParams &invParam)
Constructor.
void LeastSquaresSolve(const multi2d< DComplex > &R, const multi1d< DComplex > &rhs, multi1d< DComplex > &eta, int dim) const
multi1d< Handle< Givens > > givens_rots_
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
Handle< LinOpSystemSolver< T > > preconditioner_
void GetEigenvectors(int total_dim, const multi2d< DComplex > &H, multi1d< DComplex > &f_m, multi2d< DComplex > &evecs, multi1d< DComplex > &evals, multi1d< int > &order_array) const
SystemSolverResults_t operator()(T &psi, const T &chi) const
Solver the linear system.
~LinOpSysSolverFGMRESDR()
Destructor is automatic.
Handle< LinearOperator< T > > A_
void InitMatrices()
Initialize the internal matrices.
SystemSolver disambiguator.
Linear Operator.
Definition: linearop.h:27
static T & Instance()
Definition: singleton.h:432
Class for counted reference semantics.
Linear Operators.
int t
Definition: meslate.cc:37
bool registerAll()
Register all the factories.
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
LinOpSysSolverMGProtoClover::T T
multi1d< LatticeFermion > chi(Ncb)
Complex a
Definition: invbicg.cc:95
LatticeFermion psi
Definition: mespbg5p_w.cc:35
LatticeFermion eta
Definition: mespbg5p_w.cc:37
A(A, psi, r, Ncb, PLUS)
Complex b
Definition: invbicg.cc:96
const WilsonTypeFermAct< multi1d< LatticeFermion > > Handle< const ConnectState > state
Definition: pbg5p_w.cc:28
FloatingPoint< double > Double
Definition: gtest.h:7351
Reunitarize in place a color matrix to SU(N)
Support class for fermion actions and linear operators.
Holds return info from SystemSolver call.
Definition: syssolver.h:17
Linear system solvers.
Solve an FGMRESR-DR system.
Disambiguator for LinOp system solvers.
Factory for solving M*psi=chi where M is not hermitian or pos. def.