cgnealg.hh

Go to the documentation of this file.
00001 // cgnealg.H
00002 // created by ADP 1/8/04
00003 // last modified 06/16/04
00004 
00005 // Much code is shamelessly stolen from the umin cgne.H
00006 // originally written by WWS, with his permission
00007 
00008 /*************************************************************************
00009 
00010 Copyright Rice University, 2004.
00011 All rights reserved.
00012 
00013 Permission is hereby granted, free of charge, to any person obtaining a
00014 copy of this software and associated documentation files (the "Software"),
00015 to deal in the Software without restriction, including without limitation
00016 the rights to use, copy, modify, merge, publish, distribute, and/or sell
00017 copies of the Software, and to permit persons to whom the Software is
00018 furnished to do so, provided that the above copyright notice(s) and this
00019 permission notice appear in all copies of the Software and that both the
00020 above copyright notice(s) and this permission notice appear in supporting
00021 documentation.
00022 
00023 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00024 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00025 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
00026 RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
00027 NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
00028 DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00029 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00030 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
00031 THIS SOFTWARE.
00032 
00033 Except as contained in this notice, the name of a copyright holder shall
00034 not be used in advertising or otherwise to promote the sale, use or other
00035 dealings in this Software without prior written authorization of the
00036 copyright holder.
00037 
00038 **************************************************************************/
00039 
00040 
00041 #ifndef __RVLALG_UMIN_CGNE_H
00042 #define __RVLALG_UMIN_CGNE_H
00043 
00044 #include "alg.hh"
00045 #include "terminator.hh"
00046 #include "linop.hh"
00047 #include "table.hh"
00048 
00049 using namespace RVLAlg;
00050 
00051 namespace RVLUmin {
00052 
00053   using namespace RVL;
00054   using namespace RVLAlg;    
00055 
00056   // forward declaration
00057   template<typename Scalar>
00058   class CGNEAlg;
00059 
00083   template<typename Scalar>
00084   class CGNEStep : public Algorithm {
00085 
00086     friend class CGNEAlg<Scalar>;
00087 
00088     typedef typename ScalarFieldTraits<Scalar>::AbsType atype;
00089 
00090   public:
00091 
00092     CGNEStep(LinearOp<Scalar> const & _A,
00093          Vector<Scalar> & _x,
00094          Vector<Scalar> const & _b,
00095          atype & _rnorm, 
00096          atype & _nrnorm)
00097       : A(_A), x(_x), b(_b), rnorm(_rnorm), nrnorm(_nrnorm), r(A.getRange()), g(A.getDomain()),
00098     q(A.getRange()), p(A.getDomain()) { 
00099       // NOTE: initial x assumed to be zero vector
00100       //      cerr<<"cg initialize\n";
00101       r.copy(b);
00102       rnorm=r.norm();
00103       A.applyAdjOp(r,g);
00104       p.copy(g);
00105       nrnorm=g.norm();
00106       gamma = nrnorm*nrnorm;
00107     }
00108       
00112     void run() {
00113       try {
00114     //          cerr<<"CGSTEP::run 0\n";
00115     A.applyOp(p,q);
00116     //  cerr<<"CGSTEP::run 1\n";
00117     atype qtq = q.normsq();
00118     atype absalpha;
00119     if (ProtectedDivision<atype>(gamma,qtq,absalpha)) {
00120       RVLException e;
00121       e<<"Error: CGNEStep::run() from ProtectedDivision: alpha\n";
00122       throw e;
00123     }
00124     // can use q for workspace since it is not needed again until
00125     // reinitialized
00126     //  cerr<<"CGSTEP::update x\n";
00127 
00128     Scalar alpha=absalpha;
00129     x.linComb(alpha,p);
00130     r.linComb(-alpha,q);
00131     //  cerr<<"CGSTEP::run 3\n";
00132 
00133     A.applyAdjOp(r,g);
00134     //  cerr<<"CGSTEP::run 4\n";
00135 
00136     atype newgamma = g.normsq();
00137     atype absbeta;
00138     if (ProtectedDivision<atype>(newgamma,gamma,absbeta)) {
00139       RVLException e;
00140       e<<"Error: CGNEStep::run() from ProtectedDivision: beta\n";
00141       throw e;
00142     }
00143     //  cerr<<"CGSTEP::run 5\n";
00144 
00145     Scalar beta = absbeta;
00146     p.linComb(ScalarFieldTraits<Scalar>::One(),g,beta);
00147     gamma=newgamma;
00148     rnorm=r.norm();
00149     nrnorm=sqrt(gamma);
00150     //  cerr<<"CGSTEP::run 6\n";
00151 
00152       }
00153       catch (RVLException & e) {
00154     e<<"\ncalled from CGNEStep::run()\n";
00155     throw e;
00156       }
00157      
00158     }
00159 
00160     ~CGNEStep() {}
00161 
00162   protected:
00163 
00164     // references to external objects
00165     LinearOp<Scalar> const & A;
00166     Vector<Scalar> & x;
00167     Vector<Scalar> const & b;
00168     atype & rnorm;
00169     atype & nrnorm;
00170 
00171   private:
00172 
00173     // need four work vectors and one scalar as persistent object data
00174     Vector<Scalar> r;    // residual
00175     Vector<Scalar> g;    // gradient
00176     Vector<Scalar> q;    // image of search direction
00177     Vector<Scalar> p;    // search direction
00178     atype gamma;         // ||g||^2
00179   };
00180   
00204   template<typename Scalar>
00205   class PCGNEStep : public Algorithm {
00206 
00207     friend class CGNEAlg<Scalar>;
00208 
00209     typedef typename ScalarFieldTraits<Scalar>::AbsType atype;
00210 
00211   public:
00212 
00213     PCGNEStep(LinearOp<Scalar> const & _A,
00214           LinearOp<Scalar> const & _M,
00215           Vector<Scalar> & _x,
00216           Vector<Scalar> const & _b,
00217           atype & _rnorm, 
00218           atype & _nrnorm)
00219       : A(_A), M(_M), x(_x), b(_b), rnorm(_rnorm), nrnorm(_nrnorm), 
00220     r(A.getRange()), ng(A.getDomain()), g(A.getDomain()),
00221     q(A.getRange()), p(A.getDomain()) { 
00222       // sanity tests - cannot sensibly test M for SPD, but 
00223       // at least get domain right
00224       if ((M.getDomain() != A.getDomain()) ||
00225       (M.getRange()  != A.getDomain())) {
00226     RVLException e;
00227     e<<"Error PCGNEStep constructor\n";
00228     e<<"  preconditioning operator does not have domain, range\n";
00229     e<<"  same as domain of system operator\n";
00230     e<<"  preconditioning operator:\n";
00231     M.write(e);
00232     e<<"  system operator:\n";
00233     A.write(e);
00234     throw e;
00235       }
00236       // NOTE: initial x assumed to be zero vector
00237       r.copy(b);
00238       rnorm=r.norm();
00239       A.applyAdjOp(r,ng);
00240       M.applyOp(ng,g);
00241       p.copy(g);
00242       gamma = abs(g.inner(ng));
00243       nrnorm=sqrt(gamma);
00244     }
00245       
00249     void run() {
00250       try {
00251     A.applyOp(p,q);
00252     atype qtq = q.normsq();
00253     atype absalpha;
00254     if (ProtectedDivision<atype>(gamma,qtq,absalpha)) {
00255       RVLException e;
00256       e<<"Error: PCGNEStep::run() from ProtectedDivision: alpha\n";
00257       throw e;
00258     }
00259     // can use q for workspace since it is not needed again until
00260     // reinitialized
00261 
00262     Scalar alpha=absalpha;
00263     x.linComb(alpha,p);
00264     r.linComb(-alpha,q);
00265 
00266     A.applyAdjOp(r,ng);
00267     M.applyOp(ng,g);
00268 
00269     atype newgamma = abs(g.inner(ng));
00270     atype absbeta;
00271     if (ProtectedDivision<atype>(newgamma,gamma,absbeta)) {
00272       RVLException e;
00273       e<<"Error: PCGNEStep::run() from ProtectedDivision: beta\n";
00274       throw e;
00275     }
00276 
00277     Scalar beta = absbeta;
00278     p.linComb(ScalarFieldTraits<Scalar>::One(),g,beta);
00279     gamma=newgamma;
00280     rnorm=r.norm();
00281     nrnorm=sqrt(gamma);
00282       }
00283       catch (RVLException & e) {
00284     e<<"\ncalled from PCGNEStep::run()\n";
00285     throw e;
00286       }
00287      
00288     }
00289 
00290     ~PCGNEStep() {}
00291 
00292   protected:
00293 
00294     // references to external objects
00295     LinearOp<Scalar> const & A;
00296     LinearOp<Scalar> const & M;
00297     Vector<Scalar> & x;
00298     Vector<Scalar> const & b;
00299     atype & rnorm;
00300     atype & nrnorm;
00301 
00302   private:
00303 
00304     // need four work vectors and one scalar as persistent object data
00305     Vector<Scalar> r;    // residual
00306     Vector<Scalar> ng;   // normal residual
00307     Vector<Scalar> g;    // gradient = preconditioned normal residual
00308     Vector<Scalar> q;    // image of search direction
00309     Vector<Scalar> p;    // search direction
00310     atype gamma;         // gradient norm, inner product defined by inverse of M
00311   };
00312   
00377   template<typename Scalar>
00378   class CGNEAlg: public Algorithm, public Terminator {
00379 
00380     typedef typename ScalarFieldTraits<Scalar>::AbsType atype;
00381 
00382   public:
00383 
00423     CGNEAlg(RVL::Vector<Scalar> & x, 
00424         RVL::LinearOp<Scalar> const & A, 
00425         RVL::Vector<Scalar> const & rhs, 
00426         atype & _rnorm,
00427         atype & _nrnorm,
00428         atype _rtol = 100.0*numeric_limits<atype>::epsilon(),
00429         atype _nrtol = 100.0*numeric_limits<atype>::epsilon(),
00430         int _maxcount = 10,
00431         atype _maxstep = numeric_limits<atype>::max(),
00432         ostream & _str = cout)
00433     : rnorm(_rnorm), 
00434       nrnorm(_nrnorm), 
00435       rtol(_rtol), 
00436       nrtol(_nrtol), 
00437       maxstep(_maxstep), 
00438       maxcount(_maxcount), 
00439       count(0), 
00440       proj(false), 
00441       str(_str)
00442     {
00443       try {
00444     x.zero(); 
00445     step = new CGNEStep<Scalar>(A,x,rhs,rnorm,nrnorm);
00446       }
00447       catch (RVLException & e) {
00448     e<<"\ncalled from CGNEAlg constructor (not preconditioned)\n";
00449     throw e;
00450       }
00451     }
00452 
00497     CGNEAlg(RVL::Vector<Scalar> & x, 
00498         LinearOp<Scalar> const & A, 
00499         LinearOp<Scalar> const & M, 
00500         Vector<Scalar> const & rhs, 
00501         atype & _rnorm,
00502         atype & _nrnorm,
00503         atype _rtol = 100.0*numeric_limits<atype>::epsilon(),
00504         atype _nrtol = 100.0*numeric_limits<atype>::epsilon(),
00505         int _maxcount = 10,
00506         atype _maxstep = numeric_limits<atype>::max(),
00507         ostream & _str = cout)
00508     : rnorm(_rnorm), 
00509       nrnorm(_nrnorm), 
00510       rtol(_rtol), 
00511       nrtol(_nrtol), 
00512       maxstep(_maxstep), 
00513       maxcount(_maxcount), 
00514       count(0), 
00515       proj(false), 
00516       str(_str)
00517     { 
00518       try {
00519     x.zero(); 
00520     step = new PCGNEStep<Scalar>(A,M,x,rhs,rnorm,nrnorm);
00521       }
00522       catch (RVLException & e) {
00523     e<<"\ncalled from CGNEAlg constructor (preconditioned)\n";
00524     throw e;
00525       }
00526     }
00527 
00528     ~CGNEAlg() {
00529       delete step;
00530     }
00531 
00532     bool query() { return proj; }
00533 
00534     void run() { 
00535       try {
00536     //  cerr<<"cg::run\n";
00537     // access to internals
00538     CGNEStep<Scalar>  * cg  = dynamic_cast<CGNEStep<Scalar> *>(step);
00539     PCGNEStep<Scalar> * pcg = dynamic_cast<PCGNEStep<Scalar> *>(step);
00540     if ((!cg && !pcg) || (cg && pcg)) {
00541       RVLException e;
00542       e<<"Error: CGNEAlg::run\n";
00543       e<<"  unable to determine whether step data member\n";
00544       e<<"  is preconditioned or not. PANIC!\n";
00545       throw e;
00546     }
00547     
00548     // terminator for CGNE iteration
00549     vector<string> names(2);
00550     vector<atype *> nums(2);
00551     vector<atype> tols(2);
00552     atype rnorm0=rnorm;
00553     atype nrnorm0=nrnorm;
00554           
00555     names[0]="Residual Norm"; nums[0]=&rnorm; tols[0]=rtol*rnorm0;
00556     names[1]="Gradient Norm"; nums[1]=&nrnorm; tols[1]=nrtol*nrnorm0;
00557     if (pcg) str<<"========================== BEGIN PCGNE =========================\n";
00558     else    str<<"========================== BEGIN CGNE =========================\n";
00559     VectorCountingThresholdIterationTable<atype> stop1(maxcount,names,nums,tols,str);
00560     stop1.init();
00561     // terminator for Trust Region test and projection
00562     //      BallProjTerminator<Scalar> stop2(x,maxstep,str);
00563 
00564     Terminator * stop2 = NULL;
00565     if (cg)  stop2 = new BallProjTerminator<Scalar>( cg->x,maxstep,str);  
00566     if (pcg) stop2 = new BallProjTerminator<Scalar>(pcg->x,maxstep,str); 
00567     // terminate if either
00568     OrTerminator stop(stop1,*stop2);
00569     // loop
00570     LoopAlg doit(*step,stop);
00571     //  cerr<<"stop1="<<stop1.query()<<" stop2="<<stop2->query()<<endl;
00572     //  cerr<<"rtol="<<rtol<<" nrtol="<<nrtol<<" maxcount="<<maxcount<<endl;
00573     doit.run();
00574     // must recompute residual if scaling occured 
00575     //  cerr<<"stop1="<<stop1.query()<<" stop2="<<stop2->query()<<" xnorm="<<cg->x.norm()<<" maxstep="<<maxstep<<"\n";
00576     proj = stop2->query();
00577     if (proj) {
00578       if (cg) {
00579         //      cerr<<"adjust\n";
00580         Vector<Scalar> temp((cg->A).getRange());
00581         (cg->A).applyOp((cg->x),temp);
00582         temp.linComb(-1.0,(cg->b));
00583         rnorm=temp.norm();
00584         Vector<Scalar> temp1((cg->A).getDomain());
00585         (cg->A).applyAdjOp(temp,temp1);
00586         nrnorm=temp1.norm();
00587       }
00588       if (pcg) {
00589         Vector<Scalar> temp((pcg->A).getRange());
00590         (pcg->A).applyOp((pcg->x),temp);
00591         temp.linComb(-1.0,(pcg->b));
00592         rnorm=temp.norm();
00593         Vector<Scalar> temp1((pcg->A).getDomain());
00594         Vector<Scalar> temp2((pcg->A).getDomain());
00595         (pcg->A).applyAdjOp(temp,temp1);
00596         (pcg->M).applyOp(temp1,temp2);
00597         atype tmpgamma = abs(temp1.inner(temp2));
00598         nrnorm=sqrt(tmpgamma);
00599       }
00600     }
00601 
00602     count = stop1.getCount();
00603     if (pcg) str<<"=========================== END PCGNE ==========================\n";
00604     else str<<"=========================== END CGNE ==========================\n";
00605           // display results
00606           str<<"\n ****************** CGNE summary *****************  "<<endl;
00607           str<<"initial residual norm      = "<<rnorm0<<endl;
00608           str<<"residual norm              = "<<rnorm<<endl;
00609           str<<"residual redn              = "<<rnorm/rnorm0<<endl;
00610           str<<"initial gradient norm      = "<<nrnorm0<<endl;
00611           str<<"gradient norm              = "<<nrnorm<<endl;
00612           str<<"gradient redn              = "<<nrnorm/nrnorm0<<endl;
00613       }
00614       catch (RVLException & e) {
00615     e<<"\ncalled from CGNEAlg::run\n";
00616     throw e;
00617       }
00618     }
00619 
00620     int getCount() const { return count; }
00621 
00622   private:
00623 
00624     atype & rnorm;                 // residual norm
00625     atype & nrnorm;                // gradient norm
00626     atype rtol;                    // tolerance residual norm
00627     atype nrtol;                   // tolerance gradient norm 
00628     atype maxstep;                 // upper bound for net step x-x0
00629     int maxcount;                  // upper bound for iteration count
00630     int count;                     // actual iteration count
00631     mutable bool proj;             // whether step is projected onto TR boundary
00632     ostream & str;                 // stream for report output
00633     Algorithm * step;              // CGNE or PCGNE step
00634 
00635     // disable default, copy constructors
00636     CGNEAlg();
00637     CGNEAlg(CGNEAlg<Scalar> const &);
00638 
00639   };
00640 
00643   template<typename Scalar>
00644   class CGNEPolicyData {
00645 
00646     typedef typename ScalarFieldTraits<Scalar>::AbsType atype;
00647   
00648   public:
00649 
00650     atype rtol;
00651     atype nrtol;
00652     atype Delta;
00653     int maxcount;
00654     bool verbose;
00655 
00656     CGNEPolicyData(atype _rtol = numeric_limits<atype>::max(),
00657            atype _nrtol = numeric_limits<atype>::max(),
00658            atype _Delta = numeric_limits<atype>::max(),
00659            int _maxcount = 0,
00660            bool _verbose = false)
00661       : rtol(_rtol), nrtol(_nrtol), Delta(_Delta), maxcount(_maxcount), verbose(_verbose) {}
00662       
00663     CGNEPolicyData(CGNEPolicyData<Scalar> const & a) 
00664       : rtol(a.rtol), nrtol(a.nrtol), Delta(a.Delta), maxcount(a.maxcount), verbose(a.verbose) {}
00665 
00666     ostream & write(ostream & str) const {
00667       str<<"\n";
00668       str<<"==============================================\n";
00669       str<<"CGNEPolicyData: \n";
00670       str<<"rtol      = "<<rtol<<"\n";
00671       str<<"nrtol     = "<<nrtol<<"\n";
00672       str<<"Delta     = "<<Delta<<"\n";
00673       str<<"maxcount  = "<<maxcount<<"\n";
00674       str<<"verbose   = "<<verbose<<"\n";
00675       str<<"==============================================\n";
00676       return str;
00677     }
00678   };
00679 
00702   template<typename Scalar> 
00703   class CGNEPolicy {
00704 
00705     typedef typename ScalarFieldTraits<Scalar>::AbsType atype;
00706 
00707   public:
00727     CGNEAlg<Scalar> * build(Vector<Scalar> & x, 
00728                 LinearOp<Scalar> const & A,
00729                 Vector<Scalar> const & d,
00730                 atype & rnorm,
00731                 atype & nrnorm,
00732                 ostream & str) const {
00733       try {
00734     if (verbose) 
00735       return new CGNEAlg<Scalar>(x,A,d,rnorm,nrnorm,rtol,nrtol,maxcount,Delta,str);
00736     else
00737       return new CGNEAlg<Scalar>(x,A,d,rnorm,nrnorm,rtol,nrtol,maxcount,Delta,nullstr);
00738       }
00739       catch (RVLException & e) {
00740     e<<"\ncalled from CGNEPolicy::build\n";
00741     e<<"inputs: \n";
00742     e<<"**** x:\n";
00743     x.write(e);
00744     e<<"**** A:\n";
00745     A.write(e);
00746     e<<"**** d:\n";
00747     d.write(e);
00748     throw e;
00749       }
00750     }
00751 
00752       
00753     CGNEAlg<Scalar> * build(Vector<Scalar> & x,
00754                             LinearOp<Scalar> const & A,
00755                             LinearOp<Scalar> const & M,
00756                             Vector<Scalar> const & d,
00757                             atype & rnorm,
00758                             atype & nrnorm,
00759                             ostream & str) const {
00760     try {
00761         if (verbose)
00762             return new CGNEAlg<Scalar>(x,A,M,d,rnorm,nrnorm,rtol,nrtol,maxcount,Delta,str);
00763         else
00764             return new CGNEAlg<Scalar>(x,A,M,d,rnorm,nrnorm,rtol,nrtol,maxcount,Delta,nullstr);
00765         }
00766         catch (RVLException & e) {
00767             e<<"\ncalled from CGNEPolicy::build\n";
00768             e<<"inputs: \n";
00769             e<<"**** x:\n";
00770             x.write(e);
00771             e<<"**** A:\n";
00772             A.write(e);
00773             e<<"**** d:\n";
00774             d.write(e);
00775             throw e;
00776         }
00777     }
00778       
00784     void assign(atype _rtol, atype _nrtol, atype _Delta, int _maxcount, bool _verbose) {
00785       rtol=_rtol; nrtol=_nrtol; Delta=_Delta; maxcount=_maxcount; verbose=_verbose;
00786     }
00787 
00789     void assign(Table const & t) {
00790       rtol=getValueFromTable<atype>(t,"CGNE_ResTol");
00791       nrtol=getValueFromTable<atype>(t,"CGNE_GradTol"); 
00792       Delta=getValueFromTable<atype>(t,"TR_Delta");
00793       maxcount=getValueFromTable<int>(t,"CGNE_MaxItn"); 
00794       verbose=getValueFromTable<bool>(t,"CGNE_Verbose");
00795     }
00796 
00798     void assign(CGNEPolicyData<Scalar> const & s) {
00799       rtol=s.rtol;
00800       nrtol=s.nrtol;
00801       Delta=s.Delta;
00802       maxcount=s.maxcount;
00803       verbose=s.verbose;
00804     }
00805 
00810     mutable atype Delta;
00811 
00820     CGNEPolicy(atype _rtol = numeric_limits<atype>::max(),
00821            atype _nrtol = numeric_limits<atype>::max(),
00822            atype _Delta = numeric_limits<atype>::max(),
00823            int _maxcount = 0,
00824            bool _verbose = true)
00825       : Delta(_Delta), rtol(_rtol), nrtol(_nrtol), maxcount(_maxcount), verbose(_verbose), nullstr(0) {}
00826 
00827     CGNEPolicy(CGNEPolicy<Scalar> const & p)
00828       :     Delta(p.Delta), 
00829         rtol(p.rtol), 
00830         nrtol(p.nrtol), 
00831         maxcount(p.maxcount), 
00832         verbose(p.verbose), 
00833         nullstr(0) {}
00834       
00835   private:
00836     mutable atype rtol;
00837     mutable atype nrtol;
00838     mutable int maxcount;
00839     mutable bool verbose;
00840     mutable std::ostream nullstr;
00841   };
00842 }
00843 
00844 #endif
00845 
00846 
00847 
00848 
00849 
00850 
00851 
00852 
00853 

Generated on 5 Jan 2017 for RvlUmin by  doxygen 1.4.7