gsl_root_stef.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_STEF_H
00024 #define O2SCL_GSL_ROOT_STEF_H
00025 
00026 #include <gsl/gsl_math.h>
00027 #include <gsl/gsl_roots.h>
00028 #include <o2scl/root.h>
00029 
00030 #ifndef DOXYGENP
00031 namespace o2scl {
00032 #endif
00033 
00034   /** 
00035       \brief Steffenson equation solver (GSL)
00036 
00037       This class finds a root of a function a derivative. If the
00038       derivative is not analytically specified, it is most likely
00039       preferable to use of the alternatives, gsl_root_brent,
00040       cern_root, or cern_mroot_root. The function solve_de() performs
00041       the solution automatically, and a lower-level GSL-like interface
00042       with set() and iterate() is also provided.
00043 
00044       By default, this solver compares the present value of the root
00045       (\f$ \mathrm{root} \f$) to the previous value (\f$ \mathrm{x} \f$), 
00046       and returns
00047       success if \f$ | \mathrm{root} - \mathrm{x} | < \mathrm{tol} \f$, 
00048       where \f$ \mathrm{tol}=\mathrm{tolx}+\mathrm{tolf2}~\mathrm{root} \f$ .
00049 
00050       If \ref test_residual is set to true, then the solver 
00051       additionally requires that the absolute value of the function
00052       is less than \ref root::tolf.
00053 
00054       The original variable \c x_2 has been removed as it was unused
00055       in the original GSL code.
00056 
00057       \future There's some extra copying here which can probably
00058       be removed.
00059       \future Compare directly to GSL.
00060       
00061   */
00062   template<class param_t, class func_t, class dfunc_t> class gsl_root_stef : 
00063   public o2scl::root_de<param_t,func_t,dfunc_t> {
00064       
00065   protected:
00066       
00067     /// Function value
00068     double f;
00069 
00070     /// Derivative value
00071     double df;
00072 
00073     /// Previous value of root
00074     double x_1;
00075 
00076     /// Root
00077     double x;
00078 
00079     /// Number of iterations
00080     int count;
00081 
00082     /// The function to solve
00083     func_t *fp;
00084 
00085     /// The derivative
00086     dfunc_t *dfp;
00087       
00088     /// The function parameters
00089     param_t *params;
00090       
00091   public:
00092   
00093     gsl_root_stef() {
00094       test_residual=false;
00095       tolf2=1.0e-12;
00096     }
00097     
00098     /// Return the type, \c "gsl_root_stef".
00099     virtual const char *type() { return "gsl_root_stef"; }
00100 
00101     /// The present solution estimate
00102     double root;
00103 
00104     /** \brief The relative tolerance for subsequent solutions 
00105         (default \f$ 10^{-12} \f$)
00106     */
00107     double tolf2;
00108 
00109     /**
00110        \brief Perform an iteration
00111 
00112        After a successful iteration, \ref root contains the
00113        most recent value of the root. 
00114     */
00115     int iterate() {
00116       
00117       double x_new, f_new, df_new;
00118         
00119       double x_1t = x_1;
00120       double xt = x;
00121         
00122       if (df == 0.0) {
00123         this->last_conv=gsl_ezerodiv;
00124         O2SCL_CONV_RET("Derivative is zero in gsl_root_stef::iterate().",
00125                        o2scl::gsl_ezerodiv,this->err_nonconv);
00126       }
00127         
00128       x_new = xt - (f / df);
00129 
00130       // It is important that the derivative be evaluated first here,
00131       // because we want the last function evaluation to be an
00132       // evaluation for the returned root
00133       (*dfp)(x_new,df_new,*params);
00134       (*fp)(x_new,f_new,*params);
00135     
00136       x_1 = xt;
00137       x = x_new;
00138         
00139       f = f_new;
00140       df = df_new;
00141     
00142       if (!finite (f_new)) {
00143         O2SCL_ERR_RET("Function not continuous in gsl_root_stef::iterate().",
00144                       o2scl::gsl_ebadfunc);
00145       }
00146         
00147       if (count < 3) {
00148 
00149         root = x_new;
00150         count++;
00151 
00152       } else {
00153 
00154         double u = (xt - x_1t);
00155         double v = (x_new - 2 * xt + x_1t);
00156         
00157         if (v == 0) {
00158           root = x_new;  /* avoid division by zero */
00159         } else {
00160           root = x_1t - u * u / v;  /* accelerated value */
00161         }
00162       }
00163       
00164       if (!finite(df_new)) {
00165         O2SCL_ERR_RET
00166           ("Function not differentiable in gsl_root_stef::iterate().",
00167            o2scl::gsl_ebadfunc);
00168       }
00169       
00170       return o2scl::gsl_success;
00171     }
00172 
00173     /** \brief Solve \c func using \c x as an initial
00174         guess using derivatives \c df.
00175     */
00176     virtual int solve_de(double &xx, param_t &pa, func_t &fun, dfunc_t &dfun) {
00177       
00178       int status1, status2=gsl_continue, iter=0;
00179         
00180       status1=set(fun,dfun,xx,pa);
00181 
00182       this->last_conv=0;
00183       while (status1==gsl_success && status2==gsl_continue && 
00184              iter<this->ntrial) {
00185         iter++;
00186 
00187         status1=iterate();
00188 
00189         // Compare present value to previous value
00190         status2=gsl_root_test_delta(root,xx,this->tolx,tolf2);
00191 
00192         if (test_residual && status2==gsl_success) {
00193           double y;
00194           fun(root,y,pa);
00195           if (fabs(y)>=this->tolf) status2=gsl_continue;
00196         }
00197 
00198         if (this->verbose>0) {
00199           double fval;
00200           fun(root,fval,pa);
00201           print_iter(root,fval,iter,fabs(root-xx),this->tolx*root,
00202                      "gsl_root_stef");
00203         }
00204         xx=root;
00205       }
00206       
00207       this->last_ntrial=iter;
00208 
00209       if (status1!=gsl_success || status2!=gsl_success) {
00210         int ret=o2scl::err_hnd->get_errno();
00211         return ret;
00212       }
00213       if (iter>=this->ntrial) {
00214         if (this->last_conv==0) this->last_conv=gsl_emaxiter;
00215         O2SCL_CONV_RET("solve_de() exceeded maximum number of iterations.",
00216                        gsl_emaxiter,this->err_nonconv);
00217       }
00218 
00219       return o2scl::gsl_success;
00220     }
00221     
00222     /// True if we should test the residual also (default false)
00223     bool test_residual;
00224 
00225     /** 
00226         \brief Set the information for the solver
00227 
00228         Set the function, the derivative, the initial guess and
00229         the parameters.
00230     */
00231     int set(func_t &fun, dfunc_t &dfun, double guess, param_t &pa) {
00232     
00233       fp=&fun;
00234       dfp=&dfun;
00235       params=&pa;
00236       root=guess;
00237 
00238       dfun(root,df,pa);
00239       fun(root,f,pa);
00240 
00241       x=root;
00242       x_1=0.0;
00243       count=1;
00244         
00245       return o2scl::gsl_success;
00246         
00247     }
00248 
00249   };
00250   
00251 #ifndef DOXYGENP
00252   template<> int io_tlate<gsl_root_stef<int,funct<int>,
00253     funct<int> > >::input(cinput *co, in_file_format *ins, 
00254                           gsl_root_stef<int, funct<int>,
00255                           funct<int> > *ro);
00256   template<> int io_tlate<gsl_root_stef<int,funct<int>,
00257     funct<int> > >::output(coutput *co, out_file_format *outs, 
00258                            gsl_root_stef<int, funct<int>,
00259                            funct<int> > *ro);
00260   template<> const char *io_tlate<gsl_root_stef<int,
00261     funct<int>, funct<int> > >::type();
00262 #endif
00263   
00264   typedef io_tlate<gsl_root_stef<int,funct<int>, funct<int> > > 
00265     gsl_root_stef_io_type;
00266  
00267 #ifndef DOXYGENP
00268 }
00269 #endif
00270 
00271 #endif
00272 

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