00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, 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 (GSL) 00036 00037 \todo Simplify temporary storage and document 00038 stopping conditions. 00039 */ 00040 template<class param_t, class func_t=funct<param_t> > class gsl_min_brent : 00041 public minimize<param_t,func_t> 00042 { 00043 00044 #ifndef DOXYGEN_INTERNAL 00045 00046 protected: 00047 00048 /// The function 00049 func_t *uf; 00050 00051 /// The parameters 00052 param_t *up; 00053 00054 /// \name Temporary storage 00055 //@{ 00056 double d, e, v, w, f_v, f_w; 00057 //@} 00058 00059 /// Compute the function values at the various points 00060 int compute_f_values(func_t &func, double xminimum, double *fminimum, 00061 double xlower, double *flower, double xupper, 00062 double *fupper, param_t &pa) { 00063 00064 func(xlower,*flower,pa); 00065 func(xupper,*fupper,pa); 00066 func(xminimum,*fminimum,pa); 00067 00068 return gsl_success; 00069 } 00070 00071 #endif 00072 00073 public: 00074 00075 /// Location of minimum 00076 double x_minimum; 00077 /// Lower bound 00078 double x_lower; 00079 /// Upper mound 00080 double x_upper; 00081 /// Minimum value 00082 double f_minimum; 00083 /// Value at lower bound 00084 double f_lower; 00085 /// Value at upper bound 00086 double f_upper; 00087 00088 /// Set the function to be minimized and the initial brackeing interval 00089 int set(func_t &func, double xmin, double lower, double upper, 00090 param_t &pa) { 00091 00092 double fmin, fl, fu; 00093 int status=compute_f_values(func,lower,&fl,xmin,&fmin,upper,&fu,pa); 00094 00095 status=set_with_values(func,xmin,fmin,lower,fl,upper,fu,pa); 00096 00097 return status; 00098 } 00099 00100 /// Set the function to be minimized and the initial brackeing interval 00101 int set_with_values(func_t &func, double xmin, double fmin, 00102 double lower, double fl, double upper, 00103 double fu, param_t &pa) { 00104 00105 if (lower > upper) { 00106 set_err_ret("Invalid interval in set_with_values().",gsl_einval); 00107 } 00108 if (xmin>=upper || xmin<=lower) { 00109 set_err_ret 00110 ("'xmin' was not inside interval set_with_values().",gsl_einval); 00111 } 00112 if (fmin >= fl || fmin>=fu) { 00113 set_err_ret 00114 ("Endpoints don't enclose minimum in set_with_values().", 00115 gsl_einval); 00116 } 00117 00118 x_lower=lower; 00119 x_minimum=xmin; 00120 x_upper=upper; 00121 f_lower=fl; 00122 f_minimum=fmin; 00123 f_upper=fu; 00124 00125 uf=&func; 00126 up=&pa; 00127 00128 /* golden=(3-sqrt(5))/2 */ 00129 const double golden=0.3819660; 00130 00131 v=x_lower+golden*(x_upper-x_lower); 00132 w=v; 00133 d=0; 00134 e=0; 00135 func(v,f_v,pa); 00136 f_w=f_v; 00137 00138 return gsl_success; 00139 } 00140 00141 /// Perform an iteration 00142 int iterate() { 00143 00144 const double x_left= x_lower; 00145 const double x_right= x_upper; 00146 00147 const double z=x_minimum; 00148 double u, f_u; 00149 const double f_z=f_minimum; 00150 00151 /* golden=(3-sqrt(5))/2 */ 00152 const double golden=0.3819660; 00153 00154 const double w_lower=(z-x_left); 00155 const double w_upper=(x_right-z); 00156 00157 const double tolerance= GSL_SQRT_DBL_EPSILON*fabs (z); 00158 00159 double p=0, q=0, r=0; 00160 00161 const double midpoint=0.5*(x_left+x_right); 00162 00163 if (fabs (e) > tolerance) { 00164 /* fit parabola */ 00165 00166 r=(z-w)*(f_z-f_v); 00167 q=(z-v)*(f_z-f_w); 00168 p=(z-v)*q-(z-w)*r; 00169 q=2*(q-r); 00170 00171 if (q > 0) { 00172 p=-p; 00173 } else { 00174 q=-q; 00175 } 00176 00177 r=e; 00178 e=d; 00179 } 00180 00181 if (fabs (p) < fabs (0.5*q*r) && p < q*w_lower && 00182 p < q*w_upper) { 00183 00184 double t2=2*tolerance; 00185 00186 d=p / q; 00187 u=z+d; 00188 00189 if ((u-x_left) < t2 || (x_right-u) < t2) 00190 { 00191 d=(z < midpoint) ? tolerance : -tolerance ; 00192 } 00193 } else { 00194 e=(z < midpoint) ? x_right-z : -(z-x_left) ; 00195 d=golden*e; 00196 } 00197 00198 00199 if (fabs (d) >= tolerance) { 00200 u=z+d; 00201 } else { 00202 u=z+((d > 0) ? tolerance : -tolerance) ; 00203 } 00204 00205 (*uf)(u,f_u,*up); 00206 00207 if (f_u > f_z) { 00208 00209 if (u < z) { 00210 x_lower=u; 00211 f_lower=f_u; 00212 return gsl_success; 00213 } else { 00214 x_upper=u; 00215 f_upper=f_u; 00216 return gsl_success; 00217 } 00218 00219 } else if (f_u < f_z) { 00220 00221 if (u < z) { 00222 x_upper=z; 00223 f_upper=f_z; 00224 } else { 00225 x_lower=z; 00226 f_lower=f_z; 00227 } 00228 00229 v=w; 00230 w=z; 00231 f_v=f_w; 00232 f_w=f_z; 00233 x_minimum=u; 00234 f_minimum=f_u; 00235 00236 return gsl_success; 00237 00238 } else if (f_u <= f_w || w == z) { 00239 00240 v=w; 00241 f_v=f_w; 00242 w=u; 00243 f_w=f_u; 00244 return gsl_success; 00245 00246 } else if (f_u <= f_v || v == z || v == w) { 00247 00248 v=u; 00249 f_v=f_u; 00250 return gsl_success; 00251 00252 } else { 00253 00254 set_err_ret("Iteration failed in gsl_min_brent::iterate().", 00255 gsl_failure); 00256 00257 } 00258 00259 set_err("Sanity check failed in gsl_min_brent::iterate().", 00260 gsl_esanity); 00261 return gsl_esanity; 00262 } 00263 00264 virtual ~gsl_min_brent() {} 00265 00266 /** \brief Calculate the minimum \c min of \c func 00267 with \c x2 bracketed between \c x1 and \c x3. 00268 00269 Note that this algorithm requires that the initial guess 00270 already brackets the minimum, i.e. \f$ x_1 < x_2 < x_3 \f$, 00271 \f$ f(x_1) > f(x_2) \f$ and \f$ f(x_3) > f(x_2) \f$. This is 00272 different from \ref cern_minimize, where the initial value 00273 of the first parameter to cern_minimize::min_bkt() is 00274 ignored. 00275 */ 00276 virtual int min_bkt(double &x2, double x1, double x3, double &fmin, 00277 param_t &pa, func_t &func) { 00278 00279 int status, iter=0; 00280 double a,b; 00281 double ytmp; 00282 00283 set(func,x2,x1,x3,pa); 00284 00285 do { 00286 iter++; 00287 status=iterate(); 00288 if (status) break; 00289 00290 a=x_lower; 00291 b=x_upper; 00292 x2=x_minimum; 00293 00294 status=gsl_min_test_interval(a,b,this->tolx,this->tolf); 00295 00296 if (this->verbose>0) { 00297 func(x2,ytmp,pa); 00298 if (a*b<0.0) { 00299 if (a<b) { 00300 print_iter(x2,ytmp,iter,fabs(a-b)-this->tolf*a,this->tolx); 00301 } else { 00302 print_iter(x2,ytmp,iter,fabs(a-b)-this->tolf*b,this->tolx); 00303 } 00304 } else { 00305 print_iter(x2,ytmp,iter,fabs(a-b),this->tolx); 00306 } 00307 } 00308 00309 } while (status == gsl_continue && iter<this->ntrial); 00310 00311 this->last_ntrial=iter; 00312 func(x2,fmin,pa); 00313 00314 if (status==gsl_success) return 0; 00315 00316 return status; 00317 } 00318 00319 /// Return string denoting type ("gsl_min_brent") 00320 virtual const char *type() { return "gsl_min_brent"; } 00321 00322 }; 00323 00324 #ifndef DOXYGENP 00325 } 00326 #endif 00327 00328 #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