pub trait FamilyChannelHessian: Send + Sync {
// Required methods
fn n_outputs(&self) -> usize;
fn n_subjects(&self) -> usize;
fn fill_subject(&self, i: usize, out: &mut [f64]);
// Provided methods
fn evaluate_full(&self) -> Array3<f64> { ... }
fn channel_hessian_at(
&self,
beta: &[f64],
family_scalars: Option<&Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<dyn FamilyChannelHessian>, String> { ... }
}Expand description
Per-subject channel Hessian provider for multi-output families.
The Fisher information decomposition for multi-output families is
I(β) = Σ_i J_iᵀ W_i J_iwhere J_i is the channel-stacked Jacobian (shape n_outputs × p for
subject i) and W_i is the n_outputs × n_outputs per-subject channel
Hessian of the row negative log-likelihood (the second-derivative block of
−log L_i(u_i) at a pilot β, PSD-clamped).
For single-output families this is the scalar IRLS weight; for multi-output
families (survival marginal-slope: n_outputs = 4; location-scale:
n_outputs = 2) it carries full cross-channel curvature.
The identifiability canonicalisation step uses the n_outputs-channel
weighted joint design W_joint = Σ_i sqrt(W_i) ⊗ J_i to detect
block-against-block aliasing. When this trait is present on
ParameterBlockSpec::channel_hessian, canonicalize_for_identifiability
routes through audit_identifiability_channel_aware; when absent it falls
back to the scalar-weight flat audit.
§W-metric rank theorem
The canonicalisation computes rank(J^T W J) where W_blkdiag = block-diagonal of per-subject W_i. This rank equals
rank(J) − dim(range(J) ∩ ker(W_blkdiag))i.e. columns of J that lie in the kernel of W_blkdiag (flat directions
in the curvature landscape at the pilot β) are correctly identified as
curvature-redundant and may be dropped.
Required Methods§
Sourcefn n_subjects(&self) -> usize
fn n_subjects(&self) -> usize
Number of subjects (rows).
Sourcefn fill_subject(&self, i: usize, out: &mut [f64])
fn fill_subject(&self, i: usize, out: &mut [f64])
Fill the n_outputs × n_outputs per-subject channel Hessian W_i
into out (row-major, length n_outputs * n_outputs) for subject i.
Negative eigenvalues must be clamped to zero (PSD projection) before
or inside this call.
Provided Methods§
Sourcefn evaluate_full(&self) -> Array3<f64>
fn evaluate_full(&self) -> Array3<f64>
Materialise the full (n_subjects × n_outputs × n_outputs) tensor.
Default implementation calls fill_subject for each row.
Sourcefn channel_hessian_at(
&self,
beta: &[f64],
family_scalars: Option<&Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<dyn FamilyChannelHessian>, String>
fn channel_hessian_at( &self, beta: &[f64], family_scalars: Option<&Arc<dyn Any + Send + Sync>>, ) -> Result<Arc<dyn FamilyChannelHessian>, String>
Return a refreshed W evaluated at beta using family_scalars when
those scalars carry the per-row primary state at the current β.
§Fisher information identity
I(β) = J(β)^T W(β) J(β). T8 originally froze W at β=0; T34 refreshes
both J and W at the current β so the audit’s rank verdict reflects the
actual local identifiability.
§Default implementation (β-independent W)
Families whose W is β-independent (e.g. Gaussian-identity where
W = prior_w) return a clone of their frozen W by delegating to
evaluate_full(). No recomputation is performed. beta and
family_scalars are ignored.
§Override (β-dependent W)
Families with β-dependent W (e.g. survival marginal-slope where
W_i(β) depends on (q0_i, q1_i, qd1_i, g_i)) must override this
method and recompute W from the current primary state.
When beta is non-zero in a way that affects W (i.e. g_i != 0),
family_scalars MUST be Some(..). Return Err if scalars are
missing in that case (same error-message style as T26’s contract).
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".