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
1.2.7