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 #include <o2scl/err_hnd.h> 00027 00028 /** \file minimize.h 00029 \brief One-dimensional minimization routines 00030 */ 00031 00032 00033 #ifndef DOXYGENP 00034 namespace o2scl { 00035 #endif 00036 00037 /** 00038 \brief One-dimensional minimization [abstract base] 00039 00040 \note This base class does not actually perform any 00041 minimization. Use either gsl_min_brent or cern_minimize. 00042 00043 \future This does not have pure virtual functions, but I'd still 00044 like to prevent the user from directly instantiating a minimize 00045 object. 00046 */ 00047 template<class param_t, class func_t, class dfunc_t=func_t> 00048 class minimize { 00049 00050 #ifndef DOXYGEN_INTERNAL 00051 00052 protected: 00053 00054 /// Should be true if min_bkt() is overloaded 00055 bool over_bkt; 00056 00057 /// Should be true if min_de() is overloaded 00058 bool over_de; 00059 00060 #endif 00061 00062 public: 00063 00064 /// Output control 00065 int verbose; 00066 00067 /// Maximum number of iterations 00068 int ntrial; 00069 00070 /// The tolerance for the minimum function value 00071 double tolf; 00072 00073 /// The tolerance for the location of the minimum 00074 double tolx; 00075 00076 /// The number of iterations for in the most recent minimization 00077 int last_ntrial; 00078 00079 /** 00080 \brief The number of iterations for automatically 00081 bracketing a minimum (default 20) 00082 */ 00083 int bracket_iter; 00084 00085 minimize() { 00086 verbose=0; 00087 ntrial=100; 00088 tolf=1.0e-4; 00089 tolx=1.0e-4; 00090 last_ntrial=0; 00091 over_bkt=false; 00092 over_de=false; 00093 bracket_iter=20; 00094 } 00095 00096 virtual ~minimize() {} 00097 00098 /** 00099 \brief Print out iteration information. 00100 00101 Depending on the value of the variable \ref verbose, this 00102 prints out the iteration information. If verbose=0, then no 00103 information is printed, while if verbose>1, then after each 00104 iteration, the present values of x and y are output to 00105 std::cout along with the iteration number. If verbose>=2 then 00106 each iteration waits for a character. 00107 */ 00108 virtual int print_iter(double x, double y, int iter, double value=0.0, 00109 double limit=0.0, std::string comment="") { 00110 00111 if (verbose<=0) return gsl_success; 00112 00113 char ch; 00114 00115 std::cout << comment << " Iteration: " << iter << std::endl; 00116 if (x<0) std::cout << x << " "; 00117 else std::cout << " " << x << " "; 00118 if (y<0) std::cout << y << " "; 00119 else std::cout << " " << y << " "; 00120 if (value<0) std::cout << value << " "; 00121 else std::cout << " " << value << " "; 00122 if (limit<0) std::cout << limit << std::endl; 00123 else std::cout << " " << limit << std::endl; 00124 if (verbose>1) { 00125 std::cout << "Press a key and type enter to continue. "; 00126 std::cin >> ch; 00127 } 00128 00129 return gsl_success; 00130 } 00131 00132 /** 00133 \brief Calculate the minimum \c min of \c func w.r.t 'x'. 00134 00135 If this is not overloaded, it attempts to bracket the 00136 minimum using bracket() and then calls min_bkt() with 00137 the newly bracketed minimum. 00138 */ 00139 virtual int min(double &x, double &fmin, param_t &pa, func_t &func) { 00140 if (over_bkt) { 00141 double xl, xr, f, fl, fr; 00142 xl=x*0.9; 00143 xr=x*1.1; 00144 bracket(xl,x,xr,fl,f,fr,pa,func); 00145 return min_bkt(x,xl,xr,fmin,pa,func); 00146 } 00147 set_err_ret("No algorithm provided in minimize::min().", 00148 gsl_nobase); 00149 } 00150 00151 /** \brief Calculate the minimum \c min of \c func with x2 00152 bracketed between x1 and x3 00153 00154 If this is not overloaded, it ignores the bracket and calls min(). 00155 */ 00156 virtual int min_bkt(double &x2, double x1, double x3, double &fmin, 00157 param_t &pa, func_t &func)=0; 00158 00159 /** \brief Calculate the minimum \c min of \c func with 00160 derivative \c dfunc w.r.t 'x'. 00161 00162 If this is not overloaded, it attempts to bracket the 00163 minimum using bracket() and then calls min_bkt_de() with 00164 the newly bracketed minimum. 00165 */ 00166 virtual int min_de(double &x, double &fmin, param_t &pa, func_t &func, 00167 dfunc_t &df) { 00168 if (over_bkt) { 00169 double xl, xr, f, fl, fr; 00170 xl=x*0.9; 00171 xr=x*1.1; 00172 bracket(xl,x,xr,fl,f,fr,pa,func); 00173 return min_bkt(x,xl,xr,fmin,pa,func); 00174 } 00175 set_err_ret("No algorithm provided in minimize::min_de().", 00176 gsl_nobase); 00177 } 00178 00179 /** 00180 \brief Given interval <tt>(ax,bx)</tt>, attempt to bracket a 00181 minimum for function \c func. 00182 00183 Upon success, <tt>fa=func(ax)</tt>, <tt>fb=func(bx)</tt>, and 00184 <tt>fc=func(cx)</tt> with <tt>fb<fa</tt>, <tt>fb<fc</tt> and 00185 <tt>ax<bx<cx</tt>. The initial values of \c cx, \c fa, 00186 \c fb, and \c fc are all ignored. 00187 00188 The number of iterations is controlled by \ref bracket_iter. 00189 00190 \note This routine will fail if the function has the same 00191 value at \c ax, \c bx, and the midpoint <tt>(ax+bx)/2</tt>. 00192 00193 \future Improve this algorithm with the standard golden ratio 00194 method? 00195 */ 00196 virtual int bracket(double &ax, double &bx, double &cx, double &fa, 00197 double &fb, double &fc, param_t &pa, 00198 func_t &func) { 00199 00200 double x=ax, x2=bx, x3=(ax+bx)/2.0; 00201 double fx, fx3, fx2; 00202 int i=0; 00203 00204 bool done=false; 00205 while(done==false && i<bracket_iter) { 00206 func(x,fx,pa); 00207 func(x2,fx2,pa); 00208 func(x3,fx3,pa); 00209 00210 if (verbose>0) { 00211 std::cout << "Function minimize::bracket(), Iteration: " 00212 << i << std::endl; 00213 std::cout << " " << x << " " << x3 << " " << x2 << std::endl; 00214 std::cout << " " << fx << " " << fx3 << " " << fx2 << std::endl; 00215 if (verbose>1) { 00216 char ch; 00217 std::cout << "Press a key and type enter to continue. "; 00218 std::cin >> ch; 00219 } 00220 } 00221 00222 if (fx3>=fx2 && fx3>=fx) { 00223 if (fx2>fx) { 00224 x2=x3; 00225 x3=(x+x2)/2.0; 00226 } else { 00227 x=x3; 00228 x3=(x+x2)/2.0; 00229 } 00230 } else if (fx<=fx3 && fx3<=fx2) { 00231 x3=x; 00232 x=x2-2.0*(x2-x); 00233 } else if (fx3<fx2 && fx3<fx) { 00234 done=true; 00235 ax=x; 00236 bx=x3; 00237 cx=x2; 00238 fa=fx; 00239 fb=fx3; 00240 fc=fx2; 00241 } else { 00242 x3=x2; 00243 x2=x+2.0*(x2-x); 00244 } 00245 i++; 00246 } 00247 00248 if (done==false) { 00249 set_err_ret("Too many iterations in minimize::bracket().", 00250 gsl_emaxiter); 00251 } 00252 00253 return 0; 00254 } 00255 00256 /// Return string denoting type ("minimize") 00257 virtual const char *type() { return "minimize"; } 00258 00259 }; 00260 00261 /** 00262 \brief Constrain \c x to be within \c width 00263 of the value given by \c center 00264 00265 Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$ 00266 \c height, this returns the value \f$ h (1+|x-c-w|/w) \f$ if \f$ 00267 x>c+w \f$ and \f$ h (1+|x-c+w|/w) \f$ if \f$ x<c-w \f$ . The 00268 value near \f$ x=c-w \f$ or \f$ x=c+w \f$ is \f$ h \f$ (the 00269 value of the function exactly at these points is zero) and the 00270 value at \f$ x=c-2w \f$ or \f$ x=c+2w \f$ is \f$ 2 h \f$ . 00271 00272 It is important to note that, for large distances of \c x 00273 from \c center, this only scales linearly. If you are trying to 00274 constrain a function which decreases more than linearly by 00275 making \c x far from \c center, then a minimizer may 00276 ignore this constraint. 00277 */ 00278 inline double constraint(double x, double center, double width, 00279 double height) { 00280 double ret=0.0; 00281 if (x>center+width) { 00282 ret=height*(1.0+fabs(x-center-width)/width); 00283 } else if (x<center-width) { 00284 ret=height*(1.0+fabs(x-center+width)/width); 00285 } 00286 return ret; 00287 } 00288 00289 /** \brief Constrain \c x to be within \c width of the value given 00290 by \c center 00291 00292 Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$ 00293 \c height, \f$ t= \f$ \c tightness, and \f$ \ell= \f$ \c 00294 exp_arg_limit, this returns the value 00295 \f[ 00296 h \left(\frac{x-c}{w}\right)^2 \left[ 00297 1+ e^{t\left(x-c+w\right)\left(c+w-x\right)/w^2} 00298 \right]^{-1} 00299 \f] 00300 00301 This function is continuous and differentiable. Note that if 00302 \f$ x=c \f$ , then the function returns zero. 00303 00304 The exponential is handled gracefully by assuming that anything 00305 smaller than \f$ \exp(-\ell) \f$ is zero. This creates a small 00306 discontinuity which can be removed with the sufficiently large 00307 value of \f$ \ell \f$. 00308 00309 It is important to note that, for large distances of \c x from 00310 \c center, this scales quadratically. If you are trying to 00311 constrain a function which decreases faster than quadratically 00312 by making \c x far from \c center, then a minimizer may ignore 00313 this constraint. 00314 00315 In the limit \f$ t \rightarrow \infty \f$, this function 00316 converges towards the squared value of \ref constraint(), except 00317 exactly at the points \f$ x=c-w \f$ and \f$ x=c+w \f$. 00318 */ 00319 inline double cont_constraint(double x, double center, double width, 00320 double height, double tightness=40.0, 00321 double exp_arg_limit=50.0) { 00322 double ret, wid2=width*width; 00323 double arg=tightness/wid2*(x-center+width)*(center+width-x); 00324 if (arg<-exp_arg_limit) { 00325 ret=(x-center)*(x-center)/wid2; 00326 } else { 00327 ret=(x-center)*(x-center)/wid2/(1.0+exp(arg)); 00328 } 00329 return ret*height; 00330 } 00331 00332 /** 00333 \brief Constrain \c x to be greater than the value given by \c 00334 center 00335 00336 Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$ 00337 \c height, this returns \f$ h(1+|x-c|/w) \f$ if \f$ x<c \f$ and 00338 zero otherwise. The value at \f$ x=c \f$ is \f$ h \f$ , while 00339 the value at \f$ x=c-w \f$ is \f$ 2 h \f$ . 00340 00341 It is important to note that, for large distances of \c x from 00342 \c center, this only scales linearly. If you are trying to 00343 constrain a function which decreases more than linearly by 00344 making \c x far from \c center, then a minimizer may ignore this 00345 constraint. 00346 */ 00347 inline double lower_bound(double x, double center, double width, 00348 double height) { 00349 double ret=0.0; 00350 if (x<center) ret=height*(1.0+fabs(x-center)/width); 00351 return ret; 00352 } 00353 00354 /** 00355 \brief Constrain \c x to be greater than the value given by \c 00356 center 00357 00358 Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$ 00359 \c height, \f$ t= \f$ \c tightness, and \f$ \ell= \f$ \c 00360 exp_arg_limit, this returns \f$ h(c-x+w)/(w+w\exp(t(x-c)/w)) \f$ 00361 and has the advantage of being a continuous and differentiable 00362 function. The value of the function exactly at \f$ x=c \f$ is 00363 \f$ h/2 \f$, but for \f$ x \f$ just below \f$ c \f$ the function 00364 is \f$ h \f$ and just above \f$ c \f$ the function is quite 00365 small. 00366 00367 The exponential is handled gracefully by assuming that anything 00368 smaller than \f$ \exp(-\ell) \f$ is zero. This creates a small 00369 discontinuity which can be removed with the sufficiently large 00370 value of \f$ \ell \f$. 00371 00372 It is important to note that, for large distances of \c x 00373 from \c center, this only scales linearly. If you are trying to 00374 constrain a function which decreases more than linearly by 00375 making \c x far from \c center, then a minimizer may 00376 ingore this constraint. 00377 00378 In the limit \f$ t \rightarrow \infty \f$, this function converges 00379 towards \ref lower_bound(), except exactly at the point 00380 \f$ x=c \f$. 00381 */ 00382 inline double cont_lower_bound(double x, double center, double width, 00383 double height, double tightness=40.0, 00384 double exp_arg_limit=50.0) { 00385 double ret, arg=tightness*(x-center)/width; 00386 if (arg>exp_arg_limit) { 00387 ret=0.0; 00388 } else if (arg<-exp_arg_limit) { 00389 ret=height*(center-x+width)/width; 00390 } else { 00391 ret=height*(center-x+width)/width/(1.0+exp(arg)); 00392 } 00393 return ret; 00394 } 00395 00396 #ifndef DOXYGENP 00397 } 00398 #endif 00399 00400 #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