|
bpp-core
2.1.0
|
00001 // 00002 // File: OneDimensionOptimizationTools.cpp 00003 // Created by: Julien Dutheil 00004 // Created on: Mon Nov 17 11:15:22 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. This file is part of the Bio++ project. 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 "NewtonBacktrackOneDimension.h" 00041 #include "BrentOneDimension.h" 00042 #include "OneDimensionOptimizationTools.h" 00043 #include "../NumTools.h" 00044 #include "../NumConstants.h" 00045 00046 using namespace bpp; 00047 using namespace std; 00048 00049 /****************************************************************************** 00050 * The Point class * 00051 ******************************************************************************/ 00052 00053 inline void BracketPoint::set(double xval, double fval) { this->x = xval; this->f = fval; } 00054 00055 /****************************************************************************** 00056 * The Bracket class * 00057 ******************************************************************************/ 00058 00059 inline void Bracket::setA(double xa, double fa) { a.set(xa, fa); } 00060 inline void Bracket::setB(double xb, double fb) { b.set(xb, fb); } 00061 inline void Bracket::setC(double xc, double fc) { c.set(xc, fc); } 00062 00063 /******************************************************************************/ 00064 00065 Bracket OneDimensionOptimizationTools::bracketMinimum( 00066 double a, 00067 double b, 00068 Function * function, 00069 ParameterList parameters) 00070 { 00071 Bracket bracket; 00072 // Copy the parameter to use. 00073 bracket.a.x = a; 00074 parameters[0].setValue(bracket.a.x); bracket.a.f = function->f(parameters); 00075 bracket.b.x = b; 00076 parameters[0].setValue(bracket.b.x); bracket.b.f = function->f(parameters); 00077 if (bracket.b.f > bracket.a.f) 00078 { 00079 // Switch roles of first and second point so that we can go downhill 00080 // in the direction from a to b. 00081 NumTools::swap<double>(bracket.a.x, bracket.b.x); 00082 NumTools::swap<double>(bracket.a.f, bracket.b.f); 00083 } 00084 00085 // First guess for third point: 00086 bracket.c.x = bracket.b.x + NumConstants::GOLDEN_RATIO_PHI() * (bracket.b.x - bracket.a.x); 00087 parameters[0].setValue(bracket.c.x); bracket.c.f = function->f(parameters); 00088 00089 // Keep returning here until we bracket: 00090 while (bracket.b.f > bracket.c.f) 00091 { 00092 // Compute xu by parabolic extrapolation from a, b, c. TINY is used to prevent 00093 // any possible division by 0. 00094 double r = (bracket.b.x - bracket.a.x) * (bracket.b.f - bracket.c.f); 00095 double q = (bracket.b.x - bracket.c.x) * (bracket.b.f - bracket.a.f); 00096 00097 double xu = bracket.b.x - ((bracket.b.x - bracket.c.x) * q - (bracket.b.x - bracket.a.x) * r) / 00098 (2.0 * NumTools::sign(NumTools::max(NumTools::abs(q - r), NumConstants::VERY_TINY()), q - r)); 00099 double xulim = (bracket.b.x) + GLIMIT * (bracket.c.x - bracket.b.x); 00100 double fu; 00101 00102 // We don't go farther than this. 00103 // Test various possibilities: 00104 if ((bracket.b.x - xu) * (xu - bracket.c.x) > 0.0) 00105 { 00106 parameters[0].setValue(xu); fu = function->f(parameters); 00107 if (fu < bracket.c.f) 00108 { 00109 bracket.setA(bracket.b.x, bracket.b.f); 00110 bracket.setB(xu, fu); 00111 return bracket; 00112 } 00113 else if (fu > bracket.b.f) 00114 { 00115 bracket.setC(xu, fu); 00116 return bracket; 00117 } 00118 // Parabolic fit was no use. 00119 // Use default magnification. 00120 xu = bracket.c.x + NumConstants::GOLDEN_RATIO_PHI() * (bracket.c.x - bracket.b.x); 00121 parameters[0].setValue(xu); fu = function->f(parameters); 00122 } 00123 else if ((bracket.c.x - xu) * (xu - xulim) > 0.0) 00124 { 00125 // Parabolic fit is between point 3 and its allowed limit. 00126 parameters[0].setValue(xu); fu = function->f(parameters); 00127 if (fu < bracket.c.f) 00128 { 00129 NumTools::shift<double>(bracket.b.x, bracket.c.x, xu, bracket.c.x + NumConstants::GOLDEN_RATIO_PHI() * (bracket.c.x - bracket.b.x)); 00130 parameters[0].setValue(xu); 00131 NumTools::shift<double>(bracket.b.f, bracket.c.f, fu, function->f(parameters)); 00132 } 00133 } 00134 else if ((xu - xulim) * (xulim - bracket.c.x) >= 0.0) 00135 { 00136 // Limit parabolic xu to maximum allowed value. 00137 xu = xulim; 00138 parameters[0].setValue(xu); fu = function->f(parameters); 00139 } 00140 else 00141 { 00142 // Reject parabolic xu, use default magnification. 00143 xu = bracket.c.x + NumConstants::GOLDEN_RATIO_PHI() * (bracket.c.x - bracket.b.x); 00144 parameters[0].setValue(xu); fu = function->f(parameters); 00145 } 00146 // Eliminate oldest point and continue. 00147 NumTools::shift<double>(bracket.a.x, bracket.b.x, bracket.c.x, xu); 00148 NumTools::shift<double>(bracket.a.f, bracket.b.f, bracket.c.f, fu); 00149 } 00150 return bracket; 00151 } 00152 00153 /******************************************************************************/ 00154 00155 unsigned int OneDimensionOptimizationTools::lineMinimization( 00156 DirectionFunction& f1dim, 00157 ParameterList& parameters, 00158 std::vector<double>& xi, 00159 double tolerance, 00160 OutputStream* profiler, 00161 OutputStream* messenger, 00162 int verbose) 00163 { 00164 // Initial guess for brackets: 00165 double ax = 0.; 00166 double xx = 0.01; 00167 00168 f1dim.setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO); 00169 f1dim.setMessageHandler(messenger); 00170 f1dim.init(parameters, xi); 00171 BrentOneDimension bod(&f1dim); 00172 bod.setMessageHandler(messenger); 00173 bod.setProfiler(profiler); 00174 bod.setVerbose(verbose >= 1 ? 1 : 0); 00175 bod.setOptimizationProgressCharacter("."); 00176 bod.getStopCondition()->setTolerance(0.01); 00177 bod.setInitialInterval(ax, xx); 00178 bod.setConstraintPolicy(AutoParameter::CONSTRAINTS_KEEP); 00179 ParameterList singleParameter; 00180 singleParameter.addParameter(Parameter("x", 0.0)); 00181 bod.init(singleParameter); 00182 bod.optimize(); 00183 //Update parameters: 00184 //parameters.matchParametersValues(f1dim.getFunction()->getParameters()); 00185 00186 double xmin = f1dim.getParameters()[0].getValue(); 00187 for(size_t j = 0; j < parameters.size(); j++) 00188 { 00189 xi[j] *= xmin; 00190 parameters[j].setValue(parameters[j].getValue() + xi[j]); 00191 } 00192 return bod.getNumberOfEvaluations(); 00193 } 00194 00195 /******************************************************************************/ 00196 00197 unsigned int OneDimensionOptimizationTools::lineSearch(DirectionFunction& f1dim, 00198 ParameterList& parameters, 00199 std::vector<double>& xi, 00200 std::vector<double>& gradient, 00201 OutputStream* profiler, 00202 OutputStream* messenger, 00203 int verbose) 00204 { 00205 size_t size = xi.size(); 00206 00207 f1dim.setConstraintPolicy(AutoParameter::CONSTRAINTS_AUTO); 00208 f1dim.setMessageHandler(messenger); 00209 f1dim.init(parameters, xi); 00210 00211 double slope=0; 00212 for (unsigned int i=0;i<size;i++) 00213 slope+=xi[i]*gradient[i]; 00214 00215 // if (slope>=0) 00216 // throw Exception("Slope problem in OneDimensionOptimizationTools::lineSearch. Slope="+TextTools::toString(slope)); 00217 00218 double x, temp, test=0; 00219 for (unsigned int i=0;i<size;i++){ 00220 x=abs(parameters[i].getValue()); 00221 temp=abs(xi[i]); 00222 if (x>1.0) 00223 temp/=x; 00224 if (temp>test) 00225 test=temp; 00226 } 00227 00228 NewtonBacktrackOneDimension nbod(&f1dim, slope, test); 00229 00230 nbod.setMessageHandler(messenger); 00231 nbod.setProfiler(profiler); 00232 nbod.setVerbose(verbose >= 1 ? 1 : 0); 00233 nbod.setOptimizationProgressCharacter("."); 00234 nbod.getStopCondition()->setTolerance(0.0001); 00235 // nbod.setInitialInterval(ax, xx); 00236 nbod.setConstraintPolicy(AutoParameter::CONSTRAINTS_KEEP); 00237 ParameterList singleParameter; 00238 singleParameter.addParameter(Parameter("x", 0.0)); 00239 nbod.init(singleParameter); 00240 nbod.optimize(); 00241 //Update parameters: 00242 //parameters.matchParametersValues(f1dim.getFunction()->getParameters()); 00243 00244 double xmin = f1dim.getParameters()[0].getValue(); 00245 for(unsigned int j = 0; j < parameters.size(); j++) 00246 { 00247 xi[j] *= xmin; 00248 parameters[j].setValue(parameters[j].getValue() + xi[j]); 00249 } 00250 00251 return nbod.getNumberOfEvaluations(); 00252 } 00253 00254 /******************************************************************************/ 00255 00256 double OneDimensionOptimizationTools::GLIMIT = 100.0; 00257 00258 /******************************************************************************/ 00259