use std::collections::BTreeMap;
use crate::affine::{all_affine_bijections, Affine};
use crate::cdcl::Lit;
use crate::hypercube::{
canonical_cover, cube_group_closure, diagnose, face_vector, hyperoctahedral_generators,
min_resolution_width, minimal_cover_orbits, weakest_crushing_rung,
weakest_crushing_rung_with_char, Cover, ProofRung, Shadow,
};
use crate::solve::{solve_structured, Answer, Route};
#[derive(Clone, Debug)]
pub struct OrbitRecord {
pub n: usize,
pub rep: Cover,
pub num_clauses: usize,
pub orbit_size: usize,
pub stabilizer_order: usize,
pub face_vector: BTreeMap<usize, usize>,
pub min_res_width: usize,
pub rung: ProofRung,
pub shadow: Option<Shadow>,
pub route: Route,
pub discovered_rule_orbits: usize,
pub full_rule_orbits: usize,
pub affine_explained: bool,
pub modp_routed: bool,
}
impl OrbitRecord {
pub fn router_beats_ladder(&self) -> bool {
matches!(self.route, Route::ModP | Route::Collapse | Route::HybridXor)
&& !matches!(self.rung, ProofRung::Counting | ProofRung::Parity)
}
pub fn symmetry_underbroken(&self) -> bool {
self.discovered_rule_orbits > self.full_rule_orbits
}
}
pub fn extended_rung(rec: &OrbitRecord, primes: &[u64]) -> ProofRung {
weakest_crushing_rung_with_char(rec.n, &rec.rep.clauses(), rec.n, primes)
}
#[derive(Clone, Debug)]
pub struct CoverageSummary {
pub n: usize,
pub orbits: usize,
pub by_rung: BTreeMap<String, usize>,
pub max_ns_degree: usize,
pub structured: usize,
pub rigid: usize,
pub by_resolution_width: BTreeMap<usize, usize>,
}
pub fn coverage_summary(n: usize) -> CoverageSummary {
let mut by_rung: BTreeMap<String, usize> = BTreeMap::new();
let mut by_resolution_width: BTreeMap<usize, usize> = BTreeMap::new();
let (mut max_ns_degree, mut structured, mut rigid) = (0usize, 0usize, 0usize);
let records = census(n);
for r in &records {
let label = match r.rung {
ProofRung::Trivial => "trivial".to_string(),
ProofRung::Counting => "counting".to_string(),
ProofRung::Parity => "parity".to_string(),
ProofRung::ModCount { p } => format!("modcount-p{p}"),
ProofRung::Nullstellensatz { min_degree } => {
max_ns_degree = max_ns_degree.max(min_degree);
format!("nullstellensatz-d{min_degree}")
}
ProofRung::BeyondBudget => "beyond-budget".to_string(),
};
*by_rung.entry(label).or_insert(0) += 1;
*by_resolution_width.entry(r.min_res_width).or_insert(0) += 1;
if r.stabilizer_order > 1 {
structured += 1;
} else {
rigid += 1;
}
}
CoverageSummary { n, orbits: records.len(), by_rung, max_ns_degree, structured, rigid, by_resolution_width }
}
#[derive(Clone, Debug)]
pub struct ResidueMap {
pub n: usize,
pub total: usize,
pub crushed: usize,
pub residue: usize,
pub targetable: usize,
pub rigid_core: usize,
pub core_max_ns_degree: usize,
}
fn falsify_set(clause: &[Lit], num_vars: usize) -> u64 {
let mut set = 0u64;
for x in 0..(1u64 << num_vars) {
if clause.iter().all(|lit| {
let bit = (x >> (lit.var() as u64)) & 1;
if lit.is_positive() { bit == 0 } else { bit == 1 }
}) {
set |= 1 << x;
}
}
set
}
fn map_point_set(s: u64, phi: &Affine, num_vars: usize) -> u64 {
let mut out = 0u64;
for x in 0..(1u64 << num_vars) {
if (s >> x) & 1 == 1 {
out |= 1 << phi.apply(x);
}
}
out
}
fn pointset_to_clause(s: u64, num_vars: usize) -> Option<Vec<Lit>> {
if s == 0 {
return None;
}
let points: Vec<u64> = (0..(1u64 << num_vars)).filter(|&x| (s >> x) & 1 == 1).collect();
let mut clause = Vec::new();
let mut free = 0usize;
for i in 0..num_vars as u64 {
let first = (points[0] >> i) & 1;
if points.iter().all(|&p| (p >> i) & 1 == first) {
clause.push(Lit::new(i as u32, first == 0)); } else {
free += 1;
}
}
if points.len() != (1usize << free) {
return None;
}
Some(clause)
}
fn agl_image_formula(clauses: &[Vec<Lit>], phi: &Affine, num_vars: usize) -> Option<Vec<Vec<Lit>>> {
clauses
.iter()
.map(|c| pointset_to_clause(map_point_set(falsify_set(c, num_vars), phi, num_vars), num_vars))
.collect()
}
fn transvection_image_clause(clause: &[Lit], i: u32, j: u32) -> Option<Vec<Lit>> {
let lit_i = clause.iter().find(|l| l.var() == i);
let lit_j = clause.iter().find(|l| l.var() == j);
match (lit_i, lit_j) {
(Some(_), None) => None,
(Some(_), Some(lj)) if !lj.is_positive() => {
Some(clause.iter().map(|l| if l.var() == i { l.negated() } else { *l }).collect())
}
_ => Some(clause.to_vec()),
}
}
fn clause_set_key(clauses: &[Vec<Lit>]) -> std::collections::BTreeSet<Vec<(u32, bool)>> {
clauses
.iter()
.map(|c| {
let mut k: Vec<(u32, bool)> = c.iter().map(|l| (l.var(), l.is_positive())).collect();
k.sort_unstable();
k
})
.collect()
}
pub fn affine_transvection_generators(num_vars: usize, clauses: &[Vec<Lit>]) -> Vec<(u32, u32)> {
let original = clause_set_key(clauses);
let mut gens = Vec::new();
for i in 0..num_vars as u32 {
for j in 0..num_vars as u32 {
if i == j {
continue;
}
let image: Option<Vec<Vec<Lit>>> =
clauses.iter().map(|c| transvection_image_clause(c, i, j)).collect();
if let Some(img) = image {
if clause_set_key(&img) == original {
gens.push((i, j));
}
}
}
}
gens
}
fn composite_shear_image_clause(clause: &[Lit], targets: &[u32], j: u32) -> Option<Vec<Lit>> {
let mut c = clause.to_vec();
for &i in targets {
c = transvection_image_clause(&c, i, j)?;
}
Some(c)
}
fn combinations(pool: &[u32], k: usize) -> Vec<Vec<u32>> {
if k == 0 {
return vec![Vec::new()];
}
let mut out = Vec::new();
for (idx, &x) in pool.iter().enumerate() {
for mut rest in combinations(&pool[idx + 1..], k - 1) {
rest.insert(0, x);
out.push(rest);
}
}
out
}
pub fn affine_composite_shear_generators(
num_vars: usize,
clauses: &[Vec<Lit>],
max_targets: usize,
) -> Vec<(Vec<u32>, u32)> {
let original = clause_set_key(clauses);
let mut gens = Vec::new();
for j in 0..num_vars as u32 {
let others: Vec<u32> = (0..num_vars as u32).filter(|&v| v != j).collect();
for size in 1..=max_targets.min(others.len()) {
for combo in combinations(&others, size) {
let image: Option<Vec<Vec<Lit>>> =
clauses.iter().map(|c| composite_shear_image_clause(c, &combo, j)).collect();
if let Some(img) = image {
if clause_set_key(&img) == original {
gens.push((combo, j));
}
}
}
}
}
gens
}
fn rank1_image_clause(clause: &[Lit], u: u64, v: u64) -> Option<Vec<Lit>> {
let mut pivots: Vec<(u64, u8)> = Vec::new();
for l in clause {
let i = l.var();
let mut row = (1u64 << i) ^ (if (u >> i) & 1 == 1 { v } else { 0 });
let mut rhs: u8 = if l.is_positive() { 0 } else { 1 };
for &(prow, prhs) in &pivots {
let pbit = 1u64 << (63 - prow.leading_zeros());
if row & pbit != 0 {
row ^= prow;
rhs ^= prhs;
}
}
if row == 0 {
if rhs != 0 {
return None; }
continue;
}
let nbit = 1u64 << (63 - row.leading_zeros());
for p in pivots.iter_mut() {
if p.0 & nbit != 0 {
p.0 ^= row;
p.1 ^= rhs;
}
}
pivots.push((row, rhs));
}
let mut lits = Vec::with_capacity(pivots.len());
for (row, rhs) in pivots {
if row.count_ones() != 1 {
return None; }
lits.push(Lit::new(row.trailing_zeros(), rhs == 0));
}
Some(lits)
}
fn even_weight_masks(num_vars: usize, max_weight: usize) -> Vec<u64> {
let pool: Vec<u32> = (0..num_vars as u32).collect();
let mut out = Vec::new();
let mut k = 2;
while k <= max_weight.min(num_vars) {
for combo in combinations(&pool, k) {
out.push(combo.iter().fold(0u64, |m, &b| m | (1u64 << b)));
}
k += 2;
}
out
}
pub fn symplectic_transvection_generators(
num_vars: usize,
clauses: &[Vec<Lit>],
max_weight: usize,
) -> Vec<u64> {
let original = clause_set_key(clauses);
let mut gens = Vec::new();
for w in even_weight_masks(num_vars, max_weight) {
let image: Option<Vec<Vec<Lit>>> =
clauses.iter().map(|c| rank1_image_clause(c, w, w)).collect();
if let Some(img) = image {
if clause_set_key(&img) == original {
gens.push(w);
}
}
}
gens
}
pub fn clause_agl_symmetries(num_vars: usize, clauses: &[Vec<Lit>]) -> usize {
let blockers: std::collections::HashSet<u64> =
clauses.iter().map(|c| falsify_set(c, num_vars)).collect();
all_affine_bijections(num_vars)
.into_iter()
.filter(|phi| blockers.iter().all(|&s| blockers.contains(&map_point_set(s, phi, num_vars))))
.count()
}
fn blocker_masks(clauses: &[Vec<Lit>], num_vars: usize) -> Vec<u64> {
let mut m: Vec<u64> = clauses.iter().map(|c| falsify_set(c, num_vars)).collect();
m.sort_unstable();
m.dedup();
m
}
fn perm_table(phi: &Affine, num_vars: usize) -> Vec<u32> {
(0..(1u64 << num_vars)).map(|x| phi.apply(x) as u32).collect()
}
fn map_mask(s: u64, table: &[u32]) -> u64 {
let mut out = 0u64;
let mut bits = s;
while bits != 0 {
let x = bits.trailing_zeros() as usize;
out |= 1u64 << table[x];
bits &= bits - 1;
}
out
}
fn canonical_over_tables(masks: &[u64], tables: &[Vec<u32>]) -> Vec<u64> {
let mut best: Option<Vec<u64>> = None;
for t in tables {
let mut img: Vec<u64> = masks.iter().map(|&s| map_mask(s, t)).collect();
img.sort_unstable();
match &best {
Some(b) if *b <= img => {}
_ => best = Some(img),
}
}
best.unwrap_or_default()
}
fn is_permutation_matrix(matrix: &[u64], num_vars: usize) -> bool {
let mut cols = 0u64;
for row in matrix.iter().take(num_vars) {
if row.count_ones() != 1 || cols & row != 0 {
return false;
}
cols |= row;
}
cols == (1u64 << num_vars) - 1
}
fn bn_affines(num_vars: usize) -> Vec<Affine> {
all_affine_bijections(num_vars).into_iter().filter(|a| is_permutation_matrix(&a.matrix, num_vars)).collect()
}
fn transvections(num_vars: usize) -> Vec<Affine> {
let mut out = Vec::new();
for i in 0..num_vars {
for j in 0..num_vars {
if i == j {
continue;
}
let mut matrix: Vec<u64> = (0..num_vars).map(|k| 1u64 << k).collect();
matrix[i] |= 1u64 << j;
out.push(Affine { n: num_vars, matrix, translation: 0 });
}
}
out
}
#[derive(Clone, Debug)]
pub struct AglCollapse {
pub n: usize,
pub bn_orbits: usize,
pub agl_classes: usize,
}
impl AglCollapse {
pub fn factor(&self) -> f64 {
self.bn_orbits as f64 / self.agl_classes.max(1) as f64
}
}
pub fn agl_collapse_exact(n: usize) -> AglCollapse {
let tables: Vec<Vec<u32>> = all_affine_bijections(n).iter().map(|p| perm_table(p, n)).collect();
let mut classes: std::collections::BTreeSet<Vec<u64>> = std::collections::BTreeSet::new();
let mut bn_orbits = 0usize;
for cover in minimal_cover_orbits(n) {
bn_orbits += 1;
classes.insert(canonical_over_tables(&blocker_masks(&cover.clauses(), n), &tables));
}
AglCollapse { n, bn_orbits, agl_classes: classes.len() }
}
pub fn agl_collapse_via_transvections(n: usize) -> AglCollapse {
let reps: Vec<Vec<u64>> =
minimal_cover_orbits(n).into_iter().map(|c| blocker_masks(&c.clauses(), n)).collect();
let bn_tables: Vec<Vec<u32>> = bn_affines(n).iter().map(|p| perm_table(p, n)).collect();
let tau_tables: Vec<Vec<u32>> = transvections(n).iter().map(|p| perm_table(p, n)).collect();
let mut key_to_idx: std::collections::HashMap<Vec<u64>, usize> = std::collections::HashMap::new();
for (i, masks) in reps.iter().enumerate() {
key_to_idx.insert(canonical_over_tables(masks, &bn_tables), i);
}
let mut parent: Vec<usize> = (0..reps.len()).collect();
fn find(parent: &mut [usize], x: usize) -> usize {
let mut root = x;
while parent[root] != root {
root = parent[root];
}
let mut cur = x;
while parent[cur] != cur {
let next = parent[cur];
parent[cur] = root;
cur = next;
}
root
}
for (i, masks) in reps.iter().enumerate() {
for tau in &tau_tables {
let mut img: Vec<u64> = Vec::with_capacity(masks.len());
let mut ok = true;
for &s in masks {
let t = map_mask(s, tau);
if pointset_to_clause(t, n).is_none() {
ok = false;
break;
}
img.push(t);
}
if !ok {
continue;
}
img.sort_unstable();
img.dedup();
if let Some(&j) = key_to_idx.get(&canonical_over_tables(&img, &bn_tables)) {
let (ri, rj) = (find(&mut parent, i), find(&mut parent, j));
if ri != rj {
parent[ri] = rj;
}
}
}
}
let agl_classes = (0..reps.len()).filter(|&i| find(&mut parent, i) == i).count();
AglCollapse { n, bn_orbits: reps.len(), agl_classes }
}
#[derive(Clone, Debug)]
pub struct AglWitness {
pub map: Affine,
}
impl AglWitness {
pub fn verify(&self, from: &[u64], to: &[u64], num_vars: usize) -> bool {
let table = perm_table(&self.map, num_vars);
let img: std::collections::BTreeSet<u64> = from.iter().map(|&s| map_mask(s, &table)).collect();
img == to.iter().copied().collect()
}
}
pub fn find_agl_witness(from: &[u64], to: &[u64], num_vars: usize) -> Option<AglWitness> {
if from.len() != to.len() {
return None;
}
let target: std::collections::BTreeSet<u64> = to.iter().copied().collect();
for phi in all_affine_bijections(num_vars) {
let table = perm_table(&phi, num_vars);
let img: std::collections::BTreeSet<u64> = from.iter().map(|&s| map_mask(s, &table)).collect();
if img == target {
return Some(AglWitness { map: phi });
}
}
None
}
pub fn generic_subfamilies(n: usize) -> BTreeMap<(String, usize), usize> {
let full = format!("nullstellensatz-d{n}");
let mut seen: std::collections::BTreeSet<(String, usize, Vec<(usize, usize)>)> = std::collections::BTreeSet::new();
let mut sub: BTreeMap<(String, usize), usize> = BTreeMap::new();
for cover in minimal_cover_orbits(n) {
let clauses = cover.clauses();
if rung_label(&weakest_crushing_rung(n, &clauses, n)) != full {
continue; }
let shadow = format!("{:?}", diagnose(n, &clauses).cut);
let width = min_resolution_width(&cover).unwrap_or(usize::MAX);
let fv: Vec<(usize, usize)> = face_vector(&cover).into_iter().collect();
if seen.insert((shadow.clone(), width, fv)) {
*sub.entry((shadow, width)).or_insert(0) += 1; }
}
sub
}
fn family_label(rung_label: &str, n: usize) -> String {
match rung_label {
"trivial" => "unit-propagation".into(),
"counting" => "PHP / cardinality (counting)".into(),
"parity" => "Tseitin / XOR (parity, poly via GF(2))".into(),
s if s == format!("nullstellensatz-d{n}") => "GENERIC full-degree core (no low-degree shortcut)".into(),
s => format!("bounded-algebraic ({s})"),
}
}
pub fn named_giants(n: usize, k: usize) -> Vec<(usize, String)> {
let mut sigs: BTreeMap<(String, String, usize, Vec<(usize, usize)>), usize> = BTreeMap::new();
for cover in minimal_cover_orbits(n) {
let clauses = cover.clauses();
let rl = rung_label(&weakest_crushing_rung(n, &clauses, n));
let shadow = format!("{:?}", diagnose(n, &clauses).cut);
let width = min_resolution_width(&cover).unwrap_or(usize::MAX);
let fv: Vec<(usize, usize)> = face_vector(&cover).into_iter().collect();
*sigs.entry((rl, shadow, width, fv)).or_insert(0) += 1;
}
let mut entries: Vec<_> = sigs.into_iter().collect();
entries.sort_by(|a, b| b.1.cmp(&a.1));
entries.into_iter().take(k).map(|((rl, _, _, _), count)| (count, family_label(&rl, n))).collect()
}
pub fn family_of_types(n: usize) -> (usize, BTreeMap<String, usize>) {
let mut sig_label: BTreeMap<(String, String, usize, Vec<(usize, usize)>), String> = BTreeMap::new();
for cover in minimal_cover_orbits(n) {
let clauses = cover.clauses();
let rl = rung_label(&weakest_crushing_rung(n, &clauses, n));
let shadow = format!("{:?}", diagnose(n, &clauses).cut);
let width = min_resolution_width(&cover).unwrap_or(usize::MAX);
let fv: Vec<(usize, usize)> = face_vector(&cover).into_iter().collect();
sig_label.entry((rl.clone(), shadow, width, fv)).or_insert_with(|| family_label(&rl, n));
}
let mut by_family: BTreeMap<String, usize> = BTreeMap::new();
for label in sig_label.values() {
*by_family.entry(label.clone()).or_insert(0) += 1;
}
(sig_label.len(), by_family)
}
fn family_name(rung: &ProofRung) -> String {
match rung {
ProofRung::Trivial => "unit-propagation".into(),
ProofRung::Counting => "counting (pigeonhole/cardinality)".into(),
ProofRung::Parity => "parity (XOR/Tseitin)".into(),
ProofRung::ModCount { p } => format!("mod-{p} counting (one-hot GF({p}))"),
ProofRung::Nullstellensatz { min_degree } => format!("algebraic-d{min_degree}"),
ProofRung::BeyondBudget => "unclassified".into(),
}
}
pub fn family_growth(max_n: usize) -> Vec<(usize, usize, Vec<String>)> {
let mut prev: std::collections::BTreeSet<String> = std::collections::BTreeSet::new();
(1..=max_n)
.map(|n| {
let fam: std::collections::BTreeSet<String> = family_census(n).into_keys().collect();
let new: Vec<String> = fam.difference(&prev).cloned().collect();
prev.clone_from(&fam);
(n, fam.len(), new)
})
.collect()
}
pub fn family_census(n: usize) -> BTreeMap<String, usize> {
let mut fam: BTreeMap<String, usize> = BTreeMap::new();
for cover in minimal_cover_orbits(n) {
*fam.entry(family_name(&weakest_crushing_rung(n, &cover.clauses(), n))).or_insert(0) += 1;
}
fam
}
pub fn family_tower(n: usize) -> Vec<String> {
let mut fams = vec![
"unit-propagation".to_string(),
"counting (pigeonhole/cardinality)".to_string(),
"parity (XOR/Tseitin)".to_string(),
];
for d in 2..=n {
fams.push(format!("algebraic-d{d}"));
}
fams
}
pub fn witness_unit_propagation(n: usize) -> (usize, Vec<Vec<Lit>>) {
(n.max(1), vec![vec![Lit::pos(0)], vec![Lit::neg(0)]])
}
pub fn witness_parity(n: usize) -> (usize, Vec<Vec<Lit>>) {
let mut clauses = Vec::new();
for (a, b) in [(0u32, 1u32), (1, 2), (2, 0)] {
clauses.push(vec![Lit::pos(a), Lit::pos(b)]); clauses.push(vec![Lit::neg(a), Lit::neg(b)]);
}
(n.max(3), clauses)
}
pub fn witness_counting(pigeons: usize) -> (usize, Vec<Vec<Lit>>) {
let (cnf, _) = crate::families::php(pigeons);
(cnf.num_vars, cnf.clauses)
}
pub fn realized_tower_families(n: usize) -> BTreeMap<String, Vec<Vec<Lit>>> {
let mut out: BTreeMap<String, Vec<Vec<Lit>>> = BTreeMap::new();
for cover in minimal_cover_orbits(n) {
let clauses = cover.clauses();
out.entry(family_name(&weakest_crushing_rung(n, &clauses, n))).or_insert(clauses);
}
out
}
fn rung_label(rung: &ProofRung) -> String {
match rung {
ProofRung::Trivial => "trivial".into(),
ProofRung::Counting => "counting".into(),
ProofRung::Parity => "parity".into(),
ProofRung::ModCount { p } => format!("modcount-p{p}"),
ProofRung::Nullstellensatz { min_degree } => format!("nullstellensatz-d{min_degree}"),
ProofRung::BeyondBudget => "beyond-budget".into(),
}
}
fn degree_of_label(label: &str) -> Option<usize> {
match label {
"trivial" | "counting" => Some(0),
"parity" => Some(1),
"beyond-budget" => None,
l if l.starts_with("modcount-p") => Some(1),
l => l.strip_prefix("nullstellensatz-d").and_then(|d| d.parse().ok()),
}
}
#[derive(Clone, Debug)]
pub struct StructureAccounting {
pub n: usize,
pub orbits: usize,
pub covered_by_degree: Vec<usize>,
pub structureless: usize,
}
pub fn structure_accounting(n: usize) -> StructureAccounting {
let mut by_rung: BTreeMap<String, usize> = BTreeMap::new();
let mut orbits = 0usize;
for cover in minimal_cover_orbits(n) {
orbits += 1;
*by_rung.entry(rung_label(&weakest_crushing_rung(n, &cover.clauses(), n))).or_insert(0) += 1;
}
let mut covered_by_degree = vec![0usize; n + 1];
let mut structureless = 0usize;
for (label, &count) in &by_rung {
match degree_of_label(label) {
Some(d) => {
for slot in covered_by_degree.iter_mut().skip(d.min(n)) {
*slot += count;
}
}
None => structureless += count,
}
}
StructureAccounting { n, orbits, covered_by_degree, structureless }
}
#[derive(Clone, Debug)]
pub struct MenuSplit {
pub n: usize,
pub orbits: usize,
pub by_rung: BTreeMap<String, usize>,
pub distinct_signatures: usize,
pub largest_morph_class: usize,
}
pub fn menu_split(n: usize) -> MenuSplit {
let mut by_rung: BTreeMap<String, usize> = BTreeMap::new();
let mut sigs: BTreeMap<(String, String, usize, Vec<(usize, usize)>), usize> = BTreeMap::new();
let mut orbits = 0usize;
for cover in minimal_cover_orbits(n) {
orbits += 1;
let clauses = cover.clauses();
let label = rung_label(&weakest_crushing_rung(n, &clauses, n));
*by_rung.entry(label.clone()).or_insert(0) += 1;
let shadow = format!("{:?}", diagnose(n, &clauses).cut);
let width = min_resolution_width(&cover).unwrap_or(usize::MAX);
let fv: Vec<(usize, usize)> = face_vector(&cover).into_iter().collect();
*sigs.entry((label, shadow, width, fv)).or_insert(0) += 1;
}
MenuSplit {
n,
orbits,
by_rung,
distinct_signatures: sigs.len(),
largest_morph_class: sigs.values().copied().max().unwrap_or(0),
}
}
pub fn max_ns_degree_at(n: usize) -> usize {
minimal_cover_orbits(n)
.into_iter()
.filter_map(|cover| match weakest_crushing_rung(n, &cover.clauses(), n) {
ProofRung::Nullstellensatz { min_degree } => Some(min_degree),
_ => None,
})
.max()
.unwrap_or(0)
}
pub fn residue_map(n: usize) -> ResidueMap {
let records = census(n);
let mut m = ResidueMap {
n,
total: records.len(),
crushed: 0,
residue: 0,
targetable: 0,
rigid_core: 0,
core_max_ns_degree: 0,
};
for r in &records {
let fell_through = matches!(r.route, Route::Incompressible | Route::Cdcl);
if fell_through {
m.residue += 1;
if r.stabilizer_order == 1 {
m.rigid_core += 1;
}
if let ProofRung::Nullstellensatz { min_degree } = r.rung {
m.core_max_ns_degree = m.core_max_ns_degree.max(min_degree);
}
} else {
m.crushed += 1;
}
if r.symmetry_underbroken() {
m.targetable += 1;
}
}
m
}
pub fn census(n: usize) -> Vec<OrbitRecord> {
let gens = hyperoctahedral_generators(n);
let group = cube_group_closure(&gens, n);
let group_order = group.len();
minimal_cover_orbits(n)
.into_iter()
.map(|cover| {
let clauses = cover.clauses();
let (_, orbit_size) = canonical_cover(&cover, &gens);
let stabilizer: Vec<_> =
group.iter().filter(|g| g.is_automorphism(&cover)).cloned().collect();
let full_rule_orbits =
cover.blocker_orbits(&stabilizer).map(|o| o.len()).unwrap_or(clauses.len());
let rung = weakest_crushing_rung(n, &clauses, n);
let shadow = diagnose(n, &clauses).cut;
let solved = solve_structured(n, &clauses);
let affine_explained =
cover.to_expr().map(|e| crate::xorsat::refute_via_parity(&e)).unwrap_or(false);
OrbitRecord {
n,
num_clauses: clauses.len(),
orbit_size,
stabilizer_order: group_order / orbit_size,
face_vector: face_vector(&cover),
min_res_width: min_resolution_width(&cover).unwrap_or(usize::MAX),
rung,
shadow,
route: solved.via,
discovered_rule_orbits: cover.discovered_rule_symmetry().rule_orbits,
full_rule_orbits,
affine_explained,
modp_routed: matches!(solved.via, Route::ModP)
&& matches!(solved.answer, Answer::Unsat),
rep: cover,
}
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn residue_map_partitions_the_census_and_locates_the_wall() {
for n in 2..=3 {
let m = residue_map(n);
assert_eq!(m.crushed + m.residue, m.total, "crushed ⊎ residue = all orbits at n={n}");
assert!(m.crushed > 0, "structural specialists crush families at n={n}");
assert!(m.rigid_core <= m.residue, "rigid core ⊆ residue");
eprintln!(
"n={n}: total={} crushed={} residue={} targetable(symmetry-left)={} rigid_core={} core_ns_deg={}",
m.total, m.crushed, m.residue, m.targetable, m.rigid_core, m.core_max_ns_degree
);
}
}
#[test]
fn the_characteristic_rung_closes_the_router_ladder_audit_gap() {
let primes = [3u64, 5, 7];
let (mut gap_closed, mut modcount_seen) = (0usize, 0usize);
for n in 1..=3usize {
for rec in census(n) {
let ext = extended_rung(&rec, &primes);
match ext {
ProofRung::ModCount { p } => {
modcount_seen += 1;
let clauses = rec.rep.clauses();
let r = crate::modp::recover_from_cnf(n, &clauses)
.expect("a ModCount placement implies a recognized one-hot encoding");
assert_eq!(r.modulus, p, "the rung names the recovered modulus");
match crate::modp::solve(&r.equations, r.num_vars, p) {
crate::modp::ModpOutcome::Unsat(combo) => assert!(
crate::modp::is_refutation(&r.equations, r.num_vars, p, &combo),
"n={n}: the ModCount placement re-checks independently"
),
crate::modp::ModpOutcome::Sat(_) => {
panic!("n={n}: a ModCount placement must be refutable")
}
}
}
_ => assert_eq!(
ext, rec.rung,
"n={n}: off the ModCount population the ladders place identically"
),
}
if rec.modp_routed && rec.router_beats_ladder() {
assert!(
matches!(ext, ProofRung::ModCount { .. }),
"n={n}: the audit-gap orbit lands on the characteristic rung"
);
gap_closed += 1;
}
}
}
eprintln!(
"census n ≤ 3: {gap_closed} audit-gap orbits closed, {modcount_seen} ModCount placements"
);
}
#[test]
fn degree_growth_curve_and_covering_class_counts() {
for n in 1..=3 {
let classes = crate::hypercube::minimal_cover_orbits(n).len();
eprintln!("n={n}: covering_classes(orbits)={classes} max_ns_degree={}", max_ns_degree_at(n));
}
let (c2, c3) = (crate::hypercube::minimal_cover_orbits(2).len(), crate::hypercube::minimal_cover_orbits(3).len());
assert!(c3 > c2, "the number of covering classes grows with n: {c2} → {c3}");
assert!(max_ns_degree_at(3) > max_ns_degree_at(2), "the NS-degree wall climbs n=2 → n=3");
}
#[test]
fn lens_menu_split_and_morph_clustering() {
for n in 2..=3 {
let m = menu_split(n);
eprintln!(
"n={n}: orbits={} distinct_signatures={} largest_morph_class={} by_rung={:?}",
m.orbits, m.distinct_signatures, m.largest_morph_class, m.by_rung
);
assert_eq!(m.by_rung.values().sum::<usize>(), m.orbits, "the lens menu covers every orbit");
assert!(m.distinct_signatures <= m.orbits, "signatures ≤ orbits");
}
assert!(menu_split(3).distinct_signatures < menu_split(3).orbits, "orbits are morphs of fewer types");
}
#[test]
fn clause_agl_detector_probes_the_generic_cores_for_hidden_affine_symmetry() {
let full = "nullstellensatz-d3".to_string();
let (mut parity_checked, mut hidden, mut affine_rigid) = (false, 0usize, 0usize);
for cover in minimal_cover_orbits(3) {
let clauses = cover.clauses();
let label = rung_label(&weakest_crushing_rung(3, &clauses, 3));
let agl = clause_agl_symmetries(3, &clauses);
assert!(agl >= 1, "the identity is always an AGL automorphism");
if label == "parity" {
assert!(agl > 1, "the detector finds the parity family's affine symmetry");
parity_checked = true;
}
if label == full {
if agl > 1 {
hidden += 1; } else {
affine_rigid += 1; }
}
}
assert!(parity_checked, "validated the detector on the symmetric parity family");
eprintln!("n=3 generic cores: hidden_affine_symmetry={hidden} affine_rigid={affine_rigid}");
}
#[test]
#[ignore = "n=4 sampled clause-AGL: AGL(4,2)=322560 per core, minutes"]
fn clause_agl_at_n4_sampled_does_hidden_affine_symmetry_persist() {
let full = "nullstellensatz-d4".to_string();
let (mut hidden, mut rigid, mut sampled) = (0usize, 0usize, 0usize);
for cover in minimal_cover_orbits(4) {
if sampled >= 40 {
break;
}
let clauses = cover.clauses();
if rung_label(&weakest_crushing_rung(4, &clauses, 4)) != full {
continue;
}
sampled += 1;
if clause_agl_symmetries(4, &clauses) > 1 {
hidden += 1;
} else {
rigid += 1;
}
}
eprintln!("n=4 generic cores (sampled {sampled}): hidden_affine={hidden} affine_rigid={rigid}");
}
#[test]
fn peek_inside_the_generic_full_degree_cores() {
let sub = generic_subfamilies(3);
eprintln!("n=3 generic sub-families (shadow, width) → distinct types: {sub:?}");
let generic_types: usize = sub.values().sum();
assert!(generic_types > 0, "there are generic full-degree types at n=3");
assert!(!sub.is_empty(), "they sub-classify by (shadow, width) — sub-structure exists");
assert_eq!(structure_accounting(3).structureless, 0, "no core has literally zero structure");
}
#[test]
fn label_every_structural_type_by_family() {
let (num_types, by_family) = family_of_types(3);
eprintln!("n=3: {num_types} types → {by_family:?}");
eprintln!("n=3 giants: {:?}", named_giants(3, 5));
assert_eq!(num_types, by_family.values().sum::<usize>(), "every type is labeled by exactly one family");
assert!(num_types > 1, "multiple structural types at n=3");
assert!(named_giants(3, 3).iter().all(|(_, label)| !label.is_empty()), "every giant named");
}
#[test]
#[ignore = "n=4: label all 403 types, ~minutes"]
fn label_all_403_types_at_n4() {
let (num_types, by_family) = family_of_types(4);
eprintln!("n=4: {num_types} types → {by_family:?}");
eprintln!("n=4 giants: {:?}", named_giants(4, 8));
}
#[test]
fn family_growth_is_forced_by_the_degree_wall() {
let growth = family_growth(3);
for (n, count, new) in &growth {
eprintln!("n={n}: family_count={count} new_families={new:?}");
}
assert!(growth[2].1 > growth[0].1, "more families at n=3 than n=1");
assert!(growth[2].2.iter().any(|f| f == "algebraic-d3"), "n=3 forces the algebraic-d3 family");
}
#[test]
fn family_census_classifies_every_orbit_across_n() {
for n in 1..=3 {
let fam = family_census(n);
let total: usize = fam.values().sum();
eprintln!("n={n}: {fam:?}");
assert!(!fam.contains_key("unclassified"), "no unclassified orbit at n={n}");
assert_eq!(total, crate::hypercube::minimal_cover_orbits(n).len(), "the family census covers all orbits");
}
assert!(family_census(3).keys().any(|k| k == "algebraic-d3"), "n=3 opens the algebraic-d3 family");
assert!(!family_census(2).keys().any(|k| k == "algebraic-d3"), "which n=2 does not have");
}
#[test]
fn structure_accounting_no_finite_randomness_but_cheap_structure_runs_out() {
for n in 1..=3 {
let a = structure_accounting(n);
eprintln!(
"n={n}: orbits={} structureless={} covered_by_degree={:?}",
a.orbits, a.structureless, a.covered_by_degree
);
assert_eq!(a.structureless, 0, "no truly-structureless family at n={n} (degree ≤ n always suffices)");
assert_eq!(*a.covered_by_degree.last().unwrap(), a.orbits, "degree ≤ n covers ALL orbits");
assert!(a.covered_by_degree.windows(2).all(|w| w[0] <= w[1]), "coverage grows with the degree dial");
}
let a3 = structure_accounting(3);
assert!(a3.covered_by_degree[2] < a3.orbits, "at n=3 a degree-2 lens already misses families (need d=3)");
}
#[test]
fn parametric_witnesses_realize_the_cheap_rungs_for_all_n() {
for n in 1..=6 {
let (nv, cl) = witness_unit_propagation(n);
assert!(matches!(weakest_crushing_rung(nv, &cl, nv), ProofRung::Trivial), "unit-prop realized @ n={n}");
}
for n in 3..=6 {
let (nv, cl) = witness_parity(n);
assert!(matches!(weakest_crushing_rung(nv, &cl, nv), ProofRung::Parity), "parity realized @ n={n}");
}
for pigeons in 3..=4 {
let (nv, cl) = witness_counting(pigeons);
assert!(
matches!(weakest_crushing_rung(nv, &cl, nv), ProofRung::Counting),
"counting realized (PHP {pigeons} pigeons, {nv} vars)"
);
}
}
#[test]
fn the_realization_frontier_certifies_which_tower_rungs_occur() {
for n in 2..=3 {
let realized = realized_tower_families(n);
let tower: std::collections::BTreeSet<String> = family_tower(n).into_iter().collect();
eprintln!("n={n}: realized families = {:?}", realized.keys().collect::<Vec<_>>());
for (fam, clauses) in &realized {
assert!(tower.contains(fam), "n={n}: realized family {fam} lies in the tower");
assert!(crate::polycalc::build_ns_certificate(n, clauses).is_ok(), "n={n}: witness for {fam} is UNSAT");
}
}
for d in 2..=3usize {
let witness = realized_tower_families(d)
.remove(&format!("algebraic-d{d}"))
.unwrap_or_else(|| panic!("algebraic-d{d} must be realized at n={d}"));
assert!(crate::polycalc::nullstellensatz_refutes(d, &witness, d), "algebraic-d{d}: refuted at degree {d}");
assert!(
!crate::polycalc::nullstellensatz_refutes(d, &witness, d - 1),
"algebraic-d{d}: NOT refuted at degree {} — minimum degree is exactly {d}",
d - 1
);
}
}
#[test]
#[ignore = "n=4 census scan for the algebraic-d4 witness, minutes"]
fn algebraic_d4_rung_is_realized_with_exact_minimum_degree() {
let witness = realized_tower_families(4)
.remove("algebraic-d4")
.expect("the algebraic-d4 rung must be realized at n=4");
assert!(crate::polycalc::nullstellensatz_refutes(4, &witness, 4), "algebraic-d4: refuted at degree 4");
assert!(
!crate::polycalc::nullstellensatz_refutes(4, &witness, 3),
"algebraic-d4: NOT refuted at degree 3 — minimum degree is exactly 4"
);
}
#[test]
fn agl_collapse_factor_at_small_n_and_the_transvection_walk_is_tight() {
for n in 1..=3 {
let ex = agl_collapse_exact(n);
eprintln!(
"n={n}: Bₙ-orbits={} → AGL-classes={} (collapse ×{:.2})",
ex.bn_orbits, ex.agl_classes, ex.factor()
);
assert!(ex.agl_classes <= ex.bn_orbits, "n={n}: AGL can only merge classes, never split");
assert!(ex.agl_classes >= 1, "n={n}: at least one class");
}
let e3 = agl_collapse_exact(3);
assert!(e3.agl_classes < e3.bn_orbits, "AGL strictly collapses the n=3 census (43 → fewer)");
let w3 = agl_collapse_via_transvections(3);
assert!(w3.agl_classes >= e3.agl_classes, "the walk over-counts classes (a lower bound on collapse)");
assert_eq!(w3.agl_classes, e3.agl_classes, "the transvection walk is TIGHT at n=3 (matches exact AGL)");
}
#[test]
fn agl_merges_are_auto_discovered_and_codified_as_verified_affine_witnesses() {
let reps: Vec<Vec<u64>> =
minimal_cover_orbits(3).into_iter().map(|c| blocker_masks(&c.clauses(), 3)).collect();
let tables: Vec<Vec<u32>> = all_affine_bijections(3).iter().map(|p| perm_table(p, 3)).collect();
let canon: Vec<Vec<u64>> = reps.iter().map(|m| canonical_over_tables(m, &tables)).collect();
let mut merges = 0usize;
for i in 0..reps.len() {
for j in (i + 1)..reps.len() {
let same_class = canon[i] == canon[j];
match find_agl_witness(&reps[i], &reps[j], 3) {
Some(w) => {
assert!(same_class, "an affine witness exists only between affine-equivalent orbits");
assert!(w.verify(&reps[i], &reps[j], 3), "the auto-discovered affine witness must re-check");
merges += 1;
}
None => assert!(!same_class, "affine-distinct orbits must have NO affine witness"),
}
}
}
assert!(merges > 0, "the 43→38 collapse yields real affine equivalences to codify");
}
#[test]
#[ignore = "n=4 AGL collapse: 42263 orbits × 12 transvections × Bₙ-canon(384), minutes"]
fn agl_collapse_factor_at_n4() {
let w = agl_collapse_via_transvections(4);
eprintln!(
"n=4: Bₙ-orbits={} → AGL-classes={} (collapse ×{:.2})",
w.bn_orbits, w.agl_classes, w.factor()
);
}
#[test]
fn transvection_symbolic_image_matches_the_pointset_computation() {
let mut s = 0x9E37_79B9_7F4A_7C15u64;
let mut rng = || {
s ^= s << 13;
s ^= s >> 7;
s ^= s << 17;
s
};
let key = |o: &Option<Vec<Lit>>| {
o.as_ref().map(|cl| {
let mut k: Vec<(u32, bool)> = cl.iter().map(|l| (l.var(), l.is_positive())).collect();
k.sort_unstable();
k
})
};
for _ in 0..500 {
let n = 3 + (rng() % 4) as usize; let width = 1 + (rng() % n as u64) as usize;
let mut seen = std::collections::HashSet::new();
let mut c: Vec<Lit> = Vec::new();
while c.len() < width {
let v = (rng() % n as u64) as u32;
if seen.insert(v) {
c.push(Lit::new(v, rng() & 1 == 0));
}
}
let a = (rng() % n as u64) as u32;
let mut b = (rng() % n as u64) as u32;
while b == a {
b = (rng() % n as u64) as u32;
}
let sym = transvection_image_clause(&c, a, b);
let tau = Affine {
n,
matrix: {
let mut m: Vec<u64> = (0..n).map(|k| 1u64 << k).collect();
m[a as usize] |= 1u64 << b;
m
},
translation: 0,
};
let point_based = pointset_to_clause(map_point_set(falsify_set(&c, n), &tau, n), n);
assert_eq!(key(&sym), key(&point_based), "symbolic transvection image ≠ point-based for {c:?}, σ({a}↦{a}⊕{b})");
}
}
#[test]
fn the_affine_transvection_finder_scales_to_large_n() {
let n = 60usize;
let clauses: Vec<Vec<Lit>> =
(2..n as u32).map(|v| vec![Lit::pos(0), Lit::pos(1), Lit::pos(v)]).collect();
let gens = affine_transvection_generators(n, &clauses);
assert!(gens.contains(&(0, 1)), "the finder recovers σ(0↦0⊕1) at n={n}");
assert!(gens.contains(&(1, 0)), "and its partner σ(1↦1⊕0)");
assert!(!gens.contains(&(0, 2)), "σ(0↦0⊕2) is not a symmetry (x2 is absent from most clauses)");
}
#[test]
fn rank1_symbolic_image_matches_the_pointset_computation() {
let mut s = 0xD1B5_4A32_D192_ED03u64;
let mut rng = || {
s ^= s << 13;
s ^= s >> 7;
s ^= s << 17;
s
};
let key = |o: &Option<Vec<Lit>>| {
o.as_ref().map(|cl| {
let mut k: Vec<(u32, bool)> = cl.iter().map(|l| (l.var(), l.is_positive())).collect();
k.sort_unstable();
k
})
};
let mut bijective_seen = 0;
for _ in 0..800 {
let n = 3 + (rng() % 4) as usize; let mask = (1u64 << n) - 1;
let u = rng() & mask;
let v = rng() & mask;
if (u & v).count_ones() % 2 != 0 {
continue; }
bijective_seen += 1;
let width = 1 + (rng() % n as u64) as usize;
let mut seen = std::collections::HashSet::new();
let mut c: Vec<Lit> = Vec::new();
while c.len() < width {
let var = (rng() % n as u64) as u32;
if seen.insert(var) {
c.push(Lit::new(var, rng() & 1 == 0));
}
}
let sym = rank1_image_clause(&c, u, v);
let matrix: Vec<u64> =
(0..n).map(|a| (1u64 << a) ^ (if (u >> a) & 1 == 1 { v } else { 0 })).collect();
let tau = Affine { n, matrix, translation: 0 };
let point_based = pointset_to_clause(map_point_set(falsify_set(&c, n), &tau, n), n);
assert_eq!(key(&sym), key(&point_based), "rank-1 image ≠ point-based for {c:?}, u={u:#b}, v={v:#b}");
}
assert!(bijective_seen > 200, "exercised enough bijective (u·v=0) cases: {bijective_seen}");
}
#[test]
fn the_parity_wall_is_a_depth_not_a_wall_composite_finder_catches_it() {
let n = 4usize;
let clauses: Vec<Vec<Lit>> = (0u32..(1 << n))
.filter(|p| p.count_ones() % 2 == 1)
.map(|p| {
(0..n as u32)
.map(|i| if (p >> i) & 1 == 1 { Lit::neg(i) } else { Lit::pos(i) })
.collect()
})
.collect();
assert_eq!(clauses.len(), 8, "half of the 16 points (the odd-parity ones) are forbidden");
let depth1 = affine_transvection_generators(n, &clauses);
assert!(depth1.is_empty(), "single transvections cannot preserve parity — the depth-1 horizon");
let depth2 = affine_composite_shear_generators(n, &clauses, 2);
assert!(!depth2.is_empty(), "depth-2 composite shears preserve parity — the wall was a horizon");
assert!(
depth2.iter().all(|(s, _)| s.len() == 2),
"every parity generator is genuinely composite (needs two targets, never one)"
);
assert!(
depth2.iter().any(|(s, j)| *j == 2 && s.contains(&0) && s.contains(&1)),
"the shear (add x2 to {{x0,x1}}) is found"
);
eprintln!("parity(n={n}): depth-1 finds {} shears, depth-2 finds {}", depth1.len(), depth2.len());
}
#[test]
fn symplectic_transvection_weight_cannot_grade_ns_degree() {
use crate::polycalc::nullstellensatz_refutes;
for (m, deg) in [(3usize, 4usize), (4, 6)] {
let (php, _) = crate::families::php(m);
let nv = php.num_vars;
let gens = symplectic_transvection_generators(nv, &php.clauses, nv.min(6));
assert!(gens.is_empty(), "PHP({m}) is symplectic-rigid — no rank-1 linear involution symmetry");
assert!(nullstellensatz_refutes(nv, &php.clauses, deg), "PHP({m}) NS degree reaches {deg}");
assert!(!nullstellensatz_refutes(nv, &php.clauses, deg - 1), "…and is exactly {deg}, growing with m");
}
for w in [4usize, 6] {
let vars: Vec<u32> = (0..w as u32).collect();
let clauses: Vec<Vec<Lit>> = (0u32..(1 << w))
.filter(|p| p.count_ones() % 2 == 1)
.map(|p| (0..w).map(|i| Lit::new(vars[i], (p >> i) & 1 == 0)).collect())
.collect();
let min_weight = symplectic_transvection_generators(w, &clauses, w)
.iter()
.map(|g| g.count_ones() as usize)
.min();
assert_eq!(min_weight, Some(2), "parity_block({w}): minimal symplectic weight is a constant 2");
}
}
#[test]
fn family_is_agl_invariant_so_the_affine_lens_preserves_structure() {
let mut checked = 0usize;
let mut beyond_bn = 0usize; for cover in minimal_cover_orbits(3) {
let f = cover.clauses();
let fam_f = family_name(&weakest_crushing_rung(3, &f, 3));
for phi in all_affine_bijections(3) {
if let Some(g) = agl_image_formula(&f, &phi, 3) {
let fam_g = family_name(&weakest_crushing_rung(3, &g, 3));
assert_eq!(fam_f, fam_g, "the family must be invariant under an affine coordinate change");
checked += 1;
if phi.matrix.iter().any(|r| r.count_ones() >= 2) {
beyond_bn += 1;
}
}
}
}
assert!(checked > 43, "invariance exercised across every orbit and its affine images");
assert!(beyond_bn > 0, "AGL reaches valid CNF images via shears the permutation lens cannot");
}
#[test]
fn the_family_tower_is_provably_complete_and_finite_without_enumeration() {
for n in 1..=6 {
let tower = family_tower(n);
assert_eq!(tower.len(), 3 + n.saturating_sub(1), "n={n}: tower = 3 cheap families + algebraic d=2..=n");
}
for n in 2..=3 {
let tower: std::collections::BTreeSet<String> = family_tower(n).into_iter().collect();
for cover in minimal_cover_orbits(n) {
let clauses = cover.clauses();
let rung = weakest_crushing_rung(n, &clauses, n);
assert!(!matches!(rung, ProofRung::BeyondBudget), "n={n}: completeness ⟹ no beyond-budget family");
assert!(tower.contains(&family_name(&rung)), "n={n}: every orbit's family lies in the parametric tower");
let cert = crate::polycalc::build_ns_certificate(n, &clauses).expect("UNSAT ⟹ a certificate");
assert!(cert.verify(&clauses), "the constructive certificate witnesses the orbit's tower membership");
}
}
for n in 1..=3 {
let tower: std::collections::BTreeSet<String> = family_tower(n).into_iter().collect();
assert!(family_census(n).keys().all(|k| tower.contains(k)), "n={n}: enumerated families ⊆ the tower");
}
}
#[test]
fn the_coverage_verdict_no_random_family_theta_n_families_but_no_fixed_cost_lens() {
for n in 1..=3 {
assert_eq!(structure_accounting(n).structureless, 0, "no genuinely-random family at n={n}");
}
for n in 1..=6 {
assert_eq!(family_tower(n).len(), 3 + n.saturating_sub(1), "n={n}: Θ(n) families, not 2ⁿ");
}
for d in 1..=2usize {
let n = d + 1;
let witness = realized_tower_families(n)
.remove(&format!("algebraic-d{n}"))
.unwrap_or_else(|| panic!("a full-degree family exists at n={n}"));
assert!(
!crate::polycalc::nullstellensatz_refutes(n, &witness, d),
"a degree-{d} lens MISSES a family at n={n} — no fixed-cost lens is complete"
);
}
assert!(crate::polycalc::nullstellensatz_basis_size(10, 2) < 10u128.pow(3), "fixed-degree check is polynomial");
assert_eq!(crate::polycalc::nullstellensatz_basis_size(10, 10), 1u128 << 10, "full degree is 2ⁿ");
}
#[test]
fn every_census_cover_carries_a_constructive_certificate_that_generalizes_past_the_wall() {
for cover in minimal_cover_orbits(3) {
let clauses = cover.clauses();
let cert = crate::polycalc::build_ns_certificate(3, &clauses)
.expect("a minimal-UNSAT cover is unsatisfiable, so the construction yields a certificate");
assert!(cert.verify(&clauses), "the certificate re-checks against the cover's own clauses");
assert!(cert.degree() <= 3, "the certificate degree is ≤ n");
}
let n = 5;
let full: Vec<Vec<Lit>> = (0u64..(1u64 << n))
.map(|a| (0..n as u32).map(|v| Lit::new(v, (a >> v) & 1 == 0)).collect())
.collect();
let cert = crate::polycalc::build_ns_certificate(n, &full).expect("the all-corners-forbidden cover is UNSAT");
assert!(cert.verify(&full), "the n=5 certificate re-checks — structureless=0 proven past the census wall");
assert!(cert.degree() <= n, "the n=5 certificate degree is ≤ n");
}
#[test]
#[ignore = "n=4 lean menu split: 42263 orbits × (rung+shadow+width+face-vector), minutes"]
fn lens_menu_split_at_n4() {
let m = menu_split(4);
eprintln!(
"n=4: orbits={} distinct_signatures={} largest_morph_class={} by_rung={:?}",
m.orbits, m.distinct_signatures, m.largest_morph_class, m.by_rung
);
}
#[test]
#[ignore = "n=4 lean degree pass: 42263-orbit enumeration + certified rungs, minutes"]
fn degree_growth_at_n4() {
eprintln!(
"n=4: covering_classes={} max_ns_degree={}",
crate::hypercube::minimal_cover_orbits(4).len(),
max_ns_degree_at(4)
);
}
#[test]
#[ignore = "census-scale: 42263 orbits, minutes"]
fn residue_map_at_census_scale_n4() {
let m = residue_map(4);
assert_eq!(m.crushed + m.residue, m.total, "the partition is exhaustive at census scale");
eprintln!(
"n=4: total={} crushed={} residue={} targetable(symmetry-left)={} rigid_core={} core_ns_deg={}",
m.total, m.crushed, m.residue, m.targetable, m.rigid_core, m.core_max_ns_degree
);
}
}