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_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 the CERNLIB routines RZEROX and DZEROX, which was 00054 based on \ref Bus75 and is documented at 00055 http://wwwasdoc.web.cern.ch/wwwasdoc/shortwrupsdir/c200/top.html 00056 */ 00057 template<class param_t, class func_t=funct<param_t> > 00058 class cern_root : public root<param_t,func_t> 00059 { 00060 00061 #ifndef DOXYGEN_INTERNAL 00062 00063 protected: 00064 00065 /** 00066 \brief Internal storage for the mode 00067 00068 This internal variable is actually defined to be smaller by 00069 1 than the "mode" as it is defined in the CERNLIB 00070 documentation in order to avoid needless subtraction in 00071 solve_bkt(). 00072 */ 00073 int mode; 00074 00075 /// FORTRAN-like function for sign 00076 inline double sign(double a, double b) { 00077 if (b>=0.0) return fabs(a); 00078 return -fabs(a); 00079 } 00080 00081 friend class io_tlate<cern_root>; 00082 00083 #endif 00084 00085 public: 00086 00087 cern_root() 00088 { 00089 mode=0; 00090 this->tolx=1.0e-8; 00091 this->ntrial=200; 00092 this->over_bkt=true; 00093 } 00094 00095 /** 00096 \brief Set mode of solution (1 or 2) 00097 00098 - \c 1 should be used for simple functions where the cost is 00099 inexpensive in comparison to one iteration of solve_bkt(), 00100 or functions which have a pole near the root (this is the 00101 default). 00102 - \c 2 should be used for more time-consuming functions. 00103 00104 If an integer other than \c 1 or \c 2 is specified, \c 1 is 00105 assumed. 00106 00107 */ 00108 int set_mode(int m) { 00109 if (m!=1 && m!=2) { 00110 mode=0; 00111 set_err_ret("Invalid mode in cern_root::set_mode().", 00112 o2scl::gsl_einval); 00113 } 00114 mode=m-1; 00115 return 0; 00116 } 00117 00118 /// Return the type, \c "cern_root". 00119 virtual const char *type() { return "cern_root"; } 00120 00121 /** \brief Solve \c func in region \f$ x_1<x<x_2 \f$ returning 00122 \f$ x_1 \f$. 00123 */ 00124 virtual int solve_bkt(double &x1, double x2, param_t &pa, 00125 func_t &func) 00126 { 00127 00128 double im1[2]={2.0,3.0}, im2[2]={-1.0,3.0}, c=0.0, fa, fb; 00129 double atl, a, b, mft; 00130 double fc=0.0, d=0.0, fd=0.0, tol, h, hb, w, p, q, fdb, fda, f=0.0; 00131 bool lmt[2]; 00132 int ie=0, loop, mf; 00133 char ch; 00134 00135 func(x1,fb,pa); 00136 func(x2,fa,pa); 00137 00138 if (fa*fb>0.0) { 00139 set_err_ret 00140 ("Endpoints don't bracket function in cern_root::solve_bkt().", 00141 o2scl::gsl_einval); 00142 } 00143 00144 atl=fabs(this->tolx); 00145 b=x1; 00146 a=x2; 00147 lmt[1]=true; 00148 mf=2; 00149 loop=1; 00150 do { 00151 if (loop==1) { 00152 c=a; 00153 fc=fa; 00154 ie=0; 00155 } else if (loop==2) { 00156 ie=0; 00157 } 00158 if (fabs(fc)<fabs(fb)) { 00159 if (c!=a) { 00160 d=a; 00161 fd=fa; 00162 } 00163 a=b; 00164 b=c; 00165 c=a; 00166 fa=fb; 00167 fb=fc; 00168 fc=fa; 00169 } 00170 tol=atl*(1.0+fabs(c)); 00171 h=0.5*(c+b); 00172 hb=h-b; 00173 00174 if (this->verbose>0) { 00175 this->print_iter(c,fc,mf-2,fabs(hb),tol,"cern_root"); 00176 } 00177 00178 if (fabs(hb)>tol) { 00179 if (ie>im1[mode]) { 00180 w=hb; 00181 } else { 00182 tol*=sign(1.0,hb); 00183 p=(b-a)*fb; 00184 lmt[0]=(ie<=1); 00185 if (lmt[mode]) { 00186 q=fa-fb; 00187 lmt[1]=false; 00188 } else { 00189 fdb=(fd-fb)/(d-b); 00190 fda=(fd-fa)/(d-a); 00191 p*=fda; 00192 q=fdb*fa-fda*fb; 00193 } 00194 if (p<0.0) { 00195 p=-p; 00196 q=-q; 00197 } 00198 if (ie==im2[mode]) p+=p; 00199 if (p==0.0 || p<=q*tol) { 00200 w=tol; 00201 } else if (p<hb*q) { 00202 w=p/q; 00203 } else { 00204 w=hb; 00205 } 00206 } 00207 d=a; 00208 a=b; 00209 fd=fa; 00210 fa=fb; 00211 b+=w; 00212 mf++; 00213 if (mf>this->ntrial) { 00214 set_err_ret 00215 ("Too many function calls in cern_root::solve_bkt().", 00216 o2scl::gsl_emaxiter); 00217 } 00218 00219 func(b,fb,pa); 00220 00221 if (fb==0.0 || sign(1.0,fc)==sign(1.0,fb)) { 00222 loop=1; 00223 } else if (w==hb) { 00224 loop=2; 00225 } else { 00226 ie++; 00227 loop=3; 00228 } 00229 } else { 00230 loop=0; 00231 } 00232 } while (loop>0); 00233 x1=c; 00234 this->last_ntrial=mf; 00235 return o2scl::gsl_success; 00236 } 00237 00238 }; 00239 00240 #ifndef DOXYGENP 00241 template<> int io_tlate<cern_root<void *,funct<void *> > >::input 00242 (cinput *co, in_file_format *ins, cern_root<void *, funct<void *> > *ro); 00243 template<> int io_tlate<cern_root<void *,funct<void *> > >::output 00244 (coutput *co, out_file_format *outs, 00245 cern_root<void *, funct<void *> > *ro); 00246 template<> const char *io_tlate<cern_root<void *,funct<void *> > >::type(); 00247 #endif 00248 00249 typedef io_tlate<cern_root<void *,funct<void *> > > cern_root_io_type; 00250 00251 #ifndef DOXYGENP 00252 } 00253 #endif 00254 00255 #endif
Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.
Project hosting provided by
,
O2scl Sourceforge Project Page