![]() |
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 /* 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 /** \brief One-dimensional minimization using Brent's method (GSL) 00053 00054 The minimization in the function min_bkt() is complete when the 00055 bracketed interval is smaller than 00056 \f$ \mathrm{tol} = \mathrm{tol\_abs} + \mathrm{tol\_rel} \cdot 00057 \mathrm{min} \f$, where \f$ \mathrm{min} = 00058 \mathrm{min}(|\mathrm{lower}|,|\mathrm{upper}|) \f$. 00059 00060 Note that this algorithm requires that the initial guess 00061 already brackets the minimum, i.e. \f$ x_1 < x_2 < x_3 \f$, 00062 \f$ f(x_1) > f(x_2) \f$ and \f$ f(x_3) > f(x_2) \f$. This is 00063 different from \ref cern_minimize, where the initial value 00064 of the first parameter to cern_minimize::min_bkt() is 00065 ignored. 00066 00067 The set functions throw an error if the initial bracket is not 00068 correctly specified. The function \ref iterate() never calls the 00069 error handler. The function min_bkt() calls the error handler if 00070 the tolerances are negative or if the number of iterations is 00071 insufficient to give the specified tolerance. 00072 00073 Setting \ref minimize::err_nonconv to false will force 00074 min_bkt() not to call the error handler when the number of 00075 iterations is insufficient. 00076 00077 Note that if there are more than 1 local minima in the specified 00078 interval, there is no guarantee that this method will find the 00079 global minimum. 00080 00081 See also \ref gsl_root_brent for a similar algorithm 00082 applied as a solver rather than a minimizer. 00083 00084 \note There was a bug in this minimizer which was fixed for 00085 GSL-1.11 which has also been fixed here. 00086 */ 00087 template<class func_t=funct> class gsl_min_brent : 00088 public minimize_bkt<func_t> { 00089 00090 #ifndef DOXYGEN_INTERNAL 00091 00092 protected: 00093 00094 /// The function 00095 func_t *uf; 00096 00097 /// \name Temporary storage 00098 //@{ 00099 double d, e, v, w, f_v, f_w; 00100 //@} 00101 00102 /// Compute the function values at the various points 00103 int compute_f_values(func_t &func, double xminimum, double *fminimum, 00104 double xlower, double *flower, double xupper, 00105 double *fupper) { 00106 00107 *flower=func(xlower); 00108 *fupper=func(xupper); 00109 *fminimum=func(xminimum); 00110 00111 return gsl_success; 00112 } 00113 00114 #endif 00115 00116 public: 00117 00118 /// Location of minimum 00119 double x_minimum; 00120 /// Lower bound 00121 double x_lower; 00122 /// Upper bound 00123 double x_upper; 00124 /// Minimum value 00125 double f_minimum; 00126 /// Value at lower bound 00127 double f_lower; 00128 /// Value at upper bound 00129 double f_upper; 00130 00131 gsl_min_brent() { 00132 } 00133 00134 virtual ~gsl_min_brent() {} 00135 00136 /// Set the function and the initial bracketing interval 00137 int set(func_t &func, double xmin, double lower, double upper) { 00138 00139 double fmin, fl, fu; 00140 int status=compute_f_values(func,lower,&fl,xmin,&fmin,upper,&fu); 00141 00142 status=set_with_values(func,xmin,fmin,lower,fl,upper,fu); 00143 00144 return status; 00145 } 00146 00147 /** \brief Set the function, the initial bracketing interval, 00148 and the corresponding function values. 00149 */ 00150 int set_with_values(func_t &func, double xmin, double fmin, 00151 double lower, double fl, double upper, 00152 double fu) { 00153 00154 if (lower > upper) { 00155 std::string tmp=((std::string)"Invalid interval (lower > upper) ")+ 00156 "in gsl_min_brent::set_with_values()."; 00157 O2SCL_ERR_RET(tmp.c_str(),gsl_einval); 00158 } 00159 if (xmin>=upper || xmin<=lower) { 00160 std::string tmp=((std::string)"'xmin' was not inside interval ")+ 00161 "in gsl_min_brent::set_with_values()."; 00162 O2SCL_ERR_RET(tmp.c_str(),gsl_einval); 00163 } 00164 if (fmin>=fl || fmin>=fu) { 00165 std::string tmp=((std::string)"Endpoints don't enclose minimum ")+ 00166 "in gsl_min_brent::set_with_values()."; 00167 O2SCL_ERR_RET(tmp.c_str(),gsl_einval); 00168 } 00169 00170 x_lower=lower; 00171 x_minimum=xmin; 00172 x_upper=upper; 00173 f_lower=fl; 00174 f_minimum=fmin; 00175 f_upper=fu; 00176 00177 uf=&func; 00178 00179 /* golden=(3-sqrt(5))/2 */ 00180 const double golden=0.3819660; 00181 00182 v=x_lower+golden*(x_upper-x_lower); 00183 w=v; 00184 d=0; 00185 e=0; 00186 f_v=func(v); 00187 f_w=f_v; 00188 00189 return gsl_success; 00190 } 00191 00192 /** \brief Perform an iteration 00193 00194 \future It looks like x_left and x_right can be removed. Also, 00195 it would be great to replace the one-letter variable names 00196 with something more meaningful. 00197 */ 00198 int iterate() { 00199 00200 const double x_left=x_lower; 00201 const double x_right=x_upper; 00202 00203 const double z=x_minimum; 00204 double u, f_u; 00205 const double f_z=f_minimum; 00206 00207 /* golden=(3-sqrt(5))/2 */ 00208 const double golden=0.3819660; 00209 00210 const double w_lower=(z-x_left); 00211 const double w_upper=(x_right-z); 00212 00213 const double tolerance=GSL_SQRT_DBL_EPSILON*fabs(z); 00214 00215 double p=0, q=0, r=0; 00216 00217 const double midpoint=0.5*(x_left+x_right); 00218 00219 if (fabs (e) > tolerance) { 00220 /* fit parabola */ 00221 00222 r=(z-w)*(f_z-f_v); 00223 q=(z-v)*(f_z-f_w); 00224 p=(z-v)*q-(z-w)*r; 00225 q=2*(q-r); 00226 00227 if (q > 0) { 00228 p=-p; 00229 } else { 00230 q=-q; 00231 } 00232 00233 r=e; 00234 e=d; 00235 } 00236 00237 if (fabs (p) < fabs (0.5*q*r) && p < q*w_lower && 00238 p < q*w_upper) { 00239 00240 double t2=2*tolerance; 00241 00242 d=p / q; 00243 u=z+d; 00244 00245 if ((u-x_left) < t2 || (x_right-u) < t2) { 00246 d=(z < midpoint) ? tolerance : -tolerance ; 00247 } 00248 00249 } else { 00250 00251 e=(z < midpoint) ? x_right-z : -(z-x_left) ; 00252 d=golden*e; 00253 00254 } 00255 00256 00257 if (fabs (d) >= tolerance) { 00258 u=z+d; 00259 } else { 00260 u=z+((d > 0) ? tolerance : -tolerance); 00261 } 00262 00263 f_u=(*uf)(u); 00264 00265 if (f_u<=f_z) { 00266 00267 if (u<z) { 00268 00269 x_upper=z; 00270 f_upper=f_z; 00271 00272 } else { 00273 00274 x_lower=z; 00275 f_lower=f_z; 00276 00277 } 00278 00279 v=w; 00280 f_v=f_w; 00281 w=z; 00282 f_w=f_z; 00283 x_minimum=u; 00284 f_minimum=f_u; 00285 00286 return gsl_success; 00287 00288 } else { 00289 00290 if (u<z) { 00291 00292 x_lower=u; 00293 f_lower=f_u; 00294 00295 } else { 00296 00297 x_upper=u; 00298 f_upper=f_u; 00299 00300 } 00301 00302 if (f_u<=f_w || w==z) { 00303 00304 v=w; 00305 f_v=f_w; 00306 w=u; 00307 f_w=f_u; 00308 return gsl_success; 00309 00310 } else if (f_u<=f_v || v==z || v==w) { 00311 00312 v=u; 00313 f_v=f_u; 00314 return gsl_success; 00315 } 00316 00317 } 00318 00319 return gsl_success; 00320 } 00321 00322 /** \brief Calculate the minimum \c fmin of \c func 00323 with \c x2 bracketed between \c x1 and \c x3. 00324 00325 Note that this algorithm requires that the initial guess 00326 already brackets the minimum, i.e. \f$ x_1 < x_2 < x_3 \f$, 00327 \f$ f(x_1) > f(x_2) \f$ and \f$ f(x_3) > f(x_2) \f$. This is 00328 different from \ref cern_minimize, where the initial value 00329 of the first parameter to cern_minimize::min_bkt() is 00330 ignored. 00331 */ 00332 virtual int min_bkt(double &x2, double x1, double x3, double &fmin, 00333 func_t &func) { 00334 00335 int status, iter=0; 00336 00337 this->last_conv=0; 00338 00339 int rx=set(func,x2,x1,x3); 00340 if (rx!=0) { 00341 O2SCL_ERR2_RET("Function set() failed in ", 00342 "gsl_min_brent::min_bkt().",rx); 00343 } 00344 00345 do { 00346 iter++; 00347 status=iterate(); 00348 x2=x_minimum; 00349 if (status) { 00350 // This should never actually happen in the current 00351 // version, but we retain it for now 00352 this->last_conv=gsl_efailed; 00353 O2SCL_CONV2_RET("Function iterate() failed in gsl_min_", 00354 "brent::min_bkt().",status,this->err_nonconv); 00355 break; 00356 } 00357 00358 status=gsl_min_test_interval(x_lower,x_upper,this->tol_abs, 00359 this->tol_rel); 00360 if (status>0) { 00361 // The function gsl_min_test_interval() fails if the 00362 // tolerances are negative or if the lower bound is larger 00363 // than the upper bound 00364 std::string s="Function gsl_min_test_interval() failed in "; 00365 s+="gsl_min_brent::min_bkt()."; 00366 O2SCL_ERR(s.c_str(),status); 00367 } 00368 00369 if (this->verbose>0) { 00370 if (x_lower*x_upper<0.0) { 00371 if (x_lower<x_upper) { 00372 print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper)- 00373 this->tol_rel*x_lower,this->tol_abs,"gsl_min_brent"); 00374 } else { 00375 print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper)- 00376 this->tol_rel*x_upper,this->tol_abs,"gsl_min_brent"); 00377 } 00378 } else { 00379 print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper),this->tol_abs, 00380 "gsl_min_brent"); 00381 } 00382 } 00383 00384 } while (status == gsl_continue && iter<this->ntrial); 00385 00386 if (iter>=this->ntrial) { 00387 this->last_conv=gsl_emaxiter; 00388 O2SCL_CONV2_RET("Exceeded maximum number of ", 00389 "iterations in gsl_min_brent::min_bkt().", 00390 o2scl::gsl_emaxiter,this->err_nonconv); 00391 } 00392 00393 this->last_ntrial=iter; 00394 fmin=f_minimum; 00395 00396 return status; 00397 } 00398 00399 /// Return string denoting type ("gsl_min_brent") 00400 virtual const char *type() { return "gsl_min_brent"; } 00401 00402 }; 00403 00404 #ifndef DOXYGENP 00405 } 00406 #endif 00407 00408 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).