/* $Id: linsystemA.cc,v 1.4 1996/11/20 10:00:07 roitzsch Exp $ (C)opyright 1996 by Konrad-Zuse-Center, Berlin All rights reserved. Part of the Kaskade distribution */ #include "linsystem.h" #include "statistic.h" #include "sysmat.h" #include "precond.h" #include "dirichlet.h" #include "cmdpars.h" extern CmdPars Cmd; extern ostream* infoFile; //------------------------------------------------------------------------- Bool LinSystem:: solve(Vector& x, Real eNorm, Real error, Real reqGlobalPrecision, int step, int maxIter) { int i, nRestart, noDir=0; const Real tiny = machMin(Real(0.0)); static Real accTime = 0.0; Timer timer, accTimer; status = True; // required in compEnergy ENorm = eNorm; // for convergence test if (error < eNorm) Error = error; else Error = eNorm; globalPrecision = reqGlobalPrecision; if (Cmd.isTrue("checkDiagonal")) A->checkDiagonal(); FORALL(x,i) if (dirichletBCs->isSet(i)) { ++noDir; x[i] = dirichletBCs->value(i); } if ((A->Dim() <= directSolverLimit) || // direct solution (step == 0 && A->Dim() <= level0DirectSolverLimit)) { if (infoLinSystem) cout << "\n\t\tDirect solution by LU-Factorization\n"; A->Decompose(); A->FBSubst(x,b); } else if (noDir == A->Dim()) status = True; // all nodes constrained else // iterative solver { if (maxIter <= 0) maxIter = 10*A->Dim(); if (maxIter < 10) maxIter = 10; int maxRestarts = 0; Cmd.get("maxIter", &maxIter); Cmd.get("maxRestarts",&maxRestarts); if (step==0 || ENorm& x, Vector& r, Real bNorm, Real deltaE, Real eAe) { switch (convTest) { case ci: return ciConvergence (iter, x, r, bNorm, deltaE, eAe); case ccgDd: return ccgDdConvergence(iter, x, r, bNorm, deltaE, eAe); case ccgDB: return ccgDBConvergence(iter, x, r, bNorm, deltaE, eAe); case residual: return residualConvergence (iter, x, r, bNorm); case decayOfResidual: return residualDecay(iter, x, r, bNorm); case vectorIteration: return vectorIterConvergence(iter, x, r, bNorm); } return False; } //------------------------------------------------------------------------- void LinSystem:: compEnergy(Vector& x, Real *eNorm, Num* fct, Bool print) { Num xAx, xb, xbSave, xr; static Real tiny = machMin(Real(0)); if (status == False) // solution hath failed! { Real huge = machMax(Real(0)); *fct = huge; *eNorm = huge; return; } if (A->DirectSolution()) { xb = cdot(x,b); xbSave = cdot(x,bSave); if (symmetry == sym) { Fct = -0.5*xb + Fct0; ENorm = Abs(Fct +xbSave); } else { Fct = -0.5*xb + Fct0 + xbSave; ENorm = Abs(Fct + xb + E0); } xr = 0.0; } else { Vector aux(A->Dim()); xb = cdot(x,b); if (symmetry == sym) { A->Mult(aux,x); xAx = 0.5*cdot(x,aux); // 1/2 x*A*x Fct = xAx - xb + Fct0; ENorm = Abs(Fct + cdot(x,bSave)); } else { A->Mult(aux,x); xAx = 0.5*cdot(x,aux); // 1/2 x*A*x xbSave = cdot(x,bSave); Fct = xAx - xb + Fct0 + xbSave; ENorm = Abs(Fct + xb + E0); } xr = 0.5*(2.*xAx - xb); // x*A*x - x*b = x*r (x*r: <- residual forces) // [Fct = 1/2*x*A*x-x*b = 1/2*x(r-b)]; } if (print && infoLinSystem) { if (Abs(Fct) > tiny) { cout << "\t F=" << Fct << Form(" FRes/F=%1.2g",Abs(xr/Fct)); if (Abs(xr/Fct) > globalPrecision) cout << " > " << globalPrecision << " (global Precision)"; cout << "\n"; } } *fct = Fct; *eNorm = ENorm; //if (Cmd.isTrue("printCCGError")) // cout << "\n\tCCG: estimated error = " << Error/ENorm *100 << " %\n"; } //------------------------------------------------------------------------- //------------------------------------------------------------------------- Bool LinSystem:: residualConvergence(int iter, Vector& /*x*/, Vector& r, Real bNorm) { const char *format0 = "%14s %7s %7.3g %10s %10s |b|=%1.3g"; const char *format = "\n%14d %15.3g %10.3g %9.3g"; static Real tol, rNormM1, totRatio; static const Real tiny=10*machMin(Real(0)); Real rNorm = Norm(r); if (statistic->active) { statistic->ZD_IntWrite(statistic->idIteSteps,iter); statistic->ZD_RealWrite(statistic->idIteErr,rNorm/bNorm); } if (iter==0) // solver-setup { tol = 0.1 * extPrecFactor * globalPrecision; rNormM1 = rNorm; totRatio = 1.0; if (infoLinSystem) cout << Form(format0, "iter", "r/b < ", tol, "ratio(r)", "", bNorm); if (infoLinSystem == 1) cout << Form(format, Abs(iter), quot(rNorm,bNorm), 0.0, 0.0); if (rNorm < tiny) // unusual convergence: r == 0 { if (infoLinSystem) cout << Form(format, Abs(iter), quot(rNorm,bNorm), 0.0, 0.0) << "\n"; return True; } else return False; } totRatio *= rNorm/rNormM1; if (rNorm < tol*bNorm) // converged { if (infoLinSystem) cout << Form(format, Abs(iter), quot(rNorm,bNorm), rNorm/rNormM1, pow(totRatio, 1.0/Abs(iter))) << "\n"; if (Cmd.isTrue("writeIterations")) *infoFile << A->Dim() << " " << iter << "\n"; return True; } if (infoLinSystem) if (iter%infoLinSystem==0 || iter==1 || iter<0) cout << Form(format, Abs(iter), rNorm/bNorm, rNorm/rNormM1, pow(totRatio, 1.0/Abs(iter))); rNormM1 = rNorm; return False; } //------------------------------------------------------------------------- Bool LinSystem:: ciConvergence(int iter, Vector& /*x*/, Vector& r, Real bNorm, Real deltaE, Real eAe) { static int dimM1=0; static Real tol, iterErrM1=0.0, tiny=10*machMin(Real(0)); Real ratio=1.0, expo, rNorm, iterErr; Real KrauseFactor = 1.4789365294274; // (truncated!) const char *format0 = "%17s %10s %10s %10s tol=%1.2g |b|=%1.3g"; const char *format = "\n%17d %10.3g %10.3g %10.3g"; rNorm = Norm(r); if (iter==0) { if (Abs(Error) > tiny && Abs(ENorm) > tiny) { if (dimM1 == 0) dimM1 = A->Dim(); ratio = Real(dimM1)/Real(A->Dim()); expo = 1.0/Real(spaceDim); tol = sqrt(globalPrecision*Abs(ENorm)) / (sqrt(Error)*pow(ratio,expo)); expo = Real(spaceDim+1) / 2.0; tol = sqrt(Abs(Error)) * pow(tol,expo) + KrauseFactor*iterErrM1; tol *= 0.1 * extPrecFactor; } else tol = 0.0; Error = 0.0; if (infoLinSystem) cout << Form(format0, "iter(CI)", "eAe", "sum dE", "r/b", sqr(tol), bNorm); if (rNorm < tiny) // unusual convergence: r == 0 { if (infoLinSystem) cout << Form(format, iter, eAe, Error, rNorm/bNorm) << "\n"; return True; } else return False; } Error += deltaE; iterErr = sqrt(eAe); if (tol <= tiny) iterErr = 0.0; // forced convergence if (iterErr <= tol || rNorm < tiny) // converged { if (infoLinSystem) cout << Form(format, iter, eAe, Error, rNorm/bNorm) << "\n"; dimM1 = A->Dim(); iterErrM1 = iterErr; if (Cmd.isTrue("writeIterations")) *infoFile << A->Dim() << " " << iter << "\n"; return True; } if (infoLinSystem) if (iter%infoLinSystem==0 || iter==1 || iter<0) cout << Form(format, iter, eAe, Error, rNorm/bNorm); return False; } //------------------------------------------------------------------------- // deltaE is the "eps(jk)" in script, ratio is Theta Bool LinSystem:: ccgDBConvergence(int iter, Vector& /*x*/, Vector& r, Real bNorm, Real deltaE, Real eAe) { static Real tol, tiny=10*machMin(Real(0));; Real rNorm = Norm(r); const char *format0 = "%17s %10s %10s %10s tol=%1.2g |b|=%1.3g"; const char *format = "\n%17d %10.3g %10.3g %10.3g"; if (iter==0) // solver-setup { tol = 0.1 * extPrecFactor * globalPrecision * ::real(ENorm); if (tol < tiny) tol = 1e10; // forced convergence Error = 0.0; if (infoLinSystem) cout << Form(format0, "iter(CCGDB)", "eAe", "sum dE", "r/b", sqr(tol), bNorm); if (rNorm < tiny) // unusual convergence: r == 0 { if (infoLinSystem) cout << Form(format, iter, eAe, Error, rNorm/bNorm) << "\n"; return True; } else return False; } Error += deltaE; if (eAe < tol || rNorm < tiny) // converged { if (infoLinSystem) cout << Form(format, iter, eAe, Error, rNorm/bNorm) << "\n"; if (Cmd.isTrue("writeIterations")) *infoFile << A->Dim() << " " << iter << "\n"; return True; } if (infoLinSystem) if (iter%infoLinSystem==0 || iter==1 || iter<0) cout << Form(format, iter, eAe, Error, rNorm/bNorm); return False; } //------------------------------------------------------------------------- // deltaE is the "eps(jk)" in script, ratio is Theta Bool LinSystem:: ccgDdConvergence(int iter, Vector& /*x*/, Vector& r, Real bNorm, Real deltaE, Real /*eAe*/) { static int dimM1=0; static Real tol, deltaEM1, tiny=10*machMin(Real(0));; Real rNorm, ratio; const char *format0 = "%17s %7s%8.3g %10s %10s |b|=%1.3g"; const char *format = "\n%17d %15.3g %10.3g %10.3g"; rNorm = Norm(r); if (iter==0) // solver-setup { tol = 0.1 * extPrecFactor * globalPrecision * ::real(ENorm); if (tol < tiny) tol = 1e10; // forced convergence ratio = 1.0; Error = 0.0; if (infoLinSystem) cout << Form(format0, "iter(CCG)", "dE < ", tol, "ratio(dE)", "r/b", bNorm); if (infoLinSystem == 1) cout << Form(format, iter, deltaE, ratio, Norm(r)/bNorm); if (rNorm < tiny) // unusual convergence: r == 0 { if (infoLinSystem) cout << Form(format, iter, deltaE, ratio, rNorm/bNorm) << "\n"; return True; } else return False; } if (deltaE == 0.0) { cout << "\n*** CCG-Convergence: dE = 0 ! No CG-Solver ?\n"; } if (iter > 1) ratio = deltaE / deltaEM1; else ratio = 1.0; Error += deltaE; deltaEM1 = deltaE; if (deltaE/(1.0-Min(0.9,ratio)) < tol || rNorm < tiny) // converged { if (infoLinSystem) cout << Form(format, iter, deltaE, ratio, rNorm/bNorm) << "\n"; if (dimM1) { ratio = Real(dimM1)/Real(A->Dim()); // ~ estim. contraction factor Error *= 0.5 * ratio/(1.0-ratio); } else Error *= 0.5 * 1./3.; // contraction factor = 1/4 dimM1 = A->Dim(); if (Cmd.isTrue("writeIterations")) *infoFile << A->Dim() << " " << iter << "\n"; return True; } if (infoLinSystem) if (iter%infoLinSystem==0 || iter==1 || iter<0) cout << Form(format, iter, deltaE, ratio, rNorm/bNorm); if (rNorm < tiny) return True; return False; } //------------------------------------------------------------------------- Bool LinSystem:: residualDecay(int iter, Vector& /*x*/, Vector& r, Real /*bNorm*/) { const char *format0 = "%20s %7s%8.3g %12s |r(0)|=%1.3g"; const char *format = "\n%20d %15.3g %12.3g"; static const Real tiny=10*machMin(Real(0)); static Real tol, rNorm0, rNormM1; Real rNorm = Norm(r); if (iter==0) // solver-setup { tol = 0.1 * extPrecFactor; // *preCond->precFactor(globalPrecision,Error,ENorm); rNorm0 = rNorm; rNormM1 = rNorm; Error = machMax(Real(0.0)); // dummy if (infoLinSystem) cout << Form(format0, "iteration", "r/r0 < ", tol, "ratio(r)",rNorm); if (infoLinSystem == 1) cout << Form(format, Abs(iter), rNorm/rNorm0, rNorm/rNormM1); if (rNorm0 < tiny) // unusual convergence: r == 0 { if (infoLinSystem) cout << Form(format, Abs(iter), rNorm/rNorm0, rNorm/rNormM1) << "\n"; return True; } else return False; } if (rNorm < tol*rNorm0) // converged { if (infoLinSystem) cout << Form(format, Abs(iter), rNorm/rNorm0, rNorm/rNormM1)<<"\n"; if (Cmd.isTrue("writeIterations")) *infoFile << A->Dim() << "\t " << iter << "\n"; return True; } if (infoLinSystem) if (iter%infoLinSystem==0 || iter==1 || iter<0) cout << Form(format, Abs(iter), rNorm/rNorm0, rNorm/rNormM1); rNormM1 = rNorm; return False; } //------------------------------------------------------------------------- Bool LinSystem:: vectorIterConvergence(int iter, Vector& x, Vector& r, Real bNorm) { const char *format0 = "%18s %5s%8.3g %7s%6.3g %12s |b|=%1.3g"; const char *format = "\n%18d %13.3g %13.3g %12.3g"; static const Real tiny=10*machMin(Real(0)); static Real tol, rNormM1; Real rNorm = Norm(r); Real xNorm = Norm(x); if (iter==0) // solver-setup { tol = 0.1 * extPrecFactor * globalPrecision; // * preCond->precFactor(globalPrecision,Error,ENorm); if (infoLinSystem) cout << Form(format0, "iteration", "x/b > ", 1./sqr(tol), "r/b < ", tol, "ratio(r)", bNorm); rNormM1 = rNorm; if (rNorm < tiny) // unusual convergence: r == 0 { if (infoLinSystem) cout << Form(format, Abs(iter), xNorm/bNorm, rNorm/bNorm, rNorm/rNormM1) << "\n"; return True; } else return False; } if (xNorm > bNorm/sqr(tol) || rNorm < tol*bNorm) { if (infoLinSystem) cout << Form(format, Abs(iter), xNorm/bNorm, rNorm/bNorm, rNorm/rNormM1) << "\n"; if (Cmd.isTrue("writeIterations")) *infoFile << A->Dim() << " " << iter << "\n"; return True; } if (infoLinSystem) if (iter%infoLinSystem==0 || iter==1 || iter<0) cout << Form(format,Abs(iter),xNorm/bNorm,rNorm/bNorm,rNorm/rNormM1); rNormM1 = rNorm; return False; } //------------------------------------------------------------------------- //------------------------------------------------------------------------- Bool LinSystem:: CG(Vector& x, int maxIter) { int iter, i; Num alpha, beta, rr, rrM1; Real bNorm; int dim = A->Dim(); Vector p(dim), r(dim), aux(dim); preCond->initialize(A,x,b); bNorm = normRhs(); preCond->AMult(aux,A,x); // aux = A*x FORALL(r,i) r[i] = b[i]-aux[i]; // initial residual preCond->invert(aux,A,r); // preconditioned residual s FORALL(p,i) p[i] = aux[i]; // initial search direction rr = dot(r,aux); if (convergenceTest(0, x, r, bNorm, 0.0, 0.0)) { preCond->close(A,x,b); return True; } for (iter=1; iter<=maxIter; ++iter) { preCond->AMult(aux,A,p); alpha = rr / dot(p,aux); FORALL(x,i) x[i] += alpha * p[i]; FORALL(r,i) r[i] -= alpha * aux[i]; if (convergenceTest(iter, x, r, bNorm, Abs(alpha*rr), Abs(rr))) break; preCond->invert(aux,A,r); rrM1 = rr; rr = dot(aux,r); beta = rr / rrM1; FORALL(p,i) p[i] = aux[i] + beta*p[i]; } preCond->close(A,x,b); return iter <= maxIter; } //------------------------------------------------------------------------- Bool LinSystem:: CGOdir (Vector& x, int maxIter) { int iter, i; Num alpha, pAp, gamma, sigma, temp, pApM1=0.0, deltaE; Real bNorm; int dim = A->Dim(); Vector p(dim), r(dim), Ap(dim), CAp(dim), pM1(dim), ApM1(dim); preCond->initialize(A,x,b); bNorm = normRhs(); preCond->AMult(p,A,x); FORALL(r,i) r[i] = b[i]-p[i]; // initial residual preCond->invert(p,A,r); if (convergenceTest(0, x, r, bNorm, 0.0)) { preCond->close(A,x,b); return True; } for (iter=1; iter<=maxIter; ++iter) { preCond->AMult(Ap,A,p); preCond->invert(CAp,A,Ap); alpha = dot(r,p); pAp = dot(p,Ap); alpha = alpha / pAp; FORALL(x,i) x[i] += alpha * p[i]; FORALL(r,i) r[i] -= alpha * Ap[i]; deltaE = alpha*alpha*pAp; if (convergenceTest(iter, x, r, bNorm, Abs(deltaE))) break; gamma = dot(CAp,Ap) / pAp; if (iter > 1) sigma = dot(CAp,ApM1) / pApM1; else sigma = 0.0; FORALL(p,i) { temp = p[i]; p[i] = CAp[i] - gamma*p[i] - sigma*pM1[i]; pM1[i] = temp; ApM1[i] = Ap[i]; } pApM1 = pAp; } preCond->close(A,x,b); return iter <= maxIter; } //------------------------------------------------------------------------- /* Bool LinSystem:: CG (Vector& x, int maxIter) { int iter, i; Num alpha, beta, rr, rrM1; Real bNorm; Vector p(A->Dim()), r(A->Dim()), aux(A->Dim()); static Real tiny = 10.*machMin(Real(0)); bNorm = normRhs(); A->Mult(aux,x); FORALL(p,i) p[i] = r[i] = b[i]-aux[i]; rr = dot(r,r); convergenceTest(sqrt(Abs(rr)), bNorm, 0, 0.0); for (iter=1; iter<=maxIter; ++iter) { A->Mult(aux,p); alpha = dot(p,aux); if (Abs(alpha) > tiny) // unusual convergence alpha=0 ? { alpha = rr / alpha; FORALL(x,i) x[i] += alpha * p[i]; } if (convergenceTest(sqrt(Abs(rr)),bNorm,iter,Abs(alpha*rr))) break; FORALL(r,i) r[i] -= alpha * aux[i]; rrM1 = rr; rr = dot(r,r); beta = rr / rrM1; FORALL(p,i) p[i] = r[i] + beta*p[i]; } return iter <= maxIter; } */ //------------------------------------------------------------------------- //------------------------------------------------------------------------- Bool LinSystem:: CGS(Vector& x, int maxIter) { int iter, i; Num rho, rhoM1, alpha, beta, deltaE=0.0; Real bNorm; int dim = A->Dim(); Vector p(dim),r(dim),r0(dim),u(dim),q(dim),v(dim); preCond->initialize(A,x,b); bNorm = normRhs(); preCond->AMult(u,A,x); FORALL(r,i) r0[i] = r[i] = b[i]-u[i]; // initial residuals FORALL(p,i) p[i] = q[i] = 0.0; rho = cdot(r0,r); beta = rho; if (convergenceTest(0, x, r, bNorm, 0.0)) { preCond->close(A,x,b); return True; } for (iter=1; iter<=maxIter; ++iter) { FORALL(u,i) u[i] = r[i] + beta*q[i]; FORALL(p,i) p[i] = u[i] + beta*(q[i] + beta*p[i]); preCond->invert(q,A,p); preCond->AMult (v,A,q); alpha = rho/cdot(r0,v); FORALL(q,i) q[i] = u[i] - alpha*v[i]; FORALL(u,i) u[i] += q[i]; preCond->invert(v,A,u); preCond->AMult (u,A,v); FORALL(x,i) { x[i] += alpha*v[i]; r[i] -= alpha*u[i]; } rhoM1 = rho; rho = cdot(r0,r); // deltaE = conj(alpha)*alpha*cdot(v,u); if (convergenceTest(iter, x, r, bNorm, Abs(deltaE))) break; beta = rho/rhoM1; } preCond->close(A,x,b); return iter <= maxIter; } //------------------------------------------------------------------------- Bool LinSystem:: BiCGStab(Vector& x, int maxIter) { int iter, i; Num rho, rhoM1, omega, alpha, beta, deltaE=0.0; Real bNorm; int dim = A->Dim(); Vector p(dim), r(dim), rb(dim), t(dim), v(dim), y(dim), z(dim); preCond->initialize(A,x,b); bNorm = normRhs(); preCond->AMult(y,A,x); FORALL(r,i) rb[i] = r[i] = b[i]-y[i]; // initial residual rho = alpha = omega = 1.0; FORALL(p,i) p[i] = v[i] = 0.0; if (convergenceTest(0, x, r, bNorm, 0.0)) { preCond->close(A,x,b); return True; } for (iter=1; iter<=maxIter; ++iter) { rhoM1 = rho; rho = cdot(rb,r); beta = rho/rhoM1 * alpha/omega; FORALL(p,i) p[i] = r[i] + beta*(p[i] - omega*v[i]); preCond->invert(y,A,p); preCond->AMult (v,A,y); alpha = rho/cdot(rb,v); FORALL(r,i) r[i] = r[i] - alpha*v[i]; // s = r preCond->invert(z,A,r); preCond->AMult(t,A,z); //preCond->invert(aux,A,t); // omit this ? //omega = cdot(aux,z) / cdot(aux,aux); omega = cdot(t,z) / cdot(t,t); FORALL(x,i) { x[i] += alpha*y[i] + omega*z[i]; r[i] = r[i] - omega*t[i]; } //deltaE = conj(alpha)*alpha*cdot(y,v) + conj(omega)*omega*cdot(z,t) + // conj(alpha)*omega*cdot(y,t) + conj(omega)*alpha*cdot(z,v); if (convergenceTest(iter, x, r, bNorm, Abs(deltaE))) break; } preCond->close(A,x,b); return iter <= maxIter; } //------------------------------------------------------------------------- // This is GMRes, the GPPS (General Purpose Problem Solver) // parts of the algorithm were copied from Andreas Hohmann, // so blame HIM if it does not work! // maxOrtho: max. number of orthogonalization steps in inner iteration // right preconditioning version Bool LinSystem:: GMRes(Vector& x, int maxRestarts, int maxOrtho) { int i, j, kMax, nRestart, gmResStatus; Real bNorm; Vector g(maxOrtho+1); Vector aux(A->Dim()); Matrix R(maxOrtho,maxOrtho); Vector*> v(maxOrtho+1); // orthonormal system FORALL(v,i) v[i] = 0; v[1] = new Vector(A->Dim()); preCond->initialize(A,x,b); bNorm = normRhs(); for (nRestart=0; nRestart<=maxRestarts; ++nRestart) { gmResStatus = GMResInnerIteration(x, maxOrtho, bNorm, g, R, v, aux, nRestart, &kMax); // compute solution R^(-1)*g of least squares problem: GMResRSolve(g,R,g,kMax); FORALL(aux,j) aux[j] = 0.0; for (i=1; i<=kMax; i++) FORALL(aux,j) aux[j] += g[i] * (*v[i])[j]; preCond->invert(*v[1],A,aux); FORALL(x,j) x[j] += (*v[1])[j]; // update solution if (gmResStatus == 1) break; // convergence in inner iteration if (infoLinSystem) cout << " restart"; } preCond->close(A,x,b); FORALL(v,i) delete v[i]; return nRestart <= maxRestarts; } //------------------------------------------------------------------------- Bool LinSystem:: GMResInnerIteration(Vector& x, int maxOrtho, Real bNorm, Vector& g, Matrix& R, Vector*> &v, Vector& aux, int nRestart, int* kMax) { int i, j, k, iter; Num h, r; Real tmp; Vector c(maxOrtho), s(maxOrtho); Vector rDummy(1); preCond->AMult(aux,A,x); FORALL(b,i) (*v[1])[i] = b[i] - aux[i]; FORALL(g,i) g[i] = 0.0; g[1] = Norm(*v[1]); FORALL(*v[1],i) (*v[1])[i] /= g[1]; rDummy[1] = g[1]; if (nRestart==0) convergenceTest(0, rDummy, rDummy, bNorm, 0.0); for (k=1; k<=maxOrtho; ++k) { *kMax = k; if (v[k+1]==0) v[k+1] = new Vector(A->Dim()); // next orthonormal vector v[k+1]; preCond->invert(aux,A,*v[k]); preCond->AMult(*v[k+1],A,aux); for (i=1; i<=k; ++i) R(k,i) = dot(*v[i], *v[k+1]); for (i=1; i<=k; ++i) { FORALL(*v[k+1],j) (*v[k+1])[j] -= R(k,i) * (*v[i])[j]; } h = Norm(*v[k+1]); FORALL(*v[k+1],j) (*v[k+1])[j] /= h; // transform row k of R with previous Givens rotations: GMResQMult(k-1, R(k), c, s); // compute new Givens coefficients c[k] and s[k]; r = R(k,k); tmp = sqrt(Abs(sqr(r)+sqr(h))); // !!! c[k] = r/tmp; s[k] = -h/tmp; R(k,k) = tmp; // update constant vector g with new coefficients: GMResGivensMult(k, g.v, c, s); iter = (k& c, Vector& s) { for (int j=1; j<=k; ++j) GMResGivensMult(j, v, c, s); } // apply the j-th Givens rotation F_j to the vector v void LinSystem:: GMResGivensMult (int j, Num* v, Vector& c, Vector& s) { Num tmp = c[j]*v[j] - s[j]*v[j+1]; v[j+1] = s[j]*v[j] + c[j]*v[j+1]; v[j] = tmp; } // solve the triangular system v = R_k * g void LinSystem:: GMResRSolve (Vector& lhs, Matrix& R, Vector& rhs, int k) { for (int j=k; j>=1; --j) { lhs[j] = rhs[j]; for (int i=j+1; i<=k; ++i) lhs[j] -= R(i,j) * lhs[i]; lhs[j] /= R(j,j); } } //------------------------------------------------------------------------- /* // left preconditioning version of GMRes: int LinSystem:: GMRes(Vector& x, int maxRestarts, int maxOrtho) { int i, j, kMax, nRestart, gmResStatus; Real bNorm; Vector g(maxOrtho+1); Vector aux(A->Dim()); Matrix R(maxOrtho,maxOrtho); Vector(NumVectorP) v(maxOrtho+1); // orthonormal system FORALL(v,i) v[i] = 0; v[1] = new Vector(A->Dim()); preCond->initialize(A,x,b); bNorm = preCond->normOfRhs(A,b,aux); // compute norm of preconditioned // vector b for convergence test for (nRestart=0; nRestart<=maxRestarts; ++nRestart) { gmResStatus = GMResInnerIteration(x, maxOrtho, bNorm, g, R, v, aux, &kMax); // compute solution R^(-1)*g of least squares problem: GMResRSolve(g,R,g,kMax); for (i=1; i<=kMax; i++) FORALL(x,j) x[j] += g[i] * (*v[i])[j]; if (gmResStatus == 1) break; // convergence in inner iteration if (infoLinSystem) cout << " restart\n"; } preCond->close(A,x,b); FORALL(v,i) delete v[i]; return nRestart <= maxRestarts; } //------------------------------------------------------------------------- int LinSystem:: GMResInnerIteration (Vector& x, int maxOrtho, Real bNorm, Vector& g, Matrix& R, Vector(NumVectorP)& v, Vector& aux, int* kMax) { int i, j, k, iter; Num h, r; Real tmp, t; Vector c(maxOrtho), s(maxOrtho); preCond->AMult(aux,A,x); FORALL(b,i) aux[i] = b[i] - aux[i]; preCond->invert(*v[1],A,aux); // preconditioned residual -> v[1]; FORALL(g,i) g[i] = 0.0; g[1] = Norm(*v[1]); FORALL(*v[1],i) (*v[1])[i] /= g[1]; (*convergenceTest)(Abs(g[1]), bNorm, 0, 0.0); for (k=1; k<=maxOrtho; ++k) { *kMax = k; if (v[k+1]==0) v[k+1] = new Vector(A->Dim()); // next orthonormal vector v[k+1]; preCond->AMult(aux,A,*v[k]); preCond->invert(*v[k+1],A,aux); for (i=1; i<=k; ++i) R(k,i) = dot(*v[i], *v[k+1]); for (i=1; i<=k; ++i) { FORALL(*v[k+1],j) (*v[k+1])[j] -= R(k,i) * (*v[i])[j]; } h = Norm(*v[k+1]); FORALL(*v[k+1],j) (*v[k+1])[j] /= h; // transform row k of R with previous Givens rotations: GMResQMult(k-1, R(k), c, s); // compute new Givens coefficients c[k] and s[k]; r = R(k,k); tmp = sqrt(sqr(r)+sqr(h)); c[k] = r/tmp; s[k] = -h/tmp; R(k,k) = tmp; // update constant vector g with new coefficients: GMResGivensMult(k, g.v, c, s); iter = (k& x, int maxIter) { int iter, i; Num alpha, beta, rr, rrM1; Real bNorm, deltaE; int dim = A->Dim(); Vector p(dim), pT(dim), r(dim), rT(dim), aux(dim), h(dim); preCond->initialize(A,x,b); bNorm = normRhs(); preCond->AMult(r,A,x); FORALL(r,i) r[i] = b[i]-r[i]; // initial residual FORALL(p,i) p[i] = r[i]; // initial search direction FORALL(rT,i) rT[i] = conj(r[i]); // initial bi-residual FORALL(pT,i) pT[i] = rT[i]; // initial bi-search direction rr = cdot(rT,r); if (convergenceTest(0, x, r, bNorm, 0.0)) { preCond->close(A,x,b); return True; } for (iter=1; iter<=maxIter; ++iter) { preCond->invert(h,A,p); preCond->AMult(aux,A,h); alpha = rr/cdot(pT,aux); FORALL(x,i) x[i] += alpha * h[i]; FORALL(r,i) r[i] -= alpha * aux[i]; deltaE = Abs(conj(alpha)*alpha * cdot(h,aux)); preCond->ATMult(h,A,pT); preCond->invert(aux,A,h); FORALL(rT,i) rT[i] -= alpha * aux[i]; rrM1 = rr; rr = cdot(rT,r); if (convergenceTest(iter, x, r, bNorm, deltaE)) break; beta = rr / rrM1; FORALL(p,i) p[i] = r[i] + beta*p[i]; FORALL(pT,i) pT[i] = rT[i] + beta*pT[i]; } preCond->close(A,x,b); return iter <= maxIter; } //------------------------------------------------------------------------- Bool LinSystem:: DdCG (Vector& x, int maxIter) { int iter, i; Num s, sM1, sB, f; Real bNorm; Vector dx(A->Dim()), r(A->Dim()), aux(A->Dim()); preCond->initialize(A,x,b); preCond->invert(aux,A,b); bNorm = normRhs(); preCond->AMult(r,A,x); FORALL(r,i) aux[i] = b[i]-r[i]; preCond->invert(r,A,aux); // initial residual s = sM1 = dot(r,r); if (convergenceTest(0, x, r, bNorm, 0.0)) { preCond->close(A,x,b); return True; } preCond->invert(aux,A,r); preCond->ATMult(dx,A,aux); for (iter=1; iter<=maxIter; ++iter) { sB = dot(dx,dx); f = s/sB; FORALL(x,i) x[i] += f*dx[i]; preCond->AMult(r,A,x); FORALL(aux,i) aux[i] = b[i]-r[i]; preCond->invert(r,A,aux); // new residual sM1 = s; s = dot(r,r); if (convergenceTest(iter, x, r, bNorm, 0.0)) break; preCond->invert(aux,A,r); preCond->ATMult(r,A,aux); f = s/sM1; FORALL(dx,i) dx[i] = r[i] + f*dx[i]; } preCond->close(A,x,b); return iter <= maxIter; } //------------------------------------------------------------------------- //------------------------------------------------------------------------- Bool LinSystem:: Relax(Vector& x, int maxIter) { int i, iter; Real bNorm, eAe; Vector r(A->Dim()), e(A->Dim()); preCond->initialize(A,x,b); bNorm = normRhs(); for (iter=0; iter<=maxIter; ++iter) { preCond->AMult(e,A,x); FORALL(r,i) r[i] = b[i] - e[i]; // new residual preCond->invert(e,A,r); // e is the defect correction FORALL(x,i) x[i] += e[i]; eAe = Abs(dot(e,r)); // eAe = A**(-1)*r * r if (convergenceTest(iter, x, r, bNorm, 0.0, eAe)) break; } preCond->close(A,x,b); return iter <= maxIter; } //-------------------------------------------------------------------------