mirror of
https://github.com/paboyle/Grid.git
synced 2025-04-10 14:10:46 +01:00
Simplified lanczos, added Eigen diagonalisation.
Curious if we can deprecate dependencly on BLAS. Will see when we get 48^3 running on our BG/Q port
This commit is contained in:
parent
0486ff8e79
commit
7e35286860
@ -56,11 +56,8 @@ class BlockConjugateGradient : public OperatorFunction<Field> {
|
||||
Integer IterationsToComplete; //Number of iterations the CG took to finish. Filled in upon completion
|
||||
|
||||
BlockConjugateGradient(BlockCGtype cgtype,int _Orthog,RealD tol, Integer maxit, bool err_on_no_conv = true)
|
||||
: Tolerance(tol),
|
||||
CGtype(cgtype),
|
||||
blockDim(_Orthog),
|
||||
MaxIterations(maxit),
|
||||
ErrorOnNoConverge(err_on_no_conv){};
|
||||
: Tolerance(tol), CGtype(cgtype), blockDim(_Orthog), MaxIterations(maxit), ErrorOnNoConverge(err_on_no_conv)
|
||||
{};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Thin QR factorisation (google it)
|
||||
|
@ -1,81 +0,0 @@
|
||||
/*************************************************************************************
|
||||
|
||||
Grid physics library, www.github.com/paboyle/Grid
|
||||
|
||||
Source file: ./lib/algorithms/iterative/EigenSort.h
|
||||
|
||||
Copyright (C) 2015
|
||||
|
||||
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
||||
|
||||
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_EIGENSORT_H
|
||||
#define GRID_EIGENSORT_H
|
||||
|
||||
|
||||
namespace Grid {
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Eigen sorter to begin with
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
template<class Field>
|
||||
class SortEigen {
|
||||
private:
|
||||
|
||||
//hacking for testing for now
|
||||
private:
|
||||
static bool less_lmd(RealD left,RealD right){
|
||||
return left > right;
|
||||
}
|
||||
static bool less_pair(std::pair<RealD,Field const*>& left,
|
||||
std::pair<RealD,Field const*>& right){
|
||||
return left.first > (right.first);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
void push(DenseVector<RealD>& lmd,
|
||||
DenseVector<Field>& evec,int N) {
|
||||
DenseVector<Field> cpy(lmd.size(),evec[0]._grid);
|
||||
for(int i=0;i<lmd.size();i++) cpy[i] = evec[i];
|
||||
|
||||
DenseVector<std::pair<RealD, Field const*> > emod(lmd.size());
|
||||
for(int i=0;i<lmd.size();++i)
|
||||
emod[i] = std::pair<RealD,Field const*>(lmd[i],&cpy[i]);
|
||||
|
||||
partial_sort(emod.begin(),emod.begin()+N,emod.end(),less_pair);
|
||||
|
||||
typename DenseVector<std::pair<RealD, Field const*> >::iterator it = emod.begin();
|
||||
for(int i=0;i<N;++i){
|
||||
lmd[i]=it->first;
|
||||
evec[i]=*(it->second);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
void push(DenseVector<RealD>& 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
|
@ -7,7 +7,8 @@
|
||||
Copyright (C) 2015
|
||||
|
||||
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
|
||||
Author: paboyle <paboyle@ph.ed.ac.uk>
|
||||
Author: Chulwoo Jung
|
||||
Author: Guido Cossu
|
||||
|
||||
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
|
||||
@ -31,35 +32,71 @@ Author: paboyle <paboyle@ph.ed.ac.uk>
|
||||
|
||||
#include <string.h> //memset
|
||||
|
||||
#ifdef USE_LAPACK
|
||||
void LAPACK_dstegr(char *jobz, char *range, int *n, double *d, double *e,
|
||||
double *vl, double *vu, int *il, int *iu, double *abstol,
|
||||
int *m, double *w, double *z, int *ldz, int *isuppz,
|
||||
double *work, int *lwork, int *iwork, int *liwork,
|
||||
int *info);
|
||||
#endif
|
||||
|
||||
template<class T> using DenseVector = std::vector<T>;
|
||||
|
||||
//#include <Grid/algorithms/densematrix/DenseMatrix.h>
|
||||
#include <Grid/algorithms/iterative/EigenSort.h>
|
||||
|
||||
namespace Grid {
|
||||
|
||||
enum IRLdiagonalisation {
|
||||
IRLdiagonaliseWithDSTEGR,
|
||||
IRLdiagonaliseWithQR,
|
||||
IRLdiagonaliseWithEigen
|
||||
};
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Helper class for sorting the evalues AND evectors by Field
|
||||
// Use pointer swizzle on vectors
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template<class Field>
|
||||
class SortEigen {
|
||||
private:
|
||||
static bool less_lmd(RealD left,RealD right){
|
||||
return left > right;
|
||||
}
|
||||
static bool less_pair(std::pair<RealD,Field const*>& left,
|
||||
std::pair<RealD,Field const*>& right){
|
||||
return left.first > (right.first);
|
||||
}
|
||||
|
||||
public:
|
||||
void push(std::vector<RealD>& lmd,std::vector<Field>& evec,int N) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// PAB: FIXME: VERY VERY VERY wasteful: takes a copy of the entire vector set.
|
||||
// : The vector reorder should be done by pointer swizzle somehow
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
std::vector<Field> cpy(lmd.size(),evec[0]._grid);
|
||||
for(int i=0;i<lmd.size();i++) cpy[i] = evec[i];
|
||||
|
||||
std::vector<std::pair<RealD, Field const*> > emod(lmd.size());
|
||||
|
||||
for(int i=0;i<lmd.size();++i) emod[i] = std::pair<RealD,Field const*>(lmd[i],&cpy[i]);
|
||||
|
||||
partial_sort(emod.begin(),emod.begin()+N,emod.end(),less_pair);
|
||||
|
||||
typename std::vector<std::pair<RealD, Field const*> >::iterator it = emod.begin();
|
||||
for(int i=0;i<N;++i){
|
||||
lmd[i]=it->first;
|
||||
evec[i]=*(it->second);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
void push(std::vector<RealD>& 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);
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Implicitly restarted lanczos
|
||||
/////////////////////////////////////////////////////////////
|
||||
template<class Field>
|
||||
class ImplicitlyRestartedLanczos {
|
||||
|
||||
public:
|
||||
int Niter; // Max iterations
|
||||
private:
|
||||
int MaxIter; // Max iterations
|
||||
int Nstop; // Number of evecs checked for convergence
|
||||
int Nk; // Number of converged sought
|
||||
int Nm; // Nm -- total number of vectors
|
||||
|
||||
RealD eresid;
|
||||
|
||||
IRLdiagonalisation diagonalisation;
|
||||
////////////////////////////////////
|
||||
// Embedded objects
|
||||
////////////////////////////////////
|
||||
@ -70,65 +107,214 @@ public:
|
||||
/////////////////////////
|
||||
// Constructor
|
||||
/////////////////////////
|
||||
public:
|
||||
ImplicitlyRestartedLanczos(LinearOperatorBase<Field> &Linop, // op
|
||||
OperatorFunction<Field> & poly, // polynmial
|
||||
int _Nstop, // sought vecs
|
||||
OperatorFunction<Field> & poly, // polynomial
|
||||
int _Nstop, // really sought vecs
|
||||
int _Nk, // sought vecs
|
||||
int _Nm, // total vecs
|
||||
RealD _eresid, // resid in lmdue deficit
|
||||
int _Niter) : // Max iterations
|
||||
RealD _eresid, // resid in lmd deficit
|
||||
int _MaxIter, // Max iterations
|
||||
IRLdiagonalisation _diagonalisation= IRLdiagonaliseWithEigen ) :
|
||||
_Linop(Linop), _poly(poly),
|
||||
Nstop(_Nstop), Nk(_Nk), Nm(_Nm),
|
||||
eresid(_eresid), Niter(_Niter) { };
|
||||
eresid(_eresid), MaxIter(_MaxIter),
|
||||
diagonalisation(_diagonalisation)
|
||||
{ };
|
||||
|
||||
#if 0
|
||||
ImplicitlyRestartedLanczos(LinearOperatorBase<Field> &Linop, // op
|
||||
OperatorFunction<Field> & poly, // polynmial
|
||||
int _Nk, // sought vecs
|
||||
int _Nm, // total vecs
|
||||
RealD _eresid, // resid in lmdue deficit
|
||||
int _Niter) : // Max iterations
|
||||
_Linop(Linop), _poly(poly),
|
||||
Nstop(_Nk), Nk(_Nk), Nm(_Nm),
|
||||
eresid(_eresid), Niter(_Niter) { };
|
||||
#endif
|
||||
/* Rudy Arthur's thesis pp.137
|
||||
------------------------
|
||||
Require: M > 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(std::vector<RealD>& eval, std::vector<Field>& evec, const Field& src, int& Nconv)
|
||||
{
|
||||
|
||||
#if 0
|
||||
void calc(DenseVector<RealD>& eval,
|
||||
DenseVector<Field>& evec,
|
||||
const Field& src,
|
||||
int& Nconv);
|
||||
GridBase *grid = evec[0]._grid;
|
||||
assert(grid == src._grid);
|
||||
|
||||
void step(DenseVector<RealD>& lmd,
|
||||
DenseVector<RealD>& lme,
|
||||
DenseVector<Field>& evec,
|
||||
Field& w,int Nm,int k);
|
||||
std::cout << GridLogMessage <<"**************************************************************************"<< std::endl;
|
||||
std::cout << GridLogMessage <<" ImplicitlyRestartedLanczos::calc() starting iteration 0 / "<< MaxIter<< std::endl;
|
||||
std::cout << GridLogMessage <<"**************************************************************************"<< std::endl;
|
||||
std::cout << GridLogMessage <<" -- seek Nk = " << Nk <<" vectors"<< std::endl;
|
||||
std::cout << GridLogMessage <<" -- accept Nstop = " << Nstop <<" vectors"<< std::endl;
|
||||
std::cout << GridLogMessage <<" -- total Nm = " << Nm <<" vectors"<< std::endl;
|
||||
std::cout << GridLogMessage <<" -- size of eval = " << eval.size() << std::endl;
|
||||
std::cout << GridLogMessage <<" -- size of evec = " << evec.size() << std::endl;
|
||||
if ( diagonalisation == IRLdiagonaliseWithDSTEGR ) {
|
||||
std::cout << GridLogMessage << "Diagonalisation is DSTEGR "<<std::endl;
|
||||
} else if ( diagonalisation == IRLdiagonaliseWithQR ) {
|
||||
std::cout << GridLogMessage << "Diagonalisation is QR "<<std::endl;
|
||||
} else if ( diagonalisation == IRLdiagonaliseWithEigen ) {
|
||||
std::cout << GridLogMessage << "Diagonalisation is Eigen "<<std::endl;
|
||||
}
|
||||
std::cout << GridLogMessage <<"**************************************************************************"<< std::endl;
|
||||
|
||||
void setUnit_Qt(int Nm, DenseVector<RealD> &Qt) ;
|
||||
assert(Nm == evec.size() && Nm == eval.size());
|
||||
|
||||
static RealD normalise(Field& v) ;
|
||||
void orthogonalize(Field& w, DenseVector<Field>& evec, int k);
|
||||
void diagonalize(DenseVector<RealD>& lmd,
|
||||
DenseVector<RealD>& lme,
|
||||
int N2, int N1,
|
||||
DenseVector<RealD>& Qt,
|
||||
GridBase *grid);
|
||||
std::vector<RealD> lme(Nm);
|
||||
std::vector<RealD> lme2(Nm);
|
||||
std::vector<RealD> eval2(Nm);
|
||||
Eigen::MatrixXd Qt = Eigen::MatrixXd::Zero(Nm,Nm);
|
||||
std::vector<int> Iconv(Nm);
|
||||
|
||||
void qr_decomp(DenseVector<RealD>& lmd,
|
||||
DenseVector<RealD>& lme,
|
||||
int Nk, int Nm,
|
||||
DenseVector<RealD>& Qt,
|
||||
RealD Dsh, int kmin, int kmax);
|
||||
std::vector<Field> B(Nm,grid); // waste of space replicating
|
||||
|
||||
#ifdef USE_LAPACK
|
||||
void diagonalize_lapack(DenseVector<RealD>& lmd,
|
||||
DenseVector<RealD>& lme,
|
||||
int N1, int N2,
|
||||
DenseVector<RealD>& Qt,
|
||||
GridBase *grid);
|
||||
#endif
|
||||
#endif
|
||||
Field f(grid);
|
||||
Field v(grid);
|
||||
|
||||
int k1 = 1;
|
||||
int k2 = Nk;
|
||||
|
||||
Nconv = 0;
|
||||
|
||||
RealD beta_k;
|
||||
|
||||
// Set initial vector
|
||||
evec[0] = src;
|
||||
std::cout << GridLogMessage <<"norm2(src)= " << norm2(src)<<std::endl;
|
||||
|
||||
normalise(evec[0]);
|
||||
std::cout << GridLogMessage <<"norm2(evec[0])= " << norm2(evec[0]) <<std::endl;
|
||||
|
||||
// Initial Nk steps
|
||||
for(int k=0; k<Nk; ++k) step(eval,lme,evec,f,Nm,k);
|
||||
|
||||
// Restarting loop begins
|
||||
int iter;
|
||||
for(iter = 0; iter<MaxIter; ++iter){
|
||||
|
||||
std::cout<< GridLogMessage <<" **********************"<< std::endl;
|
||||
std::cout<< GridLogMessage <<" Restart iteration = "<< iter << std::endl;
|
||||
std::cout<< GridLogMessage <<" **********************"<< std::endl;
|
||||
|
||||
for(int k=Nk; k<Nm; ++k) step(eval,lme,evec,f,Nm,k);
|
||||
|
||||
f *= lme[Nm-1];
|
||||
|
||||
// getting eigenvalues
|
||||
for(int k=0; k<Nm; ++k){
|
||||
eval2[k] = eval[k+k1-1];
|
||||
lme2[k] = lme[k+k1-1];
|
||||
}
|
||||
Qt = Eigen::MatrixXd::Identity(Nm,Nm);
|
||||
diagonalize(eval2,lme2,Nm,Nm,Qt,grid);
|
||||
|
||||
// sorting
|
||||
_sort.push(eval2,Nm);
|
||||
|
||||
// Implicitly shifted QR transformations
|
||||
Qt = Eigen::MatrixXd::Identity(Nm,Nm);
|
||||
for(int ip=k2; ip<Nm; ++ip){
|
||||
qr_decomp(eval,lme,Nm,Nm,Qt,eval2[ip],k1,Nm);
|
||||
}
|
||||
|
||||
for(int i=0; i<(Nk+1); ++i) B[i] = 0.0;
|
||||
|
||||
for(int j=k1-1; j<k2+1; ++j){
|
||||
for(int k=0; k<Nm; ++k){
|
||||
B[j].checkerboard = evec[k].checkerboard;
|
||||
B[j] += Qt(j,k) * evec[k];
|
||||
}
|
||||
}
|
||||
for(int j=k1-1; j<k2+1; ++j) evec[j] = B[j];
|
||||
|
||||
// Compressed vector f and beta(k2)
|
||||
f *= Qt(k2-1,Nm-1);
|
||||
f += lme[k2-1] * evec[k2];
|
||||
beta_k = norm2(f);
|
||||
beta_k = sqrt(beta_k);
|
||||
std::cout<< GridLogMessage<<" beta(k) = "<<beta_k<<std::endl;
|
||||
|
||||
RealD betar = 1.0/beta_k;
|
||||
evec[k2] = betar * f;
|
||||
lme[k2-1] = beta_k;
|
||||
|
||||
// Convergence test
|
||||
for(int k=0; k<Nm; ++k){
|
||||
eval2[k] = eval[k];
|
||||
lme2[k] = lme[k];
|
||||
}
|
||||
Qt = Eigen::MatrixXd::Identity(Nm,Nm);
|
||||
diagonalize(eval2,lme2,Nk,Nm,Qt,grid);
|
||||
|
||||
for(int k = 0; k<Nk; ++k) B[k]=0.0;
|
||||
|
||||
for(int j = 0; j<Nk; ++j){
|
||||
for(int k = 0; k<Nk; ++k){
|
||||
B[j].checkerboard = evec[k].checkerboard;
|
||||
B[j] += Qt(j,k) * evec[k];
|
||||
}
|
||||
}
|
||||
|
||||
Nconv = 0;
|
||||
for(int i=0; i<Nk; ++i){
|
||||
|
||||
_Linop.HermOp(B[i],v);
|
||||
|
||||
RealD vnum = real(innerProduct(B[i],v)); // HermOp.
|
||||
RealD vden = norm2(B[i]);
|
||||
eval2[i] = vnum/vden;
|
||||
v -= eval2[i]*B[i];
|
||||
RealD vv = norm2(v);
|
||||
|
||||
std::cout.precision(13);
|
||||
std::cout << GridLogMessage << "[" << std::setw(3)<< std::setiosflags(std::ios_base::right) <<i<<"] ";
|
||||
std::cout << "eval = "<<std::setw(25)<< std::setiosflags(std::ios_base::left)<< eval2[i];
|
||||
std::cout << " |H B[i] - eval[i]B[i]|^2 "<< std::setw(25)<< std::setiosflags(std::ios_base::right)<< vv<< std::endl;
|
||||
|
||||
// change the criteria as evals are supposed to be sorted, all evals smaller(larger) than Nstop should have converged
|
||||
if((vv<eresid*eresid) && (i == Nconv) ){
|
||||
Iconv[Nconv] = i;
|
||||
++Nconv;
|
||||
}
|
||||
|
||||
} // i-loop end
|
||||
|
||||
std::cout<< GridLogMessage <<" #modes converged: "<<Nconv<<std::endl;
|
||||
|
||||
if( Nconv>=Nstop ){
|
||||
goto converged;
|
||||
}
|
||||
} // end of iter loop
|
||||
|
||||
std::cout << GridLogMessage <<"**************************************************************************"<< std::endl;
|
||||
std::cout<< GridLogError <<" ImplicitlyRestartedLanczos::calc() NOT converged.";
|
||||
std::cout << GridLogMessage <<"**************************************************************************"<< std::endl;
|
||||
abort();
|
||||
|
||||
converged:
|
||||
// Sorting
|
||||
eval.resize(Nconv);
|
||||
evec.resize(Nconv,grid);
|
||||
for(int i=0; i<Nconv; ++i){
|
||||
eval[i] = eval2[Iconv[i]];
|
||||
evec[i] = B[Iconv[i]];
|
||||
}
|
||||
_sort.push(eval,evec,Nconv);
|
||||
|
||||
std::cout << GridLogMessage <<"**************************************************************************"<< std::endl;
|
||||
std::cout << GridLogMessage << "ImplicitlyRestartedLanczos CONVERGED ; Summary :\n";
|
||||
std::cout << GridLogMessage <<"**************************************************************************"<< std::endl;
|
||||
std::cout << GridLogMessage << " -- Iterations = "<< iter << "\n";
|
||||
std::cout << GridLogMessage << " -- beta(k) = "<< beta_k << "\n";
|
||||
std::cout << GridLogMessage << " -- Nconv = "<< Nconv << "\n";
|
||||
std::cout << GridLogMessage <<"**************************************************************************"<< std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
/* 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:
|
||||
@ -139,9 +325,9 @@ public:
|
||||
7. vk+1 := wk/βk+1
|
||||
8. EndDo
|
||||
*/
|
||||
void step(DenseVector<RealD>& lmd,
|
||||
DenseVector<RealD>& lme,
|
||||
DenseVector<Field>& evec,
|
||||
void step(std::vector<RealD>& lmd,
|
||||
std::vector<RealD>& lme,
|
||||
std::vector<Field>& evec,
|
||||
Field& w,int Nm,int k)
|
||||
{
|
||||
const RealD tiny = 1.0e-20;
|
||||
@ -165,13 +351,17 @@ public:
|
||||
if ( k > 0 ) orthogonalize(w,evec,k); // orthonormalise
|
||||
if ( k < Nm-1) evec[k+1] = w;
|
||||
|
||||
if ( beta < tiny ) std::cout << " beta is tiny "<<beta<<std::endl;
|
||||
if ( beta < tiny ) std::cout << GridLogMessage << " beta is tiny "<<beta<<std::endl;
|
||||
}
|
||||
|
||||
void qr_decomp(DenseVector<RealD>& lmd, // Nm
|
||||
DenseVector<RealD>& lme, // Nm
|
||||
int Nk, int Nm,
|
||||
DenseVector<RealD>& Qt, // Nm x Nm matrix
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////
|
||||
void qr_decomp(std::vector<RealD>& lmd, // Nm
|
||||
std::vector<RealD>& lme, // Nm
|
||||
int Nk, int Nm, // Nk, Nm
|
||||
Eigen::MatrixXd& Qt, // Nm x Nm matrix
|
||||
RealD Dsh, int kmin, int kmax)
|
||||
{
|
||||
int k = kmin-1;
|
||||
@ -192,10 +382,10 @@ public:
|
||||
lme[k+1] = c*lme[k+1];
|
||||
|
||||
for(int i=0; i<Nk; ++i){
|
||||
RealD Qtmp1 = Qt[i+Nm*k ];
|
||||
RealD Qtmp2 = Qt[i+Nm*(k+1)];
|
||||
Qt[i+Nm*k ] = c*Qtmp1 - s*Qtmp2;
|
||||
Qt[i+Nm*(k+1)] = s*Qtmp1 + c*Qtmp2;
|
||||
RealD Qtmp1 = Qt(k,i);
|
||||
RealD Qtmp2 = Qt(k+1,i);
|
||||
Qt(k,i) = c*Qtmp1 - s*Qtmp2;
|
||||
Qt(k+1,i)= s*Qtmp1 + c*Qtmp2;
|
||||
}
|
||||
|
||||
// Givens transformations
|
||||
@ -220,25 +410,48 @@ public:
|
||||
}
|
||||
|
||||
for(int i=0; i<Nk; ++i){
|
||||
RealD Qtmp1 = Qt[i+Nm*k ];
|
||||
RealD Qtmp2 = Qt[i+Nm*(k+1)];
|
||||
Qt[i+Nm*k ] = c*Qtmp1 -s*Qtmp2;
|
||||
Qt[i+Nm*(k+1)] = s*Qtmp1 +c*Qtmp2;
|
||||
RealD Qtmp1 = Qt(k,i);
|
||||
RealD Qtmp2 = Qt(k+1,i);
|
||||
Qt(k,i) = c*Qtmp1 -s*Qtmp2;
|
||||
Qt(k+1,i) = s*Qtmp1 +c*Qtmp2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_LAPACK
|
||||
void diagonalize_lapack(DenseVector<RealD>& lmd,
|
||||
DenseVector<RealD>& lme,
|
||||
int N1,
|
||||
int N2,
|
||||
DenseVector<RealD>& Qt,
|
||||
void diagonalize(std::vector<RealD>& lmd, std::vector<RealD>& lme,
|
||||
int Nk, int Nm,
|
||||
Eigen::MatrixXd & Qt,
|
||||
GridBase *grid)
|
||||
{
|
||||
Qt = Eigen::MatrixXd::Identity(Nm,Nm);
|
||||
if ( diagonalisation == IRLdiagonaliseWithDSTEGR ) {
|
||||
diagonalize_lapack(lmd,lme,Nk,Nm,Qt,grid);
|
||||
} else if ( diagonalisation == IRLdiagonaliseWithQR ) {
|
||||
diagonalize_QR(lmd,lme,Nk,Nm,Qt,grid);
|
||||
} else if ( diagonalisation == IRLdiagonaliseWithEigen ) {
|
||||
diagonalize_Eigen(lmd,lme,Nk,Nm,Qt,grid);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_LAPACK
|
||||
void LAPACK_dstegr(char *jobz, char *range, int *n, double *d, double *e,
|
||||
double *vl, double *vu, int *il, int *iu, double *abstol,
|
||||
int *m, double *w, double *z, int *ldz, int *isuppz,
|
||||
double *work, int *lwork, int *iwork, int *liwork,
|
||||
int *info);
|
||||
#endif
|
||||
|
||||
void diagonalize_lapack(std::vector<RealD>& lmd,
|
||||
std::vector<RealD>& lme,
|
||||
int Nk, int Nm,
|
||||
Eigen::MatrixXd& Qt,
|
||||
GridBase *grid)
|
||||
{
|
||||
#ifdef USE_LAPACK
|
||||
const int size = Nm;
|
||||
int NN = N1;
|
||||
int NN = Nk;
|
||||
double evals_tmp[NN];
|
||||
double evec_tmp[NN][NN];
|
||||
memset(evec_tmp[0],0,sizeof(double)*NN*NN);
|
||||
@ -298,47 +511,28 @@ public:
|
||||
grid->GlobalSumVector((double*)evec_tmp,NN*NN);
|
||||
}
|
||||
}
|
||||
// cheating a bit.
|
||||
// It is better to sort instead of just reversing it,
|
||||
// Safer to sort instead of just reversing it,
|
||||
// but the document of the routine says evals are sorted in increasing order.
|
||||
// qr gives evals in decreasing order.
|
||||
for(int i=0;i<NN;i++){
|
||||
for(int j=0;j<NN;j++)
|
||||
Qt[(NN-1-i)*N2+j]=evec_tmp[i][j];
|
||||
lmd [NN-1-i]=evals_tmp[i];
|
||||
for(int j=0;j<NN;j++){
|
||||
Qt((NN-1-i),j)=evec_tmp[i][j];
|
||||
}
|
||||
}
|
||||
#else
|
||||
assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void diagonalize(DenseVector<RealD>& lmd,
|
||||
DenseVector<RealD>& lme,
|
||||
int N2,
|
||||
int N1,
|
||||
DenseVector<RealD>& Qt,
|
||||
void diagonalize_QR(std::vector<RealD>& lmd, std::vector<RealD>& lme,
|
||||
int Nk, int Nm,
|
||||
Eigen::MatrixXd & Qt,
|
||||
GridBase *grid)
|
||||
{
|
||||
|
||||
#ifdef USE_LAPACK
|
||||
const int check_lapack=0; // just use lapack if 0, check against lapack if 1
|
||||
|
||||
if(!check_lapack)
|
||||
return diagonalize_lapack(lmd,lme,N2,N1,Qt,grid);
|
||||
|
||||
DenseVector <RealD> lmd2(N1);
|
||||
DenseVector <RealD> lme2(N1);
|
||||
DenseVector<RealD> Qt2(N1*N1);
|
||||
for(int k=0; k<N1; ++k){
|
||||
lmd2[k] = lmd[k];
|
||||
lme2[k] = lme[k];
|
||||
}
|
||||
for(int k=0; k<N1*N1; ++k){
|
||||
Qt2[k] = Qt[k];
|
||||
}
|
||||
#endif
|
||||
|
||||
int Niter = 100*N1;
|
||||
int Niter = 100*Nm;
|
||||
int kmin = 1;
|
||||
int kmax = N2;
|
||||
int kmax = Nk;
|
||||
|
||||
// (this should be more sophisticated)
|
||||
for(int iter=0; iter<Niter; ++iter){
|
||||
@ -350,7 +544,7 @@ public:
|
||||
// (Dsh: shift)
|
||||
|
||||
// transformation
|
||||
qr_decomp(lmd,lme,N2,N1,Qt,Dsh,kmin,kmax);
|
||||
qr_decomp(lmd,lme,Nk,Nm,Qt,Dsh,kmin,kmax); // Nk, Nm
|
||||
|
||||
// Convergence criterion (redef of kmin and kamx)
|
||||
for(int j=kmax-1; j>= kmin; --j){
|
||||
@ -361,19 +555,6 @@ public:
|
||||
}
|
||||
}
|
||||
Niter = iter;
|
||||
#ifdef USE_LAPACK
|
||||
if(check_lapack){
|
||||
const double SMALL=1e-8;
|
||||
diagonalize_lapack(lmd2,lme2,N2,N1,Qt2,grid);
|
||||
DenseVector <RealD> lmd3(N2);
|
||||
for(int k=0; k<N2; ++k) lmd3[k]=lmd[k];
|
||||
_sort.push(lmd3,N2);
|
||||
_sort.push(lmd2,N2);
|
||||
for(int k=0; k<N2; ++k){
|
||||
if (fabs(lmd2[k] - lmd3[k]) >SMALL) std::cout <<"lmd(qr) lmd(lapack) "<< k << ": " << lmd2[k] <<" "<< lmd3[k] <<std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
|
||||
continued:
|
||||
@ -385,10 +566,34 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "[QL method] Error - Too many iteration: "<<Niter<<"\n";
|
||||
std::cout << GridLogError << "[QL method] Error - Too many iteration: "<<Niter<<"\n";
|
||||
abort();
|
||||
}
|
||||
|
||||
void diagonalize_Eigen(std::vector<RealD>& lmd, std::vector<RealD>& lme,
|
||||
int Nk, int Nm,
|
||||
Eigen::MatrixXd & Qt, // Nm x Nm
|
||||
GridBase *grid)
|
||||
{
|
||||
Eigen::MatrixXd TriDiag = Eigen::MatrixXd::Zero(Nk,Nk);
|
||||
|
||||
for(int i=0;i<Nk;i++) TriDiag(i,i) = lmd[i];
|
||||
for(int i=0;i<Nk-1;i++) TriDiag(i,i+1) = lme[i];
|
||||
for(int i=0;i<Nk-1;i++) TriDiag(i+1,i) = lme[i];
|
||||
|
||||
Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eigensolver(TriDiag);
|
||||
|
||||
for (int i = 0; i < Nk; i++) {
|
||||
lmd[Nk-1-i] = eigensolver.eigenvalues()(i);
|
||||
}
|
||||
for (int i = 0; i < Nk; i++) {
|
||||
for (int j = 0; j < Nk; j++) {
|
||||
Qt(Nk-1-i,j) = eigensolver.eigenvectors()(j,i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static RealD normalise(Field& v)
|
||||
{
|
||||
RealD nn = norm2(v);
|
||||
@ -397,23 +602,11 @@ public:
|
||||
return nn;
|
||||
}
|
||||
|
||||
void orthogonalize(Field& w,
|
||||
DenseVector<Field>& evec,
|
||||
int k)
|
||||
void orthogonalize(Field& w, std::vector<Field>& evec, int k)
|
||||
{
|
||||
typedef typename Field::scalar_type MyComplex;
|
||||
MyComplex ip;
|
||||
|
||||
if ( 0 ) {
|
||||
for(int j=0; j<k; ++j){
|
||||
normalise(evec[j]);
|
||||
for(int i=0;i<j;i++){
|
||||
ip = innerProduct(evec[i],evec[j]); // are the evecs normalised? ; this assumes so.
|
||||
evec[j] = evec[j] - ip *evec[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int j=0; j<k; ++j){
|
||||
ip = innerProduct(evec[j],w); // are the evecs normalised? ; this assumes so.
|
||||
w = w - ip * evec[j];
|
||||
@ -421,191 +614,6 @@ public:
|
||||
normalise(w);
|
||||
}
|
||||
|
||||
|
||||
void setUnit_Qt(int Nm, DenseVector<RealD> &Qt) {
|
||||
for(int i=0; i<Qt.size(); ++i) Qt[i] = 0.0;
|
||||
for(int k=0; k<Nm; ++k) Qt[k + k*Nm] = 1.0;
|
||||
}
|
||||
|
||||
/* Rudy Arthur's thesis pp.137
|
||||
------------------------
|
||||
Require: M > 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<RealD>& eval,
|
||||
DenseVector<Field>& evec,
|
||||
const Field& src,
|
||||
int& Nconv)
|
||||
{
|
||||
|
||||
GridBase *grid = evec[0]._grid;
|
||||
assert(grid == src._grid);
|
||||
|
||||
std::cout << " -- seek Nk = " << Nk <<" vectors"<< std::endl;
|
||||
std::cout << " -- accept Nstop = " << Nstop <<" vectors"<< std::endl;
|
||||
std::cout << " -- total Nm = " << Nm <<" vectors"<< 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<RealD> lme(Nm);
|
||||
DenseVector<RealD> lme2(Nm);
|
||||
DenseVector<RealD> eval2(Nm);
|
||||
DenseVector<RealD> Qt(Nm*Nm);
|
||||
DenseVector<int> Iconv(Nm);
|
||||
|
||||
DenseVector<Field> 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
|
||||
evec[0] = src;
|
||||
std:: cout <<"norm2(src)= " << norm2(src)<<std::endl;
|
||||
|
||||
normalise(evec[0]);
|
||||
std:: cout <<"norm2(evec[0])= " << norm2(evec[0]) <<std::endl;
|
||||
|
||||
// Initial Nk steps
|
||||
for(int k=0; k<Nk; ++k) step(eval,lme,evec,f,Nm,k);
|
||||
|
||||
// Restarting loop begins
|
||||
int iter;
|
||||
for(iter = 0; iter<Niter; ++iter){
|
||||
|
||||
std::cout<<"\n Restart iteration = "<< iter << std::endl;
|
||||
|
||||
for(int k=Nk; k<Nm; ++k) step(eval,lme,evec,f,Nm,k);
|
||||
|
||||
f *= lme[Nm-1];
|
||||
|
||||
// getting eigenvalues
|
||||
for(int k=0; k<Nm; ++k){
|
||||
eval2[k] = eval[k+k1-1];
|
||||
lme2[k] = lme[k+k1-1];
|
||||
}
|
||||
setUnit_Qt(Nm,Qt);
|
||||
diagonalize(eval2,lme2,Nm,Nm,Qt,grid);
|
||||
|
||||
// sorting
|
||||
_sort.push(eval2,Nm);
|
||||
|
||||
// Implicitly shifted QR transformations
|
||||
setUnit_Qt(Nm,Qt);
|
||||
for(int ip=k2; ip<Nm; ++ip){
|
||||
// std::cout << "qr_decomp "<< ip << " "<< eval2[ip] << std::endl;
|
||||
qr_decomp(eval,lme,Nm,Nm,Qt,eval2[ip],k1,Nm);
|
||||
}
|
||||
|
||||
for(int i=0; i<(Nk+1); ++i) B[i] = 0.0;
|
||||
|
||||
for(int j=k1-1; j<k2+1; ++j){
|
||||
for(int k=0; k<Nm; ++k){
|
||||
B[j].checkerboard = evec[k].checkerboard;
|
||||
B[j] += Qt[k+Nm*j] * evec[k];
|
||||
}
|
||||
}
|
||||
for(int j=k1-1; j<k2+1; ++j) evec[j] = B[j];
|
||||
|
||||
// Compressed vector f and beta(k2)
|
||||
f *= Qt[Nm-1+Nm*(k2-1)];
|
||||
f += lme[k2-1] * evec[k2];
|
||||
beta_k = norm2(f);
|
||||
beta_k = sqrt(beta_k);
|
||||
std::cout<<" beta(k) = "<<beta_k<<std::endl;
|
||||
|
||||
RealD betar = 1.0/beta_k;
|
||||
evec[k2] = betar * f;
|
||||
lme[k2-1] = beta_k;
|
||||
|
||||
// Convergence test
|
||||
for(int k=0; k<Nm; ++k){
|
||||
eval2[k] = eval[k];
|
||||
lme2[k] = lme[k];
|
||||
}
|
||||
setUnit_Qt(Nm,Qt);
|
||||
diagonalize(eval2,lme2,Nk,Nm,Qt,grid);
|
||||
|
||||
for(int k = 0; k<Nk; ++k) B[k]=0.0;
|
||||
|
||||
for(int j = 0; j<Nk; ++j){
|
||||
for(int k = 0; k<Nk; ++k){
|
||||
B[j].checkerboard = evec[k].checkerboard;
|
||||
B[j] += Qt[k+j*Nm] * evec[k];
|
||||
}
|
||||
}
|
||||
|
||||
Nconv = 0;
|
||||
for(int i=0; i<Nk; ++i){
|
||||
|
||||
_Linop.HermOp(B[i],v);
|
||||
|
||||
RealD vnum = real(innerProduct(B[i],v)); // HermOp.
|
||||
RealD vden = norm2(B[i]);
|
||||
eval2[i] = vnum/vden;
|
||||
v -= eval2[i]*B[i];
|
||||
RealD vv = norm2(v);
|
||||
|
||||
std::cout.precision(13);
|
||||
std::cout << "[" << std::setw(3)<< std::setiosflags(std::ios_base::right) <<i<<"] ";
|
||||
std::cout << "eval = "<<std::setw(25)<< std::setiosflags(std::ios_base::left)<< eval2[i];
|
||||
std::cout <<" |H B[i] - eval[i]B[i]|^2 "<< std::setw(25)<< std::setiosflags(std::ios_base::right)<< vv<< std::endl;
|
||||
|
||||
// change the criteria as evals are supposed to be sorted, all evals smaller(larger) than Nstop should have converged
|
||||
if((vv<eresid*eresid) && (i == Nconv) ){
|
||||
Iconv[Nconv] = i;
|
||||
++Nconv;
|
||||
}
|
||||
|
||||
} // i-loop end
|
||||
|
||||
std::cout<<" #modes converged: "<<Nconv<<std::endl;
|
||||
|
||||
if( Nconv>=Nstop ){
|
||||
goto converged;
|
||||
}
|
||||
} // end of iter loop
|
||||
|
||||
std::cout<<"\n NOT converged.\n";
|
||||
abort();
|
||||
|
||||
converged:
|
||||
// Sorting
|
||||
eval.resize(Nconv);
|
||||
evec.resize(Nconv,grid);
|
||||
for(int i=0; i<Nconv; ++i){
|
||||
eval[i] = eval2[Iconv[i]];
|
||||
evec[i] = B[Iconv[i]];
|
||||
}
|
||||
_sort.push(eval,evec,Nconv);
|
||||
|
||||
std::cout << "\n Converged\n Summary :\n";
|
||||
std::cout << " -- Iterations = "<< iter << "\n";
|
||||
std::cout << " -- beta(k) = "<< beta_k << "\n";
|
||||
std::cout << " -- Nconv = "<< Nconv << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -92,16 +92,15 @@ int main (int argc, char ** argv)
|
||||
|
||||
|
||||
std::vector<RealD> eval(Nm);
|
||||
FermionField src(FrbGrid); gaussian(RNG5rb,src);
|
||||
FermionField src(FrbGrid);
|
||||
gaussian(RNG5rb,src);
|
||||
std::vector<FermionField> evec(Nm,FrbGrid);
|
||||
for(int i=0;i<1;i++){
|
||||
std::cout << i<<" / "<< Nm<< " grid pointer "<<evec[i]._grid<<std::endl;
|
||||
std::cout << GridLogMessage <<i<<" / "<< Nm<< " grid pointer "<<evec[i]._grid<<std::endl;
|
||||
};
|
||||
|
||||
int Nconv;
|
||||
IRL.calc(eval,evec,
|
||||
src,
|
||||
Nconv);
|
||||
IRL.calc(eval,evec,src,Nconv);
|
||||
|
||||
|
||||
Grid_finalize();
|
||||
|
Loading…
x
Reference in New Issue
Block a user