Object-oriented Scientific Computing Library: Version 0.910
gsl_root_stef.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/steffenson.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_STEF_H
00045 #define O2SCL_GSL_ROOT_STEF_H
00046 
00047 #include <string>
00048 
00049 #include <gsl/gsl_math.h>
00050 #include <gsl/gsl_roots.h>
00051 
00052 #include <o2scl/root.h>
00053 
00054 #ifndef DOXYGENP
00055 namespace o2scl {
00056 #endif
00057 
00058   /** \brief Steffenson equation solver (GSL)
00059 
00060       This is Newton's method with an Aitken "delta-squared"
00061       acceleration of the iterates. This can improve the convergence
00062       on multiple roots where the ordinary Newton algorithm is slow.
00063 
00064       Defining the next iteration with
00065       \f[
00066       x_{i+1} = x_i - f(x_i) / f^{\prime}(x_i)
00067       \f]
00068       the accelerated value is
00069       \f[
00070       x_{\mathrm{acc},i} = x_i - (x_{i+1}-x_i)^2 / (x_{i+2} - 
00071       2 x_{i+1} + x_i)
00072       \f]
00073       We can only use the accelerated estimate after three iterations,
00074       and use the unaccelerated value until then.
00075 
00076       This class finds a root of a function a derivative. If the
00077       derivative is not analytically specified, it is most likely
00078       preferable to use of the alternatives, gsl_root_brent,
00079       cern_root, or cern_mroot_root. The function solve_de() performs
00080       the solution automatically, and a lower-level GSL-like interface
00081       with set() and iterate() is also provided.
00082 
00083       By default, this solver compares the present value of the root
00084       (\f$ \mathrm{root} \f$) to the previous value (\f$ \mathrm{x}
00085       \f$), and returns success if \f$ | \mathrm{root} - \mathrm{x} |
00086       < \mathrm{tol} \f$, where \f$ \mathrm{tol} = \mathrm{tol\_abs} +
00087       \mathrm{tolf2}~\mathrm{root} \f$ .
00088 
00089       If \ref test_residual is set to true, then the solver
00090       additionally requires that the absolute value of the function is
00091       less than \ref root::tol_rel.
00092 
00093       The original variable \c x_2 has been removed as it was unused
00094       in the original GSL code.
00095 
00096       \future There's some extra copying here which can probably
00097       be removed.
00098       \future Compare directly to GSL.
00099       \future This can probably be modified to shorten the step
00100       if the function goes out of bounds as in gsl_mroot_hybrids.
00101       
00102   */
00103 #ifdef DOXYGENP
00104   template<class func_t, class dfunc_t=func_t> class gsl_root_stef : 
00105   public root_de
00106 #else
00107   template<class func_t, class dfunc_t=func_t> class gsl_root_stef : 
00108   public root_de<func_t,dfunc_t>
00109 #endif
00110  {
00111       
00112   protected:
00113       
00114     /// Function value
00115     double f;
00116 
00117     /// Derivative value
00118     double df;
00119 
00120     /// Previous value of root
00121     double x_1;
00122 
00123     /// Root
00124     double x;
00125 
00126     /// Number of iterations
00127     int count;
00128 
00129     /// The function to solve
00130     func_t *fp;
00131 
00132     /// The derivative
00133     dfunc_t *dfp;
00134       
00135   public:
00136   
00137     gsl_root_stef() {
00138       test_residual=false;
00139       tolf2=1.0e-12;
00140     }
00141     
00142     /// Return the type, \c "gsl_root_stef".
00143     virtual const char *type() { return "gsl_root_stef"; }
00144 
00145     /// The present solution estimate
00146     double root;
00147 
00148     /** \brief The relative tolerance for subsequent solutions 
00149         (default \f$ 10^{-12} \f$)
00150     */
00151     double tolf2;
00152 
00153     /** \brief Perform an iteration
00154         
00155         After a successful iteration, \ref root contains the
00156         most recent value of the root. 
00157     */
00158     int iterate() {
00159       
00160       double x_new, f_new, df_new;
00161         
00162       double x_1t = x_1;
00163       double xt = x;
00164         
00165       if (df == 0.0) {
00166         this->last_conv=gsl_ezerodiv;
00167         O2SCL_CONV_RET("Derivative is zero in gsl_root_stef::iterate().",
00168                        o2scl::gsl_ezerodiv,this->err_nonconv);
00169       }
00170         
00171       x_new = xt - (f / df);
00172       
00173       // It is important that the derivative be evaluated first here,
00174       // because we want the last function evaluation to be an
00175       // evaluation for the returned root
00176       df_new=(*dfp)(x_new);
00177       f_new=(*fp)(x_new);
00178     
00179       x_1 = xt;
00180       x = x_new;
00181         
00182       f = f_new;
00183       df = df_new;
00184       
00185       if (!gsl_finite(f_new)) {
00186         std::string str="Function not finite (returned "+dtos(f_new)+
00187           ") in gsl_root_stef::iterate().";
00188         O2SCL_ERR_RET(str.c_str(),o2scl::gsl_ebadfunc);
00189       }
00190         
00191       if (count < 3) {
00192 
00193         root = x_new;
00194         count++;
00195 
00196       } else {
00197 
00198         double u = (xt - x_1t);
00199         double v = (x_new - 2 * xt + x_1t);
00200         
00201         if (v == 0) {
00202           // Avoid division by zero
00203           root = x_new; 
00204         } else {
00205           // Accelerated value
00206           root = x_1t - u * u / v; 
00207         }
00208       }
00209       
00210       if (!gsl_finite(df_new)) {
00211         std::string str="Derivative not finite (returned "+dtos(df_new)+
00212           ") in gsl_root_stef::iterate().";
00213         O2SCL_ERR_RET(str.c_str(),o2scl::gsl_ebadfunc);
00214       }
00215       
00216       return o2scl::gsl_success;
00217     }
00218 
00219     /** \brief Solve \c func using \c x as an initial
00220         guess using derivatives \c df.
00221     */
00222     virtual int solve_de(double &xx, func_t &fun, dfunc_t &dfun) {
00223       
00224       int status1, status2=gsl_continue, iter=0;
00225         
00226       status1=set(fun,dfun,xx);
00227 
00228       this->last_conv=0;
00229       while (status1==gsl_success && status2==gsl_continue && 
00230              iter<this->ntrial) {
00231         iter++;
00232 
00233         status1=iterate();
00234 
00235         // Compare present value to previous value
00236         status2=gsl_root_test_delta(root,xx,this->tol_abs,tolf2);
00237 
00238         if (test_residual && status2==gsl_success) {
00239           double y;
00240           y=fun(root);
00241           if (fabs(y)>=this->tol_rel) status2=gsl_continue;
00242         }
00243 
00244         if (this->verbose>0) {
00245           double fval;
00246           fval=fun(root);
00247           print_iter(root,fval,iter,fabs(root-xx),this->tol_abs*root,
00248                      "gsl_root_stef");
00249         }
00250         xx=root;
00251       }
00252       
00253       this->last_ntrial=iter;
00254 
00255       if (status1!=gsl_success || status2!=gsl_success) {
00256         int ret=o2scl::err_hnd->get_errno();
00257         return ret;
00258       }
00259       if (iter>=this->ntrial) {
00260         if (this->last_conv==0) this->last_conv=gsl_emaxiter;
00261         std::string str=((std::string)"Function solve_de() exceeded the ")+
00262           "maximum number of iterations, "+itos(this->ntrial)+".";
00263         O2SCL_CONV_RET(str.c_str(),gsl_emaxiter,this->err_nonconv);
00264       }
00265 
00266       return o2scl::gsl_success;
00267     }
00268     
00269     /// True if we should test the residual also (default false)
00270     bool test_residual;
00271 
00272     /** \brief Set the information for the solver
00273 
00274         Set the function, the derivative, the initial guess and
00275         the parameters.
00276     */
00277   int set(func_t &fun, dfunc_t &dfun, double guess) {
00278     
00279       fp=&fun;
00280       dfp=&dfun;
00281       root=guess;
00282       
00283       df=dfun(root);
00284       f=fun(root);
00285       
00286       x=root;
00287       x_1=0.0;
00288       count=1;
00289         
00290       return o2scl::gsl_success;
00291         
00292     }
00293 
00294   };
00295   
00296 #ifndef DOXYGENP
00297 }
00298 #endif
00299 
00300 #endif
00301 
 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.