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