【連立一次方程式】安定化双共役勾配法(Bi-CGSTAB法) C++コード付き
今回は正定値対称行列にしか適用できない共役勾配法(Conjugate Gradient法)をパワーアップした手法である双共役勾配法(Bi-Conjugate Gradient法)を安定化した、安定化双共役勾配法(Bi-conjugate gradient stabilized法)のC++コードを公開します。ややこしいですね。つまり
のような流れです。CG法についてはこちらをご覧下さい。
しくみはおいおい説明するとして、とりあえずコードをおいておきます。というより現在進行形で勉強中です!お待ちください。
今回解く連立一次方程式は
とあらわされます。ここで、 は の行列、 と は 次元のベクトルです。 と が既知で、 が未知です。具体的には
であり、これを解くと となります。コードを書く際に、
を参考にさせて頂いています。ではコードを以下に示します。
#include <iostream> #include <cmath> #include <fstream> #include <iomanip> using namespace std; int i,j,k; //matix vector multiplication Ax=b inline void mvm(double A[],double x[],double b[], int size) { for(i=0;i<size;i++) { b[i]=0.; for(j=0;j<size;j++) { b[i]+=A[i*size+j]*x[j]; } } } //inner product// inline double ip(double a[], double b[], int size) { double value=0.; for(i=0;i<size;i++) value+=a[i]*b[i]; return value; } main() { int size=3; double alpha,beta; double r0,rk,rk1,w; double eps=pow(2.0,-50); double *r=new double[size]; double *p=new double[size]; double *b=new double[size]; double *x=new double[size]; double *Ax=new double[size]; double *Ap=new double[size]; double *A=new double[size*size]; double *rr=new double[size]; double *s=new double[size]; double *As=new double[size]; A[0*size+0]=1.;A[0*size+1]=2.;A[0*size+2]=1.; A[1*size+0]=4.;A[1*size+1]=1.;A[1*size+2]=1.; A[2*size+0]=2.;A[2*size+1]=1.;A[2*size+2]=1.; b[0]=5.;b[1]=7.;b[2]=5.; //Initial condition// for(i=0;i<size;i++) x[i]=0.; mvm(A,x,Ax,size); for(i=0;i<size;i++) r[i]=b[i]-Ax[i]; for(i=0;i<size;i++) p[i]=r[i]; for(i=0;i<size;i++) rr[i]=r[i]; r0=sqrt(ip(r,r,size)); //main loop// for(k=0;k<100000;k++) { mvm(A,p,Ap,size); alpha=ip(r,rr,size)/ip(rr,Ap,size); rk=ip(r,rr,size); for(i=0;i<size;i++) s[i]=r[i]-alpha*Ap[i]; mvm(A,s,As,size); w=ip(As,s,size)/ip(As,As,size); for(i=0;i<size;i++) x[i]=x[i]+alpha*p[i]+w*s[i]; for(i=0;i<size;i++) r[i]=s[i]-w*As[i]; rk1=sqrt(ip(r,r,size)); if(rk1/r0<=eps) break; beta=ip(r,rr,size)/rk*alpha/w; for(i=0;i<size;i++) p[i]=r[i]+beta*(p[i]-w*Ap[i]); } for(i=0;i<size;i++) cout<<x[i]<<endl; delete [] r,p,b,x,Ax,Ap,A,rr,s,As; return 0; }