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 00024 #ifndef O2SCL_GSL_MIN_BRENT_H 00025 #define O2SCL_GSL_MIN_BRENT_H 00026 00027 #include <gsl/gsl_min.h> 00028 #include <o2scl/minimize.h> 00029 00030 #ifndef DOXYGENP 00031 namespace o2scl { 00032 #endif 00033 00034 /** 00035 \brief One-dimensional minimization using Brent's method (GSL) 00036 00037 The minimization in the function min_bkt() is complete when the 00038 bracketed interval is smaller than 00039 \f$ \mathrm{tol} = \mathrm{tolx} + \mathrm{tolf} \cdot 00040 \mathrm{min} \f$, where \f$ \mathrm{min} = 00041 \mathrm{min}(|\mathrm{lower}|,|\mathrm{upper}|) \f$. 00042 00043 Note that this algorithm requires that the initial guess 00044 already brackets the minimum, i.e. \f$ x_1 < x_2 < x_3 \f$, 00045 \f$ f(x_1) > f(x_2) \f$ and \f$ f(x_3) > f(x_2) \f$. This is 00046 different from \ref cern_minimize, where the initial value 00047 of the first parameter to cern_minimize::min_bkt() is 00048 ignored. 00049 */ 00050 template<class param_t, class func_t=funct<param_t> > class gsl_min_brent : 00051 public minimize<param_t,func_t> { 00052 00053 #ifndef DOXYGEN_INTERNAL 00054 00055 protected: 00056 00057 /// The function 00058 func_t *uf; 00059 00060 /// The parameters 00061 param_t *up; 00062 00063 /// \name Temporary storage 00064 //@{ 00065 double d, e, v, w, f_v, f_w; 00066 //@} 00067 00068 /// Compute the function values at the various points 00069 int compute_f_values(func_t &func, double xminimum, double *fminimum, 00070 double xlower, double *flower, double xupper, 00071 double *fupper, param_t &pa) { 00072 00073 func(xlower,*flower,pa); 00074 func(xupper,*fupper,pa); 00075 func(xminimum,*fminimum,pa); 00076 00077 return gsl_success; 00078 } 00079 00080 #endif 00081 00082 public: 00083 00084 /// Location of minimum 00085 double x_minimum; 00086 /// Lower bound 00087 double x_lower; 00088 /// Upper mound 00089 double x_upper; 00090 /// Minimum value 00091 double f_minimum; 00092 /// Value at lower bound 00093 double f_lower; 00094 /// Value at upper bound 00095 double f_upper; 00096 00097 gsl_min_brent() { 00098 this->over_bkt=true; 00099 } 00100 00101 virtual ~gsl_min_brent() {} 00102 00103 /// Set the function and the initial brackeing interval 00104 int set(func_t &func, double xmin, double lower, double upper, 00105 param_t &pa) { 00106 00107 double fmin, fl, fu; 00108 int status=compute_f_values(func,lower,&fl,xmin,&fmin,upper,&fu,pa); 00109 00110 status=set_with_values(func,xmin,fmin,lower,fl,upper,fu,pa); 00111 00112 return status; 00113 } 00114 00115 /** 00116 \brief Set the function, the initial brackeing interval, 00117 and the corresponding function values. 00118 */ 00119 int set_with_values(func_t &func, double xmin, double fmin, 00120 double lower, double fl, double upper, 00121 double fu, param_t &pa) { 00122 00123 if (lower > upper) { 00124 std::string tmp=((std::string)"Invalid interval (lower > upper) ")+ 00125 "in gsl_min_brent::set_with_values()."; 00126 set_err_ret(tmp.c_str(),gsl_einval); 00127 } 00128 if (xmin>=upper || xmin<=lower) { 00129 std::string tmp=((std::string)"'xmin' was not inside interval ")+ 00130 "in gsl_min_brent::set_with_values()."; 00131 set_err_ret(tmp.c_str(),gsl_einval); 00132 } 00133 if (fmin>= fl || fmin>=fu) { 00134 std::string tmp=((std::string)"Endpoints don't enclose minimum ")+ 00135 "in gsl_min_brent::set_with_values()."; 00136 set_err_ret(tmp.c_str(),gsl_einval); 00137 } 00138 00139 x_lower=lower; 00140 x_minimum=xmin; 00141 x_upper=upper; 00142 f_lower=fl; 00143 f_minimum=fmin; 00144 f_upper=fu; 00145 00146 uf=&func; 00147 up=&pa; 00148 00149 /* golden=(3-sqrt(5))/2 */ 00150 const double golden=0.3819660; 00151 00152 v=x_lower+golden*(x_upper-x_lower); 00153 w=v; 00154 d=0; 00155 e=0; 00156 func(v,f_v,pa); 00157 f_w=f_v; 00158 00159 return gsl_success; 00160 } 00161 00162 /// Perform an iteration 00163 int iterate() { 00164 00165 const double x_left= x_lower; 00166 const double x_right= x_upper; 00167 00168 const double z=x_minimum; 00169 double u, f_u; 00170 const double f_z=f_minimum; 00171 00172 /* golden=(3-sqrt(5))/2 */ 00173 const double golden=0.3819660; 00174 00175 const double w_lower=(z-x_left); 00176 const double w_upper=(x_right-z); 00177 00178 const double tolerance= GSL_SQRT_DBL_EPSILON*fabs (z); 00179 00180 double p=0, q=0, r=0; 00181 00182 const double midpoint=0.5*(x_left+x_right); 00183 00184 if (fabs (e) > tolerance) { 00185 /* fit parabola */ 00186 00187 r=(z-w)*(f_z-f_v); 00188 q=(z-v)*(f_z-f_w); 00189 p=(z-v)*q-(z-w)*r; 00190 q=2*(q-r); 00191 00192 if (q > 0) { 00193 p=-p; 00194 } else { 00195 q=-q; 00196 } 00197 00198 r=e; 00199 e=d; 00200 } 00201 00202 if (fabs (p) < fabs (0.5*q*r) && p < q*w_lower && 00203 p < q*w_upper) { 00204 00205 double t2=2*tolerance; 00206 00207 d=p / q; 00208 u=z+d; 00209 00210 if ((u-x_left) < t2 || (x_right-u) < t2) 00211 { 00212 d=(z < midpoint) ? tolerance : -tolerance ; 00213 } 00214 } else { 00215 e=(z < midpoint) ? x_right-z : -(z-x_left) ; 00216 d=golden*e; 00217 } 00218 00219 00220 if (fabs (d) >= tolerance) { 00221 u=z+d; 00222 } else { 00223 u=z+((d > 0) ? tolerance : -tolerance) ; 00224 } 00225 00226 (*uf)(u,f_u,*up); 00227 00228 // This is the old version. Will update to new GSL 00229 // version as soon as the bugs are worked out. 00230 00231 if (f_u > f_z) { 00232 00233 if (u < z) { 00234 x_lower=u; 00235 f_lower=f_u; 00236 return gsl_success; 00237 } else { 00238 x_upper=u; 00239 f_upper=f_u; 00240 return gsl_success; 00241 } 00242 00243 } else if (f_u < f_z) { 00244 00245 if (u < z) { 00246 x_upper=z; 00247 f_upper=f_z; 00248 } else { 00249 x_lower=z; 00250 f_lower=f_z; 00251 } 00252 00253 v=w; 00254 w=z; 00255 f_v=f_w; 00256 f_w=f_z; 00257 x_minimum=u; 00258 f_minimum=f_u; 00259 00260 return gsl_success; 00261 00262 } else if (f_u <= f_w || w == z) { 00263 00264 v=w; 00265 f_v=f_w; 00266 w=u; 00267 f_w=f_u; 00268 return gsl_success; 00269 00270 } else if (f_u <= f_v || v == z || v == w) { 00271 00272 v=u; 00273 f_v=f_u; 00274 return gsl_success; 00275 00276 } else { 00277 00278 set_err_ret("Iteration failed in gsl_min_brent::iterate().", 00279 gsl_failure); 00280 00281 } 00282 00283 return 0; 00284 00285 /* 00286 00287 if (f_u<=f_z) { 00288 if (u<z) { 00289 x_upper=z; 00290 f_upper=f_z; 00291 } else { 00292 x_lower=z; 00293 f_lower=f_z; 00294 } 00295 v=w; 00296 f_v=f_w; 00297 w=z; 00298 f_w=f_z; 00299 return gsl_success; 00300 } else { 00301 if (u<z) { 00302 x_lower=u; 00303 f_lower=f_u; 00304 return gsl_success; 00305 } else { 00306 x_upper=u; 00307 f_upper=f_u; 00308 return gsl_success; 00309 } 00310 } 00311 */ 00312 } 00313 00314 /** \brief Calculate the minimum \c fmin of \c func 00315 with \c x2 bracketed between \c x1 and \c x3. 00316 00317 Note that this algorithm requires that the initial guess 00318 already brackets the minimum, i.e. \f$ x_1 < x_2 < x_3 \f$, 00319 \f$ f(x_1) > f(x_2) \f$ and \f$ f(x_3) > f(x_2) \f$. This is 00320 different from \ref cern_minimize, where the initial value 00321 of the first parameter to cern_minimize::min_bkt() is 00322 ignored. 00323 */ 00324 virtual int min_bkt(double &x2, double x1, double x3, double &fmin, 00325 param_t &pa, func_t &func) { 00326 00327 int status, iter=0; 00328 00329 int rx=set(func,x2,x1,x3,pa); 00330 if (rx!=0) { 00331 add_err_ret("Function set() failed in gsl_min_brent::min_bkt().", 00332 rx); 00333 } 00334 00335 do { 00336 iter++; 00337 status=iterate(); 00338 x2=x_minimum; 00339 if (status) { 00340 add_err("Function iterate() failed in gsl_min_brent::min_bkt().", 00341 status); 00342 break; 00343 } 00344 00345 status=gsl_min_test_interval(x_lower,x_upper,this->tolx,this->tolf); 00346 if (status) { 00347 std::string s="Function gsl_min_test_interval() failed in "; 00348 s+="gsl_min_brent::min_bkt()."; 00349 add_err(s.c_str(),status); 00350 } 00351 00352 if (this->verbose>0) { 00353 if (x_lower*x_upper<0.0) { 00354 if (x_lower<x_upper) { 00355 print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper)- 00356 this->tolf*x_lower,this->tolx); 00357 } else { 00358 print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper)- 00359 this->tolf*x_upper,this->tolx); 00360 } 00361 } else { 00362 print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper),this->tolx); 00363 } 00364 } 00365 00366 } while (status == gsl_continue && iter<this->ntrial); 00367 00368 this->last_ntrial=iter; 00369 fmin=f_minimum; 00370 00371 return status; 00372 } 00373 00374 /// Return string denoting type ("gsl_min_brent") 00375 virtual const char *type() { return "gsl_min_brent"; } 00376 00377 }; 00378 00379 #ifndef DOXYGENP 00380 } 00381 #endif 00382 00383 #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