pub struct TwoSeed<const K: usize> {
pub base: Order2<K>,
pub eps: Order2<K>,
pub del: Order2<K>,
pub eps_del: Order2<K>,
}Expand description
Two-seed scalar: an Order2 base plus TWO nilpotents ε, δ
(ε² = δ² = 0, εδ retained) — four Order2 parts
s = base + ε·eps + δ·del + εδ·eps_del.
Product truncates ε² = δ² = 0 (doc §A.3): each part is built from
Order2 products of the four input parts. Composition picks up
successively higher outer derivatives, the cross part carrying the second
Faà di Bruno term f''·eps·del + f'·eps_del.
Seed each primary with seed: base = variable(x, axis),
eps = constant(u_axis), del = constant(v_axis), eps_del = constant(0).
Then the εδ-component of the evaluated Hessian channel is the contracted
fourth [eps_del.h][a][b] = Σ_{cd} ℓ_{abcd} u_c v_d — exactly
row_fourth_contracted(u, v), without materialising t4.
Fields§
§base: Order2<K>The ε⁰δ⁰ part: value / grad / Hessian of ℓ.
eps: Order2<K>The ε¹δ⁰ part.
del: Order2<K>The ε⁰δ¹ part.
eps_del: Order2<K>The ε¹δ¹ part. After a seed(u, v) evaluation,
eps_del.h[a][b] = Σ_{cd} ℓ_{abcd} u_c v_d.
Implementations§
Source§impl<const K: usize> TwoSeed<K>
impl<const K: usize> TwoSeed<K>
Sourcepub fn seed(x: f64, axis: usize, u_axis: f64, v_axis: f64) -> Self
pub fn seed(x: f64, axis: usize, u_axis: f64, v_axis: f64) -> Self
Seed primary axis at value x with ε-direction u_axis and
δ-direction v_axis:
p_axis = p_axis⁰ + x-seed + ε·u_axis + δ·v_axis (doc §A.3 “Seeding”).
Sourcepub fn contracted_fourth(&self) -> [[f64; K]; K]
pub fn contracted_fourth(&self) -> [[f64; K]; K]
The contracted-fourth channel after a seed(u, v) evaluation:
out[a][b] = Σ_{cd} ℓ_{abcd} u_c v_d, i.e. the εδ-coefficient’s Hessian.
Trait Implementations§
impl<const K: usize> Copy for TwoSeed<K>
Source§impl<const K: usize> JetScalar<K> for TwoSeed<K>
impl<const K: usize> JetScalar<K> for TwoSeed<K>
Source§fn variable(x: f64, axis: usize) -> Self
fn variable(x: f64, axis: usize) -> Self
p_axis at value x: unit first derivative in slot
axis, all higher channels zero. (The nilpotent / cross channels of the
directional scalars are seeded zero — callers set ε/δ directions through
the scalar-specific OneSeed::seed_direction / TwoSeed::seed.)Source§fn compose_unary(&self, d: [f64; 5]) -> Self
fn compose_unary(&self, d: [f64; 5]) -> Self
f ∘ self, given the outer
derivative stack d = [f(u), f′(u), f″(u), f‴(u), f⁗(u)] at
u = self.value(). Read moreSource§fn compose_unary_with(&self, stack_fn: impl Fn(f64) -> [f64; 5]) -> Self
fn compose_unary_with(&self, stack_fn: impl Fn(f64) -> [f64; 5]) -> Self
stack_fn — the generic-over-Lane
seam that lets a single-sourced row program instantiate at BOTH the scalar
f64 jets and the SIMD f64x4 batch towers from ONE expression. Read moreSource§fn ln(&self) -> Self
fn ln(&self) -> Self
ln(self). Caller guarantees positivity. Same derivative stack
crate::jet_tower::Tower4::ln uses, so any program written over both
matches term-for-term.Source§fn powf(&self, a: f64) -> Self
fn powf(&self, a: f64) -> Self
self^a for real exponent a. Caller guarantees a positive base.
Mirrors crate::jet_tower::Tower4::powf (falling-factorial stack).Source§fn ln_gamma(&self) -> Self
fn ln_gamma(&self) -> Self
ln Γ(self). Caller guarantees a positive argument. Uses the SAME
hand-certified derivative stack crate::jet_tower::Tower4::ln_gamma
consumes (crate::jet_tower::ln_gamma_derivative_stack), so any
program written over both matches term-for-term.Source§fn digamma(&self) -> Self
fn digamma(&self) -> Self
ψ(self) = d/dx ln Γ(x) (digamma). Caller guarantees a positive
argument. Same hand-certified stack
crate::jet_tower::digamma_derivative_stack.Auto Trait Implementations§
impl<const K: usize> Freeze for TwoSeed<K>
impl<const K: usize> RefUnwindSafe for TwoSeed<K>
impl<const K: usize> Send for TwoSeed<K>
impl<const K: usize> Sync for TwoSeed<K>
impl<const K: usize> Unpin for TwoSeed<K>
impl<const K: usize> UnsafeUnpin for TwoSeed<K>
impl<const K: usize> UnwindSafe for TwoSeed<K>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<const K: usize, S> RowJet<K> for Swhere
S: JetScalar<K>,
impl<const K: usize, S> RowJet<K> for Swhere
S: JetScalar<K>,
Source§fn variable(x: f64, slot: usize) -> S
fn variable(x: f64, slot: usize) -> S
slot at value x (unit first derivative in slot),
broadcast to every lane. Per-lane-DISTINCT seeding for the batch path is
done by the lane instantiators (generic_batched_fourth_tower /
generic_batched_third_tower), which build the tower variables directly
from each row’s primaries; this method is for any row-invariant auxiliary
variable a body introduces.Source§fn neg(&self) -> S
fn neg(&self) -> S
scale(-1.0); the blanket overrides it
to delegate to crate::jet_scalar::JetScalar::neg.Source§fn compose_unary_with<const N: usize>(
&self,
stack_fn: impl Fn(f64) -> [f64; N],
) -> S
fn compose_unary_with<const N: usize>( &self, stack_fn: impl Fn(f64) -> [f64; N], ) -> S
[f64; N]
derivative stack is built from the running base value PER LANE through
stack_fn. This is the SHARED-TRAIT version of the compose_unary_with
inherent method that already exists on both the scalar towers and the lane
towers: on a scalar jet stack_fn is run once at the value; on an f64x4
lane tower it is re-run per lane (the four rows carry four distinct base
values), so lane i is to_bits-identical to the scalar result on row i.
Making it a trait method is precisely what lets a body written once over
R: RowJet<K> instantiate at the batch towers. N is widened/narrowed to
the tower’s native width by [resize_stack] (N == 5 is a verbatim copy).Source§fn guard(&self, pred: impl Fn(f64) -> bool) -> GuardVerdict
fn guard(&self, pred: impl Fn(f64) -> bool) -> GuardVerdict
pred on each active lane’s value channel
and report which lanes failed (see GuardVerdict). A scalar jet checks
its one value; a lane tower checks all four. Lets a batched program detect
an out-of-domain row in a 4-group and bail that group to the scalar tail.Source§fn scale_rows(&self, s: f64) -> S
fn scale_rows(&self, s: f64) -> S
s
(Self::Value). On a scalar jet Self::Value = f64, so this is exactly
scale and the scalar call sites stay BIT-IDENTICAL when
.scale(x) is rewritten to .scale_rows(x); on an f64x4 lane tower
Self::Value = [f64; 4] and lane i is multiplied by s[i]. This is the
primitive that lets a batched body carry CONTINUOUS per-row data — the
survival covariance_ones / z_sum / observation-weight wi factors that
enter the jet algebra as .scale(per_row_value) and that the single-f64
scale would broadcast wrongly across the four rows. Build
s from the lane→row map with pack_rows.Source§fn pack_rows(rows: &[usize], value_of: impl Fn(usize) -> f64) -> f64
fn pack_rows(rows: &[usize], value_of: impl Fn(usize) -> f64) -> f64
rows: value_of(r)
is evaluated for each active lane’s row and packed into Self::Value (a
single f64 on a scalar jet, [f64; 4] on an f64x4 lane tower). This is
how a body written once over RowJet feeds per-row CONTINUOUS data (the
arguments to scale_rows) into the batch path without
knowing the concrete representation: the program holds the per-row data and
the caller threads rows (length 1 scalar, length 4 batch) into
RowNllProgramRowJet::row_nll, so the body writes
x.scale_rows(R::pack_rows(rows, |r| self.cov(r))). A multiplicative weight
buried in a compose_unary_with stack is pulled out the same way:
x.compose_unary_with(|u| stack(u, 1.0)).scale_rows(R::pack_rows(rows, |r| self.wi(r))).
(Binary per-row branches such as the event indicator di are kept
lane-uniform by grouping and the guard bail, not packed.)Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.