/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/algorithms/iterative/LocalCoherenceLanczos.h Copyright (C) 2015 Author: Christoph Lehner Author: paboyle This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. See the full license in the file "LICENSE" in the top level distribution directory *************************************************************************************/ /* END LEGAL */ #ifndef GRID_LOCAL_COHERENCE_IRL_H #define GRID_LOCAL_COHERENCE_IRL_H NAMESPACE_BEGIN(Grid); struct LanczosParams : Serializable { public: GRID_SERIALIZABLE_CLASS_MEMBERS(LanczosParams, ChebyParams, Cheby,/*Chebyshev*/ int, Nstop, /*Vecs in Lanczos must converge Nstop < Nk < Nm*/ int, Nk, /*Vecs in Lanczos seek converge*/ int, Nm, /*Total vecs in Lanczos include restart*/ RealD, resid, /*residual*/ int, MaxIt, RealD, betastp, /* ? */ int, MinRes); // Must restart }; //This class is the input parameter class for some testing programs struct LocalCoherenceLanczosParams : Serializable { public: 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, blockSize, std::string, config, std::vector < ComplexD >, omega, RealD, mass, RealD, M5); }; // Duplicate functionality; ProjectedFunctionHermOp could be used with the trivial function template class ProjectedHermOp : public LinearFunction > > { public: using LinearFunction > >::operator(); typedef iVector CoarseSiteVector; typedef Lattice CoarseField; typedef Lattice CoarseScalar; // used for inner products on fine field typedef Lattice FineField; LinearOperatorBase &_Linop; std::vector &subspace; ProjectedHermOp(LinearOperatorBase& linop, std::vector & _subspace) : _Linop(linop), subspace(_subspace) { assert(subspace.size() >0); }; void operator()(const CoarseField& in, CoarseField& out) { GridBase *FineGrid = subspace[0].Grid(); int checkerboard = subspace[0].Checkerboard(); FineField fin (FineGrid); fin.Checkerboard()= checkerboard; FineField fout(FineGrid); fout.Checkerboard() = checkerboard; blockPromote(in,fin,subspace); std::cout< class ProjectedFunctionHermOp : public LinearFunction > > { public: using LinearFunction > >::operator(); typedef iVector CoarseSiteVector; typedef Lattice CoarseField; typedef Lattice CoarseScalar; // used for inner products on fine field typedef Lattice FineField; OperatorFunction & _poly; LinearOperatorBase &_Linop; std::vector &subspace; ProjectedFunctionHermOp(OperatorFunction & poly, LinearOperatorBase& linop, std::vector & _subspace) : _poly(poly), _Linop(linop), subspace(_subspace) { }; void operator()(const CoarseField& in, CoarseField& out) { GridBase *FineGrid = subspace[0].Grid(); int checkerboard = subspace[0].Checkerboard(); FineField fin (FineGrid); fin.Checkerboard() =checkerboard; FineField fout(FineGrid);fout.Checkerboard() =checkerboard; blockPromote(in,fin,subspace); std::cout< class ImplicitlyRestartedLanczosSmoothedTester : public ImplicitlyRestartedLanczosTester > > { public: typedef iVector CoarseSiteVector; typedef Lattice CoarseField; typedef Lattice CoarseScalar; // used for inner products on fine field typedef Lattice FineField; LinearFunction & _Poly; OperatorFunction & _smoother; LinearOperatorBase &_Linop; RealD _coarse_relax_tol; std::vector &_subspace; 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 //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 //To work around this issue, every restart we separately reconstruct the fine operator eval for the lowest and highest evec and print these //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) //NOTE: If largestEvalIdxForReport=-1 (default) then this is not performed ImplicitlyRestartedLanczosSmoothedTester(LinearFunction &Poly, OperatorFunction &smoother, LinearOperatorBase &Linop, std::vector &subspace, RealD coarse_relax_tol=5.0e3, int largestEvalIdxForReport=-1) : _smoother(smoother), _Linop(Linop), _Poly(Poly), _subspace(subspace), _coarse_relax_tol(coarse_relax_tol), _largestEvalIdxForReport(largestEvalIdxForReport) { }; //evalMaxApprox: approximation of largest eval of the fine Chebyshev operator (suitably wrapped by block projection) int TestConvergence(int j,RealD eresid,CoarseField &B, RealD &eval,RealD evalMaxApprox) { CoarseField v(B); RealD eval_poly = eval; // Apply operator _Poly(B,v); RealD vnum = real(innerProduct(B,v)); // HermOp. RealD vden = norm2(B); RealD vv0 = norm2(v); eval = vnum/vden; v -= eval*B; RealD vv = norm2(v) / ::pow(evalMaxApprox,2.0); std::cout.precision(13); std::cout< nbasis ) eresid = eresid*_coarse_relax_tol; std::cout.precision(13); std::cout< class LocalCoherenceLanczos { public: typedef iVector CoarseSiteVector; typedef Lattice CoarseScalar; // used for inner products on fine field typedef Lattice CoarseField; typedef Lattice FineField; protected: GridBase *_CoarseGrid; GridBase *_FineGrid; int _checkerboard; LinearOperatorBase & _FineOp; std::vector &evals_fine; std::vector &evals_coarse; std::vector &subspace; std::vector &evec_coarse; private: std::vector _evals_fine; std::vector _evals_coarse; std::vector _subspace; std::vector _evec_coarse; public: LocalCoherenceLanczos(GridBase *FineGrid, GridBase *CoarseGrid, LinearOperatorBase &FineOp, int checkerboard) : _CoarseGrid(CoarseGrid), _FineGrid(FineGrid), _FineOp(FineOp), _checkerboard(checkerboard), evals_fine (_evals_fine), evals_coarse(_evals_coarse), subspace (_subspace), evec_coarse(_evec_coarse) { evals_fine.resize(0); evals_coarse.resize(0); }; ////////////////////////////////////////////////////////////////////////// // Alternate constructore, external storage for use by Hadrons module ////////////////////////////////////////////////////////////////////////// LocalCoherenceLanczos(GridBase *FineGrid, GridBase *CoarseGrid, LinearOperatorBase &FineOp, int checkerboard, std::vector &ext_subspace, std::vector &ext_coarse, std::vector &ext_eval_fine, std::vector &ext_eval_coarse ) : _CoarseGrid(CoarseGrid), _FineGrid(FineGrid), _FineOp(FineOp), _checkerboard(checkerboard), evals_fine (ext_eval_fine), evals_coarse(ext_eval_coarse), subspace (ext_subspace), evec_coarse (ext_coarse) { evals_fine.resize(0); evals_coarse.resize(0); }; //The block inner product is the inner product on the fine grid locally summed over the blocks //to give a Lattice on the coarse grid. This function orthnormalizes the fine-grid subspace //vectors under the block inner product. This step must be performed after computing the fine grid //eigenvectors and before computing the coarse grid eigenvectors. void Orthogonalise(void ) { CoarseScalar InnerProd(_CoarseGrid); std::cout << GridLogMessage <<" Gramm-Schmidt pass 1"< static RealD normalise(T& v) { RealD nn = norm2(v); nn = ::sqrt(nn); v = v * (1.0/nn); return nn; } /* void fakeFine(void) { int Nk = nbasis; subspace.resize(Nk,_FineGrid); subspace[0]=1.0; subspace[0].Checkerboard()=_checkerboard; normalise(subspace[0]); PlainHermOp Op(_FineOp); for(int k=1;k Op(_FineOp); ImplicitlyRestartedLanczosHermOpTester SimpleTester(Op); for(int k=0;k ChebySmooth(cheby_smooth); ProjectedFunctionHermOp ChebyOp (ChebySmooth,_FineOp,subspace); ImplicitlyRestartedLanczosSmoothedTester ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,subspace,relax); for(int k=0;k Cheby(cheby_parms); FunctionHermOp ChebyOp(Cheby,_FineOp); PlainHermOp Op(_FineOp); evals_fine.resize(Nm); subspace.resize(Nm,_FineGrid); ImplicitlyRestartedLanczos IRL(ChebyOp,Op,Nstop,Nk,Nm,resid,MaxIt,betastp,MinRes); FineField src(_FineGrid); typedef typename FineField::scalar_type Scalar; // src=1.0; src=Scalar(1.0); src.Checkerboard() = _checkerboard; int Nconv; IRL.calc(evals_fine,subspace,src,Nconv,false); // Shrink down to number saved assert(Nstop>=nbasis); assert(Nconv>=nbasis); evals_fine.resize(nbasis); subspace.resize(nbasis,_FineGrid); } //cheby_op: Parameters of the fine grid Chebyshev polynomial used for the Lanczos acceleration //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 //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 void calcCoarse(ChebyParams cheby_op,ChebyParams cheby_smooth,RealD relax, int Nstop, int Nk, int Nm,RealD resid, RealD MaxIt, RealD betastp, int MinRes) { Chebyshev Cheby(cheby_op); //Chebyshev of fine operator on fine grid ProjectedHermOp Op(_FineOp,subspace); //Fine operator on coarse grid with intermediate fine grid conversion ProjectedFunctionHermOp ChebyOp (Cheby,_FineOp,subspace); //Chebyshev of fine operator on coarse grid with intermediate fine grid conversion ////////////////////////////////////////////////////////////////////////////////////////////////// // create a smoother and see if we can get a cheap convergence test and smooth inside the IRL ////////////////////////////////////////////////////////////////////////////////////////////////// Chebyshev ChebySmooth(cheby_smooth); //lower order Chebyshev of fine operator on fine grid used to smooth regenerated eigenvectors ImplicitlyRestartedLanczosSmoothedTester ChebySmoothTester(ChebyOp,ChebySmooth,_FineOp,subspace,relax,Nstop-1); evals_coarse.resize(Nm); evec_coarse.resize(Nm,_CoarseGrid); CoarseField src(_CoarseGrid); src=1.0; //Note the "tester" here is also responsible for generating the fine grid eigenvalues which are output into the "evals_coarse" array ImplicitlyRestartedLanczos IRL(ChebyOp,ChebyOp,ChebySmoothTester,Nstop,Nk,Nm,resid,MaxIt,betastp,MinRes); int Nconv=0; IRL.calc(evals_coarse,evec_coarse,src,Nconv,false); assert(Nconv>=Nstop); evals_coarse.resize(Nstop); evec_coarse.resize (Nstop,_CoarseGrid); for (int i=0;i