minimize.h

Go to the documentation of this file.
00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 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 /** \file minimize.h
00027     \brief One-dimensional minimization routines
00028 */
00029 
00030 
00031 #ifndef DOXYGENP
00032 namespace o2scl {
00033 #endif
00034   
00035   /** 
00036       \brief Numerical differentiation base
00037   */
00038   template<class param_t, class func_t, class dfunc_t=func_t> 
00039     class minimize {
00040     
00041     public:
00042     
00043     /// Output control
00044     int verbose;
00045     
00046     /// Maximum number of iterations
00047     int ntrial;
00048     
00049     /// The tolerance for the minimum function value
00050     double tolf;
00051 
00052     /// The tolerance for the location of the minimum
00053     double tolx;
00054     
00055     /// The number of iterations for in the most recent minimization
00056     int last_ntrial;
00057     
00058     minimize() {
00059       verbose=0;
00060       ntrial=100;
00061       tolf=1.0e-4;
00062       tolx=1.0e-4;
00063       last_ntrial=0;
00064     }
00065       
00066     virtual ~minimize() {}
00067       
00068     /** 
00069         \brief Print out iteration information.
00070         
00071         Depending on the value of the variable verbose, this prints out
00072         the iteration information. If verbose=0, then no information is
00073         printed, while if verbose>1, then after each iteration, the
00074         present values of x and y are output to std::cout along with the
00075         iteration number. If verbose>=2 then each iteration waits for a
00076         character.  
00077     */
00078     virtual int print_iter(double x, double y, int iter, double value=0.0,
00079                            double limit=0.0, std::string comment="") {
00080 
00081       if (verbose<=0) return gsl_success;
00082     
00083       char ch;
00084     
00085       std::cout << comment << " Iteration: " << iter << std::endl;
00086       if (x<0) std::cout << x << " ";
00087       else std::cout << " " << x << " ";
00088       if (y<0) std::cout << y << " ";
00089       else std::cout << " " << y << " ";
00090       if (value<0) std::cout << value << " ";
00091       else std::cout << " " << value << " ";
00092       if (limit<0) std::cout << limit << std::endl;
00093       else std::cout << " " << limit << std::endl;
00094       if (verbose>1) {
00095         std::cout << "Press a key and type enter to continue. ";
00096         std::cin >> ch;
00097       }
00098     
00099       return gsl_success;
00100     }
00101   
00102     /** 
00103         \brief Calculate the minimum \c min of \c func w.r.t 'x'.
00104 
00105         If this is not overloaded, it attempts to bracket the 
00106         minimum using bracket() and then calls min_bkt() with
00107         the newly bracketed minimum.
00108     */
00109     virtual int min(double &x, double &fmin, param_t &pa, func_t &func) {
00110       double xl, xr, f, fl, fr;
00111       xl=x*0.9;
00112       xr=x*1.1;
00113       bracket(xl,x,xr,fl,f,fr,pa,func);
00114       return min_bkt(x,xl,xr,fmin,pa,func);
00115     }
00116     
00117     /** \brief Calculate the minimum \c min of \c func with x2
00118         bracketed between x1 and x3
00119           
00120         If this is not overloaded, it ignores the bracket and calls min().  
00121     */
00122     virtual int min_bkt(double &x2, double x1, double x3, double &fmin,
00123                         param_t &pa, func_t &func) 
00124     {
00125       return min(x2,fmin,pa,func);
00126     }
00127     
00128     /** \brief Calculate the minimum \c min of \c func with
00129         derivative \c dfunc w.r.t 'x'.
00130         
00131         If this is not overloaded, it attempts to bracket the 
00132         minimum using bracket() and then calls min_bkt_de() with
00133         the newly bracketed minimum.
00134     */
00135     virtual int min_de(double &x, double &fmin, param_t &pa, func_t &func,
00136                        dfunc_t &df) 
00137     {
00138       double xl, xr, f, fl, fr;
00139       xl=x*0.9;
00140       xr=x*1.1;
00141       bracket(xl,x,xr,fl,f,fr,pa,func);
00142       return min_bkt_de(x,xl,xr,fmin,pa,func,df);
00143     }
00144     
00145     /** \brief Calculate the minimum \c min of \c func with derivative
00146         \c dfunc and x2 bracketed between x1 and x3
00147         
00148         If this is not overloaded, it ignores the bracket and calls min_de().
00149     */
00150     virtual int min_bkt_de(double &x2, double x1, double x3, double &fmin, 
00151                            param_t &pa, func_t &func, dfunc_t &df) 
00152     {
00153       return min_de(x2,fmin,pa,func,df);
00154     }
00155   
00156     /** 
00157         \brief Given ax and bx, bracket a minimum for function \c func.
00158         
00159         Upon success, fa=f(ax), fb=f(bx), and fc=f(cx) with 
00160         fb<fa and fb<fc and ax<bx<cx. 
00161         
00162         \todo Improve this algorithm with the standard golden ratio
00163         method.
00164         \todo Double check that this works when at least two of 
00165         f(a), f(b) and f((a+b)/2) are equal.
00166     */
00167     virtual int bracket(double &ax, double &bx, double &cx, double &fa, 
00168                         double &fb, double &fc, param_t &pa, 
00169                         func_t &func) 
00170     {
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<20) {
00178         func(x,fx,pa);
00179         func(x2,fx2,pa);
00180         func(x3,fx3,pa);
00181       
00182         if (fx3>=fx2 && fx3>=fx) {
00183           if (fx2>fx) {
00184             x2=x3;
00185             x3=(x+x2)/2.0;
00186           } else {
00187             x=x3;
00188             x3=(x+x2)/2.0;
00189           }
00190         } else if (fx<=fx3 && fx3<=fx2) {
00191           x3=x;
00192           x=x2-2.0*(x2-x);
00193         } else if (fx3<fx2 && fx3<fx) {
00194           done=true;
00195           ax=x;
00196           bx=x3;
00197           cx=x2;
00198           fa=fx;
00199           fb=fx3;
00200           fc=fx2;
00201         } else {
00202           x3=x2;
00203           x2=x+2.0*(x2-x);
00204         }
00205         i++;
00206       }
00207     
00208       if (done==false) {
00209         set_err_ret("Too many iterations in minimize::bracket().",
00210                     gsl_emaxiter);
00211       }
00212     
00213       return 0;
00214     }
00215   
00216     /// Return string denoting type ("minimize")
00217     virtual const char *type() { return "minimize"; }
00218   
00219   };
00220 
00221   /** 
00222       \brief Constrain \c x to be within \c width
00223       of the value given by \c center
00224       
00225       Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$
00226       \c height, this returns the value \f$ h (1+|x-c-w|/w) \f$ if \f$
00227       x>c+w \f$ and \f$ h (1+|x-c+w|/w) \f$ if \f$ x<c-w \f$ . The
00228       value at \f$ x=c-w \f$ or \f$ x=c+w \f$ is \f$ h \f$ and the
00229       value at \f$ x=c-2w \f$ or \f$ x=c+2w \f$ is \f$ 2 h \f$ .
00230 
00231       It is important to note that, for large distances of \c x 
00232       from \c center, this only scales linearly. If you are trying to
00233       constrain a function which decreases more than linearly by
00234       making \c x far from \c center, then a minimizer will
00235       likely ignore this constraint.
00236   */
00237   inline double constraint(double x, double center, double width, 
00238                            double height) {
00239     double ret=0.0;
00240     if (x>center+width) {
00241       ret=height*(1.0+fabs(x-center-width)/width);
00242     } else if (x<center-width) {
00243       ret=height*(1.0+fabs(x-center+width)/width);
00244     }
00245     return ret;
00246   }
00247 
00248   /** \brief Constrain \c x to be within \c width of the value given
00249       by \c center
00250 
00251       Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$
00252       \c height, \f$ t= \f$ \c tightness, and \f$ \ell= \f$ \c
00253       exp_arg_limit, this returns the value
00254       \f[
00255       \left(\frac{x-c}{w}\right)^2 \left[ 
00256       1+ e^{t\left(x-c-w\right)\left(c+w-x\right)/w^2}
00257       \right]^{-1}
00258       \f]
00259       if \f$ x \geq c \f$ .
00260 
00261       The exponential is handled gracefully by assuming that anything
00262       smaller than \f$ \exp(-\ell) \f$ is zero. This function is
00263       continuous and differentiable.  Note that if \f$ x=c \f$ , then
00264       the function returns zero.
00265       
00266       It is important to note that, for large distances of \c x 
00267       from \c center, this only scales linearly. If you are trying to
00268       constrain a function which decreases more than linearly by
00269       making \c x far from \c center, then a minimizer will
00270       likely ignore this constraint.
00271   */
00272   inline double cont_constraint(double x, double center, double width, 
00273                                 double height, double tightness=40.0, 
00274                                 double exp_arg_limit=50.0) {
00275     double ret, wid2=width*width;
00276     double arg=tightness/wid2*(x-center-width)*(center+width-x);
00277     if (arg<-exp_arg_limit) {
00278       ret=(x-center)*(x-center)/wid2;
00279     } else {
00280       ret=(x-center)*(x-center)/wid2/(1.0+exp(arg));
00281     }
00282     return ret;
00283   }
00284   
00285   /** 
00286       \brief Constrain \c x to be greater than the value given by \c
00287       center
00288 
00289       Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$
00290       \c height, this returns \f$ h(1+|x-c|/w) \f$ if \f$ x<c \f$ and
00291       zero otherwise.  The value at \f$ x=c \f$ is \f$ h \f$ , while
00292       the value at \f$ x=c-w \f$ is \f$ 2 h \f$ .
00293 
00294       It is important to note that, for large distances of \c x 
00295       from \c center, this only scales linearly. If you are trying to
00296       constrain a function which decreases more than linearly by
00297       making \c x far from \c center, then a minimizer will
00298       likely ignore this constraint.
00299   */
00300   inline double lower_bound(double x, double center, double width, 
00301                             double height) {
00302     double ret=0.0;
00303     if (x<center) ret=height*(1.0+fabs(x-center)/width);
00304     return ret;
00305   }
00306   
00307   /** 
00308       \brief Constrain \c x to be greater than the value given by \c
00309       center 
00310 
00311       Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$ \c
00312       height, \f$ t= \f$ \c tightness, and \f$ \ell= \f$ \c exp_arg_limit,
00313       this returns \f$ h(c-x+w)/(1+\exp(t(x-c)/w)) \f$ and has the
00314       advantage of being a continuous and differentiable function. The
00315       exponential is handled gracefully by assuming that anything
00316       smaller than \f$ \exp(-\ell) \f$ is zero
00317 
00318       It is important to note that, for large distances of \c x 
00319       from \c center, this only scales linearly. If you are trying to
00320       constrain a function which decreases more than linearly by
00321       making \c x far from \c center, then the constraint will 
00322       be essentially ignored.
00323   */
00324   inline double cont_lower_bound(double x, double center, double width, 
00325                                  double height, double tightness=40.0, 
00326                                  double exp_arg_limit=50.0) {
00327     double ret, arg=tightness*(x-center)/width;
00328     if (arg>exp_arg_limit) {
00329       ret=0.0;
00330     } else if (arg<-exp_arg_limit) {
00331       ret=height*(center-x+width);
00332     } else {
00333       ret=height*(center-x+width)/(1.0+exp(arg));
00334     }
00335     return ret;
00336   }
00337 
00338 #ifndef DOXYGENP
00339 }
00340 #endif
00341 
00342 #endif

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.

Project hosting provided by SourceForge.net Logo, O2scl Sourceforge Project Page