use std::sync::OnceLock;
pub const PROOF_WIDTH: u32 = 16;
#[inline]
pub fn rev_n(x: i64, n: u32) -> i64 {
let mut r = 0i64;
for i in 0..n {
if (x >> i) & 1 != 0 {
r |= 1i64 << (n - 1 - i);
}
}
r
}
fn check_reflection_identities() -> Result<(), String> {
for n in 1..=PROOF_WIDTH {
let full = (1i64 << n) - 1;
for v in 0..(1i64 << n) {
if (full & !rev_n(v, n)) != rev_n(full & !v, n) {
return Err(format!("L1 failed at n={n}, v={v}"));
}
if (rev_n(v << 1, n) & full) != ((rev_n(v, n) >> 1) & full) {
return Err(format!("LEM4 failed at n={n}, v={v}"));
}
if (rev_n(v >> 1, n) & full) != ((rev_n(v, n) << 1) & full) {
return Err(format!("LEM5 failed at n={n}, v={v}"));
}
}
}
Ok(())
}
fn cached() -> &'static Result<(), String> {
static CERT: OnceLock<Result<(), String>> = OnceLock::new();
CERT.get_or_init(check_reflection_identities)
}
pub fn reflection_certificate() -> &'static Result<(), String> {
cached()
}
pub fn reflection_symmetry_proven() -> bool {
cached().is_ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rev_n_is_an_involution_on_low_bits() {
for n in 1..=16 {
let full = (1i64 << n) - 1;
for v in 0..(1i64 << n.min(12)) {
assert_eq!(rev_n(rev_n(v, n), n), v & full);
}
}
}
#[test]
fn reflection_identities_are_proven() {
assert!(
reflection_symmetry_proven(),
"reflection certificate failed: {:?}",
reflection_certificate()
);
}
#[test]
fn wrong_reflection_is_rejected() {
fn wrong_rev(x: i64, n: u32) -> i64 {
super::rev_n(x, n + 1)
}
let mut broke = false;
'outer: for n in 2..=10 {
let full = (1i64 << n) - 1;
for v in 0..(1i64 << n) {
if (full & !wrong_rev(v, n)) != wrong_rev(full & !v, n) {
broke = true;
break 'outer;
}
}
}
assert!(broke, "a wrong reflection passed L1 — the certificate is vacuous");
}
}