![]() |
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_MROOT_ROOT_H 00024 #define O2SCL_CERN_MROOT_ROOT_H 00025 00026 #include <string> 00027 00028 #include <o2scl/root.h> 00029 00030 #ifndef DOXYGENP 00031 namespace o2scl { 00032 #endif 00033 00034 /** \brief One-dimensional version of cern_mroot 00035 00036 This one-dimensional root-finding routine, based on cern_mroot, 00037 is probably slower than the more typical 1-d routines, but also 00038 tends to converge for a larger class of functions than 00039 cern_root, gsl_root_brent, or gsl_root_stef. It has been 00040 modified from cern_mroot and slightly optimized, but has the 00041 same basic behavior. 00042 00043 If \f$ x_i \f$ denotes the current iteration, and \f$ 00044 x^{\prime}_i \f$ denotes the previous iteration, then the 00045 calculation is terminated if either (or both) of the following 00046 tests is successful 00047 \f[ 00048 1:\quad \mathrm{max} | f_i(x) | \leq \mathrm{tol\_rel} 00049 \f] 00050 \f[ 00051 2:\quad \mathrm{max} |x_i-x^{\prime}_i| \leq 00052 \mathrm{tol\_abs} \times \mathrm{max} | x_i | 00053 \f] 00054 00055 \note This code has not been checked to ensure that it cannot 00056 fail to solve the equations without calling the error handler 00057 and returning a non-zero value. Until then, the solution may 00058 need to be checked explicitly by the caller. 00059 00060 \future Double-check this class to make sure it cannot fail 00061 while returning 0 for success. 00062 */ 00063 #ifdef DOXYGENP 00064 template<class func_t=funct> class cern_mroot_root : public root 00065 #else 00066 template<class func_t=funct> class cern_mroot_root : 00067 public root<func_t> 00068 #endif 00069 { 00070 00071 public: 00072 00073 cern_mroot_root() { 00074 info=0; 00075 eps=0.1490116119384766e-07; 00076 scale=10.0; 00077 maxf=0; 00078 } 00079 00080 virtual ~cern_mroot_root() {} 00081 00082 /** \brief Get the value of \c INFO from the last call to solve() 00083 (default 0) 00084 00085 The value of info is assigned according to the following list. 00086 The values 1-8 are the standard behavior from CERNLIB. 00087 0 - The function solve() has not been called. 00088 1 - Test 1 was successful. \n 00089 2 - Test 2 was successful. \n 00090 3 - Both tests were successful. \n 00091 4 - Number of iterations is greater than cern_mroot_root::maxf. \n 00092 5 - Approximate (finite difference) Jacobian matrix is 00093 singular. \n 00094 6 - Iterations are not making good progress. \n 00095 7 - Iterations are diverging. \n 00096 8 - Iterations are converging, but either cern_mroot_root::tol_abs 00097 is too small or the Jacobian is nearly singular 00098 or the variables are badly scaled. \n 00099 9 - Either root::tol_rel or root::tol_abs is not greater than zero. 00100 00101 */ 00102 int get_info() { return info; } 00103 00104 /** \brief Maximum number of function evaluations 00105 00106 If \f$ \mathrm{maxf}\leq 0 \f$, then 200 (which is the CERNLIB 00107 default) is used. The default value of \c maxf is zero which 00108 then implies the default from CERNLIB. 00109 */ 00110 int maxf; 00111 00112 /// Return the type, \c "cern_mroot_root". 00113 virtual const char *type() { return "cern_mroot_root"; } 00114 00115 /** \brief The original scale parameter from CERNLIB (default 10.0) 00116 */ 00117 double scale; 00118 00119 /** \brief The smallest floating point number 00120 (default \f$ \sim 1.49012 \times 10^{-8} \f$) 00121 00122 The original prescription from CERNLIB for \c eps is 00123 given below: 00124 \verbatim 00125 #if !defined(CERNLIB_DOUBLE) 00126 PARAMETER (EPS = 0.84293 69702 17878 97282 52636 392E-07) 00127 #endif 00128 #if defined(CERNLIB_IBM) 00129 PARAMETER (EPS = 0.14901 16119 38476 562D-07) 00130 #endif 00131 #if defined(CERNLIB_VAX) 00132 PARAMETER (EPS = 0.37252 90298 46191 40625D-08) 00133 #endif 00134 #if (defined(CERNLIB_UNIX))&&(defined(CERNLIB_DOUBLE)) 00135 PARAMETER (EPS = 0.14901 16119 38476 600D-07) 00136 #endif 00137 \endverbatim 00138 00139 \future This number should probably default to one of the 00140 GSL tolerances. 00141 */ 00142 double eps; 00143 00144 /// Solve \c func using \c x as an initial guess, returning \c x. 00145 virtual int solve(double &ux, func_t &func) { 00146 00147 int it=0; 00148 double fky; 00149 00150 this->last_conv=0; 00151 00152 int lmaxf; 00153 if (maxf<=0) lmaxf=200; 00154 else lmaxf=maxf; 00155 00156 info=0; 00157 00158 if (this->tol_rel<=0.0 || this->tol_abs<=0.0) { 00159 info=9; 00160 std::string str="Invalid value of tol_rel ("+dtos(this->tol_rel)+ 00161 ") or tol_abs ("+dtos(this->tol_abs)+") in cern_mroot_root::solve()."; 00162 O2SCL_ERR_RET(str.c_str(),gsl_einval); 00163 } 00164 00165 int iflag=0, numf=0, nfcall=0, nier6=-1, nier7=-1, nier8=0; 00166 double fnorm=0.0, difit=0.0, xnorm=0.0; 00167 bool set=false; 00168 00169 if (xnorm<fabs(ux)) { 00170 xnorm=fabs(ux); 00171 set=true; 00172 } 00173 00174 double delta=scale*xnorm; 00175 if (set==false) delta=scale; 00176 00177 double wmat, farr, w0arr, w1arr, w2arr; 00178 00179 bool solve_done=false; 00180 while (solve_done==false) { 00181 00182 int nsing=1; 00183 double fnorm1=fnorm; 00184 double difit1=difit; 00185 fnorm=0.0; 00186 00187 // Compute step H for the divided difference which approximates 00188 // the K-th row of the Jacobian matrix 00189 00190 double h=eps*xnorm; 00191 if (h==0.0) h=eps; 00192 00193 wmat=h; 00194 w1arr=ux; 00195 00196 // Enter a subiteration 00197 00198 iflag=0; 00199 00200 farr=func(w1arr); 00201 00202 fky=farr; 00203 nfcall++; 00204 numf=nfcall; 00205 if (fnorm<fabs(fky)) fnorm=fabs(fky); 00206 00207 // Compute the K-th row of the Jacobian matrix 00208 00209 w2arr=w1arr+wmat; 00210 00211 farr=func(w2arr); 00212 00213 double fkz=farr; 00214 nfcall++; 00215 numf=nfcall; 00216 w0arr=fkz-fky; 00217 00218 farr=fky; 00219 00220 // Compute the Householder transformation to reduce the K-th row 00221 // of the Jacobian matrix to a multiple of the K-th unit vector 00222 00223 double eta=0.0; 00224 if (eta<fabs(w0arr)) eta=fabs(w0arr); 00225 00226 if (eta!=0.0) { 00227 nsing--; 00228 double sknorm=0.0; 00229 00230 w0arr/=eta; 00231 sknorm+=w0arr*w0arr; 00232 00233 sknorm=sqrt(sknorm); 00234 if (w0arr<0.0) sknorm=-sknorm; 00235 w0arr+=sknorm; 00236 00237 // Apply the transformation 00238 00239 w2arr=0.0; 00240 w2arr+=w0arr*wmat; 00241 double temp=w0arr/(sknorm*w0arr); 00242 wmat-=temp*w2arr; 00243 00244 // Compute the subiterate 00245 00246 w0arr=sknorm*eta; 00247 double temp2=fky/w0arr; 00248 if (h*fabs(temp2)>delta) 00249 temp2=(temp2>=0.0) ? fabs(delta/h) : -fabs(delta/h); 00250 w1arr+=temp2*wmat; 00251 } 00252 00253 // Compute the norms of the iterate and correction vector 00254 00255 xnorm=0.0; 00256 difit=0.0; 00257 00258 if (xnorm<fabs(w1arr)) xnorm=fabs(w1arr); 00259 if (difit<fabs(ux-w1arr)) difit=fabs(ux-w1arr); 00260 ux=w1arr; 00261 00262 // Update the bound on the correction vector 00263 00264 if(delta<scale*xnorm) delta=scale*xnorm; 00265 00266 // Determine the progress of the iteration 00267 00268 bool lcv=(fnorm<fnorm1 && difit<difit1 && nsing==0); 00269 nier6++; 00270 nier7++; 00271 nier8++; 00272 if (lcv) nier6=0; 00273 if (fnorm<fnorm1 || difit<difit1) nier7=0; 00274 if (difit>eps*xnorm) nier8=0; 00275 00276 // Print iteration information 00277 00278 if (this->verbose>0) print_iter(ux,farr,++it,fnorm,this->tol_rel, 00279 "cern_mroot_root"); 00280 00281 // Tests for convergence 00282 00283 if (fnorm<=this->tol_rel) info=1; 00284 if (difit<=this->tol_abs*xnorm && lcv) info=2; 00285 if (fnorm<=this->tol_rel && info==2) info=3; 00286 if (info!=0) { 00287 return 0; 00288 } 00289 00290 // Tests for termination 00291 00292 if (numf>=lmaxf) { 00293 info=4; 00294 this->last_conv=gsl_emaxiter; 00295 O2SCL_CONV_RET("Too many iterations in cern_mroot_root::solve().", 00296 gsl_emaxiter,this->err_nonconv); 00297 } 00298 if (nsing==1) { 00299 info=5; 00300 this->last_conv=gsl_esing; 00301 O2SCL_CONV2_RET("Jacobian matrix singular in ", 00302 "cern_mroot_root::solve().", 00303 gsl_esing,this->err_nonconv); 00304 } 00305 if (nier6==5) { 00306 info=6; 00307 this->last_conv=gsl_enoprog; 00308 O2SCL_CONV_RET("No progress in cern_mroot_root::solve().", 00309 gsl_enoprog,this->err_nonconv); 00310 } 00311 if (nier7==3) { 00312 info=7; 00313 this->last_conv=gsl_erunaway; 00314 O2SCL_CONV_RET("Iterations diverging in cern_mroot_root::solve().", 00315 gsl_erunaway,this->err_nonconv); 00316 } 00317 if (nier8==4) { 00318 info=8; 00319 this->last_conv=gsl_efailed; 00320 std::string s2="Variable tol_abs too small, J singular, "; 00321 s2+="or bad scaling in cerm_mroot_root::solve()."; 00322 O2SCL_CONV(s2.c_str(),gsl_efailed,this->err_nonconv); 00323 } 00324 00325 // Exit if necessary 00326 00327 if (info!=0) return gsl_efailed; 00328 00329 } 00330 00331 return 0; 00332 } 00333 00334 #ifndef DOXYGEN_INTERNAL 00335 00336 protected: 00337 00338 /// Internal storage for the value of \c info 00339 int info; 00340 00341 #endif 00342 00343 }; 00344 00345 #ifndef DOXYGENP 00346 } 00347 #endif 00348 00349 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).