Class v6 census: the era-aware F8-form uniformity tool (v6census-uniform)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Documents-only replay of 14c550e38 (cfd0b1db936c45275e33697c5b283eb12b25a424) for the box mirror master
This commit is contained in:
igneum-labs 2026-10-08 12:34:41 +00:00
parent 082042e6e1
commit 2df3aedafe
2 changed files with 132 additions and 0 deletions

View file

@ -0,0 +1,15 @@
[package]
name = "v6census-uniform"
version = "0.1.0"
edition = "2021"
publish = false
[[bin]]
name = "v6census-uniform"
path = "src/main.rs"
[dependencies]
igneum-pow = { path = "../../../../igneum-pow" }
[profile.release]
opt-level = 3

View file

@ -0,0 +1,117 @@
//! v6census-uniform (class v6 census lane, 8 October 2026): the F8-form uniformity read of the invention lane's tool
//! (`tools/attack/v6-invention/uniform`) with the era draw added, for the read-width and op-mix candidates. Per seed:
//! the first accepted candidate of the class under the harness (`IGNEUM_FAMILY_GATE`, the class's own attempt cap),
//! then over `nonces` nonces every load's word index through the library's own `trace_load_indices`; per site the
//! distinct-index ratio `d_s / E_s` with `E_s = N - N^2 / (2 W_s)` at the site's window over the width (the (c'')
//! form), and the cross-hash ITEM histogram's top 0.1 percent share against a uniform SplitMix64 control of the same
//! size (the F8 harness's null; under an era the narrow-window sites raise the share by design, so the line to read
//! is the candidate against the control class at the same era, not the no-era 1.2x alone). One TSV row per seed.
//!
//! v6census-uniform --class w64m8g+sh256x27 --seeds 16 --nonces 1048576 --threads 16 [--era igneum-era-test/3 --era-widths 64]
use igneum_pow::generator::{attempts_class_to, max_attempts_for, EraParams, LoadClass, ITERATIONS};
use igneum_pow::seed::{seed_words_from_bytes, SplitMix64};
use igneum_pow::verify::{trace_load_indices, window, DatasetMode, DatasetSource};
use std::collections::HashSet;
use std::io::Write;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
fn arg(args: &[String], k: &str, d: &str) -> String {
args.iter().position(|a| a == k).and_then(|i| args.get(i + 1).cloned()).unwrap_or_else(|| d.to_string())
}
fn top_share(counts: &mut Vec<u32>, frac: f64) -> (f64, u32) {
let total: u64 = counts.iter().map(|&c| c as u64).sum();
counts.sort_unstable_by(|a, b| b.cmp(a));
let k = ((counts.len() as f64) * frac) as usize;
let top: u64 = counts[..k].iter().map(|&c| c as u64).sum();
(top as f64 / total as f64, counts[0])
}
fn parse_widths(s: &str) -> Vec<u8> {
let mut v: Vec<u8> = s.split(',').map(|x| match x.trim() { "4" => 1u8, "16" => 4, "64" => 16, _ => panic!("width") }).collect();
v.sort_unstable();
v
}
fn main() {
let args: Vec<String> = std::env::args().collect();
let class_name = arg(&args, "--class", "mx8+sh256x27");
let seeds: u32 = arg(&args, "--seeds", "16").parse().unwrap();
let nonces: u32 = arg(&args, "--nonces", "1048576").parse().unwrap();
let threads: usize = arg(&args, "--threads", "16").parse().unwrap();
let log2: u32 = arg(&args, "--log2", "28").parse().unwrap();
let day = arg(&args, "--day", "2026-10-03");
let prefix = arg(&args, "--prefix", "igneum-v6c");
let era = arg(&args, "--era", "none");
let widths = parse_widths(&arg(&args, "--era-widths", "4"));
let mut class = LoadClass::parse(&class_name).expect("class");
if era != "none" {
assert!(era.starts_with("igneum-era-test/"), "era: igneum-era-test/<n>");
class = LoadClass::era(class, &EraParams::test_era_bytes(&era), &widths);
}
let cap = max_attempts_for(&class);
let ds = DatasetSource::new(&day, DatasetMode::ClosedForm, log2);
let items = 1usize << (log2 - 4);
let mask = (1u32 << log2) - 1;
let n = (nonces as f64) * (ITERATIONS as f64); // evaluations per site
let next = AtomicUsize::new(0);
let out = Mutex::new(std::io::stdout());
println!("class\tera\tseed\tattempt\tprogram_id\tmin_site_ratio\tmin_site\ttop0.1_share\tcontrol_share\tratio_to_control\tmax_item_reads\tcontrol_max\treads");
std::thread::scope(|s| {
for _ in 0..threads {
s.spawn(|| loop {
let i = next.fetch_add(1, Ordering::Relaxed) as u32;
if i >= seeds {
break;
}
let label = format!("{prefix}/{i}");
let tries = attempts_class_to(&label, label.as_bytes(), class, cap);
let Some((p, _)) = tries.into_iter().find(|(_, r)| r.is_ok()) else {
let mut o = out.lock().unwrap();
writeln!(o, "{class_name}\t{era}\t{i}\texhausted").unwrap();
continue;
};
let seed = seed_words_from_bytes(label.as_bytes());
let loads: Vec<_> = p.instrs.iter().filter(|x| x.op.is_load()).cloned().collect();
let sites = loads.len();
let mut distinct: Vec<HashSet<u32>> = (0..sites).map(|_| HashSet::with_capacity(nonces as usize)).collect();
let mut counts = vec![0u32; items];
let mut reads: u64 = 0;
let mut base = 0u32;
while base < nonces {
let rows = trace_load_indices(&p, &seed, base, &ds);
for (k, row) in rows.iter().enumerate() {
let site = k % sites;
for &idx in row.iter() {
distinct[site].insert(idx);
counts[(idx >> 4) as usize] += 1;
reads += 1;
}
}
base += 32;
}
let (min_ratio, min_site) = distinct
.iter()
.enumerate()
.map(|(s, d)| {
let ins = &loads[s];
let w = if p.class.era.is_some() { (window(ins, mask, log2).0 as u64 + 1) as f64 } else { (1u64 << log2) as f64 } / (ins.width.max(1) as f64);
let e_s = n - n * n / (2.0 * w);
(d.len() as f64 / e_s, s)
})
.fold((f64::MAX, 0usize), |a, b| if b.0 < a.0 { b } else { a });
let (share, max_reads) = top_share(&mut counts, 0.001);
let mut ctrl = vec![0u32; items];
let mut rng = SplitMix64::new(0x9e37_79b9_7f4a_7c15 ^ i as u64);
for _ in 0..reads {
let x = rng.next() as usize & (items - 1);
ctrl[x] += 1;
}
let (cshare, cmax) = top_share(&mut ctrl, 0.001);
let mut o = out.lock().unwrap();
writeln!(o, "{class_name}\t{era}\t{i}\t{}\t{:016x}\t{min_ratio:.5}\t{min_site}\t{share:.6}\t{cshare:.6}\t{:.4}\t{max_reads}\t{cmax}\t{reads}", p.attempt, p.program_id(), share / cshare).unwrap();
});
}
});
}