C++
Polynom interpolation
Header file
#ifndef __INTERPOLATION_H__ #define __INTERPOLATION_H__ #include <boost/numeric/ublas/matrix.hpp> #include <vector> using boost::numeric::ublas::vector; using boost::numeric::ublas::matrix; using boost::numeric::ublas::zero_matrix; namespace { enum polynome_type { linear=0, monotonic=1, smooth=2 }; /** * Create interpolation polynomes between nodes **/ template<polynome_type> int interpolate ( boost::numeric::ublas::matrix<double> nodes, boost::numeric::ublas::vector<boost::numeric::ublas::matrix<double> >& polynomes ); } // POLYNOME_TYPE // Type of interpolation polynome // 0 = linear (lines with positional continuity) // 1 = monotonic (monotonic spline with tangential continuity) // 2 = smooth (spline with curvature continuity) #ifndef POLYNOME_TYPE #define POLYNOME_TYPE 1 #endif #if POLYNOME_TYPE == 0 namespace { // integrating linear polynomes with one step template<class Route, class State> void integrate ( Route r, State& x , double t0 , double t1, const double dxdt, void (*write_out) ( const State& , const double )) { write_out(x, t0); r(x, x, t0); } template<> inline int interpolate<linear> ( matrix<double> nodes, vector<matrix<double> >& polynomes ) { const size_t size=nodes.size1(); assert ( size>1 && "At least two nodes needed for interpolation" ); // linear interpolation // calculate coefficients of linear polynomes polynomes.resize ( size-1 ); for ( size_t i=0; i<size-1; ++i ) { polynomes[i]=zero_matrix<double> ( 2, 2 ); for ( size_t j = 0; j < polynomes[i].size1(); ++j ) { polynomes[i] ( j, 0 ) =nodes ( i, j ); polynomes[i] ( j, 1 ) =nodes ( i+1, j ) - nodes ( i, j ); } } } } #elif (POLYNOME_TYPE == 1) || (POLYNOME_TYPE == 2) #include <boost/numeric/ublas/lu.hpp> #include <boost/numeric/ublas/banded.hpp> #include <boost/numeric/ublas/io.hpp> #include <boost/numeric/ublas/vector.hpp> #include <boost/numeric/odeint.hpp> using boost::numeric::odeint::integrate; namespace { void hermite_matrix ( matrix<double>& ); void toeplitz_matrix ( matrix<double>&); /** * Calculate the inverse matrix * @param inverse [in, out] **/ int inverse ( matrix<double>& inverse ); template<> inline int interpolate<monotonic> ( matrix<double> nodes, vector<matrix<double> >& polynomes ) { using boost::numeric::ublas::matrix; using boost::numeric::odeint::integrate; typedef double T; // interpolation polynomes are monotone cubic splines // with continous first derivative // http://de.wikipedia.org/wiki/Kubisch_Hermitescher_Spline const size_t size=nodes.size1(); assert ( size>1 && "At least two nodes needed for interpolation" ); polynomes.resize ( size-1 ); matrix<T> A; hermite_matrix(A); inverse ( A ); // solve linear equation system AX=B for each node for ( size_t i=0; i<polynomes.size(); ++i ) { // set right hand side of the linear equation system // one column for x and one for y coordinate matrix<T> B=zero_matrix<T> ( 4, 2 ); for ( size_t j=0; j<2; ++j ) { if ( i!=0 && i!=polynomes.size()-1 ) { B ( 0, j ) =nodes ( i, j ); B ( 1, j ) =nodes ( i+1, j ); B ( 2, j ) =.5 * ( nodes ( i+1, j ) - nodes ( i-1, j ) ); //mk B ( 3, j ) =.5 * ( nodes ( i+2, j ) - nodes ( i, j ) ); //mk+1 } else { B ( 0, j ) =nodes ( i, j ); B ( 1, j ) =nodes ( i+1, j ); if ( i ) { B ( 2, j ) =0.5* ( nodes ( i+1, j ) - nodes ( i-1, j ) ); B ( 3, j ) =1.0* ( nodes ( i+1, j ) - nodes ( i, j ) ); } else { B ( 2, j ) =1.0* ( nodes ( i+1, j ) - nodes ( i, j ) ); B ( 3, j ) =.5 * ( nodes ( i+2, j ) - nodes ( i, j ) ); } } // preserve monotonicity // http://en.wikipedia.org/wiki/Monotone_cubic_interpolation if ( B ( 0, j ) ==B ( 1, j ) ) { assert ( 0 ); B ( 2, j ) =0; B ( 3, j ) =0; } else { T dk=nodes ( i+1, j ) - nodes ( i, j ); T ak=B ( 2, j ) /dk; T bk=B ( 3, j ) /dk; T r=pow ( ak,2 ) +pow ( bk,2 ); if ( r>=9 ) { B ( 2, j ) =3*ak*dk/sqrt ( r ); B ( 3, j ) =3*bk*dk/sqrt ( r ); } } } polynomes[i]=trans ( prod ( A,B ) ); } } template<> inline int interpolate<smooth> ( matrix<double> nodes, vector<matrix<double> >& polynomes ) { const size_t size=nodes.size1(); assert ( size>1 && "At least two nodes needed for interpolation" ); /** interpolation polynomes are cubic splines with continous second derivative the coefficients are calculated by solving the linear equation system A*X=B @see http://mathworld.wolfram.com/CubicSpline.html */ // create a Tridiagonal-Toeplitz-Matrix matrix<double> A(size,size); toeplitz_matrix( A ); // set right hand side of the linear equation system // one column for x and one for y coordinate matrix<double> B ( zero_matrix<double> ( size, 2 ) ); { B ( 0, 0 ) =nodes ( 1, 0 ) - nodes ( 0, 0 ); B ( 0, 1 ) =nodes ( 1, 1 ) - nodes ( 0, 1 ); for ( size_t i=1; i < size-1; ++i ) { B ( i, 0 ) =nodes ( i+1, 0 ) - nodes ( i-1, 0 ); B ( i, 1 ) =nodes ( i+1, 1 ) - nodes ( i-1, 1 ); } B ( size-1, 0 ) =nodes ( size-1, 0 ) - nodes ( size-2, 0 ); B ( size-1, 1 ) =nodes ( size-1, 1 ) - nodes ( size-2, 1 ); B*=3; } // invert the matrix inverse ( A ); // multiply right hand side with inverse matrix const matrix<double> X ( prod ( A, B ) ); // calculate coefficients of cubic polynomes polynomes.resize ( size-1 ); for ( size_t i=0; i<polynomes.size(); ++i ) { polynomes[i]=zero_matrix<double> ( B.size2(), 4 ); for ( size_t j = 0; j < polynomes[i].size1(); ++j ) { polynomes[i] ( j, 0 ) =nodes ( i, j ); polynomes[i] ( j, 1 ) =X ( i, j ); polynomes[i] ( j, 2 ) =3 * ( nodes ( i+1, j ) - nodes ( i, j ) ) - 2*X ( i, j ) - X ( i+1, j ); polynomes[i] ( j, 3 ) =2 * ( nodes ( i, j ) - nodes ( i+1, j ) ) + X ( i, j ) + X ( i+1, j ); } } } } #else #error POLYNOME_TYPE #endif // POLYNOME_TYPE == 0 #endif //__INTERPOLATION_H__
Source file
#include "Interpolation.h" #include <boost/numeric/ublas/lu.hpp> using namespace boost::numeric::ublas; namespace { /** * Calculate the inverse matrix * @param inverse [in, out] **/ int inverse ( matrix<double>& inverse ) { typedef double T; typedef permutation_matrix<std::size_t> pmatrix; matrix<T> A ( inverse ); // create a permutation matrix for the LU-factorization pmatrix pm ( A.size1() ); // perform LU-factorization int res = lu_factorize ( A, pm ); assert ( res == 0 ); // create identity matrix of "inverse" inverse.assign ( identity_matrix<T> ( A.size1() ) ); // backsubstitute to get the inverse lu_substitute ( A, pm, inverse ); //cout << inverse << endl; return 0; } void hermite_matrix ( matrix<double>& M ) { M=zero_matrix<double> ( 4, 4 ); M ( 0,0 ) =1; M ( 1,0 ) =1; M ( 1,1 ) =1; M ( 1,2 ) =1; M ( 1,3 ) =1; M ( 2,1 ) =1; M ( 3,1 ) =1; M ( 3,2 ) =2; M ( 3,3 ) =3; } void toeplitz_matrix ( matrix<double>& M ) { for ( signed i = 0; i < M.size1(); ++ i ) for ( signed j = std::max ( i - 1, 0 ); j < std::min ( i + 2, signed ( M.size2 () ) ); ++ j ) M ( i, j ) = ( i==j ) ? ( ( i==0 || i==M.size1()-1 ) ? 2 : 4 ) : 1; } }