diff --git a/Grid/algorithms/iterative/PrecGeneralisedConjugateResidualNonHermitian.h b/Grid/algorithms/iterative/PrecGeneralisedConjugateResidualNonHermitian.h index 21ac66b9..7bac5667 100644 --- a/Grid/algorithms/iterative/PrecGeneralisedConjugateResidualNonHermitian.h +++ b/Grid/algorithms/iterative/PrecGeneralisedConjugateResidualNonHermitian.h @@ -60,18 +60,29 @@ public: void Level(int lv) { level=lv; }; - PrecGeneralisedConjugateResidualNonHermitian(RealD tol,Integer maxit,LinearOperatorBase &_Linop,LinearFunction &Prec,int _mmax,int _nstep) : + PrecGeneralisedConjugateResidualNonHermitian(RealD tol,Integer maxit,LinearOperatorBase &_Linop,LinearFunction &Prec,int _mmax, int _nstep) : Tolerance(tol), MaxIterations(maxit), Linop(_Linop), Preconditioner(Prec), mmax(_mmax), - nstep(_nstep) + nstep(_nstep) // what is nstep vs mmax? one is the number of inner iterations { level=1; verbose=1; }; + // virtual method stubs for updating GCR polynomial + virtual void LogBegin(void){ + std::cout << "GCR::LogBegin() "< betas){ + std::cout << "GCR::LogIteration() "<& alphas, std::vector>& betas) { + std::cout << "GCR::LogComplete() "< q(mmax,grid); - std::vector p(mmax,grid); - std::vector qq(mmax); + std::vector q(mmax,grid); // q = Ap + std::vector p(mmax,grid); // store mmax conjugate momenta + std::vector qq(mmax); // qq = (Ap)^2 = (denom of \alpha) GCRLogLevel<< "PGCR nStep("<LogBegin(); // initialize polynomial GCR if needed (TODO think about placement of this) ///////////////////// // p = Prec(r) @@ -178,32 +190,45 @@ public: p[0]= z; q[0]= Az; qq[0]= zAAz; + + std::cout << "||init p - src||: " << norm2(p[0] - src) << std::endl; // for debugging cp =norm2(r); LinalgTimer.Stop(); + std::vector all_alphas; + std::vector> all_betas; + for(int k=0;k(mmax-1))?(mmax-1):(kp); // if more than mmax done, we orthog all mmax history. + // std::cout << "northog: " << northog << std::endl; + std::vector betas (northog); + // std::cout << "peri_kp: " << peri_kp << std::endl; + // we iterate backwards counting down from the current k+1 index (peri_kp) because we for(int back=0;back=0); + int peri_back=(k-back)%mmax; assert((k-back)>=0); + // std::cout << "peri_back: " << peri_back << std::endl; - b=-real(innerProduct(q[peri_back],Az))/qq[peri_back]; - p[peri_kp]=p[peri_kp]+b*p[peri_back]; - q[peri_kp]=q[peri_kp]+b*q[peri_back]; + // b=-real(innerProduct(q[peri_back],Az))/qq[peri_back]; + b=-(innerProduct(q[peri_back],Az))/qq[peri_back]; // TODO try complex beta + p[peri_kp]=p[peri_kp]+b*p[peri_back]; + q[peri_kp]=q[peri_kp]+b*q[peri_back]; + + // LogIterationB(peri_back, b); + // betas[back] = b; // may need to change the indexing if I ever do it with restarts + // std::cout << "[DEBUG] pushing beta for back = " << back << ", peri_back = " << peri_back << std::endl; + + betas[peri_back] = b; // may need to change the indexing if I ever do it with restarts } qq[peri_kp]=norm2(q[peri_kp]); // could use axpy_norm LinalgTimer.Stop(); + + // log iteration and update GCR polynomial if necessary. + all_betas.push_back(betas); + LogIteration(k + 1, a, betas); + + // finish if necessary + if((k==nstep-1)||(cp>>, data, + std::vector>>, betas, + std::vector>, alphas + ); +}; + +// Optionally record the GCR polynomial. [PO]: TODO +template +class PGCRPolynomial : public PrecGeneralisedConjugateResidualNonHermitian { +public: + std::vector ak; + std::vector> bk; + // std::vector poly_p; + std::vector> poly_p; + std::vector poly_Ap; // polynomial in Ap_j (only store it for last p) + std::vector poly_r; + std::vector polynomial; + + PolynomialFile& PF; + +public: + PGCRPolynomial(RealD tol, Integer maxit,LinearOperatorBase &_Linop, LinearFunction &Prec, int _mmax, int _nstep, PolynomialFile& _PF) + : PrecGeneralisedConjugateResidualNonHermitian(tol, maxit, _Linop, Prec, _mmax, _nstep), PF(_PF) + {}; + + // think this applies the polynomial in A = Linop to a field src. The coeffs are + // stored in the vector `polynomial`. + void PolyOp(const Field &src, Field &psi) + { + Field tmp(src.Grid()); + Field AtoN(src.Grid()); + AtoN = src; + psi=AtoN*polynomial[0]; + for(int n=1;nLinop.Op(tmp,AtoN); // iterate A^n + psi = psi + polynomial[n]*AtoN; // psi += poly_n A^n src + } + } + + // [PO TODO] debug this + void PGCRsequence(const Field &src, Field &x) + { + Field Ap(src.Grid()); + Field r(src.Grid()); + // Field p(src.Grid()); + // p=src; + std::vector p; + p.push_back(src); + r=src; + x=Zero(); + x.Checkerboard()=src.Checkerboard(); + for(int k=0;kLinop.Op(p[k], Ap); + r = r - ak[k] * Ap; + // p[k] = r; + p.push_back(r); + for (int i = 0; i < k; i++) { // [PO TODO] check indices + p[k+1] += bk[i, k+1] * p[i]; + } + // p = r + bk[k] * p; + } + } + + void Solve(const Field &src, Field &psi) + { + psi=Zero(); + this->operator()(src, psi); + } + + virtual void LogBegin(void) + { + std::cout << "PGCR::LogBegin() "< p0_tmp; + p0_tmp.push_back(1.0); + poly_p.push_back(p0_tmp); + poly_r.push_back(1.0); + }; + + // Updates vector psi and r and initializes vector p[k+1] + virtual void LogIteration(int k, ComplexD a, std::vector betas){ + std::cout << "PGCR::LogIteration(k = " << k << ")" << std::endl; + ak.push_back(a); + bk.push_back(betas); + + // update Ap by pushing p[k] to the right + poly_Ap.push_back(0.0); // need to pad the end with an element + poly_Ap[0] = 0.0; // technically this should be unnecessary, as the first component is never set + for(int i = 0; i < k; i++){ + poly_Ap[i+1]=poly_p[k-1][i]; // A\vec{p} = (0, \vec{p}) bc A shifts components of p to the right + } + + // update psi_{k+1} --> psi_k + a_k p_k + polynomial.push_back(0.0); + for(int i = 0; i < k; i++) { + polynomial[i] += a * poly_p[k-1][i]; + } + PF.data.push_back(polynomial); + + // r_{k+1} --> r_k - a_k A p_k + // p_{k+1} --> r_k + \sum_{i=0}^k \beta_{ik} p_i, input betas = (\beta_{ik})_i + poly_r.push_back(0.0); // should be of size k+1 if we start with k = 1 + std::vector p_next (k + 1, ComplexD(0.0)); // p_{k+1} = same size as r_{k+1} + for(int i = 0; i < k + 1; i++){ + poly_r[i] = poly_r[i] - a * poly_Ap[i]; // update r_{k+1} --> r_k - \alpha_k A p_k + p_next[i] = poly_r[i]; // init new vector as r_{k+1} + } + + // p_{k+1} --> p_{k+1} + \sum_i \beta_{ij} p_i + int nbeta = betas.size(); + std::cout << "Betas: " << betas << std::endl; + for (int j = 0; j < nbeta; j++) { + for (int i = 0; i < j+1; i++) { + p_next[i] += betas[j] * poly_p[j][i]; + } + } + poly_p.push_back(p_next); // add p_{k+1} to the list of p's + } + + virtual void LogComplete(std::vector& alphas, std::vector>& betas) { + /** Logs all alphas and betas to complete the iterations. */ + std::cout << "PGCR::LogComplete() "<