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