cern_root.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 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   /** 
00033       \brief One-dimensional root-finding routine (CERNLIB)
00034       
00035       This class attempts to find \f$ x_0 \f$ and \f$ x_1 \f$ in \f$
00036       [a,b] \f$ such that \f$ f(x_0) f(x_1) \leq 0 \f$, \f$ |f(x_0)|
00037       \leq|f(x_1)| \f$, and \f$ | x_0-x_1| \leq
00038       2~\mathrm{tolx}~(1+|x_0|) \f$.
00039       
00040       The variable cern_root::tolx 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 tolx 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       solve_bkt() returns 0 for success, \ref gsl_einval if the root
00050       is not initially bracketed, and \ref gsl_emaxiter if the number
00051       of function evaluations is greater than cern_root::ntrial.
00052     
00053       Based on CERNLIB routine DZEROX which is based on \ref Bus75.
00054     
00055   */
00056   template<class param_t, class func_t=funct<param_t> > 
00057     class cern_root : public root<param_t,func_t>
00058     {
00059 
00060 #ifndef DOXYGEN_INTERNAL
00061 
00062       protected:
00063       
00064       /** 
00065           \brief Internal storage for the mode
00066 
00067           This internal variable is actually defined to be smaller by
00068           1 than the "mode" as it is defined in the CERNLIB
00069           documentation in order to avoid needless subtraction in
00070           solve_bkt().
00071       */
00072       int mode;
00073       
00074       /// FORTRAN-like function for sign
00075       inline double sign(double a, double b) {
00076         if (b>=0.0) return fabs(a);
00077         return -fabs(a);
00078       }
00079       
00080       friend class io_tlate<cern_root>;
00081       
00082 #endif
00083       
00084       public:
00085       
00086       cern_root()
00087       {
00088         mode=0;
00089         this->tolx=1.0e-8;
00090         this->ntrial=200;
00091         this->over_bkt=true;
00092       }
00093       
00094       /** 
00095           \brief Set mode of solution (1 or 2)
00096          
00097           - \c 1 should be used for simple functions where the cost is
00098           inexpensive in comparison to one iteration of solve_bkt(),
00099           or functions which have a pole near the root (this is the
00100           default).
00101           - \c 2 should be used for more time-consuming functions.
00102  
00103           If an integer other than \c 1 or \c 2 is specified, \c 1 is
00104           assumed.
00105          
00106       */
00107       int set_mode(int m) {
00108         if (m!=1 && m!=2) {
00109           mode=0;
00110           set_err_ret("Invalid mode in cern_root::set_mode().",
00111                       o2scl::gsl_einval);
00112         }
00113         mode=m-1;
00114         return 0;
00115       }
00116 
00117       /// Return the type, \c "cern_root".
00118       virtual const char *type() { return "cern_root"; }
00119 
00120       /** \brief Solve \c func in region \f$ x_1<x<x_2 \f$ returning  
00121           \f$ x_1 \f$.
00122       */
00123       virtual int solve_bkt(double &x1, double x2, param_t &pa, 
00124                             func_t &func) 
00125       {
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     
00134         func(x1,fb,pa);
00135         func(x2,fa,pa);
00136         
00137         if (fa*fb>0.0) {
00138           set_err_ret
00139             ("Endpoints don't bracket function in cern_root::solve_bkt().",
00140              o2scl::gsl_einval);
00141         }
00142         
00143         atl=fabs(this->tolx);
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               set_err_ret
00214                 ("Too many function calls in cern_root::solve_bkt().",
00215                  o2scl::gsl_emaxiter);
00216             }
00217 
00218             func(b,fb,pa);
00219 
00220             if (fb==0.0 || sign(1.0,fc)==sign(1.0,fb)) {
00221               loop=1;
00222             } else if (w==hb) {
00223               loop=2;
00224             } else {
00225               ie++;
00226               loop=3;
00227             }
00228           } else {
00229             loop=0;
00230           }
00231         } while (loop>0);
00232         x1=c;
00233         this->last_ntrial=mf;
00234         return o2scl::gsl_success;
00235       }
00236             
00237     };
00238 
00239 #ifndef DOXYGENP
00240   template<> int io_tlate<cern_root<void *,funct<void *> > >::input
00241     (cinput *co, in_file_format *ins, cern_root<void *, funct<void *> > *ro);
00242   template<> int io_tlate<cern_root<void *,funct<void *> > >::output
00243     (coutput *co, out_file_format *outs, 
00244      cern_root<void *, funct<void *> > *ro);
00245   template<> const char *io_tlate<cern_root<void *,funct<void *> > >::type();
00246 #endif
00247   
00248   typedef io_tlate<cern_root<void *,funct<void *> > > cern_root_io_type;
00249 
00250 #ifndef DOXYGENP
00251 }
00252 #endif
00253   
00254 #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