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 /* roots/steffenson.c 00024 * 00025 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Reid Priedhorsky, 00026 * Brian Gough 00027 * 00028 * This program is free software; you can redistribute it and/or modify 00029 * it under the terms of the GNU General Public License as published by 00030 * the Free Software Foundation; either version 3 of the License, or (at 00031 * your option) any later version. 00032 * 00033 * This program is distributed in the hope that it will be useful, but 00034 * WITHOUT ANY WARRANTY; without even the implied warranty of 00035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00036 * General Public License for more details. 00037 * 00038 * You should have received a copy of the GNU General Public License 00039 * along with this program; if not, write to the Free Software 00040 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00041 * 02110-1301, USA. 00042 */ 00043 00044 #ifndef O2SCL_GSL_ROOT_STEF_H 00045 #define O2SCL_GSL_ROOT_STEF_H 00046 00047 #include <gsl/gsl_math.h> 00048 #include <gsl/gsl_roots.h> 00049 #include <o2scl/root.h> 00050 00051 #ifndef DOXYGENP 00052 namespace o2scl { 00053 #endif 00054 00055 /** 00056 \brief Steffenson equation solver (GSL) 00057 00058 This is Newton's method with an Aitken "delta-squared" 00059 acceleration of the iterates. This can improve the convergence 00060 on multiple roots where the ordinary Newton algorithm is slow. 00061 00062 \verbatim 00063 x[i+1] = x[i] - f(x[i]) / f'(x[i]) 00064 \endverbatim 00065 00066 \verbatim 00067 x_accelerated[i] = x[i] - (x[i+1] - x[i])**2 / (x[i+2] - 2*x[i+1] + x[i]) 00068 \endverbatim 00069 00070 We can only use the accelerated estimate after three iterations, 00071 and use the unaccelerated value until then. 00072 00073 This class finds a root of a function a derivative. If the 00074 derivative is not analytically specified, it is most likely 00075 preferable to use of the alternatives, gsl_root_brent, 00076 cern_root, or cern_mroot_root. The function solve_de() performs 00077 the solution automatically, and a lower-level GSL-like interface 00078 with set() and iterate() is also provided. 00079 00080 By default, this solver compares the present value of the root 00081 (\f$ \mathrm{root} \f$) to the previous value (\f$ \mathrm{x} 00082 \f$), and returns success if \f$ | \mathrm{root} - \mathrm{x} | 00083 < \mathrm{tol} \f$, where \f$ \mathrm{tol} = \mathrm{tolx} + 00084 \mathrm{tolf2}~\mathrm{root} \f$ . 00085 00086 If \ref test_residual is set to true, then the solver 00087 additionally requires that the absolute value of the function is 00088 less than \ref root::tolf. 00089 00090 The original variable \c x_2 has been removed as it was unused 00091 in the original GSL code. 00092 00093 \future There's some extra copying here which can probably 00094 be removed. 00095 \future Compare directly to GSL. 00096 00097 */ 00098 #ifdef DOXYGENP 00099 template<class param_t, class func_t, class dfunc_t> class gsl_root_stef : 00100 public root_de 00101 #else 00102 template<class param_t, class func_t, class dfunc_t> class gsl_root_stef : 00103 public root_de<param_t,func_t,dfunc_t> 00104 #endif 00105 { 00106 00107 protected: 00108 00109 /// Function value 00110 double f; 00111 00112 /// Derivative value 00113 double df; 00114 00115 /// Previous value of root 00116 double x_1; 00117 00118 /// Root 00119 double x; 00120 00121 /// Number of iterations 00122 int count; 00123 00124 /// The function to solve 00125 func_t *fp; 00126 00127 /// The derivative 00128 dfunc_t *dfp; 00129 00130 /// The function parameters 00131 param_t *params; 00132 00133 public: 00134 00135 gsl_root_stef() { 00136 test_residual=false; 00137 tolf2=1.0e-12; 00138 } 00139 00140 /// Return the type, \c "gsl_root_stef". 00141 virtual const char *type() { return "gsl_root_stef"; } 00142 00143 /// The present solution estimate 00144 double root; 00145 00146 /** \brief The relative tolerance for subsequent solutions 00147 (default \f$ 10^{-12} \f$) 00148 */ 00149 double tolf2; 00150 00151 /** 00152 \brief Perform an iteration 00153 00154 After a successful iteration, \ref root contains the 00155 most recent value of the root. 00156 */ 00157 int iterate() { 00158 00159 double x_new, f_new, df_new; 00160 00161 double x_1t = x_1; 00162 double xt = x; 00163 00164 if (df == 0.0) { 00165 this->last_conv=gsl_ezerodiv; 00166 O2SCL_CONV_RET("Derivative is zero in gsl_root_stef::iterate().", 00167 o2scl::gsl_ezerodiv,this->err_nonconv); 00168 } 00169 00170 x_new = xt - (f / df); 00171 00172 // It is important that the derivative be evaluated first here, 00173 // because we want the last function evaluation to be an 00174 // evaluation for the returned root 00175 (*dfp)(x_new,df_new,*params); 00176 (*fp)(x_new,f_new,*params); 00177 00178 x_1 = xt; 00179 x = x_new; 00180 00181 f = f_new; 00182 df = df_new; 00183 00184 if (!finite(f_new)) { 00185 O2SCL_ERR_RET("Function not finite in gsl_root_stef::iterate().", 00186 o2scl::gsl_ebadfunc); 00187 } 00188 00189 if (count < 3) { 00190 00191 root = x_new; 00192 count++; 00193 00194 } else { 00195 00196 double u = (xt - x_1t); 00197 double v = (x_new - 2 * xt + x_1t); 00198 00199 if (v == 0) { 00200 // Avoid division by zero 00201 root = x_new; 00202 } else { 00203 // Accelerated value 00204 root = x_1t - u * u / v; 00205 } 00206 } 00207 00208 if (!finite(df_new)) { 00209 O2SCL_ERR_RET 00210 ("Function not differentiable in gsl_root_stef::iterate().", 00211 o2scl::gsl_ebadfunc); 00212 } 00213 00214 return o2scl::gsl_success; 00215 } 00216 00217 /** \brief Solve \c func using \c x as an initial 00218 guess using derivatives \c df. 00219 */ 00220 virtual int solve_de(double &xx, param_t &pa, func_t &fun, dfunc_t &dfun) { 00221 00222 int status1, status2=gsl_continue, iter=0; 00223 00224 status1=set(fun,dfun,xx,pa); 00225 00226 this->last_conv=0; 00227 while (status1==gsl_success && status2==gsl_continue && 00228 iter<this->ntrial) { 00229 iter++; 00230 00231 status1=iterate(); 00232 00233 // Compare present value to previous value 00234 status2=gsl_root_test_delta(root,xx,this->tolx,tolf2); 00235 00236 if (test_residual && status2==gsl_success) { 00237 double y; 00238 fun(root,y,pa); 00239 if (fabs(y)>=this->tolf) status2=gsl_continue; 00240 } 00241 00242 if (this->verbose>0) { 00243 double fval; 00244 fun(root,fval,pa); 00245 print_iter(root,fval,iter,fabs(root-xx),this->tolx*root, 00246 "gsl_root_stef"); 00247 } 00248 xx=root; 00249 } 00250 00251 this->last_ntrial=iter; 00252 00253 if (status1!=gsl_success || status2!=gsl_success) { 00254 int ret=o2scl::err_hnd->get_errno(); 00255 return ret; 00256 } 00257 if (iter>=this->ntrial) { 00258 if (this->last_conv==0) this->last_conv=gsl_emaxiter; 00259 O2SCL_CONV_RET("solve_de() exceeded maximum number of iterations.", 00260 gsl_emaxiter,this->err_nonconv); 00261 } 00262 00263 return o2scl::gsl_success; 00264 } 00265 00266 /// True if we should test the residual also (default false) 00267 bool test_residual; 00268 00269 /** 00270 \brief Set the information for the solver 00271 00272 Set the function, the derivative, the initial guess and 00273 the parameters. 00274 */ 00275 int set(func_t &fun, dfunc_t &dfun, double guess, param_t &pa) { 00276 00277 fp=&fun; 00278 dfp=&dfun; 00279 params=&pa; 00280 root=guess; 00281 00282 dfun(root,df,pa); 00283 fun(root,f,pa); 00284 00285 x=root; 00286 x_1=0.0; 00287 count=1; 00288 00289 return o2scl::gsl_success; 00290 00291 } 00292 00293 }; 00294 00295 #ifndef DOXYGENP 00296 } 00297 #endif 00298 00299 #endif 00300
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