/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/algorithms/iterative/ConjugateGradientMultiShift.h Copyright (C) 2015 Author: Azusa Yamaguchi Author: Peter Boyle 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_CONJUGATE_MULTI_SHIFT_GRADIENT_H #define GRID_CONJUGATE_MULTI_SHIFT_GRADIENT_H namespace Grid { ///////////////////////////////////////////////////////////// // Base classes for iterative processes based on operators // single input vec, single output vec. ///////////////////////////////////////////////////////////// template class ConjugateGradientMultiShift : public OperatorMultiFunction, public OperatorFunction { public: RealD Tolerance; Integer MaxIterations; int verbose; MultiShiftFunction shifts; ConjugateGradientMultiShift(Integer maxit,MultiShiftFunction &_shifts) : MaxIterations(maxit), shifts(_shifts) { verbose=1; } void operator() (LinearOperatorBase &Linop, const Field &src, Field &psi) { GridBase *grid = src._grid; int nshift = shifts.order; std::vector results(nshift,grid); (*this)(Linop,src,results,psi); } void operator() (LinearOperatorBase &Linop, const Field &src, std::vector &results, Field &psi) { int nshift = shifts.order; (*this)(Linop,src,results); psi = shifts.norm*src; for(int i=0;i &Linop, const Field &src, std::vector &psi) { GridBase *grid = src._grid; //////////////////////////////////////////////////////////////////////// // Convenience references to the info stored in "MultiShiftFunction" //////////////////////////////////////////////////////////////////////// int nshift = shifts.order; std::vector &mass(shifts.poles); // Make references to array in "shifts" std::vector &mresidual(shifts.tolerances); std::vector alpha(nshift,1.0); std::vector ps(nshift,grid);// Search directions assert(psi.size()==nshift); assert(mass.size()==nshift); assert(mresidual.size()==nshift); // dynamic sized arrays on stack; 2d is a pain with vector RealD bs[nshift]; RealD rsq[nshift]; RealD z[nshift][2]; int converged[nshift]; const int primary =0; //Primary shift fields CG iteration RealD a,b,c,d; RealD cp,bp,qq; //prev // Matrix mult fields Field r(grid); Field p(grid); Field tmp(grid); Field mmp(grid); // Check lightest mass for(int s=0;s= mass[primary] ); converged[s]=0; } // Wire guess to zero // Residuals "r" are src // First search direction "p" is also src cp = norm2(src); for(int s=0;s 2+Ls, so ~ 3x saving // Pipelined CG gain: // // New Kernel: Load r, vector of coeffs, vector of pointers ps // New Kernel: Load psi[0], vector of coeffs, vector of pointers ps // If can predict the coefficient bs then we can fuse these and avoid write reread cyce // on ps[s]. // Before: 3 x npole + 3 x npole // After : 2 x npole (ps[s]) => 3x speed up of multishift CG. if( (!converged[s]) ) { axpy(psi[ss],-bs[s]*alpha[s],ps[s],psi[ss]); } } // Convergence checks int all_converged = 1; for(int s=0;s