#ifndef THYRA_SILLY_CG_SOLVE_HPP
#define THYRA_SILLY_CG_SOLVE_HPP
#include "Thyra_LinearOpBase.hpp"
#include "Thyra_VectorStdOps.hpp"
#include "Thyra_AssertOp.hpp"
template<class Scalar>
bool sillyCgSolve(
const Thyra::LinearOpBase<Scalar> &A
,const Thyra::VectorBase<Scalar> &b
,const int maxNumIters
,const typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance
,Thyra::VectorBase<Scalar> *x
,std::ostream *out = NULL
)
{
typedef Teuchos::ScalarTraits<Scalar> ST; typedef typename ST::magnitudeType ScalarMag;
const Scalar one = ST::one(), zero = ST::zero(); using Thyra::NOTRANS;
typedef Teuchos::RefCountPtr<const Thyra::VectorSpaceBase<Scalar> > VectorSpacePtr;
typedef Teuchos::RefCountPtr<Thyra::VectorBase<Scalar> > VectorPtr;
TEST_FOR_EXCEPT(x==NULL);
THYRA_ASSERT_LINEAR_OP_VEC_APPLY_SPACES("sillyCgSolve()",A,Thyra::NOTRANS,*x,&b);
Teuchos::EVerbosityLevel vl = Teuchos::VERB_MEDIUM;
if(out) *out << "\nStarting CG solver ...\n" << std::scientific << "\ndescribe A:\n"<<describe(A,vl)
<< "\ndescribe b:\n"<<describe(b,vl)<<"\ndescribe x:\n"<<describe(*x,vl)<<"\n";
VectorSpacePtr space = A.domain();
VectorPtr r = createMember(space);
V_V(&*r,b); apply(A,NOTRANS,*x,&*r,Scalar(-one),one);
const ScalarMag r0_nrm = norm(*r);
if(r0_nrm==zero) return true;
VectorPtr p = createMember(space), q = createMember(space);
Scalar rho_old;
for( int iter = 0; iter <= maxNumIters; ++iter ) {
const ScalarMag r_nrm = norm(*r);
const bool isConverged = r_nrm/r0_nrm <= tolerance;
if( iter%(maxNumIters/10+1) == 0 || iter == maxNumIters || isConverged ) {
if(out) *out << "Iter = " << iter << ", ||b-A*x||/||b-A*x0|| = " << (r_nrm/r0_nrm) << std::endl;
if( r_nrm/r0_nrm < tolerance ) return true;
}
const Scalar rho = scalarProd(*r,*r);
if(iter==0) V_V(&*p,*r);
else Vp_V( &*p, *r, Scalar(rho/rho_old) );
apply(A,NOTRANS,*p,&*q);
const Scalar alpha = rho/scalarProd(*p,*q);
Vp_StV( x, Scalar(+alpha), *p );
Vp_StV( &*r, Scalar(-alpha), *q );
rho_old = rho;
}
return false;
}
#endif // THYRA_SILLY_CG_SOLVE_HPP