diff --git a/lib/algorithms/iterative/DenseMatrix.h b/lib/algorithms/iterative/DenseMatrix.h new file mode 100644 index 00000000..2423677d --- /dev/null +++ b/lib/algorithms/iterative/DenseMatrix.h @@ -0,0 +1,106 @@ +#ifndef GRID_DENSE_MATRIX_H +#define GRID_DENSE_MATRIX_H + +namespace Grid { + ///////////////////////////////////////////////////////////// + // Matrix untils + ///////////////////////////////////////////////////////////// + +template using DenseVector = std::vector; +template using DenseMatrix = DenseVector >; + +template void Size(DenseVector & vec, int &N) +{ + N= vec.size(); +} +template void Size(DenseMatrix & mat, int &N,int &M) +{ + N= mat.size(); + M= mat[0].size(); +} + +template void SizeSquare(DenseMatrix & mat, int &N) +{ + int M; Size(mat,N,M); + assert(N==M); +} + +template void Resize(DenseMatrix & mat, int N, int M) { + mat.resize(N); + for(int i=0;i void Fill(DenseMatrix & mat, T&val) { + int N,M; + Size(mat,N,M); + for(int i=0;i DenseMatrix Transpose(DenseMatrix & mat){ + int N,M; + Size(mat,N,M); + DenseMatrix C; Resize(C,M,N); + for(int i=0;i void Unity(DenseMatrix &A){ + int N; SizeSquare(A,N); + for(int i=0;i +void PlusUnit(DenseMatrix & A,T c){ + int dim; SizeSquare(A,dim); + for(int i=0;i +DenseMatrix HermitianConj(DenseMatrix &mat){ + + int dim; SizeSquare(mat,dim); + + DenseMatrix C; Resize(C,dim,dim); + + for(int i=0;i +DenseMatrix GetSubMtx(DenseMatrix &A,int row_st, int row_end, int col_st, int col_end) +{ + DenseMatrix H; Resize(H,row_end - row_st,col_end-col_st); + + for(int i = row_st; i +#include + +#endif + diff --git a/lib/algorithms/iterative/EigenSort.h b/lib/algorithms/iterative/EigenSort.h new file mode 100644 index 00000000..c036110b --- /dev/null +++ b/lib/algorithms/iterative/EigenSort.h @@ -0,0 +1,52 @@ +#ifndef GRID_EIGENSORT_H +#define GRID_EIGENSORT_H + + +namespace Grid { + ///////////////////////////////////////////////////////////// + // Eigen sorter to begin with + ///////////////////////////////////////////////////////////// + +template +class SortEigen { + private: + + static bool less_lmd(RealD left,RealD right){ + return fabs(left) < fabs(right); + } + static bool less_pair(std::pair& left, + std::pair& right){ + return fabs(left.first) < fabs(right.first); + } + + public: + + void push(DenseVector& lmd, + DenseVector& evec,int N) { + + DenseVector > emod; + typename DenseVector >::iterator it; + + for(int i=0;i(lmd[i],evec[i])); + } + + partial_sort(emod.begin(),emod.begin()+N,emod.end(),less_pair); + + it=emod.begin(); + for(int i=0;ifirst; + evec[i]=it->second; + ++it; + } + } + void push(DenseVector& lmd,int N) { + std::partial_sort(lmd.begin(),lmd.begin()+N,lmd.end(),less_lmd); + } + bool saturated(RealD lmd, RealD thrs) { + return fabs(lmd) > fabs(thrs); + } +}; + +} +#endif diff --git a/lib/algorithms/iterative/Francis.h b/lib/algorithms/iterative/Francis.h new file mode 100644 index 00000000..405193d2 --- /dev/null +++ b/lib/algorithms/iterative/Francis.h @@ -0,0 +1,498 @@ +#ifndef FRANCIS_H +#define FRANCIS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include +//#include +//#include + +namespace Grid { + +template int SymmEigensystem(DenseMatrix &Ain, DenseVector &evals, DenseMatrix &evecs, RealD small); +template int Eigensystem(DenseMatrix &Ain, DenseVector &evals, DenseMatrix &evecs, RealD small); + +/** + Find the eigenvalues of an upper hessenberg matrix using the Francis QR algorithm. +H = + x x x x x x x x x + x x x x x x x x x + 0 x x x x x x x x + 0 0 x x x x x x x + 0 0 0 x x x x x x + 0 0 0 0 x x x x x + 0 0 0 0 0 x x x x + 0 0 0 0 0 0 x x x + 0 0 0 0 0 0 0 x x +Factorization is P T P^H where T is upper triangular (mod cc blocks) and P is orthagonal/unitary. +**/ +template +int QReigensystem(DenseMatrix &Hin, DenseVector &evals, DenseMatrix &evecs, RealD small) +{ + DenseMatrix H = Hin; + + int N ; SizeSquare(H,N); + int M = N; + + Fill(evals,0); + Fill(evecs,0); + + T s,t,x=0,y=0,z=0; + T u,d; + T apd,amd,bc; + DenseVector p(N,0); + T nrm = Norm(H); ///DenseMatrix Norm + int n, m; + int e = 0; + int it = 0; + int tot_it = 0; + int l = 0; + int r = 0; + DenseMatrix P; Resize(P,N,N); Unity(P); + DenseVector trows(N,0); + + /// Check if the matrix is really hessenberg, if not abort + RealD sth = 0; + for(int j=0;j small){ + std::cout << "Non hessenberg H = " << sth << " > " << small << std::endl; + exit(1); + } + } + } + + do{ + std::cout << "Francis QR Step N = " << N << std::endl; + /** Check for convergence + x x x x x + 0 x x x x + 0 0 x x x + 0 0 x x x + 0 0 0 0 x + for this matrix l = 4 + **/ + do{ + l = Chop_subdiag(H,nrm,e,small); + r = 0; ///May have converged on more than one eval + ///Single eval + if(l == N-1){ + evals[e] = H[l][l]; + N--; e++; r++; it = 0; + } + ///RealD eval + if(l == N-2){ + trows[l+1] = 1; ///Needed for UTSolve + apd = H[l][l] + H[l+1][l+1]; + amd = H[l][l] - H[l+1][l+1]; + bc = (T)4.0*H[l+1][l]*H[l][l+1]; + evals[e] = (T)0.5*( apd + sqrt(amd*amd + bc) ); + evals[e+1] = (T)0.5*( apd - sqrt(amd*amd + bc) ); + N-=2; e+=2; r++; it = 0; + } + } while(r>0); + + if(N ==0) break; + + DenseVector ck; Resize(ck,3); + DenseVector v; Resize(v,3); + + for(int m = N-3; m >= l; m--){ + ///Starting vector essentially random shift. + if(it%10 == 0 && N >= 3 && it > 0){ + s = (T)1.618033989*( abs( H[N-1][N-2] ) + abs( H[N-2][N-3] ) ); + t = (T)0.618033989*( abs( H[N-1][N-2] ) + abs( H[N-2][N-3] ) ); + x = H[m][m]*H[m][m] + H[m][m+1]*H[m+1][m] - s*H[m][m] + t; + y = H[m+1][m]*(H[m][m] + H[m+1][m+1] - s); + z = H[m+1][m]*H[m+2][m+1]; + } + ///Starting vector implicit Q theorem + else{ + s = (H[N-2][N-2] + H[N-1][N-1]); + t = (H[N-2][N-2]*H[N-1][N-1] - H[N-2][N-1]*H[N-1][N-2]); + x = H[m][m]*H[m][m] + H[m][m+1]*H[m+1][m] - s*H[m][m] + t; + y = H[m+1][m]*(H[m][m] + H[m+1][m+1] - s); + z = H[m+1][m]*H[m+2][m+1]; + } + ck[0] = x; ck[1] = y; ck[2] = z; + + if(m == l) break; + + /** Some stupid thing from numerical recipies, seems to work**/ + // PAB.. for heaven's sake quote page, purpose, evidence it works. + // what sort of comment is that!?!?!? + u=abs(H[m][m-1])*(abs(y)+abs(z)); + d=abs(x)*(abs(H[m-1][m-1])+abs(H[m][m])+abs(H[m+1][m+1])); + if ((T)abs(u+d) == (T)abs(d) ){ + l = m; break; + } + + //if (u < small){l = m; break;} + } + if(it > 100000){ + std::cout << "QReigensystem: bugger it got stuck after 100000 iterations" << std::endl; + std::cout << "got " << e << " evals " << l << " " << N << std::endl; + exit(1); + } + normalize(ck); ///Normalization cancels in PHP anyway + T beta; + Householder_vector(ck, 0, 2, v, beta); + Householder_mult(H,v,beta,0,l,l+2,0); + Householder_mult(H,v,beta,0,l,l+2,1); + ///Accumulate eigenvector + Householder_mult(P,v,beta,0,l,l+2,1); + int sw = 0; ///Are we on the last row? + for(int k=l;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(P,v, beta,0,k+1,k+3-sw,1); + } + it++; + tot_it++; + }while(N > 1); + N = evals.size(); + ///Annoying - UT solves in reverse order; + DenseVector tmp; Resize(tmp,N); + for(int i=0;i +int my_Wilkinson(DenseMatrix &Hin, DenseVector &evals, DenseMatrix &evecs, RealD small) +{ + /** + Find the eigenvalues of an upper Hessenberg matrix using the Wilkinson QR algorithm. + H = + x x 0 0 0 0 + x x x 0 0 0 + 0 x x x 0 0 + 0 0 x x x 0 + 0 0 0 x x x + 0 0 0 0 x x + Factorization is P T P^H where T is upper triangular (mod cc blocks) and P is orthagonal/unitary. **/ + return my_Wilkinson(Hin, evals, evecs, small, small); +} + +template +int my_Wilkinson(DenseMatrix &Hin, DenseVector &evals, DenseMatrix &evecs, RealD small, RealD tol) +{ + int N; SizeSquare(Hin,N); + int M = N; + + ///I don't want to modify the input but matricies must be passed by reference + //Scale a matrix by its "norm" + //RealD Hnorm = abs( Hin.LargestDiag() ); H = H*(1.0/Hnorm); + DenseMatrix H; H = Hin; + + RealD Hnorm = abs(Norm(Hin)); + H = H * (1.0 / Hnorm); + + // TODO use openmp and memset + Fill(evals,0); + Fill(evecs,0); + + T s, t, x = 0, y = 0, z = 0; + T u, d; + T apd, amd, bc; + DenseVector p; Resize(p,N); Fill(p,0); + + T nrm = Norm(H); ///DenseMatrix Norm + int n, m; + int e = 0; + int it = 0; + int tot_it = 0; + int l = 0; + int r = 0; + DenseMatrix P; Resize(P,N,N); + Unity(P); + DenseVector trows(N, 0); + /// Check if the matrix is really symm tridiag + RealD sth = 0; + for(int j = 0; j < N; ++j) + { + for(int i = j + 2; i < N; ++i) + { + if(abs(H[i][j]) > tol || abs(H[j][i]) > tol) + { + std::cout << "Non Tridiagonal H(" << i << ","<< j << ") = |" << Real( real( H[j][i] ) ) << "| > " << tol << std::endl; + std::cout << "Warning tridiagonalize and call again" << std::endl; + // exit(1); // see what is going on + //return; + } + } + } + + do{ + do{ + //Jasper + //Check if the subdiagonal term is small enough ( 0); + //Jasper + //Already converged + //-------------- + if(N == 0) break; + + DenseVector ck,v; Resize(ck,2); Resize(v,2); + + for(int m = N - 3; m >= l; m--) + { + ///Starting vector essentially random shift. + if(it%10 == 0 && N >= 3 && it > 0) + { + t = abs(H[N - 1][N - 2]) + abs(H[N - 2][N - 3]); + x = H[m][m] - t; + z = H[m + 1][m]; + } else { + ///Starting vector implicit Q theorem + d = (H[N - 2][N - 2] - H[N - 1][N - 1]) * (T) 0.5; + t = H[N - 1][N - 1] - H[N - 1][N - 2] * H[N - 1][N - 2] + / (d + sign(d) * sqrt(d * d + H[N - 1][N - 2] * H[N - 1][N - 2])); + x = H[m][m] - t; + z = H[m + 1][m]; + } + //Jasper + //why it is here???? + //----------------------- + if(m == l) + break; + + u = abs(H[m][m - 1]) * (abs(y) + abs(z)); + d = abs(x) * (abs(H[m - 1][m - 1]) + abs(H[m][m]) + abs(H[m + 1][m + 1])); + if ((T)abs(u + d) == (T)abs(d)) + { + l = m; + break; + } + } + //Jasper + if(it > 1000000) + { + std::cout << "Wilkinson: bugger it got stuck after 100000 iterations" << std::endl; + std::cout << "got " << e << " evals " << l << " " << N << std::endl; + exit(1); + } + // + T s, c; + Givens_calc(x, z, c, s); + Givens_mult(H, l, l + 1, c, -s, 0); + Givens_mult(H, l, l + 1, c, s, 1); + Givens_mult(P, l, l + 1, c, s, 1); + // + for(int k = l; k < N - 2; ++k) + { + x = H.A[k + 1][k]; + z = H.A[k + 2][k]; + Givens_calc(x, z, c, s); + Givens_mult(H, k + 1, k + 2, c, -s, 0); + Givens_mult(H, k + 1, k + 2, c, s, 1); + Givens_mult(P, k + 1, k + 2, c, s, 1); + } + it++; + tot_it++; + }while(N > 1); + + N = evals.size(); + ///Annoying - UT solves in reverse order; + DenseVector tmp(N); + for(int i = 0; i < N; ++i) + tmp[i] = evals[N-i-1]; + evals = tmp; + // + UTeigenvectors(H, trows, evals, evecs); + //UTSymmEigenvectors(H, trows, evals, evecs); + for(int i = 0; i < evals.size(); ++i) + { + evecs[i] = P * evecs[i]; + normalize(evecs[i]); + evals[i] = evals[i] * Hnorm; + } + // // FIXME this is to test + // Hin.write("evecs3", evecs); + // Hin.write("evals3", evals); + // // check rsd + // for(int i = 0; i < M; i++) { + // vector Aevec = Hin * evecs[i]; + // RealD norm2(0.); + // for(int j = 0; j < M; j++) { + // norm2 += (Aevec[j] - evals[i] * evecs[i][j]) * (Aevec[j] - evals[i] * evecs[i][j]); + // } + // } + return tot_it; +} + +template +void Hess(DenseMatrix &A, DenseMatrix &Q, int start){ + + /** + turn a matrix A = + x x x x x + x x x x x + x x x x x + x x x x x + x x x x x + into + x x x x x + x x x x x + 0 x x x x + 0 0 x x x + 0 0 0 x x + with householder rotations + Slow. + */ + int N ; SizeSquare(A,N); + DenseVector p; Resize(p,N); Fill(p,0); + + for(int k=start;k ck,v; Resize(ck,N-k-1); Resize(v,N-k-1); + for(int i=k+1;i(ck, 0, ck.size()-1, v, beta); ///Householder vector + Householder_mult(A,v,beta,start,k+1,N-1,0); ///A -> PA + Householder_mult(A,v,beta,start,k+1,N-1,1); ///PA -> PAP^H + ///Accumulate eigenvector + Householder_mult(Q,v,beta,start,k+1,N-1,1); ///Q -> QP^H + } + /*for(int l=0;l +void Tri(DenseMatrix &A, DenseMatrix &Q, int start){ +///Tridiagonalize a matrix + int N; SizeSquare(A,N); + Hess(A,Q,start); + /*for(int l=0;l +void ForceTridiagonal(DenseMatrix &A){ +///Tridiagonalize a matrix + int N ; SizeSquare(A,N); + for(int l=0;l +int my_SymmEigensystem(DenseMatrix &Ain, DenseVector &evals, DenseVector > &evecs, RealD small){ + ///Solve a symmetric eigensystem, not necessarily in tridiagonal form + int N; SizeSquare(Ain,N); + DenseMatrix A; A = Ain; + DenseMatrix Q; Resize(Q,N,N); Unity(Q); + Tri(A,Q,0); + int it = my_Wilkinson(A, evals, evecs, small); + for(int k=0;k +int Wilkinson(DenseMatrix &Ain, DenseVector &evals, DenseVector > &evecs, RealD small){ + return my_Wilkinson(Ain, evals, evecs, small); +} + +template +int SymmEigensystem(DenseMatrix &Ain, DenseVector &evals, DenseVector > &evecs, RealD small){ + return my_SymmEigensystem(Ain, evals, evecs, small); +} + +template +int Eigensystem(DenseMatrix &Ain, DenseVector &evals, DenseVector > &evecs, RealD small){ +///Solve a general eigensystem, not necessarily in tridiagonal form + int N = Ain.dim; + DenseMatrix A(N); A = Ain; + DenseMatrix Q(N);Q.Unity(); + Hess(A,Q,0); + int it = QReigensystem(A, evals, evecs, small); + for(int k=0;k +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Grid { +/** Comparison function for finding the max element in a vector **/ +template bool cf(T i, T j) { + return abs(i) < abs(j); +} + +/** + Calculate a real Givens angle + **/ +template inline void Givens_calc(T y, T z, T &c, T &s){ + + RealD mz = (RealD)abs(z); + + if(mz==0.0){ + c = 1; s = 0; + } + if(mz >= (RealD)abs(y)){ + T t = -y/z; + s = (T)1.0 / sqrt ((T)1.0 + t * t); + c = s * t; + } else { + T t = -z/y; + c = (T)1.0 / sqrt ((T)1.0 + t * t); + s = c * t; + } +} + +template inline void Givens_mult(DenseMatrix &A, int i, int k, T c, T s, int dir) +{ + int q ; SizeSquare(A,q); + + if(dir == 0){ + for(int j=0;j inline void Householder_vector(DenseVector input, int k, int j, DenseVector &v, T &beta) +{ + int N ; Size(input,N); + T m = *max_element(input.begin() + k, input.begin() + j + 1, cf ); + + if(abs(m) > 0.0){ + T alpha = 0; + + for(int i=k; i 0.0) v[k] = v[k] + (v[k]/abs(v[k]))*alpha; + else v[k] = -alpha; + } else{ + for(int i=k; i inline void Householder_vector(DenseVector input, int k, int j, int dir, DenseVector &v, T &beta) +{ + int N = input.size(); + T m = *max_element(input.begin() + k, input.begin() + j + 1, cf); + + if(abs(m) > 0.0){ + T alpha = 0; + + for(int i=k; i 0.0) v[dir] = v[dir] + (v[dir]/abs(v[dir]))*alpha; + else v[dir] = -alpha; + }else{ + for(int i=k; i inline void Householder_mult(DenseMatrix &A , DenseVector v, T beta, int l, int k, int j, int trans) +{ + int N ; SizeSquare(A,N); + + if(abs(beta) > 0.0){ + for(int p=l; p inline void Householder_mult_tri(DenseMatrix &A , DenseVector v, T beta, int l, int M, int k, int j, int trans) +{ + if(abs(beta) > 0.0){ + + int N ; SizeSquare(A,N); + + DenseMatrix tmp; Resize(tmp,N,N); Fill(tmp,0); + + T s; + for(int p=l; p +#include + namespace Grid { - ///////////////////////////////////////////////////////////// - // Base classes for iterative processes based on operators - // single input vec, single output vec. - ///////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////// +// Implicitly restarted lanczos +///////////////////////////////////////////////////////////// - template + +template class ImplicitlyRestartedLanczos { -public: + const RealD small = 1.0e-16; +public: + int lock; + int converged; int Niter; - int Nk; - int Np; - RealD enorm; - RealD vthr; - + + 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; - ImplicitlyRestartedLanczos( - LinearOperatorBase &Linop, - OperatorFunction & poly, - int _Nk, - int _Np, - RealD _enorm, - RealD _vthrs, - int _Niter) : - _Linop(Linop), + ///////////////////////// + // 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), - Np(_Np), - enorm(_enorm), - vthr(_vthrs) + Nm(_Nm), + eresid(_eresid), + Niter(_Niter) { - vthr=_vthrs; - Niter=_Niter; + Np = Nm-Nk; assert(Np>0); }; + ///////////////////////// + // Sanity checked this routine (step) against Saad. + ///////////////////////// + void RitzMatrix(DenseVector& evec,int k){ + if(1) return; - void step(Vector& lmda, - Vector& lmdb, - Vector& evec, - Field& f,int Nm,int k) - { - - assert( k< Nm ); - - w = opr_->mult(evec[k]); - - if(k==0){ // Initial step - - RealD wnorm= w*w; - std::cout<<"wnorm="<1 ) { + if (abs(in) >1.0e-9 ) { + std::cout<<"oops"<& lmda, - Vector& lmdb, +/* Saad PP. 195 +1. Choose an initial vector v1 of 2-norm unity. Set β1 ≡ 0, v0 ≡ 0 +2. For k = 1,2,...,m Do: +3. wk:=Avk−βkv_{k−1} +4. αk:=(wk,vk) // +5. wk:=wk−αkvk // wk orthog vk +6. βk+1 := ∥wk∥2. If βk+1 = 0 then Stop +7. vk+1 := wk/βk+1 +8. EndDo + */ + void step(DenseVector& 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, - Vector& Qt, - RealD Dsft, + DenseVector& Qt, + RealD Dsh, int kmin, int kmax) { int k = kmin-1; RealD x; - RealD Fden = 1.0/sqrt((lmd[k]-Dsh)*(lmd[k]-Dsh) +lme[k]*lme[k]); + RealD Fden = 1.0/hypot(lmd[k]-Dsh,lme[k]); RealD c = ( lmd[k] -Dsh) *Fden; RealD s = -lme[k] *Fden; @@ -110,7 +149,7 @@ public: 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]; + x =-s*lme[k+1]; lme[k+1] = c*lme[k+1]; for(int i=0; i& lmda, - Vector& lmdb, + void diagonalize(DenseVector& lmd, + DenseVector& lme, int Nm2, int Nm, - Vector& Qt) + DenseVector& Qt) { int Niter = 100*Nm; int kmin = 1; @@ -195,102 +235,134 @@ public: abort(); } - void orthogonalize(Field& w, - const Vector& evec, - int k) + static RealD normalise(Field& v) { - // Schmidt orthogonalization - - size_t size = w.size(); - assert(size%2 ==0); - - std::slice re(0,size/2,2); - std::slice im(1,size/2,2); - - for(int j=0; j evr(evec[j][re]); - valarray evi(evec[j][im]); - - w.add(re, -prdr*evr +prdi*evi); - w.add(im, -prdr*evi -prdi*evr); - } + RealD nn = norm2(v); + nn = sqrt(nn); + v = v * (1.0/nn); + return nn; } - void calc(Vector& lmd, - Vector& evec, - const Field& b, - int& Nsbt, + void orthogonalize(Field& w, + DenseVector& 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) { - const size_t fsize = evec[0].size(); - - Nconv = -1; - Nsbt = 0; - int Nm = Nk_+Np_; - std::cout << " -- Nk = " << Nk_ << " Np = "<< Np_ << endl; - std::cout << " -- Nm = " << Nm << endl; - std::cout << " -- size of lmd = " << lmd.size() << endl; - std::cout << " -- size of evec = " << evec.size() << endl; + 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 < lmd.size()); + assert(Nm == evec.size() && Nm == eval.size()); - vector lme(Nm); - vector lmd2(Nm); - vector lme2(Nm); - vector Qt(Nm*Nm); - vector Iconv(Nm); + DenseVector lme(Nm); + DenseVector lme2(Nm); + DenseVector eval2(Nm); + DenseVector Qt(Nm*Nm); + DenseVector Iconv(Nm); + + DenseVector B(Nm,grid); // waste of space replicating - vector B(Nm); - for(int k=0; ksaturated(lmd2[i],vthr)) ++Kthrs; - std::cout<<"Kthrs="< 0){ - // (there is a converged eigenvalue larger than Vthrs.) - Nconv = iter; + if( Nconv>=Nk ){ goto converged; } } // end of iter loop @@ -368,21 +436,586 @@ public: converged: // Sorting - lmd.clear(); + eval.clear(); evec.clear(); - for(int i=0; ipush(lmd,evec,Kdis); - Nsbt = Kdis - Kthrs; + _sort.push(eval,evec,Nconv); std::cout << "\n Converged\n Summary :\n"; std::cout << " -- Iterations = "<< Nconv << "\n"; std::cout << " -- beta(k) = "<< beta_k << "\n"; - std::cout << " -- Kdis = "<< Kdis << "\n"; - std::cout << " -- Nsbt = "<< Nsbt << "\n"; + std::cout << " -- Nconv = "<< Nconv << "\n"; } - }; + + + // Adapted from Rudy's lanczos factor routine + int Lanczos_Factor(int start, int end, int cont, + DenseVector & 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,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; + + 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; + } + } + std::cout << "Got " << converged << " so far " < goodval(get); + EigenSort(evals,evecs); + + int NM = Nm; + int Nget = this->get; + S **V; + V = new S* [NM]; + + RealD *QZ; + QZ = new RealD [NM*NM]; + for(int i = 0; i < NM; i++){ + for(int j = 0; j < NM; j++){ + + QZ[i*NM+j] = this->evecs[i][j]; + + int f_size_cb = 24*dop.cbLs*dop.node_cbvol; + + for(int cb = this->prec; cb < 2; cb++){ + for(int i = 0; i < NM; i++){ + V[i] = (S*)(this->bq[i][cb]); + + const int m0 = 4 * 4; // this is new code + assert(m0 % 16 == 0); // see the reason in VtimesQ.C + + const int row_per_thread = f_size_cb / (bfmarg::threads); + { + + { + DenseVector vrow_tmp0(m0*NM); + DenseVector vrow_tmp1(m0*NM); + RealD *row_tmp0 = vrow_tmp0.data(); + RealD *row_tmp1 = vrow_tmp1.data(); + VtimesQ(QZ, NM, V, row_tmp0, row_tmp1, id * row_per_thread, m0, (id + 1) * row_per_thread); + } + } + } + } + } + } + } +#endif + + +/** + 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 +#include +#include +#include +#include +#include +#include +#include +#include + + +/** Sign function **/ +template T sign(T p){return ( p/abs(p) );} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////// Hijack STL containers for our wicked means ///////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////// +template using Vector = Vector; +template using Matrix = Vector >; + +template void Resize(Vector & vec, int N) { vec.resize(N); } + +template void Resize(Matrix & mat, int N, int M) { + mat.resize(N); + for(int i=0;i void Size(Vector & vec, int &N) +{ + N= vec.size(); +} +template void Size(Matrix & mat, int &N,int &M) +{ + N= mat.size(); + M= mat[0].size(); +} +template void SizeSquare(Matrix & mat, int &N) +{ + int M; Size(mat,N,M); + assert(N==M); +} +template void SizeSame(Matrix & mat1,Matrix &mat2, int &N1,int &M1) +{ + int N2,M2; + Size(mat1,N1,M1); + Size(mat2,N2,M2); + assert(N1==N2); + assert(M1==M2); +} + +//***************************************** +//* (Complex) Vector operations * +//***************************************** + +/**Conj of a Vector **/ +template Vector conj(Vector p){ + Vector q(p.size()); + for(int i=0;i T norm(Vector p){ + T sum = 0; + for(int i=0;i T norm2(Vector p){ + T sum = 0; + for(int i=0;i T trace(Vector p){ + T sum = 0; + for(int i=0;i void Fill(Vector &p, T c){ + for(int i=0;i void normalize(Vector &p){ + T m = norm(p); + if( abs(m) > 0.0) for(int i=0;i Vector times(Vector p, U s){ + for(int i=0;i Vector times(U s, Vector p){ + for(int i=0;i T inner(Vector a, Vector b){ + T m = 0.; + for(int i=0;i Vector add(Vector a, Vector b){ + Vector m(a.size()); + for(int i=0;i Vector sub(Vector a, Vector b){ + Vector m(a.size()); + for(int i=0;i void Fill(Matrix & mat, T&val) { + int N,M; + Size(mat,N,M); + for(int i=0;i Transpose(Matrix & mat){ + int N,M; + Size(mat,N,M); + Matrix C; Resize(C,M,N); + for(int i=0;i void Unity(Matrix &mat){ + int N; SizeSquare(mat,N); + for(int i=0;i +void PlusUnit(Matrix & A,T c){ + int dim; SizeSquare(A,dim); + for(int i=0;i HermitianConj(Matrix &mat){ + + int dim; SizeSquare(mat,dim); + + Matrix C; Resize(C,dim,dim); + + for(int i=0;i diag(Matrix &A) +{ + int dim; SizeSquare(A,dim); + Vector d; Resize(d,dim); + + for(int i=0;i operator *(Vector &B,Matrix &A) +{ + int K,M,N; + Size(B,K); + Size(A,M,N); + assert(K==M); + + Vector C; Resize(C,N); + + for(int j=0;j inv_diag(Matrix & A){ + int dim; SizeSquare(A,dim); + Vector d; Resize(d,dim); + for(int i=0;i operator + (Matrix &A,Matrix &B) +{ + int N,M ; SizeSame(A,B,N,M); + Matrix C; Resize(C,N,M); + for(int i=0;i operator- (Matrix & A,Matrix &B){ + int N,M ; SizeSame(A,B,N,M); + Matrix C; Resize(C,N,M); + for(int i=0;i operator* (Matrix & A,T c){ + int N,M; Size(A,N,M); + Matrix C; Resize(C,N,M); + for(int i=0;i operator* (Matrix &A,Matrix &B){ + int K,L,N,M; + Size(A,K,L); + Size(B,N,M); assert(L==N); + Matrix C; Resize(C,K,M); + + for(int i=0;i operator* (Matrix &A,Vector &B){ + int M,N,K; + Size(A,N,M); + Size(B,K); assert(K==M); + Vector C; Resize(C,N); + for(int i=0;i T LargestDiag(Matrix &A) +{ + int dim ; SizeSquare(A,dim); + + T ld = abs(A[0][0]); + for(int i=1;i abs(ld) ){ld = cf;} + } + return ld; +} + +/** Look for entries on the leading subdiagonal that are smaller than 'small' **/ +template int Chop_subdiag(Matrix &A,T norm, int offset, U small) +{ + int dim; SizeSquare(A,dim); + for(int l = dim - 1 - offset; l >= 1; l--) { + if((U)abs(A[l][l - 1]) < (U)small) { + A[l][l-1]=(U)0.0; + return l; + } + } + return 0; +} + +/** Look for entries on the leading subdiagonal that are smaller than 'small' **/ +template int Chop_symm_subdiag(Matrix & A,T norm, int offset, U small) +{ + int dim; SizeSquare(A,dim); + for(int l = dim - 1 - offset; l >= 1; l--) { + if((U)abs(A[l][l - 1]) < (U)small) { + A[l][l - 1] = (U)0.0; + A[l - 1][l] = (U)0.0; + return l; + } + } + return 0; +} +/**Assign a submatrix to a larger one**/ +template +void AssignSubMtx(Matrix & A,int row_st, int row_end, int col_st, int col_end, Matrix &S) +{ + for(int i = row_st; i +Matrix GetSubMtx(Matrix &A,int row_st, int row_end, int col_st, int col_end) +{ + Matrix H; Resize(row_end - row_st,col_end-col_st); + + for(int i = row_st; i +void AssignSubMtx(Matrix & A,int row_st, int row_end, int col_st, int col_end, Matrix &S) +{ + for(int i = row_st; i T proj(Matrix A, Vector B){ + int dim; SizeSquare(A,dim); + int dimB; Size(B,dimB); + assert(dimB==dim); + T C = 0; + for(int i=0;i q Q +template void times(Vector &q, Matrix &Q) +{ + int M; SizeSquare(Q,M); + int N; Size(q,N); + assert(M==N); + + times(q,Q,N); +} + +/// q -> q Q +template void times(multi1d &q, Matrix &Q, int N) +{ + GridBase *grid = q[0]._grid; + int M; SizeSquare(Q,M); + int K; Size(q,K); + assert(N S(N,grid ); + for(int j=0;j +#include +#include + +struct Bisection { + +static void get_eig2(int row_num,std::vector &ALPHA,std::vector &BETA, std::vector & eig) +{ + int i,j; + std::vector evec1(row_num+3); + std::vector evec2(row_num+3); + RealD eps2; + ALPHA[1]=0.; + BETHA[1]=0.; + for(i=0;imag(evec2[i+1])) { + swap(evec2+i,evec2+i+1); + swapped=1; + } + } + end--; + for(i=end-1;i>=begin;i--){ + if(mag(evec2[i])>mag(evec2[i+1])) { + swap(evec2+i,evec2+i+1); + swapped=1; + } + } + begin++; + } + + for(i=0;i &c, + std::vector &b, + int n, + int m1, + int m2, + RealD eps1, + RealD relfeh, + std::vector &x, + RealD &eps2) +{ + std::vector wu(n+2); + + RealD h,q,x1,xu,x0,xmin,xmax; + int i,a,k; + + b[1]=0.0; + xmin=c[n]-fabs(b[n]); + xmax=c[n]+fabs(b[n]); + for(i=1;ixmax) xmax= c[i]+h; + if(c[i]-h0.0 ? xmax : -xmin); + if(eps1<=0.0) eps1=eps2; + eps2=0.5*eps1+7.0*(eps2); + x0=xmax; + for(i=m1;i<=m2;i++){ + x[i]=xmax; + wu[i]=xmin; + } + + for(k=m2;k>=m1;k--){ + xu=xmin; + i=k; + do{ + if(xu=m1); + if(x0>x[k]) x0=x[k]; + while((x0-xu)>2*relfeh*(fabs(xu)+fabs(x0))+eps1){ + x1=(xu+x0)/2; + + a=0; + q=1.0; + for(i=1;i<=n;i++){ + q=c[i]-x1-((q!=0.0)? b[i]*b[i]/q:fabs(b[i])/relfeh); + if(q<0) a++; + } + // printf("x1=%e a=%d\n",x1,a); + if(ax1) x[a]=x1; + } + }else x0=x1; + } + x[k]=(x0+xu)/2; + } +} +} diff --git a/lib/algorithms/iterative/get_eig.c b/lib/algorithms/iterative/get_eig.c new file mode 100644 index 00000000..d3f5a12f --- /dev/null +++ b/lib/algorithms/iterative/get_eig.c @@ -0,0 +1 @@ + diff --git a/tests/Test_synthetic_lanczos.cc b/tests/Test_synthetic_lanczos.cc new file mode 100644 index 00000000..c15ca3a7 --- /dev/null +++ b/tests/Test_synthetic_lanczos.cc @@ -0,0 +1,123 @@ +#include +#include + +using namespace std; +using namespace Grid; +using namespace Grid::QCD; + +static int +FEenableexcept (unsigned int excepts) +{ + static fenv_t fenv; + unsigned int new_excepts = excepts & FE_ALL_EXCEPT, + old_excepts; // previous masks + + if ( fegetenv (&fenv) ) return -1; + old_excepts = fenv.__control & FE_ALL_EXCEPT; + + // unmask + fenv.__control &= ~new_excepts; + fenv.__mxcsr &= ~(new_excepts << 7); + + return ( fesetenv (&fenv) ? -1 : old_excepts ); +} + + +template class DumbOperator : public LinearOperatorBase { +public: + LatticeComplex scale; + + DumbOperator(GridBase *grid) : scale(grid) + { + GridParallelRNG pRNG(grid); + std::vector seeds({5,6,7,8}); + pRNG.SeedFixedIntegers(seeds); + + random(pRNG,scale); + + scale = exp(-real(scale)*6.0); + std::cout << " True matrix \n"<< scale < seeds({1,2,3,4}); + RNG.SeedFixedIntegers(seeds); + + + RealD alpha = 1.0; + RealD beta = 0.03; + RealD mu = 0.0; + int order = 11; + ChebyshevLanczos Cheby(alpha,beta,mu,order); + + std::ofstream file("pooh.dat"); + Cheby.csv(file); + + HermOpOperatorFunction X; + DumbOperator HermOp(grid); + + const int Nk = 40; + const int Nm = 80; + const int Nit= 10000; + + int Nconv; + RealD eresid = 1.0e-8; + + ImplicitlyRestartedLanczos IRL(HermOp,X,Nk,Nm,eresid,Nit); + + ImplicitlyRestartedLanczos ChebyIRL(HermOp,Cheby,Nk,Nm,eresid,Nit); + + LatticeComplex src(grid); gaussian(RNG,src); + { + std::vector eval(Nm); + std::vector evec(Nm,grid); + IRL.calc(eval,evec,src, Nconv); + } + + { + std::vector eval(Nm); + std::vector evec(Nm,grid); + ChebyIRL.calc(eval,evec,src, Nconv); + } + + Grid_finalize(); +}