Grid 0.7.0
LocalCoherenceLanczos.h
Go to the documentation of this file.
1/*************************************************************************************
2
3 Grid physics library, www.github.com/paboyle/Grid
4
5 Source file: ./lib/algorithms/iterative/LocalCoherenceLanczos.h
6
7 Copyright (C) 2015
8
9Author: Christoph Lehner <clehner@bnl.gov>
10Author: paboyle <paboyle@ph.ed.ac.uk>
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License along
23 with this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25
26 See the full license in the file "LICENSE" in the top level distribution directory
27*************************************************************************************/
28/* END LEGAL */
29#ifndef GRID_LOCAL_COHERENCE_IRL_H
30#define GRID_LOCAL_COHERENCE_IRL_H
31
33
34struct LanczosParams : Serializable {
35public:
37 ChebyParams, Cheby,/*Chebyshev*/
38 int, Nstop, /*Vecs in Lanczos must converge Nstop < Nk < Nm*/
39 int, Nk, /*Vecs in Lanczos seek converge*/
40 int, Nm, /*Total vecs in Lanczos include restart*/
41 RealD, resid, /*residual*/
42 int, MaxIt,
43 RealD, betastp, /* ? */
44 int, MinRes); // Must restart
45};
46
47//This class is the input parameter class for some testing programs
48struct LocalCoherenceLanczosParams : Serializable {
49public:
51 bool, saveEvecs,
52 bool, doFine,
53 bool, doFineRead,
54 bool, doCoarse,
55 bool, doCoarseRead,
56 LanczosParams, FineParams,
57 LanczosParams, CoarseParams,
58 ChebyParams, Smoother,
59 RealD , coarse_relax_tol,
60 std::vector<int>, blockSize,
61 std::string, config,
62 std::vector < ComplexD >, omega,
63 RealD, mass,
64 RealD, M5);
65};
66
67// Duplicate functionality; ProjectedFunctionHermOp could be used with the trivial function
68template<class Fobj,class CComplex,int nbasis>
69class ProjectedHermOp : public LinearFunction<Lattice<iVector<CComplex,nbasis > > > {
70public:
74 typedef Lattice<CComplex> CoarseScalar; // used for inner products on fine field
76
78 std::vector<FineField> &subspace;
79
80 ProjectedHermOp(LinearOperatorBase<FineField>& linop, std::vector<FineField> & _subspace) :
81 _Linop(linop), subspace(_subspace)
82 {
83 assert(subspace.size() >0);
84 };
85
86 void operator()(const CoarseField& in, CoarseField& out) {
87 GridBase *FineGrid = subspace[0].Grid();
88 int checkerboard = subspace[0].Checkerboard();
89
90 FineField fin (FineGrid); fin.Checkerboard()= checkerboard;
91 FineField fout(FineGrid); fout.Checkerboard() = checkerboard;
92
93 blockPromote(in,fin,subspace); std::cout<<GridLogIRL<<"ProjectedHermop : Promote to fine"<<std::endl;
94 _Linop.HermOp(fin,fout); std::cout<<GridLogIRL<<"ProjectedHermop : HermOp (fine) "<<std::endl;
95 blockProject(out,fout,subspace); std::cout<<GridLogIRL<<"ProjectedHermop : Project to coarse "<<std::endl;
96 }
97};
98
99template<class Fobj,class CComplex,int nbasis>
100class ProjectedFunctionHermOp : public LinearFunction<Lattice<iVector<CComplex,nbasis > > > {
101public:
105 typedef Lattice<CComplex> CoarseScalar; // used for inner products on fine field
107
108
111 std::vector<FineField> &subspace;
112
115 std::vector<FineField> & _subspace) :
116 _poly(poly),
117 _Linop(linop),
118 subspace(_subspace)
119 { };
120
121 void operator()(const CoarseField& in, CoarseField& out) {
122
123 GridBase *FineGrid = subspace[0].Grid();
124 int checkerboard = subspace[0].Checkerboard();
125
126 FineField fin (FineGrid); fin.Checkerboard() =checkerboard;
127 FineField fout(FineGrid);fout.Checkerboard() =checkerboard;
128
129 blockPromote(in,fin,subspace); std::cout<<GridLogIRL<<"ProjectedFunctionHermop : Promote to fine"<<std::endl;
130 _poly(_Linop,fin,fout); std::cout<<GridLogIRL<<"ProjectedFunctionHermop : Poly "<<std::endl;
131 blockProject(out,fout,subspace); std::cout<<GridLogIRL<<"ProjectedFunctionHermop : Project to coarse "<<std::endl;
132 }
133};
134
135template<class Fobj,class CComplex,int nbasis>
136class ImplicitlyRestartedLanczosSmoothedTester : public ImplicitlyRestartedLanczosTester<Lattice<iVector<CComplex,nbasis > > >
137{
138public:
141 typedef Lattice<CComplex> CoarseScalar; // used for inner products on fine field
143
148 std::vector<FineField> &_subspace;
149
150 int _largestEvalIdxForReport; //The convergence of the LCL is based on the evals of the coarse grid operator, not those of the underlying fine grid operator
151 //As a result we do not know what the eval range of the fine operator is until the very end, making tuning the Cheby bounds very difficult
152 //To work around this issue, every restart we separately reconstruct the fine operator eval for the lowest and highest evec and print these
153 //out alongside the evals of the coarse operator. To do so we need to know the index of the largest eval (i.e. Nstop-1)
154 //NOTE: If largestEvalIdxForReport=-1 (default) then this is not performed
155
159 std::vector<FineField> &subspace,
160 RealD coarse_relax_tol=5.0e3,
161 int largestEvalIdxForReport=-1)
162 : _smoother(smoother), _Linop(Linop), _Poly(Poly), _subspace(subspace),
163 _coarse_relax_tol(coarse_relax_tol), _largestEvalIdxForReport(largestEvalIdxForReport)
164 { };
165
166 //evalMaxApprox: approximation of largest eval of the fine Chebyshev operator (suitably wrapped by block projection)
167 int TestConvergence(int j,RealD eresid,CoarseField &B, RealD &eval,RealD evalMaxApprox)
168 {
169 CoarseField v(B);
170 RealD eval_poly = eval;
171
172 // Apply operator
173 _Poly(B,v);
174
175 RealD vnum = real(innerProduct(B,v)); // HermOp.
176 RealD vden = norm2(B);
177 RealD vv0 = norm2(v);
178 eval = vnum/vden;
179 v -= eval*B;
180
181 RealD vv = norm2(v) / ::pow(evalMaxApprox,2.0);
182
183 std::cout.precision(13);
184 std::cout<<GridLogIRL << "[" << std::setw(3)<<j<<"] "
185 <<"eval = "<<std::setw(25)<< eval << " (" << eval_poly << ")"
186 <<" |H B[i] - eval[i]B[i]|^2 / evalMaxApprox^2 " << std::setw(25) << vv
187 <<std::endl;
188
189 if(_largestEvalIdxForReport != -1 && (j==0 || j==_largestEvalIdxForReport)){
190 std::cout<<GridLogIRL << "Estimating true eval of fine grid operator for eval idx " << j << std::endl;
191 RealD tmp_eval;
192 ReconstructEval(j,eresid,B,tmp_eval,1.0); //don't use evalMaxApprox of coarse operator! (cf below)
193 }
194
195 int conv=0;
196 if( (vv<eresid*eresid) ) conv = 1;
197 return conv;
198 }
199
200 //This function is called at the end of the coarse grid Lanczos. It promotes the coarse eigenvector 'B' to the fine grid,
201 //applies a smoother to the result then computes the computes the *fine grid* eigenvalue (output as 'eval').
202
203 //evalMaxApprox should be the approximation of the largest eval of the fine Hermop. However when this function is called by IRL it actually passes the largest eval of the *Chebyshev* operator (as this is the max approx used for the TestConvergence above)
204 //As the largest eval of the Chebyshev is typically several orders of magnitude larger this makes the convergence test pass even when it should not.
205 //We therefore ignore evalMaxApprox here and use a value of 1.0 (note this value is already used by TestCoarse)
206 int ReconstructEval(int j,RealD eresid,CoarseField &B, RealD &eval,RealD evalMaxApprox)
207 {
208 evalMaxApprox = 1.0; //cf above
209 GridBase *FineGrid = _subspace[0].Grid();
210 int checkerboard = _subspace[0].Checkerboard();
211 FineField fB(FineGrid);fB.Checkerboard() =checkerboard;
212 FineField fv(FineGrid);fv.Checkerboard() =checkerboard;
213
215
216 _smoother(_Linop,fv,fB);
217
218 RealD eval_poly = eval;
219 _Linop.HermOp(fB,fv);
220
221 RealD vnum = real(innerProduct(fB,fv)); // HermOp.
222 RealD vden = norm2(fB);
223 RealD vv0 = norm2(fv);
224 eval = vnum/vden;
225 fv -= eval*fB;
226 RealD vv = norm2(fv) / ::pow(evalMaxApprox,2.0);
227 if ( j > nbasis ) eresid = eresid*_coarse_relax_tol;
228
229 std::cout.precision(13);
230 std::cout<<GridLogIRL << "[" << std::setw(3)<<j<<"] "
231 <<"eval = "<<std::setw(25)<< eval << " (" << eval_poly << ")"
232 <<" |H B[i] - eval[i]B[i]|^2 / evalMaxApprox^2 " << std::setw(25) << vv << " target " << eresid*eresid
233 <<std::endl;
234 if( (vv<eresid*eresid) ) return 1;
235 return 0;
236 }
237};
238
240// Make serializable Lanczos params
242template<class Fobj,class CComplex,int nbasis>
244{
245public:
247 typedef Lattice<CComplex> CoarseScalar; // used for inner products on fine field
250
251protected:
256
257 std::vector<RealD> &evals_fine;
258 std::vector<RealD> &evals_coarse;
259 std::vector<FineField> &subspace;
260 std::vector<CoarseField> &evec_coarse;
261
262private:
263 std::vector<RealD> _evals_fine;
264 std::vector<RealD> _evals_coarse;
265 std::vector<FineField> _subspace;
266 std::vector<CoarseField> _evec_coarse;
267
268public:
269
271 GridBase *CoarseGrid,
273 int checkerboard) :
274 _CoarseGrid(CoarseGrid),
275 _FineGrid(FineGrid),
276 _FineOp(FineOp),
277 _checkerboard(checkerboard),
282 {
283 evals_fine.resize(0);
284 evals_coarse.resize(0);
285 };
286
287 // Alternate constructore, external storage for use by Hadrons module
290 GridBase *CoarseGrid,
292 int checkerboard,
293 std::vector<FineField> &ext_subspace,
294 std::vector<CoarseField> &ext_coarse,
295 std::vector<RealD> &ext_eval_fine,
296 std::vector<RealD> &ext_eval_coarse
297 ) :
298 _CoarseGrid(CoarseGrid),
299 _FineGrid(FineGrid),
300 _FineOp(FineOp),
301 _checkerboard(checkerboard),
302 evals_fine (ext_eval_fine),
303 evals_coarse(ext_eval_coarse),
304 subspace (ext_subspace),
305 evec_coarse (ext_coarse)
306 {
307 evals_fine.resize(0);
308 evals_coarse.resize(0);
309 };
310
311 //The block inner product is the inner product on the fine grid locally summed over the blocks
312 //to give a Lattice<Scalar> on the coarse grid. This function orthnormalizes the fine-grid subspace
313 //vectors under the block inner product. This step must be performed after computing the fine grid
314 //eigenvectors and before computing the coarse grid eigenvectors.
315 void Orthogonalise(void ) {
316 CoarseScalar InnerProd(_CoarseGrid);
317 std::cout << GridLogMessage <<" Gramm-Schmidt pass 1"<<std::endl;
318 blockOrthogonalise(InnerProd,subspace);
319 std::cout << GridLogMessage <<" Gramm-Schmidt pass 2"<<std::endl;
320 blockOrthogonalise(InnerProd,subspace);
321 };
322
323 template<typename T> static RealD normalise(T& v)
324 {
325 RealD nn = norm2(v);
326 nn = ::sqrt(nn);
327 v = v * (1.0/nn);
328 return nn;
329 }
330 /*
331 void fakeFine(void)
332 {
333 int Nk = nbasis;
334 subspace.resize(Nk,_FineGrid);
335 subspace[0]=1.0;
336 subspace[0].Checkerboard()=_checkerboard;
337 normalise(subspace[0]);
338 PlainHermOp<FineField> Op(_FineOp);
339 for(int k=1;k<Nk;k++){
340 subspace[k].Checkerboard()=_checkerboard;
341 Op(subspace[k-1],subspace[k]);
342 normalise(subspace[k]);
343 }
344 }
345 */
346
347 void testFine(RealD resid)
348 {
349 assert(evals_fine.size() == nbasis);
350 assert(subspace.size() == nbasis);
353 for(int k=0;k<nbasis;k++){
354 assert(SimpleTester.ReconstructEval(k,resid,subspace[k],evals_fine[k],1.0)==1);
355 }
356 }
357
358 //While this method serves to check the coarse eigenvectors, it also recomputes the eigenvalues from the smoothed reconstructed eigenvectors
359 //hence the smoother can be tuned after running the coarse Lanczos by using a different smoother here
360 void testCoarse(RealD resid,ChebyParams cheby_smooth,RealD relax)
361 {
362 assert(evals_fine.size() == nbasis);
363 assert(subspace.size() == nbasis);
365 // create a smoother and see if we can get a cheap convergence test and smooth inside the IRL
367 Chebyshev<FineField> ChebySmooth(cheby_smooth);
369 ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,subspace,relax);
370
371 for(int k=0;k<evec_coarse.size();k++){
372 if ( k < nbasis ) {
373 assert(ChebySmoothTester.ReconstructEval(k,resid,evec_coarse[k],evals_coarse[k],1.0)==1);
374 } else {
375 assert(ChebySmoothTester.ReconstructEval(k,resid*relax,evec_coarse[k],evals_coarse[k],1.0)==1);
376 }
377 }
378 }
379
380 void calcFine(ChebyParams cheby_parms,int Nstop,int Nk,int Nm,RealD resid,
381 RealD MaxIt, RealD betastp, int MinRes)
382 {
383 assert(nbasis<=Nm);
384 Chebyshev<FineField> Cheby(cheby_parms);
385 FunctionHermOp<FineField> ChebyOp(Cheby,_FineOp);
387
388 evals_fine.resize(Nm);
389 subspace.resize(Nm,_FineGrid);
390
391 ImplicitlyRestartedLanczos<FineField> IRL(ChebyOp,Op,Nstop,Nk,Nm,resid,MaxIt,betastp,MinRes);
392
393 FineField src(_FineGrid);
394 typedef typename FineField::scalar_type Scalar;
395 // src=1.0;
396 src=Scalar(1.0);
398
399 int Nconv;
400 IRL.calc(evals_fine,subspace,src,Nconv,false);
401
402 // Shrink down to number saved
403 assert(Nstop>=nbasis);
404 assert(Nconv>=nbasis);
405 evals_fine.resize(nbasis);
406 subspace.resize(nbasis,_FineGrid);
407 }
408
409
410 //cheby_op: Parameters of the fine grid Chebyshev polynomial used for the Lanczos acceleration
411 //cheby_smooth: Parameters of a separate Chebyshev polynomial used after the Lanczos has completed to smooth out high frequency noise in the reconstructed fine grid eigenvectors prior to computing the eigenvalue
412 //relax: Reconstructed eigenvectors (post smoothing) are naturally not as precise as true eigenvectors. This factor acts as a multiplier on the stopping condition when determining whether the results satisfy the user provided stopping condition
413 void calcCoarse(ChebyParams cheby_op,ChebyParams cheby_smooth,RealD relax,
414 int Nstop, int Nk, int Nm,RealD resid,
415 RealD MaxIt, RealD betastp, int MinRes)
416 {
417 Chebyshev<FineField> Cheby(cheby_op); //Chebyshev of fine operator on fine grid
418 ProjectedHermOp<Fobj,CComplex,nbasis> Op(_FineOp,subspace); //Fine operator on coarse grid with intermediate fine grid conversion
419 ProjectedFunctionHermOp<Fobj,CComplex,nbasis> ChebyOp (Cheby,_FineOp,subspace); //Chebyshev of fine operator on coarse grid with intermediate fine grid conversion
421 // create a smoother and see if we can get a cheap convergence test and smooth inside the IRL
423
424 Chebyshev<FineField> ChebySmooth(cheby_smooth); //lower order Chebyshev of fine operator on fine grid used to smooth regenerated eigenvectors
425 ImplicitlyRestartedLanczosSmoothedTester<Fobj,CComplex,nbasis> ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,subspace,relax,Nstop-1);
426
427 evals_coarse.resize(Nm);
428 evec_coarse.resize(Nm,_CoarseGrid);
429
430 CoarseField src(_CoarseGrid); src=1.0;
431
432 //Note the "tester" here is also responsible for generating the fine grid eigenvalues which are output into the "evals_coarse" array
433 ImplicitlyRestartedLanczos<CoarseField> IRL(ChebyOp,ChebyOp,ChebySmoothTester,Nstop,Nk,Nm,resid,MaxIt,betastp,MinRes);
434 int Nconv=0;
435 IRL.calc(evals_coarse,evec_coarse,src,Nconv,false);
436 assert(Nconv>=Nstop);
437 evals_coarse.resize(Nstop);
438 evec_coarse.resize (Nstop,_CoarseGrid);
439 for (int i=0;i<Nstop;i++){
440 std::cout << i << " Coarse eval = " << evals_coarse[i] << std::endl;
441 }
442 }
443
444 //Get the fine eigenvector 'i' by reconstruction
445 void getFineEvecEval(FineField &evec, RealD &eval, const int i) const{
447 eval = evals_coarse[i];
448 }
449
450
451};
452
454#endif
accelerator_inline Grid_simd< S, V > sqrt(const Grid_simd< S, V > &r)
B
accelerator_inline sobj eval(const uint64_t ss, const sobj &arg)
Definition Lattice_ET.h:103
Lattice< vobj > real(const Lattice< vobj > &lhs)
ComplexD innerProduct(const Lattice< vobj > &left, const Lattice< vobj > &right)
RealD norm2(const Lattice< vobj > &arg)
void blockOrthogonalise(Lattice< CComplex > &ip, std::vector< Lattice< vobj > > &Basis)
void blockPromote(const Lattice< iVector< CComplex, nbasis > > &coarseData, Lattice< vobj > &fineData, const VLattice &Basis)
void blockProject(Lattice< iVector< CComplex, nbasis > > &coarseData, const Lattice< vobj > &fineData, const VLattice &Basis)
Lattice< obj > pow(const Lattice< obj > &rhs_i, RealD y)
GridLogger GridLogIRL(1, "IRL", GridLogColours, "NORMAL")
GridLogger GridLogMessage(1, "Message", GridLogColours, "NORMAL")
#define NAMESPACE_BEGIN(A)
Definition Namespace.h:35
#define NAMESPACE_END(A)
Definition Namespace.h:36
double RealD
Definition Simd.h:61
int ReconstructEval(int j, RealD resid, Field &B, RealD &eval, RealD evalMaxApprox)
int TestConvergence(int j, RealD eresid, CoarseField &B, RealD &eval, RealD evalMaxApprox)
OperatorFunction< FineField > & _smoother
LinearOperatorBase< FineField > & _Linop
int ReconstructEval(int j, RealD eresid, CoarseField &B, RealD &eval, RealD evalMaxApprox)
ImplicitlyRestartedLanczosSmoothedTester(LinearFunction< CoarseField > &Poly, OperatorFunction< FineField > &smoother, LinearOperatorBase< FineField > &Linop, std::vector< FineField > &subspace, RealD coarse_relax_tol=5.0e3, int largestEvalIdxForReport=-1)
void calc(std::vector< RealD > &eval, std::vector< Field > &evec, const Field &src, int &Nconv, bool reverse=false)
accelerator_inline int Checkerboard(void) const
Fobj::scalar_type scalar_type
iVector< CComplex, nbasis > CoarseSiteVector
std::vector< CoarseField > _evec_coarse
void calcCoarse(ChebyParams cheby_op, ChebyParams cheby_smooth, RealD relax, int Nstop, int Nk, int Nm, RealD resid, RealD MaxIt, RealD betastp, int MinRes)
std::vector< FineField > & subspace
std::vector< RealD > _evals_fine
LinearOperatorBase< FineField > & _FineOp
std::vector< CoarseField > & evec_coarse
void calcFine(ChebyParams cheby_parms, int Nstop, int Nk, int Nm, RealD resid, RealD MaxIt, RealD betastp, int MinRes)
Lattice< CoarseSiteVector > CoarseField
LocalCoherenceLanczos(GridBase *FineGrid, GridBase *CoarseGrid, LinearOperatorBase< FineField > &FineOp, int checkerboard, std::vector< FineField > &ext_subspace, std::vector< CoarseField > &ext_coarse, std::vector< RealD > &ext_eval_fine, std::vector< RealD > &ext_eval_coarse)
void testCoarse(RealD resid, ChebyParams cheby_smooth, RealD relax)
Lattice< CComplex > CoarseScalar
std::vector< RealD > _evals_coarse
std::vector< FineField > _subspace
LocalCoherenceLanczos(GridBase *FineGrid, GridBase *CoarseGrid, LinearOperatorBase< FineField > &FineOp, int checkerboard)
std::vector< RealD > & evals_coarse
void getFineEvecEval(FineField &evec, RealD &eval, const int i) const
std::vector< RealD > & evals_fine
ProjectedFunctionHermOp(OperatorFunction< FineField > &poly, LinearOperatorBase< FineField > &linop, std::vector< FineField > &_subspace)
std::vector< FineField > & subspace
void operator()(const CoarseField &in, CoarseField &out)
LinearOperatorBase< FineField > & _Linop
OperatorFunction< FineField > & _poly
Lattice< CComplex > CoarseScalar
iVector< CComplex, nbasis > CoarseSiteVector
Lattice< CoarseSiteVector > CoarseField
void operator()(const CoarseField &in, CoarseField &out)
ProjectedHermOp(LinearOperatorBase< FineField > &linop, std::vector< FineField > &_subspace)
Lattice< CoarseSiteVector > CoarseField
LinearOperatorBase< FineField > & _Linop
Lattice< Fobj > FineField
iVector< CComplex, nbasis > CoarseSiteVector
std::vector< FineField > & subspace
Lattice< CComplex > CoarseScalar
GRID_SERIALIZABLE_CLASS_MEMBERS(LanczosParams, ChebyParams, Cheby, int, Nstop, int, Nk, int, Nm, RealD, resid, int, MaxIt, RealD, betastp, int, MinRes)
GRID_SERIALIZABLE_CLASS_MEMBERS(LocalCoherenceLanczosParams, bool, saveEvecs, bool, doFine, bool, doFineRead, bool, doCoarse, bool, doCoarseRead, LanczosParams, FineParams, LanczosParams, CoarseParams, ChebyParams, Smoother, RealD, coarse_relax_tol, std::vector< int >, blockSize, std::string, config, std::vector< ComplexD >, omega, RealD, mass, RealD, M5)