Object-oriented Scientific Computing Library: Version 0.910
cern_root.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 #ifndef O2SCL_CERN_ROOT_H
00024 #define O2SCL_CERN_ROOT_H
00025 
00026 #include <o2scl/root.h>
00027 
00028 #ifndef DOXYGENP
00029 namespace o2scl {
00030 #endif
00031 
00032   /** \brief One-dimensional root-finding routine (CERNLIB)
00033       
00034       This class attempts to find \f$ x_1 \f$ and \f$ x_2 \f$ in \f$
00035       [a,b] \f$ such that \f$ f(x_1) f(x_2) \leq 0 \f$, \f$ |f(x_1)|
00036       \leq|f(x_2)| \f$, and \f$ | x_1-x_2| \leq
00037       2~\mathrm{tol\_abs}~(1+|x_0|) \f$. The function solve_bkt() requires
00038       inputs \c x1 and \c x2 such that \f$ f(x_1) f(x_2) \leq 0 \f$. 
00039       
00040       The variable cern_root::tol_abs defaults to \f$ 10^{-8} \f$ and
00041       cern_root::ntrial defaults to 200.  
00042       \comment 
00043       I'm not sure why I chose these values for tol_abs and ntrial above,
00044       as it doesn't seem to me that these values are suggested in
00045       CERNLIB. However, they're reasonable so I'll leave them in for
00046       now. 
00047       \endcomment
00048         
00049       The function solve_bkt() returns 0 for success, \ref gsl_einval
00050       if the root is not initially bracketed, and \ref gsl_emaxiter if
00051       the number of function evaluations is greater than
00052       cern_root::ntrial.
00053     
00054       Based on the CERNLIB routines RZEROX and DZEROX, which was 
00055       based on \ref Bus75 and is documented at
00056       http://wwwasdoc.web.cern.ch/wwwasdoc/shortwrupsdir/c200/top.html
00057   */
00058   template<class func_t=funct> class cern_root : public root_bkt<func_t> {
00059     
00060 #ifndef DOXYGEN_INTERNAL
00061 
00062   protected:
00063       
00064   /** \brief Internal storage for the mode
00065 
00066       This internal variable is actually defined to be smaller by
00067       1 than the "mode" as it is defined in the CERNLIB
00068       documentation in order to avoid needless subtraction in
00069       solve_bkt().
00070   */
00071   int mode;
00072       
00073   /// FORTRAN-like function for sign
00074   inline double sign(double a, double b) {
00075     if (b>=0.0) return fabs(a);
00076     return -fabs(a);
00077   }
00078       
00079 #endif
00080       
00081   public:
00082       
00083   cern_root() {
00084     mode=0;
00085     this->tol_abs=1.0e-8;
00086     this->ntrial=200;
00087   }
00088       
00089   /** \brief Set mode of solution (1 or 2)
00090          
00091       - \c 1 should be used for simple functions where the cost is
00092       inexpensive in comparison to one iteration of solve_bkt(),
00093       or functions which have a pole near the root (this is the
00094       default).
00095       - \c 2 should be used for more time-consuming functions.
00096  
00097       If an integer other than \c 1 or \c 2 is specified, 
00098       the error handler is called.
00099   */
00100   int set_mode(int m) {
00101     if (m!=1 && m!=2) {
00102       O2SCL_ERR_RET("Invalid mode in cern_root::set_mode().",
00103                     o2scl::gsl_einval);
00104     }
00105     mode=m-1;
00106     return 0;
00107   }
00108 
00109   /// Return the type, \c "cern_root".
00110   virtual const char *type() { return "cern_root"; }
00111 
00112   /** \brief Solve \c func in region \f$ x_1<x<x_2 \f$ returning  
00113       \f$ x_1 \f$.
00114 
00115       The parameters \c x1 and \c x2 should be set so that \f$
00116       f(x_1) f(x_2) \leq 0 \f$ before calling solve_bkt(). If this
00117       is not the case, the error handler will be called and
00118       the solver will fail.
00119           
00120       This function converges unless the number of iterations is
00121       larger than root::ntrial, in which case root::last_conv is
00122       set to \ref gsl_emaxiter and the error handler is called if
00123       root::err_nonconv is true.
00124   */
00125   virtual int solve_bkt(double &x1, double x2, func_t &func) {
00126         
00127     double im1[2]={2.0,3.0}, im2[2]={-1.0,3.0}, c=0.0, fa, fb;
00128     double atl, a, b, mft;
00129     double fc=0.0, d=0.0, fd=0.0, tol, h, hb, w, p, q, fdb, fda, f=0.0;
00130     bool lmt[2];
00131     int ie=0, loop, mf;
00132     char ch;
00133     this->last_conv=0;
00134     
00135     fb=func(x1);
00136     fa=func(x2);
00137         
00138     if (fa*fb>0.0) {
00139       O2SCL_ERR2_RET("Endpoints don't bracket function in ",
00140                      "cern_root::solve_bkt().",gsl_einval);
00141     }
00142         
00143     atl=fabs(this->tol_abs);
00144     b=x1;
00145     a=x2;
00146     lmt[1]=true;
00147     mf=2;
00148     loop=1;
00149     do {
00150       if (loop==1) {
00151         c=a;
00152         fc=fa;
00153         ie=0;
00154       } else if (loop==2) {
00155         ie=0;
00156       }
00157       if (fabs(fc)<fabs(fb)) {
00158         if (c!=a) {
00159           d=a;
00160           fd=fa;
00161         }
00162         a=b;
00163         b=c;
00164         c=a;
00165         fa=fb;
00166         fb=fc;
00167         fc=fa;
00168       }
00169       tol=atl*(1.0+fabs(c));
00170       h=0.5*(c+b);
00171       hb=h-b;
00172       
00173       if (this->verbose>0) {
00174         this->print_iter(c,fc,mf-2,fabs(hb),tol,"cern_root");
00175       }
00176 
00177       if (fabs(hb)>tol) {
00178         if (ie>im1[mode]) {
00179           w=hb;
00180         } else {
00181           tol*=sign(1.0,hb);
00182           p=(b-a)*fb;
00183           lmt[0]=(ie<=1);
00184           if (lmt[mode]) {
00185             q=fa-fb;
00186             lmt[1]=false;
00187           } else {
00188             fdb=(fd-fb)/(d-b);
00189             fda=(fd-fa)/(d-a);
00190             p*=fda;
00191             q=fdb*fa-fda*fb;
00192           }
00193           if (p<0.0) {
00194             p=-p;
00195             q=-q;
00196           }
00197           if (ie==im2[mode]) p+=p;
00198           if (p==0.0 || p<=q*tol) {
00199             w=tol;
00200           } else if (p<hb*q) {
00201             w=p/q;
00202           } else {
00203             w=hb;
00204           }
00205         }
00206         d=a;
00207         a=b;
00208         fd=fa;
00209         fa=fb;
00210         b+=w;
00211         mf++;
00212         if (mf>this->ntrial) {
00213           this->last_conv=gsl_emaxiter;
00214           if (this->err_nonconv) {
00215             O2SCL_ERR2_RET("Too many function calls in ",
00216                            "cern_root::solve_bkt().",gsl_emaxiter);
00217           } else {
00218             return gsl_emaxiter;
00219           }
00220         }
00221             
00222         fb=func(b);
00223 
00224         if (fb==0.0 || sign(1.0,fc)==sign(1.0,fb)) {
00225           loop=1;
00226         } else if (w==hb) {
00227           loop=2;
00228         } else {
00229           ie++;
00230           loop=3;
00231         }
00232       } else {
00233         loop=0;
00234       }
00235     } while (loop>0);
00236     x1=c;
00237     this->last_ntrial=mf;
00238     return o2scl::gsl_success;
00239   }
00240             
00241   };
00242 
00243 #ifndef DOXYGENP
00244 }
00245 #endif
00246   
00247 #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.