Grid 0.7.0
ImplicitlyRestartedLanczos.h
Go to the documentation of this file.
1 /*************************************************************************************
2
3 Grid physics library, www.github.com/paboyle/Grid
4
5 Source file: ./lib/algorithms/iterative/ImplicitlyRestartedLanczos.h
6
7 Copyright (C) 2015
8
9Author: Peter Boyle <paboyle@ph.ed.ac.uk>
10Author: paboyle <paboyle@ph.ed.ac.uk>
11Author: Chulwoo Jung <chulwoo@bnl.gov>
12Author: Christoph Lehner <clehner@bnl.gov>
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License along
25 with this program; if not, write to the Free Software Foundation, Inc.,
26 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27
28 See the full license in the file "LICENSE" in the top level distribution directory
29 *************************************************************************************/
30 /* END LEGAL */
31#ifndef GRID_BIRL_H
32#define GRID_BIRL_H
33
34#include <string.h> //memset
35//#include <zlib.h>
36#include <sys/stat.h>
37
39
41// Implicitly restarted lanczos
43template<class Field> class ImplicitlyRestartedLanczosTester
44{
45 public:
46 virtual int TestConvergence(int j,RealD resid,Field &evec, RealD &eval,RealD evalMaxApprox)=0;
47 virtual int ReconstructEval(int j,RealD resid,Field &evec, RealD &eval,RealD evalMaxApprox)=0;
48};
49
55
57{
58 public:
59
62 int ReconstructEval(int j,RealD resid,Field &B, RealD &eval,RealD evalMaxApprox)
63 {
64 return TestConvergence(j,resid,B,eval,evalMaxApprox);
65 }
66 int TestConvergence(int j,RealD eresid,Field &B, RealD &eval,RealD evalMaxApprox)
67 {
68 Field v(B);
69 RealD eval_poly = eval;
70 // Apply operator
71 _HermOp(B,v);
72
73 RealD vnum = real(innerProduct(B,v)); // HermOp.
74 RealD vden = norm2(B);
75 RealD vv0 = norm2(v);
76 eval = vnum/vden;
77 v -= eval*B;
78
79 RealD vv = norm2(v) / ::pow(evalMaxApprox,2.0);
80
81 std::cout.precision(13);
82
83 int conv=0;
84 if( (vv<eresid*eresid) ) conv = 1;
85
86 std::cout<<GridLogIRL << "[" << std::setw(3)<<j<<"] "
87 <<"eval = "<<std::setw(25)<< eval << " (" << eval_poly << ")"
88 <<" |H B[i] - eval[i]B[i]|^2 / evalMaxApprox^2 " << std::setw(25) << vv
89 <<" target " << eresid*eresid << " conv " <<conv
90 <<std::endl;
91
92 return conv;
93 }
94};
95
96template<class Field>
98 private:
99 const RealD small = 1.0e-8;
101 int MinRestart; // Minimum number of restarts; only check for convergence after
102 int Nstop; // Number of evecs checked for convergence
103 int Nk; // Number of converged sought
104 // int Np; // Np -- Number of spare vecs in krylov space // == Nm - Nk
105 int Nm; // Nm -- total number of vectors
108
112 // Embedded objects
117 // Default tester provided (we need a ref to something in default case)
120 // Constructor
122
123public:
124
126 // PAB:
128 // Too many options & knobs.
129 // Eliminate:
130 // orth_period
131 // betastp
132 // MinRestart
133 //
134 // Do we really need orth_period
135 // What is the theoretical basis & guarantees of betastp ?
136 // Nstop=Nk viable?
137 // MinRestart avoidable with new convergence test?
138 // Could cut to PolyOp, HermOp, Tester, Nk, Nm, resid, maxiter (+diagonalisation)
139 // HermOp could be eliminated if we dropped the Power method for max eval.
140 // -- also: The eval, eval2, eval2_copy stuff is still unnecessarily unclear
143 LinearFunction<Field> & HermOp,
145 int _Nstop, // sought vecs
146 int _Nk, // sought vecs
147 int _Nm, // spare vecs
148 RealD _eresid, // resid in lmdue deficit
149 int _MaxIter, // Max iterations
150 RealD _betastp=0.0, // if beta(k) < betastp: converged
151 int _MinRestart=0, int _orth_period = 1,
153 SimpleTester(HermOp), _PolyOp(PolyOp), _HermOp(HermOp), _Tester(Tester),
154 Nstop(_Nstop) , Nk(_Nk), Nm(_Nm),
155 eresid(_eresid), betastp(_betastp),
156 MaxIter(_MaxIter) , MinRestart(_MinRestart),
157 orth_period(_orth_period), diagonalisation(_diagonalisation) { };
158
160 LinearFunction<Field> & HermOp,
161 int _Nstop, // sought vecs
162 int _Nk, // sought vecs
163 int _Nm, // spare vecs
164 RealD _eresid, // resid in lmdue deficit
165 int _MaxIter, // Max iterations
166 RealD _betastp=0.0, // if beta(k) < betastp: converged
167 int _MinRestart=0, int _orth_period = 1,
169 SimpleTester(HermOp), _PolyOp(PolyOp), _HermOp(HermOp), _Tester(SimpleTester),
170 Nstop(_Nstop) , Nk(_Nk), Nm(_Nm),
171 eresid(_eresid), betastp(_betastp),
172 MaxIter(_MaxIter) , MinRestart(_MinRestart),
173 orth_period(_orth_period), diagonalisation(_diagonalisation) { };
174
176 // Helpers
178 template<typename T> static RealD normalise(T& v)
179 {
180 RealD nn = norm2(v);
181 nn = std::sqrt(nn);
182 v = v * (1.0/nn);
183 return nn;
184 }
185
186 void orthogonalize(Field& w, std::vector<Field>& evec,int k)
187 {
188 OrthoTime-=usecond()/1e6;
189 basisOrthogonalize(evec,w,k);
190 normalise(w);
191 OrthoTime+=usecond()/1e6;
192 }
193
194/* Rudy Arthur's thesis pp.137
195------------------------
196Require: M > K P = M − K †
197Compute the factorization AVM = VM HM + fM eM
198repeat
199 Q=I
200 for i = 1,...,P do
201 QiRi =HM −θiI Q = QQi
202 H M = Q †i H M Q i
203 end for
204 βK =HM(K+1,K) σK =Q(M,K)
205 r=vK+1βK +rσK
206 VK =VM(1:M)Q(1:M,1:K)
207 HK =HM(1:K,1:K)
208 →AVK =VKHK +fKe†K † Extend to an M = K + P step factorization AVM = VMHM + fMeM
209until convergence
210*/
211 void calc(std::vector<RealD>& eval, std::vector<Field>& evec, const Field& src, int& Nconv, bool reverse=false)
212 {
213 GridBase *grid = src.Grid();
214 assert(grid == evec[0].Grid());
215
216 // GridLogIRL.TimingMode(1);
217 std::cout << GridLogIRL <<"**************************************************************************"<< std::endl;
218 std::cout << GridLogIRL <<" ImplicitlyRestartedLanczos::calc() starting iteration 0 / "<< MaxIter<< std::endl;
219 std::cout << GridLogIRL <<"**************************************************************************"<< std::endl;
220 std::cout << GridLogIRL <<" -- seek Nk = " << Nk <<" vectors"<< std::endl;
221 std::cout << GridLogIRL <<" -- accept Nstop = " << Nstop <<" vectors"<< std::endl;
222 std::cout << GridLogIRL <<" -- total Nm = " << Nm <<" vectors"<< std::endl;
223 std::cout << GridLogIRL <<" -- size of eval = " << eval.size() << std::endl;
224 std::cout << GridLogIRL <<" -- size of evec = " << evec.size() << std::endl;
226 std::cout << GridLogIRL << "Diagonalisation is DSTEGR "<<std::endl;
227 } else if ( diagonalisation == IRLdiagonaliseWithQR ) {
228 std::cout << GridLogIRL << "Diagonalisation is QR "<<std::endl;
229 } else if ( diagonalisation == IRLdiagonaliseWithEigen ) {
230 std::cout << GridLogIRL << "Diagonalisation is Eigen "<<std::endl;
231 }
232 std::cout << GridLogIRL <<"**************************************************************************"<< std::endl;
233
234 assert(Nm <= evec.size() && Nm <= eval.size());
235
236 // quickly get an idea of the largest eigenvalue to more properly normalize the residuum
237 RealD evalMaxApprox = 0.0;
238 {
239 auto src_n = src;
240 auto tmp = src;
241 std::cout << GridLogIRL << " IRL source norm " << norm2(src) << std::endl;
242 const int _MAX_ITER_IRL_MEVAPP_ = 50;
243 for (int i=0;i<_MAX_ITER_IRL_MEVAPP_;i++) {
244 normalise(src_n);
245 _HermOp(src_n,tmp);
246 // std::cout << GridLogMessage<< tmp<<std::endl; exit(0);
247 // std::cout << GridLogIRL << " _HermOp " << norm2(tmp) << std::endl;
248// RealD vnum = real(innerProduct(src_n,tmp)); // HermOp.
249 RealD vnum = real(innerProduct(tmp,tmp)); // HermOp^2.
250 RealD vden = norm2(src_n);
251 RealD na = std::sqrt(vnum/vden);
252 if (fabs(evalMaxApprox/na - 1.0) < 0.0001)
253 i=_MAX_ITER_IRL_MEVAPP_;
254 evalMaxApprox = na;
255 std::cout << GridLogIRL << " Approximation of largest eigenvalue: " << evalMaxApprox << std::endl;
256 src_n = tmp;
257 }
258 }
259 std::cout << GridLogIRL << " Final evalMaxApprox " << evalMaxApprox << std::endl;
260
261 std::vector<RealD> lme(Nm);
262 std::vector<RealD> lme2(Nm);
263 std::vector<RealD> eval2(Nm);
264 std::vector<RealD> eval2_copy(Nm);
265 Eigen::MatrixXd Qt = Eigen::MatrixXd::Zero(Nm,Nm);
266
267 Field f(grid);
268 Field v(grid);
269 int k1 = 1;
270 int k2 = Nk;
271 RealD beta_k;
272
273 Nconv = 0;
274
275 // Set initial vector
276 evec[0] = src;
277 normalise(evec[0]);
278
279 // Initial Nk steps
280 OrthoTime=0.;
281 for(int k=0; k<Nk; ++k) step(eval,lme,evec,f,Nm,k);
282 std::cout<<GridLogIRL <<"Initial "<< Nk <<"steps done "<<std::endl;
283 std::cout<<GridLogIRL <<"Initial steps:OrthoTime "<<OrthoTime<< "seconds"<<std::endl;
284
286 // Restarting loop begins
288 int iter;
289 for(iter = 0; iter<MaxIter; ++iter){
290
291 OrthoTime=0.;
292
293 std::cout<< GridLogMessage <<" **********************"<< std::endl;
294 std::cout<< GridLogMessage <<" Restart iteration = "<< iter << std::endl;
295 std::cout<< GridLogMessage <<" **********************"<< std::endl;
296
297 std::cout<<GridLogIRL <<" running "<<Nm-Nk <<" steps: "<<std::endl;
298 for(int k=Nk; k<Nm; ++k) step(eval,lme,evec,f,Nm,k);
299 f *= lme[Nm-1];
300
301 std::cout<<GridLogIRL <<" "<<Nm-Nk <<" steps done "<<std::endl;
302 std::cout<<GridLogIRL <<"Initial steps:OrthoTime "<<OrthoTime<< "seconds"<<std::endl;
303
305 // getting eigenvalues
307 for(int k=0; k<Nm; ++k){
308 eval2[k] = eval[k+k1-1];
309 lme2[k] = lme[k+k1-1];
310 }
311 Qt = Eigen::MatrixXd::Identity(Nm,Nm);
312 diagonalize(eval2,lme2,Nm,Nm,Qt,grid);
313 std::cout<<GridLogIRL <<" diagonalized "<<std::endl;
314
316 // sorting
318 eval2_copy = eval2;
319 std::partial_sort(eval2.begin(),eval2.begin()+Nm,eval2.end(),std::greater<RealD>());
320 std::cout<<GridLogIRL <<" evals sorted "<<std::endl;
321 const int chunk=8;
322 for(int io=0; io<k2;io+=chunk){
323 std::cout<<GridLogIRL << "eval "<< std::setw(3) << io ;
324 for(int ii=0;ii<chunk;ii++){
325 if ( (io+ii)<k2 )
326 std::cout<< " "<< std::setw(12)<< eval2[io+ii];
327 }
328 std::cout << std::endl;
329 }
330
332 // Implicitly shifted QR transformations
334 Qt = Eigen::MatrixXd::Identity(Nm,Nm);
335 for(int ip=k2; ip<Nm; ++ip){
336 QR_decomp(eval,lme,Nm,Nm,Qt,eval2[ip],k1,Nm);
337 }
338 std::cout<<GridLogIRL <<"QR decomposed "<<std::endl;
339
340 assert(k2<Nm); assert(k2<Nm); assert(k1>0);
341
342 basisRotate(evec,Qt,k1-1,k2+1,0,Nm,Nm);
343 std::cout<<GridLogIRL <<"basisRotated by Qt *"<<k1-1<<","<<k2+1<<")"<<std::endl;
344
346 // Compressed vector f and beta(k2)
348 f *= Qt(k2-1,Nm-1);
349 f += lme[k2-1] * evec[k2];
350 beta_k = norm2(f);
351 beta_k = std::sqrt(beta_k);
352 std::cout<<GridLogIRL<<" beta(k) = "<<beta_k<<std::endl;
353
354 RealD betar = 1.0/beta_k;
355 evec[k2] = betar * f;
356 lme[k2-1] = beta_k;
357
359 // Convergence test
361 for(int k=0; k<Nm; ++k){
362 eval2[k] = eval[k];
363 lme2[k] = lme[k];
364 }
365 Qt = Eigen::MatrixXd::Identity(Nm,Nm);
366 diagonalize(eval2,lme2,Nk,Nm,Qt,grid);
367 std::cout<<GridLogIRL <<" Diagonalized "<<std::endl;
368
369 Nconv = 0;
370 if (iter >= MinRestart) {
371
372 std::cout << GridLogIRL << "Test convergence: rotate subset of vectors to test convergence " << std::endl;
373
374 Field B(grid); B.Checkerboard() = evec[0].Checkerboard();
375
376 // power of two search pattern; not every evalue in eval2 is assessed.
377 int allconv =1;
378 for(int jj = 1; jj<=Nstop; jj*=2){
379 int j = Nstop-jj;
380 RealD e = eval2_copy[j]; // Discard the evalue
381 basisRotateJ(B,evec,Qt,j,0,Nk,Nm);
382 if( !_Tester.TestConvergence(j,eresid,B,e,evalMaxApprox) ) {
383 allconv=0;
384 }
385 }
386 // Do evec[0] for good measure
387 {
388 int j=0;
389 RealD e = eval2_copy[0];
390 basisRotateJ(B,evec,Qt,j,0,Nk,Nm);
391 if( !_Tester.TestConvergence(j,eresid,B,e,evalMaxApprox) ) allconv=0;
392 }
393 if ( allconv ) Nconv = Nstop;
394
395 // test if we converged, if so, terminate
396 std::cout<<GridLogIRL<<" #modes converged: >= "<<Nconv<<"/"<<Nstop<<std::endl;
397 // if( Nconv>=Nstop || beta_k < betastp){
398 if( Nconv>=Nstop){
399 goto converged;
400 }
401
402 } else {
403 std::cout << GridLogIRL << "iter < MinRestart: do not yet test for convergence\n";
404 } // end of iter loop
405 }
406
407 std::cout<<GridLogError<<"\n NOT converged.\n";
408 abort();
409
410 converged:
411 {
412 Field B(grid); B.Checkerboard() = evec[0].Checkerboard();
413 basisRotate(evec,Qt,0,Nk,0,Nk,Nm);
414 std::cout << GridLogIRL << " Rotated basis"<<std::endl;
415 Nconv=0;
417 // Full final convergence test; unconditionally applied
419 for(int j = 0; j<=Nk; j++){
420 B=evec[j];
421 if( _Tester.ReconstructEval(j,eresid,B,eval2[j],evalMaxApprox) ) {
422 Nconv++;
423 }
424 }
425
426 if ( Nconv < Nstop ) {
427 std::cout << GridLogIRL << "Nconv ("<<Nconv<<") < Nstop ("<<Nstop<<")"<<std::endl;
428 std::cout << GridLogIRL << "returning Nstop vectors, the last "<< Nstop-Nconv << "of which might meet convergence criterion only approximately" <<std::endl;
429 }
430 eval=eval2;
431
432 //Keep only converged
433 eval.resize(Nstop);// was Nconv
434 evec.resize(Nstop,grid);// was Nconv
435 basisSortInPlace(evec,eval,reverse);
436
437 }
438
439 std::cout << GridLogIRL <<"**************************************************************************"<< std::endl;
440 std::cout << GridLogIRL << "ImplicitlyRestartedLanczos CONVERGED ; Summary :\n";
441 std::cout << GridLogIRL <<"**************************************************************************"<< std::endl;
442 std::cout << GridLogIRL << " -- Iterations = "<< iter << "\n";
443 std::cout << GridLogIRL << " -- beta(k) = "<< beta_k << "\n";
444 std::cout << GridLogIRL << " -- Nconv = "<< Nconv << "\n";
445 std::cout << GridLogIRL <<"**************************************************************************"<< std::endl;
446 }
447
448 private:
449/* Saad PP. 195
4501. Choose an initial vector v1 of 2-norm unity. Set β1 ≡ 0, v0 ≡ 0
4512. For k = 1,2,...,m Do:
4523. wk:=Avk - b_k v_{k-1}
4534. ak:=(wk,vk) //
4545. wk:=wk-akvk // wk orthog vk
4556. bk+1 := ||wk||_2. If b_k+1 = 0 then Stop
4567. vk+1 := wk/b_k+1
4578. EndDo
458 */
459 void step(std::vector<RealD>& lmd,
460 std::vector<RealD>& lme,
461 std::vector<Field>& evec,
462 Field& w,int Nm,int k)
463 {
464 std::cout<<GridLogDebug << "Lanczos step " <<k<<std::endl;
465 const RealD tiny = 1.0e-20;
466 assert( k< Nm );
467
468 GridStopWatch gsw_op,gsw_o;
469
470 Field& evec_k = evec[k];
471
472 _PolyOp(evec_k,w); std::cout<<GridLogDebug << "PolyOp" <<std::endl;
473
474 if(k>0) w -= lme[k-1] * evec[k-1];
475
476 ComplexD zalph = innerProduct(evec_k,w);
477 RealD alph = real(zalph);
478
479 w = w - alph * evec_k;
480
481 RealD beta = normalise(w);
482
483 lmd[k] = alph;
484 lme[k] = beta;
485
486 if ( (k>0) && ( (k % orth_period) == 0 )) {
487 std::cout<<GridLogDebug << "Orthogonalising " <<k<<std::endl;
488 orthogonalize(w,evec,k); // orthonormalise
489 std::cout<<GridLogDebug << "Orthogonalised " <<k<<std::endl;
490 }
491
492 if(k < Nm-1) evec[k+1] = w;
493
494 std::cout<<GridLogIRL << "Lanczos step alpha[" << k << "] = " << zalph << " beta[" << k << "] = "<<beta<<std::endl;
495 if ( beta < tiny )
496 std::cout<<GridLogIRL << " beta is tiny "<<beta<<std::endl;
497
498 std::cout<<GridLogDebug << "Lanczos step complete " <<k<<std::endl;
499 }
500
501 void diagonalize_Eigen(std::vector<RealD>& lmd, std::vector<RealD>& lme,
502 int Nk, int Nm,
503 Eigen::MatrixXd & Qt, // Nm x Nm
504 GridBase *grid)
505 {
506 Eigen::MatrixXd TriDiag = Eigen::MatrixXd::Zero(Nk,Nk);
507
508 for(int i=0;i<Nk;i++) TriDiag(i,i) = lmd[i];
509 for(int i=0;i<Nk-1;i++) TriDiag(i,i+1) = lme[i];
510 for(int i=0;i<Nk-1;i++) TriDiag(i+1,i) = lme[i];
511
512 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eigensolver(TriDiag);
513
514 for (int i = 0; i < Nk; i++) {
515 lmd[Nk-1-i] = eigensolver.eigenvalues()(i);
516 }
517 for (int i = 0; i < Nk; i++) {
518 for (int j = 0; j < Nk; j++) {
519 Qt(Nk-1-i,j) = eigensolver.eigenvectors()(j,i);
520 }
521 }
522 }
523
525 // File could end here if settle on Eigen ??? !!!
527 void QR_decomp(std::vector<RealD>& lmd, // Nm
528 std::vector<RealD>& lme, // Nm
529 int Nk, int Nm, // Nk, Nm
530 Eigen::MatrixXd& Qt, // Nm x Nm matrix
531 RealD Dsh, int kmin, int kmax)
532 {
533 int k = kmin-1;
534 RealD x;
535
536 RealD Fden = 1.0/hypot(lmd[k]-Dsh,lme[k]);
537 RealD c = ( lmd[k] -Dsh) *Fden;
538 RealD s = -lme[k] *Fden;
539
540 RealD tmpa1 = lmd[k];
541 RealD tmpa2 = lmd[k+1];
542 RealD tmpb = lme[k];
543
544 lmd[k] = c*c*tmpa1 +s*s*tmpa2 -2.0*c*s*tmpb;
545 lmd[k+1] = s*s*tmpa1 +c*c*tmpa2 +2.0*c*s*tmpb;
546 lme[k] = c*s*(tmpa1-tmpa2) +(c*c-s*s)*tmpb;
547 x =-s*lme[k+1];
548 lme[k+1] = c*lme[k+1];
549
550 for(int i=0; i<Nk; ++i){
551 RealD Qtmp1 = Qt(k,i);
552 RealD Qtmp2 = Qt(k+1,i);
553 Qt(k,i) = c*Qtmp1 - s*Qtmp2;
554 Qt(k+1,i)= s*Qtmp1 + c*Qtmp2;
555 }
556
557 // Givens transformations
558 for(int k = kmin; k < kmax-1; ++k){
559
560 RealD Fden = 1.0/hypot(x,lme[k-1]);
561 RealD c = lme[k-1]*Fden;
562 RealD s = - x*Fden;
563
564 RealD tmpa1 = lmd[k];
565 RealD tmpa2 = lmd[k+1];
566 RealD tmpb = lme[k];
567
568 lmd[k] = c*c*tmpa1 +s*s*tmpa2 -2.0*c*s*tmpb;
569 lmd[k+1] = s*s*tmpa1 +c*c*tmpa2 +2.0*c*s*tmpb;
570 lme[k] = c*s*(tmpa1-tmpa2) +(c*c-s*s)*tmpb;
571 lme[k-1] = c*lme[k-1] -s*x;
572
573 if(k != kmax-2){
574 x = -s*lme[k+1];
575 lme[k+1] = c*lme[k+1];
576 }
577
578 for(int i=0; i<Nk; ++i){
579 RealD Qtmp1 = Qt(k,i);
580 RealD Qtmp2 = Qt(k+1,i);
581 Qt(k,i) = c*Qtmp1 -s*Qtmp2;
582 Qt(k+1,i) = s*Qtmp1 +c*Qtmp2;
583 }
584 }
585 }
586
587 void diagonalize(std::vector<RealD>& lmd, std::vector<RealD>& lme,
588 int Nk, int Nm,
589 Eigen::MatrixXd & Qt,
590 GridBase *grid)
591 {
592 Qt = Eigen::MatrixXd::Identity(Nm,Nm);
594 diagonalize_lapack(lmd,lme,Nk,Nm,Qt,grid);
595 } else if ( diagonalisation == IRLdiagonaliseWithQR ) {
596 diagonalize_QR(lmd,lme,Nk,Nm,Qt,grid);
597 } else if ( diagonalisation == IRLdiagonaliseWithEigen ) {
598 diagonalize_Eigen(lmd,lme,Nk,Nm,Qt,grid);
599 } else {
600 assert(0);
601 }
602 }
603
604#ifdef USE_LAPACK
605void LAPACK_dstegr(char *jobz, char *range, int *n, double *d, double *e,
606 double *vl, double *vu, int *il, int *iu, double *abstol,
607 int *m, double *w, double *z, int *ldz, int *isuppz,
608 double *work, int *lwork, int *iwork, int *liwork,
609 int *info);
610#endif
611
612void diagonalize_lapack(std::vector<RealD>& lmd,
613 std::vector<RealD>& lme,
614 int Nk, int Nm,
615 Eigen::MatrixXd& Qt,
616 GridBase *grid)
617{
618#ifdef USE_LAPACK
619 const int size = Nm;
620 int NN = Nk;
621 double evals_tmp[NN];
622 double evec_tmp[NN][NN];
623 memset(evec_tmp[0],0,sizeof(double)*NN*NN);
624 double DD[NN];
625 double EE[NN];
626 for (int i = 0; i< NN; i++) {
627 for (int j = i - 1; j <= i + 1; j++) {
628 if ( j < NN && j >= 0 ) {
629 if (i==j) DD[i] = lmd[i];
630 if (i==j) evals_tmp[i] = lmd[i];
631 if (j==(i-1)) EE[j] = lme[j];
632 }
633 }
634 }
635 int evals_found;
636 int lwork = ( (18*NN) > (1+4*NN+NN*NN)? (18*NN):(1+4*NN+NN*NN)) ;
637 int liwork = 3+NN*10 ;
638 int iwork[liwork];
639 double work[lwork];
640 int isuppz[2*NN];
641 char jobz = 'V'; // calculate evals & evecs
642 char range = 'I'; // calculate all evals
643 // char range = 'A'; // calculate all evals
644 char uplo = 'U'; // refer to upper half of original matrix
645 char compz = 'I'; // Compute eigenvectors of tridiagonal matrix
646 int ifail[NN];
647 int info;
648 int total = grid->_Nprocessors;
649 int node = grid->_processor;
650 int interval = (NN/total)+1;
651 double vl = 0.0, vu = 0.0;
652 int il = interval*node+1 , iu = interval*(node+1);
653 if (iu > NN) iu=NN;
654 double tol = 0.0;
655 if (1) {
656 memset(evals_tmp,0,sizeof(double)*NN);
657 if ( il <= NN){
658 LAPACK_dstegr(&jobz, &range, &NN,
659 (double*)DD, (double*)EE,
660 &vl, &vu, &il, &iu, // these four are ignored if second parameteris 'A'
661 &tol, // tolerance
662 &evals_found, evals_tmp, (double*)evec_tmp, &NN,
663 isuppz,
664 work, &lwork, iwork, &liwork,
665 &info);
666 for (int i = iu-1; i>= il-1; i--){
667 evals_tmp[i] = evals_tmp[i - (il-1)];
668 if (il>1) evals_tmp[i-(il-1)]=0.;
669 for (int j = 0; j< NN; j++){
670 evec_tmp[i][j] = evec_tmp[i - (il-1)][j];
671 if (il>1) evec_tmp[i-(il-1)][j]=0.;
672 }
673 }
674 }
675 {
676 grid->GlobalSumVector(evals_tmp,NN);
677 grid->GlobalSumVector((double*)evec_tmp,NN*NN);
678 }
679 }
680 // Safer to sort instead of just reversing it,
681 // but the document of the routine says evals are sorted in increasing order.
682 // qr gives evals in decreasing order.
683 for(int i=0;i<NN;i++){
684 lmd [NN-1-i]=evals_tmp[i];
685 for(int j=0;j<NN;j++){
686 Qt((NN-1-i),j)=evec_tmp[i][j];
687 }
688 }
689#else
690 assert(0);
691#endif
692}
693
694void diagonalize_QR(std::vector<RealD>& lmd, std::vector<RealD>& lme,
695 int Nk, int Nm,
696 Eigen::MatrixXd & Qt,
697 GridBase *grid)
698{
699 int QRiter = 100*Nm;
700 int kmin = 1;
701 int kmax = Nk;
702
703 // (this should be more sophisticated)
704 for(int iter=0; iter<QRiter; ++iter){
705
706 // determination of 2x2 leading submatrix
707 RealD dsub = lmd[kmax-1]-lmd[kmax-2];
708 RealD dd = std::sqrt(dsub*dsub + 4.0*lme[kmax-2]*lme[kmax-2]);
709 RealD Dsh = 0.5*(lmd[kmax-2]+lmd[kmax-1] +dd*(dsub/fabs(dsub)));
710 // (Dsh: shift)
711
712 // transformation
713 QR_decomp(lmd,lme,Nk,Nm,Qt,Dsh,kmin,kmax); // Nk, Nm
714
715 // Convergence criterion (redef of kmin and kamx)
716 for(int j=kmax-1; j>= kmin; --j){
717 RealD dds = fabs(lmd[j-1])+fabs(lmd[j]);
718 if(fabs(lme[j-1])+dds > dds){
719 kmax = j+1;
720 goto continued;
721 }
722 }
723 QRiter = iter;
724 return;
725
726 continued:
727 for(int j=0; j<kmax-1; ++j){
728 RealD dds = fabs(lmd[j])+fabs(lmd[j+1]);
729 if(fabs(lme[j])+dds > dds){
730 kmin = j+1;
731 break;
732 }
733 }
734 }
735 std::cout << GridLogError << "[QL method] Error - Too many iteration: "<<QRiter<<"\n";
736 abort();
737}
738};
739
741#endif
@ IRLdiagonaliseWithEigen
@ IRLdiagonaliseWithDSTEGR
B
accelerator_inline sobj eval(const uint64_t ss, const sobj &arg)
Definition Lattice_ET.h:103
void basisRotate(VField &basis, Matrix &Qt, int j0, int j1, int k0, int k1, int Nm)
void basisOrthogonalize(std::vector< Field > &basis, Field &w, int k)
void basisSortInPlace(std::vector< Field > &_v, std::vector< RealD > &sort_vals, bool reverse)
void basisRotateJ(Field &result, std::vector< Field > &basis, Eigen::MatrixXd &Qt, int j, int k0, int k1, int Nm)
Lattice< vobj > real(const Lattice< vobj > &lhs)
ComplexD innerProduct(const Lattice< vobj > &left, const Lattice< vobj > &right)
RealD norm2(const Lattice< vobj > &arg)
Lattice< obj > pow(const Lattice< obj > &rhs_i, RealD y)
GridLogger GridLogError(1, "Error", GridLogColours, "RED")
GridLogger GridLogIRL(1, "IRL", GridLogColours, "NORMAL")
GridLogger GridLogDebug(1, "Debug", GridLogColours, "PURPLE")
GridLogger GridLogMessage(1, "Message", GridLogColours, "NORMAL")
#define NAMESPACE_BEGIN(A)
Definition Namespace.h:35
#define NAMESPACE_END(A)
Definition Namespace.h:36
std::complex< RealD > ComplexD
Definition Simd.h:79
double RealD
Definition Simd.h:61
double usecond(void)
Definition Timer.h:50
void GlobalSumVector(RealF *, int N)
int TestConvergence(int j, RealD eresid, Field &B, RealD &eval, RealD evalMaxApprox)
ImplicitlyRestartedLanczosHermOpTester(LinearFunction< Field > &HermOp)
int ReconstructEval(int j, RealD resid, Field &B, RealD &eval, RealD evalMaxApprox)
virtual int TestConvergence(int j, RealD resid, Field &evec, RealD &eval, RealD evalMaxApprox)=0
virtual int ReconstructEval(int j, RealD resid, Field &evec, RealD &eval, RealD evalMaxApprox)=0
ImplicitlyRestartedLanczosTester< Field > & _Tester
void diagonalize(std::vector< RealD > &lmd, std::vector< RealD > &lme, int Nk, int Nm, Eigen::MatrixXd &Qt, GridBase *grid)
void diagonalize_Eigen(std::vector< RealD > &lmd, std::vector< RealD > &lme, int Nk, int Nm, Eigen::MatrixXd &Qt, GridBase *grid)
ImplicitlyRestartedLanczos(LinearFunction< Field > &PolyOp, LinearFunction< Field > &HermOp, ImplicitlyRestartedLanczosTester< Field > &Tester, int _Nstop, int _Nk, int _Nm, RealD _eresid, int _MaxIter, RealD _betastp=0.0, int _MinRestart=0, int _orth_period=1, IRLdiagonalisation _diagonalisation=IRLdiagonaliseWithEigen)
void QR_decomp(std::vector< RealD > &lmd, std::vector< RealD > &lme, int Nk, int Nm, Eigen::MatrixXd &Qt, RealD Dsh, int kmin, int kmax)
void diagonalize_lapack(std::vector< RealD > &lmd, std::vector< RealD > &lme, int Nk, int Nm, Eigen::MatrixXd &Qt, GridBase *grid)
void diagonalize_QR(std::vector< RealD > &lmd, std::vector< RealD > &lme, int Nk, int Nm, Eigen::MatrixXd &Qt, GridBase *grid)
void orthogonalize(Field &w, std::vector< Field > &evec, int k)
void step(std::vector< RealD > &lmd, std::vector< RealD > &lme, std::vector< Field > &evec, Field &w, int Nm, int k)
void calc(std::vector< RealD > &eval, std::vector< Field > &evec, const Field &src, int &Nconv, bool reverse=false)
ImplicitlyRestartedLanczos(LinearFunction< Field > &PolyOp, LinearFunction< Field > &HermOp, int _Nstop, int _Nk, int _Nm, RealD _eresid, int _MaxIter, RealD _betastp=0.0, int _MinRestart=0, int _orth_period=1, IRLdiagonalisation _diagonalisation=IRLdiagonaliseWithEigen)
ImplicitlyRestartedLanczosHermOpTester< Field > SimpleTester