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_GSL_CHEBAPP_H 00024 #define O2SCL_GSL_CHEBAPP_H 00025 00026 #include <o2scl/collection.h> 00027 #include <o2scl/funct.h> 00028 #include <gsl/gsl_chebyshev.h> 00029 #include <cmath> 00030 00031 #ifndef DOXYGENP 00032 namespace o2scl { 00033 #endif 00034 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 /** \brief Initialize a Chebyshev approximation of the function 00099 \c func over the interval from \c a1 to \c b1 00100 00101 The interval must be specified so that \f$ a < b \f$ , so 00102 a and b are swapped if this is not the case. 00103 */ 00104 template<class param_t, class func_t> 00105 int init(func_t &func, size_t ord, double a1, double b1, param_t &vp) { 00106 size_t k, j; 00107 00108 if(a>=b) { 00109 b=a1; 00110 a=b1; 00111 } else { 00112 a=a1; 00113 b=b1; 00114 } 00115 order=ord; 00116 order_sp=ord; 00117 c.allocate(order+1); 00118 f.allocate(order+1); 00119 00120 double bma=0.5*(b-a); 00121 double bpa=0.5*(b+a); 00122 double fac=2.0/(order+1.0); 00123 00124 for(k=0;k<=order;k++) { 00125 double y=cos(M_PI*(k+0.5)/(order+1)); 00126 f[k]=func(y*bma+bpa,vp); 00127 } 00128 00129 for(j=0;j<=order;j++) { 00130 double sum=0.0; 00131 for(k=0;k<=order; k++) { 00132 sum+=f[k]*cos(M_PI*j*(k+0.5)/(order+1)); 00133 } 00134 c[j]=fac*sum; 00135 } 00136 00137 init_called=true; 00138 00139 return 0; 00140 } 00141 00142 /// Create an approximation from a vector of coefficients 00143 template<class vec_t> int init(double a1, double b1, 00144 size_t ord, vec_t &v) { 00145 order=ord; 00146 order_sp=order; 00147 a=a1; 00148 b=b1; 00149 c.allocate(order+1); 00150 for(size_t i=0;i<order+1;i++) c[i]=v[i]; 00151 00152 init_called=true; 00153 00154 return 0; 00155 } 00156 00157 /// Create an approximation from a vector of function values 00158 template<class vec_t> int init_func_values(double a1, double b1, 00159 size_t ord, vec_t &fval) { 00160 size_t k, j; 00161 00162 if(a>=b) { 00163 b=a1; 00164 a=b1; 00165 } else { 00166 a=a1; 00167 b=b1; 00168 } 00169 order=ord; 00170 order_sp=ord; 00171 c.allocate(order+1); 00172 f.allocate(order+1); 00173 00174 double bma=0.5*(b-a); 00175 double bpa=0.5*(b+a); 00176 double fac=2.0/(order+1.0); 00177 00178 for(j=0;j<=order;j++) { 00179 double sum=0.0; 00180 for(k=0;k<=order; k++) { 00181 sum+=fval[k]*cos(M_PI*j*(k+0.5)/(order+1)); 00182 } 00183 c[j]=fac*sum; 00184 } 00185 00186 init_called=true; 00187 00188 return 0; 00189 } 00190 00191 /** \brief Evaluate the approximation 00192 */ 00193 double eval(double x) const { 00194 00195 if (init_called==false) { 00196 O2SCL_ERR("Series not initialized in gsl_chebapp::eval()", 00197 gsl_einval); 00198 return 0.0; 00199 } 00200 00201 size_t i; 00202 double d1 = 0.0; 00203 double d2 = 0.0; 00204 00205 double y = (2.0 * x - a - b) / (b - a); 00206 double y2 = 2.0 * y; 00207 00208 for (i=order; i >= 1; i--) { 00209 double temp = d1; 00210 d1 = y2 * d1 - d2 + c[i]; 00211 d2 = temp; 00212 } 00213 00214 return y * d1 - d2 + 0.5 * c[0]; 00215 } 00216 00217 /** \brief Evaluate the approximation to a specified order 00218 */ 00219 double eval_n(size_t n, double x) const { 00220 size_t i; 00221 double d1 = 0.0; 00222 double d2 = 0.0; 00223 00224 size_t eval_order = GSL_MIN (n, order); 00225 00226 double y = (2.0 * x - a - b) / (b - a); 00227 double y2 = 2.0 * y; 00228 00229 for (i = eval_order; i >= 1; i--) { 00230 double temp = d1; 00231 d1 = y2 * d1 - d2 + c[i]; 00232 d2 = temp; 00233 } 00234 00235 return y * d1 - d2 + 0.5 * c[0]; 00236 } 00237 00238 /** \brief Evaluate the approximation and give the uncertainty 00239 */ 00240 int eval_err(double x, double &result, double &abserr) { 00241 00242 size_t i; 00243 double d1 = 0.0; 00244 double d2 = 0.0; 00245 00246 double y = (2. * x - a - b) / (b - a); 00247 double y2 = 2.0 * y; 00248 00249 double absc = 0.0; 00250 00251 for (i = order; i >= 1; i--) { 00252 double temp = d1; 00253 d1 = y2 * d1 - d2 + c[i]; 00254 d2 = temp; 00255 } 00256 00257 result = y * d1 - d2 + 0.5 * c[0]; 00258 00259 /* Estimate cumulative numerical error */ 00260 00261 for (i = 0; i <= order; i++) { 00262 absc += fabs(c[i]); 00263 } 00264 00265 /* Combine truncation error and numerical error */ 00266 00267 abserr = fabs (c[order]) + absc * GSL_DBL_EPSILON; 00268 00269 return GSL_SUCCESS; 00270 } 00271 00272 /** \brief Evaluate the approximation to a specified order 00273 and give the uncertainty 00274 */ 00275 int eval_n_err(size_t n, double x, double &result, double &abserr) { 00276 size_t i; 00277 double d1 = 0.0; 00278 double d2 = 0.0; 00279 00280 double y = (2. * x - a - b) / (b - a); 00281 double y2 = 2.0 * y; 00282 00283 double absc = 0.0; 00284 00285 size_t eval_order = GSL_MIN (n, order); 00286 00287 for (i = eval_order; i >= 1; i--) { 00288 double temp = d1; 00289 d1 = y2 * d1 - d2 + c[i]; 00290 d2 = temp; 00291 } 00292 00293 result = y * d1 - d2 + 0.5 * c[0]; 00294 00295 /* Estimate cumulative numerical error */ 00296 00297 for (i = 0; i <= eval_order; i++) { 00298 absc += fabs(c[i]); 00299 } 00300 00301 /* Combine truncation error and numerical error */ 00302 abserr = fabs (c[eval_order]) + absc * GSL_DBL_EPSILON; 00303 00304 return GSL_SUCCESS; 00305 } 00306 00307 /** 00308 \brief Get a coefficient 00309 00310 Legal values of the argument are 0 to \c order (inclusive) 00311 */ 00312 double get_coefficient(size_t ix) const { 00313 if (ix<order+1) { 00314 return c[ix]; 00315 } 00316 O2SCL_ERR 00317 ("Requested invalid coefficient in gsl_chebapp::get_coefficient()", 00318 gsl_einval); 00319 return 0.0; 00320 } 00321 00322 /** 00323 \brief Set a coefficient 00324 00325 Legal values of the argument are 0 to \c order (inclusive) 00326 */ 00327 int set_coefficient(size_t ix, double co) { 00328 if (ix<order+1) { 00329 c[ix]=co; 00330 return 0; 00331 } 00332 O2SCL_ERR_RET 00333 ("Requested invalid coefficient in gsl_chebapp::get_coefficient()", 00334 gsl_einval); 00335 } 00336 00337 /// Return the endpoints of the approximation 00338 int get_endpoints(double &la, double &lb) { 00339 la=a; 00340 lb=b; 00341 return 0; 00342 } 00343 00344 /** 00345 \brief Get the coefficients 00346 */ 00347 template<class vec_t> int get_coefficients(size_t n, vec_t &v) const { 00348 for(size_t i=0;i<order+1 && i<n;i++) { 00349 v[i]=c[i]; 00350 } 00351 return 0; 00352 } 00353 00354 /** 00355 \brief Set the coefficients 00356 */ 00357 template<class vec_t> int set_coefficients(size_t n, const vec_t &v) { 00358 for(size_t i=0;i<order+1 && i<n;i++) { 00359 c[i]=v[i]; 00360 } 00361 return 0; 00362 } 00363 00364 /// Make \c gc an approximation to the derivative 00365 int deriv(gsl_chebapp &gc) const { 00366 00367 size_t n = order+1; 00368 00369 const double con = 2.0/(b-a); 00370 size_t i; 00371 00372 gc.init_called=true; 00373 gc.order=order; 00374 gc.order_sp=order; 00375 gc.a=a; 00376 gc.b=b; 00377 gc.c.allocate(n); 00378 gc.f.allocate(n); 00379 00380 gc.c[n-1] = 0.0; 00381 00382 if (n > 1) { 00383 00384 gc.c[n-2] = 2.0 *(n-1.0) * c[n-1]; 00385 00386 for(i = n-3; i>0; i--) { 00387 gc.c[i] = gc.c[i+2] + 2.0 *(i+1.0) * c[i+1]; 00388 } 00389 00390 gc.c[0] = gc.c[2] + 2.0 * c[1]; 00391 00392 for(i = 0 ; i<n ; i++) { 00393 gc.c[i] *= con; 00394 } 00395 } 00396 00397 return 0; 00398 } 00399 00400 /// Make \c gc an approximation to the integral 00401 int integ(gsl_chebapp &gc) const { 00402 00403 size_t n = order+1; 00404 00405 const double con = 0.25*(b-a); 00406 00407 gc.init_called=true; 00408 gc.order=order; 00409 gc.order_sp=order; 00410 gc.a=a; 00411 gc.b=b; 00412 gc.c.allocate(n); 00413 gc.f.allocate(n); 00414 00415 if (n == 1) { 00416 00417 gc.c[0]=0.0; 00418 00419 } else if (n == 2) { 00420 00421 gc.c[1]=con*c[0]; 00422 gc.c[0]=2.0*gc.c[1]; 00423 00424 } else { 00425 00426 double sum = 0.0; 00427 double fac = 1.0; 00428 00429 for(size_t i=1; i<=n-2; i++) { 00430 gc.c[i] = con * (c[i-1] - c[i+1])/((double)i); 00431 sum += fac * gc.c[i]; 00432 fac = -fac; 00433 } 00434 gc.c[n-1] = con * c[n-2]/(n-1.0); 00435 sum += fac * gc.c[n-1]; 00436 gc.c[0] = 2.0 * sum; 00437 } 00438 00439 return 0; 00440 } 00441 00442 }; 00443 00444 #ifndef DOXYGENP 00445 } 00446 #endif 00447 00448 #endif
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