![]() |
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 /*--------------------------------------------------------------------------*/ 00024 /* */ 00025 /* quad_golden.c */ 00026 /* */ 00027 /* Copyright (C) 2007 James Howse */ 00028 /* Copyright (C) 2009 Brian Gough */ 00029 /* */ 00030 /* This program is free software; you can redistribute it and/or modify */ 00031 /* it under the terms of the GNU General Public License as published by */ 00032 /* the Free Software Foundation; either version 3 of the License, or (at */ 00033 /* your option) any later version. */ 00034 /* */ 00035 /* This program is distributed in the hope that it will be useful, but */ 00036 /* WITHOUT ANY WARRANTY; without even the implied warranty of */ 00037 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ 00038 /* General Public License for more details. */ 00039 /* */ 00040 /* You should have received a copy of the GNU General Public License */ 00041 /* along with this program; if not, write to the Free Software */ 00042 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, */ 00043 /* Boston, MA 02110-1301, USA. */ 00044 /*--------------------------------------------------------------------------*/ 00045 #ifndef O2SCL_GSL_MIN_QUAD_GOLDEN_H 00046 #define O2SCL_GSL_MIN_QUAD_GOLDEN_H 00047 00048 #include <gsl/gsl_min.h> 00049 #include <o2scl/minimize.h> 00050 00051 #ifndef DOXYGENP 00052 namespace o2scl { 00053 #endif 00054 00055 /** \brief Minimization of a function using the safeguarded step-length 00056 algorithm of Gill and Murray [GSL] 00057 00058 This class is unfinished. 00059 00060 Documentation from GSL: 00061 \verbatim 00062 00063 This algorithm performs univariate minimization (i.e., line 00064 search). It requires only objective function values g(x) to 00065 compute the minimum. The algorithm maintains an interval of 00066 uncertainty [a,b] and a point x in the interval [a,b] such that 00067 a < x < b, and g(a) > g(x) and g(x) < g(b). The algorithm also 00068 maintains the three points with the smallest objective values x, 00069 v and w such that g(x) < g(v) < g(w). The algorithm terminates 00070 when max( x-a, b-x ) < 2(r |x| + t) where r and t are small 00071 positive reals. At a given iteration, the algorithm first fits a 00072 quadratic through the three points (x, g(x)), (v, g(v)) and (w, 00073 g(w)) and computes the location of the minimum u of the 00074 resulting quadratic. If u is in the interval [a,b] then g(u) is 00075 computed. If u is not in the interval [a,b], and either v < x 00076 and w < x, or v > x and w > x (i.e., the quadratic is 00077 extrapolating), then a point u' is computed using a safeguarding 00078 procedure and g(u') is computed. If u is not in the interval 00079 [a,b], and the quadratic is not extrapolating, then a point u'' 00080 is computed using approximate golden section and g(u'') is 00081 computed. After evaluating g() at the appropriate new point, a, 00082 b, x, v, and w are updated and the next iteration is performed. 00083 The algorithm is based on work presented in the following 00084 references. 00085 00086 Algorithms for Minimization without derivatives 00087 Richard Brent 00088 Prentice-Hall Inc., Englewood Cliffs, NJ, 1973 00089 00090 Safeguarded Steplength Algorithms for Optimization using Descent Methods 00091 Philip E. Gill and Walter Murray 00092 Division of Numerical Analysis and Computing 00093 National Physical Laboratory, Teddington, United Kingdom 00094 NPL Report NAC 37, August 1974 00095 \endverbatim 00096 00097 \future Take common elements of this and gsl_min_brent and 00098 move to a generic GSL minimizer type? 00099 */ 00100 template<class func_t=funct> class gsl_min_quad_golden : 00101 public minimize_bkt<func_t> { 00102 00103 #ifndef DOXYGEN_INTERNAL 00104 00105 protected: 00106 00107 /// The function 00108 func_t *uf; 00109 00110 double x_prev_small; 00111 double f_prev_small; 00112 double x_small; 00113 double f_small; 00114 double step_size; 00115 double stored_step; 00116 double prev_stored_step; 00117 size_t num_iter; 00118 00119 double rel_err_val; 00120 double abs_err_val; 00121 double golden_mean; 00122 double golden_ratio; 00123 00124 /// Compute the function values at the various points 00125 int compute_f_values(func_t &func, double xminimum, double *fminimum, 00126 double xlower, double *flower, double xupper, 00127 double *fupper) { 00128 00129 *flower=func(xlower); 00130 *fupper=func(xupper); 00131 *fminimum=func(xminimum); 00132 00133 return gsl_success; 00134 } 00135 00136 #endif 00137 00138 public: 00139 00140 /// Location of minimum 00141 double x_minimum; 00142 /// Lower bound 00143 double x_lower; 00144 /// Upper bound 00145 double x_upper; 00146 /// Minimum value 00147 double f_minimum; 00148 /// Value at lower bound 00149 double f_lower; 00150 /// Value at upper bound 00151 double f_upper; 00152 00153 gsl_min_quad_golden() { 00154 rel_err_val=1.0e-06; 00155 abs_err_val=1.0e-10; 00156 golden_mean=0.3819660112501052; 00157 golden_ratio=1.6180339887498950; 00158 } 00159 00160 virtual ~gsl_min_quad_golden() {} 00161 00162 /// Set the function and the initial bracketing interval 00163 int set(func_t &func, double xmin, double lower, double upper) { 00164 00165 double fmin, fl, fu; 00166 int status=compute_f_values(func,lower,&fl,xmin,&fmin,upper,&fu); 00167 00168 status=set_with_values(func,xmin,fmin,lower,fl,upper,fu); 00169 00170 return status; 00171 } 00172 00173 /** \brief Set the function, the initial bracketing interval, 00174 and the corresponding function values. 00175 */ 00176 int set_with_values(func_t &func, double xmin, double fmin, 00177 double lower, double fl, double upper, 00178 double fu) { 00179 00180 if (lower > upper) { 00181 std::string tmp=((std::string)"Invalid interval (lower > upper) ")+ 00182 "in gsl_min_quad_golden::set_with_values()."; 00183 O2SCL_ERR_RET(tmp.c_str(),gsl_einval); 00184 } 00185 if (xmin>=upper || xmin<=lower) { 00186 std::string tmp=((std::string)"'xmin' was not inside interval ")+ 00187 "in gsl_min_quad_golden::set_with_values()."; 00188 O2SCL_ERR_RET(tmp.c_str(),gsl_einval); 00189 } 00190 if (fmin>= fl || fmin>=fu) { 00191 std::string tmp=((std::string)"Endpoints don't enclose minimum ")+ 00192 "in gsl_min_quad_golden::set_with_values()."; 00193 O2SCL_ERR_RET(tmp.c_str(),gsl_einval); 00194 } 00195 00196 x_lower=lower; 00197 x_minimum=xmin; 00198 x_upper=upper; 00199 f_lower=fl; 00200 f_minimum=fmin; 00201 f_upper=fu; 00202 00203 uf=&func; 00204 00205 x_prev_small=xmin; 00206 x_small=xmin; 00207 f_prev_small=fmin; 00208 f_small=fmin; 00209 00210 step_size=0.0; 00211 stored_step=0.0; 00212 prev_stored_step=0.0; 00213 num_iter=0; 00214 00215 return gsl_success; 00216 } 00217 00218 /** \brief Perform an iteration 00219 */ 00220 int iterate() { 00221 00222 const double x_m=x_minimum; 00223 const double f_m=f_minimum; 00224 00225 const double x_l=x_lower; 00226 const double x_u=x_upper; 00227 00228 double quad_step_size=prev_stored_step; 00229 00230 double x_trial; 00231 double x_eval, f_eval; 00232 00233 double x_midpoint=0.5*(x_l+x_u); 00234 double tol=rel_err_val*fabs(x_m)+abs_err_val; 00235 00236 if (fabs(stored_step)-tol>-2.0*GSL_DBL_EPSILON) { 00237 00238 // [GSL] Fit quadratic 00239 double c3=(x_m-x_small)*(f_m-f_prev_small); 00240 double c2=(x_m-x_prev_small)*(f_m-f_small); 00241 double c1=(x_m-x_prev_small)*c2-(x_m-x_small)*c3; 00242 00243 c2=2.0*(c2-c3); 00244 00245 // [GSL] if (c2!=0) 00246 if (fabs(c2)>GSL_DBL_EPSILON) { 00247 if (c2>0.0) { 00248 c1=-c1; 00249 } 00250 c2=fabs(c2); 00251 quad_step_size=c1/c2; 00252 } else { 00253 // [GSL] Handle case where c2 is nearly 0. Insure that the 00254 // line search will NOT take a quadratic interpolation step 00255 // in this iteration 00256 quad_step_size=stored_step; 00257 } 00258 00259 prev_stored_step=stored_step; 00260 stored_step=step_size; 00261 } 00262 00263 x_trial=x_m+quad_step_size; 00264 00265 if (fabs(quad_step_size)<fabs(0.5*prev_stored_step) && 00266 x_trial>x_l && x_trial<x_u) { 00267 00268 // [GSL] Take quadratic interpolation step 00269 step_size=quad_step_size; 00270 00271 // [GSL] Do not evaluate function too close to x_l or x_u 00272 if ((x_trial-x_l)<2.0*tol || (x_u-x_trial)<2.0*tol) { 00273 step_size=(x_midpoint >= x_m ? +1.0 : -1.0)*fabs(tol); 00274 } 00275 00276 } else if ((x_small!=x_prev_small && x_small<x_m && 00277 x_prev_small<x_m) || 00278 (x_small!=x_prev_small && x_small>x_m && 00279 x_prev_small>x_m)) { 00280 00281 // [GSL] Take safeguarded function comparison step 00282 double outside_interval, inside_interval; 00283 00284 if (x_small<x_m) { 00285 outside_interval=x_l-x_m; 00286 inside_interval=x_u-x_m; 00287 } else { 00288 outside_interval=x_u-x_m; 00289 inside_interval=x_l-x_m; 00290 } 00291 00292 if (fabs(inside_interval) <= tol) { 00293 // [GSL] Swap inside and outside intervals 00294 double tmp=outside_interval; 00295 outside_interval=inside_interval; 00296 inside_interval=tmp; 00297 } 00298 00299 { 00300 double step=inside_interval; 00301 double scale_factor; 00302 00303 if (fabs(outside_interval)<fabs(inside_interval)) { 00304 scale_factor=0.5*sqrt (-outside_interval/inside_interval); 00305 } else { 00306 scale_factor=(5.0/11.0)* 00307 (0.1-inside_interval/outside_interval); 00308 } 00309 00310 stored_step=step; 00311 step_size=scale_factor*step; 00312 } 00313 00314 } else { 00315 00316 // [GSL] Take golden section step 00317 double step; 00318 00319 if (x_m<x_midpoint) { 00320 step=x_u-x_m; 00321 } else { 00322 step=x_l-x_m; 00323 } 00324 00325 stored_step=step; 00326 step_size=golden_mean*step; 00327 00328 } 00329 00330 // [GSL] Do not evaluate function too close to x_minimum 00331 if (fabs(step_size)>tol) { 00332 x_eval=x_m+step_size; 00333 } else { 00334 x_eval=x_m+(step_size >= 0 ? +1.0 : -1.0)*fabs(tol); 00335 } 00336 00337 00338 // [GSL] Evaluate function at the new point x_eval 00339 f_eval=(*uf)(x_eval); 00340 00341 // [GSL] Update {x,f}_lower, {x,f}_upper, {x,f}_prev_small, 00342 // {x,f}_small, and {x,f}_minimum 00343 if (f_eval <= f_m) { 00344 if (x_eval<x_m) { 00345 x_upper=x_m; 00346 f_upper=f_m; 00347 } else { 00348 x_lower=x_m; 00349 f_upper=f_m; 00350 } 00351 00352 x_prev_small=x_small; 00353 f_prev_small=f_small; 00354 00355 x_small=x_m; 00356 f_small=f_m; 00357 00358 x_minimum=x_eval; 00359 f_minimum=f_eval; 00360 } else { 00361 if (x_eval<x_m) { 00362 x_lower=x_eval; 00363 f_lower=f_eval; 00364 } else { 00365 x_upper=x_eval; 00366 f_upper=f_eval; 00367 } 00368 00369 if (f_eval <= f_small || fabs(x_small-x_m)<2.0*GSL_DBL_EPSILON) { 00370 x_prev_small=x_small; 00371 f_prev_small=f_small; 00372 00373 x_small=x_eval; 00374 f_small=f_eval; 00375 } else if (f_eval <= f_prev_small || 00376 fabs(x_prev_small-x_m)<2.0*GSL_DBL_EPSILON || 00377 fabs(x_prev_small-x_small)<2.0*GSL_DBL_EPSILON) { 00378 x_prev_small=x_eval; 00379 f_prev_small=f_eval; 00380 } 00381 } 00382 00383 // Update for next iteration 00384 num_iter++; 00385 00386 return gsl_success; 00387 } 00388 00389 /** \brief Calculate the minimum \c fmin of \c func 00390 with \c x2 bracketed between \c x1 and \c x3. 00391 00392 Note that this algorithm requires that the initial guess 00393 already brackets the minimum, i.e. \f$ x_1<x_2<x_3 \f$, 00394 \f$ f(x_1)>f(x_2) \f$ and \f$ f(x_3)>f(x_2) \f$. This is 00395 different from \ref cern_minimize, where the initial value 00396 of the first parameter to cern_minimize::min_bkt() is 00397 ignored. 00398 */ 00399 virtual int min_bkt(double &x2, double x1, double x3, double &fmin, 00400 func_t &func) { 00401 00402 int status, iter=0; 00403 00404 this->last_conv=0; 00405 00406 int rx=set(func,x2,x1,x3); 00407 if (rx!=0) { 00408 O2SCL_ERR2_RET("Function set() failed in ", 00409 "gsl_min_quad_golden::min_bkt().",rx); 00410 } 00411 00412 do { 00413 iter++; 00414 status=iterate(); 00415 x2=x_minimum; 00416 if (status) { 00417 // This should never actually happen in the current 00418 // version, but we retain it for now 00419 this->last_conv=gsl_efailed; 00420 O2SCL_CONV2_RET("Function iterate() failed in gsl_min_", 00421 "quad_golden::min_bkt().",status,this->err_nonconv); 00422 break; 00423 } 00424 00425 status=gsl_min_test_interval(x_lower,x_upper,this->tol_abs, 00426 this->tol_rel); 00427 if (status>0) { 00428 // The function gsl_min_test_interval() fails if the 00429 // tolerances are negative or if the lower bound is larger 00430 // than the upper bound 00431 std::string s="Function gsl_min_test_interval() failed in "; 00432 s+="gsl_min_quad_golden::min_bkt()."; 00433 O2SCL_ERR(s.c_str(),status); 00434 } 00435 00436 if (this->verbose>0) { 00437 if (x_lower*x_upper<0.0) { 00438 if (x_lower<x_upper) { 00439 print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper)- 00440 this->tol_rel*x_lower,this->tol_abs, 00441 "gsl_min_quad_golden"); 00442 } else { 00443 print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper)- 00444 this->tol_rel*x_upper,this->tol_abs, 00445 "gsl_min_quad_golden"); 00446 } 00447 } else { 00448 print_iter(x2,f_minimum,iter,fabs(x_lower-x_upper),this->tol_abs, 00449 "gsl_min_quad_golden"); 00450 } 00451 } 00452 00453 } while (status == gsl_continue && iter<this->ntrial); 00454 00455 if (iter>=this->ntrial) { 00456 this->last_conv=gsl_emaxiter; 00457 O2SCL_CONV2_RET("Exceeded maximum number of ", 00458 "iterations in gsl_min_quad_golden::min_bkt().", 00459 o2scl::gsl_emaxiter,this->err_nonconv); 00460 } 00461 00462 this->last_ntrial=iter; 00463 fmin=f_minimum; 00464 00465 return status; 00466 } 00467 00468 /// Return string denoting type ("gsl_min_quad_golden") 00469 virtual const char *type() { return "gsl_min_quad_golden"; } 00470 00471 }; 00472 00473 #ifndef DOXYGENP 00474 } 00475 #endif 00476 00477 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).