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