functional.hh

Go to the documentation of this file.
00001 /*************************************************************************
00002 
00003 Copyright Rice University, 2004, 2005, 2006
00004 All rights reserved.
00005 
00006 Permission is hereby granted, free of charge, to any person obtaining a
00007 copy of this software and associated documentation files (the "Software"),
00008 to deal in the Software without restriction, including without limitation
00009 the rights to use, copy, modify, merge, publish, distribute, and/or sell
00010 copies of the Software, and to permit persons to whom the Software is
00011 furnished to do so, provided that the above copyright notice(s) and this
00012 permission notice appear in all copies of the Software and that both the
00013 above copyright notice(s) and this permission notice appear in supporting
00014 documentation.
00015 
00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
00019 RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
00020 NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
00021 DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00022 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00023 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
00024 THIS SOFTWARE.
00025 
00026 Except as contained in this notice, the name of a copyright holder shall
00027 not be used in advertising or otherwise to promote the sale, use or other
00028 dealings in this Software without prior written authorization of the
00029 copyright holder.
00030 
00031 **************************************************************************/
00032 
00033 #ifndef __RVL_FUNC
00034 #define __RVL_FUNC
00035 
00036 #include "op.hh"
00037 #include "blockop.hh"
00038 
00039 namespace RVL {
00040  
00041   template<class Scalar>
00042   class FunctionalEvaluation;
00043 
00044   template<class Scalar>
00045   class Functional;
00046 
00047   template<class Scalar>
00048   class FcnlOpComp;
00049 
00050   template<class Scalar>
00051   class LinCombFunctional;
00052 
00098   template<class Scalar>
00099   class Functional: public Writeable {
00100 
00101     friend class FunctionalEvaluation<Scalar>;
00102     friend class FcnlOpComp<Scalar>;
00103     friend class LinCombFunctional<Scalar>;
00104 
00105   protected:
00106 
00113     virtual void apply(const Vector<Scalar> & x, 
00114                Scalar & val) const = 0;
00115 
00117     virtual void applyGradient(const Vector<Scalar> & x, 
00118                    Vector<Scalar> & g) const = 0;
00119 
00121     virtual void applyHessian(const Vector<Scalar> & x,
00122                   const Vector<Scalar> & dx, 
00123                   Vector<Scalar> & dy) const = 0;
00124 
00129     void export_apply(Functional<Scalar> const & f,
00130               const Vector<Scalar> & x,
00131               Scalar & val) const {
00132       f.apply(x,val);
00133     }
00134 
00135     void export_applyGradient(Functional<Scalar> const & f,
00136                   const Vector<Scalar> & x,
00137                   Vector<Scalar> & g) const {
00138       f.applyGradient(x,g);
00139     }
00140 
00141     void export_applyHessian(Functional<Scalar> const & f,
00142                  const Vector<Scalar> & x,
00143                  const Vector<Scalar> & dx, 
00144                  Vector<Scalar> & dy) const {
00145       f.applyHessian(x,dx,dy);
00146     }
00147 
00154 #ifndef RVL_OPERATOR_NEW_ENABLED
00155     void * operator new(size_t size) { 
00156       void * ptr;
00157       ptr = (void *) ::new unsigned char[size]; 
00158       return ptr;
00159     }
00160 #endif
00161 
00167     virtual Functional<Scalar> * clone() const = 0;
00168 
00169     void export_clone(Functional<Scalar> const & fref,
00170               Functional<Scalar> ** f) const {
00171       try {
00172     if (*f) {
00173       RVLException e;
00174       e<<"Error: Functional::export_clone\n";
00175       e<<"cannot clone to a non-null pointer\n";
00176       throw e;
00177     }
00178     *f = fref.clone();
00179       }
00180       catch (RVLException & e) {
00181     e<<"\ncalled from Functional::export_clone\n";
00182     throw e;
00183       }
00184     }
00185       
00186   public:
00187 
00188     Functional() {}
00189 
00190     Functional(const Functional<Scalar> &) {}
00191 
00192     virtual ~Functional() {}
00193 
00194     // access to domain
00195     virtual const Space<Scalar> & getDomain() const = 0;
00196 
00207     virtual Scalar getMaxStep(const Vector<Scalar> & x,
00208                   const Vector<Scalar> & dx) const {
00209       return numeric_limits<Scalar>::max();
00210     }
00211 
00237   };
00238 
00239   template<class Scalar>
00240   class FunctionalProductDomainEvaluation;
00241 
00243   template<class Scalar>
00244   class FunctionalProductDomain: public Functional<Scalar> {
00245 
00246     friend class FunctionalEvaluation<Scalar>;
00247     friend class FunctionalProductDomainEvaluation<Scalar>;
00248 
00249   protected:
00250 
00255     virtual void applyPartialGradient(int i,
00256                       const Vector<Scalar> & x,
00257                       Vector<Scalar> & g) const = 0;
00258 
00259     void export_applyPartialGradient(FunctionalProductDomain<Scalar> const & f,
00260                      int i,
00261                      const Vector<Scalar> & x,
00262                      Vector<Scalar> & g) const {
00263       try {
00264     f.applyPartialGradient(i,x,g);
00265       }
00266       catch (RVLException & e) {
00267     e<<"\ncalled from export_applyPartialGradient\n";
00268     throw e;
00269       }
00270     }
00271 
00275     virtual void applyGradient(const Vector<Scalar> & x,
00276                    Vector<Scalar> & g) const {
00277       try {
00278     Components<Scalar> cx(x);
00279     applyPartialGradient(0,cx[0],g);
00280     Vector<Scalar> tmp(g);
00281     for (int i=1;i<cx.getSize();i++) {
00282       applyPartialGradient(i,cx[i],tmp);
00283       g.linComb(ScalarFieldTraits<Scalar>::One(),tmp);
00284     }
00285       }
00286       catch (RVLException & e) {
00287     e<<"\ncalled from FunctionalProductDomain::applyGradient\n";
00288     throw e;
00289       }
00290     }
00291 
00300     virtual void applyPartialHessian(int i,
00301                      int j,
00302                      const Vector<Scalar> & x,
00303                      const Vector<Scalar> & dxj,
00304                      Vector<Scalar> & dxi) const = 0;
00305 
00306     void export_applyPartialHessian(FunctionalProductDomain<Scalar> const & f,
00307                     int i,
00308                     int j,
00309                     const Vector<Scalar> & x,
00310                     const Vector<Scalar> & dxj,
00311                     Vector<Scalar> & dxi) const {
00312       try {
00313     f.applyPartialHessian(i,j,x,dxj,dxi);
00314       }
00315       catch (RVLException & e) {
00316     e<<"\ncalled from export_applyPartialHessian\n";
00317     throw e;
00318       }
00319     }
00320 
00325     virtual void applyHessian(const Vector<Scalar> & x,
00326                   const Vector<Scalar> & yin,
00327                   Vector<Scalar> & yout) const {
00328       try {
00329     Components<Scalar> cyin(yin);
00330     Components<Scalar> cyout(yout);
00331     for (int i=0; i<cyin.getSize(); i++) {
00332       cyout[i].zero();
00333       Vector<Scalar> tmp(this->getProductDomain()[i]);
00334       for (int j=0; j<cyin.getSize(); j++) {
00335         applyPartialHessian(i,j,x,cyin[j],tmp);
00336         cyout[i].linComb(ScalarFieldTraits<Scalar>::One(),tmp);
00337       }
00338     }
00339       }
00340       catch (RVLException & e) {
00341     e<<"\ncalled from FunctionalProductDomain::applyHessian\n";
00342     throw e;
00343       }
00344     }
00345     virtual FunctionalProductDomain<Scalar> * clonePD() const = 0;
00346     Functional<Scalar> * clone() const { return clonePD(); }
00347 
00348   public:
00349 
00350     // Default constructor.
00351     FunctionalProductDomain() {}
00352     // Copy constructor.
00353     FunctionalProductDomain(const FunctionalProductDomain<Scalar> &) {}
00354     // Destructor.
00355     virtual ~FunctionalProductDomain() {}
00356 
00359     const Space<Scalar> & getDomain() const { 
00360       return getProductDomain(); 
00361     }
00366     virtual const ProductSpace<Scalar> & getProductDomain() const = 0;
00367 
00368     // This method checks the analytic second derivatives against the
00369     // second order finite-difference formula
00370     //
00371     //     \[D_{ij}f(x)(\delta x_j,\delta x_i) \doteq 
00372     //          f(x+\tilde{\delta x_i}+\tilde{\delta x_j})+
00373     //          f(x-\tilde{\delta x_i}-\tilde{\delta x_j})-
00374     //          f(x+\tilde{\delta x_i})-
00375     //          f(x-\tilde{\delta x_i})-
00376     //          f(x+\tilde{\delta x_j})-
00377     //          f(x-\tilde{\delta x_j})+2f(x)\].
00378     //
00379     //  Here $\tilde{\delta x_i}$ is the vector in the domain of $f$ with every
00380     //  component equal to zero except the $i$th, which equals $\delta x_i$.
00381   
00410   };
00411 
00412   template<class Scalar>
00413   class HessianEvaluation;
00414 
00415   template<class Scalar>
00416   class PartialHessianEvaluation;
00417 
00423   template<class Scalar>
00424   class FunctionalEvaluation: public Writeable {
00425 
00426     friend class HessianEvaluation<Scalar>;
00427     friend class PartialHessianEvaluation<Scalar>;
00428     friend class FcnlOpComp<Scalar>;
00429     typedef typename ScalarFieldTraits<Scalar>::AbsType NormRetType;
00430 
00431   private:
00432 
00433     // Vector and functional are independent copies
00434     const Functional<Scalar> & fref;
00435     WatchedVecRef<Scalar> wx;
00436     mutable Functional<Scalar> * f;
00437 
00438     mutable Scalar val;
00439     mutable bool applied;
00440     mutable Vector<Scalar> grad;
00441     mutable bool gapplied;
00442     mutable NormRetType gnorm;
00443     mutable bool gnormapplied;
00444 
00445     // disabled
00446     FunctionalEvaluation();
00447 
00448     void reset() const {
00449       try {
00450     if (f) delete f;
00451     f = fref.clone();
00452     applied=false;
00453     gapplied=false;
00454     gnormapplied=false;
00455       }
00456       catch (RVLException & e) {
00457     e<<"\ncalled from FunctionalEvaluation::reset\n";
00458     throw e;
00459       }
00460     }
00461 
00462   protected:
00463 
00464     // accessed in product domain subclasses
00465     Components<Scalar> cg;
00466     HessianEvaluation<Scalar> hess;
00467 
00468     // access through HessianEvaluation
00469     void applyHessian(const Vector<Scalar> & yin,
00470               Vector<Scalar> & yout) const {
00471       try {
00472     if (wx.update()) reset();
00473     f->applyHessian(wx.get(),yin,yout);
00474       }
00475       catch (RVLException & e) {
00476     e<<"\ncalled from FunctionalEvaluation::applyHessian()\n";
00477     throw e;
00478       }
00479     }
00480     
00488     const ProductSpace<Scalar> & getProductDomain() const {
00489       
00490       try {
00491     const FunctionalProductDomain<Scalar> & pf =
00492       dynamic_cast<const FunctionalProductDomain<Scalar> &>(fref);
00493     return pf.getProductDomain();
00494       }
00495       catch (bad_cast) {
00496     RVLException e;
00497     e<<"Error: FunctionalEvaluation::getProductDomain\n";
00498     e<<"referenced Functional does not have ProductSpace domain\n";
00499     throw e;
00500       }
00501       catch (RVLException & e) {
00502     e<<"\ncalled from FunctionalEvaluation::getProductDomain\n";
00503     throw e;
00504       }
00505     }
00506 
00507     // this version computes entire gradient
00508     Vector<Scalar> const & getPartialGradient(int i) const {
00509       try {
00510     if (wx.update()) reset();
00511     if (!gapplied) {
00512       //      grad.relLock();
00513       f->applyGradient(wx.get(),grad);
00514       gapplied=true;
00515       //      grad.setLock();
00516     }
00517     return cg[i];
00518       }
00519       catch (RVLException & e) {
00520     e<<"\ncalled from FunctionalEvaluation::getPartialGradient\n";
00521     throw e;
00522       }
00523     }
00524 
00528     void applyPartialHessian(int i,
00529                  int j,
00530                  const Vector<Scalar> & dxi,
00531                  Vector<Scalar> & dxj) const {
00532       try {
00533     if (wx.update()) reset();
00534     FunctionalProductDomain<Scalar> * pf = NULL;
00535     if ((pf = dynamic_cast<FunctionalProductDomain<Scalar> *>(f))) {
00536       pf->applyPartialHessian(i,j,wx.get(),dxi,dxj);
00537     }
00538     else {
00539       RVLException e;
00540       e<<"Error: FunctionalEvaluation::applyPartialHessian\n";
00541       e<<"referenced Functional does not have ProductSpace domain\n";
00542       e<<"so Hessian block structure not defined\n";
00543       throw e;
00544     }
00545       }
00546       catch (RVLException & e) {
00547     e<<"\ncalled from FunctionalEvaluation";
00548     e<<"::applyHessianBloack()\n";
00549     throw e;
00550       }
00551     }
00552 
00559 #ifndef RVL_OPERATOR_NEW_ENABLED
00560     void * operator new(size_t size) { 
00561       void * ptr;
00562       ptr = (void *) ::new unsigned char[size]; 
00563       return ptr;
00564     }
00565 #endif
00566 
00567   public:
00568 
00574     FunctionalEvaluation(const Functional<Scalar> & _f, 
00575              const Vector<Scalar> & x)
00576       : fref(_f), wx(x), f(_f.clone()), 
00577     applied(false), grad(fref.getDomain()), 
00578     gapplied(false), gnormapplied(false),
00579     cg(grad), hess(*this)
00580     {
00581       grad.zero();
00582       
00583       if (x.getSpace() != fref.getDomain()) {
00584     RVLException e;
00585     e<<"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
00586     e<<"Error: FunctionalEvaluation constructor\n";
00587     e<<"-- input not in domain of Functional \n";
00588     e<<"**********************\n";
00589     e<<"*** this fnctnl:   ***\n";
00590     e<<"**********************\n";
00591     fref.write(e);
00592     e<<"**********************\n";
00593     e<<"*** domain space:  ***\n";
00594     e<<"**********************\n";
00595     fref.getDomain().write(e);
00596     e<<"**********************\n";
00597     e<<"*** input space:   ***\n";
00598     e<<"**********************\n";
00599     x.getSpace().write(e);
00600     e<<"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
00601     throw e;
00602       }
00603 
00604     }
00605 
00606     FunctionalEvaluation(const FunctionalEvaluation<Scalar> & ev)
00607       : wx(ev.wx), f(ev.fref.clone()), fref(ev.fref), 
00608     applied(false),
00609     grad(fref.getDomain()),
00610     cg(grad), gapplied(false), gnormapplied(false),
00611     hess(*this) { grad.zero(); }
00612 
00613     virtual ~FunctionalEvaluation() { 
00614       if (f) delete f;
00615     }
00616 
00618     const Space<Scalar> & getDomain() const {
00619       try { return fref.getDomain(); }
00620       catch (RVLException & e) {
00621     e<<"\ncalled from FunctionalEvaluation::getDomain\n";
00622     throw e;
00623       }
00624     }
00625 
00629     Scalar getMaxStep(const Vector<Scalar> & dx) const {
00630       const Vector<Scalar> & fruit = getPoint();
00631       return fref.getMaxStep(fruit,dx);
00632     }
00633 
00635     Vector<Scalar> & getPoint() { return wx.get(); }
00636     Vector<Scalar> const & getPoint() const { return wx.get(); }
00637 
00641     Scalar getValue() const {
00642       try {
00643     if (wx.update()) {
00644       reset();
00645     }
00646     if (!applied) {
00647       f->apply(wx.get(),val);
00648       applied = true;
00649     }
00650     return val;
00651       }
00652       catch (RVLException & e) {
00653     e<<"\ncalled from FunctionalEvaluation::getValue()\n";
00654     throw e;
00655       }
00656     }
00657 
00663     Vector<Scalar> const & getGradient() const {
00664       try {
00665     if (wx.update()) {
00666       reset();
00667     }
00668     if (!gapplied) {
00669       grad.zero();
00670       f->applyGradient(wx.get(),grad);
00671       gapplied=true;
00672     }
00673     return grad;
00674       }
00675       catch (RVLException & e) {
00676     e<<"\ncalled from FunctionalEvaluation::getGradient\n";
00677     throw e;
00678       }
00679     }
00680     
00686     Scalar getGradientNorm() const {
00687       try {
00688     if (wx.update()) {
00689       reset();
00690     }
00691     if (!gnormapplied) {
00692       gnorm = getGradient().norm();
00693       gnormapplied = true;
00694     }
00695     return gnorm;
00696       }
00697       catch (RVLException & e) {
00698     e<<"\ncalled from FunctionalEvaluation::getGradientNorm\n";
00699     throw e;
00700       }
00701     }
00702 
00709     LinearOp<Scalar> const & getHessian() const { return hess; }
00710     
00714     Functional<Scalar> const & getFunctional() const { return *f; }
00715 
00716     ostream & write(ostream & str) const {
00717       str<<"Functional Evaluation:"<<endl;
00718       str<<"  functional"<<endl;
00719       fref.write(str);
00720       str<<"  evaluated at\n";
00721       wx.get().write(str);
00722       return str;
00723     }
00724   };
00725 
00730   template<class Scalar>
00731   class HessianEvaluation: public BlockLinearOp<Scalar> {
00732 
00733   private:
00734     
00735     FunctionalEvaluation<Scalar> const & fx;
00736     StdProductSpace<Scalar> unique_dom;
00737     
00738     // disabled
00739     HessianEvaluation();
00740     HessianEvaluation(const HessianEvaluation<Scalar> & h)
00741       : fx(h.fx), unique_dom(h.unique_dom) {}
00742 
00743   protected:
00744     
00745     BlockLinearOp<Scalar> * cloneBlockLinearOp() const {
00746       return new HessianEvaluation<Scalar>(*this);
00747     }
00748 
00749     LinearOp<Scalar> * clone() const {
00750       return cloneBlockLinearOp();
00751     }
00752 
00753     void apply(int i, int j,
00754            const Vector<Scalar> & xj, 
00755            Vector<Scalar> & yi) const {
00756       try {
00757     fx.applyPartialHessian(i,j,xj,yi);
00758       }
00759       catch (RVLException & e) {
00760     if (i != 0 || j != 0) {
00761       RVLException e;
00762       e<<"Error: HessianEvaluation::apply(i,j,...)\n";
00763       e<<"  eval not product domain - i="<<i<<" j="<<j<<" not allowed\n";
00764       e<<"  must both be = 0\n";
00765       throw e;
00766     }
00767     fx.applyHessian(xj,yi);
00768       }
00769     }
00770     
00771     // image of adjoint (transpose) operator
00772     void applyAdj(int i, int j, 
00773           const Vector<Scalar> & yi,
00774           Vector<Scalar> & xj) const {
00775       try {
00776     fx.applyPartialHessian(j,i,yi,xj);
00777       }
00778       catch (RVLException & e) {
00779     if (i != 0 || j != 0) {
00780       RVLException e;
00781       e<<"Error: HessianEvaluation::applyAdj(i,j,...)\n";
00782       e<<"  eval not product domain - i="<<i<<" j="<<j<<" not allowed\n";
00783       e<<"  must both be = 0\n";
00784       throw e;
00785     }
00786     fx.applyHessian(yi,xj);
00787       }
00788     }
00789     
00790   public:
00791 
00792     HessianEvaluation(FunctionalEvaluation<Scalar> const & _fx)
00793       : fx(_fx),
00794     unique_dom(fx.getDomain())
00795     {}
00796     ~HessianEvaluation() {}
00797 
00798     // access to domain and range
00799     const Space<Scalar> & getDomain() const { return fx.getDomain(); }
00800     const ProductSpace<Scalar> & getProductDomain() const {
00801       try {
00802     return fx.getProductDomain();
00803       }
00804       catch (RVLException & e) {
00805     return unique_dom;
00806       }
00807     }
00808     /*
00809       FunctionalProductDomainEvaluation<Scalar> const * fpd = NULL;
00810       if ((fpd=dynamic_cast<FunctionalProductDomainEvaluation<Scalar> const *>(&fx))) 
00811     return fpd->getProductDomain();
00812       else 
00813     }
00814     */
00815 
00816     const Space<Scalar> & getRange() const { return fx.getDomain(); }
00817     const ProductSpace<Scalar> & getProductRange() const {
00818       try {
00819     return fx.getProductDomain();
00820       }
00821       catch (RVLException & e) {
00822     return unique_dom;
00823       }
00824     }
00825     /*
00826       FunctionalProductDomainEvaluation<Scalar> const * fpd = NULL;
00827       if ((fpd=dynamic_cast<FunctionalProductDomainEvaluation<Scalar> const *>(&fx))) 
00828     return fpd->getProductDomain();
00829       else return unique_dom;
00830     }
00831     */
00832 
00834     ostream & write(ostream & str) const {
00835       str<<"Hessian operator"<<endl;
00836       str<<"part of functional evaluation"<<endl;
00837       fx.write(str);
00838       return str;
00839     }
00840   };
00841 
00845   template<class Scalar>
00846   class FunctionalProductDomainEvaluation: 
00847     public FunctionalEvaluation<Scalar> {
00848 
00849   private:
00850 
00851     // disabled
00852     FunctionalProductDomainEvaluation();
00853     FunctionalProductDomainEvaluation
00854     (const FunctionalProductDomainEvaluation<Scalar> &);
00855   
00856   public:
00857   
00858     FunctionalProductDomainEvaluation(FunctionalProductDomain<Scalar> & _f, 
00859                       const Vector<Scalar> & _x)
00860       : FunctionalEvaluation<Scalar>(_f,_x) {}
00861 
00862     ~FunctionalProductDomainEvaluation() {}
00863 
00864     
00865 
00867     Vector<Scalar> const & getPartialGradient(int i) const {
00868       try {
00869     return FunctionalEvaluation<Scalar>::getPartialGradient(i);
00870       }
00871       catch (RVLException & e) {
00872     e<<"\ncalled from FunctionalProductDomainEvaluation";
00873     e<<"::getPartialGradient\n";
00874     throw e;
00875       }
00876     }
00877 
00881     const BlockLinearOp<Scalar> & getPartialHessian() const { 
00882       return FunctionalEvaluation<Scalar>::hess; }
00883 
00884     ostream & write(ostream & str) const {
00885       str<<"Functional Evaluation with Product Domain; as"<<"\n";
00886       return FunctionalEvaluation<Scalar>::write(str);
00887     }
00888   };
00889 
00921   template<class Scalar>
00922   class LinCombFunctional: public Functional<Scalar> {
00923   private:
00924   
00925     mutable std::vector<Functional<Scalar> *> fnvec;
00926     mutable std::vector<Scalar> wtvec;
00927     mutable bool applied;
00928 
00930     void setNext(Scalar a, Functional<Scalar> & fn) {
00931       try {
00932     if (applied) {
00933       RVLException e;
00934       e<<"Error: LinCombFunctional::setNext\n";
00935       e<<"object already initialized - non-initialization method called\n";
00936       e<<"further alteration to object data not allowed\n";
00937       throw e;
00938     }
00939     if (fnvec.size() > 0) {
00940       if (fn.getDomain() != fnvec[0]->getDomain()) {
00941         RVLException e;
00942         e<<"Error: LinCombOp::setNext\n";
00943         e<<"domain of input Functional incompatible with reference (summand 0)\n";
00944         e<<"*** input Functional:\n";
00945         fn.write(e);
00946         e<<"*** reference Functional:\n";
00947         fnvec[0]->write(e);
00948         throw e;
00949       }
00950     }
00951     wtvec.push_back(a);
00952     fnvec.push_back(fn.clone());
00953       }
00954       catch (RVLException & e) {
00955     e<<"\ncalled from LinCombFunctional::setNext\n";
00956     throw e;
00957       }
00958     }
00959 
00960   protected:
00961 
00962     void apply(const Vector<Scalar> & x, 
00963            Scalar & val) const {
00964       try {
00965    
00966     if (fnvec.size()<1) {
00967       RVLException e;
00968       e<<"Error: LinCombFcnl::apply\n";
00969       e<<"not initialized\n";
00970       throw e;
00971     }
00972     applied = true;
00973     this->export_apply(*(fnvec[0]),x,val);
00974     val *= wtvec[0];
00975     if (fnvec.size() > 1) {
00976       Scalar tmp;
00977       for (int i=1; i<fnvec.size(); i++) {
00978         this->export_apply(*(fnvec[i]),x,tmp);
00979         val += wtvec[i]*tmp;
00980       }
00981     }
00982       }
00983       catch (RVLException & e) {
00984     e<<"\ncalled from LinCombFunctional::apply\n";
00985     throw e;
00986       }
00987     }
00988 
00989     void applyGradient(const Vector<Scalar> & x,
00990                Vector<Scalar> & g) const {
00991       try {
00992     if (fnvec.size()<1) {
00993       RVLException e;
00994       e<<"Error: LinCombFcnl::applyGradient\n";
00995       e<<"not initialized\n";
00996       throw e;
00997     }
00998     applied = true;
00999     this->export_applyGradient(*(fnvec[0]),x,g);
01000     g.scale(wtvec[0]);
01001     if (fnvec.size() > 1) {
01002       Vector<Scalar> tmp(fnvec[0]->getDomain());
01003       for (int i=1; i<fnvec.size(); i++) {
01004         this->export_applyGradient(*(fnvec[i]),x,tmp);
01005         g.linComb(wtvec[i],tmp);
01006       }
01007     }
01008       }
01009       catch (RVLException & e) {
01010     e<<"\ncalled from LinCombFunctional::applyDeriv\n";
01011     throw e;
01012       }
01013     }
01014 
01015     void applyHessian(const Vector<Scalar> & x,
01016               const Vector<Scalar> & dx,
01017               Vector<Scalar> & dy) const {
01018       try {
01019     if (fnvec.size()<1) {
01020       RVLException e;
01021       e<<"Error: LinCombOp::applyHessian\n";
01022       e<<"not initialized\n";
01023       throw e;
01024     }
01025     applied = true;
01026     this->export_applyHessian(*(fnvec[0]),x,dx,dy);
01027     dy.scale(wtvec[0]);
01028     if (fnvec.size() > 1) {
01029       Vector<Scalar> tmp(fnvec[0]->getDomain());
01030       for (int i=1; i<fnvec.size(); i++) {
01031         this->export_applyHessian(*(fnvec[i]),x,dx,tmp);
01032         dy.linComb(wtvec[i],tmp);
01033       }
01034     }
01035       }
01036       catch (RVLException & e) {
01037     e<<"\ncalled from LinCombFunctional::applyHessian\n";
01038     throw e;
01039       }
01040     }
01041 
01042     Functional<Scalar> * clone() const { 
01043       applied = true;
01044       return new LinCombFunctional<Scalar>(*this); 
01045     }
01046 
01047   public:
01048   
01049     LinCombFunctional() {}
01050     LinCombFunctional(LinCombFunctional<Scalar> const & fn) {
01051       try {
01052     for (int i=0;i<fn.fnvec.size(); i++) {
01053       fnvec.push_back(fn.fnvec[i]->clone());
01054       wtvec.push_back(fn.wtvec[i]);
01055     }   
01056       }
01057       catch (RVLException & e) {
01058     e<<"\ncalled from LinCombFunctional copy constructor\n";
01059     throw e;
01060       }
01061     }
01062 
01063     LinCombFunctional(Scalar a1,const Functional<Scalar> & fn1,
01064               Scalar a2,const Functional<Scalar> & fn2)
01065       : fnvec(2), wtvec(2) {
01066       try {
01067     if (fn1.getDomain() != fn2.getDomain()) {      
01068       RVLException e;
01069       e<<"Error: LinCombFunctional pair constructor\n";
01070       e<<"domains do not matcth\n";
01071       e<<"first Functional:\n";
01072       fn1.write(e);
01073       e<<"second Functional:\n";
01074       fn2.write(e);
01075       throw e;
01076     }
01077     fnvec[0] = fn1.clone();
01078     fnvec[1] = fn2.clone();
01079     wtvec[0] = a1;
01080     wtvec[1] = a2;
01081       }
01082       catch (RVLException & e) {
01083     e<<"\ncalled from LinCombFunctional pair constructor\n";
01084     throw e;
01085       }
01086     }
01087 
01088     ~LinCombFunctional() {
01089       for (int i=0;i<fnvec.size(); i++) if (fnvec[i]) delete fnvec[i];
01090     }
01091 
01093     const Space<Scalar> & getDomain() const {
01094       try {
01095     if (fnvec.size()<1) {
01096       RVLException e;
01097       e<<"Error: LinCombFunctional::getDomain\n";
01098       e<<"object not initialized\n";
01099       throw e;
01100     }
01101     applied = true;
01102     return fnvec[0]->getDomain();
01103       }
01104       catch (RVLException & e) {
01105     e<<"\ncalled from LinCombFunctional::getDomain\n";
01106     throw e;
01107       }
01108     }
01109 
01110     ostream & write(ostream & str) const {
01111       str<<"LinCombFunctional: linear combination of scalar-valued functions\n";
01112       if (fnvec.size()<1) {
01113     str<<"not initialized\n";
01114       }
01115       else {
01116     for (int i=0;i<fnvec.size();i++) {
01117       str<<" --- Functional "<<i<<" with weight "<<wtvec[i]<<"\n";
01118       fnvec[i]->write(str);
01119     }
01120       }
01121       return str;
01122     }
01123   };
01124 
01151   template<class Scalar, class DataType = Scalar>
01152   class StdFOFunctional : public Functional<Scalar> {
01153   protected:
01154     FunctionObjectScalarRedn<Scalar> & f;
01155     FunctionObject & gradf;
01156     FunctionObject & hessf;
01157     Space<Scalar> const & dom;    
01158 
01162     virtual void apply(const Vector<Scalar> & x, 
01163                Scalar & val) const {
01164       //replace with component-wise statements (D.S. 04.10.11)
01165           x.eval(f);
01166           val = f.getValue(); 
01167       //Components<Scalar> cx(x);
01168       //int csize = cx.getSize();
01169       //val = ScalarFieldTraits<Scalar>::Zero();
01170       //for (int i=0; i< csize; i++) {
01171       //cx[i].eval(f);
01172       //val += f.getValue();
01173       //}
01174     }
01175 
01177     virtual void applyGradient(const Vector<Scalar> & x, 
01178                    Vector<Scalar> & g) const {
01179       g.eval(gradf,x);
01180     }
01181 
01183     virtual void applyHessian(const Vector<Scalar> & x,
01184                   const Vector<Scalar> & dx, 
01185                   Vector<Scalar> & dy) const {
01186       dy.eval(hessf,x,dx);
01187     }
01188 
01194     virtual Functional<Scalar> * clone() const {
01195       return new StdFOFunctional<Scalar,DataType>(*this);
01196     }
01197 
01198     StdFOFunctional();
01199   public:
01200     
01203     StdFOFunctional( FunctionObjectScalarRedn<Scalar> & f_,
01204              FunctionObject & gradf_,
01205              FunctionObject & hessf_,
01206              const Space<Scalar> & dom_)
01207       : f(f_), gradf(gradf_), hessf(hessf_), dom(dom_) {}
01208 
01209     StdFOFunctional( const StdFOFunctional<Scalar, DataType> & s)
01210       : f(s.f), gradf(s.gradf), hessf(s.hessf), dom(s.dom) {}
01211     
01212     ~StdFOFunctional() {}
01213 
01214     // access to domain
01215     virtual const Space<Scalar> & getDomain() const { return dom; }
01216 
01217     virtual ostream & write(ostream & str) const {
01218       str << "StdFOFunctional with f = ";
01219       f.write(str);
01220       str << "\n gradf = ";
01221       gradf.write(str);
01222       str << "\n hessf = ";
01223       hessf.write(str);
01224       return str;
01225     }
01226   };
01227 
01228   /*
01229   template<class Scalar>
01230   bool Functional<Scalar>::checkHessian(const Vector<Scalar> & y,
01231                     const Vector<Scalar> & p,
01232                     ostream & str,
01233                     int n,
01234                     Scalar hmin,
01235                     Scalar hmax) {
01236     try {
01237       if (!y.inSpace(getDomain())) {
01238     RVLException e; e<<"Error in Functional::checkGradient: \n";
01239     e<<"base vector is not in Domain\n";
01240     throw e;
01241       }
01242       if (!p.inSpace(getDomain())) {
01243     RVLException e; e<<"Error in Functional::checkGradient: \n";
01244     e<<"direction vector is not in Domain\n";
01245     throw e;
01246       }
01247    
01248       if (hmax <= hmin) {
01249     Scalar temp = hmax;
01250     hmax = hmin;
01251     hmin = temp;
01252       }
01253       if (hmin <= 0.0) {
01254     hmin = 0.1;
01255     hmax = 1.0;
01256       }
01257       if (n <= 0)
01258     n = 10;
01259       
01260       Scalar hlimit1;
01261       Scalar hlimit2;
01262       hlimit1 = getMaxStep(y,p);
01263       {
01264     Vector<Scalar> ptemp(getDomain());
01265     ptemp.scale(-1.0,p);
01266     hlimit2 = getMaxStep(y,ptemp);
01267       }
01268       Scalar hlimit = min(hlimit1,hlimit2);
01269       if (hlimit <= 0.0) {
01270     RVLException e; e<<"Error in Functional::checkHessian: \n";
01271     e<<"direction is not feasible\n";
01272     throw e;
01273       }
01274       if (hmax >= hlimit) {
01275     hmax = 0.99*hlimit;
01276     if (hmin >= hmax)
01277       hmin = hmax/n;
01278       }
01279 
01280       Vector<Scalar> x1(getDomain());
01281       Vector<Scalar> x2(getDomain());
01282       Vector<Scalar> g1(getDomain());
01283       Vector<Scalar> g2(getDomain());
01284       Vector<Scalar> dg(getDomain());
01285 
01286       FunctionalEvaluation<Scalar> Fy(*this,y);
01287       Fy.getHessian().applyOp(p,dg);
01288 
01289       int nd;
01290       if (numeric_precision<Scalar>()==1) nd = 8;
01291       if (numeric_precision<Scalar>()==2) nd = 16;
01292 
01293       int oldprecision = str.precision(nd);
01294 
01295       Scalar dgnorm = dg.norm();
01296       int rflag = 1;
01297       if (dgnorm < numeric_limits<Scalar>::epsilon()) {
01298     rflag = 0;
01299     str << "Functional::checkHessian: norm of gradient is too "
01300         << endl << "small; displaying absolute error" << endl;
01301       }
01302       
01303       str<<endl<<"Hessian Computation Check"<<endl<<endl;
01304       
01305       if (rflag)
01306     str << setw(8) << "h" << setw(nd+7) << "norm of diff."
01307         << setw(nd+8) << "norm" << setw(nd+6) << "Rel. Err."
01308         << endl;
01309       else
01310     str << setw(8) << "h" << setw(nd+7) << "norm of diff."
01311         << setw(nd+6) << "norm" << endl;
01312       int i;
01313       Scalar hstep = (hmax-hmin)/(n-1);
01314       for (i=n-1;i>=0;i--) {
01315     Scalar h = hmin+i*hstep;
01316     x1.copy(y);
01317     x1.linComb(-h,p);
01318     FunctionalEvaluation<Scalar> F1(*this,x1);
01319     x2.copy(y);
01320     x2.linComb(h,p);
01321     FunctionalEvaluation<Scalar> F2(*this,x2);
01322     g2.copy(F2.getGradient());
01323     g2.linComb(-1.0,F1.getGradient());
01324     g2.scale(1.0/(2.0*h));
01325     g2.linComb(-1.0,dg);
01326     Scalar n1 = g2.norm();
01327     if (rflag)
01328       str << setprecision(6) << setw(8) << h << " "
01329           << setprecision(nd) << setw(nd+6) << n1 << " " 
01330           << setw(nd+6) << dgnorm << " " << setw(nd+6)
01331           << n1/dgnorm << endl;
01332     else
01333       str << setprecision(6) << setw(8) << h << " "
01334           << setprecision(nd) << setw(nd+6) << n1 << " " 
01335           << setw(nd+6) << dgnorm << " " << endl;
01336       }
01337       str.precision(oldprecision);
01338       return 0;
01339     }
01340     catch (RVLException & e) {
01341       e<<"\ncalled from Functional::checkHessian\n";
01342       throw e;
01343     }
01344   }
01345 
01346   template<class Scalar>
01347   bool FunctionalProductDomain<Scalar>::checkPartialHessian
01348   (const Vector<Scalar> & y,
01349    const Vector<Scalar> & pi,
01350    const Vector<Scalar> & pj,
01351    int i,
01352    int j,
01353    ostream & str,
01354    int n,
01355    Scalar hmin,
01356    Scalar hmax) {
01357     try {
01358       if (i==j)
01359     return checkPartialHessian(y,pi,i,str,n,hmin,hmax);
01360       
01361       if (i < 1 || i > getProductDomain().getSize() || j < 1 ||
01362       j > getProductDomain().getSize()) {
01363     RVLException e; e<<"Error in FunctionalProductDomain::";
01364     e<<"checkPartialHessian: \n";
01365     e<<"invalid index\n";
01366     throw e;
01367       }
01368       if (!y.inSpace(getDomain())) {
01369     RVLException e; e<<"Error in FunctionalProductDomain::";
01370     e<<"checkPartialHessian: \n";
01371     e<<"base vector is not in Domain\n";
01372     throw e;
01373       }
01374       if (!pi.inSpace(getProductDomain()[i])) {
01375     RVLException e; e<<"Error in FunctionalProductDomain::";
01376     e<<"checkPartialHessian: \n";
01377     e<<"direction vector pi is not in Domain\n";
01378     throw e;
01379       }
01380       if (!pj.inSpace(getProductDomain()[j])) {
01381     RVLException e; e<<"Error in FunctionalProductDomain::";
01382     e<<"checkPartialHessian: \n";
01383     e<<"direction vector pj is not in Domain\n";
01384     throw e;
01385       }
01386 
01387       if (hmax <= hmin) {
01388     Scalar temp = hmax;
01389     hmax = hmin;
01390     hmin = temp;
01391       }
01392       if (hmin <= 0.0) {
01393     hmin = 0.1;
01394     hmax = 1.0;
01395       }
01396       if (n <= 0)
01397     n = 10;
01398       
01399       // There are now six directions to check: pi+pj,-pi-pj,pi,-pi,pj,-pj
01400       Scalar hlimit;
01401       {
01402     Vector<Scalar> yp(getDomain());
01403     yp.zero();
01404     Components<Scalar> cy(yp);
01405     yp[i].copy(pi);
01406     yp[j].copy(pj);
01407     hlimit = getMaxStep(y,yp);
01408     yp.negate();
01409     hlimit = min(getMaxStep(y,yp),hlimit);
01410     yp.zero();
01411     yp[i].copy(pi);
01412     hlimit = min(getMaxStep(y,yp),hlimit);
01413     yp.negate();
01414     hlimit = min(getMaxStep(y,yp),hlimit);
01415     yp.zero();
01416     yp[j].copy(pj);
01417     hlimit = min(getMaxStep(y,yp),hlimit);
01418     yp.negate();
01419     hlimit = min(getMaxStep(y,yp),hlimit);
01420       }
01421       if (hlimit <= 0.0) {
01422     RVLException e; e<<"Error in FunctionalProductDomain::";
01423     e<<"checkPartialHessian: direction is not feasible\n";
01424     throw e;
01425       }
01426       if (hmax >= hlimit) {
01427     hmax = 0.99*hlimit;
01428     if (hmin >= hmax)
01429       hmin = hmax/n;
01430       }
01431 
01432       Vector<Scalar> x1(getDomain());
01433       Scalar v0,dv;
01434 
01435       FunctionalProductDomainEvaluation<Scalar> Fy(*this,y);
01436       Vector<Scalar> pi1(getProductDomain()[i]);
01437       Fy.getPartialHessian(i,j).applyOp(pj,pi1);
01438       dv = pi.inner(pi1);
01439 
01440       int nd;
01441       if (numeric_precision<Scalar>()==1) nd = 8;
01442       if (numeric_precision<Scalar>()==2) nd = 16;
01443       int oldprecision = str.precision(nd);
01444 
01445       Scalar dvmag = abs(dv);
01446       int rflag = 1;
01447       if (dvmag < numeric_limits<Scalar>::epsilon()) {
01448     rflag = 0;
01449     str << "FunctionalProductDomain::CheckPartialHessian: norm of "
01450       "second variation is too "
01451         << endl << "small; displaying absolute error" << endl;
01452       }
01453       if (rflag)
01454     str << setw(5) << "h" << setw(nd+6) << "2nd variation" << setw(nd+6)
01455         << "cent. diff." << setw(nd+4) << "Rel. Err." << endl;
01456       else
01457     str << setw(5) << "h" << setw(nd+6) << "2nd variation" << setw(nd+6)
01458         << "cent. diff." << setw(nd+4) << "Error" << endl;
01459       int ii;
01460       Scalar hstep = (hmax-hmin)/(n-1);
01461       Scalar val;
01462       Components<Scalar> cx1(x1);
01463       for(ii=n-1;ii>=0;ii--) {
01464     Scalar v = 2.0*Fy.getValue();
01465     Scalar h = hmin+ii*hstep
01466 ;
01467     x1.copy(y);
01468     cx1[i].linComb(h,pi);
01469     cx1[j].linComb(h,pj);
01470     {
01471       FunctionalEvaluation<Scalar> Fp(*this,x1);
01472       v += Fp.getValue();
01473     }
01474 
01475     x1.copy(y);
01476     cx1[i].linComb(-h,pi);
01477     cx1[j].linComb(-h,pj);
01478     {
01479       FunctionalEvaluation<Scalar> Fp(*this,x1);
01480       v += Fp.getValue();
01481     }
01482     
01483     x1.copy(y);
01484     cx1[i].linComb(h,pi);
01485     {
01486       FunctionalEvaluation<Scalar> Fp(*this,x1);
01487       v -= Fp.getValue();
01488     }
01489 
01490     x1.copy(y);
01491     cx1[i].linComb(-h,pi);
01492     {
01493       FunctionalEvaluation<Scalar> Fp(*this,x1);
01494       v -= Fp.getValue();
01495     }
01496 
01497     x1.copy(y);
01498     cx1[j].linComb(h,pj);
01499     {
01500       FunctionalEvaluation<Scalar> Fp(*this,x1);
01501       v -= Fp.getValue();
01502     }
01503 
01504     x1.copy(y);
01505     cx1[j].linComb(-h,pj);
01506     {
01507       FunctionalEvaluation<Scalar> Fp(*this,x1);
01508       v -= Fp.getValue();
01509     }
01510 
01511     v /= (2.0*h*h);
01512     Scalar n1 = abs(v-dv);
01513     
01514     if (rflag)
01515       str << setprecision(6) << setw(8) << h << " " << setprecision(nd)
01516           << setw(nd+6) << dv << " " << setw(nd+6)
01517           << v << " " << setw(nd+6) << n1/dvmag << endl;
01518     else
01519       str << setprecision(6) << setw(8) << h << " " << setprecision(nd)
01520           << setw(nd+6) << dv << " " << setw(nd+6)
01521           << v << " " << setw(nd+6) << n1 << endl;
01522       }
01523       str.precision(oldprecision);
01524       return 0;
01525     }
01526     catch (RVLException & e) {
01527       e<<"\ncalled from FunctionalProductDomain::checkPartialHessian\n";
01528       throw e;
01529     }
01530   }
01531 
01532   template<class Scalar>
01533   bool FunctionalProductDomain<Scalar>::checkPartialHessian
01534   (const Vector<Scalar> & y,
01535    const Vector<Scalar> & pi,
01536    int i,
01537    ostream & str,
01538    int n,
01539    Scalar hmin,
01540    Scalar hmax) {
01541     try {
01542       if (i < 1 || i > i > getProductDomain()) {
01543     RVLException e; e<<"Error in FunctionalProductDomain::";
01544     e<<"checkPartialHessian: \n";
01545     e<<"invalid index\n";
01546     throw e;
01547       }
01548       if (!y.inSpace(getDomain())) {
01549     RVLException e; e<<"Error in FunctionalProductDomain::";
01550     e<<"checkPartialHessian: \n";
01551     e<<"base vector is not in Domain\n";
01552     throw e;
01553       }
01554       if (!pi.inSpace(getProductDomain()[i])) {
01555     RVLException e; e<<"Error in FunctionalProductDomain::";
01556     e<<"checkPartialHessian: \n";
01557     e<<"direction vector pi is not in Domain\n";
01558     throw e;
01559       }
01560 
01561       if (hmax <= hmin) {
01562     Scalar temp = hmax;
01563     hmax = hmin;
01564     hmin = temp;
01565       }
01566       if (hmin <= 0.0) {
01567     hmin = 0.1;
01568     hmax = 1.0;
01569       }
01570       if (n <= 0)
01571     n = 10;
01572 
01573       Scalar hlimit;
01574       {
01575     Vector<Scalar> yp(getDomain());
01576     yp.zero();
01577     Components<Scalar> cy(yp);
01578     cy[i].copy(pi);
01579     hlimit = getMaxStep(y,yp);
01580     yp.negate();
01581     hlimit = min(getMaxStep(y,yp),hlimit);
01582       }
01583       if (hlimit <= 0.0) {
01584     RVLException e; e<<"Error in FunctionalProductDomain::";
01585     e<<"checkPartialHessian: direction is not feasible\n";
01586     throw e;
01587       }
01588       if (hmax >= hlimit) {
01589     hmax = 0.99*hlimit;
01590     if (hmin >= hmax)
01591       hmin = hmax/n;
01592       }
01593 
01594       Vector<Scalar> x1(getDomain());
01595       Scalar v0,dv;
01596 
01597       FunctionalEvaluation<Scalar> Fy(*this,y);
01598       Vector<Scalar> pi1(getProductDomain()[i]);
01599       Fy.getPartialHessian(i,i).applyOp(pi,pi1);
01600       dv = pi.inner(pi1);
01601 
01602       int nd;
01603       if (numeric_precision<Scalar>()==1) nd = 8;
01604       if (numeric_precision<Scalar>()==2) nd = 16;
01605       int oldprecision = str.precision(nd);
01606 
01607       Scalar dvmag = abs(dv);
01608       int rflag = 1;
01609       if (dvmag < numeric_limits<Scalar>::epsilon()) {
01610     rflag = 0;
01611     str << "FunctionalProductDomain_d::CheckPartialHessian: norm of "
01612       "second variation is too "
01613         << endl << "small; displaying absolute error" << endl;
01614       }
01615 
01616       if (rflag)
01617     str << setw(5) << "h" << setw(nd+6) << "2nd variation" << setw(nd+6)
01618         << "cent. diff." << setw(nd+4) << "Rel. Err." << endl;
01619       else
01620     str << setw(5) << "h" << setw(nd+6) << "2nd variation" << setw(nd+6)
01621         << "cent. diff." << setw(nd+4) << "Error" << endl;
01622       Scalar hstep = (hmax-hmin)/(n-1);
01623       Scalar val;
01624       Components<Scalar> cx1(x1);
01625       int ii;
01626       for (ii=n-1;ii>=0;ii--) {
01627     Scalar v = -2.0*v0;
01628     Scalar h = hmin+ii*hstep;
01629     x1.copy(y);
01630     cx1[i].linComb(h,pi);
01631     {
01632       FunctionalEvaluation<Scalar> F1(*this,x1);
01633       v += F1.getValue();
01634     }
01635 
01636     x1.copy(y);
01637     cx1[i].linComb(-h,pi);
01638     {
01639       FunctionalEvaluation<Scalar> F1(*this,x1);
01640       v += F1.getValue();
01641     }
01642 
01643     v /= (h*h);
01644     Scalar n1 = abs(v-dv);
01645 
01646     if (rflag)
01647       str << setprecision(6) << setw(8) << h << " " << setprecision(nd)
01648           << setw(nd+6) << dv << " " << setw(nd+6)
01649           << v << " " << setw(nd+6) << n1/dvmag << endl;
01650     else
01651       str << setprecision(6) << setw(8) << h << " " << setprecision(nd)
01652           << setw(nd+6) << dv << " " << setw(nd+6)
01653           << v << " " << setw(nd+6) << n1 << endl;
01654       }
01655       str.precision(oldprecision);
01656       return 0;
01657     }
01658     catch (RVLException & e) {
01659       e<<"\ncalled from FunctionalProductDomain::checkPartialHessian\n";
01660       throw e;
01661     }
01662   }
01663 
01664   */
01665 
01666 
01668   template<class Scalar>
01669   class NullFunctional : public Functional<Scalar> {
01670 
01671   private:    
01672 
01673     Space<Scalar> const & dom; 
01674 
01675     NullFunctional();
01676 
01677   protected:
01679     virtual void apply(const Vector<Scalar> & x, 
01680                Scalar & val) const {
01681       val = 0;
01682     }
01683     
01685     virtual void applyGradient(const Vector<Scalar> & x, 
01686                    Vector<Scalar> & g) const {
01687       g.zero();
01688     }
01689     
01691     virtual void applyHessian(const Vector<Scalar> & x,
01692                   const Vector<Scalar> & dx, 
01693                   Vector<Scalar> & dy) const {
01694       dy.zero();
01695     }
01696 
01697   public:
01698 
01699     NullFunctional(const Space<Scalar> & sp)
01700       : dom(sp) {}
01701 
01702     NullFunctional(const Functional<Scalar> & _f)
01703       : dom(_f.getDomain()) {}
01704 
01705     ~NullFunctional() { }
01706 
01711     virtual Functional<Scalar> * clone() const {
01712       return new NullFunctional<Scalar>(*this);
01713     }
01714 
01715     // access to domain
01716     virtual const Space<Scalar> & getDomain() const {
01717       return dom;
01718     }
01719 
01720     virtual ostream & write(ostream & str) const {
01721       str << "NullFunctional on space\n ";
01722       dom.write(str);
01723       str << " \n";
01724       return str;
01725     }
01726   };
01727 
01742   template<class Scalar>
01743   class FcnlOpComp: public Functional<Scalar> {
01744 
01745   private:
01746 
01747     Functional<Scalar> const & f;
01748     Operator<Scalar> const & op;
01749     mutable FunctionalEvaluation<Scalar> * fneval;
01750     mutable OperatorEvaluation<Scalar> * opeval;
01751 
01752   protected:
01753 
01754     void apply(const Vector<Scalar> & x, 
01755            Scalar & val) const {
01756       try {
01757     if (!opeval) 
01758       opeval = new OperatorEvaluation<Scalar>(op,x);
01759     if (!fneval)
01760       fneval = new FunctionalEvaluation<Scalar>(f,opeval->getValue());
01761     //  cerr<<"FcnlOpComp::apply -> getValue()\n";
01762     val=fneval->getValue();
01763     // delete fneval; fneval=NULL;
01764     // delete opeval; opeval=NULL;
01765       }
01766       catch (RVLException & e) {
01767     e<<"\ncalled from FcnlOpComp::apply\n";
01768     throw e;
01769       }
01770     }
01771 
01773     virtual void applyGradient(const Vector<Scalar> & x, 
01774                    Vector<Scalar> & g) const {
01775       try {
01776     if (!opeval)
01777       opeval = new OperatorEvaluation<Scalar>(op,x);
01778     if (!fneval)
01779       fneval = new FunctionalEvaluation<Scalar>(f,opeval->getValue());
01780     Vector<Scalar> const & gtmp = fneval->getGradient();
01781     opeval->getDeriv().applyAdjOp(gtmp,g);
01782     //  delete fneval; fneval=NULL;
01783     //  delete opeval; opeval=NULL;
01784       }
01785       catch (RVLException & e) {
01786     e<<"\ncalled from FcnlOpComp::applyGradient\n";
01787     throw e;
01788       }
01789     }
01790 
01791     virtual void applyHessian(const Vector<Scalar> & x,
01792                   const Vector<Scalar> & dx, 
01793                   Vector<Scalar> & dy) const {
01794 
01795       try {
01796     if (!opeval) 
01797       opeval = new OperatorEvaluation<Scalar>(op,x);
01798     if (!fneval) 
01799       fneval = new FunctionalEvaluation<Scalar>(f,opeval->getValue());
01800     Vector<Scalar> tmp1(op.getRange());
01801     Vector<Scalar> tmp2(op.getRange());
01802     opeval->getDeriv().applyOp(dx,tmp1);
01803     fneval->getHessian().applyOp(tmp1,tmp2);
01804         opeval->getDeriv().applyAdjOp(tmp2,dy);
01805     //  delete fneval; fneval=NULL;
01806     //  delete opeval; opeval=NULL;
01807       }
01808       catch (RVLException & e) {
01809     e<<"\ncalled from FcnlOpComp::applyHessian\n";
01810     throw e;
01811       }
01812     }
01813 
01819     virtual Functional<Scalar> * clone() const { 
01820       //      cerr<<"FcnlOpComp::clone\n";
01821       return new FcnlOpComp<Scalar>(*this);
01822     }
01823 
01824   public:
01825 
01826     FcnlOpComp(const Functional<Scalar> & fref,
01827            const Operator<Scalar> & opref)
01828       : f(fref), op(opref),
01829     fneval(NULL), opeval(NULL) {}
01830 
01831     FcnlOpComp(const FcnlOpComp<Scalar> & c) 
01832       : f(c.f), op(c.op), fneval(NULL), opeval(NULL) {
01833 #if 0
01834       cerr<<"\n\n***************************\n";
01835       cerr<<"NEW FCNLOPCOMP:\n";
01836       cerr<<"FCNL:\n";
01837       f.write(cerr);
01838       cerr<<"\nOP:\n";
01839       op.write(cerr);
01840       cerr<<"\n***************************\n\n";
01841 #endif
01842     }
01843 
01844     ~FcnlOpComp() {
01845       if (fneval) delete fneval;
01846       if (opeval) delete opeval;
01847     }
01848 
01850     const Space<Scalar> & getDomain() const {
01851       try { 
01852     return op.getDomain(); 
01853       }
01854       catch (RVLException & e) {
01855     e<<"\ncalled from FcnlOpComp::getDomain\n";
01856     throw e;
01857       }
01858     }
01859 
01860     virtual Scalar getMaxStep(const Vector<Scalar> & x,
01861                   const Vector<Scalar> & dx) const {
01862       try {
01863     /* this is a tricky bit - in fact it is not clear
01864        how in general you should interpret this. A natural
01865        method might be the next block of code, i.e. linearize
01866        the correspondence in direction between dom(op) and dom(f).
01867        however it's clearly not right, so for the moment the 
01868        domain of f plays no role in this computation, which is 
01869        not right either.
01870        
01871        Since it's so tricky, we've left it virtual - override 
01872        with anything sensible.
01873     */
01874     /*
01875     Scalar os = op.get().getMaxStep(x,dx);
01876     if (!opapplied) {
01877       op.get().apply(x,opx);
01878       opapplied=true;
01879     }
01880     Vector<Scalar> tmp1(op.get().getRange());
01881     op.get().applyDeriv(x,dx,tmp1);
01882     Scalar fs = f.get().getMaxStep(opx,tmp1);
01883     Scalar st = min(fs,os);
01884     return st;
01885     */
01886     return op.getMaxStep(x,dx);
01887       }
01888       catch (RVLException & e) {
01889     e<<"\ncalled from FcnlOpComp::getMaxStep\n";
01890     throw e;
01891       }
01892     }
01893 
01896     OperatorEvaluation<Scalar> const & getOpEval() const { 
01897       if (opeval) return *opeval;
01898       RVLException e;
01899       e<<"Error: FcnlOpComp::getOpEval\n";
01900       e<<"  apparently not yet evaluated so operator evaluation component\n";
01901       e<<"  not available\n";
01902       throw e;
01903     }
01904 
01907     FunctionalEvaluation<Scalar> const & getFcnlEval() const { 
01908       if (fneval) return *fneval;
01909       RVLException e;
01910       e<<"Error: FcnlOpComp::getFcnlEval\n";
01911       e<<"  apparently not yet evaluated so functional evaluation component\n";
01912       e<<"  not available\n";
01913       throw e;
01914     }
01915 
01916     ostream & write(ostream & str) const {
01917       str<<"FcnlOpComp: Functional-Operator composition\n";
01918       str<<"operator:\n";
01919       op.write(str);
01920       str<<"followed by functional:\n";
01921       f.write(str);
01922       return str;
01923     }
01924     
01925   };
01926 
01928   template<typename Scalar>
01929   class RestrictFcnl: public Functional<Scalar> {
01930 
01931   private: 
01932     
01933     FunctionalProductDomain<Scalar> const & f;
01934     mutable Vector<Scalar> xx;
01935     mutable Components<Scalar> cxx;
01936 
01937   protected:
01938 
01939     void apply(Vector<Scalar> const & x,
01940            Scalar & val) const {
01941       try {
01942     cxx[1].copy(x);
01943     export_apply(f, xx, val);
01944       }
01945       catch (RVLException & e) {
01946     e<<"\ncalled from RestrictFcnl::apply\n";
01947     throw e;
01948       }
01949     }
01950 
01951     // note the apparently unavoidable extra storage and copying - would 
01952     // need to be able to assemble vector in product space from components 
01953     // to avoid some of this.
01954     void applyGradient(Vector<Scalar> const & x,
01955                Vector<Scalar> & g) const {
01956       try {
01957     cxx[1].copy(x);
01958     export_applyPartialGradient(f, 1, xx, g);   
01959       }
01960       catch (RVLException & e) {
01961     e<<"\ncalled from RestrictFcnl::applyGradient\n";
01962     throw e;
01963       }
01964     }
01965 
01966     void applyHessian(Vector<Scalar> const & x,
01967               Vector<Scalar> const & dx,
01968               Vector<Scalar> & dy) const {
01969       try {
01970     cxx[1].copy(x);
01971     export_applyPartialHessian(f, 1, 1, xx, dx, dy);    
01972       }
01973       catch (RVLException & e) {
01974     e<<"\ncalled from RestrictFcnl::applyHessian\n";
01975     throw e;
01976       }
01977     }
01978 
01979     Functional<Scalar> * clone() const { 
01980       return new RestrictFcnl(*this);
01981     }
01982     
01983   public:
01984     
01985     RestrictFcnl(FunctionalProductDomain<Scalar> const & _f,
01986          Vector<Scalar> const & x0) 
01987       : f(_f), xx(_f.getDomain()), cxx(xx) {
01988       try {
01989     int ncomp = f.getProductDomain().getSize();
01990     if (ncomp != 2) {
01991       RVLException e; 
01992       e<<"ERROR: RestrictFcnl constructor\n";
01993       e<<"  input FcnlProdDom has domain with "<<ncomp<<" components\n";
01994       e<<"  current implementation implementation allows only 2, with";
01995       e<<"  first restricted\n";
01996       e<<"  FcnlProdDom:\n";
01997       f.write(e);
01998       throw e;
01999     }
02000     cxx[1].copy(x0);
02001       }
02002       catch (RVLException & e) {
02003     e<<"\ncalled from RestrictFcnl constructor\n";
02004     throw e;
02005       }
02006     }
02007 
02008     RestrictFcnl(RestrictFcnl<Scalar> const & g): f(g.f), xx(g.xx) {}
02009 
02010     ~RestrictFcnl() {}
02011 
02012     Space<Scalar> const & getDomain() { return f.getDomain(); }
02013 
02014     Scalar getMaxStep(const Vector<Scalar> & x,
02015               const Vector<Scalar> & dx) const {
02016       try {
02017     // as usual this doesn't really make sense
02018     cxx[1].copy(x);
02019     Vector<Scalar> dxx(f.getDomain(),true);
02020     Components<Scalar> cdxx(dxx);
02021     dxx[1].copy(dx);
02022     return f.getMaxStep(xx,dxx);
02023       }
02024       catch (RVLException & e) {
02025     e<<"\ncalled from RestrictFcnl::getMaxStep\n";
02026     throw e;
02027       }
02028     }
02029 
02030     ostream & write(ostream & str) const {
02031       str<<"RestrictFcnl with components\n";
02032       str<<"  Vector:\n";
02033       xx.write(str);
02034       str<<"  FcnlProdDom:\n";
02035       f.write(str);
02036       return str;
02037     }
02038   };
02039   
02040 }
02041 
02042 #endif
02043 
02044 
02045 
02046 
02047 

Generated on 5 Jan 2017 for RVL by  doxygen 1.4.7