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
1.4.7