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 00033 #ifndef DOXYGENP 00034 namespace o2scl { 00035 #endif 00036 00037 /** 00038 \brief One-dimensional minimization [abstract base] 00039 */ 00040 template<class param_t, class func_t, class dfunc_t=func_t> 00041 class minimize { 00042 00043 public: 00044 00045 minimize() { 00046 verbose=0; 00047 ntrial=100; 00048 tolf=1.0e-4; 00049 tolx=1.0e-4; 00050 last_ntrial=0; 00051 bracket_iter=20; 00052 err_nonconv=true; 00053 last_conv=0; 00054 } 00055 00056 virtual ~minimize() {} 00057 00058 /// Output control 00059 int verbose; 00060 00061 /// Maximum number of iterations 00062 int ntrial; 00063 00064 /// The tolerance for the minimum function value 00065 double tolf; 00066 00067 /// The tolerance for the location of the minimum 00068 double tolx; 00069 00070 /// The number of iterations for in the most recent minimization 00071 int last_ntrial; 00072 00073 /** 00074 \brief The number of iterations for automatically 00075 bracketing a minimum (default 20) 00076 */ 00077 int bracket_iter; 00078 00079 /// If true, call the error handler if the routine does not "converge" 00080 bool err_nonconv; 00081 00082 /** \brief Zero if last call to min(), min_bkt(), or 00083 min_de() converged. 00084 00085 This is particularly useful if err_nonconv is false to test 00086 if the last call to min(), min_bkt(), or min_de() 00087 converged. 00088 */ 00089 int last_conv; 00090 00091 /** 00092 \brief Print out iteration information. 00093 00094 Depending on the value of the variable \ref verbose, this 00095 prints out the iteration information. If verbose=0, then no 00096 information is printed, while if verbose>1, then after each 00097 iteration, the present values of x and y are output to 00098 std::cout along with the iteration number. If verbose>=2 then 00099 each iteration waits for a character. 00100 */ 00101 virtual int print_iter(double x, double y, int iter, double value=0.0, 00102 double limit=0.0, std::string comment="") { 00103 00104 if (verbose<=0) return gsl_success; 00105 00106 char ch; 00107 00108 std::cout << comment << " Iteration: " << iter << std::endl; 00109 if (x<0) std::cout << x << " "; 00110 else std::cout << " " << x << " "; 00111 if (y<0) std::cout << y << " "; 00112 else std::cout << " " << y << " "; 00113 if (value<0) std::cout << value << " "; 00114 else std::cout << " " << value << " "; 00115 if (limit<0) std::cout << limit << std::endl; 00116 else std::cout << " " << limit << std::endl; 00117 if (verbose>1) { 00118 std::cout << "Press a key and type enter to continue. "; 00119 std::cin >> ch; 00120 } 00121 00122 return gsl_success; 00123 } 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, param_t &pa, 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 param_t &pa, 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, param_t &pa, func_t &func, 00150 dfunc_t &df)=0; 00151 00152 /** 00153 \brief Given interval <tt>(ax,bx)</tt>, attempt to bracket a 00154 minimum for function \c func. 00155 00156 Upon success, <tt>fa=func(ax)</tt>, <tt>fb=func(bx)</tt>, and 00157 <tt>fc=func(cx)</tt> with <tt>fb<fa</tt>, <tt>fb<fc</tt> and 00158 <tt>ax<bx<cx</tt>. The initial values of \c cx, \c fa, 00159 \c fb, and \c fc are all ignored. 00160 00161 The number of iterations is controlled by \ref bracket_iter. 00162 00163 \note This routine will fail if the function has the same 00164 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 (fx2>fx) { 00197 x2=x3; 00198 x3=(x+x2)/2.0; 00199 } else { 00200 x=x3; 00201 x3=(x+x2)/2.0; 00202 } 00203 } else if (fx<=fx3 && fx3<=fx2) { 00204 x3=x; 00205 x=x2-2.0*(x2-x); 00206 } else if (fx3<fx2 && fx3<fx) { 00207 done=true; 00208 ax=x; 00209 bx=x3; 00210 cx=x2; 00211 fa=fx; 00212 fb=fx3; 00213 fc=fx2; 00214 } else { 00215 x3=x2; 00216 x2=x+2.0*(x2-x); 00217 } 00218 i++; 00219 } 00220 00221 if (done==false) { 00222 O2SCL_ERR_RET("Too many iterations in minimize::bracket().", 00223 gsl_emaxiter); 00224 } 00225 00226 return 0; 00227 } 00228 00229 /// Return string denoting type ("minimize") 00230 virtual const char *type() { return "minimize"; } 00231 00232 }; 00233 00234 /** 00235 \brief One-dimensional bracketing minimization [abstract base] 00236 */ 00237 template<class param_t, class func_t, class dfunc_t=func_t> 00238 class minimize_bkt : public minimize<param_t,func_t,dfunc_t> { 00239 00240 public: 00241 00242 minimize_bkt() { 00243 bracket_iter=20; 00244 } 00245 00246 virtual ~minimize_bkt() {} 00247 00248 /** 00249 \brief The number of iterations for automatically 00250 bracketing a minimum (default 20) 00251 */ 00252 int bracket_iter; 00253 00254 /** 00255 \brief Calculate the minimum \c min of \c func w.r.t 'x'. 00256 00257 If this is not overloaded, it attempts to bracket the 00258 minimum using bracket() and then calls min_bkt() with 00259 the newly bracketed minimum. 00260 */ 00261 virtual int min(double &x, double &fmin, param_t &pa, func_t &func) { 00262 double xl, xr, f, fl, fr; 00263 xl=x*0.9; 00264 xr=x*1.1; 00265 if (bracket(xl,x,xr,fl,f,fr,pa,func)!=0) { 00266 O2SCL_CONV_RET("Failed to bracket in min().",gsl_efailed, 00267 this->err_nonconv); 00268 } 00269 return min_bkt(x,xl,xr,fmin,pa,func); 00270 } 00271 00272 /** \brief Calculate the minimum \c min of \c func with x2 00273 bracketed between x1 and x3 00274 00275 If this is not overloaded, it ignores the bracket and calls min(). 00276 */ 00277 virtual int min_bkt(double &x2, double x1, double x3, double &fmin, 00278 param_t &pa, func_t &func)=0; 00279 00280 /** \brief Calculate the minimum \c min of \c func with 00281 derivative \c dfunc w.r.t 'x'. 00282 00283 If this is not overloaded, it attempts to bracket the 00284 minimum using bracket() and then calls min_bkt_de() with 00285 the newly bracketed minimum. 00286 */ 00287 virtual int min_de(double &x, double &fmin, param_t &pa, func_t &func, 00288 dfunc_t &df) { 00289 double xl, xr, f, fl, fr; 00290 xl=x*0.9; 00291 xr=x*1.1; 00292 if (bracket(xl,x,xr,fl,f,fr,pa,func)!=0) { 00293 O2SCL_CONV_RET("Failed to bracket in min_de().",gsl_efailed, 00294 this->err_nonconv); 00295 } 00296 return min_bkt(x,xl,xr,fmin,pa,func); 00297 } 00298 00299 /** 00300 \brief Given interval <tt>(ax,bx)</tt>, attempt to bracket a 00301 minimum for function \c func. 00302 00303 Upon success, <tt>fa=func(ax)</tt>, <tt>fb=func(bx)</tt>, and 00304 <tt>fc=func(cx)</tt> with <tt>fb<fa</tt>, <tt>fb<fc</tt> and 00305 <tt>ax<bx<cx</tt>. The initial values of \c cx, \c fa, 00306 \c fb, and \c fc are all ignored. 00307 00308 The number of iterations is controlled by \ref bracket_iter. 00309 00310 \note This routine will fail if the function has the same 00311 value at \c ax, \c bx, and the midpoint <tt>(ax+bx)/2</tt>. 00312 00313 \future Improve this algorithm with the standard golden ratio 00314 method? 00315 */ 00316 virtual int bracket(double &ax, double &bx, double &cx, double &fa, 00317 double &fb, double &fc, param_t &pa, 00318 func_t &func) { 00319 00320 double x=ax, x2=bx, x3=(ax+bx)/2.0; 00321 double fx, fx3, fx2; 00322 int i=0; 00323 00324 bool done=false; 00325 while(done==false && i<bracket_iter) { 00326 func(x,fx,pa); 00327 func(x2,fx2,pa); 00328 func(x3,fx3,pa); 00329 00330 if (this->verbose>0) { 00331 std::cout << "Function minimize::bracket(), Iteration: " 00332 << i << std::endl; 00333 std::cout << " " << x << " " << x3 << " " << x2 << std::endl; 00334 std::cout << " " << fx << " " << fx3 << " " << fx2 << std::endl; 00335 if (this->verbose>1) { 00336 char ch; 00337 std::cout << "Press a key and type enter to continue. "; 00338 std::cin >> ch; 00339 } 00340 } 00341 00342 if (fx3>=fx2 && fx3>=fx) { 00343 if (fx2>fx) { 00344 x2=x3; 00345 x3=(x+x2)/2.0; 00346 } else { 00347 x=x3; 00348 x3=(x+x2)/2.0; 00349 } 00350 } else if (fx<=fx3 && fx3<=fx2) { 00351 x3=x; 00352 x=x2-2.0*(x2-x); 00353 } else if (fx3<fx2 && fx3<fx) { 00354 done=true; 00355 ax=x; 00356 bx=x3; 00357 cx=x2; 00358 fa=fx; 00359 fb=fx3; 00360 fc=fx2; 00361 } else { 00362 x3=x2; 00363 x2=x+2.0*(x2-x); 00364 } 00365 i++; 00366 } 00367 00368 if (done==false) { 00369 O2SCL_ERR_RET("Too many iterations in minimize::bracket().", 00370 gsl_emaxiter); 00371 } 00372 00373 return 0; 00374 } 00375 00376 /// Return string denoting type ("minimize_bkt") 00377 virtual const char *type() { return "minimize_bkt"; } 00378 00379 }; 00380 00381 /** 00382 \brief One-dimensional minimization using derivatives [abstract base] 00383 00384 At the moment there are no minimizers of this type implemented in 00385 \o2. 00386 */ 00387 template<class param_t, class func_t, class dfunc_t=func_t> 00388 class minimize_de : public minimize<param_t,func_t,dfunc_t> { 00389 00390 public: 00391 00392 minimize_de() { 00393 } 00394 00395 virtual ~minimize_de() {} 00396 00397 /** 00398 \brief Calculate the minimum \c min of \c func w.r.t 'x'. 00399 00400 If this is not overloaded, it attempts to bracket the 00401 minimum using bracket() and then calls min_bkt() with 00402 the newly bracketed minimum. 00403 */ 00404 virtual int min(double &x, double &fmin, param_t &pa, func_t &func) { 00405 O2SCL_ERR_RET("Function min() not implemented.",gsl_eunimpl); 00406 } 00407 00408 /** \brief Calculate the minimum \c min of \c func with x2 00409 bracketed between x1 and x3 00410 00411 If this is not overloaded, it ignores the bracket and calls min(). 00412 */ 00413 virtual int min_bkt(double &x2, double x1, double x3, double &fmin, 00414 param_t &pa, func_t &func) { 00415 O2SCL_ERR_RET("Function min_bkt() not implemented.",gsl_eunimpl); 00416 } 00417 00418 /** \brief Calculate the minimum \c min of \c func with 00419 derivative \c dfunc w.r.t 'x'. 00420 00421 If this is not overloaded, it attempts to bracket the 00422 minimum using bracket() and then calls min_bkt_de() with 00423 the newly bracketed minimum. 00424 */ 00425 virtual int min_de(double &x, double &fmin, param_t &pa, func_t &func, 00426 dfunc_t &df)=0; 00427 00428 /// Return string denoting type ("minimize_de") 00429 virtual const char *type() { return "minimize_de"; } 00430 00431 }; 00432 00433 /** 00434 \brief Constrain \c x to be within \c width 00435 of the value given by \c center 00436 00437 Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$ 00438 \c height, this returns the value \f$ h (1+|x-c-w|/w) \f$ if \f$ 00439 x>c+w \f$ and \f$ h (1+|x-c+w|/w) \f$ if \f$ x<c-w \f$ . The 00440 value near \f$ x=c-w \f$ or \f$ x=c+w \f$ is \f$ h \f$ (the 00441 value of the function exactly at these points is zero) and the 00442 value at \f$ x=c-2w \f$ or \f$ x=c+2w \f$ is \f$ 2 h \f$ . 00443 00444 It is important to note that, for large distances of \c x 00445 from \c center, this only scales linearly. If you are trying to 00446 constrain a function which decreases more than linearly by 00447 making \c x far from \c center, then a minimizer may 00448 ignore this constraint. 00449 */ 00450 inline double constraint(double x, double center, double width, 00451 double height) { 00452 double ret=0.0; 00453 if (x>center+width) { 00454 ret=height*(1.0+fabs(x-center-width)/width); 00455 } else if (x<center-width) { 00456 ret=height*(1.0+fabs(x-center+width)/width); 00457 } 00458 return ret; 00459 } 00460 00461 /** \brief Constrain \c x to be within \c width of the value given 00462 by \c center 00463 00464 Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$ 00465 \c height, \f$ t= \f$ \c tightness, and \f$ \ell= \f$ \c 00466 exp_arg_limit, this returns the value 00467 \f[ 00468 h \left(\frac{x-c}{w}\right)^2 \left[ 00469 1+ e^{t\left(x-c+w\right)\left(c+w-x\right)/w^2} 00470 \right]^{-1} 00471 \f] 00472 00473 This function is continuous and differentiable. Note that if 00474 \f$ x=c \f$ , then the function returns zero. 00475 00476 The exponential is handled gracefully by assuming that anything 00477 smaller than \f$ \exp(-\ell) \f$ is zero. This creates a small 00478 discontinuity which can be removed with the sufficiently large 00479 value of \f$ \ell \f$. 00480 00481 It is important to note that, for large distances of \c x from 00482 \c center, this scales quadratically. If you are trying to 00483 constrain a function which decreases faster than quadratically 00484 by making \c x far from \c center, then a minimizer may ignore 00485 this constraint. 00486 00487 In the limit \f$ t \rightarrow \infty \f$, this function 00488 converges towards the squared value of \ref constraint(), except 00489 exactly at the points \f$ x=c-w \f$ and \f$ x=c+w \f$. 00490 */ 00491 inline double cont_constraint(double x, double center, double width, 00492 double height, double tightness=40.0, 00493 double exp_arg_limit=50.0) { 00494 double ret, wid2=width*width; 00495 double arg=tightness/wid2*(x-center+width)*(center+width-x); 00496 if (arg<-exp_arg_limit) { 00497 ret=(x-center)*(x-center)/wid2; 00498 } else { 00499 ret=(x-center)*(x-center)/wid2/(1.0+exp(arg)); 00500 } 00501 return ret*height; 00502 } 00503 00504 /** 00505 \brief Constrain \c x to be greater than the value given by \c 00506 center 00507 00508 Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$ 00509 \c height, this returns \f$ h(1+|x-c|/w) \f$ if \f$ x<c \f$ and 00510 zero otherwise. The value at \f$ x=c \f$ is \f$ h \f$ , while 00511 the value at \f$ x=c-w \f$ is \f$ 2 h \f$ . 00512 00513 It is important to note that, for large distances of \c x from 00514 \c center, this only scales linearly. If you are trying to 00515 constrain a function which decreases more than linearly by 00516 making \c x far from \c center, then a minimizer may ignore this 00517 constraint. 00518 */ 00519 inline double lower_bound(double x, double center, double width, 00520 double height) { 00521 double ret=0.0; 00522 if (x<center) ret=height*(1.0+fabs(x-center)/width); 00523 return ret; 00524 } 00525 00526 /** 00527 \brief Constrain \c x to be greater than the value given by \c 00528 center 00529 00530 Defining \f$ c= \f$ \c center, \f$ w= \f$ \c width, \f$ h= \f$ 00531 \c height, \f$ t= \f$ \c tightness, and \f$ \ell= \f$ \c 00532 exp_arg_limit, this returns \f$ h(c-x+w)/(w+w\exp(t(x-c)/w)) \f$ 00533 and has the advantage of being a continuous and differentiable 00534 function. The value of the function exactly at \f$ x=c \f$ is 00535 \f$ h/2 \f$, but for \f$ x \f$ just below \f$ c \f$ the function 00536 is \f$ h \f$ and just above \f$ c \f$ the function is quite 00537 small. 00538 00539 The exponential is handled gracefully by assuming that anything 00540 smaller than \f$ \exp(-\ell) \f$ is zero. This creates a small 00541 discontinuity which can be removed with the sufficiently large 00542 value of \f$ \ell \f$. 00543 00544 It is important to note that, for large distances of \c x 00545 from \c center, this only scales linearly. If you are trying to 00546 constrain a function which decreases more than linearly by 00547 making \c x far from \c center, then a minimizer may 00548 ingore this constraint. 00549 00550 In the limit \f$ t \rightarrow \infty \f$, this function converges 00551 towards \ref lower_bound(), except exactly at the point 00552 \f$ x=c \f$. 00553 */ 00554 inline double cont_lower_bound(double x, double center, double width, 00555 double height, double tightness=40.0, 00556 double exp_arg_limit=50.0) { 00557 double ret, arg=tightness*(x-center)/width; 00558 if (arg>exp_arg_limit) { 00559 ret=0.0; 00560 } else if (arg<-exp_arg_limit) { 00561 ret=height*(center-x+width)/width; 00562 } else { 00563 ret=height*(center-x+width)/width/(1.0+exp(arg)); 00564 } 00565 return ret; 00566 } 00567 00568 #ifndef DOXYGENP 00569 } 00570 #endif 00571 00572 #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