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