Object-oriented Scientific Computing Library: Version 0.910
minimize.h
Go to the documentation of this file.
00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006-2012, Andrew W. Steiner
00005   
00006   This file is part of O2scl.
00007   
00008   O2scl is free software; you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation; either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   O2scl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
00020 
00021   -------------------------------------------------------------------
00022 */
00023 #ifndef O2SCL_MINIMIZE_H
00024 #define O2SCL_MINIMIZE_H
00025 
00026 // For fabs()
00027 #include <cmath>
00028 
00029 #include <o2scl/err_hnd.h>
00030 #include <o2scl/funct.h>
00031  
00032 /** \file minimize.h
00033     \brief One-dimensional minimization base class and associated functions
00034 */
00035 
00036 #ifndef DOXYGENP
00037 namespace o2scl {
00038 #endif
00039   
00040   /** \brief One-dimensional minimization [abstract base]
00041 
00042       \future Add a class for the quad_golden algorithm from GSL.
00043   */
00044   template<class func_t=funct, class dfunc_t=func_t> class minimize {
00045     
00046   public:
00047   
00048   minimize() {
00049     verbose=0;
00050     ntrial=100;
00051     tol_rel=1.0e-4;
00052     tol_abs=1.0e-4;
00053     last_ntrial=0;
00054     bracket_iter=20;
00055     err_nonconv=true;
00056     last_conv=0;
00057   }
00058       
00059   virtual ~minimize() {}
00060       
00061   /// Output control
00062   int verbose;
00063     
00064   /// Maximum number of iterations
00065   int ntrial;
00066     
00067   /// The tolerance for the minimum function value
00068   double tol_rel;
00069 
00070   /// The tolerance for the location of the minimum
00071   double tol_abs;
00072     
00073   /// The number of iterations for in the most recent minimization
00074   int last_ntrial;
00075     
00076   /** \brief The number of iterations for automatically 
00077       bracketing a minimum (default 20)
00078   */
00079   int bracket_iter;
00080 
00081   /// If true, call the error handler if the routine does not "converge"
00082   bool err_nonconv;
00083     
00084   /** \brief Zero if last call to min(), min_bkt(), or 
00085       min_de() converged. 
00086         
00087       This is particularly useful if err_nonconv is false to test
00088       if the last call to min(), min_bkt(), or min_de() 
00089       converged.
00090   */
00091   int last_conv;
00092     
00093   /** \brief Print out iteration information.
00094         
00095       Depending on the value of the variable \ref verbose, this
00096       prints out the iteration information. If verbose=0, then no
00097       information is printed, while if verbose>1, then after each
00098       iteration, the present values of x and y are output to
00099       std::cout along with the iteration number. If verbose>=2 then
00100       each iteration waits for a character.
00101   */
00102   virtual int print_iter(double x, double y, int iter, double value=0.0,
00103                          double limit=0.0, std::string comment="") {
00104     
00105     if (verbose<=0) return gsl_success;
00106     
00107     char ch;
00108     
00109     std::cout << comment << " Iteration: " << iter << std::endl;
00110     if (x<0) std::cout << x << " ";
00111     else std::cout << " " << x << " ";
00112     if (y<0) std::cout << y << " ";
00113     else std::cout << " " << y << " ";
00114     if (value<0) std::cout << value << " ";
00115     else std::cout << " " << value << " ";
00116     if (limit<0) std::cout << limit << std::endl;
00117     else std::cout << " " << limit << std::endl;
00118     if (verbose>1) {
00119       std::cout << "Press a key and type enter to continue. ";
00120       std::cin >> ch;
00121     }
00122     
00123     return gsl_success;
00124   }
00125   
00126   /** \brief Calculate the minimum \c min of \c func w.r.t 'x'.
00127 
00128       If this is not overloaded, it attempts to bracket the 
00129       minimum using bracket() and then calls min_bkt() with
00130       the newly bracketed minimum.
00131   */
00132   virtual int min(double &x, double &fmin, func_t &func)=0;
00133     
00134   /** \brief Calculate the minimum \c min of \c func with x2
00135       bracketed between x1 and x3
00136           
00137       If this is not overloaded, it ignores the bracket and calls min().  
00138   */
00139   virtual int min_bkt(double &x2, double x1, double x3, double &fmin,
00140                       func_t &func)=0;
00141     
00142   /** \brief Calculate the minimum \c min of \c func with
00143       derivative \c dfunc w.r.t 'x'.
00144         
00145       If this is not overloaded, it attempts to bracket the 
00146       minimum using bracket() and then calls min_bkt_de() with
00147       the newly bracketed minimum.
00148   */
00149   virtual int min_de(double &x, double &fmin, func_t &func,
00150                      dfunc_t &df)=0;
00151   
00152   /** \brief Given interval <tt>(ax,bx)</tt>, attempt to bracket a
00153       minimum for function \c func.
00154         
00155       Upon success, <tt>fa=func(ax)</tt>, <tt>fb=func(bx)</tt>, and
00156       <tt>fc=func(cx)</tt> with <tt>fb<fa</tt>, <tt>fb<fc</tt> and
00157       <tt>ax<bx<cx</tt>. The initial values of \c cx, \c fa, 
00158       \c fb, and \c fc are all ignored.
00159 
00160       The number of iterations is controlled by \ref bracket_iter.
00161 
00162       \note This algorithm can fail if there's a minimum which has a
00163       much smaller size than \f$ bx-ax \f$, or if the function has the
00164       same value at \c ax, \c bx, and the midpoint <tt>(ax+bx)/2</tt>.
00165       
00166       \future Improve this algorithm with the golden ratio
00167       method in gsl/min/bracketing.c?
00168   */
00169   virtual int bracket(double &ax, double &bx, double &cx, double &fa, 
00170                       double &fb, double &fc, func_t &func) {
00171       
00172     double x=ax, x2=bx, x3=(ax+bx)/2.0;
00173     double fx, fx3, fx2;
00174     int i=0;
00175       
00176     bool done=false;
00177     while(done==false && i<bracket_iter) {
00178       fx=func(x);
00179       fx2=func(x2);
00180       fx3=func(x3);
00181 
00182       if (verbose>0) {
00183         std::cout << "Function minimize::bracket(), Iteration: " 
00184                   << i << std::endl;
00185         std::cout << " " << x << " " << x3 << " " << x2 << std::endl;
00186         std::cout << " " << fx << " " << fx3 << " " << fx2 << std::endl;
00187         if (verbose>1) {
00188           char ch;
00189           std::cout << "Press a key and type enter to continue. ";
00190           std::cin >> ch;
00191         }
00192       }
00193 
00194       if (fx3>=fx2 && fx3>=fx) {
00195         // If the middle value is higher than the endpoints, 
00196         // try again with one side or the other
00197         if (fx2>fx) {
00198           x2=x3;
00199           x3=(x+x2)/2.0;
00200         } else {
00201           x=x3;
00202           x3=(x+x2)/2.0;
00203         }
00204       } else if (fx<=fx3 && fx3<=fx2) {
00205         // If we're increasing, extend to the left
00206         x3=x;
00207         x=x2-2.0*(x2-x);
00208       } else if (fx3<fx2 && fx3<fx) {
00209         // If we've succeeded, copy the results over
00210         done=true;
00211         ax=x;
00212         bx=x3;
00213         cx=x2;
00214         fa=fx;
00215         fb=fx3;
00216         fc=fx2;
00217       } else {
00218         // Otherwise we're decreasing, extend to the right
00219         x3=x2;
00220         x2=x+2.0*(x2-x);
00221       }
00222       i++;
00223     }
00224     
00225     if (done==false) {
00226       O2SCL_ERR_RET("Too many iterations in minimize::bracket().",
00227                     gsl_emaxiter);
00228     }
00229     
00230     return 0;
00231   }
00232   
00233   /// Return string denoting type ("minimize")
00234   virtual const char *type() { return "minimize"; }
00235   
00236   };
00237 
00238   /** \brief One-dimensional bracketing minimization [abstract base]
00239   */
00240   template<class func_t, class dfunc_t=func_t> 
00241     class minimize_bkt : public minimize<func_t,dfunc_t> {
00242 
00243   public:
00244     
00245   minimize_bkt() {
00246     bracket_iter=20;
00247   }
00248   
00249   virtual ~minimize_bkt() {}
00250       
00251   /** \brief The number of iterations for automatically 
00252       bracketing a minimum (default 20)
00253   */
00254   int bracket_iter;
00255 
00256   /** \brief Calculate the minimum \c min of \c func w.r.t 'x'.
00257 
00258       If this is not overloaded, it attempts to bracket the 
00259       minimum using bracket() and then calls min_bkt() with
00260       the newly bracketed minimum.
00261   */
00262   virtual int min(double &x, double &fmin, func_t &func) {
00263     double xl, xr, f, fl, fr;
00264     xl=x*0.9;
00265     xr=x*1.1;
00266     if (bracket(xl,x,xr,fl,f,fr,func)!=0) {
00267       O2SCL_CONV_RET("Failed to bracket in min().",gsl_efailed,
00268                              this->err_nonconv);
00269     }
00270     return min_bkt(x,xl,xr,fmin,func);
00271   }
00272     
00273   /** \brief Calculate the minimum \c min of \c func with x2
00274       bracketed between x1 and x3
00275           
00276       If this is not overloaded, it ignores the bracket and calls min().  
00277   */
00278   virtual int min_bkt(double &x2, double x1, double x3, double &fmin,
00279                       func_t &func)=0;
00280     
00281   /** \brief Calculate the minimum \c min of \c func with
00282       derivative \c dfunc w.r.t 'x'.
00283         
00284       If this is not overloaded, it attempts to bracket the 
00285       minimum using bracket() and then calls min_bkt_de() with
00286       the newly bracketed minimum.
00287   */
00288   virtual int min_de(double &x, double &fmin, func_t &func,
00289                      dfunc_t &df) {
00290     double xl, xr, f, fl, fr;
00291     xl=x*0.9;
00292     xr=x*1.1;
00293     if (bracket(xl,x,xr,fl,f,fr,func)!=0) {
00294       O2SCL_CONV_RET("Failed to bracket in min_de().",gsl_efailed,
00295                              this->err_nonconv);
00296     }
00297     return min_bkt(x,xl,xr,fmin,func);
00298   }
00299   
00300   /// Return string denoting type ("minimize_bkt")
00301   virtual const char *type() { return "minimize_bkt"; }
00302   
00303   };
00304 
00305   /** \brief One-dimensional minimization using derivatives [abstract base]
00306 
00307       At the moment there are no minimizers of this type implemented in
00308       \o2. 
00309 
00310       \future Create a version of \ref gsl_mmin_conf which
00311       implements a minimizer with this interface.
00312   */
00313   template<class func_t, class dfunc_t=func_t> 
00314     class minimize_de : public minimize<func_t,dfunc_t> {
00315 
00316   public:
00317     
00318   minimize_de() {
00319   }
00320       
00321   virtual ~minimize_de() {}
00322       
00323   /** \brief Calculate the minimum \c min of \c func w.r.t 'x'.
00324 
00325       If this is not overloaded, it attempts to bracket the 
00326       minimum using bracket() and then calls min_bkt() with
00327       the newly bracketed minimum.
00328   */
00329   virtual int min(double &x, double &fmin, func_t &func)=0;
00330     
00331   /** \brief Calculate the minimum \c min of \c func with x2
00332       bracketed between x1 and x3
00333           
00334       If this is not overloaded, it ignores the bracket and calls min().  
00335   */
00336   virtual int min_bkt(double &x2, double x1, double x3, double &fmin,
00337                       func_t &func)=0;
00338   
00339   /** \brief Calculate the minimum \c min of \c func with
00340       derivative \c dfunc w.r.t 'x'.
00341       
00342       If this is not overloaded, it attempts to bracket the 
00343       minimum using bracket() and then calls min_bkt_de() with
00344       the newly bracketed minimum.
00345   */
00346   virtual int min_de(double &x, double &fmin, func_t &func,
00347                      dfunc_t &df)=0;
00348   
00349   /// Return string denoting type ("minimize_de")
00350   virtual const char *type() { return "minimize_de"; }
00351   
00352   };
00353 
00354   /** \brief Constrain \c x to be within \c width
00355       of the value given by \c center
00356       
00357       Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$
00358       \c height, this returns the value \f$ h (1+|x-c-w|/w) \f$ if \f$
00359       x>c+w \f$ and \f$ h (1+|x-c+w|/w) \f$ if \f$ x<c-w \f$ . The
00360       value near \f$ x=c-w \f$ or \f$ x=c+w \f$ is \f$ h \f$ (the
00361       value of the function exactly at these points is zero) and the
00362       value at \f$ x=c-2w \f$ or \f$ x=c+2w \f$ is \f$ 2 h \f$ .
00363 
00364       It is important to note that, for large distances of \c x 
00365       from \c center, this only scales linearly. If you are trying to
00366       constrain a function which decreases more than linearly by
00367       making \c x far from \c center, then a minimizer may
00368       ignore this constraint.
00369   */
00370   inline double constraint(double x, double center, double width, 
00371                            double height) {
00372     double ret=0.0;
00373     if (x>center+width) {
00374       ret=height*(1.0+fabs(x-center-width)/width);
00375     } else if (x<center-width) {
00376       ret=height*(1.0+fabs(x-center+width)/width);
00377     }
00378     return ret;
00379   }
00380 
00381   /** \brief Constrain \c x to be within \c width of the value given
00382       by \c center
00383 
00384       Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$
00385       \c height, \f$ t= \f$ \c tightness, and \f$ \ell= \f$ \c
00386       exp_arg_limit, this returns the value
00387       \f[
00388       h \left(\frac{x-c}{w}\right)^2 \left[ 
00389       1+ e^{t\left(x-c+w\right)\left(c+w-x\right)/w^2}
00390       \right]^{-1}
00391       \f]
00392       
00393       This function is continuous and differentiable.  Note that if
00394       \f$ x=c \f$ , then the function returns zero.
00395 
00396       The exponential is handled gracefully by assuming that anything
00397       smaller than \f$ \exp(-\ell) \f$ is zero. This creates a small
00398       discontinuity which can be removed with the sufficiently large
00399       value of \f$ \ell \f$. 
00400       
00401       It is important to note that, for large distances of \c x from
00402       \c center, this scales quadratically. If you are trying to
00403       constrain a function which decreases faster than quadratically
00404       by making \c x far from \c center, then a minimizer may ignore
00405       this constraint.
00406       
00407       In the limit \f$ t \rightarrow \infty \f$, this function
00408       converges towards the squared value of \ref constraint(), except
00409       exactly at the points \f$ x=c-w \f$ and \f$ x=c+w \f$.
00410   */
00411   inline double cont_constraint(double x, double center, double width, 
00412                                 double height, double tightness=40.0, 
00413                                 double exp_arg_limit=50.0) {
00414     double ret, wid2=width*width;
00415     double arg=tightness/wid2*(x-center+width)*(center+width-x);
00416     if (arg<-exp_arg_limit) {
00417       ret=(x-center)*(x-center)/wid2;
00418     } else {
00419       ret=(x-center)*(x-center)/wid2/(1.0+exp(arg));
00420     }
00421     return ret*height;
00422   }
00423   
00424   /** \brief Constrain \c x to be greater than the value given by \c
00425       center
00426       
00427       Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$
00428       \c height, this returns \f$ h(1+|x-c|/w) \f$ if \f$ x<c \f$ and
00429       zero otherwise.  The value at \f$ x=c \f$ is \f$ h \f$ , while
00430       the value at \f$ x=c-w \f$ is \f$ 2 h \f$ .
00431 
00432       It is important to note that, for large distances of \c x from
00433       \c center, this only scales linearly. If you are trying to
00434       constrain a function which decreases more than linearly by
00435       making \c x far from \c center, then a minimizer may ignore this
00436       constraint.
00437   */
00438   inline double lower_bound(double x, double center, double width, 
00439                             double height) {
00440     double ret=0.0;
00441     if (x<center) ret=height*(1.0+fabs(x-center)/width);
00442     return ret;
00443   }
00444   
00445   /** \brief Constrain \c x to be greater than the value given by \c
00446       center 
00447 
00448       Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$
00449       \c height, \f$ t= \f$ \c tightness, and \f$ \ell= \f$ \c
00450       exp_arg_limit, this returns \f$ h(c-x+w)/(w+w\exp(t(x-c)/w)) \f$
00451       and has the advantage of being a continuous and differentiable
00452       function.  The value of the function exactly at \f$ x=c \f$ is
00453       \f$ h/2 \f$, but for \f$ x \f$ just below \f$ c \f$ the function
00454       is \f$ h \f$ and just above \f$ c \f$ the function is quite
00455       small. 
00456 
00457       The exponential is handled gracefully by assuming that anything
00458       smaller than \f$ \exp(-\ell) \f$ is zero. This creates a small
00459       discontinuity which can be removed with the sufficiently large
00460       value of \f$ \ell \f$. 
00461 
00462       It is important to note that, for large distances of \c x 
00463       from \c center, this only scales linearly. If you are trying to
00464       constrain a function which decreases more than linearly by
00465       making \c x far from \c center, then a minimizer may
00466       ingore this constraint.
00467 
00468       In the limit \f$ t \rightarrow \infty \f$, this function
00469       converges towards \ref lower_bound(), except exactly at the
00470       point \f$ x=c \f$.
00471   */
00472   inline double cont_lower_bound(double x, double center, double width, 
00473                                  double height, double tightness=40.0, 
00474                                  double exp_arg_limit=50.0) {
00475     double ret, arg=tightness*(x-center)/width;
00476     if (arg>exp_arg_limit) {
00477       ret=0.0;
00478     } else if (arg<-exp_arg_limit) {
00479       ret=height*(center-x+width)/width;
00480     } else {
00481       ret=height*(center-x+width)/width/(1.0+exp(arg));
00482     }
00483     return ret;
00484   }
00485 
00486 #ifndef DOXYGENP
00487 }
00488 #endif
00489 
00490 #endif
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.