Object-oriented Scientific Computing Library: Version 0.910
gsl_root_brent.h
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.