adv-accept: attempts command (row 90: per-part rejections, cap, last resort, forced-exhaust plant)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
ff81c2dea1
commit
67d40c9b97
1 changed files with 125 additions and 0 deletions
|
|
@ -328,6 +328,7 @@ fn main() {
|
|||
"sweep" => sweep(&args[2..]),
|
||||
"plant" => plant(&args[2..]),
|
||||
"gap" => gap_cmd(&args[2..]),
|
||||
"attempts" => attempts_cmd(&args[2..]),
|
||||
_ => {
|
||||
eprintln!("unknown command {}", args[1]);
|
||||
std::process::exit(2);
|
||||
|
|
@ -582,3 +583,127 @@ fn gap_cmd(args: &[String]) {
|
|||
gap::run(&p, day, threads, zero);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------
|
||||
// Row 90 (owner adv-accept-3, unspawned; claimed by this lane): the attempt loop walked through the real rule,
|
||||
// attempt by attempt, recording WHICH part rejected each candidate (the first failing test in the module's
|
||||
// order), the attempt count of the accepted program, any seed reaching the 256 cap, and the last-resort program.
|
||||
// The draw and every verdict are the library's (candidate_class, accept::check, last_resort_v4).
|
||||
// Known-failed shape: `--force-exhaust` treats every verdict as a rejection, so the loop MUST hit the cap and
|
||||
// print the last-resort program's shape (what a rule that rejects everything would hand the chain).
|
||||
// --------------------------------------------------------------------------------------------------------------
|
||||
|
||||
fn attempts_cmd(args: &[String]) {
|
||||
use igneum_pow::generator::{candidate_class, last_resort_v4, LoadClass, GENERATOR_VERSION_V4, MAX_ATTEMPTS_V4};
|
||||
let get = |k: &str, d: &str| -> String { args.windows(2).find(|w| w[0] == k).map(|w| w[1].clone()).unwrap_or_else(|| d.to_string()) };
|
||||
let seed_start: u64 = get("--seed-start", "2").parse().unwrap();
|
||||
let seeds: u64 = get("--seeds", "1000").parse().unwrap();
|
||||
let threads: usize = get("--threads", "32").parse().unwrap();
|
||||
let force_exhaust = args.iter().any(|a| a == "--force-exhaust");
|
||||
let out = get("--out", "");
|
||||
println!("adv-accept attempts: seeds {seed_start}..{} ({seeds}), {threads} threads, cap {MAX_ATTEMPTS_V4}, force-exhaust {force_exhaust}", seed_start + seeds);
|
||||
let t0 = Instant::now();
|
||||
let next = AtomicUsize::new(0);
|
||||
// per attempt index (0..=MAX): counts of each reject class; the accepted attempt histogram; exhaustions
|
||||
const CLASSES: usize = 11;
|
||||
fn class_of(r: &Reject) -> usize {
|
||||
match r {
|
||||
Reject::StaleLoadSource { .. } => 0,
|
||||
Reject::NoInjectingWrite { .. } => 1,
|
||||
Reject::UnfreshLoadSource { .. } => 2,
|
||||
Reject::ConstantBit { .. } => 3,
|
||||
Reject::LaneConstantSite { .. } => 4,
|
||||
Reject::Saturated { .. } => 5,
|
||||
Reject::SaturatedSource { .. } => 6,
|
||||
Reject::RepeatedSource { .. } => 7,
|
||||
Reject::LowEntropySite { .. } => 8,
|
||||
Reject::OutputBias { .. } => 9,
|
||||
Reject::DistinctAddresses { .. } => 10,
|
||||
}
|
||||
}
|
||||
const NAMES: [&str; CLASSES] = ["(a) stale", "(b) no-inject", "(a') unfresh", "(c) const-bit", "(c) lane-const", "(c) saturated", "(c') sat-source", "(c'') repeated", "(c'') low-entropy", "(c) bias", "(c) distinct"];
|
||||
let parts: Vec<(Vec<[u64; CLASSES]>, Vec<u64>, u64, Vec<String>, Vec<(u64, u32, u64, f64)>)> = std::thread::scope(|sc| {
|
||||
let mut hs = Vec::new();
|
||||
for _ in 0..threads {
|
||||
let next = &next;
|
||||
hs.push(sc.spawn(move || {
|
||||
let mut by_attempt = vec![[0u64; CLASSES]; MAX_ATTEMPTS_V4 as usize + 1];
|
||||
let mut accepted_at = vec![0u64; MAX_ATTEMPTS_V4 as usize + 1];
|
||||
let mut exhausted = 0u64;
|
||||
let mut notes = Vec::new();
|
||||
let mut rows = Vec::new();
|
||||
loop {
|
||||
let i = next.fetch_add(1, Ordering::Relaxed) as u64;
|
||||
if i >= seeds { break; }
|
||||
let k = seed_start + i;
|
||||
let epoch = seed_bytes("epoch", k);
|
||||
let era = seed_bytes("era", k);
|
||||
let class = LoadClass::era(V4_CLASS, &era, &V3_ALLOWED);
|
||||
let label = format!("igneum-attack-f8/{k}");
|
||||
let mut done = false;
|
||||
let cap = if force_exhaust { 8 } else { MAX_ATTEMPTS_V4 }; // under the plant a short cap shows the path
|
||||
for a in 0..cap {
|
||||
let mut p = candidate_class(&label, &epoch, a, class);
|
||||
p.generator = GENERATOR_VERSION_V4;
|
||||
match check(&p) {
|
||||
Ok(r) if !force_exhaust => {
|
||||
accepted_at[a as usize] += 1;
|
||||
rows.push((k, a, p.program_id(), r.distinct_mean()));
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
Ok(_) => { by_attempt[a as usize][3] += 0; } // forced: counted as a rejection of no class
|
||||
Err(r) => { by_attempt[a as usize][class_of(&r)] += 1; }
|
||||
}
|
||||
}
|
||||
if !done {
|
||||
exhausted += 1;
|
||||
let mut lr = candidate_class(&label, &epoch, cap, class);
|
||||
lr.generator = GENERATOR_VERSION_V4;
|
||||
let lr = last_resort_v4(lr);
|
||||
let v = check(&lr);
|
||||
let (lossy_last, n_or, n_mul, n_mulhi, regs) = structure(&lr);
|
||||
notes.push(format!("seed {k}: EXHAUSTED at cap {cap}; last resort id {:016x} attempt {} op mix {} shadow mix {}; rule verdict on it {:?}; structure lossy_last {lossy_last} or {n_or} mul {n_mul} mulhi {n_mulhi} regs {regs}", lr.program_id(), lr.attempt, lr.op_mix(), lr.shadow_op_mix(), v.as_ref().map(|r| format!("accept distinct_mean {:.3} sat {} bias {}", r.distinct_mean(), r.saturated, r.bias_max)).map_err(|e| e.to_string())));
|
||||
}
|
||||
}
|
||||
(by_attempt, accepted_at, exhausted, notes, rows)
|
||||
}));
|
||||
}
|
||||
hs.into_iter().map(|h| h.join().unwrap()).collect()
|
||||
});
|
||||
let mut by_attempt = vec![[0u64; CLASSES]; MAX_ATTEMPTS_V4 as usize + 1];
|
||||
let mut accepted_at = vec![0u64; MAX_ATTEMPTS_V4 as usize + 1];
|
||||
let mut exhausted = 0u64;
|
||||
let mut rows = Vec::new();
|
||||
for (b, acc, ex, notes, r) in parts {
|
||||
for a in 0..b.len() { for c in 0..CLASSES { by_attempt[a][c] += b[a][c]; } accepted_at[a] += acc[a]; }
|
||||
exhausted += ex;
|
||||
for n in notes { println!("{n}"); }
|
||||
rows.extend(r);
|
||||
}
|
||||
let n = rows.len() as u64 + exhausted;
|
||||
let total_rej: [u64; CLASSES] = { let mut t = [0u64; CLASSES]; for a in &by_attempt { for c in 0..CLASSES { t[c] += a[c]; } } t };
|
||||
let rejections: u64 = total_rej.iter().sum();
|
||||
println!("attempts: {n} seeds in {:.0} s; {rejections} rejected candidates, {} accepted, {exhausted} exhausted (cap {})", t0.elapsed().as_secs_f64(), rows.len(), MAX_ATTEMPTS_V4);
|
||||
println!("rejection by part over all candidates: {}", NAMES.iter().zip(total_rej.iter()).map(|(nm, c)| format!("{nm}={c} ({:.1}%)", *c as f64 * 100.0 / rejections.max(1) as f64)).collect::<Vec<_>>().join(" "));
|
||||
let max_a = accepted_at.iter().rposition(|&c| c > 0).unwrap_or(0);
|
||||
println!("accepted-attempt histogram 0..{max_a}: {:?}", &accepted_at[..=max_a]);
|
||||
for a in 0..=max_a.min(3) {
|
||||
let tot: u64 = by_attempt[a].iter().sum::<u64>() + accepted_at[a];
|
||||
println!("attempt {a}: {tot} candidates, rejected {} ({:.1}%): {}", by_attempt[a].iter().sum::<u64>(), by_attempt[a].iter().sum::<u64>() as f64 * 100.0 / tot.max(1) as f64, NAMES.iter().zip(by_attempt[a].iter()).filter(|(_, c)| **c > 0).map(|(nm, c)| format!("{nm}={c}")).collect::<Vec<_>>().join(" "));
|
||||
}
|
||||
let mean_a = accepted_at.iter().enumerate().map(|(a, &c)| a as f64 * c as f64).sum::<f64>() / rows.len().max(1) as f64;
|
||||
let p_rej = rejections as f64 / (rejections + rows.len() as u64) as f64;
|
||||
println!("mean accepted attempt {mean_a:.3}; per-candidate rejection probability {p_rej:.4}; P(256 consecutive rejections) if independent = {:.3e}", p_rej.powi(256));
|
||||
if rows.len() > 0 {
|
||||
let dm: Vec<f64> = rows.iter().map(|r| r.3).collect();
|
||||
println!("closed-form distinct-item mean of accepted programs: mean {:.4} min {:.4}", dm.iter().sum::<f64>() / dm.len() as f64, dm.iter().cloned().fold(f64::MAX, f64::min));
|
||||
}
|
||||
if !out.is_empty() {
|
||||
let mut f = std::fs::File::create(&out).unwrap();
|
||||
writeln!(f, "# seed accepted_attempt program_id distinct_mean").unwrap();
|
||||
for (k, a, id, d) in &rows { writeln!(f, "{k} {a} {id:016x} {d:.5}").unwrap(); }
|
||||
println!("wrote {out}");
|
||||
}
|
||||
println!("attempts DONE");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue