casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Chebyshev.h
Go to the documentation of this file.
00001 //# Chebyshev.h  A function class that defines a Chebyshev polynomial
00002 //# Copyright (C) 2000,2001,2002,2003,2005
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //#
00005 //# This library is free software; you can redistribute it and/or modify it
00006 //# under the terms of the GNU Library General Public License as published by
00007 //# the Free Software Foundation; either version 2 of the License, or (at your
00008 //# option) any later version.
00009 //#
00010 //# This library is distributed in the hope that it will be useful, but WITHOUT
00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013 //# License for more details.
00014 //#
00015 //# You should have received a copy of the GNU Library General Public License
00016 //# along with this library; if not, write to the Free Software Foundation,
00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00018 //#
00019 //# Correspondence concerning AIPS++ should be addressed as follows:
00020 //#        Internet email: aips2-request@nrao.edu.
00021 //#        Postal address: AIPS++ Project Office
00022 //#                        National Radio Astronomy Observatory
00023 //#                        520 Edgemont Road
00024 //#                        Charlottesville, VA 22903-2475 USA
00025 //#
00026 //#! ========================================================================
00027 //# $Id: Chebyshev.h 21024 2011-03-01 11:46:18Z gervandiepen $
00028 
00029 #ifndef SCIMATH_CHEBYSHEV_H
00030 #define SCIMATH_CHEBYSHEV_H
00031 
00032 #include <casa/aips.h>
00033 #include <scimath/Functionals/ChebyshevParam.h>
00034 #include <scimath/Functionals/Function1D.h>
00035 #include <scimath/Mathematics/AutoDiff.h>
00036 #include <scimath/Mathematics/AutoDiffMath.h>
00037 
00038 namespace casa { //# NAMESPACE CASA - BEGIN
00039 
00040 //# Forward Declarations
00041 
00042 // <summary> A function class that defines a Chebyshev polynomial
00043 // </summary>
00044 
00045 // <use visibility=export>
00046 
00047 // <reviewed reviewer="wbrouw" date="2001/11/12" tests="tChebyshev" demos="">
00048 // </reviewed>
00049 
00050 // <prerequisite>
00051 //   <li> <linkto class=Function>Function</linkto>
00052 // </prerequisite>
00053 //
00054 // <etymology>
00055 // This class is named after Chebyshev Type I polynomials 
00056 // </etymology>
00057 //
00058 // <synopsis>
00059 // This class allows one to form and evaluate a function as a
00060 // Chebyshev series, a linear combination of so-called Chebyshev
00061 // polynomials. 
00062 //
00063 // This class's implementation is split into two parts: 
00064 // the parent class <linkto class="ChebyshevParam">ChebyshevParam&lt;T&gt;</linkto>,
00065 // which manages the function's parameters, and this class, which handles
00066 // how the function is evaluated.  Thus, be sure to also consult 
00067 // <linkto class="ChebyshevParam">ChebyshevParam&lt;T&gt;</linkto> for 
00068 // the full interface of this function.  
00069 // 
00070 // <ANCHOR NAME="Chebyshev:about">
00071 // <H3>About Chebyshev Polynomials</H3></ANCHOR>
00072 // 
00073 // Chebyshev polynomials are a special type of ultraspheric polynomials 
00074 // that are useful in such contexts as numerical analysis and circuit
00075 // design. They form an orthogobnal set.
00076 // A (type I) Chebyshev polynomial, T_n, is generated via the
00077 // equation:
00078 // <srcblock>
00079 // T_n(x) = cos n(arccos x)
00080 // </srcblock>
00081 // Through clever use of trigometric identities, one can express T_n
00082 // as a real polynomial expression of the form
00083 // <srcblock>
00084 //           n
00085 // T_n(x) = SUM C_i t^i
00086 //          i=0
00087 // </srcblock>
00088 // The low order polynomials look like this:
00089 // <srcblock>
00090 // T_0 = 1
00091 // T_1 = x
00092 // T_2 = 2x^2 - 1
00093 // T_3 = 4x^3 - 3x
00094 // T_4 = 8x^4 - 8x^2 + 1
00095 // T_5 = 16x^5 - 20x^3 + 5x 
00096 // </srcblock>
00097 // Higher order polynomials satisfy the recurrance relation,
00098 // <srcblock>
00099 // T_(n+1) = 2xT_(n) - T_(n-1).
00100 // </srcblock>
00101 // 
00102 // A common use of Chebyshev polynomials is in approximating
00103 // functions.  In particular, any function that is approximated by
00104 // a power series,
00105 // <srcblock>
00106 // f(x) ~ SUM P_i x^i,
00107 // </srcblock>
00108 // over the interval [-1, 1] can be approximated by a linear
00109 // combination of Chebyshev polynomials:
00110 // <srcblock>
00111 // f(x) ~ SUM C_i T_i(x),
00112 // </srcblock>
00113 // where C_i is the set of so-called Chebyshev coefficients.
00114 // 
00115 // Approximating a function with Chebyshev polynomials has some
00116 // important advantages.  For one, if the function is well approximated
00117 // by a converging power series, one can obtain an equally accurate
00118 // estimate using fewer terms of the corresponding Chebyshev series.
00119 // More important, though, is the property over the interval [-1, 1],
00120 // each polynomial has a domain of [-1, 1]; thus, the series is nicely
00121 // bounded.  And because of this bounded property, approximations
00122 // calculated from a Chebyshev series are less susceptible to machine
00123 // rounding errors than the equivalent power series.  
00124 //
00125 // <ANCHOR NAME="Chebyshev:using">
00126 // <H3>Using the Chebyshev Function class</H3></ANCHOR>
00127 // 
00128 // With a simple change of variable, it is possible to approximate a
00129 // continuous function over any restricted interval using a
00130 // Chebyshev series.  This documention refers to this interval as the
00131 // <em>Chebyshev interval</em> (set with the
00132 // <linkto class="ChebyshevParam">setInterval()</linkto> function).  The
00133 // other important input parameters, of course, include the
00134 // coefficients of the polynomials.  
00135 //
00136 // Like all Functions, the Chebyshev series is evaluated via the 
00137 // function operator, <src>operator()</src>.  If the input value is 
00138 // within the range set by
00139 // <linkto class="ChebyshevParam">setInterval()</linkto>, it is 
00140 // transformed to the range [-1, 1] via,
00141 // <srcblock>
00142 // y = x - (min + max)/2) / ((max - min)/2)
00143 // </srcblock>
00144 // The series is then evaluated with the coefficients set either at
00145 // construction or via setCoefficients().  The value that is returned
00146 // when the input value is outside the Chebyshev interval depends on
00147 // the out-of-interval mode (set via 
00148 // <linkto class="ChebyshevParam">setOutOfIntervalMode()</linkto>).  The
00149 // default mode is to return a default value which can be set via
00150 // <linkto class="ChebyshevParam">setDefault()</linkto>.  The supported 
00151 // modes are identified by the
00152 // enumeration OutOfIntervalMode; see the 
00153 // <linkto class="ChebyshevParam">documentation for ChebyshevParam</linkto>
00154 // for a detailed description of these modes.  In practice, though, it is 
00155 // expected that this class will be configured for the interval of interest.  
00156 // 
00157 // The derivative of a Chebyshev series with respect to the independent 
00158 // variable (i.e. the argument <src>x</src>) is easily calculated analytically 
00159 // and can be expressed as another Chebyshev series; this is what the
00160 // <src>derivative()</src> function returns.  However, the more general way to
00161 // obtain derivatives is via the <linkto class="AutoDiff">AutoDiff</linkto> 
00162 // templated type.  
00163 //
00164 // </synopsis>
00165 //
00166 // <example>
00167 // In this example, a 2nd order Chebyshev polynomial series is
00168 // created.
00169 // <srcblock>
00170 //   // set coeffs to desired values
00171 //   Vector<Double> coeffs(3, 1);   
00172 //
00173 //   // configure the function   
00174 //   Chebyshev<Double> cheb;
00175 //   cheb.setInterval(-0.8, 7.2);
00176 //   cheb.setDefault(1.0);
00177 //   cheb.setCoefficients(coeffs);
00178 //
00179 //   // evaluate the function as necessary
00180 //   Double z = cheb(-0.5);    // -0.5 is within range, z = 0.78625
00181 //   z = cheb(4.2);            // 4.2 is within range, z = 0.375
00182 //   z = cheb(-3);             // -3 is out of the interval, z = 1
00183 // </srcblock>
00184 //
00185 // The next example illustrates how to use the 
00186 // <linkto class="AutoDiff">AutoDiff</linkto> class to simultaneously
00187 // calculate derivatives.  Here, we replace the Double type with 
00188 // AutoDiff<Double>.
00189 // <srcblock>
00190 //   Chebyshev<AutoDiffA<Double> > cheb;
00191 //   cheb.setDefault(AutoDiffA<Double>(1));
00192 //   cheb.setInterval(AutoDiffA<Double>(-0.8), AutoDiffA<Double>(7.2));
00193 //
00194 //   // we'll track derivatives with respect to x and each of our
00195 //   // coefficients; for a second-order series, this makes 4
00196 //   // derivatives total.  x will be the first variable; the
00197 //   // coefficients will the 2nd-4th variables
00198 //   cheb.setCoefficient(0, AutoDiffA<Double>(3.1, 4, 1));   // c0 = 3.1
00199 //   cheb.setCoefficient(1, AutoDiffA<Double>(2.4, 4, 2));   // c1 = 2.4
00200 //   cheb.setCoefficient(2, AutoDiffA<Double>(0.5, 4, 3));   // c2 = 0.5
00201 //   
00202 //   // now evaluate the function
00203 //   AutoDiffA<Double> x(1.2, 4, 0);    // x = 1.2
00204 //   AutoDiffA<Double> y = cheb(x);     // y = 1.65
00205 //   Double dydx = y.derivative(0);     // dy/dx = 0.35
00206 //   Double dydc1 = y.derivative(2);    // dy/dc1 = -0.5
00207 // </srcblock>
00208 // </example>
00209 //
00210 // <motivation>
00211 // This class was created to support systematic errors in the simulator tool.  
00212 // It can be used by Jones matrix classes to vary gains in a predictable way,
00213 // mimicing natural processes of the atmosphere or instrumental effects.  
00214 // </motivation>
00215 
00216 // <templating arg=T>
00217 //  <li> T should have standard numerical operators. Current
00218 //      implementation only tested for real types (and their AutoDiffs).
00219 // </templating>
00220 
00221 // <thrown>
00222 //    <li> Assertion in debug mode if attempt is made to address incorrect
00223 //              coefficients
00224 // </thrown>
00225 //
00226 // <todo asof="2001/08/22">
00227 //    <li> It would be helpful to be able to convert to and from the 
00228 //         Polynomial<T> type; this would be supported via a function,
00229 //         Polynomial<T> polynomial(), and constructor, 
00230 //         Chebyshev(Polynomial<T>)
00231 // </todo>
00232 
00233 template<class T>
00234 class Chebyshev : public ChebyshevParamModeImpl<T> {
00235 public: 
00236 
00237     //# Constructors
00238     // create a zero-th order Chebyshev polynomial with the first coefficient
00239     // equal to zero.  The bounded domain is [T(-1), T(1)].  The 
00240     // OutOfDomainMode is CONSTANT, and the default value is T(0).
00241     Chebyshev() : ChebyshevParamModeImpl<T>() {}
00242 
00243     // create an n-th order Chebyshev polynomial with the coefficients
00244     // equal to zero.  The bounded domain is [T(-1), T(1)].  The 
00245     // OutOfDomainMode is CONSTANT, and the default value is T(0).
00246     explicit Chebyshev(const uInt n) : ChebyshevParamModeImpl<T>(n) {}
00247 
00248     // create a zero-th order Chebyshev polynomical with the first coefficient
00249     // equal to one.  
00250     //   min is the minimum value of its Chebyshev interval, and 
00251     //   max is the maximum value.  
00252     //   mode sets the behavior of the function outside the Chebyshev interval
00253     //      (see setOutOfIntervalMode() and OutOfIntervalMode enumeration 
00254     //      definition for details).  
00255     //   defval is the value returned when the function is evaluated outside
00256     //      the Chebyshev interval and mode=CONSTANT.
00257     Chebyshev(const T &min, const T &max,
00258               const typename ChebyshevEnums::
00259               OutOfIntervalMode mode=ChebyshevEnums::CONSTANT,
00260               const T &defval=T(0)) :
00261         ChebyshevParamModeImpl<T>(min, max, mode, defval) {}
00262   
00263     // create a fully specified Chebyshev polynomial.  
00264     //   coeffs holds the coefficients of the Chebyshev polynomial (see 
00265     //      setCoefficients() for details).
00266     //   min is the minimum value of its canonical range, and 
00267     //   max is the maximum value.  
00268     //   mode sets the behavior of the function outside the Chebyshev interval
00269     //      (see setOutOfIntervalMode() and OutOfIntervalMode enumeration 
00270     //      definition for details).  
00271     //   defval is the value returned when the function is evaluated outside
00272     //      the canonical range and mode=CONSTANT.
00273     Chebyshev(const Vector<T> &coeffs, const T &min, const T &max, 
00274               const typename ChebyshevEnums::
00275               OutOfIntervalMode mode=ChebyshevEnums::CONSTANT,
00276               const T &defval=T(0)) :
00277         ChebyshevParamModeImpl<T>(coeffs, min, max, mode, defval) {}
00278 
00279     // create a fully specified Chebyshev polynomial.
00280     //   config  is a record that contains the non-coefficient data 
00281     //             that configures this class.
00282     // The fields recognized by this class are those documented for the 
00283     // <linkto class="ChebyshevParam">ChebyshevPara::setMode()</linkto> 
00284     // function.
00285     // <group>
00286     Chebyshev(uInt order, const RecordInterface& mode) :
00287         ChebyshevParamModeImpl<T>(order, mode) { }
00288     Chebyshev(const Vector<T> &coeffs, const RecordInterface& mode) :
00289         ChebyshevParamModeImpl<T>(coeffs, mode) { }
00290     // </group>
00291   
00292     // create a deep copy of another Chebyshev polynomial
00293     // <group>
00294     Chebyshev(const Chebyshev &other) : ChebyshevParamModeImpl<T>(other) {}
00295     // </group>
00296 
00297     // make this instance a (deep) copy of another Chebyshev polynomial
00298     Chebyshev<T> &operator=(const Chebyshev<T> &other) {
00299         ChebyshevParam<T>::operator=(other); return *this; }
00300   
00301     // Destructor
00302     virtual ~Chebyshev() {}
00303   
00304     //# Operators    
00305     // Evaluate the Chebyshev at <src>x</src>.
00306     virtual T eval(const typename FunctionTraits<T>::ArgType *x) const;
00307   
00308     //# Member functions
00309     // Return the Chebyshev polynomial which is the derivative of this one
00310     // (with respect to the argument <src>x</src>).
00311     Chebyshev<T> derivative() const;
00312   
00313     // Create a new copy of this object.  The caller is responsible 
00314     // for deleting the pointer. 
00315     // <group>
00316     virtual Function<T> *clone() const { return new Chebyshev<T>(*this); }
00317   // </group>
00318 
00319 };
00320 
00321 
00322 } //# NAMESPACE CASA - END
00323 
00324 #ifndef CASACORE_NO_AUTO_TEMPLATES
00325 #include <scimath/Functionals/Chebyshev.tcc>
00326 #endif //# CASACORE_NO_AUTO_TEMPLATES
00327 #endif