// lnsrchDS.H // created by ADP and WWS // last modified 08.12.04 /************************************************************************* Copyright Rice University, 2004. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s) and this permission notice appear in all copies of the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. **************************************************************************/ #ifndef __RVL_ALG_LINE_SEARCH_DS #define __RVL_ALG_LINE_SEARCH_DS #include "umintable.hh" #include "lnsrch.hh" namespace RVLUmin { using namespace RVLAlg; using namespace RVL; /** An implementation of a backtracking line search algorithm using cubic interpolation (See Dennis and Schnabel, "Numerical Methods for Unconstrained Optimization and Nonlinear Equations", Prentice-Hall (1983)). The description of this class differs from the description of the base class LineSearch in only one regard: the second criteria for defining an acceptable step is \f$ \phi'(a) \ge tol \phi'(0). \f$ This prevents short steps by requiring that the slope be increased from its initial (negative) value, although it does not require that the step reach an approximate minimizer. This criterion is sufficient to allow a positive definite update in a BFGS algorithm. Adapted from Dennis-Schnabel line search implementation in HCL1.0, authored by Mark Gockenbach. ADP and WWS, Spring 04. */ template class LineSearchDS: public LineSearchAlg { private: /**@name Term codes */ //@{ enum { NoErr = 0, Succeed = 0, NoReduction = -2, InitialSlopePositive = -1, TooManyFunctionEvals = 2, Fail = 3 } ErrorCodes; //@} // parameters found in UMinTable - see docs on that class for // meaning and defaults Scalar FcnDecreaseTol; Scalar SlopeDecreaseTol; int MaxSample; Scalar MinStep; Scalar MaxStep; Scalar ZeroDivideTol; int DispFlag; int DispPrecision; Scalar BracketIncrease; /**@name Output parameters */ //@{ ///exit status (<0 = no reduction, 0 = success, >0 = reduction, but failed) mutable int TermCode; ///maximum step size taken? (1 = taken, 0 = not taken) mutable int MaxTkn; //@} /// Read parameters from parameter table void initialize(UMinTable & holder) { if (holder.getValue("MinStep",MinStep) || holder.getValue("MaxStep",MaxStep) || holder.getValue("MaxSample",MaxSample) || holder.getValue("FcnDecreaseTol",FcnDecreaseTol) || holder.getValue("SlopeDecreaseTol",SlopeDecreaseTol) || holder.getValue("BracketIncrease",BracketIncrease) || holder.getValue("ZeroDivideTol",ZeroDivideTol) || holder.getValue("DispFlag",DispFlag) || holder.getValue("DispPrecision",DispPrecision)) { RVLException e; e<<"Error: LineSearchDS::initialize\n"; e<<"UMinTable object corrupted\n"; holder.write(cerr); throw e; } } ostream & str; LineSearchDS(); public: /** Initialize internal data from a table loaded from a file. */ LineSearchDS(const Space & sp, UMinTable & holder, ostream & _str = cout) : LineSearchAlg(sp), str(_str) { try { initialize(holder); } catch (RVLException & e) { e<<"\ncalled from LineSearchDS constructor\n"; throw e; } } /** copy constructor */ LineSearchDS(const LineSearchDS & a) : LineSearchAlg(a), DispFlag(a.DispFlag), MaxSample(a.MaxSample), FcnDecreaseTol(a.FcnDecreaseTol), SlopeDecreaseTol(a.SlopeDecreaseTol), BracketIncrease(a.BracketIncrease), MinStep(a.MinStep), MaxStep(a.MaxStep), ZeroDivideTol(a.ZeroDivideTol), DispPrecision(a.DispPrecision), str(a.str) {} // Destructor virtual ~LineSearchDS() {} bool query() {if (TermCode) return false; return true; } void run() { try { int NumFcnSampled = 0; TermCode = NoErr; MaxTkn = 0; if (DispFlag) str<<"===============LineSearchDS==============="< & x0 = this->getBasePoint(); Vector & x = this->getTrialPoint(); Vector & dx = this->getSearchDirection(); FunctionalEvaluation & fx = LineSearchAlg::getFunctionalEvaluation(); // no need to copy!!!! // x.copy(x0); Scalar newtlen=dx.norm(); Scalar t = fx.getMaxStep(dx); if (t<=0.0) { RVLException e; e<<"Error: LineSearchDS::run\n"; e<<"any positive step in direction indicated is infeasible\n"; if (DispFlag) e.write(str); throw e; } Scalar fmaxs; if (t == numeric_limits::max()) fmaxs = t; else fmaxs = 0.99*newtlen*t; Scalar fcnmaxstep = min(fmaxs,MaxStep); if (newtlen>fcnmaxstep) { // ||dir|| > MaxStep Scalar scale; if (ProtectedDivision(fcnmaxstep, newtlen, scale, ZeroDivideTol)) { RVLException e; e<<"Error: LineSearchDS::run\n"; e<<"ProtectedDivision error: newtlen too small"; <<" "< 1) str<<"Vector dir is too long; multiply by " <=0.0) { if (DispFlag) { str<<"Initial slope nonnegative in line search"<(MinStep, newtlen, minmu, ZeroDivideTol)) minmu=numeric_limits::min(); if (ProtectedDivision(fcnmaxstep, newtlen, maxmu, ZeroDivideTol)) maxmu=numeric_limits::max(); if (DispFlag > 1) { Scalar xnorm=x.norm(); str<<"f(x) = "< 1) str<<"mu = "< 1) str< 1) str<<"Insufficient decrease in slope; new slope = " <= maxmu) mu=0.99*maxmu; else mu *= BracketIncrease; // cerr<<"update x"< 1) str< 1) str<<"Sufficient decrease in function value; " "new slope = "<mu0 && fnext>fcur+FcnDecreaseTol*mu*initslope)) { // There is an acceptable step length between mulo and the // muhi; find it by using successive quadratic interpolation. mulo = min(mu,muprev); mudiff = abs(mu-muprev); if (mu 1) str<<"An acceptable step length has been bracketed: [" <(-newslope*mudiff*mudiff, 2.0*(fhi-(flo+newslope*mudiff)), muincr, ZeroDivideTol)) { if (DispFlag > 1) str<<"Protected division failed: searching " <<"within bracket"< 1) str< 1) str<<"Sufficient decrease in function value " < 1) str<<"new slope = "< 1) str<<"Insufficient decrease in slope; " "mudiff = "<=minmu && NumFcnSampled 0.99*MaxStep) MaxTkn = 1; this->step = mulo; return; } else { if (DispFlag > 1) str<<"Sufficient decrease in gradient; newslope = " < 1) str<<"Sufficient decrease in gradient; newslope = " < 0.99*MaxStep) MaxTkn = 1; // The line search was successful, so return xnext if (DispFlag) str<<"Number of fcn evals = "<(-initslope, 2.0*(fnext-fcur-mu*initslope), mutemp, ZeroDivideTol)) { if (DispFlag > 1) str<<"Protected division failed: quadratic " <<"interpolation"< 1) str<<"Quadratic backtrack: mutemp = "<(1.0, mu-muprev, t3, ZeroDivideTol)) { if (DispFlag > 1) str<<"Protected division failed: cubic " "interpolation (t3)"<(t1, mu*mu, v1, ZeroDivideTol)) { if (DispFlag > 1) str<<"Protected division failed: cubic " "interpolation (v1)"<(t2, muprev*muprev, v2, ZeroDivideTol)) { if (DispFlag > 1) str<<"Protected division failed: cubic " "interpolation (v2)"<(-initslope, 2.0*b, w1, ZeroDivideTol)) { if (DispFlag > 1) str<<"Protected division failed: cubic " "interpolation (w1)"<(sqrt(disc)-b, 3.0*a, w2, ZeroDivideTol)) { if (DispFlag > 1) str<<"Protected division failed: cubic " "interpolation (w2)"< 1) str<<"Cubic backtrack: mutemp = "<