This library provides various interpolations such as piece-wise constant, linear or cubic interpolation. Right now the main feature is that it provides a function which takes bunch of one dimensional interpolations and creates an interpolation in arbitrary dimension.
Assume we have a function double fun(int)
defined on integers and we want to extend this function to floating point numbers with piece-wise interpolation, i.e. to get double fun(double)
. This library provides a function LinearInterpolation
auto LinearInterpolation = [](auto fun) {
return [=](double x) {
double wx = x - floor(x);
int ix = (int)floor(x);
return wx * fun(ix + 1) + (1 - wx) * fun(ix);
};
}
LinearInterpolation
takes a function, assuming it is of type double fun(int)
, and return a function defined on floating point nubers: double fun(double)
. The following code demonstrate a use:
// define a function `fun :: int -> double`
auto fun = [](int i) -> double { return sin(i); }
// extend `fun` to `ifun :: double -> double`
auto ifun = LinearInterpolation(ifun);
ifun(1.5); // == 0.5*sin(1)+0.5*sin(2)
A general one dimensional interpolation is assumed to be a function which takse a function Float fun(Integer)
and generates Float fun(Float)
, where Float
is any floating point type and Integer
is an integer like type. Therefore any one dimensional interpolation is assumed to be of type Interpolation :: (Integer -> Float) -> (Float -> Float)
.
The resulting function of an interpolation holds a copy of the original function. Therefore, the function to be interpolated should be a light object if you want to avoid unnecessary copies. When you want to preform interpolation over a container such as a std::vector
we recommend wrap the container into a lambda function which holds a reference to the container, this way you can also handle out of bound access. The following code demonstrates interpolation of a container:
std::vector<double> vec;
// initialize `vec`
auto fun = [&vec](int i) {
i = std::clamp(i, 0, vec.size() - 1);
return vec[i];
};
auto ifun = LinearInterpolation(fun);
ifun(1.5); // == 0.5*vec[1]+0.5*vec[2];
The library provides a functionality how to glue one dimensional interpolations to do multidimensional interpolation. We can take a function double fun(int, int, int)
and turn it into a function double fun(double,double,double)
by preforming linear interpolation on each argument. This is demonstrated with the following code:
auto fun = [](int i, int j, int k) -> double {
return sin(i) + sin(j) + sin(k);
};
auto LinearInterpol3D = InterpolationDimWise(
LinearInterpolation, LinearInterpolation, LinearInterpolation);
auto ifun = LinearInterpol3D(fun);
ifun(1.5, 2.1, 3.7);
We first define a function double fun(int, int, int)
, then we create a three dimensional interpolation function, which can take a function on integers and with linear interpolation extends this function to floating points numbers. The third line actually extends fun
from integer to floating point numbers and in the final step we just evaluate the function at a arbitrary point.
We can also preform cubic interpolation on the first argument, linear on the second and constant(nearest neighbour) on the third one.
auto Interpol3D = InterpolationDimWise(CubicInterpolation, LinearInterpolation,
ConstantInterpolation);
auto ifun = Interpol3D(fun);
ifun(1.5, 2.1, 3.7);
Sometimes, when doing multidimensional interpolation is it important in which order is the interpolation done.
Can we implement currying in some way? This might be useful when we need to compute fun(x,y)
for many different y
but fixed x
and the interpolation over y
has quite expensive precomputation.