pub trait BiLinearInterpolation<Point, Input> {
// Required method
fn bilinear_interpolate(
&self,
x: Input,
) -> Result<Point, InterpolationError>;
}Expand description
A trait for bilinear interpolation on 2D data grids.
§Purpose
The BiLinearInterpolation trait is designed to perform bilinear interpolation
to estimate intermediate values within a grid of 2D points. This method is often
used in numerical computation tasks, such as image processing, terrain modeling,
and scientific data visualization.
§Type Parameters
Point: The output type, typically used to represent the interpolated 2D point.Input: The input type for the interpolation parameter, typically a scalar value.
§Associated Type
Error: Defines the type returned in case of a failure during interpolation.
§Method
bilinear_interpolate: Computes the interpolated value at the given input, returning either the result or an error if the operation cannot proceed.
§Errors
Any errors encountered during interpolation are encapsulated in the type Error.
This trait is expected to return meaningful errors in cases like:
- Insufficient or invalid data for computation.
- Inputs that are out of bounds for the given dataset.
- Issues specific to the interpolation logic.
§Example Usage
Below is an example demonstrating how an implementing struct might use this trait:
use rust_decimal::Decimal;
use optionstratlib_math::curves::Point2D;
use optionstratlib_math::error::InterpolationError;
use optionstratlib_math::geometrics::BiLinearInterpolation;
struct GridInterpolator {
// Implementation-specific fields like the grid or data.
}
impl BiLinearInterpolation<Point2D, Decimal> for GridInterpolator {
fn bilinear_interpolate(&self, x: Decimal) -> Result<Point2D, InterpolationError> {
Ok(Point2D::new(x, x)) // Placeholder implementation
}
}In this example:
GridInterpolatorimplements the trait for bilinear interpolation.- The
bilinear_interpolatemethod calculates the interpolatedPoint2Dfor a givenxvalue.
§Related Types
Point2D: A struct representing a 2D point withxandycoordinates.CurvesError: A recommended error type for detailed error categorization.
§See Also
crate::geometrics::interpolation::InterpolationType: A module defining different types of interpolation methods.crate::geometrics::interpolation::LinearInterpolation: A simpler interpolation method for one-dimensional data.
§One point per abscissa
Every interpolator here reads its sample as a function of the abscissa:
at most one ordinate per x. See
Curve::new for the rule and for why no
constructor enforces it. A sample carrying several ordinates at one
abscissa is outside the contract: the grid cell around a repeated
abscissa has zero width and the slope across it is undefined, so the
answer is InterpolationError::DegenerateInterval.
That holds on every branch, including the exact match: the
Curve implementation short-circuits an x that
lands on a sample, and on a stack of ordinates at that x it reports the
degeneracy rather than returning the lowest of them.
A projection of a surface is multi-valued by construction, which is why
Surface::project_onto returns a
Vec<Point2D> and not a curve; aggregate it before interpolating.
§Cells at the edge of the sample
A cell wants samples on both sides of the query along every axis, which
the samples at the upper edge of the domain cannot supply. The
Curve implementation builds its cell out of two
consecutive segments and clamps the far one to the curve’s last segment
where it would run off the end, so the segment holding the query is
always one edge of the cell and the answer stays a convex combination of
the four ordinates read; that implementation documents the rule and its
consequences in full. The Surface one picks
the four samples nearest the query, so its cell has no end to run off.
Required Methods§
Sourcefn bilinear_interpolate(&self, x: Input) -> Result<Point, InterpolationError>
fn bilinear_interpolate(&self, x: Input) -> Result<Point, InterpolationError>
Performs bilinear interpolation to compute a value for the given input.
§Parameters
x: The input value (e.g., anxcoordinate in 2D space) for which the interpolation is performed.
§Returns
Ok(Point): The interpolated point (e.g., aPoint2D) representing the computed values.Err(Self::Error): An error indicating why the interpolation could not be performed.
§Example
use std::collections::BTreeSet;
use rust_decimal::Decimal;
use tracing::info;
use optionstratlib_math::curves::{Curve, Point2D};
use optionstratlib_math::geometrics::BiLinearInterpolation;
let curve = Curve::new(BTreeSet::from_iter(vec![
Point2D::new(Decimal::ZERO, Decimal::ZERO),
Point2D::new(Decimal::ONE, Decimal::TWO),
]));
let result = curve.bilinear_interpolate(Decimal::from(2));
match result {
Ok(point) => info!("Interpolated point: {:?}", point),
Err(e) => info!("Interpolation failed: {:?}", e),
}§Errors
Returns InterpolationError::EmptyData when the grid has
no samples, InterpolationError::OutOfRange when x falls
outside the covered domain,
InterpolationError::DegenerateInterval when the
neighbouring grid cell has zero width on either axis, and
InterpolationError::Bilinear when the sample is too small to build
a cell from (fewer than four points on a
Curve), or when a checked-arithmetic step
leaves the representable range.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementors§
impl BiLinearInterpolation<Point2D, Decimal> for Curve
Implementation of the BiLinearInterpolation trait for the Curve struct.
§What it computes
Bilinear interpolation is defined on a cell of a two-dimensional grid: the answer is the mean of four corner samples, weighted by the query’s fractional position along each axis. A curve has one axis, so the cell is built out of two of its segments and the second fraction is fixed at one half:
- the near edge is the segment that brackets
x, from sampleito samplei + 1; - the far edge is the segment two positions further along, from sample
fto samplef + 1; - the answer is the mean of the two edges read at the same fraction.
t = (x - x[i]) / (x[i+1] - x[i])
near = y[i] + t * (y[i+1] - y[i])
far = y[f] + t * (y[f+1] - y[f])
y = (near + far) / 2§Behaviour near the upper boundary
The far edge is f = i + 2 while such a segment exists. Over the last two
segments of the curve it does not, and f is clamped to len - 2, the
curve’s last segment. Two consequences a caller can act on:
- on the final segment the two edges coincide,
nearequalsfar, and the answer is the linear interpolant there. Not always to the last digit: this method normalisesxbefore scaling by the rise andLinearInterpolation::linear_interpolatescales first, so where the fraction along the segment has no finite decimal expansion the two round at scale 28 on different quantities and can part company in the 28th place; - on the second-to-last segment the far edge is the segment immediately after the near one instead of the one after that.
§Why not clamp the window start
The obvious repair, and the one
CubicInterpolation::cubic_interpolate applies at its own boundary, is
to slide the whole window back to the last four samples. Do not reach for
it here. The window start is also the denominator of t, so moving it
back off the segment holding x pushes t past 1. Written out, the
answer weights the four ordinates it reads by
y = (1 - t)/2 * y[i] + t/2 * y[i+1] + (1 - t)/2 * y[f] + t/2 * y[f+1]which sums to one for any t, but has every weight non-negative only
while t is in [0, 1]. Past 1 the two (1 - t)/2 weights go
negative, the answer stops being a convex combination of the cell’s
corners, and what is left is an extrapolation of a cell that does not
contain x: on (0,0), (1,1), (2,4), (3,9) the window-start clamp
returns 9.5 at x = 2.5, above every ordinate the curve has. Being a
convex combination of its cell’s corners is what makes bilinear
interpolation bilinear interpolation, so it is the near edge that has to
stay put and the far edge that gives way. That is why the two boundary
rules differ.
Before this rule existed the last two segments returned
InterpolationError::Bilinear because the window ran off the end.
§What this is not
The far edge sits elsewhere on the curve, so the result does not follow
the samples between knots and this is not an interpolant through them: on
(0,0), (1,1), (2,4), (3,9) the value at x = 0.5 is 3.5, not the
0.5 a straight reading of the bracketing segment gives.
An x landing exactly on a sample returns that sample, which neither
one-sided limit approaching it matches, so the result jumps at every
sample. That jump is as old as the method and owes nothing to the
boundary rule above: on (0,0), (1,1), (2,4), (3,9), (4,16) both limits
at x = 1 are 5 against a sample of 1, and both segments meeting
there are far from the clamp. What the clamp does add is that at the last
two samples before the end of the curve the two limits no longer agree
with each other either, because the segments on either side get different
far edges.
Reach for LinearInterpolation or SplineInterpolation when a curve
through the samples is what is wanted.
§Parameters
x: The x-coordinate to interpolate at. Must lie within the range of the curve’s x-coordinates.
§Returns
Ok(Point2D): The interpolated point atx, both coordinates asDecimal.Err(InterpolationError): See the error list below.
§Errors
InterpolationError::Bilinear: the curve holds fewer than four samples, or a checked-arithmetic step left the representableDecimalrange.InterpolationError::OutOfRange:xfalls outside the curve’s x-range.InterpolationError::DegenerateInterval: several samples share the abscissax, so the curve has no value there.
§One point per abscissa
A curve is a function of its abscissa; see Curve::new. Asking for a
repeated abscissa returns InterpolationError::DegenerateInterval, as
it does for the three sibling algorithms; no ordinate of the stack is
chosen. A stack elsewhere on the curve does not stop this method
answering: only the near edge’s width is divided by, and a stack sitting
on the far edge is read for its two ordinates alone.
§Related Traits
BiLinearInterpolation: The trait defining this method.Interpolate: Ensures compatibility of the curve with multiple interpolation methods.
§See Also
Curve: The overarching structure that represents the curve.Point2D: The data type used to represent individual points on the curve.find_bracket_points: A helper method used to locate the two points that bracket the given x-coordinate.