bpp-core  2.1.0
OneDimensionOptimizationTools.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Friends