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