|
bpp-core
2.1.0
|
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