00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, 2008, 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
,
O2scl Sourceforge Project Page