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 /* roots/brent.c 00024 * 00025 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Reid Priedhorsky, 00026 * Brian Gough 00027 * 00028 * This program is free software; you can redistribute it and/or modify 00029 * it under the terms of the GNU General Public License as published by 00030 * the Free Software Foundation; either version 3 of the License, or (at 00031 * your option) any later version. 00032 * 00033 * This program is distributed in the hope that it will be useful, but 00034 * WITHOUT ANY WARRANTY; without even the implied warranty of 00035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00036 * General Public License for more details. 00037 * 00038 * You should have received a copy of the GNU General Public License 00039 * along with this program; if not, write to the Free Software 00040 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00041 * 02110-1301, USA. 00042 */ 00043 00044 #ifndef O2SCL_GSL_ROOT_BRENT_H 00045 #define O2SCL_GSL_ROOT_BRENT_H 00046 00047 #include <gsl/gsl_math.h> 00048 #include <gsl/gsl_roots.h> 00049 #include <o2scl/funct.h> 00050 #include <o2scl/root.h> 00051 00052 #ifndef DOXYGENP 00053 namespace o2scl { 00054 #endif 00055 00056 /** 00057 \brief One-dimensional root-finding (GSL) 00058 00059 This class finds the root of a user-specified function. 00060 If \ref test_form is 0, then solve_bkt() stops when the size of 00061 the bracket is smaller than \ref root::tolx. If \ref test_form 00062 is 1, then the function stops when the residual is less than 00063 \ref root::tolf. If test_form is 2, then both tests are applied. 00064 00065 An example demonstrating the usage of this class is 00066 given in <tt>examples/ex_fptr.cpp</tt> and the \ref ex_fptr_sect . 00067 00068 \future There is some duplication in the variables \c x_lower, 00069 \c x_upper, \c a, and \c b, which could be removed. 00070 00071 \comment 00072 Note that I used \c instead of \ref to refer to variables above 00073 since the variables a and b are protected, and not available if 00074 compiling the documentation without the internal portion. 00075 00076 Also, at first I got confused that GSL didn't require 00077 lower<upper, but it turns out that this is indeed a 00078 requirement in GSL, but I didn't see it because it was 00079 in roots/fsolver.c rather than in roots/brent.c . Thus, 00080 everything looks fine now. 00081 \endcomment 00082 */ 00083 #ifdef DOXYGENP 00084 template<class param_t, class func_t=funct<param_t> > 00085 class gsl_root_brent : public root_bkt 00086 #else 00087 template<class param_t, class func_t=funct<param_t> > 00088 class gsl_root_brent : public root_bkt<param_t,func_t> 00089 #endif 00090 00091 { 00092 00093 public: 00094 00095 gsl_root_brent() { 00096 test_form=0; 00097 } 00098 00099 /// Return the type, \c "gsl_root_brent". 00100 virtual const char *type() { return "gsl_root_brent"; } 00101 00102 /** 00103 \brief Perform an iteration 00104 00105 This function always returns \ref gsl_success. 00106 00107 */ 00108 int iterate(func_t &f) { 00109 00110 double tol, m; 00111 00112 int ac_equal = 0; 00113 00114 if ((fb < 0 && fc < 0) || (fb > 0 && fc > 0)) { 00115 ac_equal = 1; 00116 c = a; 00117 fc = fa; 00118 d = b - a; 00119 e = b - a; 00120 } 00121 00122 if (fabs (fc) < fabs (fb)) { 00123 ac_equal = 1; 00124 a = b; 00125 b = c; 00126 c = a; 00127 fa = fb; 00128 fb = fc; 00129 fc = fa; 00130 } 00131 00132 tol = 0.5 * GSL_DBL_EPSILON * fabs (b); 00133 m = 0.5 * (c - b); 00134 00135 if (fb == 0) { 00136 root = b; 00137 x_lower = b; 00138 x_upper = b; 00139 00140 return o2scl::gsl_success; 00141 } 00142 if (fabs (m) <= tol) { 00143 root = b; 00144 00145 if (b < c) { 00146 x_lower = b; 00147 x_upper = c; 00148 } else { 00149 x_lower = c; 00150 x_upper = b; 00151 } 00152 00153 return o2scl::gsl_success; 00154 } 00155 00156 if (fabs (e) < tol || fabs (fa) <= fabs (fb)) { 00157 d = m; /* use bisection */ 00158 e = m; 00159 } else { 00160 double p, q, r; /* use inverse cubic interpolation */ 00161 double s = fb / fa; 00162 00163 if (ac_equal) { 00164 p = 2 * m * s; 00165 q = 1 - s; 00166 } else { 00167 q = fa / fc; 00168 r = fb / fc; 00169 p = s * (2 * m * q * (q - r) - (b - a) * (r - 1)); 00170 q = (q - 1) * (r - 1) * (s - 1); 00171 } 00172 00173 if (p > 0) { 00174 q = -q; 00175 } else { 00176 p = -p; 00177 } 00178 if (2 * p < GSL_MIN (3 * m * q - fabs (tol * q), fabs (e * q))) { 00179 e = d; 00180 d = p / q; 00181 } else { 00182 /* interpolation failed, fall back to bisection */ 00183 00184 d = m; 00185 e = m; 00186 } 00187 } 00188 00189 a = b; 00190 fa = fb; 00191 00192 if (fabs (d) > tol) { 00193 b += d; 00194 } else { 00195 b += (m > 0 ? +tol : -tol); 00196 } 00197 00198 f(b,fb,*params); 00199 00200 /* Update the best estimate of the root and bounds on each 00201 iteration */ 00202 00203 root = b; 00204 00205 if ((fb < 0 && fc < 0) || (fb > 0 && fc > 0)) { 00206 c = a; 00207 } 00208 if (b < c) { 00209 x_lower = b; 00210 x_upper = c; 00211 } else { 00212 x_lower = c; 00213 x_upper = b; 00214 } 00215 00216 return o2scl::gsl_success; 00217 } 00218 00219 /// Solve \c func in region \f$ x_1<x<x_2 \f$ returning \f$ x_1 \f$. 00220 virtual int solve_bkt(double &x1, double x2, param_t &pa, 00221 func_t &f) { 00222 00223 int status, iter=0; 00224 00225 if (set(f,x1,x2,pa)!=0) { 00226 O2SCL_ERR2_RET("Function set() failed in", 00227 "gsl_root_brent::solve_bkt().",gsl_einval); 00228 } 00229 00230 if (test_form==0) { 00231 00232 /// Test the bracket size 00233 00234 status=GSL_CONTINUE; 00235 while (status==GSL_CONTINUE && iter<this->ntrial) { 00236 00237 iter++; 00238 iterate(f); 00239 status=gsl_root_test_interval(x_lower,x_upper,0.0,this->tolx); 00240 00241 if (this->verbose>0) { 00242 double y; 00243 00244 f(root,y,pa); 00245 00246 print_iter(root,y,iter,fabs(x_upper-x_lower),this->tolx, 00247 "gsl_root_brent"); 00248 } 00249 } 00250 00251 } else if (test_form==1) { 00252 00253 /// Test the residual 00254 00255 status=GSL_CONTINUE; 00256 while (status==GSL_CONTINUE && iter<this->ntrial) { 00257 00258 iter++; 00259 iterate(f); 00260 00261 double y; 00262 00263 f(root,y,pa); 00264 00265 if (fabs(y)<this->tolf) status=o2scl::gsl_success; 00266 00267 status=gsl_root_test_interval(x_lower,x_upper,0.0,this->tolx); 00268 00269 if (this->verbose>0) { 00270 print_iter(root,y,iter,fabs(x_upper-x_lower),this->tolx, 00271 "gsl_root_brent"); 00272 } 00273 } 00274 00275 00276 } else { 00277 00278 /// Test the bracket size and the residual 00279 00280 status=GSL_CONTINUE; 00281 while (status==GSL_CONTINUE && iter<this->ntrial) { 00282 00283 iter++; 00284 iterate(f); 00285 status=gsl_root_test_interval(x_lower,x_upper,0.0,this->tolx); 00286 00287 if (status==o2scl::gsl_success) { 00288 double y; 00289 00290 f(root,y,pa); 00291 00292 if (fabs(y)>=this->tolf) status=GSL_CONTINUE; 00293 } 00294 00295 if (this->verbose>0) { 00296 double y; 00297 00298 f(root,y,pa); 00299 00300 print_iter(root,y,iter,fabs(x_upper-x_lower),this->tolx, 00301 "gsl_root_brent"); 00302 } 00303 } 00304 00305 } 00306 00307 x1=root; 00308 00309 if (status!=o2scl::gsl_success) { 00310 int ret=o2scl::err_hnd->get_errno(); 00311 return ret; 00312 } 00313 this->last_conv=0; 00314 if (iter>=this->ntrial) { 00315 this->last_conv=gsl_emaxiter; 00316 O2SCL_CONV_RET("solve_bkt() exceeded maximum number of iterations.", 00317 o2scl::gsl_emaxiter,this->err_nonconv); 00318 } 00319 00320 return o2scl::gsl_success; 00321 } 00322 00323 /// The type of convergence test applied: 0, 1, or 2 (default 0) 00324 int test_form; 00325 00326 /// Get the most recent value of the root 00327 double get_root() { return root; } 00328 00329 /// Get the lower limit 00330 double get_lower() { return x_lower; } 00331 00332 /// Get the upper limit 00333 double get_upper() { return x_upper; } 00334 00335 /** 00336 \brief Set the information for the solver 00337 00338 This function always returns \ref gsl_success. 00339 */ 00340 int set(func_t &ff, double lower, double upper, param_t &pa) { 00341 00342 if (lower > upper) { 00343 double tmp=lower; 00344 lower=upper; 00345 upper=tmp; 00346 } 00347 00348 params=&pa; 00349 00350 x_lower=lower; 00351 x_upper=upper; 00352 root=0.5*(lower+upper); 00353 00354 double f_lower, f_upper; 00355 00356 ff(x_lower,f_lower,pa); 00357 ff(x_upper,f_upper,pa); 00358 00359 a = x_lower; 00360 fa = f_lower; 00361 00362 b = x_upper; 00363 fb = f_upper; 00364 00365 c = x_upper; 00366 fc = f_upper; 00367 00368 d = x_upper - x_lower; 00369 e = x_upper - x_lower; 00370 00371 if ((f_lower < 0.0 && f_upper < 0.0) || 00372 (f_lower > 0.0 && f_upper > 0.0)) { 00373 O2SCL_ERR_RET 00374 ("Endpoints don't straddle y=0 in gsl_root_brent::set().", 00375 o2scl::gsl_einval); 00376 } 00377 00378 return o2scl::gsl_success; 00379 00380 } 00381 00382 #ifndef DOXYGEN_INTERNAL 00383 00384 protected: 00385 00386 /// The present solution estimate 00387 double root; 00388 /// The present lower limit 00389 double x_lower; 00390 /// The present upper limit 00391 double x_upper; 00392 /// The function parameters 00393 param_t *params; 00394 00395 /// \name Storage for solver state 00396 //@{ 00397 double a, b, c, d, e; 00398 double fa, fb, fc; 00399 //@} 00400 00401 #endif 00402 00403 }; 00404 00405 #ifndef DOXYGENP 00406 } 00407 #endif 00408 00409 #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