seed.rs

5.1 kB · rust · 144 lines

1use crate::rules::{evolve, mirrored, RULES};2use std::collections::{BTreeMap, BTreeSet};34pub const STEPS: usize = 256;56pub struct Census {7    pub class: Vec<usize>,8    pub occurring: Vec<u8>,9}1011struct Pass {12    class: Vec<usize>,13    occurring: Vec<u8>,14    distinct: usize,15    reflected: usize,16    histogram: BTreeMap<usize, usize>,17}1819fn classify(steps: usize, pad: usize) -> Pass {20    let mut seen: BTreeMap<Vec<u8>, usize> = BTreeMap::new();21    let mut folded: BTreeSet<Vec<u8>> = BTreeSet::new();22    let mut class = vec![0usize; RULES];23    let mut occurring = vec![0u8; RULES];24    for rule in 0..RULES {25        let (diagram, met) = evolve(rule, steps, pad);26        occurring[rule] = met;27        let mirror = mirrored(&diagram);28        let next = seen.len();29        class[rule] = *seen.entry(diagram.cells.clone()).or_insert(next);30        folded.insert(diagram.cells.min(mirror));31    }32    let mut sizes: BTreeMap<usize, usize> = BTreeMap::new();33    for rule in 0..RULES {34        *sizes.entry(class[rule]).or_insert(0) += 1;35    }36    let mut histogram: BTreeMap<usize, usize> = BTreeMap::new();37    for size in sizes.values() {38        *histogram.entry(*size).or_insert(0) += 1;39    }40    Pass {41        distinct: seen.len(),42        reflected: folded.len(),43        class,44        occurring,45        histogram,46    }47}4849pub fn report() -> Census {50    println!("SINGLE-SEED CENSUS");51    println!("one live cell on a line padded by pad cells beyond the 2T+1 window that is cropped and compared");52    let mut last: Option<Pass> = None;53    for steps in [64usize, 128, STEPS] {54        let narrow = classify(steps, steps);55        let wide = classify(steps, 2 * steps);56        assert_eq!(57            narrow.class, wide.class,58            "the diagrams move between pad = T and pad = 2T at T = {steps}"59        );60        assert_eq!(61            narrow.occurring, wide.occurring,62            "the occurring neighbourhoods move between pad = T and pad = 2T at T = {steps}"63        );64        println!(65            "T = {steps}: {} distinct diagrams, {} up to left-right reflection, class-size histogram {:?}, identical at pad = T and pad = 2T",66            narrow.distinct, narrow.reflected, narrow.histogram67        );68        if let Some(before) = &last {69            assert_eq!(70                before.occurring, narrow.occurring,71                "the occurring neighbourhoods move with T at {steps}"72            );73        }74        last = Some(narrow);75    }76    let pass = last.expect("three depths ran");77    let (class, occurring, distinct) = (pass.class, pass.occurring, pass.distinct);78    println!("the occurring neighbourhood set is the same at T = 64, 128 and {STEPS}");79    let mut failures = 0usize;80    for a in 0..RULES {81        for b in 0..RULES {82            let mask = occurring[a] as usize;83            if occurring[a] == occurring[b] && a & mask == b & mask && class[a] != class[b] {84                failures += 1;85            }86        }87    }88    assert_eq!(89        failures, 0,90        "rules sharing the occurring key do not share the diagram"91    );92    println!("law: equal key implies equal diagram, 0 failures over all {} ordered pairs, the key being the occurring set together with the rule restricted to it", RULES * RULES);93    let keys: BTreeSet<(u8, usize)> = (0..RULES)94        .map(|r| (occurring[r], r & occurring[r] as usize))95        .collect();96    let mut members: BTreeMap<usize, Vec<usize>> = BTreeMap::new();97    for rule in 0..RULES {98        members.entry(class[rule]).or_default().push(rule);99    }100    let split: Vec<usize> = members101        .values()102        .filter(|rules| {103            rules104                .iter()105                .map(|r| (occurring[*r], r & occurring[*r] as usize))106                .collect::<BTreeSet<_>>()107                .len()108                > 1109        })110        .flatten()111        .copied()112        .collect();113    let split_classes: BTreeSet<usize> = split.iter().map(|r| class[*r]).collect();114    let split_keys: BTreeSet<(u8, usize)> = split115        .iter()116        .map(|r| (occurring[*r], r & occurring[*r] as usize))117        .collect();118    println!(119        "the key takes {} values against {distinct} distinct diagrams, so it separates strictly more than the diagram does and is not a complete invariant",120        keys.len()121    );122    println!("over-separated rules, {} of them spread over {} diagram classes carrying {} keys in all: {split:?}", split.len(), split_classes.len(), split_keys.len());123    assert_eq!(split_keys.len(), 11);124    assert!(125        keys.len() > distinct,126        "the key no longer over-separates the diagram"127    );128    assert_eq!(129        split,130        vec![23, 31, 55, 63, 87, 95, 119, 127, 151, 159, 183, 191, 215, 223, 247, 255],131        "the over-separated rules are not the expected 16"132    );133    assert_eq!(134        split_classes.len(),135        2,136        "the over-separated rules do not fall into two diagram classes"137    );138    let mut occ_sizes: BTreeMap<u32, usize> = BTreeMap::new();139    for rule in 0..RULES {140        *occ_sizes.entry(occurring[rule].count_ones()).or_insert(0) += 1;141    }142    println!("occurring-set sizes {occ_sizes:?}");143    Census { class, occurring }144}