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$ \mathrm{root} \f$) to the previous value (\f$ \mathrm{x} \f$), 00046 and returns 00047 success if \f$ | \mathrm{root} - \mathrm{x} | < \mathrm{tol} \f$, 00048 where \f$ \mathrm{tol}=\mathrm{tolx}+\mathrm{tolf2}~\mathrm{root} \f$ . 00049 00050 If \ref test_residual is set to true, then the solver 00051 additionally requires that the absolute value of the function 00052 is less than \ref root::tolf. 00053 00054 The original variable \c x_2 has been removed as it was unused 00055 in the original GSL code. 00056 00057 \future There's some extra copying here which can probably 00058 be removed. 00059 \future Compare directly to GSL. 00060 00061 */ 00062 template<class param_t, class func_t, class dfunc_t> class gsl_root_stef : 00063 public o2scl::root_de<param_t,func_t,dfunc_t> { 00064 00065 protected: 00066 00067 /// Function value 00068 double f; 00069 00070 /// Derivative value 00071 double df; 00072 00073 /// Previous value of root 00074 double x_1; 00075 00076 /// Root 00077 double x; 00078 00079 /// Number of iterations 00080 int count; 00081 00082 /// The function to solve 00083 func_t *fp; 00084 00085 /// The derivative 00086 dfunc_t *dfp; 00087 00088 /// The function parameters 00089 param_t *params; 00090 00091 public: 00092 00093 gsl_root_stef() { 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 this->last_conv=gsl_ezerodiv; 00124 O2SCL_CONV_RET("Derivative is zero in gsl_root_stef::iterate().", 00125 o2scl::gsl_ezerodiv,this->err_nonconv); 00126 } 00127 00128 x_new = xt - (f / df); 00129 00130 // It is important that the derivative be evaluated first here, 00131 // because we want the last function evaluation to be an 00132 // evaluation for the returned root 00133 (*dfp)(x_new,df_new,*params); 00134 (*fp)(x_new,f_new,*params); 00135 00136 x_1 = xt; 00137 x = x_new; 00138 00139 f = f_new; 00140 df = df_new; 00141 00142 if (!finite (f_new)) { 00143 O2SCL_ERR_RET("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 O2SCL_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 this->last_conv=0; 00183 while (status1==gsl_success && status2==gsl_continue && 00184 iter<this->ntrial) { 00185 iter++; 00186 00187 status1=iterate(); 00188 00189 // Compare present value to previous value 00190 status2=gsl_root_test_delta(root,xx,this->tolx,tolf2); 00191 00192 if (test_residual && status2==gsl_success) { 00193 double y; 00194 fun(root,y,pa); 00195 if (fabs(y)>=this->tolf) status2=gsl_continue; 00196 } 00197 00198 if (this->verbose>0) { 00199 double fval; 00200 fun(root,fval,pa); 00201 print_iter(root,fval,iter,fabs(root-xx),this->tolx*root, 00202 "gsl_root_stef"); 00203 } 00204 xx=root; 00205 } 00206 00207 this->last_ntrial=iter; 00208 00209 if (status1!=gsl_success || status2!=gsl_success) { 00210 int ret=o2scl::err_hnd->get_errno(); 00211 return ret; 00212 } 00213 if (iter>=this->ntrial) { 00214 if (this->last_conv==0) this->last_conv=gsl_emaxiter; 00215 O2SCL_CONV_RET("solve_de() exceeded maximum number of iterations.", 00216 gsl_emaxiter,this->err_nonconv); 00217 } 00218 00219 return o2scl::gsl_success; 00220 } 00221 00222 /// True if we should test the residual also (default false) 00223 bool test_residual; 00224 00225 /** 00226 \brief Set the information for the solver 00227 00228 Set the function, the derivative, the initial guess and 00229 the parameters. 00230 */ 00231 int set(func_t &fun, dfunc_t &dfun, double guess, param_t &pa) { 00232 00233 fp=&fun; 00234 dfp=&dfun; 00235 params=&pa; 00236 root=guess; 00237 00238 dfun(root,df,pa); 00239 fun(root,f,pa); 00240 00241 x=root; 00242 x_1=0.0; 00243 count=1; 00244 00245 return o2scl::gsl_success; 00246 00247 } 00248 00249 }; 00250 00251 #ifndef DOXYGENP 00252 template<> int io_tlate<gsl_root_stef<int,funct<int>, 00253 funct<int> > >::input(cinput *co, in_file_format *ins, 00254 gsl_root_stef<int, funct<int>, 00255 funct<int> > *ro); 00256 template<> int io_tlate<gsl_root_stef<int,funct<int>, 00257 funct<int> > >::output(coutput *co, out_file_format *outs, 00258 gsl_root_stef<int, funct<int>, 00259 funct<int> > *ro); 00260 template<> const char *io_tlate<gsl_root_stef<int, 00261 funct<int>, funct<int> > >::type(); 00262 #endif 00263 00264 typedef io_tlate<gsl_root_stef<int,funct<int>, funct<int> > > 00265 gsl_root_stef_io_type; 00266 00267 #ifndef DOXYGENP 00268 } 00269 #endif 00270 00271 #endif 00272
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