use cortiq_engine::skillbake::{mask_init_logit, mask_step_scale};
fn sigmoid(x: f32) -> f32 {
1.0 / (1.0 + (-x).exp())
}
#[test]
fn the_effective_start_is_the_same_at_every_loop_depth() {
let want = sigmoid(2.0);
for loops in 1..=6 {
let m0 = mask_init_logit(loops);
let effective = sigmoid(m0).powi(loops as i32);
let rel = (effective - want).abs() / want;
println!(
"loops={loops}: m0={m0:.4} σ={:.4} effective={effective:.6} (want {want:.6})",
sigmoid(m0)
);
assert!(
rel < 1e-4,
"loops={loops}: effective start {effective} is not σ(2.0)={want}"
);
}
}
#[test]
fn a_single_loop_reproduces_the_validated_constant() {
let m0 = mask_init_logit(1);
assert!(
(m0 - 2.0).abs() < 1e-5,
"an unlooped model must still start at 2.0, got {m0}"
);
assert_eq!(mask_step_scale(1), 1.0, "an unlooped step must be unscaled");
}
#[test]
fn the_start_leaves_a_usable_gradient() {
for loops in 1..=4 {
let s = sigmoid(mask_init_logit(loops));
let dsigma = s * (1.0 - s);
println!("loops={loops}: σ={s:.4} σ'={dsigma:.5}");
assert!(
dsigma > 0.02,
"loops={loops}: σ'={dsigma:.5} is too flat to train (identity trap)"
);
}
}
#[test]
fn the_mask_step_is_normalised_by_the_visit_count() {
for loops in 1..=8 {
let scale = mask_step_scale(loops);
assert!(
(scale * loops as f64 - 1.0).abs() < 1e-12,
"loops={loops}: scale {scale} does not undo the per-visit accumulation"
);
}
assert_eq!(mask_step_scale(0), 1.0, "loops=0 must be treated as 1");
}
#[test]
fn deeper_loops_open_the_per_visit_gate_wider() {
let mut prev = 0f32;
for loops in 1..=6 {
let s = sigmoid(mask_init_logit(loops));
assert!(
s > prev,
"loops={loops}: per-visit gate {s} did not open past {prev}"
);
assert!(s < 1.0, "loops={loops}: gate saturated at {s}");
prev = s;
}
}