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 #ifndef O2SCL_GSL_ROOT_BRENT_H 00024 #define O2SCL_GSL_ROOT_BRENT_H 00025 00026 #include <gsl/gsl_math.h> 00027 #include <gsl/gsl_roots.h> 00028 #include <o2scl/funct.h> 00029 #include <o2scl/root.h> 00030 00031 #ifndef DOXYGENP 00032 namespace o2scl { 00033 #endif 00034 00035 /** 00036 \brief One-dimensional root-finding (GSL) 00037 00038 This class finds the root of a user-specified function. 00039 If \ref test_form is 0, then solve_bkt() stops when the size of 00040 the bracket is smaller than \ref root::tolx. If \ref test_form 00041 is 1, then the function stops when the residual is less than 00042 \ref root::tolf. If test_form is 2, then both tests are applied. 00043 00044 \todo There is some duplication in the variables \c x_lower, 00045 \c x_upper, \c a, and \c b, which could be removed. 00046 00047 \comment 00048 Note that I used \c instead of \ref to refer to variables above 00049 since the variables a and b are protected, and not available if 00050 compiling the documentation without the internal portion. 00051 \endcomment 00052 */ 00053 template<class param_t, class func_t=funct<void *>, class dfunc_t=func_t> 00054 class gsl_root_brent : public root<param_t,func_t,dfunc_t> 00055 00056 { 00057 00058 public: 00059 00060 gsl_root_brent() { 00061 test_form=0; 00062 this->over_bkt=true; 00063 } 00064 00065 /// Return the type, \c "gsl_root_brent". 00066 virtual const char *type() { return "gsl_root_brent"; } 00067 00068 /** 00069 \brief Perform an iteration 00070 00071 This function always returns \ref gsl_success. 00072 00073 */ 00074 int iterate(func_t &f) { 00075 00076 double tol, m; 00077 00078 int ac_equal = 0; 00079 00080 if ((fb < 0 && fc < 0) || (fb > 0 && fc > 0)) { 00081 ac_equal = 1; 00082 c = a; 00083 fc = fa; 00084 d = b - a; 00085 e = b - a; 00086 } 00087 00088 if (fabs (fc) < fabs (fb)) { 00089 ac_equal = 1; 00090 a = b; 00091 b = c; 00092 c = a; 00093 fa = fb; 00094 fb = fc; 00095 fc = fa; 00096 } 00097 00098 tol = 0.5 * GSL_DBL_EPSILON * fabs (b); 00099 m = 0.5 * (c - b); 00100 00101 if (fb == 0) { 00102 root = b; 00103 x_lower = b; 00104 x_upper = b; 00105 00106 return o2scl::gsl_success; 00107 } 00108 if (fabs (m) <= tol) { 00109 root = b; 00110 00111 if (b < c) { 00112 x_lower = b; 00113 x_upper = c; 00114 } else { 00115 x_lower = c; 00116 x_upper = b; 00117 } 00118 00119 return o2scl::gsl_success; 00120 } 00121 00122 if (fabs (e) < tol || fabs (fa) <= fabs (fb)) { 00123 d = m; /* use bisection */ 00124 e = m; 00125 } else { 00126 double p, q, r; /* use inverse cubic interpolation */ 00127 double s = fb / fa; 00128 00129 if (ac_equal) { 00130 p = 2 * m * s; 00131 q = 1 - s; 00132 } else { 00133 q = fa / fc; 00134 r = fb / fc; 00135 p = s * (2 * m * q * (q - r) - (b - a) * (r - 1)); 00136 q = (q - 1) * (r - 1) * (s - 1); 00137 } 00138 00139 if (p > 0) { 00140 q = -q; 00141 } else { 00142 p = -p; 00143 } 00144 if (2 * p < GSL_MIN (3 * m * q - fabs (tol * q), fabs (e * q))) { 00145 e = d; 00146 d = p / q; 00147 } else { 00148 /* interpolation failed, fall back to bisection */ 00149 00150 d = m; 00151 e = m; 00152 } 00153 } 00154 00155 a = b; 00156 fa = fb; 00157 00158 if (fabs (d) > tol) { 00159 b += d; 00160 } else { 00161 b += (m > 0 ? +tol : -tol); 00162 } 00163 00164 f(b,fb,*params); 00165 00166 /* Update the best estimate of the root and bounds on each 00167 iteration */ 00168 00169 root = b; 00170 00171 if ((fb < 0 && fc < 0) || (fb > 0 && fc > 0)) { 00172 c = a; 00173 } 00174 if (b < c) { 00175 x_lower = b; 00176 x_upper = c; 00177 } else { 00178 x_lower = c; 00179 x_upper = b; 00180 } 00181 00182 return o2scl::gsl_success; 00183 } 00184 00185 /// Solve \c func in region \f$ x_1<x<x_2 \f$ returning \f$ x_1 \f$. 00186 virtual int solve_bkt(double &x1, double x2, param_t &pa, 00187 func_t &f) { 00188 00189 int status, iter=0; 00190 00191 set(f,x1,x2,pa); 00192 00193 if (test_form==0) { 00194 /// Test the bracket size 00195 00196 status=GSL_CONTINUE; 00197 while (status==GSL_CONTINUE && iter<this->ntrial) { 00198 00199 iter++; 00200 iterate(f); 00201 status=gsl_root_test_interval(x_lower,x_upper,0.0,this->tolx); 00202 00203 if (this->verbose>0) { 00204 double y; 00205 00206 f(root,y,pa); 00207 00208 print_iter(root,y,iter,fabs(x_upper-x_lower),this->tolx, 00209 "gsl_root_brent"); 00210 } 00211 } 00212 00213 } else if (test_form==1) { 00214 /// Test the residual 00215 00216 status=GSL_CONTINUE; 00217 while (status==GSL_CONTINUE && iter<this->ntrial) { 00218 00219 iter++; 00220 iterate(f); 00221 00222 double y; 00223 00224 f(root,y,pa); 00225 00226 if (fabs(y)<this->tolf) status=o2scl::gsl_success; 00227 00228 status=gsl_root_test_interval(x_lower,x_upper,0.0,this->tolx); 00229 00230 if (this->verbose>0) { 00231 print_iter(root,y,iter,fabs(x_upper-x_lower),this->tolx, 00232 "gsl_root_brent"); 00233 } 00234 } 00235 00236 00237 } else { 00238 /// Test the bracket size and the residual 00239 00240 status=GSL_CONTINUE; 00241 while (status==GSL_CONTINUE && iter<this->ntrial) { 00242 00243 iter++; 00244 iterate(f); 00245 status=gsl_root_test_interval(x_lower,x_upper,0.0,this->tolx); 00246 00247 if (status==o2scl::gsl_success) { 00248 double y; 00249 00250 f(root,y,pa); 00251 00252 if (fabs(y)>=this->tolf) status=GSL_CONTINUE; 00253 } 00254 00255 if (this->verbose>0) { 00256 double y; 00257 00258 f(root,y,pa); 00259 00260 print_iter(root,y,iter,fabs(x_upper-x_lower),this->tolx, 00261 "gsl_root_brent"); 00262 } 00263 } 00264 00265 } 00266 00267 x1=root; 00268 00269 if (status!=o2scl::gsl_success) { 00270 int ret=o2scl::err_hnd->get_errno(); 00271 return ret; 00272 } 00273 if (iter>=this->ntrial) { 00274 set_err_ret("solve_bkt() exceeded maximum number of iterations.", 00275 o2scl::gsl_emaxiter); 00276 } 00277 00278 return o2scl::gsl_success; 00279 } 00280 00281 /// The type of convergence test applied: 0, 1, or 2 (default 0) 00282 int test_form; 00283 00284 /// Get the most recent value of the root 00285 double get_root() { return root; } 00286 00287 /// Get the lower limit 00288 double get_lower() { return x_lower; } 00289 00290 /// Get the upper limit 00291 double get_upper() { return x_upper; } 00292 00293 /** 00294 \brief Set the information for the solver 00295 00296 This function always returns \ref gsl_success. 00297 */ 00298 int set(func_t &ff, double lower, double upper, param_t &pa) { 00299 00300 if (lower > upper) { 00301 set_err_ret("Invalid interval in gsl_root_brent::set().", 00302 o2scl::gsl_einval); 00303 } 00304 00305 params=&pa; 00306 00307 x_lower=lower; 00308 x_upper=upper; 00309 root=0.5*(lower+upper); 00310 00311 double f_lower, f_upper; 00312 00313 ff(x_lower,f_lower,pa); 00314 ff(x_upper,f_upper,pa); 00315 00316 a = x_lower; 00317 fa = f_lower; 00318 00319 b = x_upper; 00320 fb = f_upper; 00321 00322 c = x_upper; 00323 fc = f_upper; 00324 00325 d = x_upper - x_lower; 00326 e = x_upper - x_lower; 00327 00328 if ((f_lower < 0.0 && f_upper < 0.0) || 00329 (f_lower > 0.0 && f_upper > 0.0)) { 00330 set_err_ret 00331 ("Endpoints don't straddle y=0 in gsl_root_brent::set().", 00332 o2scl::gsl_einval); 00333 } 00334 00335 return o2scl::gsl_success; 00336 00337 } 00338 00339 #ifndef DOXYGEN_INTERNAL 00340 00341 protected: 00342 00343 /// The present solution estimate 00344 double root; 00345 /// The present lower limit 00346 double x_lower; 00347 /// The present upper limit 00348 double x_upper; 00349 /// The function parameters 00350 param_t *params; 00351 00352 /// \name Storage for solver state 00353 //@{ 00354 double a, b, c, d, e; 00355 double fa, fb, fc; 00356 //@} 00357 00358 #endif 00359 00360 }; 00361 00362 #ifndef DOXYGENP 00363 template<> int io_tlate<gsl_root_brent<void *,funct<void *> > >::input 00364 (cinput *co, in_file_format *ins, 00365 gsl_root_brent<void *, funct<void *> > *ro); 00366 template<> int io_tlate<gsl_root_brent<void *,funct<void *> > >::output 00367 (coutput *co, out_file_format *outs, 00368 gsl_root_brent<void *, funct<void *> > *ro); 00369 template<> const char *io_tlate<gsl_root_brent<void *, 00370 funct<void *> > >::type(); 00371 #endif 00372 00373 typedef io_tlate<gsl_root_brent<void *,funct<void *> > > 00374 gsl_root_brent_io_type; 00375 00376 #ifndef DOXYGENP 00377 } 00378 #endif 00379 00380 #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