-
Notifications
You must be signed in to change notification settings - Fork 0
/
bl_bicgstab_rq.cpp
61 lines (50 loc) · 1.71 KB
/
bl_bicgstab_rq.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <tuple>
#include <Eigen/Dense>
#include "linear_algebra_addon.hpp"
using namespace Eigen;
using namespace std;
MatrixXcd bl_bicgstab_rq(const MatrixXcd& A, const MatrixXcd& B, const double& tol, const int& itermax)
{
//Originally derived based on
// Rashedi et al. 2016, On short recurrence Krylov type methods for linear systems with many right-hand sides, J. Comput. Appl. Math.
// Guennouni et al 2003, A block version of BICGSTAB for linear systems with multiple right-hand sides, Electronic Transaction on Numerical Anaysis
int N= B.rows();
int L= B.cols();
MatrixXcd thinQ(MatrixXcd::Identity(N,L));
double Bnorm= B.norm();
MatrixXcd X= MatrixXcd::Zero(N,L); // Initial guess of X (zeros)
MatrixXcd R0= B-A*X;
MatrixXcd R;
MatrixXcd C;
tie(R,C)= qr_reduced(R0);
MatrixXcd Y0= R0;
double norm0= R0.norm();
double normr= norm0;
MatrixXcd P= R;
for(int k= 0; k < itermax; ++k){
MatrixXcd AP= A*P;
FullPivLU<MatrixXcd> lu(Y0.adjoint()*AP);
MatrixXcd alpha= lu.solve(Y0.adjoint()*R);
MatrixXcd S= R-AP*alpha;
MatrixXcd T= A*S;
MatrixXcd SC= S*C;
MatrixXcd TC= T*C;
complex<double> w= (SC.adjoint()*TC).trace()/(TC.adjoint()*TC).trace();
X= X+P*alpha*C+w*SC;
R= S-w*T;
MatrixXcd U;
tie(R,U)= qr_reduced(R);
C= U*C;
double err= C.norm()/Bnorm;
cout << "bl_bicgstab_rq: " << "iter= " << k << " relative err= " << err << endl;
if(err < tol) break;
MatrixXcd beta= -lu.solve(Y0.adjoint()*T*U.inverse());
P= R+(P-AP*w)*beta;
}
if((A*X-B).norm()/Bnorm > 10*tol){
cerr << "bl_bicgstab_rq did not converge to solution within error tolerance !" << endl;
// exit(EXIT_FAILURE);
}
return X;
}