![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
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
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).