Skip to main content

Family

Trait Family 

pub trait Family:
    Lift
    + Clone
    + Debug
    + PartialEq {
    // Required methods
    fn parameters(&self) -> &[f64];
    fn parts(&self) -> Vec<&Self>;
    fn own_labels(&self) -> Vec<ParameterLabel>;
    fn own_refusal(&self) -> Option<&'static str>;

    // Provided methods
    fn view_with<'a, R: Scalar>(
        &'a self,
        params: &'a [R],
    ) -> Result<Self::View<'a, R>, CurveError> { ... }
    fn view_seeded<R: Scalar + Seedable>(
        &self,
        index: usize,
    ) -> Result<Self::View<'_, R>, CurveError> { ... }
    fn parameter_count(&self) -> usize { ... }
    fn for_each_owner<'a>(&'a self, f: &mut dyn FnMut(&'a Self)) { ... }
    fn parameter_owners(&self) -> Vec<&Self> { ... }
    fn parameter_labels(&self) -> Vec<ParameterLabel> { ... }
    fn adjoint_refusal(&self) -> Option<&'static str> { ... }
}
Expand description

The parameter discipline every closed family set shares.

A set states four facts per variant — the parameters it owns directly, the families it reads, the labels of its own parameters, and its own reason for refusing adjoints — and inherits everything that follows from them: the count, the owner walk, the labels in lift order, the composed refusal, and the checked substituted and seeded lifts. One definition of each walk, so no set can count, flatten or label its parameters differently from another.

This is the storage and lift discipline only — what the survival module calls “the same discipline as the discount side”. Each set keeps its own evaluation trait and vocabulary: a survival curve answers survival probabilities and a discount curve answers discount factors, and nothing here asks one to answer the other.

Every method is also available inherently on each set, so a caller needs no import; the trait is the bound generic code names.

Required Methods§

fn parameters(&self) -> &[f64]

The free parameters this family owns directly.

A transform owns none: its parameters belong to the curve it reads, which reports its own on its own risk axis. Flattening them here would merge two axes that a risk ladder must keep apart. A family may be both — read a base and own a parameter — as Curve::FxImplied does.

fn parts(&self) -> Vec<&Self>

Every family this one reads, in evaluation order. A leaf reads none.

This is how a risk lift walks a composition to find the parameter-owning leaves without each family reimplementing the walk.

fn own_labels(&self) -> Vec<ParameterLabel>

The labels for the parameters this family owns directly, in the order parameters reports them.

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

Why this family itself cannot report correct parameter sensitivities, if it cannot — its own scheme only, not its parts’.

Provided Methods§

fn view_with<'a, R: Scalar>( &'a self, params: &'a [R], ) -> Result<Self::View<'a, R>, CurveError>

This family lifted into mode R over params, in place of its stored ones — the whole of what arming used to be.

params is one flat vector over every free parameter reachable, in parameter_owners order, exactly as a seeded index counts. The view borrows it at every depth, so substituting costs no allocation, and the stored family is not touched: a reverse-mode risk pass registers one vector of tape handles, hands it here, and reads its adjoints back afterwards. There is no shadow copy to keep in step and nothing to de-arm.

§Errors

CurveError::ParameterCountMismatch if params is not exactly as long as this family’s free parameter vector.

fn view_seeded<R: Scalar + Seedable>( &self, index: usize, ) -> Result<Self::View<'_, R>, CurveError>

This family lifted into forward mode with parameter index carrying a unit tangent and every other a zero tangent.

index is a single flat index over every free parameter reachable from this family, in the order parameter_owners reports them — so a composition is addressed as one parameter vector rather than by naming a leaf and an offset into it. That is the shape the sequential calibration solve wants: one input, one output, one forward pass, and .derivative() read straight off the result. No tape, no reverse sweep.

§Errors

CurveError::NoSuchParameter if index is past the last free parameter.

fn parameter_count(&self) -> usize

Every free parameter reachable from this family, counted once.

A recursive sum, not a collected owner list: this runs per curve per trade on the value-only path (view_with length-checks with it), so it must not allocate for a leaf.

fn for_each_owner<'a>(&'a self, f: &mut dyn FnMut(&'a Self))

Visits every parameter-owning family reachable from this one, in parameter_owners order, without collecting them. The lift flattens parameters through this so a market of leaves allocates one vector, not one per curve.

fn parameter_owners(&self) -> Vec<&Self>

Every parameter-owning family reachable from this one, depth first, including this one.

Owning parameters and reading other families are independent — an FxImplied does both — so a family reports itself when it owns parameters and still recurses into what it reads. A family that owns none and reads none is a degenerate leaf and reports itself, so the walk never silently drops a family.

fn parameter_labels(&self) -> Vec<ParameterLabel>

What each free parameter reachable from this family is, in the same order view_with consumes them.

One walk drives the substituted lift, the seeded lift and this, so a risk row cannot be labelled with a pillar the lift installed somewhere else. The length is parameter_count by construction, and a test asserts it for every family of every set.

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

Why this family cannot report correct parameter sensitivities, if it cannot.

None means every scheme reachable from here is linear in its ordinates and records exact adjoints. Some(reason) means a risk read-back must fail loud with that reason rather than return numbers whose sign is not justified — a judgement each scheme makes, asked here of the whole composition, because a composed curve is no more differentiable than the least differentiable curve it reads.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§