Report a bug
If you spot a problem with this page, click here to create a Github issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

mir.interpolate.linear

Linear Interpolation

See Also:
Authors:
Ilya Yaroshenko
template linear(T, size_t N = 1, FirstGridIterator = immutable(T)*, NextGridIterators = Repeat!(N - 1, FirstGridIterator))
Constructs multivariate linear interpolant with nodes on rectilinear grid.
Parameters:
T element floating point type
N arity (dimension) number
GridVectors grid N x values for interpolation
Slice!(ykind, [N], yIterator) values f(x) values for interpolation

Constraints: grid, values must have the same length >= 2

Returns:
Examples:
R -> R: Linear interpolation
import mir.ndslice;
import std.math: approxEqual;

immutable x = [0, 1, 2, 3, 5.00274, 7.00274, 10.0055, 20.0137, 30.0192];
immutable y = [0.0011, 0.0011, 0.0030, 0.0064, 0.0144, 0.0207, 0.0261, 0.0329, 0.0356,];
auto xs = [1, 2, 3, 4.00274, 5.00274, 6.00274, 7.00274, 8.00548, 9.00548, 10.0055, 11.0055, 12.0082, 13.0082, 14.0082, 15.0082, 16.011, 17.011, 18.011, 19.011, 20.0137, 21.0137, 22.0137, 23.0137, 24.0164, 25.0164, 26.0164, 27.0164, 28.0192, 29.0192, 30.0192];

auto interpolation = linear!double(x.sliced, y.sliced);

auto data = [0.0011, 0.0030, 0.0064, 0.0104, 0.0144, 0.0176, 0.0207, 0.0225, 0.0243, 0.0261, 0.0268, 0.0274, 0.0281, 0.0288, 0.0295, 0.0302, 0.0309, 0.0316, 0.0322, 0.0329, 0.0332, 0.0335, 0.0337, 0.0340, 0.0342, 0.0345, 0.0348, 0.0350, 0.0353, 0.0356];

assert(approxEqual(xs.sliced.map!interpolation, data, 1e-4, 1e-4));
Examples:
R^2 -> R: Bilinear interpolaiton
import std.math: approxEqual;
import mir.ndslice;
alias appreq = (a, b) => approxEqual(a, b, 10e-10, 10e-10);

///// set test function ////
const double y_x0 = 2;
const double y_x1 = -7;
const double y_x0x1 = 3;

// this function should be approximated very well
alias f = (x0, x1) => y_x0 * x0 + y_x1 * x1 + y_x0x1 * x0 * x1 - 11;

///// set interpolant ////
auto x0 = [-1.0, 2, 8, 15].idup.sliced;
auto x1 = [-4.0, 2, 5, 10, 13].idup.sliced;
auto grid = cartesian(x0, x1);

auto interpolant = linear!(double, 2)(x0, x1, grid.map!f);

///// compute test data ////
auto test_grid = cartesian(x0 + 1.23, x1 + 3.23);
auto real_data = test_grid.map!f;
auto interp_data = test_grid.vmap(interpolant);

///// verify result ////
assert(all!appreq(interp_data, real_data));

//// check derivatives ////
auto z0 = 1.23;
auto z1 = 3.21;
auto d = interpolant.withDerivative(z0, z1);
assert(appreq(interpolant(z0, z1), f(z0, z1)));
assert(appreq(d[0][0], f(z0, z1)));
assert(appreq(d[1][0], y_x0 + y_x0x1 * z1));
assert(appreq(d[0][1], y_x1 + y_x0x1 * z0));
assert(appreq(d[1][1], y_x0x1));
Examples:
R^3 -> R: Trilinear interpolaiton
import std.math: approxEqual;
import mir.ndslice;
alias appreq = (a, b) => approxEqual(a, b, 10e-10, 10e-10);

///// set test function ////
const y_x0 = 2;
const y_x1 = -7;
const y_x2 = 5;
const y_x0x1 = 10;
const y_x0x1x2 = 3;

// this function should be approximated very well
alias f = (x0, x1, x2) => y_x0 * x0 + y_x1 * x1 + y_x2 * x2
     + y_x0x1 * x0 * x1 + y_x0x1x2 * x0 * x1 * x2 - 11;

///// set interpolant ////
auto x0 = [-1.0, 2, 8, 15].idup.sliced;
auto x1 = [-4.0, 2, 5, 10, 13].idup.sliced;
auto x2 = [3, 3.7, 5].idup.sliced;
auto grid = cartesian(x0, x1, x2);

auto interpolant = linear!(double, 3)(x0, x1, x2, grid.map!f);

///// compute test data ////
auto test_grid = cartesian(x0 + 1.23, x1 + 3.23, x2 - 3);
auto real_data = test_grid.map!f;
auto interp_data = test_grid.vmap(interpolant);

///// verify result ////
assert(all!appreq(interp_data, real_data));

//// check derivatives ////
auto z0 = 1.23;
auto z1 = 3.21;
auto z2 = 4;
auto d = interpolant.withDerivative(z0, z1, z2);
assert(appreq(interpolant(z0, z1, z2), f(z0, z1, z2)));
assert(appreq(d[0][0][0], f(z0, z1, z2)));
assert(appreq(d[1][0][0], y_x0 + y_x0x1 * z1 + y_x0x1x2 * z1 * z2));
assert(appreq(d[0][1][0], y_x1 + y_x0x1 * z0 + y_x0x1x2 * z0 * z2));
assert(appreq(d[1][1][0], y_x0x1 + y_x0x1x2 * z2));
assert(appreq(d[1][1][1], y_x0x1x2));
Linear!(T, N, GridIterators) linear(SliceKind ykind, yIterator)(GridVectors grid, scope Slice!(ykind, [N], yIterator) values, bool forceCopyValues = false);
Parameters:
GridVectors grid immutable x values for interpolant
Slice!(ykind, [N], yIterator) values f(x) values for interpolant
bool forceCopyValues always copy values if set

Constraints: grid and values must have the same length >= 2

Returns:
struct Linear(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterators...) if (N && N <= 6 && NextGridIterators.length == N - 1);
Multivariate linear interpolant with nodes on rectilinear grid.
Slice!(Contiguous, [N], F*) _data;
Aligned buffer allocated with mir.internal.memory. For internal use.
GridIterators _grid;
Grid iterators. For internal use.
bool _ownsData;
nothrow @nogc @trusted this()(GridVectors grid);
nothrow @nogc @trusted this()(GridVectors grid, Slice!(Contiguous, [N], const(F)*) values);
const @property GridVectors[dimension] grid(size_t dimension = 0)()
if (dimension < N);
const @property size_t intervalCount(size_t dimension = 0)();
Returns:
intervals count.
const @property size_t[N] gridShape()();
enum uint derivativeOrder;
template opCall(uint derivative = 0) if (derivative <= derivativeOrder)
const @trusted auto opCall(X...)(in X xs)
if (X.length == N);
(x) and [x] operators.

Complexity: O(log(grid.length))

alias withDerivative = opCall!1;
struct LinearKernel(X);
this()(X x0, X x1, X x);
template opCall(uint derivative = 0) if (derivative <= 1)
auto opCall(Y)(in Y y0, in Y y1);
alias withDerivative = opCall!1;