gsl_root_brent.h

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 SourceForge.net Logo, O2scl Sourceforge Project Page