2016-01-02 14:51:32 +00:00
/*************************************************************************************
Grid physics library , www . github . com / paboyle / Grid
Source file : . / lib / algorithms / iterative / ImplicitlyRestartedLanczos . h
Copyright ( C ) 2015
Author : Peter Boyle < paboyle @ ph . ed . ac . uk >
Author : paboyle < paboyle @ ph . ed . ac . uk >
2017-04-07 04:35:30 +01:00
Author : Chulwoo Jung < chulwoo @ bnl . gov >
2016-01-02 14:51:32 +00:00
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 */
2015-09-23 13:23:45 +01:00
# ifndef GRID_IRL_H
# define GRID_IRL_H
2016-01-11 16:36:45 +00:00
# include <string.h> //memset
2017-04-15 08:54:11 +01:00
2016-02-20 07:50:32 +00:00
# ifdef USE_LAPACK
2017-04-04 20:18:12 +01:00
# ifdef USE_MKL
# include <mkl_lapack.h>
# else
2016-10-31 16:31:27 +00:00
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 ) ;
2017-04-04 20:18:12 +01:00
//#include <lapacke/lapacke.h>
# endif
2016-02-20 07:50:32 +00:00
# endif
2017-04-15 08:54:11 +01:00
# include <Grid/algorithms/densematrix/DenseMatrix.h>
# include <Grid/algorithms/iterative/EigenSort.h>
2015-10-08 23:40:25 +01:00
2017-04-07 04:35:30 +01:00
// eliminate temorary vector in calc()
# define MEM_SAVE
2015-09-23 13:23:45 +01:00
namespace Grid {
2015-10-08 23:40:25 +01:00
/////////////////////////////////////////////////////////////
// Implicitly restarted lanczos
/////////////////////////////////////////////////////////////
2015-09-23 13:23:45 +01:00
2015-10-08 23:40:25 +01:00
template < class Field >
2015-09-23 13:23:45 +01:00
class ImplicitlyRestartedLanczos {
2015-10-08 23:40:25 +01:00
const RealD small = 1.0e-16 ;
public :
int lock ;
2015-11-29 00:32:45 +00:00
int get ;
2015-09-23 13:23:45 +01:00
int Niter ;
2015-11-29 00:32:45 +00:00
int converged ;
2015-10-08 23:40:25 +01:00
2016-01-11 16:36:45 +00:00
int Nstop ; // Number of evecs checked for convergence
2015-10-08 23:40:25 +01:00
int Nk ; // Number of converged sought
int Np ; // Np -- Number of spare vecs in kryloc space
int Nm ; // Nm -- total number of vectors
2017-04-04 20:18:12 +01:00
RealD OrthoTime ;
2015-10-08 23:40:25 +01:00
RealD eresid ;
SortEigen < Field > _sort ;
2015-09-23 13:23:45 +01:00
LinearOperatorBase < Field > & _Linop ;
2015-10-08 23:40:25 +01:00
2015-09-23 13:23:45 +01:00
OperatorFunction < Field > & _poly ;
2015-10-08 23:40:25 +01:00
/////////////////////////
// Constructor
/////////////////////////
void init ( void ) { } ;
void Abort ( int ff , DenseVector < RealD > & evals , DenseVector < DenseVector < RealD > > & evecs ) ;
2016-02-20 07:50:32 +00:00
ImplicitlyRestartedLanczos (
LinearOperatorBase < Field > & Linop , // op
2015-10-08 23:40:25 +01:00
OperatorFunction < Field > & poly , // polynmial
2016-01-11 16:36:45 +00:00
int _Nstop , // sought vecs
2015-10-08 23:40:25 +01:00
int _Nk , // sought vecs
int _Nm , // spare vecs
RealD _eresid , // resid in lmdue deficit
int _Niter ) : // Max iterations
_Linop ( Linop ) ,
2015-09-23 13:23:45 +01:00
_poly ( poly ) ,
2016-01-11 16:36:45 +00:00
Nstop ( _Nstop ) ,
2015-09-23 13:23:45 +01:00
Nk ( _Nk ) ,
2015-10-08 23:40:25 +01:00
Nm ( _Nm ) ,
eresid ( _eresid ) ,
Niter ( _Niter )
2015-09-23 13:23:45 +01:00
{
2015-10-08 23:40:25 +01:00
Np = Nm - Nk ; assert ( Np > 0 ) ;
2015-09-23 13:23:45 +01:00
} ;
2016-02-20 07:50:32 +00:00
ImplicitlyRestartedLanczos (
LinearOperatorBase < Field > & Linop , // op
OperatorFunction < Field > & poly , // polynmial
int _Nk , // sought vecs
int _Nm , // spare 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 )
{
Np = Nm - Nk ; assert ( Np > 0 ) ;
} ;
2015-10-08 23:40:25 +01:00
/////////////////////////
// Sanity checked this routine (step) against Saad.
/////////////////////////
void RitzMatrix ( DenseVector < Field > & evec , int k ) {
2015-11-29 00:32:45 +00:00
2015-10-08 23:40:25 +01:00
if ( 1 ) return ;
GridBase * grid = evec [ 0 ] . _grid ;
Field w ( grid ) ;
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " RitzMatrix " < < std : : endl ;
2015-10-08 23:40:25 +01:00
for ( int i = 0 ; i < k ; i + + ) {
_poly ( _Linop , evec [ i ] , w ) ;
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " [ " < < i < < " ] " ;
2015-10-08 23:40:25 +01:00
for ( int j = 0 ; j < k ; j + + ) {
ComplexD in = innerProduct ( evec [ j ] , w ) ;
if ( fabs ( ( double ) i - j ) > 1 ) {
if ( abs ( in ) > 1.0e-9 ) {
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " oops " < < std : : endl ;
2015-10-08 23:40:25 +01:00
abort ( ) ;
} else
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " 0 " ;
2015-10-08 23:40:25 +01:00
} else {
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " " < < in < < " " ;
2015-10-08 23:40:25 +01:00
}
}
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < std : : endl ;
2015-10-08 23:40:25 +01:00
}
}
2015-09-23 13:23:45 +01:00
2015-10-08 23:40:25 +01:00
/* 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 < RealD > & lmd ,
DenseVector < RealD > & lme ,
DenseVector < Field > & evec ,
2017-04-15 14:32:15 +01:00
Field & w , int Nm , int k , RealD & norm )
2015-09-23 13:23:45 +01:00
{
assert ( k < Nm ) ;
2015-10-08 23:40:25 +01:00
_poly ( _Linop , evec [ k ] , w ) ; // 3. wk:=Avk− βkv_{k− 1}
if ( k > 0 ) {
w - = lme [ k - 1 ] * evec [ k - 1 ] ;
}
2015-09-23 13:23:45 +01:00
2015-10-08 23:40:25 +01:00
ComplexD zalph = innerProduct ( evec [ k ] , w ) ; // 4. α k:=(wk,vk)
RealD alph = real ( zalph ) ;
2015-09-23 13:23:45 +01:00
2015-10-08 23:40:25 +01:00
w = w - alph * evec [ k ] ; // 5. wk:=wk− α kvk
2015-09-23 13:23:45 +01:00
2015-10-08 23:40:25 +01:00
RealD beta = normalise ( w ) ; // 6. βk+1 := ∥wk∥2. If βk+1 = 0 then Stop
// 7. vk+1 := wk/βk+1
2017-04-15 14:32:15 +01:00
norm = beta ;
2015-09-23 13:23:45 +01:00
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " alpha = " < < zalph < < " beta " < < beta < < std : : endl ;
2015-10-08 23:40:25 +01:00
const RealD tiny = 1.0e-20 ;
if ( beta < tiny ) {
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " beta is tiny " < < beta < < std : : endl ;
2016-01-11 16:36:45 +00:00
}
2015-10-08 23:40:25 +01:00
lmd [ k ] = alph ;
lme [ k ] = beta ;
2015-09-23 13:23:45 +01:00
2015-10-08 23:40:25 +01:00
if ( k > 0 ) {
orthogonalize ( w , evec , k ) ; // orthonormalise
2015-09-23 13:23:45 +01:00
}
2015-10-08 23:40:25 +01:00
if ( k < Nm - 1 ) evec [ k + 1 ] = w ;
2015-09-23 13:23:45 +01:00
}
2015-10-08 23:40:25 +01:00
void qr_decomp ( DenseVector < RealD > & lmd ,
DenseVector < RealD > & lme ,
2015-09-23 13:23:45 +01:00
int Nk ,
int Nm ,
2015-10-08 23:40:25 +01:00
DenseVector < RealD > & Qt ,
RealD Dsh ,
2015-09-23 13:23:45 +01:00
int kmin ,
int kmax )
{
int k = kmin - 1 ;
RealD x ;
2015-10-08 23:40:25 +01:00
RealD Fden = 1.0 / hypot ( lmd [ k ] - Dsh , lme [ k ] ) ;
2015-09-23 13:23:45 +01:00
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 ;
2015-10-08 23:40:25 +01:00
x = - s * lme [ k + 1 ] ;
2015-09-23 13:23:45 +01:00
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 ;
}
// Givens transformations
for ( int k = kmin ; k < kmax - 1 ; + + k ) {
2015-10-08 23:40:25 +01:00
RealD Fden = 1.0 / hypot ( x , lme [ k - 1 ] ) ;
2015-09-23 13:23:45 +01:00
RealD c = lme [ k - 1 ] * Fden ;
RealD s = - x * 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 ;
lme [ k - 1 ] = c * lme [ k - 1 ] - s * x ;
if ( k ! = kmax - 2 ) {
x = - s * lme [ k + 1 ] ;
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 ;
}
}
}
2016-02-20 07:50:32 +00:00
# ifdef USE_LAPACK
2017-05-18 23:33:47 +01:00
# ifdef USE_MKL
# define LAPACK_INT MKL_INT
# else
2017-04-04 20:18:12 +01:00
# define LAPACK_INT long long
2017-05-18 23:33:47 +01:00
# endif
2016-01-11 16:36:45 +00:00
void diagonalize_lapack ( DenseVector < RealD > & lmd ,
DenseVector < RealD > & lme ,
2016-02-20 07:50:32 +00:00
int N1 ,
int N2 ,
DenseVector < RealD > & Qt ,
GridBase * grid ) {
2016-01-11 16:36:45 +00:00
const int size = Nm ;
// tevals.resize(size);
// tevecs.resize(size);
2017-04-04 20:18:12 +01:00
LAPACK_INT NN = N1 ;
2016-01-11 16:36:45 +00:00
double evals_tmp [ NN ] ;
double evec_tmp [ NN ] [ NN ] ;
memset ( evec_tmp [ 0 ] , 0 , sizeof ( double ) * NN * NN ) ;
2016-01-25 06:26:25 +00:00
// double AA[NN][NN];
2016-01-11 16:36:45 +00:00
double DD [ NN ] ;
double EE [ NN ] ;
for ( int i = 0 ; i < NN ; i + + )
for ( int j = i - 1 ; j < = i + 1 ; j + + )
if ( j < NN & & j > = 0 ) {
if ( i = = j ) DD [ i ] = lmd [ i ] ;
if ( i = = j ) evals_tmp [ i ] = lmd [ i ] ;
if ( j = = ( i - 1 ) ) EE [ j ] = lme [ j ] ;
}
2017-04-04 20:18:12 +01:00
LAPACK_INT evals_found ;
LAPACK_INT lwork = ( ( 18 * NN ) > ( 1 + 4 * NN + NN * NN ) ? ( 18 * NN ) : ( 1 + 4 * NN + NN * NN ) ) ;
LAPACK_INT liwork = 3 + NN * 10 ;
LAPACK_INT iwork [ liwork ] ;
2016-01-11 16:36:45 +00:00
double work [ lwork ] ;
2017-04-04 20:18:12 +01:00
LAPACK_INT isuppz [ 2 * NN ] ;
2016-01-11 16:36:45 +00:00
char jobz = ' V ' ; // calculate evals & evecs
char range = ' I ' ; // calculate all evals
// char range = 'A'; // calculate all evals
char uplo = ' U ' ; // refer to upper half of original matrix
char compz = ' I ' ; // Compute eigenvectors of tridiagonal matrix
int ifail [ NN ] ;
2017-05-18 23:33:47 +01:00
LAPACK_INT info ;
2016-01-11 16:36:45 +00:00
// int total = QMP_get_number_of_nodes();
// int node = QMP_get_node_number();
2016-02-20 07:50:32 +00:00
// GridBase *grid = evec[0]._grid;
int total = grid - > _Nprocessors ;
int node = grid - > _processor ;
2016-01-11 16:36:45 +00:00
int interval = ( NN / total ) + 1 ;
double vl = 0.0 , vu = 0.0 ;
2017-04-04 20:18:12 +01:00
LAPACK_INT il = interval * node + 1 , iu = interval * ( node + 1 ) ;
2016-01-11 16:36:45 +00:00
if ( iu > NN ) iu = NN ;
double tol = 0.0 ;
if ( 1 ) {
memset ( evals_tmp , 0 , sizeof ( double ) * NN ) ;
if ( il < = NN ) {
printf ( " total=%d node=%d il=%d iu=%d \n " , total , node , il , iu ) ;
2017-04-04 20:18:12 +01:00
# ifdef USE_MKL
dstegr ( & jobz , & range , & NN ,
# else
2016-01-11 16:36:45 +00:00
LAPACK_dstegr ( & jobz , & range , & NN ,
2017-04-04 20:18:12 +01:00
# endif
2016-01-11 16:36:45 +00:00
( double * ) DD , ( double * ) EE ,
& vl , & vu , & il , & iu , // these four are ignored if second parameteris 'A'
& tol , // tolerance
& evals_found , evals_tmp , ( double * ) evec_tmp , & NN ,
isuppz ,
work , & lwork , iwork , & liwork ,
& info ) ;
for ( int i = iu - 1 ; i > = il - 1 ; i - - ) {
printf ( " node=%d evals_found=%d evals_tmp[%d] = %g \n " , node , evals_found , i - ( il - 1 ) , evals_tmp [ i - ( il - 1 ) ] ) ;
evals_tmp [ i ] = evals_tmp [ i - ( il - 1 ) ] ;
if ( il > 1 ) evals_tmp [ i - ( il - 1 ) ] = 0. ;
for ( int j = 0 ; j < NN ; j + + ) {
evec_tmp [ i ] [ j ] = evec_tmp [ i - ( il - 1 ) ] [ j ] ;
if ( il > 1 ) evec_tmp [ i - ( il - 1 ) ] [ j ] = 0. ;
}
}
}
{
// QMP_sum_double_array(evals_tmp,NN);
// QMP_sum_double_array((double *)evec_tmp,NN*NN);
2016-02-20 07:50:32 +00:00
grid - > GlobalSumVector ( evals_tmp , NN ) ;
grid - > GlobalSumVector ( ( double * ) evec_tmp , NN * NN ) ;
2016-01-11 16:36:45 +00:00
}
}
2016-02-20 07:50:32 +00:00
// cheating a bit. It is better 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.
2016-01-11 16:36:45 +00:00
for ( int i = 0 ; i < NN ; i + + ) {
for ( int j = 0 ; j < NN ; j + + )
2016-02-20 07:50:32 +00:00
Qt [ ( NN - 1 - i ) * N2 + j ] = evec_tmp [ i ] [ j ] ;
lmd [ NN - 1 - i ] = evals_tmp [ i ] ;
2016-01-11 16:36:45 +00:00
}
}
2017-04-04 20:18:12 +01:00
# undef LAPACK_INT
2016-02-20 07:50:32 +00:00
# endif
2016-01-11 16:36:45 +00:00
2015-10-08 23:40:25 +01:00
void diagonalize ( DenseVector < RealD > & lmd ,
DenseVector < RealD > & lme ,
2016-02-20 07:50:32 +00:00
int N2 ,
int N1 ,
DenseVector < RealD > & Qt ,
GridBase * grid )
2015-09-23 13:23:45 +01:00
{
2016-01-11 16:36:45 +00:00
2016-02-20 07:50:32 +00:00
# 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 ) {
2016-01-11 16:36:45 +00:00
lmd2 [ k ] = lmd [ k ] ;
lme2 [ k ] = lme [ k ] ;
}
2016-02-20 07:50:32 +00:00
for ( int k = 0 ; k < N1 * N1 ; + + k )
Qt2 [ k ] = Qt [ k ] ;
2016-01-11 16:36:45 +00:00
2016-02-20 07:50:32 +00:00
// diagonalize_lapack(lmd2,lme2,Nm2,Nm,Qt,grid);
# endif
2016-01-11 16:36:45 +00:00
2017-04-04 20:18:12 +01:00
int Niter = 10000 * N1 ;
2015-09-23 13:23:45 +01:00
int kmin = 1 ;
2016-02-20 07:50:32 +00:00
int kmax = N2 ;
2015-09-23 13:23:45 +01:00
// (this should be more sophisticated)
2017-04-04 20:18:12 +01:00
for ( int iter = 0 ; ; + + iter ) {
if ( ( iter + 1 ) % ( 100 * N1 ) = = 0 )
std : : cout < < GridLogMessage < < " [QL method] Not converged - iteration " < < iter + 1 < < " \n " ;
2015-09-23 13:23:45 +01:00
// determination of 2x2 leading submatrix
RealD dsub = lmd [ kmax - 1 ] - lmd [ kmax - 2 ] ;
RealD dd = sqrt ( dsub * dsub + 4.0 * lme [ kmax - 2 ] * lme [ kmax - 2 ] ) ;
RealD Dsh = 0.5 * ( lmd [ kmax - 2 ] + lmd [ kmax - 1 ] + dd * ( dsub / fabs ( dsub ) ) ) ;
// (Dsh: shift)
// transformation
2016-02-20 07:50:32 +00:00
qr_decomp ( lmd , lme , N2 , N1 , Qt , Dsh , kmin , kmax ) ;
2015-09-23 13:23:45 +01:00
// Convergence criterion (redef of kmin and kamx)
for ( int j = kmax - 1 ; j > = 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 ;
2016-02-20 07:50:32 +00:00
# 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 ) {
2017-04-04 20:18:12 +01:00
if ( fabs ( lmd2 [ k ] - lmd3 [ k ] ) > SMALL ) std : : cout < < GridLogMessage < < " lmd(qr) lmd(lapack) " < < k < < " : " < < lmd2 [ k ] < < " " < < lmd3 [ k ] < < std : : endl ;
// if (fabs(lme2[k] - lme[k]) >SMALL) std::cout<<GridLogMessage <<"lme(qr)-lme(lapack) "<< k << ": " << lme2[k] - lme[k] <<std::endl;
2016-02-20 07:50:32 +00:00
}
for ( int k = 0 ; k < N1 * N1 ; + + k ) {
2017-04-04 20:18:12 +01:00
// if (fabs(Qt2[k] - Qt[k]) >SMALL) std::cout<<GridLogMessage <<"Qt(qr)-Qt(lapack) "<< k << ": " << Qt2[k] - Qt[k] <<std::endl;
2016-02-20 07:50:32 +00:00
}
}
# endif
2015-09-23 13:23:45 +01:00
return ;
continued :
for ( int j = 0 ; j < kmax - 1 ; + + j ) {
RealD dds = fabs ( lmd [ j ] ) + fabs ( lmd [ j + 1 ] ) ;
if ( fabs ( lme [ j ] ) + dds > dds ) {
kmin = j + 1 ;
break ;
}
}
}
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " [QL method] Error - Too many iteration: " < < Niter < < " \n " ;
2015-09-23 13:23:45 +01:00
abort ( ) ;
}
2016-02-20 07:50:32 +00:00
# if 1
2015-10-08 23:40:25 +01:00
static RealD normalise ( Field & v )
{
RealD nn = norm2 ( v ) ;
nn = sqrt ( nn ) ;
v = v * ( 1.0 / nn ) ;
return nn ;
}
2015-09-23 13:23:45 +01:00
void orthogonalize ( Field & w ,
2015-10-08 23:40:25 +01:00
DenseVector < Field > & evec ,
2015-09-23 13:23:45 +01:00
int k )
{
2017-04-04 20:18:12 +01:00
double t0 = - usecond ( ) / 1e6 ;
2015-10-08 23:40:25 +01:00
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 ] ;
}
}
}
2015-09-23 13:23:45 +01:00
for ( int j = 0 ; j < k ; + + j ) {
2015-10-08 23:40:25 +01:00
ip = innerProduct ( evec [ j ] , w ) ; // are the evecs normalised? ; this assumes so.
w = w - ip * evec [ j ] ;
2015-09-23 13:23:45 +01:00
}
2015-10-08 23:40:25 +01:00
normalise ( w ) ;
2017-04-04 20:18:12 +01:00
t0 + = usecond ( ) / 1e6 ;
OrthoTime + = t0 ;
2015-09-23 13:23:45 +01:00
}
2015-10-08 23:40:25 +01:00
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 ;
}
2017-05-02 06:26:22 +01:00
// needs more memory
2017-05-05 00:32:00 +01:00
void Rotate0 (
int _Nm ,
2017-05-02 06:26:22 +01:00
DenseVector < RealD > & Qt ,
DenseVector < Field > & evec ,
2017-05-05 00:32:00 +01:00
//int k1, int k2
int j0 , int j1 ,
int _Nk
2017-05-02 06:26:22 +01:00
)
2017-05-05 00:32:00 +01:00
// void Rotate0( int Nm, DenseVector<RealD>& Qt, DenseVector<Field>& evec, int k1, int k2)
2017-05-02 06:26:22 +01:00
{
GridBase * grid = evec [ 0 ] . _grid ;
2017-05-05 00:32:00 +01:00
DenseVector < Field > B ( _Nm , grid ) ; // waste of space replicating
2017-05-02 06:26:22 +01:00
if ( 0 ) { // old implementation without blocking
2017-05-05 00:32:00 +01:00
for ( int i = 0 ; i < ( _Nm ) ; + + i ) B [ i ] = 0.0 ;
2017-05-02 06:26:22 +01:00
2017-05-05 00:32:00 +01:00
for ( int j = j0 ; j < j1 ; + + j ) {
for ( int k = 0 ; k < _Nm ; + + k ) {
2017-05-02 06:26:22 +01:00
B [ j ] . checkerboard = evec [ k ] . checkerboard ;
2017-05-05 00:32:00 +01:00
B [ j ] + = Qt [ k + _Nm * j ] * evec [ k ] ;
2017-05-02 06:26:22 +01:00
}
}
}
{
2017-05-05 00:32:00 +01:00
for ( int i = 0 ; i < ( _Nm ) ; + + i ) {
2017-05-02 06:26:22 +01:00
B [ i ] = 0.0 ;
B [ i ] . checkerboard = evec [ 0 ] . checkerboard ;
}
int j_block = 24 ; int k_block = 24 ;
PARALLEL_FOR_LOOP
for ( int ss = 0 ; ss < grid - > oSites ( ) ; ss + + ) {
2017-05-05 00:32:00 +01:00
for ( int jj = j0 ; jj < j1 ; jj + = j_block )
for ( int kk = 0 ; kk < _Nm ; kk + = k_block )
for ( int j = jj ; ( j < ( j1 ) ) & & j < ( jj + j_block ) ; + + j ) {
for ( int k = kk ; ( k < _Nm ) & & k < ( kk + k_block ) ; + + k ) {
B [ j ] . _odata [ ss ] + = Qt [ k + _Nm * j ] * evec [ k ] . _odata [ ss ] ;
2017-05-02 06:26:22 +01:00
}
}
}
}
2017-05-05 00:32:00 +01:00
for ( int j = j0 ; j < j1 ; + + j ) evec [ j ] = B [ j ] ;
2017-05-02 06:26:22 +01:00
}
2017-05-05 00:32:00 +01:00
void Rotate (
int _Nm ,
2017-05-02 06:26:22 +01:00
DenseVector < RealD > & Qt ,
DenseVector < Field > & evec ,
2017-05-05 00:32:00 +01:00
//int k1, int k2
int j0 , int j1 ,
int _Nk
2017-05-02 06:26:22 +01:00
)
{
GridBase * grid = evec [ 0 ] . _grid ;
2017-05-04 21:05:07 +01:00
typedef typename Field : : vector_object vobj ;
2017-05-05 00:32:00 +01:00
assert ( j0 > = 0 ) ;
assert ( j1 < _Nm ) ;
2017-05-04 21:05:07 +01:00
2017-05-02 06:26:22 +01:00
# pragma omp parallel
{
2017-05-04 21:05:07 +01:00
// int thr=GridThread::GetThreads();
// printf("thr=%d ss=%d me=%d\n",thr,ss,me);fflush(stdout);
// std::cout<<GridLogMessage << "GridThread::GetThreads() = " << thr << std::endl;
// std::cout<<GridLogMessage << "GridThread::GetThreads() = " << thr << "B.size()= "<< B.size() << std::endl;
2017-05-05 15:55:07 +01:00
std : : vector < vobj > B ( _Nm ) ;
2017-05-02 06:26:22 +01:00
# pragma omp for
for ( int ss = 0 ; ss < grid - > oSites ( ) ; ss + + ) {
2017-05-04 21:05:07 +01:00
// int me = GridThread::ThreadBarrier();
// assert(me <thr);
2017-05-05 00:32:00 +01:00
// for(int j=0; j<_Nm; ++j) B[j]=0.;
2017-05-05 15:55:07 +01:00
// zeroit(B);
for ( int j = j0 ; j < j1 ; + + j )
zeroit ( B [ j ] ) ;
2017-05-05 00:32:00 +01:00
for ( int j = j0 ; j < j1 ; + + j ) {
for ( int k = 0 ; k < _Nk ; + + k ) {
B [ j ] + = Qt [ k + _Nm * j ] * evec [ k ] . _odata [ ss ] ;
2017-05-02 06:26:22 +01:00
}
}
2017-05-05 00:32:00 +01:00
for ( int j = j0 ; j < j1 ; + + j ) {
2017-05-02 06:26:22 +01:00
evec [ j ] . _odata [ ss ] = B [ j ] ;
}
}
}
}
void Rotate2 (
int Nm ,
DenseVector < RealD > & Qt ,
DenseVector < Field > & evec ,
int k1 , int k2
)
{
GridBase * grid = evec [ 0 ] . _grid ;
int j_block = 24 ; int k_block = 24 ;
assert ( k2 < Nm ) ;
assert ( k1 > 0 ) ;
2017-05-04 21:05:07 +01:00
int thr = GridThread : : GetThreads ( ) ;
int n_field = 1 ;
int each = 1 ;
if ( ( Nm * thr ) > ( grid - > oSites ( ) ) ) {
each = ( grid - > oSites ( ) ) / Nm ;
n_field = thr / each + 1 ;
}
std : : cout < < GridLogMessage < < " thr = " < < thr < < " n_field= " < < n_field < < " each= " < < each < < std : : endl ;
DenseVector < Field > B ( n_field , grid ) ;
2017-05-02 06:26:22 +01:00
PARALLEL_FOR_LOOP
for ( int ss = 0 ; ss < grid - > oSites ( ) ; ss + + ) {
int me = GridThread : : ThreadBarrier ( ) ;
2017-05-04 21:05:07 +01:00
int i_field = me / each ;
int k_field = me % each ;
assert ( i_field < n_field ) ;
std : : cout < < GridLogMessage < < " me = " < < me < < " i_field= " < < i_field < < " k_field= " < < k_field < < std : : endl ;
2017-05-02 06:26:22 +01:00
// printf("thr=%d ss=%d me=%d\n",thr,ss,me);fflush(stdout);
2017-05-04 21:05:07 +01:00
// assert(Nm*thr<grid->oSites());
for ( int j = 0 ; j < Nm ; + + j ) B [ i_field ] . _odata [ j + Nm * k_field ] = 0. ;
2017-05-02 06:26:22 +01:00
for ( int j = k1 - 1 ; j < ( k2 + 1 ) ; + + j ) {
for ( int k = 0 ; k < Nm ; + + k ) {
2017-05-04 21:05:07 +01:00
B [ i_field ] . _odata [ j + Nm * k_field ] + = Qt [ k + Nm * j ] * evec [ k ] . _odata [ ss ] ;
2017-05-02 06:26:22 +01:00
}
}
for ( int j = k1 - 1 ; j < ( k2 + 1 ) ; + + j ) {
2017-05-04 21:05:07 +01:00
evec [ j ] . _odata [ ss ] = B [ i_field ] . _odata [ j + Nm * k_field ] ;
}
}
}
void ConvCheck0 ( int Nk , int Nm ,
DenseVector < RealD > & Qt ,
DenseVector < Field > & evec ,
DenseVector < RealD > & eval2 ,
DenseVector < int > & Iconv ,
int & Nconv )
{
GridBase * grid = evec [ 0 ] . _grid ;
DenseVector < Field > B ( Nm , grid ) ; // waste of space replicating
Field v ( grid ) ;
if ( 0 ) {
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 ] ;
}
std : : cout < < GridLogMessage < < " norm(B[ " < < j < < " ])= " < < norm2 ( B [ j ] ) < < std : : endl ;
}
}
if ( 1 ) {
for ( int i = 0 ; i < ( Nk + 1 ) ; + + i ) {
B [ i ] = 0.0 ;
B [ i ] . checkerboard = evec [ 0 ] . checkerboard ;
}
int j_block = 24 ; int k_block = 24 ;
PARALLEL_FOR_LOOP
for ( int ss = 0 ; ss < grid - > oSites ( ) ; ss + + ) {
for ( int jj = 0 ; jj < Nk ; jj + = j_block )
for ( int kk = 0 ; kk < Nk ; kk + = k_block )
for ( int j = jj ; ( j < Nk ) & & j < ( jj + j_block ) ; + + j ) {
for ( int k = kk ; ( k < Nk ) & & k < ( kk + k_block ) ; + + k ) {
B [ j ] . _odata [ ss ] + = Qt [ k + Nm * j ] * evec [ k ] . _odata [ ss ] ;
}
}
}
}
Nconv = 0 ;
// std::cout<<GridLogMessage << std::setiosflags(std::ios_base::scientific);
for ( int i = 0 ; i < Nk ; + + i ) {
// _poly(_Linop,B[i],v);
_Linop . HermOp ( B [ i ] , v ) ;
RealD vnum = real ( innerProduct ( B [ i ] , v ) ) ; // HermOp.
RealD vden = norm2 ( B [ i ] ) ;
RealD vv0 = norm2 ( v ) ;
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 : : cout < < " " < < vnum / ( sqrt ( vden ) * sqrt ( vv0 ) ) < < 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 << std::resetiosflags(std::ios_base::scientific);
}
2017-05-05 00:32:00 +01:00
void FinalCheck ( int Nk , int Nm ,
2017-05-18 23:33:47 +01:00
DenseVector < RealD > & eval ,
2017-05-05 00:32:00 +01:00
DenseVector < Field > & evec
)
{
GridBase * grid = evec [ 0 ] . _grid ;
Field v ( grid ) ;
Field B ( grid ) ;
for ( int j = 0 ; j < Nk ; + + j ) {
std : : cout < < GridLogMessage < < " norm(evec[ " < < j < < " ])= " < < norm2 ( evec [ j ] ) < < std : : endl ;
_Linop . HermOp ( evec [ j ] , v ) ;
RealD vnum = real ( innerProduct ( evec [ j ] , v ) ) ; // HermOp.
RealD vden = norm2 ( evec [ j ] ) ;
RealD vv0 = norm2 ( v ) ;
RealD eval2 = vnum / vden ;
v - = eval2 * evec [ j ] ;
RealD vv = norm2 ( v ) ;
std : : cout . precision ( 13 ) ;
std : : cout < < GridLogMessage < < " [ " < < std : : setw ( 3 ) < < std : : setiosflags ( std : : ios_base : : right ) < < j < < " ] " ;
std : : cout < < " eval = " < < std : : setw ( 25 ) < < std : : setiosflags ( std : : ios_base : : left ) < < eval2 ;
std : : cout < < " |H B[i] - eval[i]B[i]|^2 " < < std : : setw ( 25 ) < < std : : setiosflags ( std : : ios_base : : right ) < < vv ;
std : : cout < < " " < < vnum / ( sqrt ( vden ) * sqrt ( vv0 ) ) < < std : : endl ;
2017-05-18 23:33:47 +01:00
eval [ j ] = eval2 ;
2017-05-05 00:32:00 +01:00
}
}
2017-05-04 21:05:07 +01:00
void ConvCheck ( int Nk , int Nm ,
DenseVector < RealD > & Qt ,
DenseVector < Field > & evec ,
DenseVector < RealD > & eval2 ,
DenseVector < int > & Iconv ,
int & Nconv )
{
GridBase * grid = evec [ 0 ] . _grid ;
Field v ( grid ) ;
Field B ( grid ) ;
Nconv = 0 ;
for ( int j = 0 ; j < Nk ; + + j ) {
B = 0. ;
B . checkerboard = evec [ 0 ] . checkerboard ;
for ( int k = 0 ; k < Nk ; + + k ) {
B + = Qt [ k + j * Nm ] * evec [ k ] ;
}
std : : cout < < GridLogMessage < < " norm(B[ " < < j < < " ])= " < < norm2 ( B ) < < std : : endl ;
// _poly(_Linop,B,v);
_Linop . HermOp ( B , v ) ;
RealD vnum = real ( innerProduct ( B , v ) ) ; // HermOp.
RealD vden = norm2 ( B ) ;
RealD vv0 = norm2 ( v ) ;
eval2 [ j ] = vnum / vden ;
v - = eval2 [ j ] * B ;
RealD vv = norm2 ( v ) ;
std : : cout . precision ( 13 ) ;
std : : cout < < GridLogMessage < < " [ " < < std : : setw ( 3 ) < < std : : setiosflags ( std : : ios_base : : right ) < < j < < " ] " ;
std : : cout < < " eval = " < < std : : setw ( 25 ) < < std : : setiosflags ( std : : ios_base : : left ) < < eval2 [ j ] ;
std : : cout < < " |H B[i] - eval[i]B[i]|^2 " < < std : : setw ( 25 ) < < std : : setiosflags ( std : : ios_base : : right ) < < vv ;
std : : cout < < " " < < vnum / ( sqrt ( vden ) * sqrt ( vv0 ) ) < < 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 ) & & ( j = = Nconv ) ) {
Iconv [ Nconv ] = j ;
+ + Nconv ;
}
}
}
void ConvRotate2 ( int Nk , int Nm ,
DenseVector < RealD > & Qt ,
DenseVector < Field > & evec ,
DenseVector < RealD > & eval ,
DenseVector < RealD > & eval2 ,
DenseVector < int > & Iconv ,
int & Nconv )
{
GridBase * grid = evec [ 0 ] . _grid ;
int thr = GridThread : : GetThreads ( ) ;
for ( int i = 0 ; i < Nconv ; + + i )
eval [ i ] = eval2 [ Iconv [ i ] ] ;
// int thr=GridThread::GetThreads();
// printf("thr=%d\n",thr);
Field B ( grid ) ;
PARALLEL_FOR_LOOP
for ( int ss = 0 ; ss < grid - > oSites ( ) ; ss + + ) {
int me = GridThread : : ThreadBarrier ( ) ;
printf ( " thr=%d ss=%d me=%d \n " , thr , ss , me ) ; fflush ( stdout ) ;
assert ( ( Nm * thr ) < grid - > oSites ( ) ) ;
// auto B2 = evec[0]._odata[0];
// std::vector < decltype( B2 ) > B(Nm,B2);
for ( int j = 0 ; j < Nconv ; + + j ) B . _odata [ Iconv [ j ] + Nm * me ] = 0. ;
for ( int j = 0 ; j < Nconv ; + + j ) {
for ( int k = 0 ; k < Nk ; + + k ) {
B . _odata [ Iconv [ j ] + Nm * me ] + = Qt [ k + Nm * Iconv [ j ] ] * evec [ k ] . _odata [ ss ] ;
}
}
for ( int j = 0 ; j < Nconv ; + + j ) {
evec [ j ] . _odata [ ss ] = B . _odata [ Iconv [ j ] + Nm * me ] ;
2017-05-02 06:26:22 +01:00
}
}
}
2017-05-04 21:05:07 +01:00
void ConvRotate ( int Nk , int Nm ,
DenseVector < RealD > & Qt ,
DenseVector < Field > & evec ,
DenseVector < RealD > & eval ,
DenseVector < RealD > & eval2 ,
DenseVector < int > & Iconv ,
int & Nconv )
{
GridBase * grid = evec [ 0 ] . _grid ;
typedef typename Field : : vector_object vobj ;
# pragma omp parallel
{
std : : vector < vobj > B ( Nm ) ;
# pragma omp for
for ( int ss = 0 ; ss < grid - > oSites ( ) ; ss + + ) {
// for(int j=0; j<Nconv; ++j) B[j]=0.;
for ( int j = 0 ; j < Nconv ; + + j ) {
for ( int k = 0 ; k < Nk ; + + k ) {
B [ j ] + = Qt [ k + Nm * Iconv [ j ] ] * evec [ k ] . _odata [ ss ] ;
}
}
for ( int j = 0 ; j < Nconv ; + + j ) {
evec [ j ] . _odata [ ss ] = B [ j ] ;
}
}
}
for ( int i = 0 ; i < Nconv ; + + i ) eval [ i ] = eval2 [ Iconv [ i ] ] ;
}
2015-10-08 23:40:25 +01:00
/* 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
*/
2017-04-07 03:21:56 +01:00
// alternate implementation for minimizing memory usage. May affect the performance
2017-05-18 23:33:47 +01:00
void calc (
DenseVector < RealD > & eval ,
2015-10-08 23:40:25 +01:00
DenseVector < Field > & evec ,
const Field & src ,
2015-09-23 13:23:45 +01:00
int & Nconv )
{
2015-10-08 23:40:25 +01:00
GridBase * grid = evec [ 0 ] . _grid ;
2016-02-20 07:50:32 +00:00
assert ( grid = = src . _grid ) ;
2015-10-08 23:40:25 +01:00
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " -- Nk = " < < Nk < < " Np = " < < Np < < std : : endl ;
std : : cout < < GridLogMessage < < " -- Nm = " < < Nm < < std : : endl ;
std : : cout < < GridLogMessage < < " -- size of eval = " < < eval . size ( ) < < std : : endl ;
std : : cout < < GridLogMessage < < " -- size of evec = " < < evec . size ( ) < < std : : endl ;
2015-09-23 13:23:45 +01:00
2015-10-08 23:40:25 +01:00
assert ( Nm = = evec . size ( ) & & Nm = = eval . size ( ) ) ;
2015-09-23 13:23:45 +01:00
2015-10-08 23:40:25 +01:00
DenseVector < RealD > lme ( Nm ) ;
DenseVector < RealD > lme2 ( Nm ) ;
DenseVector < RealD > eval2 ( Nm ) ;
DenseVector < RealD > Qt ( Nm * Nm ) ;
DenseVector < int > Iconv ( Nm ) ;
2015-09-23 13:23:45 +01:00
2015-10-08 23:40:25 +01:00
Field f ( grid ) ;
Field v ( grid ) ;
2015-09-23 13:23:45 +01:00
int k1 = 1 ;
2015-10-08 23:40:25 +01:00
int k2 = Nk ;
Nconv = 0 ;
2015-09-23 13:23:45 +01:00
RealD beta_k ;
// Set initial vector
2015-10-08 23:40:25 +01:00
// (uniform vector) Why not src??
// evec[0] = 1.0;
evec [ 0 ] = src ;
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " norm2(src)= " < < norm2 ( src ) < < std : : endl ;
2016-02-20 07:50:32 +00:00
// << src._grid << std::endl;
2015-10-08 23:40:25 +01:00
normalise ( evec [ 0 ] ) ;
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " norm2(evec[0])= " < < norm2 ( evec [ 0 ] ) < < std : : endl ;
2016-02-20 07:50:32 +00:00
// << evec[0]._grid << std::endl;
2015-09-23 13:23:45 +01:00
// Initial Nk steps
2017-04-04 20:18:12 +01:00
OrthoTime = 0. ;
double t0 = usecond ( ) / 1e6 ;
2017-04-15 14:32:15 +01:00
RealD norm ; // sqrt norm of last vector
for ( int k = 0 ; k < Nk ; + + k ) step ( eval , lme , evec , f , Nm , k , norm ) ;
2017-04-04 20:18:12 +01:00
double t1 = usecond ( ) / 1e6 ;
std : : cout < < GridLogMessage < < " IRL::Initial steps: " < < t1 - t0 < < " seconds " < < std : : endl ; t0 = t1 ;
std : : cout < < GridLogMessage < < " IRL::Initial steps:OrthoTime " < < OrthoTime < < " seconds " < < std : : endl ;
// std:: cout<<GridLogMessage <<"norm2(evec[1])= " << norm2(evec[1]) << std::endl;
// std:: cout<<GridLogMessage <<"norm2(evec[2])= " << norm2(evec[2]) << std::endl;
2015-10-08 23:40:25 +01:00
RitzMatrix ( evec , Nk ) ;
2017-04-04 20:18:12 +01:00
t1 = usecond ( ) / 1e6 ;
std : : cout < < GridLogMessage < < " IRL::RitzMatrix: " < < t1 - t0 < < " seconds " < < std : : endl ; t0 = t1 ;
2016-01-11 16:36:45 +00:00
for ( int k = 0 ; k < Nk ; + + k ) {
2017-04-04 20:18:12 +01:00
// std:: cout<<GridLogMessage <<"eval " << k << " " <<eval[k] << std::endl;
// std:: cout<<GridLogMessage <<"lme " << k << " " << lme[k] << std::endl;
2016-01-11 16:36:45 +00:00
}
2015-10-08 23:40:25 +01:00
2015-09-23 13:23:45 +01:00
// Restarting loop begins
2015-10-08 23:40:25 +01:00
for ( int iter = 0 ; iter < Niter ; + + iter ) {
2015-09-23 13:23:45 +01:00
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " \n Restart iteration = " < < iter < < std : : endl ;
2015-10-08 23:40:25 +01:00
//
// Rudy does a sort first which looks very different. Getting fed up with sorting out the algo defs.
// We loop over
//
2017-04-04 20:18:12 +01:00
OrthoTime = 0. ;
2017-04-15 14:32:15 +01:00
for ( int k = Nk ; k < Nm ; + + k ) step ( eval , lme , evec , f , Nm , k , norm ) ;
2017-04-04 20:18:12 +01:00
t1 = usecond ( ) / 1e6 ;
std : : cout < < GridLogMessage < < " IRL:: " < < Np < < " steps: " < < t1 - t0 < < " seconds " < < std : : endl ; t0 = t1 ;
std : : cout < < GridLogMessage < < " IRL::Initial steps:OrthoTime " < < OrthoTime < < " seconds " < < std : : endl ;
2015-09-23 13:23:45 +01:00
f * = lme [ Nm - 1 ] ;
2015-10-08 23:40:25 +01:00
RitzMatrix ( evec , k2 ) ;
2017-04-04 20:18:12 +01:00
t1 = usecond ( ) / 1e6 ;
std : : cout < < GridLogMessage < < " IRL:: RitzMatrix: " < < t1 - t0 < < " seconds " < < std : : endl ; t0 = t1 ;
2015-09-23 13:23:45 +01:00
// getting eigenvalues
2015-10-08 23:40:25 +01:00
for ( int k = 0 ; k < Nm ; + + k ) {
eval2 [ k ] = eval [ k + k1 - 1 ] ;
2015-09-23 13:23:45 +01:00
lme2 [ k ] = lme [ k + k1 - 1 ] ;
}
setUnit_Qt ( Nm , Qt ) ;
2016-02-20 07:50:32 +00:00
diagonalize ( eval2 , lme2 , Nm , Nm , Qt , grid ) ;
2017-04-04 20:18:12 +01:00
t1 = usecond ( ) / 1e6 ;
std : : cout < < GridLogMessage < < " IRL:: diagonalize: " < < t1 - t0 < < " seconds " < < std : : endl ; t0 = t1 ;
2017-04-15 14:32:15 +01:00
int prelNconv = 0 ;
for ( int k = 0 ; k < Nm ; + + k ) { //check all k's because QR can permutate eigenvectors
std : : cout < < GridLogMessage < < " IRL:: Prel. conv. Test " < < k < < " " < < norm < < " " < < fabs ( Qt [ Nm - 1 + Nm * k ] ) < < std : : endl ;
// Arbitrarily add factor of 10 for now, to be conservative
if ( norm * fabs ( Qt [ Nm - 1 + Nm * k ] ) < eresid * 10 ) prelNconv + + ;
}
2015-10-08 23:40:25 +01:00
2015-09-23 13:23:45 +01:00
// sorting
2015-10-08 23:40:25 +01:00
_sort . push ( eval2 , Nm ) ;
2017-04-04 20:18:12 +01:00
t1 = usecond ( ) / 1e6 ;
std : : cout < < GridLogMessage < < " IRL:: eval sorting: " < < t1 - t0 < < " seconds " < < std : : endl ; t0 = t1 ;
2015-09-23 13:23:45 +01:00
// Implicitly shifted QR transformations
setUnit_Qt ( Nm , Qt ) ;
2017-04-04 20:18:12 +01:00
for ( int ip = 0 ; ip < k2 ; + + ip ) {
std : : cout < < GridLogMessage < < " eval " < < ip < < " " < < eval2 [ ip ] < < std : : endl ;
}
2016-01-11 16:36:45 +00:00
for ( int ip = k2 ; ip < Nm ; + + ip ) {
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " qr_decomp " < < ip < < " " < < eval2 [ ip ] < < std : : endl ;
2015-10-08 23:40:25 +01:00
qr_decomp ( eval , lme , Nm , Nm , Qt , eval2 [ ip ] , k1 , Nm ) ;
2016-01-11 16:36:45 +00:00
}
2017-04-04 20:18:12 +01:00
t1 = usecond ( ) / 1e6 ;
std : : cout < < GridLogMessage < < " IRL::qr_decomp: " < < t1 - t0 < < " seconds " < < std : : endl ; t0 = t1 ;
2017-04-15 14:32:15 +01:00
2017-04-07 03:21:56 +01:00
assert ( k2 < Nm ) ;
2017-05-04 21:05:07 +01:00
// Uses more temorary
// Rotate0(Nm,Qt,evec,k1,k2);
// Uses minimal temporary, possibly with less speed
2017-05-05 00:32:00 +01:00
// Rotate(Nm,Qt,evec,k1,k2);
Rotate ( Nm , Qt , evec , k1 - 1 , k2 + 1 , Nm ) ;
2017-05-04 21:05:07 +01:00
// Try if Rotate() doesn't work
// Rotate2(Nm,Qt,evec,k1,k2);
2017-04-04 20:18:12 +01:00
t1 = usecond ( ) / 1e6 ;
std : : cout < < GridLogMessage < < " IRL::QR rotation: " < < t1 - t0 < < " seconds " < < std : : endl ; t0 = t1 ;
2015-09-23 13:23:45 +01:00
// Compressed vector f and beta(k2)
f * = Qt [ Nm - 1 + Nm * ( k2 - 1 ) ] ;
f + = lme [ k2 - 1 ] * evec [ k2 ] ;
2015-10-08 23:40:25 +01:00
beta_k = norm2 ( f ) ;
2015-09-23 13:23:45 +01:00
beta_k = sqrt ( beta_k ) ;
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " beta(k) = " < < beta_k < < std : : endl ;
2015-09-23 13:23:45 +01:00
RealD betar = 1.0 / beta_k ;
evec [ k2 ] = betar * f ;
lme [ k2 - 1 ] = beta_k ;
// Convergence test
2015-10-08 23:40:25 +01:00
for ( int k = 0 ; k < Nm ; + + k ) {
eval2 [ k ] = eval [ k ] ;
2015-09-23 13:23:45 +01:00
lme2 [ k ] = lme [ k ] ;
}
setUnit_Qt ( Nm , Qt ) ;
2016-02-20 07:50:32 +00:00
diagonalize ( eval2 , lme2 , Nk , Nm , Qt , grid ) ;
2017-04-04 20:18:12 +01:00
t1 = usecond ( ) / 1e6 ;
std : : cout < < GridLogMessage < < " IRL::diagonalize: " < < t1 - t0 < < " seconds " < < std : : endl ; t0 = t1 ;
2015-09-23 13:23:45 +01:00
2017-04-15 14:32:15 +01:00
if ( prelNconv < Nstop )
std : : cout < < GridLogMessage < < " Prel. Convergence test ( " < < prelNconv < < " ) failed, skipping a real(and expnesive) one " < < std : : endl ;
else
2017-05-04 21:05:07 +01:00
// ConvCheck0( Nk, Nm, Qt, evec, eval2, Iconv, Nconv);
ConvCheck ( Nk , Nm , Qt , evec , eval2 , Iconv , Nconv ) ;
2017-04-04 20:18:12 +01:00
t1 = usecond ( ) / 1e6 ;
std : : cout < < GridLogMessage < < " IRL::convergence testing: " < < t1 - t0 < < " seconds " < < std : : endl ; t0 = t1 ;
2015-09-23 13:23:45 +01:00
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " #modes converged: " < < Nconv < < std : : endl ;
2015-09-23 13:23:45 +01:00
2016-01-11 16:36:45 +00:00
if ( Nconv > = Nstop ) {
2015-09-23 13:23:45 +01:00
goto converged ;
}
} // end of iter loop
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " \n NOT converged. \n " ;
2015-09-23 13:23:45 +01:00
abort ( ) ;
converged :
2016-03-30 08:16:02 +01:00
// Sorting
eval . resize ( Nconv ) ;
2017-04-07 04:35:30 +01:00
# ifndef MEM_SAVE
2017-04-15 14:32:15 +01:00
evec . resize ( Nconv , grid ) ;
2016-03-30 08:16:02 +01:00
for ( int i = 0 ; i < Nconv ; + + i ) {
eval [ i ] = eval2 [ Iconv [ i ] ] ;
evec [ i ] = B [ Iconv [ i ] ] ;
}
2017-04-07 03:21:56 +01:00
# else
2017-05-04 21:05:07 +01:00
// ConvRotate0( Nk, Nm, Qt, evec, eval,eval2,Iconv,Nconv);
2017-05-24 23:57:32 +01:00
ConvRotate ( Nk , Nm , Qt , evec , eval , eval2 , Iconv , Nconv ) ;
2017-05-05 00:32:00 +01:00
// ConvCheck only counts Iconv[j]=j. ignore Iconv[]
2017-05-24 23:57:32 +01:00
// Rotate0(Nm,Qt,evec,0,Nk,Nk);
2017-05-18 23:33:47 +01:00
FinalCheck ( Nk , Nm , eval , evec ) ;
2017-05-05 15:55:07 +01:00
//exit(-1);
2017-05-04 21:05:07 +01:00
// ConvRotate2( Nk, Nm, Qt, evec, eval,eval2,Iconv,Nconv);
2017-04-07 03:21:56 +01:00
# endif
2017-05-19 15:49:09 +01:00
// Skip sorting, as it doubles the memory usage(!) and can be avoided by diagonalizing "right away"
// _sort.push(eval,evec,Nconv);
2016-03-30 08:16:02 +01:00
2017-04-04 20:18:12 +01:00
std : : cout < < GridLogMessage < < " \n Converged \n Summary : \n " ;
std : : cout < < GridLogMessage < < " -- Iterations = " < < Nconv < < " \n " ;
std : : cout < < GridLogMessage < < " -- beta(k) = " < < beta_k < < " \n " ;
std : : cout < < GridLogMessage < < " -- Nconv = " < < Nconv < < " \n " ;
2016-03-30 08:16:02 +01:00
}
2015-10-08 23:40:25 +01:00
void EigenSort ( DenseVector < double > evals ,
DenseVector < Field > evecs ) {
int N = evals . size ( ) ;
_sort . push ( evals , evecs , evals . size ( ) , N ) ;
}
/**
There is some matrix Q such that for any vector y
Q . e_1 = y and Q is unitary .
* */
template < class T >
static T orthQ ( DenseMatrix < T > & Q , DenseVector < T > y ) {
int N = y . size ( ) ; //Matrix Size
Fill ( Q , 0.0 ) ;
T tau ;
for ( int i = 0 ; i < N ; i + + ) {
Q [ i ] [ 0 ] = y [ i ] ;
}
T sig = conj ( y [ 0 ] ) * y [ 0 ] ;
2017-04-15 14:32:15 +01:00
T tau0 = fabs ( sqrt ( sig ) ) ;
2015-10-08 23:40:25 +01:00
for ( int j = 1 ; j < N ; j + + ) {
sig + = conj ( y [ j ] ) * y [ j ] ;
tau = abs ( sqrt ( sig ) ) ;
if ( abs ( tau0 ) > 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 < T > & Q , DenseVector < T > 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 1 st colum
and the matrix is upper hessenberg
and with f and Q appropriately modidied with Q is the arnoldi factorization
* */
template < class T >
2017-04-04 20:18:12 +01:00
static void Lock ( DenseMatrix < T > & H , ///Hess mtx
DenseMatrix < T > & Q , ///Lock Transform
T val , ///value to be locked
int con , ///number already locked
2015-10-08 23:40:25 +01:00
RealD small ,
int dfg ,
bool herm )
{
//ForceTridiagonal(H);
int M = H . dim ;
DenseVector < T > vec ; Resize ( vec , M - con ) ;
DenseMatrix < T > AH ; Resize ( AH , M - con , M - con ) ;
AH = GetSubMtx ( H , con , M , con , M ) ;
DenseMatrix < T > QQ ; Resize ( QQ , M - con , M - con ) ;
Unity ( Q ) ; Unity ( QQ ) ;
DenseVector < T > evals ; Resize ( evals , M - con ) ;
DenseMatrix < T > evecs ; Resize ( evecs , M - con , M - con ) ;
Wilkinson < T > ( AH , evals , evecs , small ) ;
int k = 0 ;
RealD cold = abs ( val - evals [ k ] ) ;
for ( int i = 1 ; i < M - con ; i + + ) {
RealD cnew = abs ( val - evals [ i ] ) ;
if ( cnew < cold ) { k = i ; cold = cnew ; }
}
vec = evecs [ k ] ;
ComplexD tau ;
orthQ ( QQ , vec ) ;
//orthQM(QQ,AH,vec);
AH = Hermitian ( QQ ) * AH ;
AH = AH * QQ ;
for ( int i = con ; i < M ; i + + ) {
for ( int j = con ; j < M ; j + + ) {
Q [ i ] [ j ] = QQ [ i - con ] [ j - con ] ;
H [ i ] [ j ] = AH [ i - con ] [ j - con ] ;
}
}
for ( int j = M - 1 ; j > con + 2 ; j - - ) {
DenseMatrix < T > U ; Resize ( U , j - 1 - con , j - 1 - con ) ;
DenseVector < T > z ; Resize ( z , j - 1 - con ) ;
T nm = norm ( z ) ;
for ( int k = con + 0 ; k < j - 1 ; k + + ) {
z [ k - con ] = conj ( H ( j , k + 1 ) ) ;
}
normalise ( z ) ;
RealD tmp = 0 ;
for ( int i = 0 ; i < z . size ( ) - 1 ; i + + ) { tmp = tmp + abs ( z [ i ] ) ; }
if ( tmp < small / ( ( RealD ) z . size ( ) - 1.0 ) ) { continue ; }
tau = orthU ( U , z ) ;
DenseMatrix < T > Hb ; Resize ( Hb , j - 1 - con , M ) ;
for ( int a = 0 ; a < M ; a + + ) {
for ( int b = 0 ; b < j - 1 - con ; b + + ) {
T sum = 0 ;
for ( int c = 0 ; c < j - 1 - con ; c + + ) {
sum + = H [ a ] [ con + 1 + c ] * U [ c ] [ b ] ;
} //sum += H(a,con+1+c)*U(c,b);}
Hb [ b ] [ a ] = sum ;
}
}
for ( int k = con + 1 ; k < j ; k + + ) {
for ( int l = 0 ; l < M ; l + + ) {
H [ l ] [ k ] = Hb [ k - 1 - con ] [ l ] ;
}
} //H(Hb[k-1-con][l] , l,k);}}
DenseMatrix < T > Qb ; Resize ( Qb , M , M ) ;
for ( int a = 0 ; a < M ; a + + ) {
for ( int b = 0 ; b < j - 1 - con ; b + + ) {
T sum = 0 ;
for ( int c = 0 ; c < j - 1 - con ; c + + ) {
sum + = Q [ a ] [ con + 1 + c ] * U [ c ] [ b ] ;
} //sum += Q(a,con+1+c)*U(c,b);}
Qb [ b ] [ a ] = sum ;
}
}
for ( int k = con + 1 ; k < j ; k + + ) {
for ( int l = 0 ; l < M ; l + + ) {
Q [ l ] [ k ] = Qb [ k - 1 - con ] [ l ] ;
}
} //Q(Qb[k-1-con][l] , l,k);}}
DenseMatrix < T > Hc ; Resize ( Hc , M , M ) ;
for ( int a = 0 ; a < j - 1 - con ; a + + ) {
for ( int b = 0 ; b < M ; b + + ) {
T sum = 0 ;
for ( int c = 0 ; c < j - 1 - con ; c + + ) {
sum + = conj ( U [ c ] [ a ] ) * H [ con + 1 + c ] [ b ] ;
} //sum += conj( U(c,a) )*H(con+1+c,b);}
Hc [ b ] [ a ] = sum ;
}
}
for ( int k = 0 ; k < M ; k + + ) {
for ( int l = con + 1 ; l < j ; l + + ) {
H [ l ] [ k ] = Hc [ k ] [ l - 1 - con ] ;
}
} //H(Hc[k][l-1-con] , l,k);}}
}
}
2016-02-20 07:50:32 +00:00
# endif
2015-10-08 23:40:25 +01:00
} ;
2015-09-23 13:23:45 +01:00
}
# endif
2015-11-29 00:32:45 +00:00