#include "PBCG.h" PBCG::PBCG() { sa = NULL; ija = NULL; } PBCG::~PBCG() { if(sa != NULL) delete sa; if(ija != NULL) delete ija; } void PBCG::linbcg(unsigned long n, double b[], double x[], int itol, double tol, int itmax, int *iter, double *err) { unsigned long j; double ak,akden,bk,bkden,bknum,bnrm,dxnrm,xnrm,zm1nrm,znrm; double *p,*pp,*r,*rr,*z,*zz; p=dvector(1,n); pp=dvector(1,n); r=dvector(1,n); rr=dvector(1,n); z=dvector(1,n); zz=dvector(1,n); *iter=0; atimes(n,x,r,0); for (j=1;j<=n;j++) { r[j]=b[j]-r[j]; rr[j]=r[j]; } znrm=1.0; if (itol == 1) bnrm=snrm(n,b,itol); else if (itol == 2) { asolve(n,b,z,0); bnrm=snrm(n,z,itol); } else if (itol == 3 || itol == 4) { asolve(n,b,z,0); bnrm=snrm(n,z,itol); asolve(n,r,z,0); znrm=snrm(n,z,itol); } else nrerror("illegal itol in linbcg"); asolve(n,r,z,0); while (*iter <= itmax) { ++(*iter); zm1nrm=znrm; asolve(n,rr,zz,1); for (bknum=0.0,j=1;j<=n;j++) bknum += z[j]*rr[j]; if (*iter == 1) { for (j=1;j<=n;j++) { p[j]=z[j]; pp[j]=zz[j]; } } else { bk=bknum/bkden; for (j=1;j<=n;j++) { p[j]=bk*p[j]+z[j]; pp[j]=bk*pp[j]+zz[j]; } } bkden=bknum; atimes(n,p,z,0); for (akden=0.0,j=1;j<=n;j++) akden += z[j]*pp[j]; ak=bknum/akden; atimes(n,pp,zz,1); for (j=1;j<=n;j++) { x[j] += ak*p[j]; r[j] -= ak*z[j]; rr[j] -= ak*zz[j]; } asolve(n,r,z,0); if (itol == 1 || itol == 2) { znrm=1.0; *err=snrm(n,r,itol)/bnrm; } else if (itol == 3 || itol == 4) { znrm=snrm(n,z,itol); if (fabs(zm1nrm-znrm) > EPS*znrm) { dxnrm=fabs(ak)*snrm(n,p,itol); *err=znrm/fabs(zm1nrm-znrm)*dxnrm; } else { *err=znrm/bnrm; continue; } xnrm=snrm(n,x,itol); if (*err <= 0.5*xnrm) *err /= xnrm; else { *err=znrm/bnrm; continue; } } printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\biter=%4d err=%12.6f",*iter,*err/diagonal); if (*err <= tol){ printf("\n"); break; } } free_dvector(p,1,n); free_dvector(pp,1,n); free_dvector(r,1,n); free_dvector(rr,1,n); free_dvector(z,1,n); free_dvector(zz,1,n); } void PBCG::asolve(unsigned long n, double b[], double x[], int itrnsp) { unsigned long i; for(i=1;i<=n;i++) x[i]=(sa[i] != 0.0 ? b[i]/sa[i] : b[i]); } void PBCG::atimes(unsigned long n, double x[], double r[], int itrnsp) { if (itrnsp) dsprstx(sa,ija,x,r,n); else dsprsax(sa,ija,x,r,n); } double PBCG::snrm(unsigned long n, double sx[], int itol) { unsigned long i,isamax; double ans; if (itol <= 3) { ans = 0.0; for (i=1;i<=n;i++) ans += sx[i]*sx[i]; return sqrt(ans); } else { isamax=1; for (i=1;i<=n;i++) { if (fabs(sx[i]) > fabs(sx[isamax])) isamax=i; } return fabs(sx[isamax]); } } void PBCG::dsprsax(double sa[], unsigned long ija[], double x[], double b[], unsigned long n) { unsigned long i,k; if (ija[1] != n+2) nrerror("dsprsax: mismatched vector and matrix"); for (i=1;i<=n;i++) { b[i]=sa[i]*x[i]; for (k=ija[i];k<=ija[i+1]-1;k++) b[i] += sa[k]*x[ija[k]]; } } void PBCG::dsprstx(double sa[], unsigned long ija[], double x[], double b[], unsigned long n) { unsigned long i,j,k; if (ija[1] != n+2) nrerror("mismatched vector and matrix in dsprstx"); for (i=1;i<=n;i++) b[i]=sa[i]*x[i]; for (i=1;i<=n;i++) { for (k=ija[i];k<=ija[i+1]-1;k++) { j=ija[k]; b[j] += sa[k]*x[i]; } } }