Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

polynomial.h

Go to the documentation of this file.
00001 // SuperMix version 1.0  C++ source file
00002 //
00003 // Copyright (c) 1999 California Institute of Technology.
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms for noncommercial
00007 // purposes are permitted provided that the above copyright notice and
00008 // this paragraph are duplicated in all such forms and that any
00009 // documentation and other materials related to such distribution and
00010 // use acknowledge that the software was developed by California
00011 // Institute of Technology. Redistribution and/or use in source or
00012 // binary forms is not permitted for any commercial purpose. Use of
00013 // this software does not include a permitted use of the Institute's
00014 // name or trademark for any purpose.
00015 //
00016 // DISCLAIMER:
00017 // THIS SOFTWARE AND/OR RELATED MATERIALS ARE PROVIDED "AS-IS" WITHOUT
00018 // WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR
00019 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE (AS SET
00020 // FORTH IN UCC 23212-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
00021 // LICENSED PRODUCT, HOWEVER USED.  IN NO EVENT SHALL CALTECH/JPL BE
00022 // LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING BUT NOT LIMITED TO
00023 // INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING ECONOMIC
00024 // DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF
00025 // WHETHER CALTECH/JPL SHALL BE ADVISED, HAVE REASON TO KNOW, OR IN
00026 // FACT SHALL KNOW OF THE POSSIBILITY.  THE USER BEARS ALL RISK
00027 // RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND/OR RELATED
00028 // MATERIALS.
00029 //
00030 // ********************************************************************
00031 // polynomial.h
00032 //
00033 // includes classes for generating and manipulating polynomials
00034 //
00035 // F. Rice
00036 // 7/8/99
00037 //
00038 // ********************************************************************
00039 #ifndef POLYNOMIAL_H
00040 #define POLYNOMIAL_H
00041 
00042 #include <pair.h>
00043 #include <vector>
00044 #include "error.h"
00045 
00046 // ********************************************************************
00047 // class poly_fit
00048 //
00049 // 1-dimensional polynomial interpolation and extrapolation from a set of
00050 // supplied data points. The x (independent variable) values must be doubles;
00051 // the y (dependent variable) objects must be members of a "vector space" with
00052 // the following operations defined on them (Y_type is the type of the objects):
00053 //
00054 // Y_type A;    // construct an instance of Y_type, no particular value.
00055 // Y_type B(A); // construct an independent copy of Y_type A;
00056 // A = B;       // make A an independent copy of B
00057 // A *= x;      // modify A by scaling by the double x.
00058 // A += B;      // modify A by adding B to it
00059 // A -= B;      // modify A by subtracting B from it
00060 //
00061 // Y_type objects must be a vector space, in that (A *= 2.0) is equivalent
00062 // to (A += A), and (A *= 0.0) is equivalent to (A -= A) and gives the
00063 // additive identity of Y_type, etc. 
00064 //
00065 // The data point (x,y) pairs are passed to poly_fit using an STL vector
00066 // object of STL pairs; typedefs are provided to streamline the declarations
00067 // of these objects.
00068 //
00069 // The returned value is an STL pair of y values; the first element is the
00070 // interpolated value, the second is an estimate of the error in the
00071 // interpolation. For example:
00072 //
00073 // poly_fit<complex> Z;
00074 //
00075 // poly_fit<complex>::result answer = Z(x);  // do an interpolation
00076 //
00077 // complex   z     = answer.first; 
00078 // complex   error = answer.second;
00079 // 
00080 //
00081 // Algorithm based on routine polint(), from Numerical Recipes in C, 2nd ed.
00082 //
00083 // F. Rice
00084 // 7/8/99
00085 //
00086 // ********************************************************************
00087 
00088 template <class Y>
00089 class poly_fit
00090 {
00091 public:
00092 
00093   // data types used by poly_fit:
00094   typedef pair<double,Y>          entry;    // hold an (x,Y) point 
00095   typedef vector<entry>           entries;  // vector of (x,Y) points
00096   typedef entries::const_iterator const_iterator;  // iterator into supplied points
00097   typedef pair<Y,Y>               result;   // hold result and error estimate
00098   
00099   // fit a polynomial P to the points in STL vector v, and return P(x):
00100   result operator()(double x, const entries & v);
00101 
00102   // fit a polynomial to the n points of the STL vector starting with p, return P(x):
00103   // (this also works with a C array of entry for p);
00104   result operator()(double x, const_iterator p, unsigned n);
00105 
00106   // fit a polynomial to the most recently provided points (saved internally),
00107   // return P(x):
00108   result operator()(double x) const;
00109   
00110 private:
00111 
00112   // hold the result returned by operator():
00113   mutable result save_result;
00114 
00115   // hold a vector of points that were last fit:
00116   entries data;
00117   unsigned N;    // one greater than order of fit
00118 
00119   // hold forward and backward differences:
00120   mutable vector<Y> fd, bd;
00121 
00122 };  // class poly_fit
00123 
00124 template <class Y>
00125 inline poly_fit<Y>::result poly_fit<Y>::operator()(double x) const
00126 {
00127   Y & y  = save_result.first;   // aliases for the result
00128   Y & dy = save_result.second;  // and the error estimate
00129 
00130   if(!N) {
00131     // size()==0, so no data to fit
00132     error::warning("No data points passed to poly_fit.");
00133     y = dy = Y();               // "empty" return value
00134     return save_result;
00135   }
00136 
00137   // first step: loop through data, find nearest neighbor of x while
00138   //initializing fd and bd.
00139 
00140   unsigned fm = fd.size();  // bd is the same size as fd
00141 
00142   double d = fabs(x - data[0].first);  // assume for now that x0 is nearest 
00143   unsigned n = 0;                      // n is a node index into difference tree
00144 
00145   for(unsigned i = 0; i < N; ++i) {
00146 
00147     const Y & yd = data[i].second;
00148     if (i < fm) 
00149       fd[i] = bd[i] = yd; // no constructor calls here
00150     else {
00151       fd.push_back(yd);
00152       bd.push_back(yd);
00153     }
00154 
00155     double xd = data[i].first;
00156     if(fabs(x - xd) < d) {
00157       d = fabs(x - xd);
00158       n = i;
00159     }
00160   }
00161 
00162   // 0th order approx is that nearest neighbor is the answer:
00163   y = data[n].second;
00164 
00165   // loop generates ever higher order approximations:
00166   for(unsigned order = 1; order < N; ++order) {
00167  
00168     // this loop generates new differences from the old:
00169     for(unsigned i = 0; i < N-order; ++i) {
00170       fd[i] = fd[i+1]; fd[i] -= bd[i];  // now fd[i] == fd[i+1]-bd[i]
00171       bd[i] = fd[i];
00172       double dx = data[i].first - data[i+order].first;  // ie: x[i]-x[i+order]
00173       if (dx == 0.0) {
00174         // two x values match; no polynomial fit is possible
00175         error::fatal("x values in data points passed to poly_fit must be unique.");
00176       }
00177       dx = 1.0/dx;    // so we really divide by dx below:
00178       fd[i] *= dx*(data[i].first - x);       // ie: (x[i]-x)/dx
00179       bd[i] *= dx*(data[i+order].first - x); // ie: (x[i+order]-x)/dx
00180     }
00181 
00182     // Now use the new differences to update solution,
00183     // taking a path which keeps node n near x:
00184     dy = ( 2*n < N-order ) ? fd[n] : bd[--n];
00185     y += dy;
00186   }
00187 
00188   return save_result;
00189 
00190 }  // poly_fit::operator()
00191 
00192 
00193 // the tricky part for these other operator() is to minimize calls to constructors
00194 // and destructors for the elements:
00195 
00196 template <class Y>
00197 inline poly_fit<Y>::result poly_fit<Y>::operator()(double x, const entries & v)
00198 { 
00199   N = v.size();
00200   unsigned i;
00201   unsigned m = (N > data.size()) ? data.size() : N;
00202 
00203   for (i = 0; i < m; ++i) data[i] = v[i];       // no constructor calls here
00204   for (     ; i < N; ++i) data.push_back(v[i]); 
00205   return operator()(x);
00206 }
00207 
00208 template <class Y>
00209 inline poly_fit<Y>::result poly_fit<Y>::operator()(double x, const_iterator p, unsigned n)
00210 { 
00211   N = n;
00212   unsigned i;
00213   unsigned m = (N > data.size()) ? data.size() : N;
00214 
00215   for (i = 0; i < m; ++i) data[i] = *(p++);       // no constructor calls here
00216   for (     ; i < N; ++i) data.push_back(*(p++)); 
00217   return operator()(x);
00218 }
00219 
00220 #endif /* POLYNOMIAL_H */

Please direct comments and corrections to supermix@submm.caltech.edu
Go to the supermix home page
Generated by doxygen1.2.7