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

adaptive.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 // adaptive.h : contains class adaptive<> and function adaptive_fill()
00032 //
00033 // ********************************************************************
00034 // adaptive_fill():
00035 //
00036 // Fills and builds an interpolator (using class adaptive<>) so that it
00037 // approximates a given function.
00038 //
00039 // usage:
00040 // 
00041 // Given a function f() returning a Y_type:
00042 //        Y_type f(double x);
00043 //
00044 // And an interpolator of Y_types:
00045 //        interpolator<Y_type> Y;
00046 //
00047 // calling:
00048 //        adaptive_fill(Y, f, min_x, max_x);  // to use default tolerances
00049 // (or)   adaptive_fill(Y, f, min_x, max_x, abs_error, rel_error);
00050 //
00051 // will build Y so that Y(x) approximates f(x) within the range
00052 // [min_x .. max_x]. adaptive_fill() returns an int which equals 0 if all
00053 // went well. The tolerances will be calculated using the default global
00054 // norm() function for Y_type objects: double norm(Y_type);
00055 //
00056 // ********************************************************************
00057 // Class adaptive<>:
00058 //
00059 // A templated class used to adaptively build an interpolator
00060 // (cf interpolate.h) of an arbitrary function which meets specified
00061 // accuracy targets. If the default norm() function is adequate, function
00062 // adaptive_fill() is a simple alternative (see below).
00063 //
00064 // Given a function f(x) which calculates some Y_type object as a function
00065 // of the double x, we wish to approximate this function using an
00066 // interpolator Y(x). Class adaptive accomplishes the task of building
00067 // Y(x).
00068 //
00069 // Here's how to use it:
00070 //
00071 // double x;
00072 // Y_type f(double);       // The function to be interpolated. It could
00073 //                         // return a const Y_type & instead.
00074 //
00075 //  ** Note that if f() is a MEMBER FUNCTION of a class object, it can't **
00076 //  ** be used directly by class adaptive. It must be used as described  ** 
00077 //  ** below!!!                                                          **
00078 //
00079 // interpolator<Y_type> Y;  // declare the interpolator object, then
00080 // adaptive<Y_type> a(Y);   // construct an adaptive object from it.
00081 //
00082 // a.min_x = x1;
00083 // a.max_x = x2;            // set the interpolation limits
00084 //
00085 // int bad = a(f);          // this call fills and builds Y to approximate f.
00086 //     or                   // The optional second argument is a function for
00087 // int bad = a(f,n);        // the "squared magnitude" or "norm" of a Y_type y.
00088 //                          // If no second argument is provided, a will use
00089 //                          // the global function norm(y), if it is defined.
00090 //
00091 // if(bad) ...              // bad == 1 if a problem occured with the build.
00092 //
00093 // If either the function to be interpolated or the norm to be used is
00094 // defined as a member function, it must be converted for use with adaptive.
00095 // If, for example, the function to be interpolated is a member function
00096 // of the object Obj of class Cl: ie, f(x) is really Obj.f(x), then the
00097 // function must be passed to a() as follows:
00098 //
00099 //   a(member_function(& Cl::f, Obj))
00100 //
00101 // member_function() returns a function object properly bound to Obj.f() for
00102 // use by adaptive. This extra step is required because pointers to member
00103 // functions (ie, the name of a member function) are not pointers to functions.
00104 // The same conversion must be applied to a norm function as well, if it is
00105 // really a member function of some class.
00106 //
00107 //
00108 // Now we can use the interpolator to approximate f(x):
00109 // 
00110 // Y_type approx_f = Y(x);
00111 // 
00112 // If you wish to change the interpolation, use Y.clear() to throw away
00113 // the old points, then a(f) to rebuild Y.
00114 //
00115 // There are member variables for adaptive which control the accuracy and
00116 // other aspects of approximation; see the class declaration below for
00117 // details.
00118 //
00119 // ********************************************************************
00120 // Change history:
00121 //
00122 // 7/19/99:  Added adaptive_fill()
00123 // 7/8/99:   Moved some definitions into num_utility.h
00124 //
00125 // ********************************************************************
00126 
00127 #ifndef ADAPTIVE_H
00128 #define ADAPTIVE_H
00129 
00130 #include "interpolate.h"
00131 #include "matmath.h"
00132 #include "error.h"
00133 #include <set>
00134 #include "num_utility.h"
00135 
00136 template < class Y_type >  // Y_type is the type of object we're interpolating
00137 class adaptive
00138 {
00139 public:
00140 
00141   // the constructor must be called with an interpolator<Y_type>, which it
00142   // will at a later time adaptively fill with data to meet the desired
00143   // interpolation accuracy.
00144 
00145   explicit adaptive( interpolator<Y_type> & Y_interp );
00146 
00147 
00148   // the following variables control or limit the adaptive sampling process
00149   // (default values in parentheses)
00150 
00151   unsigned min_points;      // (25)       the minimum number of points in the interpolator
00152   unsigned max_points;      // (1000)     the maximum number of points allowed
00153   unsigned recursion_limit; // (10)       the max allowable number of interval subdivisions
00154 
00155     // if either of the following accuracy limits is met, then accuracy is o.k:
00156   double abs_tolerance;  // (1.0e-100) the max absolute error target in the interpolation
00157   double rel_tolerance;  // (1.0e-6)   the max relative error target in the interpolation 
00158 
00159   double min_x;          // (0.0)      the minimum x for the range being interpolated 
00160   double max_x;          // (0.0)      the maximum x for the range being interpolated
00161 
00162 
00163   // The following function (operator ()) actually builds the interpolator, filling
00164   // it with appropriate data points in order to meet the accuracy targets. It returns
00165   // 0 if all went well, 1 if something went wrong (an appropriate error msg will be
00166   // generated in this case as well.) It must be called with a function object to be
00167   // interpolated and a function object returning a double "norm", or "magnitude
00168   // squared" of a Y_type object. The function object f must have an operator ()
00169   // defined which takes a single double argument and returns a Y_type or a const
00170   // reference to a Y_type, that is, it will be called like: "Y_type y = f(x)",
00171   // x a double. The function object n must have an operator () defined which takes a
00172   // single Y_type argument and returns a double which represents the squared
00173   // "magnitude" of the argument; it will be compared to rel_tolerance*rel_tolerance
00174   // and abs_tolerance*abs_tolerance. If no norm function is specified, a default of
00175   // the globally-defined funtion double norm(Y_type) is used, if it exists.
00176 
00177   template <class F, class N>
00178   int operator ()(F f, N n) { return build(f,n); }
00179 
00180   template <class F>
00181   inline int operator ()(F f) { return (*this)(f,norm); }
00182 
00183 
00184 private:
00185 
00186   interpolator <Y_type> & Y;  // the interpolator to build
00187   set<double> chk_pts;        // temporarily holds x values during builds
00188   template <class F, class N> int build(F, N);
00189   template <class F>  double init(F);
00190   template <class F, class N> void check_and_add(F, N, double);
00191 
00192   // the following functional provides access to the overloaded global norm().
00193   default_norm<Y_type> norm ;
00194 
00195 };  // end of adaptive class declaration
00196 
00197 
00198 template < class Y_type >
00199 inline adaptive<Y_type>::adaptive( interpolator<Y_type> & Y_interp )
00200   :
00201   min_points      ( 25       ),
00202   max_points      ( 1000     ),
00203   recursion_limit ( 10       ),
00204   abs_tolerance   ( 1.0e-100 ),
00205   rel_tolerance   ( 1.0e-6   ),
00206   min_x           ( 0.0      ),
00207   max_x           ( 0.0      ),
00208   Y               ( Y_interp )
00209 { }
00210 
00211 
00212 template < class Y_type > template <class F, class N>
00213 inline int adaptive<Y_type>::build(F f, N n)
00214 {
00215   int r;                // counts down recursive interval subdivisions
00216   double dx = init(f);  // fill interpolator with initial points
00217 
00218   // the recursive build loop
00219   for (r = recursion_limit; r && chk_pts.size(); --r, dx /= 2.0) {
00220     check_and_add(f, n, dx);  // checks accuracy and picks new points to add
00221     Y.build();                // rebuild the interpolator with more points
00222     if(Y.size() >= max_points) break;
00223     // normal exit is for chk_pts to be empty
00224   }
00225 
00226   // check for an abnormal termination of the build loop
00227   if(chk_pts.size()) {
00228     if (r == 0)
00229       error::warning("Recursion limit reached in adaptive interpolator build.");
00230     else if (Y.size() >= max_points)
00231       error::warning("Table size limit reached in adaptive interpolator build.");
00232     return 1;
00233   }
00234 
00235   // everthing went as planned
00236   return 0;
00237 
00238 }
00239 
00240 
00241 template < class Y_type > template < class F >
00242 inline double adaptive<Y_type>::init(F f)
00243 {
00244   // initializes:
00245   //  (1) the interpolator with min_points/2 + 1 equally-spaced points
00246   //  (2) chk_pts with the midpoints of the intervals between points
00247   //  (3) dx (returned value) of 1/4 the interval between points
00248   // Since any points in chk_pts get added to the interpolator, we
00249   // anticipate this by not using min_points initially.
00250 
00251   double x1, x2, dx;
00252   unsigned i;
00253 
00254   dx = (max_x - min_x)/(min_points/2); // interval between points
00255   Y.add(min_x,f(min_x));
00256   for (i = 1, x1 = min_x+dx, x2 = min_x+dx/2.0;
00257        i <= min_points/2;
00258        ++i, x1 += dx, x2 += dx) {
00259     Y.add(x1,f(x1));     // adds points to the interpolator
00260     chk_pts.insert(x2);  // interval midpoints to be checked for accuracy
00261   }
00262 
00263   Y.build();      // initial build of the interpolator
00264   return dx/4.0;  // the interval at which new check points should be added to s
00265 }
00266 
00267 
00268 template < class Y_type > template <class F, class N>
00269 inline void adaptive<Y_type>::check_and_add(F f, N n, double dx)
00270 {
00271   // steps through the points in chk_pts (which are sorted and unique, since
00272   // chk_pts is of type set. The value of dx SHOULD BE 1/4 the minimum 
00273   // separation between adjacent points, and determines the spacing to new
00274   // points which may be added. n() is the norm function for a Y_type.
00275 
00276   set<double>::iterator i;  // iterator into chk_pts
00277   double x;
00278   double abs_lim = abs_tolerance*abs_tolerance;  // since norm() = magnitude^2
00279   double rel_lim = rel_tolerance*rel_tolerance;
00280 
00281   // examine and delete each point in chk_pts; add others if required
00282   for (i = chk_pts.begin(); i != chk_pts.end(); /* no increment here */) {
00283 
00284     // destructively fetch the next x from s and increment iterator:
00285     x = *i;
00286     chk_pts.erase(i++);
00287 
00288     // get f(x) and Y(x) and compare them
00289     Y_type y = f(x);
00290     Y.add(x,y);           // add it to the interpolator, since we calculated it
00291     double normf = n(y);  // for relative error calculation
00292     y -= Y(x);            // the error
00293     double error = n(y);  // the norm of the error
00294 
00295     // examine norm of the error and add points to s if necessary
00296     if (error > abs_lim && (normf == 0.0 || error/normf > rel_lim)) {
00297       // accuracy insufficient; add additional points
00298       chk_pts.insert(i, x+dx);
00299       chk_pts.insert(i, x-dx);
00300     }
00301   }
00302 }
00303 
00304 
00305 // ********************************************************************
00306 // fill an interpolator with values to interpolate the function f:
00307 
00308 template < class Y_type, class F >
00309 inline void adaptive_fill(
00310                           interpolator<Y_type> & fi,  // the interpolator to fill
00311                           F f,                        // the function to interpolate
00312                           double min, double max,     // interpolation x limits
00313                           double abs_error = 0.0,     // target absolute error
00314                           double rel_error = 0.0      // target relative error
00315                           )                           //   0 gives the default errors
00316 {
00317   adaptive<Y_type> a(fi);
00318   a.min_x = min; a.max_x = max;
00319   if (abs_error != 0.0) a.abs_tolerance = abs_error;
00320   if (rel_error != 0.0) a.rel_tolerance = rel_error;
00321   a(f);
00322 }
00323 
00324 
00325 #endif /* ADAPTIVE_H */
00326 
00327 

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