From 93650f3a61419830622476224327f14f61716364 Mon Sep 17 00:00:00 2001 From: Chulwoo Jung Date: Mon, 24 Jul 2017 21:49:25 -0400 Subject: [PATCH] Adding back (temporarily) dense matrix routines until Lanczos is fininalized --- lib/algorithms/densematrix/DenseMatrix.h | 137 ++++++ lib/algorithms/densematrix/Francis.h | 525 +++++++++++++++++++++++ lib/algorithms/densematrix/Householder.h | 242 +++++++++++ lib/algorithms/iterative/SimpleLanczos.h | 2 +- 4 files changed, 905 insertions(+), 1 deletion(-) create mode 100644 lib/algorithms/densematrix/DenseMatrix.h create mode 100644 lib/algorithms/densematrix/Francis.h create mode 100644 lib/algorithms/densematrix/Householder.h diff --git a/lib/algorithms/densematrix/DenseMatrix.h b/lib/algorithms/densematrix/DenseMatrix.h new file mode 100644 index 00000000..d86add21 --- /dev/null +++ b/lib/algorithms/densematrix/DenseMatrix.h @@ -0,0 +1,137 @@ + /************************************************************************************* + + Grid physics library, www.github.com/paboyle/Grid + + Source file: ./lib/algorithms/iterative/DenseMatrix.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_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(DenseVector & mat, int N) { + mat.resize(N); +} +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 + + 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 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 + + 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 HOUSEHOLDER_H +#define HOUSEHOLDER_H + +#define TIMER(A) std::cout << GridLogMessage << __FUNC__ << " file "<< __FILE__ <<" line " << __LINE__ << std::endl; +#define ENTER() std::cout << GridLogMessage << "ENTRY "<<__FUNC__ << " file "<< __FILE__ <<" line " << __LINE__ << std::endl; +#define LEAVE() std::cout << GridLogMessage << "EXIT "<<__FUNC__ << " file "<< __FILE__ <<" line " << __LINE__ << std::endl; + +#include +#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 +//#include // eliminate temorary vector in calc() #define MEM_SAVE