/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/algorithms/iterative/ImplicitlyRestartedLanczos.h Copyright (C) 2015 Author: Peter Boyle 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_IRL_H #define GRID_IRL_H #include #include namespace Grid { ///////////////////////////////////////////////////////////// // Implicitly restarted lanczos ///////////////////////////////////////////////////////////// template class ImplicitlyRestartedLanczos { const RealD small = 1.0e-16; public: int lock; int get; int Niter; int converged; int Nk; // Number of converged sought int Np; // Np -- Number of spare vecs in kryloc space int Nm; // Nm -- total number of vectors RealD eresid; SortEigen _sort; LinearOperatorBase &_Linop; OperatorFunction &_poly; ///////////////////////// // Constructor ///////////////////////// void init(void){}; void Abort(int ff, DenseVector &evals, DenseVector > &evecs); ImplicitlyRestartedLanczos(LinearOperatorBase &Linop, // op OperatorFunction & poly, // polynmial int _Nk, // sought vecs int _Nm, // spare vecs RealD _eresid, // resid in lmdue deficit int _Niter) : // Max iterations _Linop(Linop), _poly(poly), Nk(_Nk), Nm(_Nm), eresid(_eresid), Niter(_Niter) { Np = Nm-Nk; assert(Np>0); }; ///////////////////////// // Sanity checked this routine (step) against Saad. ///////////////////////// void RitzMatrix(DenseVector& evec,int k){ if(1) return; GridBase *grid = evec[0]._grid; Field w(grid); std::cout << "RitzMatrix "<1 ) { if (abs(in) >1.0e-9 ) { std::cout<<"oops"<& lmd, DenseVector& lme, DenseVector& evec, Field& w,int Nm,int k) { assert( k< Nm ); _poly(_Linop,evec[k],w); // 3. wk:=Avk−βkv_{k−1} if(k>0){ w -= lme[k-1] * evec[k-1]; } ComplexD zalph = innerProduct(evec[k],w); // 4. αk:=(wk,vk) RealD alph = real(zalph); w = w - alph * evec[k];// 5. wk:=wk−αkvk RealD beta = normalise(w); // 6. βk+1 := ∥wk∥2. If βk+1 = 0 then Stop // 7. vk+1 := wk/βk+1 const RealD tiny = 1.0e-20; if ( beta < tiny ) { std::cout << " beta is tiny "<0) { orthogonalize(w,evec,k); // orthonormalise } if(k < Nm-1) evec[k+1] = w; } void qr_decomp(DenseVector& lmd, DenseVector& lme, int Nk, int Nm, DenseVector& Qt, RealD Dsh, int kmin, int kmax) { int k = kmin-1; RealD x; RealD Fden = 1.0/hypot(lmd[k]-Dsh,lme[k]); RealD c = ( lmd[k] -Dsh) *Fden; RealD s = -lme[k] *Fden; RealD tmpa1 = lmd[k]; RealD tmpa2 = lmd[k+1]; RealD tmpb = lme[k]; lmd[k] = c*c*tmpa1 +s*s*tmpa2 -2.0*c*s*tmpb; lmd[k+1] = s*s*tmpa1 +c*c*tmpa2 +2.0*c*s*tmpb; lme[k] = c*s*(tmpa1-tmpa2) +(c*c-s*s)*tmpb; x =-s*lme[k+1]; lme[k+1] = c*lme[k+1]; for(int i=0; i& lmd, DenseVector& lme, int Nm2, int Nm, DenseVector& Qt) { int Niter = 100*Nm; int kmin = 1; int kmax = Nk; // (this should be more sophisticated) for(int iter=0; iter= kmin; --j){ RealD dds = fabs(lmd[j-1])+fabs(lmd[j]); if(fabs(lme[j-1])+dds > dds){ kmax = j+1; goto continued; } } Niter = iter; return; continued: for(int j=0; j dds){ kmin = j+1; break; } } } std::cout << "[QL method] Error - Too many iteration: "<& evec, int k) { typedef typename Field::scalar_type MyComplex; MyComplex ip; if ( 0 ) { for(int j=0; j &Qt) { for(int i=0; i K P = M − K † Compute the factorization AVM = VM HM + fM eM repeat Q=I for i = 1,...,P do QiRi =HM −θiI Q = QQi H M = Q †i H M Q i end for βK =HM(K+1,K) σK =Q(M,K) r=vK+1βK +rσK VK =VM(1:M)Q(1:M,1:K) HK =HM(1:K,1:K) →AVK =VKHK +fKe†K † Extend to an M = K + P step factorization AVM = VMHM + fMeM until convergence */ void calc(DenseVector& eval, DenseVector& evec, const Field& src, int& Nconv) { GridBase *grid = evec[0]._grid; std::cout << " -- Nk = " << Nk << " Np = "<< Np << std::endl; std::cout << " -- Nm = " << Nm << std::endl; std::cout << " -- size of eval = " << eval.size() << std::endl; std::cout << " -- size of evec = " << evec.size() << std::endl; assert(Nm == evec.size() && Nm == eval.size()); DenseVector lme(Nm); DenseVector lme2(Nm); DenseVector eval2(Nm); DenseVector Qt(Nm*Nm); DenseVector Iconv(Nm); DenseVector B(Nm,grid); // waste of space replicating Field f(grid); Field v(grid); int k1 = 1; int k2 = Nk; Nconv = 0; RealD beta_k; // Set initial vector // (uniform vector) Why not src?? // evec[0] = 1.0; evec[0] = src; normalise(evec[0]); // Initial Nk steps for(int k=0; k=Nk ){ goto converged; } } // end of iter loop std::cout<<"\n NOT converged.\n"; abort(); converged: // Sorting eval.clear(); evec.clear(); for(int i=0; i & bq, Field &bf, DenseMatrix &H){ GridBase *grid = bq[0]._grid; RealD beta; RealD sqbt; RealD alpha; for(int i=start;i 1) std::cout << "orthagonality refined " << re << " times" < evals, DenseVector evecs){ int N= evals.size(); _sort.push(evals,evecs, evals.size(),N); } void ImplicitRestart(int TM, DenseVector &evals, DenseVector > &evecs, DenseVector &bq, Field &bf, int cont) { std::cout << "ImplicitRestart begin. Eigensort starting\n"; DenseMatrix H; Resize(H,Nm,Nm); EigenSort(evals, evecs); ///Assign shifts int K=Nk; int M=Nm; int P=Np; int converged=0; if(K - converged < 4) P = (M - K-1); //one // DenseVector shifts(P + shift_extra.size()); DenseVector shifts(P); for(int k = 0; k < P; ++k) shifts[k] = evals[k]; /// Shift to form a new H and q DenseMatrix Q; Resize(Q,TM,TM); Unity(Q); Shift(Q, shifts); // H is implicitly passed in in Rudy's Shift routine int ff = K; /// Shifted H defines a new K step Arnoldi factorization RealD beta = H[ff][ff-1]; RealD sig = Q[TM - 1][ff - 1]; std::cout << "beta = " << beta << " sig = " << real(sig) < q Q times_real(bq, Q, TM); std::cout << norm2(bq[0]) << " -- after " << ff < &bq, Field &bf, DenseVector > & evecs,DenseVector &evals) { init(); int M=Nm; DenseMatrix H; Resize(H,Nm,Nm); Resize(evals,Nm); Resize(evecs,Nm); int ff = Lanczos_Factor(0, M, cont, bq,bf,H); // 0--M to begin with if(ff < M) { std::cout << "Krylov: aborting ff "< " << it << std::endl; int lock_num = lock ? converged : 0; DenseVector tevals(M - lock_num ); DenseMatrix tevecs; Resize(tevecs,M - lock_num,M - lock_num); //check residual of polynominal TestConv(H,M, tevals, tevecs); if(converged >= Nk) break; ImplicitRestart(ff, tevals,tevecs,H); } Wilkinson(H, evals, evecs, small); // Check(); std::cout << "Done "< & H,DenseMatrix &Q, DenseVector shifts) { int P; Size(shifts,P); int M; SizeSquare(Q,M); Unity(Q); int lock_num = lock ? converged : 0; RealD t_Househoulder_vector(0.0); RealD t_Househoulder_mult(0.0); for(int i=0;i ck(3), v(3); x = H[lock_num+0][lock_num+0]-shifts[i]; y = H[lock_num+1][lock_num+0]; ck[0] = x; ck[1] = y; ck[2] = 0; normalise(ck); ///Normalization cancels in PHP anyway RealD beta; Householder_vector(ck, 0, 2, v, beta); Householder_mult(H,v,beta,0,lock_num+0,lock_num+2,0); Householder_mult(H,v,beta,0,lock_num+0,lock_num+2,1); ///Accumulate eigenvector Householder_mult(Q,v,beta,0,lock_num+0,lock_num+2,1); int sw = 0; for(int k=lock_num+0;k(ck, 0, 2-sw, v, beta); Householder_mult(H,v, beta,0,k+1,k+3-sw,0); Householder_mult(H,v, beta,0,k+1,k+3-sw,1); ///Accumulate eigenvector Householder_mult(Q,v, beta,0,k+1,k+3-sw,1); } } } void TestConv(DenseMatrix & H,int SS, DenseVector &bq, Field &bf, DenseVector &tevals, DenseVector > &tevecs, int lock, int converged) { std::cout << "Converged " << converged << " so far." << std::endl; int lock_num = lock ? converged : 0; int M = Nm; ///Active Factorization DenseMatrix AH; Resize(AH,SS - lock_num,SS - lock_num ); AH = GetSubMtx(H,lock_num, SS, lock_num, SS); int NN=tevals.size(); int AHsize=SS-lock_num; RealD small=1.0e-16; Wilkinson(AH, tevals, tevecs, small); EigenSort(tevals, tevecs); RealD resid_nrm= norm2(bf); if(!lock) converged = 0; #if 0 for(int i = SS - lock_num - 1; i >= SS - Nk && i >= 0; --i){ RealD diff = 0; diff = abs( tevecs[i][Nm - 1 - lock_num] ) * resid_nrm; std::cout << "residual estimate " << SS-1-i << " " << diff << " of (" << tevals[i] << ")" << std::endl; if(diff < converged) { if(lock) { DenseMatrix Q; Resize(Q,M,M); bool herm = true; Lock(H, Q, tevals[i], converged, small, SS, herm); times_real(bq, Q, bq.size()); bf = Q[M - 1][M - 1]* bf; lock_num++; } converged++; std::cout << " converged on eval " << converged << " of " << Nk << std::endl; } else { break; } } #endif std::cout << "Got " << converged << " so far " < &evals, DenseVector > &evecs) { DenseVector goodval(this->get); EigenSort(evals,evecs); int NM = Nm; DenseVector< DenseVector > V; Size(V,NM); DenseVector QZ(NM*NM); for(int i = 0; i < NM; i++){ for(int j = 0; j < NM; j++){ // evecs[i][j]; } } } /** There is some matrix Q such that for any vector y Q.e_1 = y and Q is unitary. **/ template static T orthQ(DenseMatrix &Q, DenseVector y){ int N = y.size(); //Matrix Size Fill(Q,0.0); T tau; for(int i=0;i 0.0){ T gam = conj( (y[j]/tau)/tau0 ); for(int k=0;k<=j-1;k++){ Q[k][j]=-gam*y[k]; } Q[j][j]=tau0/tau; } else { Q[j-1][j]=1.0; } tau0 = tau; } return tau; } /** There is some matrix Q such that for any vector y Q.e_k = y and Q is unitary. **/ template< class T> static T orthU(DenseMatrix &Q, DenseVector y){ T tau = orthQ(Q,y); SL(Q); return tau; } /** Wind up with a matrix with the first con rows untouched say con = 2 Q is such that Qdag H Q has {x, x, val, 0, 0, 0, 0, ...} as 1st colum and the matrix is upper hessenberg and with f and Q appropriately modidied with Q is the arnoldi factorization **/ template static void Lock(DenseMatrix &H, ///Hess mtx DenseMatrix &Q, ///Lock Transform T val, ///value to be locked int con, ///number already locked RealD small, int dfg, bool herm) { //ForceTridiagonal(H); int M = H.dim; DenseVector vec; Resize(vec,M-con); DenseMatrix AH; Resize(AH,M-con,M-con); AH = GetSubMtx(H,con, M, con, M); DenseMatrix QQ; Resize(QQ,M-con,M-con); Unity(Q); Unity(QQ); DenseVector evals; Resize(evals,M-con); DenseMatrix evecs; Resize(evecs,M-con,M-con); Wilkinson(AH, evals, evecs, small); int k=0; RealD cold = abs( val - evals[k]); for(int i=1;icon+2; j--){ DenseMatrix U; Resize(U,j-1-con,j-1-con); DenseVector z; Resize(z,j-1-con); T nm = norm(z); for(int k = con+0;k Hb; Resize(Hb,j-1-con,M); for(int a = 0;a Qb; Resize(Qb,M,M); for(int a = 0;a Hc; Resize(Hc,M,M); for(int a = 0;a