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