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_ROOT_H 00024 #define O2SCL_ROOT_H 00025 00026 #include <iostream> 00027 #include <cmath> 00028 #include <o2scl/err_hnd.h> 00029 #include <o2scl/collection.h> 00030 #include <o2scl/funct.h> 00031 00032 #ifndef DOXYGENP 00033 namespace o2scl { 00034 #endif 00035 00036 /** 00037 \brief 1-dimensional solver [abstract base] 00038 00039 \future Maybe consider allowing the user to specify 00040 the stream to which 'verbose' information is sent. 00041 */ 00042 template<class param_t, class func_t=funct<param_t>, 00043 class dfunc_t=func_t> class root { 00044 00045 public: 00046 00047 root() { 00048 ntrial=100; 00049 tolf=1.0e-8; 00050 verbose=0; 00051 tolx=1.0e-12; 00052 last_ntrial=0; 00053 err_nonconv=true; 00054 last_conv=0; 00055 } 00056 00057 virtual ~root() {} 00058 00059 /** \brief The maximum value of the functions for success 00060 (default \f$ 10^{-8} \f$ ) 00061 */ 00062 double tolf; 00063 00064 /** \brief The minimum allowable stepsize 00065 (default \f$ 10^{-12} \f$ ) 00066 */ 00067 double tolx; 00068 00069 /// Output control (default 0) 00070 int verbose; 00071 00072 /// Maximum number of iterations (default 100) 00073 int ntrial; 00074 00075 /// If true, call the error handler if the routine does not "converge" 00076 bool err_nonconv; 00077 00078 /** \brief Zero if last call to solve(), solve_bkt(), or 00079 solve_de() converged. 00080 00081 This is particularly useful if err_nonconv is false to test 00082 if the last call to solve(), solve_bkt(), or solve_de() 00083 converged. 00084 */ 00085 int last_conv; 00086 00087 /// The number of iterations for in the most recent minimization 00088 int last_ntrial; 00089 00090 /// Return the type, \c "root". 00091 virtual const char *type() { return "root"; } 00092 00093 /** 00094 \brief Print out iteration information. 00095 00096 Depending on the value of the variable verbose, this prints 00097 out the iteration information. If verbose=0, then no 00098 information is printed, while if verbose>1, then after each 00099 iteration, the present values of \c x and \c y are 00100 output to std::cout along with the iteration number. If 00101 verbose>=2 then each iteration waits for a character before 00102 continuing. 00103 00104 */ 00105 virtual int print_iter(double x, double y, int iter, double value=0.0, 00106 double limit=0.0, std::string comment="") { 00107 if (verbose<=0) return gsl_success; 00108 00109 char ch; 00110 00111 std::cout << comment << " Iteration: " << iter << std::endl; 00112 if (x<0) std::cout << x << " "; 00113 else std::cout << " " << x << " "; 00114 if (y<0) std::cout << y << " "; 00115 else std::cout << " " << y << " "; 00116 if (value<0) std::cout << value << " "; 00117 else std::cout << " " << value << " "; 00118 if (limit<0) std::cout << limit << std::endl; 00119 else std::cout << " " << limit << std::endl; 00120 if (verbose>1) { 00121 std::cout << "Press a key and type enter to continue. "; 00122 std::cin >> ch; 00123 } 00124 00125 return gsl_success; 00126 } 00127 00128 /** 00129 \brief Solve \c func using \c x as an initial guess 00130 */ 00131 virtual int solve(double &x, param_t &pa, func_t &func)=0; 00132 00133 /** \brief Solve \c func in region \f$ x_1<x<x_2 \f$ 00134 returning \f$ x_1 \f$ . 00135 */ 00136 virtual int solve_bkt(double &x1, double x2, param_t &pa, 00137 func_t &func) { 00138 return solve(x1,pa,func); 00139 } 00140 00141 /** \brief Solve \c func using \c x as an initial 00142 guess using derivatives \c df. 00143 */ 00144 virtual int solve_de(double &x, param_t &pa, func_t &func, dfunc_t &df) { 00145 return solve(x,pa,func); 00146 } 00147 00148 }; 00149 00150 /** 00151 \brief 1-dimensional bracketing solver [abstract base] 00152 */ 00153 template<class param_t, class func_t=funct<param_t>, 00154 class dfunc_t=func_t> class root_bkt : 00155 public root<param_t,func_t,dfunc_t> { 00156 00157 public: 00158 00159 root_bkt() { 00160 bracket_step=1.0e-4; 00161 } 00162 00163 virtual ~root_bkt() {} 00164 00165 /** 00166 \brief The stepsize for automatic bracketing 00167 (default \f$ 10^{-4} \f$) 00168 00169 If this is exactly zero, it will be reset to 00170 \f$ 10^{-4} \f$ by solve(). 00171 */ 00172 double bracket_step; 00173 00174 /// Return the type, \c "root_bkt". 00175 virtual const char *type() { return "root_bkt"; } 00176 00177 /** \brief Solve \c func in region \f$ x_1<x<x_2 \f$ 00178 returning \f$ x_1 \f$ . 00179 */ 00180 virtual int solve_bkt(double &x1, double x2, param_t &pa, 00181 func_t &func)=0; 00182 00183 /** 00184 \brief Solve \c func using \c x as an initial guess 00185 */ 00186 virtual int solve(double &x, param_t &pa, func_t &func) { 00187 00188 if (bracket_step==0.0) bracket_step=1.0e-4; 00189 00190 double x2=0.0, dx, fx, fx2; 00191 int i=0; 00192 bool done=false; 00193 // Use function to try to bracket a root 00194 while(done==false && i<10) { 00195 00196 func(x,fx,pa); 00197 func(x*(1.0+bracket_step),fx2,pa); 00198 00199 dx=(fx2-fx)/(bracket_step*x); 00200 x2=x-2.0*fx/dx; 00201 00202 func(x2,fx2,pa); 00203 00204 if (fx*fx2<0.0) { 00205 done=true; 00206 } else { 00207 x=(x2+x)/2.0; 00208 } 00209 00210 i++; 00211 } 00212 if (done==false) { 00213 O2SCL_ERR_RET("Failed to bracket function in root_bkt::solve().", 00214 o2scl::gsl_emaxiter); 00215 } 00216 return solve_bkt(x,x2,pa,func); 00217 00218 return 0; 00219 } 00220 00221 /** \brief Solve \c func using \c x as an initial 00222 guess using derivatives \c df. 00223 */ 00224 virtual int solve_de(double &x, param_t &pa, func_t &func, dfunc_t &df) { 00225 00226 double x2=0.0, dx, fx, fx2; 00227 int i=0; 00228 bool done=false; 00229 00230 // Use derivative information to try to bracket a root 00231 while(done==false && i<10) { 00232 00233 func(x,fx,pa); 00234 df(x,dx,pa); 00235 00236 x2=x-2.0*fx/dx; 00237 00238 func(x2,fx2,pa); 00239 00240 if (fx*fx2<0.0) { 00241 done=true; 00242 } else { 00243 x=(x2+x)/2.0; 00244 } 00245 i++; 00246 } 00247 00248 if (done==false) { 00249 O2SCL_ERR_RET("Failed to bracket function in root_bkt::solve_de().", 00250 o2scl::gsl_efailed); 00251 } 00252 00253 return solve_bkt(x,x2,pa,func); 00254 00255 } 00256 00257 }; 00258 00259 /** 00260 \brief 1-dimensional with solver with derivatives [abstract base] 00261 00262 \future At the moment, the functions solve() and solve_bkt() 00263 are not implemented for derivative solvers. 00264 */ 00265 #ifdef DOXYGENP 00266 template<class param_t, class func_t=funct<param_t>, class dfunc_t=func_t> 00267 class root_de : public root 00268 #else 00269 template<class param_t, class func_t=funct<param_t>, class dfunc_t=func_t> 00270 class root_de : public root<param_t,func_t> 00271 #endif 00272 { 00273 00274 public: 00275 00276 root_de() { 00277 } 00278 00279 virtual ~root_de() {} 00280 00281 /// Return the type, \c "root_de". 00282 virtual const char *type() { return "root_de"; } 00283 00284 /** \brief Solve \c func in region \f$ x_1<x<x_2 \f$ 00285 returning \f$ x_1 \f$ . 00286 */ 00287 virtual int solve_bkt(double &x1, double x2, param_t &pa, 00288 func_t &func) { 00289 O2SCL_ERR_RET("Function solve_bkt() not implemented.",gsl_eunimpl); 00290 } 00291 00292 /** 00293 \brief Solve \c func using \c x as an initial guess 00294 */ 00295 virtual int solve(double &x, param_t &pa, func_t &func) { 00296 O2SCL_ERR_RET("Function solve() not implemented.",gsl_eunimpl); 00297 } 00298 00299 /** \brief Solve \c func using \c x as an initial 00300 guess using derivatives \c df. 00301 */ 00302 virtual int solve_de(double &x, param_t &pa, func_t &func, dfunc_t &df)=0; 00303 00304 }; 00305 00306 #ifndef DOXYGENP 00307 } 00308 #endif 00309 00310 #endif 00311
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