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_MROOT_ROOT_H 00024 #define O2SCL_CERN_MROOT_ROOT_H 00025 00026 #include <o2scl/root.h> 00027 00028 #ifndef DOXYGENP 00029 namespace o2scl { 00030 #endif 00031 00032 /** 00033 \brief One-dimensional version of cern_mroot 00034 00035 This one-dimensional root-finding routine, based on cern_mroot, 00036 is probably slower than the more typical 1-d routines, but also 00037 tends to converge for a larger class of functions than 00038 cern_root, gsl_root_brent, or gsl_root_stef. It has been 00039 modified from cern_mroot and slightly optimized, but has the 00040 same basic behavior. 00041 00042 If \f$ x_i \f$ denotes the current iteration, and \f$ 00043 x^{\prime}_i \f$ denotes the previous iteration, then the 00044 calculation is terminated if either (or both) of the following 00045 tests is successful 00046 \f[ 00047 1:\quad \mathrm{max} | f_i(x) | \leq \mathrm{tolf} 00048 \f] 00049 \f[ 00050 2:\quad \mathrm{max} |x_i-x^{\prime}_i| \leq 00051 \mathrm{tolx} \times \mathrm{max} | x_i | 00052 \f] 00053 00054 \note This code has not been checked to ensure that it cannot 00055 fail to solve the equations without calling the error handler 00056 and returning a non-zero value. Until then, the solution may 00057 need to be checked explicitly by the caller. 00058 00059 \future Double-check this class to make sure it cannot fail 00060 while returning 0 for success. 00061 */ 00062 #ifdef DOXYGENP 00063 template<class param_t=int, class func_t=funct<param_t> > 00064 class cern_mroot_root : public root 00065 #else 00066 template<class param_t=int, class func_t=funct<param_t> > 00067 class cern_mroot_root : public root<param_t,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::tolx 00097 is too small or the Jacobian is nearly singular 00098 or the variables are badly scaled. \n 00099 9 - Either root::tolf or root::tolx is not greater than zero. 00100 00101 */ 00102 int get_info() { return info; } 00103 00104 /** 00105 \brief Maximum number of function evaluations 00106 00107 If \f$ \mathrm{maxf}\leq 0 \f$, then 200 (which is the CERNLIB 00108 default) is used. The default value of \c maxf is zero which 00109 then implies the default from CERNLIB. 00110 */ 00111 int maxf; 00112 00113 /// Return the type, \c "cern_mroot_root". 00114 virtual const char *type() { return "cern_mroot_root"; } 00115 00116 /** \brief The original scale parameter from CERNLIB (default 10.0) 00117 */ 00118 double scale; 00119 00120 /** \brief The smallest floating point number 00121 (default \f$ \sim 1.49012 \times 10^{-8} \f$) 00122 00123 The original prescription from CERNLIB for \c eps is 00124 given below: 00125 \verbatim 00126 #if !defined(CERNLIB_DOUBLE) 00127 PARAMETER (EPS = 0.84293 69702 17878 97282 52636 392E-07) 00128 #endif 00129 #if defined(CERNLIB_IBM) 00130 PARAMETER (EPS = 0.14901 16119 38476 562D-07) 00131 #endif 00132 #if defined(CERNLIB_VAX) 00133 PARAMETER (EPS = 0.37252 90298 46191 40625D-08) 00134 #endif 00135 #if (defined(CERNLIB_UNIX))&&(defined(CERNLIB_DOUBLE)) 00136 PARAMETER (EPS = 0.14901 16119 38476 600D-07) 00137 #endif 00138 \endverbatim 00139 00140 \future This number should probably default to one of the 00141 GSL tolerances. 00142 */ 00143 double eps; 00144 00145 /// Solve \c func using \c x as an initial guess, returning \c x. 00146 virtual int solve(double &ux, param_t &pa, func_t &func) { 00147 00148 int it=0; 00149 double fky; 00150 00151 this->last_conv=0; 00152 00153 int lmaxf; 00154 if (maxf<=0) lmaxf=200; 00155 else lmaxf=maxf; 00156 00157 info=0; 00158 00159 if (this->tolf<=0.0 || this->tolx<=0.0) { 00160 info=9; 00161 O2SCL_ERR_RET("Invalid arguments in cern_mroot_root::solve().", 00162 gsl_efailed); 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 func(w1arr,farr,pa); 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 func(w2arr,farr,pa); 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->tolf, 00279 "cern_mroot_root"); 00280 00281 // Tests for convergence 00282 00283 if (fnorm<=this->tolf) info=1; 00284 if (difit<=this->tolx*xnorm && lcv) info=2; 00285 if (fnorm<=this->tolf && 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 tolx 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 and provided under the GNU Free Documentation License. See License Information for details.
Project hosting provided by
,
O2scl Sourceforge Project Page