![]() |
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_GSL_CHEBAPP_H 00024 #define O2SCL_GSL_CHEBAPP_H 00025 00026 #include <cmath> 00027 #include <gsl/gsl_chebyshev.h> 00028 #include <o2scl/funct.h> 00029 #include <o2scl/uvector_tlate.h> 00030 #include <o2scl/ovector_tlate.h> 00031 00032 #ifndef DOXYGENP 00033 namespace o2scl { 00034 #endif 00035 00036 /** \brief Chebyshev approximation (GSL) 00037 00038 Approximate a function on a finite interval using a Chebyshev series: 00039 \f[ 00040 f(x) = \sum_n c_n T_n(x) \qquad \mathrm{where} 00041 \qquad T_n(x)=\cos(n \arccos x) 00042 \f] 00043 */ 00044 class gsl_chebapp { 00045 00046 protected: 00047 00048 /// Coefficients 00049 uvector c; 00050 /// Order of the approximation 00051 size_t order; 00052 /// Lower end of the interval 00053 double a; 00054 /// Upper end of the interval 00055 double b; 00056 /// Single precision order 00057 size_t order_sp; 00058 /// Function evaluated at Chebyshev points 00059 uvector f; 00060 /// True if init has been called 00061 bool init_called; 00062 00063 public: 00064 00065 gsl_chebapp() { 00066 init_called=false; 00067 } 00068 00069 /// Copy constructor 00070 gsl_chebapp(const gsl_chebapp &gc) { 00071 order=gc.order; 00072 init_called=gc.init_called; 00073 c=gc.c; 00074 f=gc.f; 00075 a=gc.a; 00076 b=gc.b; 00077 order_sp=gc.order_sp; 00078 } 00079 00080 /// Copy constructor 00081 gsl_chebapp &operator=(const gsl_chebapp &gc) { 00082 00083 // Check for self-assignment so that we don't 00084 // reallocate the vectors and lose the coefficients 00085 if (this==&gc) return *this; 00086 00087 order=gc.order; 00088 init_called=gc.init_called; 00089 c=gc.c; 00090 f=gc.f; 00091 a=gc.a; 00092 b=gc.b; 00093 order_sp=gc.order_sp; 00094 00095 return *this; 00096 } 00097 00098 /// \name Initialization methods 00099 //@{ 00100 /** \brief Initialize a Chebyshev approximation of the function 00101 \c func over the interval from \c a1 to \c b1 00102 00103 The interval must be specified so that \f$ a < b \f$ , so 00104 a and b are swapped if this is not the case. 00105 */ 00106 template<class func_t> 00107 int init(func_t &func, size_t ord, double a1, double b1) { 00108 size_t k, j; 00109 00110 if(a1>=b1) { 00111 b=a1; 00112 a=b1; 00113 } else { 00114 a=a1; 00115 b=b1; 00116 } 00117 order=ord; 00118 order_sp=ord; 00119 c.allocate(order+1); 00120 f.allocate(order+1); 00121 00122 double bma=0.5*(b-a); 00123 double bpa=0.5*(b+a); 00124 double fac=2.0/(order+1.0); 00125 00126 for(k=0;k<=order;k++) { 00127 double y=cos(M_PI*(k+0.5)/(order+1)); 00128 f[k]=func(y*bma+bpa); 00129 } 00130 00131 for(j=0;j<=order;j++) { 00132 double sum=0.0; 00133 for(k=0;k<=order; k++) { 00134 sum+=f[k]*cos(M_PI*j*(k+0.5)/(order+1)); 00135 } 00136 c[j]=fac*sum; 00137 } 00138 00139 init_called=true; 00140 00141 return 0; 00142 } 00143 00144 /// Create an approximation from a vector of coefficients 00145 template<class vec_t> int init(double a1, double b1, 00146 size_t ord, vec_t &v) { 00147 order=ord; 00148 order_sp=order; 00149 a=a1; 00150 b=b1; 00151 c.allocate(order+1); 00152 for(size_t i=0;i<order+1;i++) c[i]=v[i]; 00153 00154 init_called=true; 00155 00156 return 0; 00157 } 00158 00159 /// Create an approximation from a vector of function values 00160 template<class vec_t> int init_func_values(double a1, double b1, 00161 size_t ord, vec_t &fval) { 00162 size_t k, j; 00163 00164 if(a>=b) { 00165 b=a1; 00166 a=b1; 00167 } else { 00168 a=a1; 00169 b=b1; 00170 } 00171 order=ord; 00172 order_sp=ord; 00173 c.allocate(order+1); 00174 f.allocate(order+1); 00175 00176 double bma=0.5*(b-a); 00177 double bpa=0.5*(b+a); 00178 double fac=2.0/(order+1.0); 00179 00180 for(j=0;j<=order;j++) { 00181 double sum=0.0; 00182 for(k=0;k<=order; k++) { 00183 sum+=fval[k]*cos(M_PI*j*(k+0.5)/(order+1)); 00184 } 00185 c[j]=fac*sum; 00186 } 00187 00188 init_called=true; 00189 00190 return 0; 00191 } 00192 //@} 00193 00194 /// \name Evaulation methods 00195 //@{ 00196 00197 /** \brief Evaluate the approximation 00198 */ 00199 double eval(double x) const { 00200 00201 if (init_called==false) { 00202 O2SCL_ERR("Series not initialized in gsl_chebapp::eval()", 00203 gsl_einval); 00204 return 0.0; 00205 } 00206 00207 size_t i; 00208 double d1 = 0.0; 00209 double d2 = 0.0; 00210 00211 double y = (2.0*x - a - b) / (b - a); 00212 double y2 = 2.0*y; 00213 00214 for (i=order; i >= 1; i--) { 00215 double temp = d1; 00216 d1 = y2*d1 - d2 + c[i]; 00217 d2 = temp; 00218 } 00219 00220 return y*d1 - d2 + 0.5*c[0]; 00221 } 00222 00223 /** \brief Evaluate the approximation 00224 */ 00225 double operator()(double x) const { 00226 return eval(x); 00227 } 00228 00229 /** \brief Evaluate the approximation to a specified order 00230 */ 00231 double eval_n(size_t n, double x) const { 00232 size_t i; 00233 double d1 = 0.0; 00234 double d2 = 0.0; 00235 00236 size_t eval_order = GSL_MIN (n, order); 00237 00238 double y = (2.0*x - a - b) / (b - a); 00239 double y2 = 2.0*y; 00240 00241 for (i = eval_order; i >= 1; i--) { 00242 double temp = d1; 00243 d1 = y2*d1 - d2 + c[i]; 00244 d2 = temp; 00245 } 00246 00247 return y*d1 - d2 + 0.5*c[0]; 00248 } 00249 00250 /** \brief Evaluate the approximation and give the uncertainty 00251 */ 00252 int eval_err(double x, double &result, double &abserr) { 00253 00254 size_t i; 00255 double d1 = 0.0; 00256 double d2 = 0.0; 00257 00258 double y = (2.*x - a - b) / (b - a); 00259 double y2 = 2.0*y; 00260 00261 double absc = 0.0; 00262 00263 for (i = order; i >= 1; i--) { 00264 double temp = d1; 00265 d1 = y2*d1 - d2 + c[i]; 00266 d2 = temp; 00267 } 00268 00269 result = y*d1 - d2 + 0.5*c[0]; 00270 00271 /* Estimate cumulative numerical error */ 00272 00273 for (i = 0; i <= order; i++) { 00274 absc += fabs(c[i]); 00275 } 00276 00277 /* Combine truncation error and numerical error */ 00278 00279 abserr = fabs (c[order]) + absc*GSL_DBL_EPSILON; 00280 00281 return GSL_SUCCESS; 00282 } 00283 00284 /** \brief Evaluate the approximation to a specified order 00285 and give the uncertainty 00286 */ 00287 int eval_n_err(size_t n, double x, double &result, double &abserr) { 00288 size_t i; 00289 double d1 = 0.0; 00290 double d2 = 0.0; 00291 00292 double y = (2.*x - a - b) / (b - a); 00293 double y2 = 2.0*y; 00294 00295 double absc = 0.0; 00296 00297 size_t eval_order = GSL_MIN (n, order); 00298 00299 for (i = eval_order; i >= 1; i--) { 00300 double temp = d1; 00301 d1 = y2*d1 - d2 + c[i]; 00302 d2 = temp; 00303 } 00304 00305 result = y*d1 - d2 + 0.5*c[0]; 00306 00307 /* Estimate cumulative numerical error */ 00308 00309 for (i = 0; i <= eval_order; i++) { 00310 absc += fabs(c[i]); 00311 } 00312 00313 /* Combine truncation error and numerical error */ 00314 abserr = fabs (c[eval_order]) + absc*GSL_DBL_EPSILON; 00315 00316 return GSL_SUCCESS; 00317 } 00318 //@} 00319 00320 /// \name Maniupulating coefficients and endpoints 00321 //@{ 00322 /** \brief Get a coefficient 00323 00324 Legal values of the argument are 0 to \c order (inclusive) 00325 */ 00326 double get_coefficient(size_t ix) const { 00327 if (ix<order+1) { 00328 return c[ix]; 00329 } 00330 O2SCL_ERR 00331 ("Requested invalid coefficient in gsl_chebapp::get_coefficient()", 00332 gsl_einval); 00333 return 0.0; 00334 } 00335 00336 /** \brief Set a coefficient 00337 00338 Legal values of the argument are 0 to \c order (inclusive) 00339 */ 00340 int set_coefficient(size_t ix, double co) { 00341 if (ix<order+1) { 00342 c[ix]=co; 00343 return 0; 00344 } 00345 O2SCL_ERR_RET 00346 ("Requested invalid coefficient in gsl_chebapp::get_coefficient()", 00347 gsl_einval); 00348 } 00349 00350 /// Return the endpoints of the approximation 00351 int get_endpoints(double &la, double &lb) { 00352 la=a; 00353 lb=b; 00354 return 0; 00355 } 00356 00357 /** \brief Get the coefficients 00358 */ 00359 template<class vec_t> int get_coefficients(size_t n, vec_t &v) const { 00360 for(size_t i=0;i<order+1 && i<n;i++) { 00361 v[i]=c[i]; 00362 } 00363 return 0; 00364 } 00365 00366 /** \brief Set the coefficients 00367 */ 00368 template<class vec_t> int set_coefficients(size_t n, const vec_t &v) { 00369 for(size_t i=0;i<order+1 && i<n;i++) { 00370 c[i]=v[i]; 00371 } 00372 return 0; 00373 } 00374 //@} 00375 00376 /// \name Derivatives and integrals 00377 //@{ 00378 /// Make \c gc an approximation to the derivative 00379 int deriv(gsl_chebapp &gc) const { 00380 00381 size_t n=order+1; 00382 00383 const double con=2.0/(b-a); 00384 size_t i; 00385 00386 gc.init_called=true; 00387 gc.order=order; 00388 gc.order_sp=order; 00389 gc.a=a; 00390 gc.b=b; 00391 gc.c.allocate(n); 00392 gc.f.allocate(n); 00393 00394 gc.c[n-1]=0.0; 00395 00396 if (n > 1) { 00397 00398 gc.c[n-2]=2.0*(n-1.0)*c[n-1]; 00399 00400 for(i=n;i>=3;i--) { 00401 gc.c[i-3]=gc.c[i-1]+2.0*(i-2.0)*c[i-2]; 00402 } 00403 00404 for(i=0;i<n;i++) { 00405 gc.c[i]*=con; 00406 } 00407 } 00408 00409 return 0; 00410 } 00411 00412 /// Make \c gc an approximation to the integral 00413 int integ(gsl_chebapp &gc) const { 00414 00415 size_t n=order+1; 00416 00417 const double con=0.25*(b-a); 00418 00419 gc.init_called=true; 00420 gc.order=order; 00421 gc.order_sp=order; 00422 gc.a=a; 00423 gc.b=b; 00424 gc.c.allocate(n); 00425 gc.f.allocate(n); 00426 00427 if (n == 1) { 00428 00429 gc.c[0]=0.0; 00430 00431 } else if (n == 2) { 00432 00433 gc.c[1]=con*c[0]; 00434 gc.c[0]=2.0*gc.c[1]; 00435 00436 } else { 00437 00438 double sum=0.0; 00439 double fac=1.0; 00440 00441 for(size_t i=1; i<=n-2; i++) { 00442 gc.c[i]=con*(c[i-1] - c[i+1])/((double)i); 00443 sum += fac*gc.c[i]; 00444 fac=-fac; 00445 } 00446 gc.c[n-1]=con*c[n-2]/(n-1.0); 00447 sum += fac*gc.c[n-1]; 00448 gc.c[0]=2.0*sum; 00449 } 00450 00451 return 0; 00452 } 00453 //@} 00454 00455 }; 00456 00457 #ifndef DOXYGENP 00458 } 00459 #endif 00460 00461 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).