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