Object-oriented Scientific Computing Library: Version 0.910
gsl_chebapp.h
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.