![]() |
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 /* 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 <string> 00048 00049 #include <gsl/gsl_math.h> 00050 #include <gsl/gsl_roots.h> 00051 00052 #include <o2scl/root.h> 00053 00054 #ifndef DOXYGENP 00055 namespace o2scl { 00056 #endif 00057 00058 /** \brief Steffenson equation solver (GSL) 00059 00060 This is Newton's method with an Aitken "delta-squared" 00061 acceleration of the iterates. This can improve the convergence 00062 on multiple roots where the ordinary Newton algorithm is slow. 00063 00064 Defining the next iteration with 00065 \f[ 00066 x_{i+1} = x_i - f(x_i) / f^{\prime}(x_i) 00067 \f] 00068 the accelerated value is 00069 \f[ 00070 x_{\mathrm{acc},i} = x_i - (x_{i+1}-x_i)^2 / (x_{i+2} - 00071 2 x_{i+1} + x_i) 00072 \f] 00073 We can only use the accelerated estimate after three iterations, 00074 and use the unaccelerated value until then. 00075 00076 This class finds a root of a function a derivative. If the 00077 derivative is not analytically specified, it is most likely 00078 preferable to use of the alternatives, gsl_root_brent, 00079 cern_root, or cern_mroot_root. The function solve_de() performs 00080 the solution automatically, and a lower-level GSL-like interface 00081 with set() and iterate() is also provided. 00082 00083 By default, this solver compares the present value of the root 00084 (\f$ \mathrm{root} \f$) to the previous value (\f$ \mathrm{x} 00085 \f$), and returns success if \f$ | \mathrm{root} - \mathrm{x} | 00086 < \mathrm{tol} \f$, where \f$ \mathrm{tol} = \mathrm{tol\_abs} + 00087 \mathrm{tolf2}~\mathrm{root} \f$ . 00088 00089 If \ref test_residual is set to true, then the solver 00090 additionally requires that the absolute value of the function is 00091 less than \ref root::tol_rel. 00092 00093 The original variable \c x_2 has been removed as it was unused 00094 in the original GSL code. 00095 00096 \future There's some extra copying here which can probably 00097 be removed. 00098 \future Compare directly to GSL. 00099 \future This can probably be modified to shorten the step 00100 if the function goes out of bounds as in gsl_mroot_hybrids. 00101 00102 */ 00103 #ifdef DOXYGENP 00104 template<class func_t, class dfunc_t=func_t> class gsl_root_stef : 00105 public root_de 00106 #else 00107 template<class func_t, class dfunc_t=func_t> class gsl_root_stef : 00108 public root_de<func_t,dfunc_t> 00109 #endif 00110 { 00111 00112 protected: 00113 00114 /// Function value 00115 double f; 00116 00117 /// Derivative value 00118 double df; 00119 00120 /// Previous value of root 00121 double x_1; 00122 00123 /// Root 00124 double x; 00125 00126 /// Number of iterations 00127 int count; 00128 00129 /// The function to solve 00130 func_t *fp; 00131 00132 /// The derivative 00133 dfunc_t *dfp; 00134 00135 public: 00136 00137 gsl_root_stef() { 00138 test_residual=false; 00139 tolf2=1.0e-12; 00140 } 00141 00142 /// Return the type, \c "gsl_root_stef". 00143 virtual const char *type() { return "gsl_root_stef"; } 00144 00145 /// The present solution estimate 00146 double root; 00147 00148 /** \brief The relative tolerance for subsequent solutions 00149 (default \f$ 10^{-12} \f$) 00150 */ 00151 double tolf2; 00152 00153 /** \brief Perform an iteration 00154 00155 After a successful iteration, \ref root contains the 00156 most recent value of the root. 00157 */ 00158 int iterate() { 00159 00160 double x_new, f_new, df_new; 00161 00162 double x_1t = x_1; 00163 double xt = x; 00164 00165 if (df == 0.0) { 00166 this->last_conv=gsl_ezerodiv; 00167 O2SCL_CONV_RET("Derivative is zero in gsl_root_stef::iterate().", 00168 o2scl::gsl_ezerodiv,this->err_nonconv); 00169 } 00170 00171 x_new = xt - (f / df); 00172 00173 // It is important that the derivative be evaluated first here, 00174 // because we want the last function evaluation to be an 00175 // evaluation for the returned root 00176 df_new=(*dfp)(x_new); 00177 f_new=(*fp)(x_new); 00178 00179 x_1 = xt; 00180 x = x_new; 00181 00182 f = f_new; 00183 df = df_new; 00184 00185 if (!gsl_finite(f_new)) { 00186 std::string str="Function not finite (returned "+dtos(f_new)+ 00187 ") in gsl_root_stef::iterate()."; 00188 O2SCL_ERR_RET(str.c_str(),o2scl::gsl_ebadfunc); 00189 } 00190 00191 if (count < 3) { 00192 00193 root = x_new; 00194 count++; 00195 00196 } else { 00197 00198 double u = (xt - x_1t); 00199 double v = (x_new - 2 * xt + x_1t); 00200 00201 if (v == 0) { 00202 // Avoid division by zero 00203 root = x_new; 00204 } else { 00205 // Accelerated value 00206 root = x_1t - u * u / v; 00207 } 00208 } 00209 00210 if (!gsl_finite(df_new)) { 00211 std::string str="Derivative not finite (returned "+dtos(df_new)+ 00212 ") in gsl_root_stef::iterate()."; 00213 O2SCL_ERR_RET(str.c_str(),o2scl::gsl_ebadfunc); 00214 } 00215 00216 return o2scl::gsl_success; 00217 } 00218 00219 /** \brief Solve \c func using \c x as an initial 00220 guess using derivatives \c df. 00221 */ 00222 virtual int solve_de(double &xx, func_t &fun, dfunc_t &dfun) { 00223 00224 int status1, status2=gsl_continue, iter=0; 00225 00226 status1=set(fun,dfun,xx); 00227 00228 this->last_conv=0; 00229 while (status1==gsl_success && status2==gsl_continue && 00230 iter<this->ntrial) { 00231 iter++; 00232 00233 status1=iterate(); 00234 00235 // Compare present value to previous value 00236 status2=gsl_root_test_delta(root,xx,this->tol_abs,tolf2); 00237 00238 if (test_residual && status2==gsl_success) { 00239 double y; 00240 y=fun(root); 00241 if (fabs(y)>=this->tol_rel) status2=gsl_continue; 00242 } 00243 00244 if (this->verbose>0) { 00245 double fval; 00246 fval=fun(root); 00247 print_iter(root,fval,iter,fabs(root-xx),this->tol_abs*root, 00248 "gsl_root_stef"); 00249 } 00250 xx=root; 00251 } 00252 00253 this->last_ntrial=iter; 00254 00255 if (status1!=gsl_success || status2!=gsl_success) { 00256 int ret=o2scl::err_hnd->get_errno(); 00257 return ret; 00258 } 00259 if (iter>=this->ntrial) { 00260 if (this->last_conv==0) this->last_conv=gsl_emaxiter; 00261 std::string str=((std::string)"Function solve_de() exceeded the ")+ 00262 "maximum number of iterations, "+itos(this->ntrial)+"."; 00263 O2SCL_CONV_RET(str.c_str(),gsl_emaxiter,this->err_nonconv); 00264 } 00265 00266 return o2scl::gsl_success; 00267 } 00268 00269 /// True if we should test the residual also (default false) 00270 bool test_residual; 00271 00272 /** \brief Set the information for the solver 00273 00274 Set the function, the derivative, the initial guess and 00275 the parameters. 00276 */ 00277 int set(func_t &fun, dfunc_t &dfun, double guess) { 00278 00279 fp=&fun; 00280 dfp=&dfun; 00281 root=guess; 00282 00283 df=dfun(root); 00284 f=fun(root); 00285 00286 x=root; 00287 x_1=0.0; 00288 count=1; 00289 00290 return o2scl::gsl_success; 00291 00292 } 00293 00294 }; 00295 00296 #ifndef DOXYGENP 00297 } 00298 #endif 00299 00300 #endif 00301
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).