example_NIntp.txt

The following source file shows the application of multi-dimensional interpolation calc::NIntp objects and the calc::OptIntp object which analyzes and reduces interpolation errors. The objective in this example is to show the similar uses of the three interpolation objects in optimizing and curve-fitting data.

First, a two-dimensional curve is defined by a generating function curve(). Dictated by the optimizing calc::OptIntp object, this function must accept a vector array of <xType*> which contains a evaluation data for each dimension. The generating function should return a single value of <yType>. The generating function for this example quantifies the Gauss bell-curve in two dimensions.

Parameters should be set which clarify the interpolation. The interpolation interval of the curve is from the origin (the top of the bell) out to unit length in the positive quadrant. Tolerances are set indicating the magnitude of values that will be encountered during the interpolation optimization. If the difference between two interpolation points is less than the given x-tolerance, then the points are assumed identical. The data count by dimension array, ND[NDIM], defines the structure of the interpolation table. The length of the array equals the number of dimensions NDIM in the interpolation table. Each value in the array indictes how many x-intervals the interpolation table has for the specified dimension. From the example below, the x-array of pointers to an array of data and the y-array of multi-dimensional data can be declared from values in the data count by dimension array.

The function calc::OptIntp::setSpanX() completely fills the x-array with values along equally spaced intervals. Optimization can start from any point, however, equal spacing should be a good guess.

Next, the 3 different spline objects are defined, and associated with the curve generating function. The calc::EndCube object is used with calc::NCube to better define the curve. The bell-curve has zero slope at the origin, and this fact can be passed to the cubic spline using the enumerator calc::EndCube::DY (1st derivative). The upper end of the spline is given the default "natural spline" condition using the enumerator calc::EndCube::DDY (2nd derivative) and a zero value. The 3 interpolation optimizer are given increased calc::OptIntp::GRID_SAMPLE values to improve their curve-fit. Because there are 2 dimensions, 25 error samples will be taken to determine interval error in each interval of the interpolation grid.

Once all parameters have been defined, interpolation optimization can begin. The y-arrays of the interpolation objects are initially set to zero. A call to calc::OptIntp::update() automatically fills the array with the correct data. Error data is generated from the current state of the interpolation object with calls to calc::OptIntp::gridError() and calc::OptIntp::randomError(). This data generation/print out is performed before and after the optimization to show if error has decreased.

00001 
00002  #include <cstring>                                    // standard library memory functions
00003  #include "OptIntp.h"                                  // function interpolation objects
00004  #include "PrtC.h"                                     // auxiliary print stream object
00005 
00006  using namespace std;                                  // standard C++ library namespace
00007  using namespace calc;                                 // CalcLib namespace
00008 
00009  typedef EndCube<double,double> ECUd;                  // cubic spline derivative information type
00010  typedef OptIntp<double,double> OPTd;                  // interpolation optimization type
00011 
00012  // 2D Gauss curve generating function
00013  double curve(const double *xVec)
00014     {return exp(-(xVec[0]*xVec[0]+xVec[1]*xVec[1]));}
00015 
00016  // results print function
00017  void results(ostream &ostr, const char *cDat, double va, double vb, double vc)
00018     {ostr<<"   "<<cDat<<"  "<<va<<"   "<<vb<<"   "<<vc<<endl;}
00019 
00020  // error generate function
00021  bool errors(OPTd& opt)
00022     {return (opt.update()                              // check interpolation tables
00023            ||opt.gridError()                           // generate grid selection errors
00024            ||opt.randomError());}                      // generate random selection errors
00025 
00026  // summary print function
00027  bool summary(ostream &ostr, const char *cDat, OPTd& ocu, OPTd& onu, OPTd& opo)
00028  {
00029     // generate error data
00030     if((errors(ocu))||(errors(onu))||(errors(opo))) return true;
00031 
00032     // print error data
00033     ostr<<"   "<<cDat<<endl;
00034     ostr<<"   "<<"                          NCube      NNurb      NPoly"<<endl;
00035     results(ostr,"Grid Error Average:   ",ocu.getError(ocu.GRID_AVG  ),
00036              onu.getError(onu.GRID_AVG  ),opo.getError(opo.GRID_AVG  ));
00037     results(ostr,"Random Error Average: ",ocu.getError(ocu.RANDOM_AVG),
00038              onu.getError(onu.RANDOM_AVG),opo.getError(opo.RANDOM_AVG));
00039     ostr<<endl;
00040 
00041     return false;
00042  }
00043 
00044  int main(void)
00045  {
00046     // set parameters
00047     const int    NDIM=2;                               // number of interpolation dimensions
00048     const int    NCNT0=3;                              // data count of 1st dimension
00049     const int    NCNT1=3;                              // data count of 2nd dimension
00050     const int    ND[NDIM]={NCNT0,NCNT1};               // data count by dimension array
00051     const double XLO =0.0;                             // independent interpolation data low value
00052     const double XHI =1.0;                             // independent interpolation data high value
00053     const double XTOL=0.001;                           // independent data tolerance
00054     const double YTOL=0.001;                           // dependent data tolerance
00055 
00056     double aX0[NCNT0];                                 // independent data array (1st dimension)
00057     double aX1[NCNT1];                                 // independent data array (2nd dimension)
00058     double *aXn[NDIM]={aX0,aX1};                       // independent data by dimension array
00059     double aYn[NCNT1][NCNT0];                          // dependent data array (1st dimension)
00060 
00061     // clear data arrays
00062     std::memset(aX0,0,ND[0]*sizeof(*aX0));             // standard library function from <cstring>
00063     std::memset(aX1,0,ND[1]*sizeof(*aX1));             // set independent data arrays to zero's
00064     std::memset(aYn[0],0,ND[0]*ND[1]*sizeof(**aYn));   // set dependent data array to zero's
00065 
00066     // spread independent data array values at even intervals
00067     if(OPTd::setSpanX(aXn,XLO,XHI,ND,NDIM)) return 1;
00068 
00069     // create interpolation objects
00070     const ECUd EC(0.0,ECUd::DY,0.0,ECUd::DDY);         // spline lower end point should have zero slope
00071     const ECUd ECN[NDIM]={EC,EC};                      // required for both dimensions
00072     NCube<double,double> ncu(aXn,&aYn[0][0],ND,NDIM,ECN);
00073     NNurb<double,double> nnu=ncu;
00074     NPoly<double,double> npo=nnu;
00075 
00076     // create optimization objects
00077     OPTd ocu(curve,ncu); 
00078     OPTd onu(curve,nnu);
00079     OPTd opo(curve,npo);
00080 
00081     ocu.setParameter(ocu.GRID_SAMPLE,5);               // set 5 test samples per dimension
00082     onu.setParameter(onu.GRID_SAMPLE,5);
00083     opo.setParameter(opo.GRID_SAMPLE,5);
00084 
00085     // set up print stream
00086     cout.precision(5);
00087     cout.setf(ios::showpoint,ios::showpoint);
00088 
00089     // print errors, optimize, print errors
00090     cout<<endl<<"   calc::NIntp Class Example Application"<<endl<<endl;
00091     if((summary(cout,"Errors Before Optimization",ocu,onu,opo))
00092      ||(ocu.optimize(XTOL,YTOL))
00093      ||(onu.optimize(XTOL,YTOL))
00094      ||(opo.optimize(XTOL,YTOL))
00095      ||(summary(cout,"Errors After Optimization",ocu,onu,opo))) return 1;
00096 
00097     // print out interpolation object with best results (cubic spline)
00098     PrtC pr;
00099     pr.setFormat(pr.DOUBLE,pr.DOUBLE);
00100     pr.stream(cout,ncu);
00101     cout<<flush;
00102 
00103     return 0;
00104  }
00105 

The following output file was generated by the above source code. Three different interpolation methods are used: (1) calc::NCube (cubic splines); (2) calc::NNurb (non-uniform rational Bezier splines); (3) calc::NPoly (polynomial curve-fit splines). Each interpolation object is evaluated using the same data. From the output data, the calc::NCube cubic spline is optimized to have the lowest error.

00001 
00002    calc::NIntp Class Example Application
00003 
00004    Errors Before Optimization
00005                              NCube      NNurb      NPoly
00006    Grid Error Average:     0.0074914   0.020002   0.020002
00007    Random Error Average:   0.0065139   0.018117   0.018117
00008 
00009    Errors After Optimization
00010                              NCube      NNurb      NPoly
00011    Grid Error Average:     0.0047456   0.020002   0.020002
00012    Random Error Average:   0.0041324   0.018117   0.018117
00013 
00014 
00015    // CalcLib NIntp Multi-Dimensional Tabular Interpolation Parameters
00016 
00017    // CalcLib EndCube Derivative Identifier Parameters
00018    const EndCube< double,double > endCuben     [ 2]={
00019       EndCube< double,double >(double(  0.00000e+00), EndCube< double,double >::DY  , double(  0.00000e+00), EndCube< double,double >::DDY ),
00020       EndCube< double,double >(double(  0.00000e+00), EndCube< double,double >::DY  , double(  0.00000e+00), EndCube< double,double >::DDY ),
00021    };
00022 
00023    // CalcLib Data Count by Dimension Data Array
00024    const int           arNn         [ 2]={ int(            3), int(            3)};
00025 
00026    // CalcLib Independent Data Array
00027    const double        arX0         [ 3]={ double(  0.00000e+00), double(  6.88000e-01), double(  1.00000e+00)};
00028    const double        arX1         [ 3]={ double(  0.00000e+00), double(  6.89000e-01), double(  1.00000e+00)};
00029    const double*       arXn         [ 2]={ arX0, arX1};
00030 
00031    // CalcLib Dependent Data Array
00032    const double        arYn         [ 3][ 3]=
00033       {
00034          { double(  1.00000e+00), double(  6.22916e-01), double(  3.67879e-01)},
00035          { double(  6.22059e-01), double(  3.87490e-01), double(  2.28843e-01)},
00036          { double(  3.67879e-01), double(  2.29158e-01), double(  1.35335e-01)},
00037       };
00038 
00039    // CalcLib 2nd Derivative Data Array
00040    const double        arDn         [ 3][ 3]=
00041       {
00042          { double( -3.99741e-01), double(  2.84256e-03), double(  0.00000e+00)},
00043          { double( -2.48662e-01), double(  1.76824e-03), double(  0.00000e+00)},
00044          { double( -1.47056e-01), double(  1.04572e-03), double(  0.00000e+00)},
00045       };
00046 

Generated on Wed Jul 19 09:23:35 2006 for CalcLib by  doxygen 1.4.7