#ifndef __RVLALG_LINFIT_L2_H #define __RVLALG_LINFIT_L2_H #include "alg.hh" #include "cgalg.hh" #include "cgnealg.hh" #include "terminator.hh" #include "linop.hh" #include "table.hh" using namespace RVLAlg; namespace RVLUmin { using namespace RVL; using namespace RVLAlg; /** Given an Operator F and a Vector d in the range of op, implements the function \f$$ f(x) = \inf_{dx} \|DF(x)dx - d\|^2 \f$$ as an RVL::Functional. The linear least squares solver is specified by policy. */ template class LinFitLS: public Functional, public LSPolicy { typedef typename ScalarFieldTraits::AbsType atype; private: Operator const & op; // operator LinearOp const & preop; // preconditioner Vector const & d; // data Vector const & x0; // input initial linear solution bool refine; // refine as in Kern & Symes 1994 mutable Vector dx; // preimage of linear solution mutable Vector dltx; // linear solution mutable bool applied; ostream & str; protected: void apply(const Vector & x, Scalar & val) const { try { /* if (applied) { RVLException e; e<<"Error: LinFitLS::apply(x,val)\n"; e<<"already applied, may not alter\n"; throw e; } */ atype rnorm; atype nrnorm; // access Operator through OperatorEvaluation OperatorEvaluation opeval(op,x); // Get Derivative of Operator LinearOp const & lop = opeval.getDeriv(); // Composition of lop and preop OpComp gop(preop,lop); Vector tmp(gop.getDomain()); tmp.zero(); // for non-zero initial solution Vector d0(lop.getRange()); lop.applyOp(x0,d0); d0.linComb(1.0,d,-1.0); dx.zero(); // build least square solver , solve for dx OperatorEvaluation gopeval(gop,tmp); Algorithm * solver = LSPolicy::build(dx,gopeval.getDeriv(),d0,rnorm,nrnorm,str); solver->run(); // get the value of objective function val = 0.5*rnorm*rnorm; preop.applyOp(dx,dltx); dltx.linComb(1.0,x0); applied = true; delete solver; } catch (RVLException & e) { e<<"\ncalled from LinFitLSx0::apply\n"; throw e; } } void applyGradient(const Vector & x, Vector & g) const { try{ if(!applied){ Scalar val; this->apply(x,val); } OperatorEvaluation opeval(op,x); LinearOp const & lop = opeval.getDeriv(); SymmetricBilinearOp const & sblop = opeval.getDeriv2(); Vector dltd(lop.getRange()); // compute dltx and dltd = DF * dltx - d lop.applyOp(dltx,dltd); dltd.linComb(-1.0,d); // naive computation of gradient sblop.applyAdjOp(dltx,dltd,g); // compute and add correction term to gradient if (refine) { atype rnorm; atype nrnorm; OpComp gop(preop,lop); Vector tmp(gop.getDomain()); Vector dx1(gop.getDomain()); tmp.zero(); dx1.zero(); OperatorEvaluation gopeval(gop,tmp); // solve DF * dx = dltd in LS sense Algorithm * solver = LSPolicy::build(dx1,gopeval.getDeriv(),dltd,rnorm,nrnorm,str); solver->run(); delete solver; Vector tmp2(g.getSpace()); Vector dx2(preop.getRange()); preop.applyOp(dx1,dx2); // compute and add correction term tmp to gradient g sblop.applyAdjOp(dx2,d,tmp2); g.linComb(1.0, tmp2); } } catch (RVLException & e) { e<<"\ncalled from LinFitLS::applyGradient\n"; throw e; } } void applyHessian(const Vector & x, const Vector & dx, Vector & dy) const {} Functional * clone() const { return new LinFitLS(*this); } public: /* typical policy data atype _rtol, atype _nrtol, int _maxcount, */ LinFitLS(Operator const & _op, LinearOp const & _preop, Vector const & _d, Vector const & _x0, LSPolicyData const & s, bool _refine=false, ostream & _str=cerr) : LSPolicy(), op(_op), preop(_preop), d(_d), x0(_x0), refine(_refine), dx(preop.getDomain()), dltx(preop.getRange()), applied(false), str(_str) { try{ dx.zero(); LSPolicy::assign(s); if (s.verbose) { str<<"\n"; str<<"==============================================\n"; str<<"LinFitLS constructor - ls policy data = \n"; s.write(str); } } catch (RVLException & e) { e<<"\ncalled from LinFitLS::Constructor\n"; throw e; } } LinFitLS(LinFitLS const & f) : LSPolicy(f), op(f.op), preop(f.preop), d(f.d), x0(f.x0), refine(f.refine), dx(f.dx), dltx(f.dltx), applied(f.applied), str(f.str) {} const Space & getDomain() const { return op.getDomain(); } Scalar getMaxStep(const Vector & x, const Vector & dx) const { try { return op.getMaxStep(x,dx); } catch (RVLException & e) { e<<"\ncalled from LinFitLS::getMaxStep\n"; throw e; } } Vector const & getLSSoln() const { return dltx; } ostream & write(ostream & str) const { str<<"LinFitLS: \n"; str<<"*** operator:\n"; op.write(str); str<<"*** data vector:\n"; d.write(str); return str; } }; template class PIVAObj2: public Functional { typedef typename ScalarFieldTraits::AbsType atype; private: Operator const & op; // operator LinearOp const & preop; // preconditioner LinearOp const & helmop; // smoothing op applied to gradient LinearOp const & A; // annihilator LinearOp const & R; // regularization Vector const & d; // data Vector const & x0; // input initial linear solution //Scalar eps; // weight on regularization CGNEPolicyData pdcgne; mutable Vector dx; // preimage of linear solution mutable Vector dltx; // linear solution mutable Vector q; // CG solution mutable Vector qrhs; // rhs of CG mutable bool applied; ostream & str; protected: void apply(const Vector & x, Scalar & val) const { try { /* if (applied) { RVLException e; e<<"Error: LinFitLS::apply(x,val)\n"; e<<"already applied, may not alter\n"; throw e; } */ atype rnorm; atype nrnorm; // access Operator through OperatorEvaluation OperatorEvaluation opeval(op,x); // Get Derivative of Operator LinearOp const & lop = opeval.getDeriv(); // for non-zero initial solution Vector d0(lop.getRange()); lop.applyOp(x0,d0); d0.linComb(1.0,d,-1.0); CompLinearOp nop(preop,lop); TensorLinearOp top(nop, R); // create RHS of block system Vector td(top.getRange()); Components ctd(td); ctd[0].copy(d0); ctd[1].zero(); //Vector pdx(op.getDomain()); dx.zero(); // build least square solver , solve for dx CGNEPolicy cgnep; cgnep.assign(pdcgne); CGNEAlg * solver = cgnep.build(dx,top,td,rnorm,nrnorm,str); // CGNEAlg * solver = cgnep.build(dx,nop,d0,rnorm,nrnorm,str); solver->run(); // get the value of objective function //val = 0.5*rnorm*rnorm; //preop.applyOp(pdx,dx); dx.linComb(1.0,x0); A.applyOp(dx,dltx); val = dltx.norm() * 0.5f; Scalar dxn = dx.norm(); applied = true; delete solver; } catch (RVLException & e) { e<<"\ncalled from PIVAObj2::apply\n"; throw e; } } void applyGradient(const Vector & x, Vector & g) const { try{ if(!applied){ Scalar val; this->apply(x,val); } atype rnorm; OperatorEvaluation opeval(op,x); LinearOp const & lop = opeval.getDeriv(); SymmetricBilinearOp const & sblop = opeval.getDeriv2(); // build RHS Vector tmpm(lop.getDomain()); A.applyAdjOp(dltx,qrhs); CompLinearOp cop(preop,lop); NormalLinearOp nop(cop); NormalLinearOp rop(R); LinCombLinearOp rnop(1.0, nop, 1.0, rop); CGAlg alg(q,rnop,qrhs,rnorm,pdcgne.rtol,pdcgne.maxcount,pdcgne.Delta,str); alg.run(); Vector tmpd(lop.getRange()); lop.applyOp(q,tmpd); sblop.applyAdjOp(dx,tmpd,g); g.scale(-1.0f); //helmop.applyOp(tmpb,g); } catch (RVLException & e) { e<<"\ncalled from PIVAObj2::applyGradient\n"; throw e; } } void applyHessian(const Vector & x, const Vector & dx, Vector & dy) const {} Functional * clone() const { return new PIVAObj2(*this); } public: /* typical policy data atype _rtol, atype _nrtol, int _maxcount, */ PIVAObj2(Operator const & _op, LinearOp const & _preop, LinearOp const & _helmop, LinearOp const & _A, LinearOp const & _R, Vector const & _d, Vector const & _x0, //Scalar _eps, CGNEPolicyData const & _pdcgne, ostream & _str=cerr) : op(_op), preop(_preop), helmop(_helmop), A(_A), R(_R), d(_d), x0(_x0), pdcgne(_pdcgne), dx(preop.getDomain()), q(op.getDomain()), qrhs(op.getDomain()), dltx(preop.getRange()), applied(false), str(_str) { try{ dx.zero(); q.zero(); qrhs.zero(); if (pdcgne.verbose) { str<<"\n"; str<<"==============================================\n"; str<<"PIVAObj2 constructor - ls policy data = \n"; pdcgne.write(str); } } catch (RVLException & e) { e<<"\ncalled from LinFitLSP::Constructor\n"; throw e; } } PIVAObj2(PIVAObj2 const & f) : op(f.op), preop(f.preop), helmop(f.helmop), A(f.A), R(f.R), d(f.d), x0(f.x0), pdcgne(f.pdcgne), dx(f.dx), q(f.q), qrhs(f.qrhs), dltx(f.dltx), applied(f.applied), str(f.str) {} const Space & getDomain() const { return op.getDomain(); } Scalar getMaxStep(const Vector & x, const Vector & dx) const { try { return op.getMaxStep(x,dx); } catch (RVLException & e) { e<<"\ncalled from PIVAObj2::getMaxStep\n"; throw e; } } Vector const & getLSSoln() const { return dx; } Vector const & getCGSoln() const { return q; } Vector const & getCGRHS() const { //cerr << "qrhs.norm()=" << qrhs.norm() << endl; return qrhs; } ostream & write(ostream & str) const { str<<"PIVAObj2: \n"; str<<"*** operator:\n"; op.write(str); str<<"*** data vector:\n"; d.write(str); return str; } }; template class PIVAObj: public Functional { typedef typename ScalarFieldTraits::AbsType atype; private: Operator const & op; // operator LinearOp const & preop; // preconditioner LinearOp const & helmop; // smoothing op applied to gradient LinearOp const & A; // annihilator Vector const & d; // data Vector const & x0; // input initial linear solution CGNEPolicyData pdcgne; mutable Vector dx; // preimage of linear solution mutable Vector dltx; // linear solution mutable Vector q; // CG solution mutable bool applied; ostream & str; protected: void apply(const Vector & x, Scalar & val) const { try { /* if (applied) { RVLException e; e<<"Error: LinFitLS::apply(x,val)\n"; e<<"already applied, may not alter\n"; throw e; } */ atype rnorm; atype nrnorm; // access Operator through OperatorEvaluation OperatorEvaluation opeval(op,x); // Get Derivative of Operator LinearOp const & lop = opeval.getDeriv(); // for non-zero initial solution Vector d0(lop.getRange()); lop.applyOp(x0,d0); d0.linComb(1.0,d,-1.0); dx.zero(); // build least square solver , solve for dx CGNEPolicy cgnep; cgnep.assign(pdcgne); CGNEAlg * solver = cgnep.build(dx,lop,preop,d0,rnorm,nrnorm,str); solver->run(); // get the value of objective function //val = 0.5*rnorm*rnorm; dx.linComb(1.0,x0); A.applyOp(dx,dltx); val = dltx.norm() * 0.5f; // if (retrieveGlobalRank() == 0) { // cerr << "val="<< val << endl; // } applied = true; delete solver; } catch (RVLException & e) { e<<"\ncalled from PIVAObj::apply\n"; throw e; } } void applyGradient(const Vector & x, Vector & g) const { try{ if(!applied){ Scalar val; this->apply(x,val); // cerr << "\n val=" << val << endl; } atype rnorm; OperatorEvaluation opeval(op,x); LinearOp const & lop = opeval.getDeriv(); AdjLinearOp lopadj(lop); SymmetricBilinearOp const & sblop = opeval.getDeriv2(); // if (retrieveGlobalRank() == 0) { // cerr << "\n before RHS \n"; // } // build RHS Vector tmpb(op.getDomain()); // cerr << " before applying A " << endl; A.applyAdjOp(dltx,tmpb); CompLinearOp nop(lop, lopadj); CGAlg alg(q,nop,tmpb,rnorm,pdcgne.rtol,pdcgne.maxcount,pdcgne.Delta,str); alg.run(); Vector tmpd(lop.getRange()); lop.applyOp(q,tmpd); sblop.applyAdjOp(dx,tmpd,tmpb); tmpb.scale(-1.0f); helmop.applyOp(tmpb,g); } catch (RVLException & e) { e<<"\ncalled from PIVAObj::applyGradient\n"; throw e; } } void applyHessian(const Vector & x, const Vector & dx, Vector & dy) const {} Functional * clone() const { return new PIVAObj(*this); } public: /* typical policy data atype _rtol, atype _nrtol, int _maxcount, */ PIVAObj(Operator const & _op, LinearOp const & _preop, LinearOp const & _helmop, LinearOp const & _A, Vector const & _d, Vector const & _x0, CGNEPolicyData const & _pdcgne, ostream & _str=cerr) : op(_op), preop(_preop), helmop(_helmop), A(_A), d(_d), x0(_x0), pdcgne(_pdcgne), dx(preop.getDomain()), q(op.getDomain()), dltx(preop.getRange()), applied(false), str(_str) { try{ dx.zero(); q.zero(); if (pdcgne.verbose) { str<<"\n"; str<<"==============================================\n"; str<<"PIVAObj constructor - ls policy data = \n"; pdcgne.write(str); } } catch (RVLException & e) { e<<"\ncalled from LinFitLSP::Constructor\n"; throw e; } } PIVAObj(PIVAObj const & f) : op(f.op), preop(f.preop), helmop(f.helmop), A(f.A), d(f.d), x0(f.x0), pdcgne(f.pdcgne), dx(f.dx), q(f.q), dltx(f.dltx), applied(f.applied), str(f.str) {} const Space & getDomain() const { return op.getDomain(); } Scalar getMaxStep(const Vector & x, const Vector & dx) const { try { return op.getMaxStep(x,dx); } catch (RVLException & e) { e<<"\ncalled from PIVAObj::getMaxStep\n"; throw e; } } Vector const & getLSSoln() const { return dx; } Vector const & getCGSoln() const { return q; } ostream & write(ostream & str) const { str<<"PIVAObj: \n"; str<<"*** operator:\n"; op.write(str); str<<"*** data vector:\n"; d.write(str); return str; } }; } #endif