//============================================================================ KrylovSolverStatus CGNR_Solver:: solve(const LinearOperator &A, const double *rhs, double *result, const LinearOperator *preconditioner, bool use_given_initial_guess) { const int m=A.m, n=A.n; assert(preconditioner==0 || (preconditioner->m==n && preconditioner->n==n)); if((int)s.size()!=n){ r.resize(n); z.resize(n); s.resize(n); u.resize(m); } // convergence tolerance A.apply_transpose(rhs, &r[0]); // form A^T*rhs in r double tol=tolerance_factor*BLAS::abs_max(r); // initial guess if(use_given_initial_guess){ A.apply_and_subtract(result, rhs, &u[0]); A.apply_transpose(u, r); }else{ BLAS::set_zero(n, result); } // check instant convergence iteration=0; residual_norm=BLAS::abs_max(r); if(residual_norm==0) return status=KRYLOV_CONVERGED; // set up CG double rho; if(preconditioner) preconditioner->apply(r, z); else BLAS::copy(r, z); rho=BLAS::dot(r, z); if(rho<=0 || rho!=rho) return status=KRYLOV_BREAKDOWN; BLAS::copy(z, s); // and iterate for(iteration=1; iteration<max_iterations; ++iteration){ double alpha; A.apply(s, u); A.apply_transpose(u, z); double sz=BLAS::dot(u, u); if(sz<=0 || sz!=sz) return status=KRYLOV_BREAKDOWN; alpha=rho/sz; BLAS::add_scaled(n, alpha, &s[0], result); BLAS::add_scaled(-alpha, z, r); residual_norm=BLAS::abs_max(r); if(residual_norm<=tol) return status=KRYLOV_CONVERGED; if(preconditioner) preconditioner->apply(r, z); else BLAS::copy(r, z); double rho_new=BLAS::dot(r, z); if(rho_new<=0 || rho_new!=rho_new) return status=KRYLOV_BREAKDOWN; double beta=rho_new/rho; BLAS::add_scaled(beta, s, z); s.swap(z); // s=beta*s+z rho=rho_new; if ( iteration % 5000 == 0 ) { std::cout << "CGNR_Solver --- residual_norm: " << residual_norm << std::endl; } } return status=KRYLOV_EXCEEDED_MAX_ITERATIONS; }
//============================================================================ KrylovSolverStatus MINRES_CR_Solver:: solve(const LinearOperator &A, const double *rhs, double *result, const LinearOperator *preconditioner, bool use_given_initial_guess) { const int n=A.m; assert(A.n==n); assert(preconditioner==0 || (preconditioner->m==n && preconditioner->n==n)); if((int)s.size()!=n){ r.resize(n); z.resize(n); q.resize(n); s.resize(n); t.resize(n); } // convergence tolerance double tol=tolerance_factor*BLAS::abs_max(n, rhs); // initial guess if(use_given_initial_guess){ A.apply_and_subtract(result, rhs, &r[0]); }else{ BLAS::set_zero(n, result); BLAS::copy(n, rhs, &r[0]); } // check instant convergence iteration=0; residual_norm=BLAS::abs_max(r); if(residual_norm==0) return status=KRYLOV_CONVERGED; // set up CR double rho; if(preconditioner) preconditioner->apply(r, z); else BLAS::copy(r, s); A.apply(s, t); rho=BLAS::dot(r, t); if(rho==0 || rho!=rho) return status=KRYLOV_BREAKDOWN; // and iterate for(iteration=1; iteration<max_iterations; ++iteration){ double alpha; double tt=BLAS::dot(t, t); if(tt==0 || tt!=tt) return status=KRYLOV_BREAKDOWN; alpha=rho/tt; BLAS::add_scaled(n, alpha, &s[0], result); BLAS::add_scaled(-alpha, t, r); residual_norm=BLAS::abs_max(r); if(residual_norm<=tol) return KRYLOV_CONVERGED; if(preconditioner) preconditioner->apply(r, z); else BLAS::copy(r, z); A.apply(z, q); double rho_new=BLAS::dot(r, q); if(rho_new==0 || rho_new!=rho_new) return KRYLOV_BREAKDOWN; double beta=rho_new/rho; BLAS::add_scaled(beta, s, z); s.swap(z); // s=beta*s+z BLAS::add_scaled(beta, t, q); t.swap(q); // t=beta*t+q rho=rho_new; } return KRYLOV_EXCEEDED_MAX_ITERATIONS; }