Skip to main content

optionstratlib_math/geometrics/interpolation/
bilinear.rs

1use crate::error::InterpolationError;
2
3/// A trait for bilinear interpolation on 2D data grids.
4///
5/// # Purpose
6/// The `BiLinearInterpolation` trait is designed to perform bilinear interpolation
7/// to estimate intermediate values within a grid of 2D points. This method is often
8/// used in numerical computation tasks, such as image processing, terrain modeling,
9/// and scientific data visualization.
10///
11/// # Type Parameters
12/// - `Point`: The output type, typically used to represent the interpolated 2D point.
13/// - `Input`: The input type for the interpolation parameter, typically a scalar value.
14///
15/// # Associated Type
16/// - `Error`: Defines the type returned in case of a failure during interpolation.
17///
18/// # Method
19/// - [`bilinear_interpolate`](#method.bilinear_interpolate):
20///   Computes the interpolated value at the given input, returning either the result
21///   or an error if the operation cannot proceed.
22///
23/// # Errors
24/// Any errors encountered during interpolation are encapsulated in the type `Error`.
25/// This trait is expected to return meaningful errors in cases like:
26/// - Insufficient or invalid data for computation.
27/// - Inputs that are out of bounds for the given dataset.
28/// - Issues specific to the interpolation logic.
29///
30/// # Example Usage
31/// Below is an example demonstrating how an implementing struct might use this trait:
32/// ```rust
33/// use rust_decimal::Decimal;
34/// use optionstratlib_math::curves::Point2D;
35/// use optionstratlib_math::error::InterpolationError;
36/// use optionstratlib_math::geometrics::BiLinearInterpolation;
37/// struct GridInterpolator {
38///     // Implementation-specific fields like the grid or data.
39/// }
40///
41/// impl BiLinearInterpolation<Point2D, Decimal> for GridInterpolator {
42///
43///     fn bilinear_interpolate(&self, x: Decimal) -> Result<Point2D, InterpolationError> {
44///         Ok(Point2D::new(x, x)) // Placeholder implementation
45///     }
46/// }
47/// ```
48///
49/// In this example:
50/// - `GridInterpolator` implements the trait for bilinear interpolation.
51/// - The `bilinear_interpolate` method calculates the interpolated `Point2D` for a given `x` value.
52///
53/// # Related Types
54/// - [`Point2D`](crate::curves::Point2D): A struct representing a 2D point with `x` and `y` coordinates.
55/// - [`CurvesError`](crate::error::CurveError): A recommended error type for detailed error categorization.
56///
57/// # See Also
58/// - [`crate::geometrics::interpolation::InterpolationType`](crate::geometrics::InterpolationType):
59///   A module defining different types of interpolation methods.
60/// - [`crate::geometrics::interpolation::LinearInterpolation`](crate::geometrics::LinearInterpolation):
61///   A simpler interpolation method for one-dimensional data.
62///
63/// # One point per abscissa
64///
65/// Every interpolator here reads its sample as a function of the abscissa:
66/// at most one ordinate per `x`. See
67/// [`Curve::new`](crate::curves::Curve::new) for the rule and for why no
68/// constructor enforces it. A sample carrying several ordinates at one
69/// abscissa is outside the contract: the grid cell around a repeated
70/// abscissa has zero width and the slope across it is undefined, so the
71/// answer is [`InterpolationError::DegenerateInterval`].
72///
73/// That holds on every branch, including the exact match: the
74/// [`Curve`](crate::curves::Curve) implementation short-circuits an `x` that
75/// lands on a sample, and on a stack of ordinates at that `x` it reports the
76/// degeneracy rather than returning the lowest of them.
77///
78/// A projection of a surface is multi-valued by construction, which is why
79/// [`Surface::project_onto`](crate::surfaces::Surface::project_onto) returns a
80/// `Vec<Point2D>` and not a curve; aggregate it before interpolating.
81///
82/// # Cells at the edge of the sample
83///
84/// A cell wants samples on both sides of the query along every axis, which
85/// the samples at the upper edge of the domain cannot supply. The
86/// [`Curve`](crate::curves::Curve) implementation builds its cell out of two
87/// consecutive segments and clamps the far one to the curve's last segment
88/// where it would run off the end, so the segment holding the query is
89/// always one edge of the cell and the answer stays a convex combination of
90/// the four ordinates read; that implementation documents the rule and its
91/// consequences in full. The [`Surface`](crate::surfaces::Surface) one picks
92/// the four samples nearest the query, so its cell has no end to run off.
93pub trait BiLinearInterpolation<Point, Input> {
94    /// Performs bilinear interpolation to compute a value for the given input.
95    ///
96    /// # Parameters
97    /// - `x`: The input value (e.g., an `x` coordinate in 2D space) for which the interpolation is performed.
98    ///
99    /// # Returns
100    /// - `Ok(Point)`: The interpolated point (e.g., a `Point2D`) representing the computed values.
101    /// - `Err(Self::Error)`: An error indicating why the interpolation could not be performed.
102    ///
103    /// # Example
104    /// ```rust
105    /// use std::collections::BTreeSet;
106    /// use rust_decimal::Decimal;
107    /// use tracing::info;
108    /// use optionstratlib_math::curves::{Curve, Point2D};
109    /// use optionstratlib_math::geometrics::BiLinearInterpolation;
110    /// let curve = Curve::new(BTreeSet::from_iter(vec![
111    ///            Point2D::new(Decimal::ZERO, Decimal::ZERO),
112    ///            Point2D::new(Decimal::ONE, Decimal::TWO),
113    ///        ]));
114    /// let result = curve.bilinear_interpolate(Decimal::from(2));
115    ///
116    /// match result {
117    ///     Ok(point) => info!("Interpolated point: {:?}", point),
118    ///     Err(e) => info!("Interpolation failed: {:?}", e),
119    /// }
120    /// ```
121    ///
122    /// # Errors
123    ///
124    /// Returns [`InterpolationError::EmptyData`] when the grid has
125    /// no samples, [`InterpolationError::OutOfRange`] when `x` falls
126    /// outside the covered domain,
127    /// [`InterpolationError::DegenerateInterval`] when the
128    /// neighbouring grid cell has zero width on either axis, and
129    /// [`InterpolationError::Bilinear`] when the sample is too small to build
130    /// a cell from (fewer than four points on a
131    /// [`Curve`](crate::curves::Curve)), or when a checked-arithmetic step
132    /// leaves the representable range.
133    fn bilinear_interpolate(&self, x: Input) -> Result<Point, InterpolationError>;
134}