High-order convolution interpolation, derivatives and integrals on uniform grids, in any number of dimensions
convinterp interpolates data sampled on uniform grids, in one dimension or many, and differentiates and integrates the interpolant analytically. Its kernels are piecewise polynomials, evaluated in a compiled Rust core; the Python interface works with NumPy arrays.
convinterp is a port of the Julia package ConvolutionInterpolations.jl, by the same author, and is tested against it.
This documentation has four more pages:
User guide: every argument, with examples of kernels, derivatives, integrals, boundary conditions and data in more dimensions, and the method’s limitations.
Theory: how convolution interpolation works, with every kernel derived from its defining conditions.
About: the relation to the Julia package, and how to cite convinterp.
NoteAlpha release
Interpolation, derivatives and integrals on uniform grids work in any number of dimensions. Scattered data are coming, and this documentation grows with the package.
Installation
pip install convinterp
Prebuilt wheels are available for Linux, macOS and Windows, on x86_64 and ARM.
A first example
import numpy as np # arraysfrom convinterp import convolution_interpolation # the one function you need# 1D: data on a uniform gridx = np.linspace(0.0, 2* np.pi, 50) # 50 uniformly spaced knotsitp = convolution_interpolation(x, np.sin(x)) # the interpolant of sin(x)print(f"itp(1.0) = {itp(1.0):.12f}") # the interpolated value at x = 1print(f"sin(1.0) = {np.sin(1.0):.12f}") # the exact value, for comparison# its first derivative, evaluated analytically from the kerneld_itp = convolution_interpolation(x, np.sin(x), derivative=1)print(f"d_itp(1.0) = {d_itp(1.0):.12f}") # the interpolated derivative at x = 1print(f"cos(1.0) = {np.cos(1.0):.12f}") # the exact derivative# its integral from the first knot x[0] = 0, also evaluated analyticallyi_itp = convolution_interpolation(x, np.sin(x), derivative=-1)print(f"i_itp(1.0) = {i_itp(1.0):.12f}") # the interpolated integral from 0 to 1print(f"1 - cos(1.0) = {1- np.cos(1.0):.12f}") # the exact integral
In more dimensions, give one knot array per axis. The data array’s axis d runs along knots[d]:
y = np.linspace(0.0, 1.0, 30) # knots of the second axisdata = np.sin(x)[:, None] * np.exp(y)[None, :] # sin(x)·exp(y) on the 50 × 30 griditp2 = convolution_interpolation((x, y), data) # the 2D interpolant# a mixed derivative ∂²/∂x∂y, with one derivative order per axisdxy = convolution_interpolation((x, y), data, derivative=(1, 1))print(f"dxy(1.0, 0.5) = {dxy(1.0, 0.5):.10f}") # the interpolated mixed derivativeprint(f"cos(1.0)·exp(0.5) = {np.cos(1.0) * np.exp(0.5):.10f}") # the exact value
High order. The kernels "b7" to "b13" converge at 7th order on smooth data, and "b5" at 6th, with exact polynomial reproduction up to the boundaries.
Derivatives. Every derivative order a kernel supports, up to 7 for the widest kernels, is evaluated analytically from the kernel’s polynomial pieces. Orders can differ per axis.
Integrals. Integrals up to order 8, anchored at the first knot, are evaluated analytically as well, in constant time per point whatever the grid size. They can be mixed with derivatives, one order per axis.
Any number of dimensions. The same function covers 1D curves, 2D images and fields, and higher-dimensional tables.
Fast. Locating a point on a uniform grid takes one division, and the kernel weights come from exact polynomials evaluated in compiled, vectorized Rust.
Boundary handling. The data are extended beyond each boundary by polynomial extrapolation where the data allow it, chosen automatically per boundary, or set by hand.