Skip to main content

Interpolation

Enum Interpolation 

#[non_exhaustive]
pub enum Interpolation {
Show 15 variants LogLinear, BackwardFlat, ForwardFlat, LinearZero, AnchoredLinearZero { anchor: f64, }, NaturalCubic, ClampedCubic { left: f64, right: f64, }, NotAKnotCubic, TensionSpline { sigma: f64, }, MonotoneConvex, MonotoneCubic, Akima, Kruger, MonotonicNaturalCubic, KrugerZero,
}
Expand description

How a discount curve reads between its pillars.

The set is closed for the same reason the curve families are: a scheme is a stored property that the mode-generic evaluation has to dispatch on, and a new one should be a variant the compiler makes every caller handle. Eq and Hash are absent deliberately: ClampedCubic and TensionSpline carry f64 payloads, which admit neither. Nothing keys a map or a set on a scheme.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

LogLinear

Straight line on the log discount factors — equivalently, a piecewise-constant instantaneous forward rate. The default, and what a step curve is.

§

BackwardFlat

The right-hand pillar’s zero rate z = −ln DF / τ held across each segment, so ln DF(τ) = −z·τ: the instantaneous forward is flat behind each pillar (equal to that pillar’s zero rate) and jumps at it, the anchor is exact, and every pillar reproduces. What a step scheme cannot have is left-continuity at interior pillars — the price of holding a rate flat rather than averaging it, and inherent to any backward-flat reading that is not LogLinear in disguise.

§

ForwardFlat

The left-hand pillar’s log discount factor across each segment.

The discount factor is held constant across a segment, so a date strictly inside one reads the pillar to its left and the pillar to its right has no effect on it whatever. A calibrating rung therefore has to be noded at or before its own last accrual end: node it later — at its final payment date, which is what any payment lag produces, and the placement a curve replicating a vendor bootstrap needs — and its accrual is governed entirely by the pillar to its left, leaving its par rate deaf to the pillar it is supposed to determine. calibrate refuses such a ladder by name rather than returning a curve that does not fit it; see CalibrationError::Insensitive.

§

LinearZero

Straight line on the continuously-compounded zero rate z = −ln DF / τ, converted back on the way out. Differs from LogLinear whenever the pillars are unevenly spaced, which they always are.

§

AnchoredLinearZero

LinearZero with a stated zero rate at the anchor: the first segment runs from anchor to the first pillar’s rate rather than holding the latter flat. What a zero curve with a node at its reference date reads as.

Fields

§anchor: f64

The continuously compounded zero rate at the anchor, on the curve’s year-fraction measure. Declared data, not a risk parameter.

§

NaturalCubic

Cubic spline with zero second derivative at both ends.

§

ClampedCubic

Cubic spline with the first derivative pinned at each end.

Fields

§left: f64

dy/dτ at the anchor.

§right: f64

dy/dτ at the last pillar.

§

NotAKnotCubic

Cubic spline whose third derivative is continuous across the second and second-to-last knots — the ends are “not a knot”, so the first two segments share one cubic and the last two share another.

Needs at least three segments to be determined. With fewer, the conditions are vacuous and the scheme reads as NaturalCubic; the fallback is documented and tested rather than silent.

§

TensionSpline

Exponential-tension spline: S'' − σ²S is linear on each segment, so σ → 0 recovers NaturalCubic and large σ pulls the curve towards the piecewise-linear reading. The knot-spacing-only matrix survives the generalisation, so this too records exact adjoints.

Fields

§sigma: f64

The tension, strictly positive and finite.

§

MonotoneConvex

Hagan-West monotone convex: a piecewise-quadratic instantaneous forward, repaired region by region so the curve cannot overshoot between pillars.

§

MonotoneCubic

Fritsch-Carlson (PCHIP): cubic Hermite whose knot slopes are a weighted harmonic mean, zeroed at a turning point.

§

Akima

Akima: cubic Hermite whose knot slopes weight the neighbouring secants by the absolute changes across them, so an outlying pillar disturbs only its own neighbourhood.

§

Kruger

Kruger: cubic Hermite over harmonic-mean interior slopes with the end rule that keeps the last segment’s shape.

§

MonotonicNaturalCubic

A natural cubic spline whose knot slopes pass Hyman’s monotonicity filter before the Hermite cubic is formed, both ends a zero second derivative. Where the spline is already monotone the filter leaves it, and the curve is the natural spline.

§

KrugerZero

Kruger over the continuously compounded zero rate z = −ln DF / τ rather than the log discount factor, read back as −τ·z. The anchor’s zero rate is the first pillar’s.

Implementations§

§

impl Interpolation

pub const ALL: [Interpolation; 15]

Every scheme, at representative parameters — a payload-carrying variant has no canonical value, so the sweep fixes one and says so.

pub const ACCEPTED: &'static [&'static str]

Every spelling a caller may name a scheme by, derived from ALL at compile time rather than restated — so the list a rejection advertises cannot omit a scheme or name one that is gone.

pub fn from_code(code: &str) -> Result<Self, VocabularyParseError>

The scheme named by code, with the parameters ALL carries for the two schemes that take them.

A caller supplying its own parameters replaces them after resolving the name; this is the name half, and it is here rather than in the binding so that a Rust caller and a Python caller name a scheme identically.

§Errors

VocabularyParseError naming code and the accepted set when no scheme carries that spelling. The accepted set is derived from ALL, so it cannot advertise a spelling this function would then refuse.

pub const fn code(self) -> &'static str

The canonical, separator-free lower-case name.

pub fn is_global(self) -> bool

Whether this scheme reads pillars beyond the two bracketing a query.

A local scheme blends the segment’s own two ends and nothing else, so a query is a bracket and a little arithmetic. A global scheme — every spline is one — has coefficients that depend on all the ordinates at once, through a solve over the whole knot sequence.

The distinction is not cosmetic: it decides when the work happens. A global scheme’s coefficients are solved once when the curve is lifted into a view and carried there, so the per-query path stays a bracket over precomputed numbers and the O(log n), allocation-free discount query holds for every scheme. Solving per query would make a discount lookup O(n) in the pillar count.

A local scheme solves nothing and allocates nothing when lifted.

pub fn adjoint_refusal(self) -> Option<&'static str>

Why this scheme cannot report correct pillar sensitivities, if it cannot.

None means the scheme records exact adjoints: it is linear in its ordinates, or — the monotone family — piecewise smooth in them and solved in the mode with each branch chosen on the passive values. Some(reason) means a risk read-back through it must fail loud with that reason rather than return numbers.

Every scheme currently implemented records, so this is None throughout — but the mechanism is here, and the differential harness holds it honest: a scheme that declares a refusal must actually fail the finite-difference check, so refusing can never become a way to opt out of being tested.

pub fn coefficients<R: Scalar>(self, taus: &[f64], ys: &[R]) -> Vec<R>

A global scheme’s coefficients over the knot sequence, solved once per lift.

taus are the free pillars’ year fractions and ys their ordinates in mode R; the implicit anchor (0, 0) is the leftmost knot and is supplied by each solver rather than appearing in either slice — it constrains the spline and is not a free parameter, so it contributes no adjoint.

§Panics

Called only for a scheme where is_global holds; a local scheme has nothing to solve and panics rather than return an empty vector that a query might silently read.

pub fn validate(self) -> Result<(), CurveError>

Whether this scheme’s own parameters are usable.

A tension must be finite and strictly positive — at zero the scheme is NaturalCubic and should be spelled that way — and a clamped end slope must be finite. Checked where the scheme meets a curve, so a bad parameter fails at construction rather than as a NaN mid-valuation.

§Errors

CurveError::Malformed naming what was wrong.

pub fn log_df_with<R: Scalar>( self, taus: &[f64], ys: &[R], coefficients: Option<&[R]>, tau: f64, ) -> R

The log discount factor at tau, given a global scheme’s precomputed coefficients.

coefficients is Some exactly when is_global holds; a local scheme ignores it and reads the bracketing pillars alone.

pub fn read_log_df( self, taus: &[f64], ys: &[f64], tau: f64, ) -> Result<f64, CurveError>

The log discount factor at tau from knots a caller holds, checked: what log_df reads, after refusing what it assumes.

taus are the free pillars’ year fractions and ys their log discount factors; the anchor (0, 0) is implicit and past the last pillar the forward is held flat — exactly what a discount curve under this scheme reads. log_df is the unchecked form valuations take.

§Errors

CurveError::Malformed for unusable scheme parameters, no knots, lists of unequal length, a non-finite value, abscissae not strictly increasing or not positive, or a query that is not finite or lies before the anchor.

pub fn log_df<R: Scalar>(self, taus: &[f64], ys: &[R], tau: f64) -> R

The log discount factor at tau.

taus are the free pillars’ year fractions, strictly increasing and all positive; ys are their log discount factors in mode R. The anchor (0, 0) is implicit. Past the last pillar every scheme holds the forward rate flat: the last segment’s average forward, the same for every scheme.

Trait Implementations§

§

impl Clone for Interpolation

§

fn clone(&self) -> Interpolation

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
§

impl Copy for Interpolation

§

impl Debug for Interpolation

§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
§

impl Default for Interpolation

§

fn default() -> Interpolation

Returns the “default value” for a type. Read more
§

impl Display for Interpolation

§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
§

impl PartialEq for Interpolation

§

fn eq(&self, other: &Interpolation) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
§

impl StructuralPartialEq for Interpolation

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.