Enum Interpolation
#[non_exhaustive]pub enum Interpolation {
}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
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
NaturalCubic
Cubic spline with zero second derivative at both ends.
ClampedCubic
Cubic spline with the first derivative pinned at each end.
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.
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
impl Interpolation
pub const ALL: [Interpolation; 15]
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]
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>
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 fn is_global(self) -> bool
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>
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>
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>
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
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>
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
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
impl Clone for Interpolation
§fn clone(&self) -> Interpolation
fn clone(&self) -> Interpolation
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more