Skip to main content

FamilyChannelHessian

Trait FamilyChannelHessian 

Source
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_i

where 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§

Source

fn n_outputs(&self) -> usize

Number of output channels n_outputs (= K in the row Jacobian).

Source

fn n_subjects(&self) -> usize

Number of subjects (rows).

Source

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§

Source

fn evaluate_full(&self) -> Array3<f64>

Materialise the full (n_subjects × n_outputs × n_outputs) tensor. Default implementation calls fill_subject for each row.

Source

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".

Implementors§