bpp-core  2.1.0
BrentOneDimension.cpp
Go to the documentation of this file.
00001 //
00002 // File: BrentOneDimension.cpp
00003 // Created by: Julien Dutheil
00004 // Created on: Mon Nov 17 11:45:58 2003
00005 //
00006 
00007 /*
00008 Copyright or © or Copr. CNRS, (November 17, 2004)
00009 
00010 This software is a computer program whose purpose is to provide classes
00011 for numerical calculus.
00012 
00013 This software is governed by the CeCILL  license under French law and
00014 abiding by the rules of distribution of free software.  You can  use, 
00015 modify and/ or redistribute the software under the terms of the CeCILL
00016 license as circulated by CEA, CNRS and INRIA at the following URL
00017 "http://www.cecill.info". 
00018 
00019 As a counterpart to the access to the source code and  rights to copy,
00020 modify and redistribute granted by the license, users are provided only
00021 with a limited warranty  and the software's author,  the holder of the
00022 economic rights,  and the successive licensors  have only  limited
00023 liability. 
00024 
00025 In this respect, the user's attention is drawn to the risks associated
00026 with loading,  using,  modifying and/or developing or reproducing the
00027 software by the user in light of its specific status of free software,
00028 that may mean  that it is complicated to manipulate,  and  that  also
00029 therefore means  that it is reserved for developers  and  experienced
00030 professionals having in-depth computer knowledge. Users are therefore
00031 encouraged to load and test the software's suitability as regards their
00032 requirements in conditions enabling the security of their systems and/or 
00033 data to be ensured and,  more generally, to use and operate it in the 
00034 same conditions as regards security. 
00035 
00036 The fact that you are presently reading this means that you have had
00037 knowledge of the CeCILL license and that you accept its terms.
00038 */
00039 
00040 #include "BrentOneDimension.h"
00041 #include "OneDimensionOptimizationTools.h"
00042 #include "../NumTools.h"
00043 #include "../NumConstants.h"
00044 #include "../../Text/TextTools.h"
00045 
00046 using namespace bpp;
00047 
00048 /******************************************************************************/
00049 
00050 bool BrentOneDimension::BODStopCondition::isToleranceReached() const
00051 {
00052   callCount_++;
00053   if (callCount_ <= burnin_) return false;
00054   const BrentOneDimension* bod = dynamic_cast<const BrentOneDimension *>(optimizer_);
00055   return getCurrentTolerance() <= (bod->tol2 - 0.5 * (bod->b - bod->a));
00056 }
00057     
00058 /******************************************************************************/
00059 
00060 double BrentOneDimension::BODStopCondition::getCurrentTolerance() const
00061 {
00062   // NRC Test for done:
00063   const BrentOneDimension* bod = dynamic_cast<const BrentOneDimension *>(optimizer_);
00064   return NumTools::abs(bod->x - bod->xm);
00065 }
00066  
00067 /******************************************************************************/
00068 
00069 BrentOneDimension::BrentOneDimension(Function* function) :
00070   AbstractOptimizer(function),
00071   a(0), b(0), d(0), e(0), etemp(0), fu(0), fv(0), fw(0), fx(0), p(0), q(0), r(0), tol1(0), tol2(0),
00072   u(0), v(0), w(0), x(0), xm(0), _xinf(0), _xsup(0), isInitialIntervalSet_(false)
00073 {
00074   setDefaultStopCondition_(new BODStopCondition(this));
00075   setStopCondition(*getDefaultStopCondition());
00076   setMaximumNumberOfEvaluations(10000);
00077 }
00078 
00079 /******************************************************************************/
00080   
00081 double BrentOneDimension::ZEPS  = 1.0e-10;
00082   
00083 /******************************************************************************/
00084   
00085 void BrentOneDimension::doInit(const ParameterList& params) throw (Exception)
00086 {
00087   if (params.size() != 1)
00088     throw Exception("BrentOneDimension::init(). This optimizer only deals with one parameter.");
00089 
00090   // Bracket the minimum.
00091   Bracket bracket = OneDimensionOptimizationTools::bracketMinimum(_xinf, _xsup, getFunction(), getParameters());
00092   if (getVerbose() > 0)
00093   {
00094     printMessage("Initial bracketing:");
00095     printMessage("A: x = " + TextTools::toString(bracket.a.x) + ", f = " + TextTools::toString(bracket.a.f));
00096     printMessage("B: x = " + TextTools::toString(bracket.b.x) + ", f = " + TextTools::toString(bracket.b.f));
00097     printMessage("C: x = " + TextTools::toString(bracket.c.x) + ", f = " + TextTools::toString(bracket.c.f));
00098   }
00099   
00100   // This will be the distance moved on the step before last.
00101   e = 0.0;
00102 
00103   // a and b must be in ascending order, but input abscissa need not be.
00104   a = (bracket.a.x < bracket.c.x ? bracket.a.x : bracket.c.x);
00105   b = (bracket.a.x > bracket.c.x ? bracket.a.x : bracket.c.x);
00106   // Initializations...
00107   fw = fv = fx = getFunction()->f(getParameters());
00108   if (fx < bracket.b.f)
00109   {
00110     //We don't want to lose our initial guess!
00111     x = w = v = bracket.b.x = getParameters()[0].getValue();
00112   }
00113   else
00114   {
00115     x = w = v = bracket.b.x;
00116     getParameter_(0).setValue(x);
00117     fw = fv = fx = getFunction()->f(getParameters());
00118   }
00119 }
00120 
00121 /******************************************************************************/
00122   
00123 void BrentOneDimension::setInitialInterval(double inf, double sup)
00124 {
00125   if(sup > inf)
00126   {
00127     _xinf = inf; _xsup = sup;
00128   }
00129   else
00130   {
00131     _xinf = sup; _xsup = inf;
00132   }
00133   isInitialIntervalSet_ = true;
00134 }
00135 
00136 /******************************************************************************/
00137 
00138 double BrentOneDimension::doStep() throw (Exception)
00139 {
00140   xm   = 0.5 * (a + b);
00141   tol2 = 2.0 * (tol1 = getStopCondition()->getTolerance() * NumTools::abs(x) + ZEPS);
00142   
00143   if(NumTools::abs(e) > tol1)
00144   {
00145     r = (x - w) * (fx - fv);
00146     q = (x - v) * (fx - fw);
00147     p = (x - v) * q - (x - w) * r;
00148     q = 2.0 * (q - r);
00149     if (q > 0.0) p = -p;
00150     q = NumTools::abs(q);
00151     etemp = e;
00152     e = d;
00153     if (NumTools::abs(p) >= NumTools::abs(0.5 * q * etemp) || p <= q * (a - x) || p >= q * (b - x))
00154       d = NumConstants::GOLDEN_RATIO_C() * (e = (x >= xm ? a - x : b - x));
00155     else
00156     {
00157       d = p / q;
00158       u = x + d;
00159       if (u - a < tol2 || b - u < tol2)
00160         d = NumTools::sign(tol1, xm - x);
00161     }
00162   }
00163   else
00164   {
00165     d = NumConstants::GOLDEN_RATIO_C() * (e = (x >= xm ? a - x : b - x));
00166   }
00167   u = (NumTools::abs(d) >= tol1 ? x + d : x + NumTools::sign(tol1, d));
00168 
00169   // Function evaluaton:
00170   ParameterList pl = getParameters();
00171   pl[0].setValue(u);
00172   fu = getFunction()->f(pl);
00173   if (fu <= fx)
00174   {
00175     if (u >= x) a = x; else b = x;
00176     NumTools::shift(v, w, x, u);
00177     NumTools::shift(fv, fw, fx, fu);
00178   }
00179   else
00180   {
00181     if (u < x) a = u; else b = u;
00182     if (fu <= fw || w == x)
00183     {
00184       v  = w;
00185       w  = u;
00186       fv = fw;
00187       fw = fu;
00188     }
00189     else if (fu <= fv || v == x || v == w)
00190     {
00191       v  = u;
00192       fv = fu;
00193     }
00194   }
00195 
00196   // Store results for this step:
00197   getParameter_(0).setValue(x);
00198   return fx;
00199 }
00200 
00201 /******************************************************************************/
00202   
00203 double BrentOneDimension::optimize() throw (Exception)
00204 {
00205   if (!isInitialIntervalSet_)
00206     throw Exception("BrentOneDimension::optimize. Initial interval not set: call the 'setInitialInterval' method first!");
00207   AbstractOptimizer::optimize();
00208   // Apply parameters and evaluate function at minimum point:
00209   currentValue_ = getFunction()->f(getParameters());
00210   return currentValue_;
00211 }
00212 
00213 /******************************************************************************/
00214 
 All Classes Namespaces Files Functions Variables Typedefs Friends