use crate::simd;
const RMS_EPS: f32 = 1e-8;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum DepthInvarianceKind {
DepthInvariant = 0,
DepthSpecificRefinement = 1,
Collapsed = 2,
Insufficient = 3,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct DepthInvarianceDiagnostic {
pub magnitude_slope: f32,
pub mean_cos_step: f32,
pub effective_rank_slope: f32,
pub kind: DepthInvarianceKind,
}
#[derive(Clone, Copy, Debug)]
pub struct DepthInvarianceConfig {
pub min_samples: usize,
pub magnitude_slope_drift: f32,
pub magnitude_slope_collapse: f32,
pub effective_rank_collapse: f32,
pub cos_step_drift_lock: f32,
}
impl Default for DepthInvarianceConfig {
fn default() -> Self {
Self {
min_samples: 4,
magnitude_slope_drift: 0.05,
magnitude_slope_collapse: -0.05,
effective_rank_collapse: -0.05,
cos_step_drift_lock: 0.95,
}
}
}
pub struct Scratch {
pub magnitude_series: Vec<f32>,
pub rank_series: Vec<f32>,
pub h_tmp: Vec<f32>,
}
impl Scratch {
pub fn with_capacity(max_k_plus_1: usize, d: usize) -> Self {
Self {
magnitude_series: Vec::with_capacity(max_k_plus_1),
rank_series: Vec::with_capacity(max_k_plus_1),
h_tmp: Vec::with_capacity(d),
}
}
pub fn clear(&mut self) {
self.magnitude_series.clear();
self.rank_series.clear();
self.h_tmp.clear();
}
}
#[inline]
fn least_squares_slope_vs_index(ys: &[f32]) -> f32 {
let n = ys.len();
if n < 2 {
return 0.0;
}
let nf = n as f32;
let x_mean = (nf - 1.0) * 0.5;
let y_mean: f32 = ys.iter().copied().sum::<f32>() / nf;
let mut num: f32 = 0.0;
let mut den: f32 = 0.0;
for (i, &y) in ys.iter().enumerate() {
let dx = i as f32 - x_mean;
num = dx.mul_add(y - y_mean, num);
den = dx.mul_add(dx, den);
}
match den < 1e-30 {
true => 0.0,
false => num / den,
}
}
pub fn classify_chain(
states: &[f32],
d: usize,
cfg: &DepthInvarianceConfig,
scratch: &mut Scratch,
) -> DepthInvarianceDiagnostic {
if d == 0 || !states.len().is_multiple_of(d) {
return DepthInvarianceDiagnostic {
magnitude_slope: 0.0,
mean_cos_step: 0.0,
effective_rank_slope: 0.0,
kind: DepthInvarianceKind::Insufficient,
};
}
let k_plus_1 = states.len() / d;
if k_plus_1 < cfg.min_samples {
return DepthInvarianceDiagnostic {
magnitude_slope: 0.0,
mean_cos_step: 0.0,
effective_rank_slope: 0.0,
kind: DepthInvarianceKind::Insufficient,
};
}
scratch.clear();
let d_f = d as f32;
let mut cos_sum: f32 = 0.0;
let mut cos_count: usize = 0;
for t in 0..k_plus_1 {
let h_t = &states[t * d..(t + 1) * d];
let (sum_sq, sum_quartic) = simd::simd_sum_sq_quartic(h_t);
let magnitude = sum_sq.sqrt();
scratch.magnitude_series.push(magnitude);
let rank_t = match sum_quartic < 1e-12 {
true => 0.0, false => {
let pr = (sum_sq * sum_sq) / (d_f * sum_quartic);
pr.clamp(0.0, 1.0)
}
};
scratch.rank_series.push(rank_t);
if t > 0 {
let h_prev = &states[(t - 1) * d..t * d];
let mag_prev = scratch.magnitude_series[t - 1];
if mag_prev > 0.0 && magnitude > 0.0 {
let dot = simd::simd_dot_f32(h_t, h_prev, d);
cos_sum += dot / (mag_prev * magnitude);
cos_count += 1;
} }
}
let magnitude_slope = least_squares_slope_vs_index(&scratch.magnitude_series);
let effective_rank_slope = least_squares_slope_vs_index(&scratch.rank_series);
let mean_cos_step = match cos_count {
0 => 0.0,
c => cos_sum / c as f32,
};
let collapsed = effective_rank_slope < cfg.effective_rank_collapse;
let drifting = magnitude_slope.abs() > cfg.magnitude_slope_drift;
let kind = match (collapsed, drifting) {
(true, _) => DepthInvarianceKind::Collapsed,
(false, true) => DepthInvarianceKind::DepthSpecificRefinement,
(false, false) => DepthInvarianceKind::DepthInvariant,
};
DepthInvarianceDiagnostic {
magnitude_slope,
mean_cos_step,
effective_rank_slope,
kind,
}
}
pub fn classify_chain_batched(
states_per_kernel: &[&[f32]],
d: usize,
cfg: &DepthInvarianceConfig,
scratch: &mut Scratch,
out: &mut Vec<DepthInvarianceDiagnostic>,
) {
out.clear();
for &states in states_per_kernel {
let diag = classify_chain(states, d, cfg, scratch);
out.push(diag);
}
}
#[derive(Clone, Copy, Debug)]
#[repr(u8)]
pub enum MagnitudeRegularization {
None = 0,
RmsNorm = 1,
ScalarPinch { max_rms: f32 } = 2,
}
pub fn apply_magnitude_regularization(
h_raw: &mut [f32],
mode: MagnitudeRegularization,
_scratch: &mut [f32],
) {
match mode {
MagnitudeRegularization::None => { }
MagnitudeRegularization::RmsNorm => {
let d_f = h_raw.len() as f32;
let mut sum_sq: f32 = 0.0;
for &x in h_raw.iter() {
sum_sq += x * x;
}
let rms = (sum_sq / d_f + RMS_EPS).sqrt();
for x in h_raw.iter_mut() {
*x /= rms;
}
}
MagnitudeRegularization::ScalarPinch { max_rms } => {
let d_f = h_raw.len() as f32;
let mut sum_sq: f32 = 0.0;
for &x in h_raw.iter() {
sum_sq += x * x;
}
let current_rms = (sum_sq / d_f).sqrt();
if current_rms > max_rms && current_rms > 0.0 {
let scale = max_rms / current_rms;
for x in h_raw.iter_mut() {
*x *= scale;
}
} }
}
}
#[cfg(test)]
mod tests {
use super::*;
fn rms(h: &[f32]) -> f32 {
let n = h.len() as f32;
let sum_sq: f32 = h.iter().map(|x| x * x).sum();
(sum_sq / n).sqrt()
}
#[test]
fn none_is_identity() {
let original = [0.1f32, -0.5, 0.8, 0.3, -0.2, 0.7];
let mut h = original;
let mut scratch = [0.0f32; 6];
apply_magnitude_regularization(&mut h, MagnitudeRegularization::None, &mut scratch);
assert_eq!(h, original, "None mode must be bit-identical identity");
}
#[test]
fn rmsnorm_produces_unit_rms() {
let mut h = [0.5f32, 1.2, -0.8, 0.3, 1.5, -0.4];
let mut scratch = [0.0f32; 6];
apply_magnitude_regularization(&mut h, MagnitudeRegularization::RmsNorm, &mut scratch);
let post_rms = rms(&h);
assert!(
(post_rms - 1.0).abs() < 1e-5,
"RmsNorm should produce unit RMS, got {post_rms}"
);
}
#[test]
fn scalar_pinch_caps_at_max_rms() {
let mut h = [2.0f32, 2.0, 2.0, 2.0]; let mut scratch = [0.0f32; 4];
apply_magnitude_regularization(
&mut h,
MagnitudeRegularization::ScalarPinch { max_rms: 1.0 },
&mut scratch,
);
let post_rms = rms(&h);
assert!(
post_rms <= 1.0 + 1e-5,
"ScalarPinch should cap at max_rms=1.0, got {post_rms}"
);
}
#[test]
fn scalar_pinch_no_op_below_max_rms() {
let original = [0.5f32, 0.5, 0.5, 0.5]; let mut h = original;
let mut scratch = [0.0f32; 4];
apply_magnitude_regularization(
&mut h,
MagnitudeRegularization::ScalarPinch { max_rms: 1.0 },
&mut scratch,
);
assert_eq!(
h, original,
"ScalarPinch must be no-op (bit-identical) when rms < max_rms"
);
}
#[test]
fn g1_flat_magnitude_is_depth_invariant() {
let d = 4;
let k_plus_1 = 6;
let states: Vec<f32> = (0..k_plus_1)
.flat_map(|_| [1.0f32, 1.0, 1.0, 1.0])
.collect();
let cfg = DepthInvarianceConfig::default();
let mut scratch = Scratch::with_capacity(k_plus_1, d);
let diag = classify_chain(&states, d, &cfg, &mut scratch);
assert_eq!(
diag.kind,
DepthInvarianceKind::DepthInvariant,
"flat magnitude → DepthInvariant, got {:?}",
diag.kind
);
assert!(
diag.magnitude_slope.abs() < 1e-5,
"flat magnitude → slope ≈ 0, got {}",
diag.magnitude_slope
);
}
#[test]
fn g1_linear_growth_is_depth_specific() {
let d = 4;
let k_plus_1 = 6;
let v = [1.0f32, 0.5, 0.3, 0.2];
let states: Vec<f32> = (0..k_plus_1)
.flat_map(|t| {
let s = t as f32;
[s * v[0], s * v[1], s * v[2], s * v[3]]
})
.collect();
let cfg = DepthInvarianceConfig::default();
let mut scratch = Scratch::with_capacity(k_plus_1, d);
let diag = classify_chain(&states, d, &cfg, &mut scratch);
assert_eq!(
diag.kind,
DepthInvarianceKind::DepthSpecificRefinement,
"linear growth → DepthSpecificRefinement, got {:?}",
diag.kind
);
assert!(
diag.magnitude_slope > 0.0,
"linear growth → positive slope, got {}",
diag.magnitude_slope
);
}
#[test]
fn g1_rank_collapse_is_collapsed() {
let d = 4;
let k_plus_1 = 6;
let states: Vec<f32> = (0..k_plus_1)
.flat_map(|t| {
let s = (t + 1) as f32;
[s, 1.0f32, 1.0, 1.0]
})
.collect();
let cfg = DepthInvarianceConfig::default();
let mut scratch = Scratch::with_capacity(k_plus_1, d);
let diag = classify_chain(&states, d, &cfg, &mut scratch);
assert_eq!(
diag.kind,
DepthInvarianceKind::Collapsed,
"rank collapse → Collapsed, got {:?} (rank_slope={}, mag_slope={})",
diag.kind,
diag.effective_rank_slope,
diag.magnitude_slope
);
assert!(
diag.effective_rank_slope < cfg.effective_rank_collapse,
"rank collapse → rank_slope < {}, got {}",
cfg.effective_rank_collapse,
diag.effective_rank_slope
);
}
#[test]
fn g1_insufficient_samples() {
let d = 4;
let k_plus_1 = 3;
let states: Vec<f32> = (0..k_plus_1)
.flat_map(|_| [1.0f32, 1.0, 1.0, 1.0])
.collect();
let cfg = DepthInvarianceConfig::default();
let mut scratch = Scratch::with_capacity(8, d);
let diag = classify_chain(&states, d, &cfg, &mut scratch);
assert_eq!(diag.kind, DepthInvarianceKind::Insufficient);
assert_eq!(diag.magnitude_slope, 0.0);
assert_eq!(diag.effective_rank_slope, 0.0);
}
#[test]
fn g1_oscillating_chain_is_depth_invariant() {
let d = 4;
let k_plus_1 = 6;
let states: Vec<f32> = (0..k_plus_1)
.flat_map(|t| {
let s = if t % 2 == 0 { 1.0f32 } else { -1.0 };
[s, s, s, s]
})
.collect();
let cfg = DepthInvarianceConfig::default();
let mut scratch = Scratch::with_capacity(k_plus_1, d);
let diag = classify_chain(&states, d, &cfg, &mut scratch);
assert_eq!(
diag.kind,
DepthInvarianceKind::DepthInvariant,
"oscillating flat-magnitude → DepthInvariant, got {:?} (cos={})",
diag.kind,
diag.mean_cos_step
);
assert!(
diag.mean_cos_step < 0.0,
"oscillating → negative cos_step, got {}",
diag.mean_cos_step
);
}
#[test]
fn g1_locked_drift_high_cos_growing_mag() {
let d = 4;
let k_plus_1 = 6;
let v = [1.0f32, 0.5, 0.3, 0.2];
let states: Vec<f32> = (0..k_plus_1)
.flat_map(|t| {
let s = 1.0 + 0.1 * t as f32;
[s * v[0], s * v[1], s * v[2], s * v[3]]
})
.collect();
let cfg = DepthInvarianceConfig::default();
let mut scratch = Scratch::with_capacity(k_plus_1, d);
let diag = classify_chain(&states, d, &cfg, &mut scratch);
assert_eq!(
diag.kind,
DepthInvarianceKind::DepthSpecificRefinement,
"locked drift → DepthSpecificRefinement, got {:?}",
diag.kind
);
assert!(
diag.mean_cos_step > cfg.cos_step_drift_lock,
"locked drift → cos_step > {}, got {}",
cfg.cos_step_drift_lock,
diag.mean_cos_step
);
}
#[test]
fn g1_zero_chain_degenerate() {
let d = 4;
let k_plus_1 = 6;
let states: Vec<f32> = (0..(k_plus_1 * d)).map(|_| 0.0f32).collect();
let cfg = DepthInvarianceConfig::default();
let mut scratch = Scratch::with_capacity(k_plus_1, d);
let diag = classify_chain(&states, d, &cfg, &mut scratch);
assert_eq!(
diag.kind,
DepthInvarianceKind::DepthInvariant,
"zero chain → DepthInvariant (degenerate stable), got {:?}",
diag.kind
);
}
#[test]
fn g1_batched_matches_single() {
let d = 4;
let chain_flat: Vec<f32> = (0..6).flat_map(|_| [1.0f32, 1.0, 1.0, 1.0]).collect();
let chain_grow: Vec<f32> = (0..6)
.flat_map(|t| {
let s = 1.0 + 0.1 * t as f32;
[s, s * 0.5, s * 0.3, s * 0.2]
})
.collect();
let chain_collapse: Vec<f32> = (0..6)
.flat_map(|t| {
let s = (t + 1) as f32;
[s, 1.0f32, 1.0, 1.0]
})
.collect();
let chains: Vec<&[f32]> = vec![&chain_flat, &chain_grow, &chain_collapse];
let cfg = DepthInvarianceConfig::default();
let mut scratch_single = Scratch::with_capacity(8, d);
let singles: Vec<_> = chains
.iter()
.map(|&s| classify_chain(s, d, &cfg, &mut scratch_single))
.collect();
let mut scratch_batch = Scratch::with_capacity(8, d);
let mut batched = Vec::with_capacity(chains.len());
classify_chain_batched(&chains, d, &cfg, &mut scratch_batch, &mut batched);
assert_eq!(
singles.len(),
batched.len(),
"batched should produce one diagnostic per chain"
);
for (i, (s, b)) in singles.iter().zip(batched.iter()).enumerate() {
assert_eq!(
s.kind, b.kind,
"chain {i}: kind mismatch single={:?} batched={:?}",
s.kind, b.kind
);
assert!(
(s.magnitude_slope - b.magnitude_slope).abs() < 1e-6,
"chain {i}: magnitude_slope mismatch single={} batched={}",
s.magnitude_slope,
b.magnitude_slope
);
assert!(
(s.effective_rank_slope - b.effective_rank_slope).abs() < 1e-6,
"chain {i}: effective_rank_slope mismatch single={} batched={}",
s.effective_rank_slope,
b.effective_rank_slope
);
assert!(
(s.mean_cos_step - b.mean_cos_step).abs() < 1e-6,
"chain {i}: mean_cos_step mismatch single={} batched={}",
s.mean_cos_step,
b.mean_cos_step
);
}
}
}