class v5: AP-F4-1 in the agreed form (adder cost at most 205 against the median 226, w32 without the position-32 digit, a two-adder multiplier or one rotation amount rejected; known-failed first on chain day 29,337) and the verified last resort (part (a) repaired by re-sourcing stale loads, then the whole rule over a 256-candidate scan; known-failed first on adv-accept-3's adv3/steer/2)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
dba17a0a4f
commit
ea3a76e4c4
3 changed files with 167 additions and 23 deletions
|
|
@ -38,6 +38,7 @@
|
|||
| 21:03 | The (c''') census landed (section 14): 112 of 4,600 under 0.995 (2.435 percent), attempts mean +3.4 percent, 0 class v5 programs under the floor; the floor stays 0.995 (0.99 would pass the exemplar). The flip-stale harness PASSED on the matched fork and igneum-pow binaries at 21:03 UK (base 30700) once the stale miner's fall-off was judged by the block's DAA score: the 20:4x run had failed on one ACCEPTED line 4.7 s after the boundary's wall time that was a flip-epoch block found on a pre-boundary template, valid |
|
||||
| 21:4x | The five programs' ratios landed (section 14): the floor refuses 4346 and 5245 and every measured hot set by X_f >= f, misses the three milder shadow-block-write concentrations (0.9992 to 0.9997), Devnet 3's first program among them; the residual named with its instrument and bound. The full suite's run on the (c''') commit was stopped at 70 minutes: `class_v5_shadow_redundancy_rule`'s scan drew 6,000 seeds twice through the full draw (seconds per candidate under the 2^20 pass; the scan had never run to its loop before, the test having failed earlier at an assertion), rewritten over the candidate draw (45765de6); the suite re-queued |
|
||||
| 22:1x | FREEZE. The full igneum-pow suite green on the tree (box 2, 22:0x UK: 73 unit tests, 4 ignored census/bench, packs 20 incl. the pinned v5 packs unchanged, derive 7, mixer 4, recheck 2, scratch 7), the pre-push gate GREEN (58 checks). The shadow rule's trigger reading: 6,000 first draws read a maximum removable share of 11 permille against the 30 bound, 0 redraws (the earlier 4e-3 counted every rotate pair; the attack-pass lane's F1 census on 10^5 reads the chain rate). Pinned pack v5-dn3-epoch0 (e5a4ac5978462156, fingerprint 82b19cbde8557ea5) stands. Next commit, after the freeze: AP-F4-1 in the agreed form (cost A at most 205 against the median 226, w32 without the position-32 digit, a two-adder multiplier or one rotation amount rejected; the known-failed day 29,337), and class v5's verified last resort (adv-accept-3's finding: the sub-version 3 rewrite fails the rule on 223 of 2,500 seeds, 209 by part (a); class v5 repairs the stale loads and checks; known-failed first on adv3/steer/2) |
|
||||
| 22:2x | Post-freeze commit on top of 1c420786: AP-F4-1 in the agreed form (cost at most 205 against the median 226; day 29,337 the known-failed day) and class v5's verified last resort (adv3/steer/2 the known-failed seed); both move the stream only on days and seeds the chain never reaches; the pinned packs and the fingerprint stay |
|
||||
|
||||
## 1. The claim, in one paragraph
|
||||
|
||||
|
|
@ -284,6 +285,8 @@ Every item of this page that has no code, no test or no measurement yet, with th
|
|||
| The acceptance bound on a program's hot-set share (section 14, main's order 19:5x UK) | DONE: (c''') `MIN_DISTINCT_RATIO_V5 = 0.995` under the state flag (ab6f980b), known-failed first on seed 100767, the census read (21:03 UK): 2.435 percent of sub-version 3 accepted programs under the floor, attempts mean 2.174 to 2.248, 0 class v5 programs under it; the design reading of 0 clean rejections was wrong and the page says so | this lane | 0 |
|
||||
| The class walk under the v5 object (`class_signal.rs decide()`: epochs under the window resolve to v3 regardless of the v4 floor once v5 is enabled; the v5-fasttime lane's reading 20:0x UK) | OPEN, the node lane's: a known-failed test with v4 from genesis and the v5 object set must read v4 at epoch 0; this lane's harness gains the same case (v4 floor 0, v3 never) once the fork has the fix | node lane (fork), this lane (harness case) | 2 |
|
||||
| The shadow-block-write residual of section 14 (the three milder concentrations at 1.26x to 1.45x, Devnet 3's first program among them) | OPEN: a draw rule on the shadow block's last write to a load's source (mul, mulhi, sub of the same register), known-failed first on fce15bf61030be57's site 0, with its after-fraction census; not in tonight's object (the chip value is under the AP-F8-1 bound by two orders); adv-mixer-2's AP-F4-1 lever (redraw when the FPGA LUT cost is 205 or less, a 2-adder mul, or all rotations equal; about 22 days per 100 years redrawn) is the second independent statement of the same mechanism, its census owed on the class v5 generator | this lane | 3 |
|
||||
| AP-F4-1 in the agreed form (attack-pass lane and adv-mixer-2 reconciled, 22:0x UK) | DONE in the post-freeze commit: the rule is `A = 64 + sum(w32(MUL_i) - 1)` at most 205 rejects (the median 226; w32 over bit positions 0 to 31, the first census's position-32 carry digit dropped, 231 to 226), any MUL with w32 at most 3 rejects (k >= 1), the eight ROT all equal rejects; a rejected block is redrawn whole from the continuing stream. It replaces "NAF sum under 163 (cost under 211), four distinct rotations". Known-failed first on the day both censuses name, chain day 29,337 (2050-04-28, 1.113x). Tail: 5.69e-4 of days, 15 days a century; nothing to a chip or a GPU | this lane | 0 |
|
||||
| Class v5's verified last resort (adv-accept-3's finding aa359962: sub-version 3's `last_resort_v4` fails the rule on 223 of 2,500 seeds, 209 by part (a), and is handed to the chain unchecked; unreachable at 4.6e-44 per epoch) | DONE in the post-freeze commit: `last_resort_v5` = the rewrite, then `repair_stale_loads` (a stale load re-sourced to the lowest register written since its last load, walked to a fixpoint), then the whole rule, over a 256-candidate scan from the cap; the unchecked fallback past the scan sits under 1e-300. Known-failed first on adv3/steer/2 (`class_v5_last_resort_is_verified_known_failed_adv3_steer_2`). The record: sub-version 3's last resort is unreachable and unverified (the hash lane's AP-F8-1 entry); class v5's is verified by that test | this lane | 0 |
|
||||
| The spec text (01 1.8.5 the leaf line, 1.12 the cut, 10 the witness) | NO text | this lane | 2 |
|
||||
| The litepaper paragraph and ledger M35 | done (the litepaper's measured numbers are the 4090's) | this lane | 0 |
|
||||
|
||||
|
|
|
|||
|
|
@ -1589,7 +1589,12 @@ pub fn try_generate_class(seed_string: &str, seed_bytes: &[u8], class: LoadClass
|
|||
}
|
||||
if crate::accept::is_class_v4_shape(&class) {
|
||||
// AP-F8-2 (7 October 2026, main's ruling: the draw is total and no consensus path panics): a class v4 seed that
|
||||
// exhausts its attempts takes the last-resort program, deterministic and accepted as drawn
|
||||
// exhausts its attempts takes the last-resort program, deterministic. Sub-version 3's is accepted as drawn
|
||||
// (unreachable at 4.6e-44 per epoch and unverified against the rule: adv-accept-3's finding, 223 of 2,500
|
||||
// rewritten candidates fail it, 209 by part (a)); class v5's is the verified one.
|
||||
if class.state {
|
||||
return Ok(last_resort_v5(seed_string, seed_bytes, cap, class));
|
||||
}
|
||||
return Ok(last_resort_v4(candidate_class(seed_string, seed_bytes, cap, class)));
|
||||
}
|
||||
Err(Exhausted { seed_string: seed_string.to_string(), attempts: cap, last: last.unwrap() })
|
||||
|
|
@ -1613,6 +1618,55 @@ pub fn last_resort_v4(mut p: Program) -> Program {
|
|||
p
|
||||
}
|
||||
|
||||
/// Class v5's last resort, verified (adv-accept-3's finding of 7 October 2026: the sub-version 3 rewrite alone fails the
|
||||
/// rule on 223 of 2,500 seeds, 209 by part (a), a load reading a register no instruction wrote since the previous load
|
||||
/// from it). From attempt `cap` on, each candidate is rewritten as [`last_resort_v4`] does, its stale loads re-sourced
|
||||
/// by [`repair_stale_loads`], and the result checked against the whole rule; the first that passes is the program. The
|
||||
/// scan runs [`LAST_RESORT_SCAN`] candidates; past it the first repaired candidate stands as drawn, so the draw is total,
|
||||
/// and that fallback sits behind the 4.6e-44 of reaching the last resort at all times the rejection rate of a repaired
|
||||
/// candidate (about 0.09 per adv-accept-3) to the power of the scan: under 1e-300.
|
||||
pub fn last_resort_v5(seed_string: &str, seed_bytes: &[u8], cap: u32, class: LoadClass) -> Program {
|
||||
for k in cap..cap + LAST_RESORT_SCAN {
|
||||
let p = repair_stale_loads(last_resort_v4(candidate_class(seed_string, seed_bytes, k, class)));
|
||||
if check(&p).is_ok() {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
repair_stale_loads(last_resort_v4(candidate_class(seed_string, seed_bytes, cap, class)))
|
||||
}
|
||||
|
||||
/// The candidates class v5's last resort scans past the attempt cap before the unchecked fallback.
|
||||
pub const LAST_RESORT_SCAN: u32 = 256;
|
||||
|
||||
/// Part (a) by construction: a load whose source register no instruction wrote since the previous load from it (in
|
||||
/// cyclic order over the 64 instructions, the two-pass walk of the acceptance's `check_stale_loads`) is re-sourced to
|
||||
/// the lowest register that was written since its last load. The walk repeats until a full two-pass walk changes
|
||||
/// nothing (a re-sourced load can make a later load from the new register stale, which the next walk re-sources);
|
||||
/// with 16 loads among 64 instructions a non-pending register always exists. Only the `src` field moves.
|
||||
pub fn repair_stale_loads(mut p: Program) -> Program {
|
||||
for _round in 0..16 {
|
||||
let mut changed = false;
|
||||
let mut pending = [false; 8];
|
||||
for _pass in 0..2 {
|
||||
for ins in p.instrs.iter_mut() {
|
||||
if ins.op.is_load() && pending[ins.src as usize] {
|
||||
let q = (0..8usize).find(|&q| !pending[q]).expect("a register written since its last load") as u8;
|
||||
ins.src = q;
|
||||
changed = true;
|
||||
}
|
||||
pending[ins.dst as usize] = false;
|
||||
if ins.op.is_load() {
|
||||
pending[ins.src as usize] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !changed {
|
||||
break;
|
||||
}
|
||||
}
|
||||
p
|
||||
}
|
||||
|
||||
/// [`try_generate_from_seed_bytes`], treating exhaustion as the consensus fault it is.
|
||||
pub fn generate_from_seed_bytes(seed_string: &str, seed_bytes: &[u8]) -> Program {
|
||||
try_generate_from_seed_bytes(seed_string, seed_bytes).unwrap_or_else(|e| panic!("{e}"))
|
||||
|
|
@ -2273,6 +2327,44 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
/// Class v5's last resort is verified (adv-accept-3's finding, 7 October 2026): on seed adv3/steer/2 of that lane's
|
||||
/// label space (`seed_words_from_bytes("igneum-adv-accept-3/steer/2")` as the epoch bytes, Devnet 3's genesis as the
|
||||
/// era) the sub-version 3 rewrite of the candidate at the cap fails the rule by part (a), a cyclic stale load, and
|
||||
/// would be handed to the chain; class v5's repair re-sources the load and the result passes the whole rule, as
|
||||
/// does the program `last_resort_v5` returns. The class v4 path is unchanged (frozen, unreachable, recorded).
|
||||
#[test]
|
||||
fn class_v5_last_resort_is_verified_known_failed_adv3_steer_2() {
|
||||
use crate::accept::{check, check_static, Reject};
|
||||
use crate::seed::seed_words_from_bytes;
|
||||
let epoch: Vec<u8> = seed_words_from_bytes(b"igneum-adv-accept-3/steer/2").iter().flat_map(|x| x.to_le_bytes()).collect();
|
||||
let era = crate::bind::unhex("4020cb4382e3fe4b281c817c02582e147d8f851f566ae9172b28912b8e68b925").unwrap();
|
||||
let v4 = LoadClass::era(V4_CLASS, &era, &V3_ALLOWED);
|
||||
let v5 = LoadClass::era(V5_CLASS, &era, &V3_ALLOWED);
|
||||
let cap = max_attempts_for(&v4);
|
||||
let old = last_resort_v4(candidate_class("adv3/steer/2", &epoch, cap, v4));
|
||||
match check_static(&old) {
|
||||
Err(Reject::StaleLoadSource { instr, reg }) => println!("adv3/steer/2: the sub-version 3 last resort fails part (a) at instruction {instr} reading r{reg}"),
|
||||
other => panic!("the known-failed case must fail part (a): {other:?}"),
|
||||
}
|
||||
let repaired = repair_stale_loads(old.clone());
|
||||
assert!(check_static(&repaired).is_ok(), "the repair restores part (a): {:?}", check_static(&repaired).err());
|
||||
assert_eq!(repaired.instrs.len(), old.instrs.len());
|
||||
assert!(repaired.instrs.iter().zip(old.instrs.iter()).all(|(a, b)| a.op == b.op && a.dst == b.dst), "only load sources move");
|
||||
let lr = last_resort_v5("adv3/steer/2", &epoch, cap, v5);
|
||||
assert!(check(&lr).is_ok(), "class v5's last resort passes the whole rule: {:?}", check(&lr).err());
|
||||
assert!(lr.attempt >= cap && lr.attempt < cap + LAST_RESORT_SCAN);
|
||||
assert!(lr.class.state);
|
||||
println!("adv3/steer/2: class v5 last resort at attempt {} id {:016x}", lr.attempt, lr.program_id());
|
||||
// the sub-version 3 path is byte for byte what it was
|
||||
assert_eq!(try_generate_class("adv3/steer/2", &epoch, v4).map(|p| p.attempt).ok(), Some(try_generate_class("adv3/steer/2", &epoch, v4).unwrap().attempt));
|
||||
// a few more of the label space: every class v5 last resort passes
|
||||
for i in [11u32, 33, 56, 58, 77] {
|
||||
let e: Vec<u8> = seed_words_from_bytes(format!("igneum-adv-accept-3/steer/{i}").as_bytes()).iter().flat_map(|x| x.to_le_bytes()).collect();
|
||||
let lr = last_resort_v5(&format!("adv3/steer/{i}"), &e, cap, v5);
|
||||
assert!(check(&lr).is_ok(), "steer/{i}: {:?}", check(&lr).err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn class_v4_draw_is_total_with_the_last_resort() {
|
||||
assert_eq!(max_attempts_for(&V4_CLASS), MAX_ATTEMPTS_V4);
|
||||
|
|
|
|||
|
|
@ -210,12 +210,15 @@ pub struct MixParams {
|
|||
pub redraws: u32,
|
||||
}
|
||||
|
||||
/// Class v5's mixer-draw rule (AP-F4-1): the NAF sum of the 16 multipliers at least this.
|
||||
pub const MIXER_NAF_SUM_MIN: u32 = 163;
|
||||
/// Class v5's mixer-draw rule: every multiplier's NAF weight at least this.
|
||||
/// Class v5's mixer-draw rule (AP-F4-1, the form the attack-pass lane and adv-mixer-2 agreed on 7 October 2026, 22:0x
|
||||
/// UK; it replaces the first form's "NAF sum under 163"): the adder-datapath cost of a mixer block is
|
||||
/// `A = 64 + sum over the 16 multipliers of (w32(m) - 1)`, `w32` the NAF weight over bit positions 0 to 31 only (the
|
||||
/// carry digit at position 32 a 32-bit multiplier never pays; the first census counted it, so its median read 231
|
||||
/// where the agreed median is 226). A block whose cost is at most this is rejected (a 1.1x gain against the median).
|
||||
pub const MIXER_COST_REJECT_MAX: u32 = 205;
|
||||
/// Class v5's mixer-draw rule: every multiplier's `w32` at least this (a multiplier with a two-adder chain, `w32 <= 3`,
|
||||
/// is rejected on its own: adv-mixer-2's `k >= 1`).
|
||||
pub const MIXER_NAF_WORD_MIN: u32 = 4;
|
||||
/// Class v5's mixer-draw rule: at least this many distinct rotation amounts among the eight.
|
||||
pub const MIXER_DISTINCT_ROT_MIN: usize = 4;
|
||||
/// Class v5's mixer-draw rule: redraws before the last block stands as drawn (never reached at 6.1e-4 per try).
|
||||
pub const MIXER_REDRAW_CAP: u32 = 64;
|
||||
|
||||
|
|
@ -238,14 +241,40 @@ pub fn naf_weight(mut x: u64) -> u32 {
|
|||
w
|
||||
}
|
||||
|
||||
/// Whether a mixer block passes class v5's draw rule (AP-F4-1).
|
||||
/// The NAF weight of a 32-bit multiplier over bit positions 0 to 31: [`naf_weight`] without the digit at position 32.
|
||||
pub fn naf32_weight(m: u32) -> u32 {
|
||||
let mut x = m as u64;
|
||||
let mut w = 0;
|
||||
let mut pos = 0;
|
||||
while x != 0 {
|
||||
if x & 1 == 1 {
|
||||
if pos < 32 {
|
||||
w += 1;
|
||||
}
|
||||
if x & 3 == 3 {
|
||||
x += 1;
|
||||
} else {
|
||||
x -= 1;
|
||||
}
|
||||
}
|
||||
x >>= 1;
|
||||
pos += 1;
|
||||
}
|
||||
w
|
||||
}
|
||||
|
||||
/// The adder-datapath cost of a mixer block: `64 + sum(w32(m) - 1)` over the 16 multipliers.
|
||||
pub fn mixer_cost(mul: &[u32; 16]) -> u32 {
|
||||
64 + mul.iter().map(|&m| naf32_weight(m).saturating_sub(1)).sum::<u32>()
|
||||
}
|
||||
|
||||
/// Whether a mixer block passes class v5's draw rule (AP-F4-1): cost over [`MIXER_COST_REJECT_MAX`], every
|
||||
/// multiplier's `w32` at least [`MIXER_NAF_WORD_MIN`], and the eight rotation amounts not all equal. A rejected block
|
||||
/// is redrawn whole (all forty draws) from the continuing stream.
|
||||
pub fn mixer_block_admissible(rot: &[u32; 8], mul: &[u32; 16]) -> bool {
|
||||
let sum: u32 = mul.iter().map(|&m| naf_weight(m as u64)).sum();
|
||||
let words = mul.iter().all(|&m| naf_weight(m as u64) >= MIXER_NAF_WORD_MIN);
|
||||
let mut distinct = rot.to_vec();
|
||||
distinct.sort_unstable();
|
||||
distinct.dedup();
|
||||
sum >= MIXER_NAF_SUM_MIN && words && distinct.len() >= MIXER_DISTINCT_ROT_MIN
|
||||
let words = mul.iter().all(|&m| naf32_weight(m) >= MIXER_NAF_WORD_MIN);
|
||||
let rot_equal = rot.iter().all(|&r| r == rot[0]);
|
||||
mixer_cost(mul) > MIXER_COST_REJECT_MAX && words && !rot_equal
|
||||
}
|
||||
|
||||
impl MixParams {
|
||||
|
|
@ -269,11 +298,11 @@ impl MixParams {
|
|||
}
|
||||
let mut redraws = 0u32;
|
||||
if shape.state {
|
||||
// Class v5 (docs/design/class-v5-stored-state.md section 11, AP-F4-1, the attack-pass lane's weak-day census):
|
||||
// a mixer block whose multipliers are cheap on an adder datapath (NAF sum under 163, a word under NAF weight 4)
|
||||
// or whose rotations repeat (under 4 distinct amounts) is redrawn from the next stream values, so no day is a
|
||||
// weak day for a per-day LUT-recompute FPGA (the worst calendar day of the census, chain day 29,337, was 1.121x).
|
||||
// About 6.1e-4 of days redraw. The derive program's draws (none under v5) come after, as before.
|
||||
// Class v5 (docs/design/class-v5-stored-state.md section 11, AP-F4-1, the attack-pass lane's and adv-mixer-2's
|
||||
// reconciled weak-day census): a mixer block whose adder cost is at most 205 against the median 226, or with a
|
||||
// two-adder multiplier, or with one rotation amount, is redrawn whole from the next forty stream values, so no
|
||||
// day is a weak day for a per-day LUT-recompute FPGA (the worst calendar day, chain day 29,337 = 2050-04-28,
|
||||
// read 1.113x). About 5.69e-4 of days redraw, 15 days a century. The derive program's draws come after.
|
||||
while !mixer_block_admissible(&rot, &mul) && redraws < MIXER_REDRAW_CAP {
|
||||
for r in rot.iter_mut() {
|
||||
*r = 1 + rng.below(31) as u32;
|
||||
|
|
@ -818,9 +847,11 @@ impl MemhardCpu {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// Class v5's mixer-draw rule (AP-F4-1), the known-failed case first: a block of cheap multipliers (NAF sum under
|
||||
/// 163) or repeated rotations is inadmissible; a scan of day keys finds days the rule redraws (the census's 6.1e-4),
|
||||
/// every v5 block passes after the draw, and the v4 constants of the same keys never move.
|
||||
/// Class v5's mixer-draw rule (AP-F4-1 in the agreed form), the known-failed case first: the day the two censuses
|
||||
/// name as the worst of the century, chain day 29,337 (2050-04-28, 1.113x), draws a block the rule rejects and class
|
||||
/// v5 redraws it; a block of two-adder multipliers or one rotation amount is inadmissible; a scan of day keys finds
|
||||
/// the redrawn days (about 5.69e-4), every v5 block passes after the draw, and the v4 constants of the same keys
|
||||
/// never move.
|
||||
#[test]
|
||||
fn class_v5_mixer_draw_rule() {
|
||||
assert_eq!(naf_weight(0), 0);
|
||||
|
|
@ -828,16 +859,34 @@ mod tests {
|
|||
assert_eq!(naf_weight(3), 2, "11 = 100 - 1");
|
||||
assert_eq!(naf_weight(7), 2, "111 = 1000 - 1");
|
||||
assert_eq!(naf_weight(0xffff_ffff), 2);
|
||||
assert_eq!(naf32_weight(0xffff_ffff), 1, "the carry digit at position 32 is not paid");
|
||||
assert_eq!(naf32_weight(0xc000_0001), 2, "2^32 - 2^30 + 1: the digit at 32 dropped, -2^30 and +1 kept");
|
||||
assert_eq!(naf_weight(0b1010_1010), 4);
|
||||
assert_eq!(naf32_weight(0b1010_1010), 4);
|
||||
let good_rot = [1u32, 5, 9, 13, 17, 21, 25, 29];
|
||||
let cheap = [0x8000_0001u32; 16];
|
||||
assert_eq!(mixer_cost(&cheap), 64 + 16, "16 two-adder multipliers");
|
||||
assert!(!mixer_block_admissible(&good_rot, &cheap), "the known-failed case: 16 two-adder multipliers");
|
||||
let dense = [0xaaaa_aaabu32; 16];
|
||||
assert!(mixer_cost(&dense) > MIXER_COST_REJECT_MAX);
|
||||
assert!(mixer_block_admissible(&good_rot, &dense));
|
||||
assert!(!mixer_block_admissible(&[7u32; 8], &dense), "one rotation amount");
|
||||
assert!(!mixer_block_admissible(&[1u32, 2, 3, 3, 3, 3, 3, 3], &dense), "three distinct amounts");
|
||||
assert!(mixer_block_admissible(&[1u32, 2, 3, 3, 3, 3, 3, 3], &dense), "three distinct amounts pass the agreed form");
|
||||
// one two-adder multiplier among dense ones is rejected on its own (k >= 1)
|
||||
let mut one_cheap = dense;
|
||||
one_cheap[5] = 0x0000_0401;
|
||||
assert!(mixer_cost(&one_cheap) > MIXER_COST_REJECT_MAX);
|
||||
assert!(!mixer_block_admissible(&good_rot, &one_cheap), "a two-adder multiplier");
|
||||
// the known-failed day
|
||||
let v5 = Shape { mixer_mult: 8, cache_log2_words: 26, derive_len: 0, state: true };
|
||||
let v4 = Shape { mixer_mult: 8, cache_log2_words: 26, derive_len: 0, state: false };
|
||||
let worst = crate::seed::seed_words_from_bytes(&crate::bind::day_bytes(29_337));
|
||||
let b = MixParams::with_shape(worst, v4);
|
||||
println!("day 29,337 (2050-04-28) under class v4: cost {}, w32 min {}, distinct rot {}", mixer_cost(&b.mul), b.mul.iter().map(|&m| naf32_weight(m)).min().unwrap(), { let mut r = b.rot.to_vec(); r.sort_unstable(); r.dedup(); r.len() });
|
||||
assert!(!mixer_block_admissible(&b.rot, &b.mul), "the known-failed day: the sub-version 3 block of day 29,337 is one the rule rejects");
|
||||
let a = MixParams::with_shape(worst, v5);
|
||||
assert!(a.redraws >= 1 && mixer_block_admissible(&a.rot, &a.mul), "class v5 redraws day 29,337");
|
||||
assert_ne!((a.rot, a.mul), (b.rot, b.mul));
|
||||
let mut redrawn = 0;
|
||||
let mut scanned = 0;
|
||||
for d in 0..60_000u64 {
|
||||
|
|
@ -859,7 +908,7 @@ mod tests {
|
|||
break;
|
||||
}
|
||||
}
|
||||
assert!(redrawn >= 1, "no redraw in {scanned} days (the census says about 6.1e-4 per day)");
|
||||
assert!(redrawn >= 1, "no redraw in {scanned} days (the census says about 5.69e-4 per day)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in a new issue