boolean DL_largematrix::conjug_gradient(DL_largevector *x, DL_largevector *b){ // Solves Ax=b using conjugate gradient // returns if the solution was diverging |Ax-b|>|b| static DL_largevector p,pp, r,rr, z,zz; if ((rep==lud) || (rep==ludb)) { DL_dsystem->get_companion()->Msg("DL_largematrix::conjug_grad not implemented for LU decomposed matrices\n"); return FALSE; } int j, iter=0, itmax=nrrows; DL_Scalar ak, akden, bk, bkden=0, bknum, bnrm; p.resize(nrrows); pp.resize(nrrows); r.assign(b); rr.assign(b); z.resize(nrrows); zz.resize(nrrows); bnrm=b->norm(); x->makezero(); asolve(&r,&z); while (iter<itmax) { ++iter; asolve(&rr,&zz); bknum=z.inprod(&rr); if (iter==1) { p.assign(&z); pp.assign(&zz); } else { bk=bknum/bkden; for (j=0;j<nrrows;j++) { p.set(j,bk*p.get(j)+z.get(j)); pp.set(j,bk*pp.get(j)+zz.get(j)); } } bkden=bknum; times(&p,&z); akden=z.inprod(&pp); ak=bknum/akden; transposetimes(&pp,&zz); for(j=0;j<nrrows;j++) { // not very nice to use the implementation // of x, r and rr here, but += and -= are faster... x->v[j]+=ak*p.get(j); r.v[j]-=ak*z.get(j); rr.v[j]-=ak*zz.get(j); } asolve(&r,&z); if (r.norm()<=(TOL*bnrm)) break; } return (r.norm()>bnrm); }
void PCBCGSolver::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=new double[n+1]; pp=new double[n+1]; r=new double[n+1]; rr=new double[n+1]; z=new double[n+1]; zz=new double[n+1]; *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 printf("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("iter=%4d err=%12.6f\n",*iter,*err); if (*err <= tol) break; } delete [] p; delete [] pp; delete [] r; delete [] rr; delete [] z; delete [] zz; p = NULL; pp = NULL; r = NULL; rr = NULL; z = NULL; zz = NULL; }
void linbcg(unsigned long n, double b[], double x[], int itol, double tol, int itmax, int *iter, double *err) { void asolve(unsigned long n, double b[], double x[], int itrnsp); void atimes(unsigned long n, double x[], double r[], int itrnsp); double snrm(unsigned long n, double sx[], int itol); 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("iter=%4d err=%12.6f\n",*iter,*err); if (*err <= tol) 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); }