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 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
,
O2scl Sourceforge Project Page