#ifndef __RVLALG_LINFIT_Cheb_H #define __RVLALG_LINFIT_Cheb_H /** Given an Operator F, a Vector d in the range of op, and a initial vector dx=x0 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. */ #include "chebalg.hh" #include "terminator.hh" #include "linop.hh" #include "table.hh" using namespace RVLAlg; namespace RVLUmin { using namespace RVL; using namespace RVLAlg; template class LinFitLSCheb: public Functional { typedef typename ScalarFieldTraits::AbsType atype; private: Operator const & op; // operator LinearOp const & preop; // preconditioner LinearOp const & helmop; // smoothing op applied to gradient Vector const & d; // data Vector const & x0; // input initial linear solution ChebPolicyData s; mutable Scalar specbd; // spectrum bound of DF(x) 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(); 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,x0); ChebPolicy chebp; chebp.assign(s); ChebAlg * solver = chebp.build(dx,gopeval.getDeriv(),d0,rnorm,nrnorm,str); solver->run(); specbd = solver-> getSpectrumBound(); // 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 LinFitLSCheb::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; } OperatorEvaluation opeval(op,x); LinearOp const & lop = opeval.getDeriv(); SymmetricBilinearOp const & sblop = opeval.getDeriv2(); Vector dltd(lop.getRange()); Vector gtmp(g.getSpace()); // compute dltx and dltd = DF * dltx - d lop.applyOp(dltx,dltd); // cerr << "\n dltx.norm()=" << dltx.norm() << endl; dltd.linComb(-1.0,d); //cerr << "\n dltd.norm()=" << dltd.norm() << endl; // naive computation of gradient sblop.applyAdjOp(dltx,dltd,gtmp); // cerr << "\n g.norm()=" << g.norm() << endl; // compute and add correction term to gradient // cerr << "\n LinFitLS refine=" << refine << endl; if (refine) { // cerr << "\n LinFitLS: inside refine branch\n" ; atype rnorm; atype nrnorm; OpComp gop(preop,lop); Vector tmp(gop.getDomain()); Vector dx1(gop.getDomain()); tmp.zero(); dx1.zero(); OperatorEvaluation gopeval(gop,x0); // solve DF * dx = dltd in LS sense ChebPolicyData param; param.maxcount=s.maxcount; param.gamma=s.gamma; param.epsilon=s.epsilon; param.alpha=s.alpha; param.lbd_est=specbd; cerr << "\n estimated spectrum bound is " << specbd << endl; param.verbose=false; ChebPolicy chebp; chebp.assign(param); ChebAlg * solver = chebp.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); // cerr << "\n LinFitLS:applyGradient term1.norm = " << g.norm() << endl; // cerr << "\n LinFitLS:applyGradient term2.norm = " << tmp.norm() << endl; gtmp.linComb(1.0, tmp2); // cerr << "\n LinFitLS:applyGradient g.norm = " << g.norm() << endl; } helmop.applyOp(gtmp,g); } 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 LinFitLSCheb(*this); } public: /* typical policy data atype _rtol, atype _nrtol, int _maxcount, */ LinFitLSCheb(Operator const & _op, LinearOp const & _preop, LinearOp const & _helmop, Vector const & _d, Vector const & _x0, ChebPolicyData const & _s, bool _refine=false, ostream & _str=cerr) : op(_op), helmop(_helmop), preop(_preop), d(_d), x0(_x0),s(_s), refine(_refine), dx(preop.getDomain()), dltx(preop.getRange()), applied(false), str(_str) { try{ dx.zero(); if (s.verbose) { str<<"\n"; str<<"==============================================\n"; str<<"LinFitLSCheb constructor - ls policy data = \n"; s.write(str); } } catch (RVLException & e) { e<<"\ncalled from LinFitLSCheb::Constructor\n"; throw e; } } LinFitLSCheb(LinFitLSCheb const & f) : op(f.op), preop(f.preop), helmop(f.helmop), d(f.d), x0(f.x0), s(f.s), 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<<"LinFitLSCheb: \n"; str<<"*** operator:\n"; op.write(str); str<<"*** data vector:\n"; d.write(str); return str; } }; } #endif