use crate::identifiability::{FrameColumnLayout, ResidualGaugeCurvature};
use crate::manifold::construction::ResidualGaugeCurvatureSource;
use crate::manifold::{
AssignmentMode, PeriodicHarmonicEvaluator, SaeAssignment, SaeAtomBasisKind, SaeBasisEvaluator,
SaeManifoldAtom, SaeManifoldRho, SaeManifoldTerm,
};
use gam_terms::latent::LatentManifold;
use ndarray::{Array1, Array2};
use std::sync::Arc;
use std::time::Instant;
fn lcg(s: &mut u64) -> f64 {
*s = s
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
((*s >> 11) as f64) / ((1u64 << 53) as f64)
}
fn planted_term(n: usize, p: usize, k_atoms: usize, dense_tail: bool) -> SaeManifoldTerm {
planted_term_with_gate(n, p, k_atoms, dense_tail, 3.0)
}
pub(crate) fn expect_stored(
source: ResidualGaugeCurvatureSource,
context: &str,
) -> ResidualGaugeCurvature {
match source {
ResidualGaugeCurvatureSource::Stored(curvature) => curvature,
ResidualGaugeCurvatureSource::Streamed { layout, .. } => panic!(
"{context}: expected a materialized curvature, but this fit's curvature is \
streamed (param_dim = {})",
layout.param_dim()
),
}
}
pub(crate) fn source_structure_tag(source: &ResidualGaugeCurvatureSource) -> &'static str {
match source {
ResidualGaugeCurvatureSource::Stored(curvature) => curvature.structure_tag(),
ResidualGaugeCurvatureSource::Streamed { .. } => "streamed_operator",
}
}
pub(crate) fn source_stored_scalars(source: &ResidualGaugeCurvatureSource) -> usize {
match source {
ResidualGaugeCurvatureSource::Stored(curvature) => curvature.stored_scalars(),
ResidualGaugeCurvatureSource::Streamed { .. } => 0,
}
}
pub(crate) fn source_root_rows(source: &ResidualGaugeCurvatureSource) -> usize {
match source {
ResidualGaugeCurvatureSource::Stored(curvature) => curvature.root_rows(),
ResidualGaugeCurvatureSource::Streamed { root_rows, .. } => *root_rows,
}
}
pub(crate) fn planted_term_for_probe(
n: usize,
p: usize,
k_atoms: usize,
dense_tail: bool,
) -> SaeManifoldTerm {
planted_term(n, p, k_atoms, dense_tail)
}
pub(crate) fn unit_rho_for_probe(k_atoms: usize) -> SaeManifoldRho {
unit_rho(k_atoms)
}
fn planted_term_with_gate(
n: usize,
p: usize,
k_atoms: usize,
dense_tail: bool,
gate_logit: f64,
) -> SaeManifoldTerm {
let mut s = 0x2757_0000_0000_0001u64;
let evaluator = Arc::new(PeriodicHarmonicEvaluator::new(3).expect("harmonic order 3"));
let mut atoms = Vec::with_capacity(k_atoms);
let mut coord_blocks = Vec::with_capacity(k_atoms);
let mut manifolds = Vec::with_capacity(k_atoms);
for k in 0..k_atoms {
let theta: Vec<f64> = (0..n).map(|_| lcg(&mut s)).collect();
let coords = Array2::<f64>::from_shape_fn((n, 1), |(r, _)| theta[r]);
let (phi, jet) = evaluator
.evaluate(coords.view())
.expect("periodic evaluate");
let mut decoder = Array2::<f64>::zeros((3, p));
decoder[[1, (2 * k) % p]] = 1.0;
decoder[[2, (2 * k + 1) % p]] = 1.0;
if dense_tail {
for c in 0..p {
decoder[[0, c]] = 0.05 * (lcg(&mut s) - 0.5);
decoder[[1, c]] += 0.05 * (lcg(&mut s) - 0.5);
decoder[[2, c]] += 0.05 * (lcg(&mut s) - 0.5);
}
}
atoms.push(
SaeManifoldAtom::new_with_provided_function_gram(
format!("circle{k}"),
SaeAtomBasisKind::Periodic,
1,
phi,
jet,
decoder,
Array2::<f64>::eye(3),
)
.expect("atom blocks agree")
.with_basis_second_jet(evaluator.clone()),
);
coord_blocks.push(coords);
manifolds.push(LatentManifold::Circle { period: 1.0 });
}
let logits = Array2::<f64>::from_elem((n, k_atoms), gate_logit);
let assignment = SaeAssignment::from_blocks_with_mode_and_manifolds(
logits,
coord_blocks,
manifolds,
AssignmentMode::ordered_beta_bernoulli(0.7, 1.0, false),
)
.expect("assignment blocks agree");
let mut term = SaeManifoldTerm::new(atoms, assignment).expect("term");
term.set_guards_enabled(false);
term
}
pub(crate) fn planted_constant_decoder_term(n: usize, p: usize, k_atoms: usize) -> SaeManifoldTerm {
let mut s = 0x2757_0000_0000_0009u64;
let evaluator = Arc::new(PeriodicHarmonicEvaluator::new(3).expect("harmonic order 3"));
let mut atoms = Vec::with_capacity(k_atoms);
let mut coord_blocks = Vec::with_capacity(k_atoms);
let mut manifolds = Vec::with_capacity(k_atoms);
for k in 0..k_atoms {
let coords = Array2::<f64>::from_shape_fn((n, 1), |_| lcg(&mut s));
let (phi, jet) = evaluator
.evaluate(coords.view())
.expect("periodic evaluate");
let mut decoder = Array2::<f64>::zeros((3, p));
for c in 0..p {
decoder[[0, c]] = 0.3 + 0.01 * c as f64;
}
atoms.push(
SaeManifoldAtom::new_with_provided_function_gram(
format!("flat{k}"),
SaeAtomBasisKind::Periodic,
1,
phi,
jet,
decoder,
Array2::<f64>::eye(3),
)
.expect("atom blocks agree")
.with_basis_second_jet(evaluator.clone()),
);
coord_blocks.push(coords);
manifolds.push(LatentManifold::Circle { period: 1.0 });
}
let assignment = SaeAssignment::from_blocks_with_mode_and_manifolds(
Array2::<f64>::from_elem((n, k_atoms), 3.0),
coord_blocks,
manifolds,
AssignmentMode::ordered_beta_bernoulli(0.7, 1.0, false),
)
.expect("assignment blocks agree");
let mut term = SaeManifoldTerm::new(atoms, assignment).expect("term");
term.set_guards_enabled(false);
term
}
fn unit_rho(k_atoms: usize) -> SaeManifoldRho {
SaeManifoldRho::new(0.0, 0.0, vec![Array1::<f64>::zeros(1); k_atoms])
}
pub(crate) fn reference_dense_gram(
term: &SaeManifoldTerm,
metric: &gam_problem::RowMetric,
layout: &FrameColumnLayout,
) -> Array2<f64> {
let n = term.n_obs();
let p = term.output_dim();
let param_dim = layout.param_dim();
let assignments = term.assignment.assignments();
let mut gram = Array2::<f64>::zeros((param_dim, param_dim));
let mut tangent = vec![0.0_f64; p];
let rank = metric.metric_rank();
for row in 0..n {
let mut j = Array2::<f64>::zeros((p, param_dim));
let mut base = 0usize;
for (atom_idx, atom) in term.atoms.iter().enumerate() {
let d = atom.latent_dim();
let a_nk = assignments[[row, atom_idx]];
if a_nk > 0.0 {
for axis in 0..d {
atom.fill_decoded_derivative_row(row, axis, &mut tangent);
for i in 0..p {
j[[i, base + i * d + axis]] += a_nk * tangent[i];
}
}
}
base += p * d;
}
let mut whitened = Array2::<f64>::zeros((rank, param_dim));
for r in 0..rank {
for c in 0..param_dim {
let mut acc = 0.0_f64;
for i in 0..p {
acc += metric.factor_entry(row, i, r) * j[[i, c]];
}
whitened[[r, c]] = acc;
}
}
gram = gram + whitened.t().dot(&whitened);
}
gram
}
pub(crate) fn reference_dense_root(
term: &SaeManifoldTerm,
metric: &gam_problem::RowMetric,
layout: &FrameColumnLayout,
) -> Array2<f64> {
let n = term.n_obs();
let p = term.output_dim();
let param_dim = layout.param_dim();
let rank = metric.metric_rank();
let assignments = term.assignment.assignments();
let mut root = Array2::<f64>::zeros((n * rank, param_dim));
let mut tangent = vec![0.0_f64; p];
for row in 0..n {
let mut j = Array2::<f64>::zeros((p, param_dim));
let mut base = 0usize;
for (atom_idx, atom) in term.atoms.iter().enumerate() {
let d = atom.latent_dim();
let a_nk = assignments[[row, atom_idx]];
if a_nk > 0.0 {
for axis in 0..d {
atom.fill_decoded_derivative_row(row, axis, &mut tangent);
for i in 0..p {
j[[i, base + i * d + axis]] += a_nk * tangent[i];
}
}
}
base += p * d;
}
for r in 0..rank {
for c in 0..param_dim {
let mut acc = 0.0_f64;
for i in 0..p {
acc += metric.factor_entry(row, i, r) * j[[i, c]];
}
root[[row * rank + r, c]] = acc;
}
}
}
root
}
#[test]
fn output_block_curvature_equals_the_dense_gram_and_has_no_off_block_mass() {
let (n, p, k_atoms) = (48usize, 24usize, 3usize);
let term = planted_term(n, p, k_atoms, true);
let metric = term.diagnostic_metric().expect("metric");
assert!(
!metric.drives_gauge(),
"the diagnostic fallback must be the Euclidean (non-gauge-driving) metric"
);
let layout = FrameColumnLayout::new(p, &vec![1usize; k_atoms]);
let curvature = term
.residual_gauge_streamed_data_curvature(
&metric,
&layout,
Array2::<f64>::zeros((0, layout.param_dim())),
)
.expect("streamed curvature");
assert_eq!(curvature.structure_tag(), "output_block_roots");
assert_eq!(curvature.root_rows(), n * metric.metric_rank());
let reference = reference_dense_gram(&term, &metric, &layout);
let structured = curvature.to_dense_gram();
assert_eq!(structured.dim(), reference.dim());
let scale = reference.iter().fold(0.0_f64, |m, v| m.max(v.abs()));
assert!(scale > 0.0, "the fixture must produce a nonzero curvature");
let mut worst = 0.0_f64;
let mut off_block = 0.0_f64;
let mut off_block_reference = 0.0_f64;
for a in 0..reference.nrows() {
let ia = layout.output_of(a).expect("column in range");
for b in 0..reference.ncols() {
let ib = layout.output_of(b).expect("column in range");
worst = worst.max((structured[[a, b]] - reference[[a, b]]).abs());
if ia != ib {
off_block = off_block.max(structured[[a, b]].abs());
off_block_reference = off_block_reference.max(reference[[a, b]].abs());
}
}
}
assert!(
worst <= 1.0e-12 * scale,
"structured curvature must reproduce the dense Gram: worst |Δ| {worst:.3e} \
against scale {scale:.3e}"
);
assert_eq!(
off_block, 0.0,
"the structured curvature must carry no mass between two output coordinates"
);
assert_eq!(
off_block_reference, 0.0,
"and neither does the dense reference — the block structure is the operator's, \
not the representation's"
);
let touched = (0..p)
.filter(|&i| {
(0..k_atoms).any(|l| {
let c = layout.column(i, l);
reference[[c, c]].abs() > 0.0
})
})
.count();
assert_eq!(
touched, p,
"every output coordinate must carry curvature for this gate to bite"
);
}
#[test]
fn output_block_curvature_stores_p_times_fewer_scalars_than_the_dense_gram() {
let (n, p, k_atoms) = (24usize, 64usize, 4usize);
let term = planted_term(n, p, k_atoms, true);
let metric = term.diagnostic_metric().expect("metric");
let layout = FrameColumnLayout::new(p, &vec![1usize; k_atoms]);
let curvature = term
.residual_gauge_streamed_data_curvature(
&metric,
&layout,
Array2::<f64>::zeros((0, layout.param_dim())),
)
.expect("streamed curvature");
let param_dim = layout.param_dim();
let d = layout.block_dim();
assert_eq!(curvature.stored_scalars(), p * d * d);
assert_eq!(
curvature.stored_scalars() * p,
param_dim * param_dim,
"the saving is exactly the factor p the dense layout was padding by"
);
}
#[test]
fn certificate_is_identical_under_the_structured_and_dense_reductions() {
use crate::identifiability::residual_gauge_exact_from_curvature;
let (n, p, k_atoms) = (40usize, 20usize, 3usize);
let term = planted_term(n, p, k_atoms, true);
let metric = term.diagnostic_metric().expect("metric");
let (model, streamed) = term
.to_residual_gauge_model(metric, None, false)
.expect("certificate model");
let structured = expect_stored(streamed, "unpinned path streams its curvature");
assert_eq!(structured.structure_tag(), "output_block_roots");
let dense = ResidualGaugeCurvature::DenseGram {
gram: structured.to_dense_gram(),
root_rows: structured.root_rows(),
};
let views: Vec<Option<crate::identifiability::AtomParameterView>> =
vec![None; model.atoms.len()];
let ops: Vec<Option<crate::identifiability::OrbitPenaltyOperator>> =
(0..model.atoms.len()).map(|_| None).collect();
let from_blocks = residual_gauge_exact_from_curvature(&model, &views, &ops, structured)
.expect("structured certificate");
let from_dense = residual_gauge_exact_from_curvature(&model, &views, &ops, dense)
.expect("dense certificate");
assert_eq!(
from_blocks.pinning_rank, from_dense.pinning_rank,
"pinning rank must not depend on the representation"
);
assert_eq!(from_blocks.generators.len(), from_dense.generators.len());
assert!(
!from_blocks.generators.is_empty(),
"the fixture must enumerate generators for this gate to bite"
);
for (b, dsn) in from_blocks
.generators
.iter()
.zip(from_dense.generators.iter())
{
assert_eq!(b.description, dsn.description);
assert_eq!(b.family, dsn.family);
assert_eq!(
b.unpinned, dsn.unpinned,
"generator '{}' verdict must not depend on the representation",
b.description
);
let gap = (b.pinned_energy_fraction - dsn.pinned_energy_fraction).abs();
assert!(
gap <= 1.0e-12,
"generator '{}' energy fraction differs by {gap:.3e} between representations",
b.description
);
}
assert_eq!(from_blocks.group_signature(), from_dense.group_signature());
assert_eq!(
from_blocks.residual_gauge_dim,
from_dense.residual_gauge_dim
);
}
#[test]
fn rank_deficient_blocks_agree_with_the_dense_spectrum() {
use crate::identifiability::residual_gauge_exact_from_curvature;
let (n, p, k_atoms) = (32usize, 16usize, 2usize);
let term = planted_term(n, p, k_atoms, false);
let metric = term.diagnostic_metric().expect("metric");
let (model, streamed) = term
.to_residual_gauge_model(metric, None, false)
.expect("certificate model");
let structured = expect_stored(streamed, "unpinned path streams its curvature");
let dense = ResidualGaugeCurvature::DenseGram {
gram: structured.to_dense_gram(),
root_rows: structured.root_rows(),
};
let views: Vec<Option<crate::identifiability::AtomParameterView>> =
vec![None; model.atoms.len()];
let ops: Vec<Option<crate::identifiability::OrbitPenaltyOperator>> =
(0..model.atoms.len()).map(|_| None).collect();
let from_blocks = residual_gauge_exact_from_curvature(&model, &views, &ops, structured)
.expect("structured certificate");
let from_dense = residual_gauge_exact_from_curvature(&model, &views, &ops, dense)
.expect("dense certificate");
assert!(
from_blocks.pinning_rank < p * k_atoms,
"the fixture must be rank deficient for this gate to bite (rank {} of {})",
from_blocks.pinning_rank,
p * k_atoms
);
assert_eq!(from_blocks.pinning_rank, from_dense.pinning_rank);
}
#[test]
fn gauge_driving_metric_folds_into_a_root_that_reproduces_the_dense_gram() {
let (n, p, k_atoms, rank) = (12usize, 10usize, 2usize, 3usize);
let mut term = planted_term(n, p, k_atoms, true);
let mut s = 0x2757_FEED_0000_0001u64;
let factors = Array2::<f64>::from_shape_fn((n, p * rank), |_| lcg(&mut s) - 0.5);
let metric = gam_problem::RowMetric::output_fisher(Arc::new(factors), p, rank)
.expect("output-Fisher metric");
term.set_row_metric(metric.clone())
.expect("metric is conformable with the term");
assert!(metric.drives_gauge());
let layout = FrameColumnLayout::new(p, &vec![1usize; k_atoms]);
let curvature = term
.residual_gauge_streamed_data_curvature(
&metric,
&layout,
Array2::<f64>::zeros((0, layout.param_dim())),
)
.expect("streamed curvature");
assert_eq!(curvature.structure_tag(), "dual_root");
assert_eq!(
curvature.stored_scalars(),
layout.param_dim() * layout.param_dim(),
"the folded factor is param_dim-square, which is the point: it is the \
SMALLER of the two exact sides once the root outgrows its columns"
);
let reference = reference_dense_gram(&term, &metric, &layout);
let built = curvature.to_dense_gram();
let scale = reference.iter().fold(0.0_f64, |m, v| m.max(v.abs()));
assert!(scale > 0.0);
let worst = built
.iter()
.zip(reference.iter())
.fold(0.0_f64, |m, (a, b)| m.max((a - b).abs()));
assert!(
worst <= 1.0e-12 * scale,
"gauge-driving curvature must reproduce the dense Gram: worst |Δ| {worst:.3e}"
);
let mut off_block = 0.0_f64;
for a in 0..reference.nrows() {
let ia = layout.output_of(a).expect("in range");
for b in 0..reference.ncols() {
if ia != layout.output_of(b).expect("in range") {
off_block = off_block.max(reference[[a, b]].abs());
}
}
}
assert!(
off_block > 0.0,
"an output-Fisher metric must couple output coordinates, else this arm is vacuous"
);
}
#[test]
fn the_folded_root_and_the_dense_gram_certify_the_same_model() {
use crate::identifiability::residual_gauge_exact_from_curvature;
let (n, p, k_atoms, rank) = (24usize, 12usize, 3usize, 3usize);
let mut term = planted_term(n, p, k_atoms, true);
let mut s = 0x2757_F01D_0000_0001u64;
let factors = Array2::<f64>::from_shape_fn((n, p * rank), |_| lcg(&mut s) - 0.5);
let metric = gam_problem::RowMetric::output_fisher(Arc::new(factors), p, rank)
.expect("output-Fisher metric");
term.set_row_metric(metric.clone())
.expect("metric is conformable");
let layout = FrameColumnLayout::new(p, &vec![1usize; k_atoms]);
let (model, source) = term
.to_residual_gauge_model(metric.clone(), None, false)
.expect("certificate model");
assert_eq!(source_structure_tag(&source), "streamed_operator");
let folded = term
.residual_gauge_streamed_data_curvature(
&metric,
&layout,
Array2::<f64>::zeros((0, layout.param_dim())),
)
.expect("materialized curvature");
assert_eq!(folded.structure_tag(), "dual_root");
assert_eq!(folded.root_rows(), n * rank);
let dense = ResidualGaugeCurvature::DenseGram {
gram: folded.to_dense_gram(),
root_rows: folded.root_rows(),
};
let views = term.atom_parameter_views();
let ops: Vec<Option<crate::identifiability::OrbitPenaltyOperator>> =
(0..k_atoms).map(|_| None).collect();
let from_fold = residual_gauge_exact_from_curvature(&model, &views, &ops, folded)
.expect("folded certificate");
let from_gram = residual_gauge_exact_from_curvature(&model, &views, &ops, dense)
.expect("dense-Gram certificate");
assert_eq!(from_fold.generators.len(), from_gram.generators.len());
assert!(
!from_fold.generators.is_empty(),
"a certificate with no generators cannot separate the two reductions"
);
for (a, b) in from_fold.generators.iter().zip(from_gram.generators.iter()) {
assert_eq!(a.description, b.description);
assert_eq!(
a.unpinned, b.unpinned,
"generator `{}` is {} from the folded root and {} from the dense Gram",
a.description,
if a.unpinned { "unpinned" } else { "pinned" },
if b.unpinned { "unpinned" } else { "pinned" }
);
let gap = (a.pinned_energy_fraction - b.pinned_energy_fraction).abs();
assert!(
gap <= 1.0e-9,
"generator `{}` scores {:.17e} from the folded root against {:.17e} from \
the dense Gram",
a.description,
a.pinned_energy_fraction,
b.pinned_energy_fraction
);
}
let bound = (n * rank).min(model.param_dim());
assert!(
from_fold.pinning_rank <= bound && from_gram.pinning_rank <= bound,
"no reduction may report a rank above min(root rows, param_dim) = {bound}; \
folded {} gram {}",
from_fold.pinning_rank,
from_gram.pinning_rank
);
assert!(
from_gram.pinning_rank <= from_fold.pinning_rank,
"the Gram decision is floored at the eigensolver's resolution, so it can \
only count a subset of what the root counts; gram {} > folded {}",
from_gram.pinning_rank,
from_fold.pinning_rank
);
}
#[test]
fn a_zero_curvature_folds_to_rank_zero_under_a_gauge_driving_metric() {
let (n, p, k_atoms, rank) = (20usize, 8usize, 2usize, 3usize);
let mut term = planted_constant_decoder_term(n, p, k_atoms);
let mut s = 0x2757_F01D_0000_0002u64;
let factors = Array2::<f64>::from_shape_fn((n, p * rank), |_| lcg(&mut s) - 0.5);
let metric = gam_problem::RowMetric::output_fisher(Arc::new(factors), p, rank)
.expect("output-Fisher metric");
term.set_row_metric(metric.clone())
.expect("metric is conformable");
let layout = FrameColumnLayout::new(p, &vec![1usize; k_atoms]);
let curvature = term
.residual_gauge_streamed_data_curvature(
&metric,
&layout,
Array2::<f64>::zeros((0, layout.param_dim())),
)
.expect("streamed curvature");
assert_eq!(curvature.structure_tag(), "dual_root");
let worst = curvature
.to_dense_gram()
.iter()
.fold(0.0_f64, |m, v| m.max(v.abs()));
assert!(
worst == 0.0,
"a constant decoder has an identically zero curvature; the folded factor \
reconstructs {worst:.3e}"
);
}
#[test]
fn dual_root_and_dense_gram_agree_on_a_rank_neither_may_exceed() {
use crate::identifiability::residual_gauge_exact_from_curvature;
let (n, p, k_atoms, rank) = (6usize, 40usize, 2usize, 2usize);
let mut term = planted_term(n, p, k_atoms, true);
let mut s = 0x2757_FEED_0000_0002u64;
let factors = Array2::<f64>::from_shape_fn((n, p * rank), |_| lcg(&mut s) - 0.5);
let metric = gam_problem::RowMetric::output_fisher(Arc::new(factors), p, rank)
.expect("output-Fisher metric");
term.set_row_metric(metric.clone())
.expect("metric is conformable");
let layout = FrameColumnLayout::new(p, &vec![1usize; k_atoms]);
let curvature = term
.residual_gauge_streamed_data_curvature(
&metric,
&layout,
Array2::<f64>::zeros((0, layout.param_dim())),
)
.expect("streamed curvature");
assert_eq!(curvature.structure_tag(), "dual_root");
assert_eq!(curvature.stored_scalars(), n * rank * layout.param_dim());
let reference = reference_dense_gram(&term, &metric, &layout);
let scale = reference.iter().fold(0.0_f64, |m, v| m.max(v.abs()));
let worst = curvature
.to_dense_gram()
.iter()
.zip(reference.iter())
.fold(0.0_f64, |m, (a, b)| m.max((a - b).abs()));
assert!(
worst <= 1.0e-12 * scale,
"dual-root curvature must reproduce the dense Gram: worst |Δ| {worst:.3e}"
);
let (model, streamed) = term
.to_residual_gauge_model(metric, None, false)
.expect("certificate model");
let structured = expect_stored(streamed, "unpinned path streams its curvature");
let root_rows = structured.root_rows();
let dense = ResidualGaugeCurvature::DenseGram {
gram: structured.to_dense_gram(),
root_rows,
};
let views: Vec<Option<crate::identifiability::AtomParameterView>> =
(0..model.atoms.len()).map(|_| None).collect();
let ops: Vec<Option<crate::identifiability::OrbitPenaltyOperator>> =
(0..model.atoms.len()).map(|_| None).collect();
let from_root = residual_gauge_exact_from_curvature(&model, &views, &ops, structured)
.expect("dual-root certificate");
let from_dense = residual_gauge_exact_from_curvature(&model, &views, &ops, dense)
.expect("dense certificate");
let bound = root_rows.min(layout.param_dim());
assert!(
from_root.pinning_rank <= bound,
"rank(RᵀR) <= rows(R): root path reported {} against the bound {bound}",
from_root.pinning_rank
);
assert!(
from_dense.pinning_rank <= bound,
"rank(RᵀR) <= rows(R): dense-Gram path reported {} against the bound {bound} — the Gram is counting eigenvalues below its own resolution",
from_dense.pinning_rank
);
assert_eq!(
from_root.pinning_rank, from_dense.pinning_rank,
"the two representations must decide one rank"
);
for (r, d) in from_root
.generators
.iter()
.zip(from_dense.generators.iter())
{
assert_eq!(r.unpinned, d.unpinned, "generator '{}'", r.description);
assert!(
(r.pinned_energy_fraction - d.pinned_energy_fraction).abs() <= 1.0e-10,
"generator '{}' energy fraction",
r.description
);
}
}
#[test]
fn a_non_finite_curvature_is_refused_in_every_representation() {
use crate::identifiability::residual_gauge_exact_from_curvature;
let (n, p, k_atoms) = (16usize, 8usize, 2usize);
let term = planted_term(n, p, k_atoms, true);
let metric = term.diagnostic_metric().expect("metric");
let (model, streamed) = term
.to_residual_gauge_model(metric, None, false)
.expect("certificate model");
let clean = expect_stored(streamed, "unpinned path streams its curvature");
let root_rows = clean.root_rows();
let layout = FrameColumnLayout::new(p, &vec![1usize; k_atoms]);
let views: Vec<Option<crate::identifiability::AtomParameterView>> =
(0..model.atoms.len()).map(|_| None).collect();
let ops: Vec<Option<crate::identifiability::OrbitPenaltyOperator>> =
(0..model.atoms.len()).map(|_| None).collect();
assert!(
residual_gauge_exact_from_curvature(&model, &views, &ops, clean).is_ok(),
"the fixture must certify before the poisoned arms mean anything"
);
let mut poisoned = ndarray::Array3::<f64>::zeros((p, k_atoms, k_atoms));
poisoned[[p - 1, k_atoms - 1, k_atoms - 1]] = f64::NAN;
let arms = [
ResidualGaugeCurvature::OutputBlockRoots {
roots: poisoned,
dense_rows: Array2::<f64>::zeros((0, layout.param_dim())),
layout: layout.clone(),
root_rows,
},
ResidualGaugeCurvature::DualRoot {
root: Array2::<f64>::from_elem((2, layout.param_dim()), f64::NAN),
root_rows,
},
ResidualGaugeCurvature::DenseGram {
gram: Array2::<f64>::from_elem((layout.param_dim(), layout.param_dim()), f64::NAN),
root_rows,
},
];
for arm in arms {
let tag = arm.structure_tag();
let refusal = residual_gauge_exact_from_curvature(&model, &views, &ops, arm);
let message = refusal
.err()
.unwrap_or_else(|| panic!("{tag}: a non-finite curvature must be refused"));
assert!(
message.contains("non-finite"),
"{tag}: refusal must name the cause, got {message:?}"
);
}
}
#[test]
fn an_unassigned_term_certifies_at_rank_zero() {
use crate::identifiability::residual_gauge_exact_from_curvature;
let (n, p, k_atoms) = (12usize, 6usize, 2usize);
let term = planted_constant_decoder_term(n, p, k_atoms);
for row in 0..n {
for atom in &term.atoms {
let tangent = atom.decoded_derivative_row(row, 0);
assert!(
tangent.iter().all(|v| *v == 0.0),
"the fixture must have no decoded tangent for this gate to bite"
);
}
}
let metric = term.diagnostic_metric().expect("metric");
let (model, streamed) = term
.to_residual_gauge_model(metric, None, false)
.expect("certificate model");
let curvature = expect_stored(streamed, "unpinned path streams its curvature");
assert_eq!(curvature.structure_tag(), "output_block_roots");
let views: Vec<Option<crate::identifiability::AtomParameterView>> =
(0..model.atoms.len()).map(|_| None).collect();
let ops: Vec<Option<crate::identifiability::OrbitPenaltyOperator>> =
(0..model.atoms.len()).map(|_| None).collect();
let report = residual_gauge_exact_from_curvature(&model, &views, &ops, curvature)
.expect("a zero curvature is a certificate, not an error");
assert_eq!(report.pinning_rank, 0);
}
#[test]
fn the_certification_decomposes_nothing_at_the_parameter_dimension() {
let (n, p, k_atoms) = (32usize, 48usize, 4usize);
let param_dim = p * k_atoms;
let observed = std::thread::spawn(move || {
assert_eq!(
gam_linalg::faer_ndarray::eigh_census_this_thread().calls,
0,
"a freshly spawned thread starts with an empty census, which is what makes \
`max_dim` below a property of THIS region"
);
let term = planted_term(n, p, k_atoms, true);
let rho = unit_rho(k_atoms);
let fitted = term
.try_fitted_target_aware(Array2::<f64>::zeros((n, p)).view(), Some(&rho))
.expect("fitted");
term.fit_diagnostics_report(None, false, None, fitted.view(), None)
.expect("diagnostics report");
gam_linalg::faer_ndarray::eigh_census_this_thread()
})
.join()
.expect("certification thread");
assert!(
observed.max_dim < param_dim as u64,
"the certification must not decompose anything at the joint parameter dimension \
({param_dim}); the census saw {} across {} calls",
observed.max_dim,
observed.calls
);
assert!(
observed.max_dim <= p as u64,
"and in fact nothing wider than the output dimension {p}; the census saw {}",
observed.max_dim
);
}
#[test]
fn a_curvature_from_a_different_frame_layout_is_refused() {
use crate::identifiability::residual_gauge_exact_from_curvature;
let (n, p, k_atoms) = (16usize, 8usize, 2usize);
let term = planted_term(n, p, k_atoms, true);
let metric = term.diagnostic_metric().expect("metric");
let (model, streamed) = term
.to_residual_gauge_model(metric, None, false)
.expect("certificate model");
let curvature = expect_stored(streamed, "unpinned path streams its curvature");
let root_rows = curvature.root_rows();
let mine = FrameColumnLayout::new(p, &[1usize, 1]);
let impostor = FrameColumnLayout::new(p, &[2usize]);
assert_eq!(impostor.param_dim(), mine.param_dim());
assert_eq!(impostor.block_dim(), mine.block_dim());
assert_ne!(
impostor.column(1, 1),
mine.column(1, 1),
"the two layouts must disagree somewhere for this gate to bite"
);
let views: Vec<Option<crate::identifiability::AtomParameterView>> =
(0..model.atoms.len()).map(|_| None).collect();
let ops: Vec<Option<crate::identifiability::OrbitPenaltyOperator>> =
(0..model.atoms.len()).map(|_| None).collect();
let relabelled = ResidualGaugeCurvature::OutputBlockRoots {
roots: ndarray::Array3::<f64>::zeros((p, 2, 2)),
dense_rows: Array2::<f64>::zeros((0, impostor.param_dim())),
layout: impostor,
root_rows,
};
let message = residual_gauge_exact_from_curvature(&model, &views, &ops, relabelled)
.err()
.expect("a curvature from another parameterization must be refused");
assert!(
message.contains("frame-column layout"),
"refusal must name the cause, got {message:?}"
);
}
#[test]
fn the_pin_active_branch_streams_instead_of_retaining_a_dense_jacobian() {
let (n, k_atoms) = (12usize, 2usize);
for &p in &[16usize, 32, 64] {
let term = planted_term(n, p, k_atoms, true);
let metric = term.diagnostic_metric().expect("metric");
let (model, streamed) = term
.to_residual_gauge_model(metric, None, true)
.expect("pin-active certificate model");
assert!(
model.jacobian_rows.is_empty(),
"the pin-active branch must not retain a dense per-row Jacobian"
);
let curvature = expect_stored(streamed, "both branches stream their curvature");
assert_eq!(curvature.structure_tag(), "output_block_roots");
assert!(
model.isometry_penalty_root.nrows() > 0,
"the pin must actually be installed for this gate to bite"
);
let expected =
p * k_atoms * k_atoms + model.isometry_penalty_root.nrows() * model.param_dim();
assert_eq!(curvature.stored_scalars(), expected);
assert!(
curvature.stored_scalars() < n * p * model.param_dim(),
"the structured curvature must be smaller than one dense Jacobian stack"
);
}
}
#[test]
fn the_pin_active_certificate_matches_the_dense_gram_exactly() {
use crate::identifiability::residual_gauge_exact_from_curvature;
let (n, p, k_atoms) = (24usize, 12usize, 3usize);
let term = planted_term(n, p, k_atoms, true);
let metric = term.diagnostic_metric().expect("metric");
let (model, streamed) = term
.to_residual_gauge_model(metric, None, true)
.expect("pin-active certificate model");
let structured = expect_stored(streamed, "pin-active branch streams its curvature");
assert!(model.isometry_penalty_root.nrows() > 0);
let dense = ResidualGaugeCurvature::DenseGram {
gram: structured.to_dense_gram(),
root_rows: structured.root_rows(),
};
let views: Vec<Option<crate::identifiability::AtomParameterView>> =
(0..model.atoms.len()).map(|_| None).collect();
let ops: Vec<Option<crate::identifiability::OrbitPenaltyOperator>> =
(0..model.atoms.len()).map(|_| None).collect();
let from_blocks = residual_gauge_exact_from_curvature(&model, &views, &ops, structured)
.expect("structured pin-active certificate");
let from_dense = residual_gauge_exact_from_curvature(&model, &views, &ops, dense)
.expect("dense certificate");
assert_eq!(
from_blocks.pinning_rank, from_dense.pinning_rank,
"the inertia count must agree with the dense spectrum"
);
assert!(!from_blocks.generators.is_empty());
for (b, d) in from_blocks
.generators
.iter()
.zip(from_dense.generators.iter())
{
assert_eq!(b.description, d.description);
assert_eq!(
b.unpinned, d.unpinned,
"generator '{}' verdict must not depend on the representation",
b.description
);
let gap = (b.pinned_energy_fraction - d.pinned_energy_fraction).abs();
assert!(
gap <= 1.0e-10,
"generator '{}' energy fraction differs by {gap:.3e}",
b.description
);
}
assert_eq!(from_blocks.group_signature(), from_dense.group_signature());
}
#[test]
fn fit_diagnostics_report_certifies_the_same_thing_on_both_branches() {
use crate::identifiability::residual_gauge_exact_from_curvature;
let (n, p, k_atoms) = (24usize, 12usize, 3usize);
for pin in [false, true] {
let term = planted_term(n, p, k_atoms, true);
let rho = unit_rho(k_atoms);
let fitted = term
.try_fitted_target_aware(Array2::<f64>::zeros((n, p)).view(), Some(&rho))
.expect("fitted");
let report = term
.fit_diagnostics_report(None, pin, None, fitted.view(), None)
.expect("diagnostics report")
.residual_gauge;
assert!(
report.pinning_rank > 0,
"pin={pin}: the certificate must see a nonzero curvature"
);
let metric = term.diagnostic_metric().expect("metric");
let (model, streamed) = term
.to_residual_gauge_model(metric, None, pin)
.expect("certificate model");
let structured = expect_stored(streamed, "both branches stream their curvature");
assert_eq!(
(model.isometry_penalty_root.nrows() > 0),
pin,
"pin={pin}: the pin must be installed exactly when requested"
);
let dense = ResidualGaugeCurvature::DenseGram {
gram: structured.to_dense_gram(),
root_rows: structured.root_rows(),
};
let views: Vec<Option<crate::identifiability::AtomParameterView>> =
(0..model.atoms.len()).map(|_| None).collect();
let ops: Vec<Option<crate::identifiability::OrbitPenaltyOperator>> = if pin {
model
.atoms
.iter()
.map(|_| None)
.collect::<Vec<Option<crate::identifiability::OrbitPenaltyOperator>>>()
} else {
(0..model.atoms.len()).map(|_| None).collect()
};
let from_dense = residual_gauge_exact_from_curvature(&model, &views, &ops, dense)
.expect("dense certificate");
assert_eq!(
report.pinning_rank, from_dense.pinning_rank,
"pin={pin}: the shipped report must agree with the dense reduction"
);
assert_eq!(
report.diffeomorphism_unpinned, !pin,
"pin={pin}: the escalation must track the installed pin"
);
}
}
#[test]
fn block_plus_rows_inertia_matches_a_dense_eigendecomposition() {
use crate::identifiability::frame_curvature::BlockPlusRowsSpectrum;
use gam_linalg::faer_ndarray::FaerEigh;
let layout = FrameColumnLayout::new(5, &[2usize, 1]);
let (p, d) = (layout.output_dim(), layout.block_dim());
let mut seed = 0x2757_11E4_71A0_0001u64;
let mut next = || {
seed = seed
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
((seed >> 11) as f64) / ((1u64 << 53) as f64) - 0.5
};
let mut roots = ndarray::Array3::<f64>::zeros((p, d, d));
for i in 0..p {
if i == 2 {
continue; }
for a in 0..d {
for b in a..d {
if i == 3 && a == d - 1 {
continue;
}
roots[[i, a, b]] = next();
}
}
}
let mut dense_rows = Array2::<f64>::zeros((2, layout.param_dim()));
for j in 0..2 {
for c in 0..layout.param_dim() {
dense_rows[[j, c]] = next();
}
}
let curvature = ResidualGaugeCurvature::OutputBlockRoots {
roots: roots.clone(),
dense_rows: dense_rows.clone(),
layout: layout.clone(),
root_rows: p * d + 2,
};
let gram = curvature.to_dense_gram();
let (evals, _) = gram.eigh(faer::Side::Lower).expect("dense reference");
let spectrum =
BlockPlusRowsSpectrum::new(&roots, &dense_rows, &layout).expect("inertia machinery");
let lambda_max = spectrum.lambda_max().expect("lambda_max");
let reference_max = evals.iter().cloned().fold(0.0_f64, f64::max);
assert!(
(lambda_max - reference_max).abs() <= 1.0e-10 * reference_max.max(1.0),
"lambda_max {lambda_max:.12e} against the dense {reference_max:.12e}"
);
for exponent in -13i32..=1 {
let shift = reference_max * 10.0_f64.powi(exponent);
let counted = spectrum.count_above(shift).expect("inertia count");
let reference = evals.iter().filter(|v| **v > shift).count();
assert_eq!(
counted, reference,
"shift {shift:.3e}: inertia says {counted}, the dense spectrum says {reference}"
);
}
}
#[test]
fn diagnostics_report_no_longer_grows_cubically_in_the_output_dimension() {
let (n, k_atoms) = (48usize, 4usize);
let mut timings: Vec<(usize, f64)> = Vec::new();
println!("\n#2757: fit_diagnostics_report on the structured curvature (n={n}, K={k_atoms})");
for &p in &[256usize, 512, 1024] {
let term = planted_term(n, p, k_atoms, true);
let rho = unit_rho(k_atoms);
let fitted = term
.try_fitted_target_aware(Array2::<f64>::zeros((n, p)).view(), Some(&rho))
.expect("fitted");
let metric = term.diagnostic_metric().expect("metric");
let layout = FrameColumnLayout::new(p, &vec![1usize; k_atoms]);
let curvature = term
.residual_gauge_streamed_data_curvature(
&metric,
&layout,
Array2::<f64>::zeros((0, layout.param_dim())),
)
.expect("streamed curvature");
assert_eq!(curvature.structure_tag(), "output_block_roots");
assert_eq!(curvature.stored_scalars(), p * k_atoms * k_atoms);
let started = Instant::now();
let report = term
.fit_diagnostics_report(None, false, None, fitted.view(), None)
.expect("diagnostics report");
let seconds = started.elapsed().as_secs_f64();
println!(
" p={p:>5} param_dim={:>6} report {seconds:>8.3}s pinning_rank={}",
p * k_atoms,
report.residual_gauge.pinning_rank
);
timings.push((p, seconds));
}
for pair in timings.windows(2) {
let (p_lo, t_lo) = pair[0];
let (p_hi, t_hi) = pair[1];
let growth = t_hi / t_lo.max(1.0e-6);
assert!(
growth <= 4.0,
"doubling p from {p_lo} to {p_hi} multiplied the report by {growth:.2}x; \
the certification cost must not be cubic in the output dimension"
);
}
}