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_GSL_ROOT_STEF_H 00024 #define O2SCL_GSL_ROOT_STEF_H 00025 00026 #include <gsl/gsl_math.h> 00027 #include <gsl/gsl_roots.h> 00028 #include <o2scl/root.h> 00029 00030 #ifndef DOXYGENP 00031 namespace o2scl { 00032 #endif 00033 00034 /** 00035 \brief Steffenson equation solver (GSL) 00036 00037 This class finds a root of a function a derivative. If the 00038 derivative is not analytically specified, it is most likely 00039 preferable to use of the alternatives, gsl_root_brent, 00040 cern_root, or cern_mroot_root. The function solve_de() performs 00041 the solution automatically, and a lower-level GSL-like interface 00042 with set() and iterate() is also provided. 00043 00044 By default, this solver compares the present value of the root 00045 (\f$ root \f$) to the previous value (\f$ x \f$), and returns 00046 success if \f$ | root - x | < tol \f$, where \f$ tol = tolx + 00047 tolf2 root \f$. 00048 00049 If \ref test_residual is set to true, then the solver 00050 additionally requires that the absolute value of the function 00051 is less than \ref root::tolf. 00052 00053 The original variable \c x_2 has been removed as it was unused 00054 in the original GSL code. 00055 00056 \future There's some extra copying here which can probably 00057 be removed. 00058 \future Compare directly to GSL. 00059 00060 */ 00061 template<class param_t, class func_t, class dfunc_t> class gsl_root_stef : 00062 public o2scl::root<param_t,func_t,dfunc_t> { 00063 00064 protected: 00065 00066 /// Function value 00067 double f; 00068 00069 /// Derivative value 00070 double df; 00071 00072 /// Previous value of root 00073 double x_1; 00074 00075 /// Root 00076 double x; 00077 00078 /// Number of iterations 00079 int count; 00080 00081 /// The function to solve 00082 func_t *fp; 00083 00084 /// The derivative 00085 dfunc_t *dfp; 00086 00087 /// The function parameters 00088 param_t *params; 00089 00090 public: 00091 00092 gsl_root_stef() { 00093 this->over_de=true; 00094 test_residual=false; 00095 tolf2=1.0e-12; 00096 } 00097 00098 /// Return the type, \c "gsl_root_stef". 00099 virtual const char *type() { return "gsl_root_stef"; } 00100 00101 /// The present solution estimate 00102 double root; 00103 00104 /** \brief The relative tolerance for subsequent solutions 00105 (default \f$ 10^{-12} \f$) 00106 */ 00107 double tolf2; 00108 00109 /** 00110 \brief Perform an iteration 00111 00112 After a successful iteration, \ref root contains the 00113 most recent value of the root. 00114 */ 00115 int iterate() { 00116 00117 double x_new, f_new, df_new; 00118 00119 double x_1t = x_1; 00120 double xt = x; 00121 00122 if (df == 0.0) { 00123 set_err_ret("Derivative is zero in gsl_root_stef::iterate().", 00124 o2scl::gsl_ezerodiv); 00125 } 00126 00127 x_new = xt - (f / df); 00128 00129 // It is important that the derivative be evaluated first here, 00130 // because we want the last function evaluation to be an 00131 // evaluation for the returned root 00132 (*dfp)(x_new,df_new,*params); 00133 (*fp)(x_new,f_new,*params); 00134 00135 x_1 = xt; 00136 x = x_new; 00137 00138 f = f_new; 00139 df = df_new; 00140 00141 if (!finite (f_new)) { 00142 set_err_ret 00143 ("Function not continuous in gsl_root_stef::iterate().", 00144 o2scl::gsl_ebadfunc); 00145 } 00146 00147 if (count < 3) { 00148 00149 root = x_new; 00150 count++; 00151 00152 } else { 00153 00154 double u = (xt - x_1t); 00155 double v = (x_new - 2 * xt + x_1t); 00156 00157 if (v == 0) { 00158 root = x_new; /* avoid division by zero */ 00159 } else { 00160 root = x_1t - u * u / v; /* accelerated value */ 00161 } 00162 } 00163 00164 if (!finite(df_new)) { 00165 set_err_ret 00166 ("Function not differentiable in gsl_root_stef::iterate().", 00167 o2scl::gsl_ebadfunc); 00168 } 00169 00170 return o2scl::gsl_success; 00171 } 00172 00173 /** \brief Solve \c func using \c x as an initial 00174 guess using derivatives \c df. 00175 */ 00176 virtual int solve_de(double &xx, param_t &pa, func_t &fun, dfunc_t &dfun) { 00177 00178 int status1, status2=gsl_continue, iter=0; 00179 00180 status1=set(fun,dfun,xx,pa); 00181 00182 while (status1==gsl_success && status2==gsl_continue && 00183 iter<this->ntrial) { 00184 iter++; 00185 00186 status1=iterate(); 00187 00188 // Compare present value to previous value 00189 status2=gsl_root_test_delta(root,xx,this->tolx,tolf2); 00190 00191 if (test_residual && status2==gsl_success) { 00192 double y; 00193 fun(root,y,pa); 00194 if (fabs(y)>=this->tolf) status2=gsl_continue; 00195 } 00196 00197 if (this->verbose>0) { 00198 double fval; 00199 fun(root,fval,pa); 00200 print_iter(root,fval,iter,fabs(root-xx),this->tolx*root, 00201 "gsl_root_stef"); 00202 } 00203 xx=root; 00204 } 00205 00206 this->last_ntrial=iter; 00207 00208 if (status1!=gsl_success || status2!=gsl_success) { 00209 int ret=o2scl::err_hnd->get_errno(); 00210 return ret; 00211 } 00212 if (iter>=this->ntrial) { 00213 set_err_ret("solve_de() exceeded maximum number of iterations.", 00214 gsl_emaxiter); 00215 } 00216 00217 return o2scl::gsl_success; 00218 } 00219 00220 /// True if we should test the residual also (default false) 00221 bool test_residual; 00222 00223 /** 00224 \brief Set the information for the solver 00225 00226 Set the function, the derivative, the initial guess and 00227 the parameters. 00228 */ 00229 int set(func_t &fun, dfunc_t &dfun, double guess, param_t &pa) { 00230 00231 fp=&fun; 00232 dfp=&dfun; 00233 params=&pa; 00234 root=guess; 00235 00236 dfun(root,df,pa); 00237 fun(root,f,pa); 00238 00239 x=root; 00240 x_1=0.0; 00241 count=1; 00242 00243 return o2scl::gsl_success; 00244 00245 } 00246 00247 }; 00248 00249 #ifndef DOXYGENP 00250 template<> int io_tlate<gsl_root_stef<void *,funct<void *>, 00251 funct<void *> > >::input(cinput *co, in_file_format *ins, 00252 gsl_root_stef<void *, funct<void *>, 00253 funct<void *> > *ro); 00254 template<> int io_tlate<gsl_root_stef<void *,funct<void *>, 00255 funct<void *> > >::output(coutput *co, out_file_format *outs, 00256 gsl_root_stef<void *, funct<void *>, 00257 funct<void *> > *ro); 00258 template<> const char *io_tlate<gsl_root_stef<void *, 00259 funct<void *>, funct<void *> > >::type(); 00260 #endif 00261 00262 typedef io_tlate<gsl_root_stef<void *,funct<void *>, funct<void *> > > 00263 gsl_root_stef_io_type; 00264 00265 #ifndef DOXYGENP 00266 } 00267 #endif 00268 00269 #endif 00270
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