card.rs

4.7 kB · rust · 120 lines

1use crate::dynamics::{injective, surjective};2use crate::groups::{group, orbit};3use crate::seed::Census;4use crate::table::{genus, levels};5use mrlymath::bang::universe::degree;6use mrlynum::boolean::walsh_spectrum;7use std::collections::BTreeSet;89fn line(rule: usize, census: &Census, b3: &[crate::groups::Elem]) -> String {10    let sigma = levels(rule);11    format!(12        "{rule} surj {} rev {} diagram {} deg {} pop {} genus {} occ {:08b} S {} {} {} {}",13        u8::from(surjective(rule)),14        u8::from(injective(rule)),15        census.class[rule],16        degree(rule as u128, 3),17        (rule as u32).count_ones(),18        genus(rule, b3),19        census.occurring[rule],20        sigma[0],21        sigma[1],22        sigma[2],23        sigma[3]24    )25}2627pub fn report(census: &Census) {28    println!("THE 110 CARD");29    let b3 = group("B3");30    let h = group("H");31    let big = orbit(110, &b3);32    let small = orbit(110, &h);33    let expected: BTreeSet<usize> = [34        61, 62, 91, 94, 103, 110, 118, 122, 124, 155, 157, 167, 173, 181, 185, 188, 199, 203, 211,35        217, 218, 227, 229, 230,36    ]37    .into_iter()38    .collect();39    assert_eq!(big, expected, "the B3 orbit of 110 is not the expected 24");40    assert!(41        !big.contains(&137) && !big.contains(&193),42        "137 or 193 sits in the B3 orbit of 110"43    );44    assert_eq!(45        small,46        BTreeSet::from([110, 124, 137, 193]),47        "the H class of 110 is not the expected four"48    );49    println!("B3 orbit of 110, {} members", big.len());50    for rule in &big {51        println!("{}", line(*rule, census, &b3));52    }53    println!("H class of 110, 4 members");54    for rule in &small {55        println!("{}", line(*rule, census, &b3));56    }57    let surj: BTreeSet<u8> = big.iter().map(|r| u8::from(surjective(*r))).collect();58    let revs: BTreeSet<u8> = big.iter().map(|r| u8::from(injective(*r))).collect();59    let degs: BTreeSet<i32> = big.iter().map(|r| degree(*r as u128, 3)).collect();60    let pops: BTreeSet<u32> = big.iter().map(|r| (*r as u32).count_ones()).collect();61    let diagrams: BTreeSet<usize> = big.iter().map(|r| census.class[*r]).collect();62    let occs: BTreeSet<u8> = big.iter().map(|r| census.occurring[*r]).collect();63    println!(64        "on the B3 orbit: surjective values {surj:?}, reversible {revs:?}, degree {degs:?}, popcount {pops:?}, diagram classes {}, occurring sets {}",65        diagrams.len(),66        occs.len()67    );68    let hdiagrams: BTreeSet<usize> = small.iter().map(|r| census.class[*r]).collect();69    let hpops: BTreeSet<u32> = small.iter().map(|r| (*r as u32).count_ones()).collect();70    println!(71        "on the H class: diagram classes {}, popcount {hpops:?}",72        hdiagrams.len()73    );74    let sigmas: BTreeSet<[i64; 4]> = big.iter().map(|r| levels(*r)).collect();75    println!(76        "signed Walsh level sums on the B3 orbit: {} distinct vectors",77        sigmas.len()78    );79    for rule in 0..256usize {80        let profile = amplitudes(rule);81        for mate in orbit(rule, &b3) {82            assert_eq!(83                profile,84                amplitudes(mate),85                "the Walsh amplitude profile of {rule} moves at {mate}"86            );87        }88    }89    println!("law: the multiset of |W| at each character weight is a B3 invariant on all 256 rules, while the signed level sums are not");90    println!("constant on the B3 orbit of 110: surjectivity, reversibility, degree, popcount, genus, the Walsh amplitude profile, so none of them separates 110 from a class-mate");91    for rule in [122usize, 218] {92        assert_eq!(93            census.occurring[rule], 0b0011_0111,94            "rule {rule} does not meet exactly the occurring set 00110111"95        );96        assert_eq!(97            census.occurring[rule].count_ones(),98            5,99            "rule {rule} does not meet exactly 5 neighbourhoods"100        );101    }102    for rule in big.iter().filter(|r| **r != 122 && **r != 218) {103        assert_eq!(104            census.occurring[*rule], 0xff,105            "rule {rule} on the B3 orbit of 110 does not meet all 8 neighbourhoods"106        );107    }108    println!("separating on that orbit: the single-seed diagram, distinct on all 24, and the occurring neighbourhood set, which splits 122 and 218, meeting the 5 neighbourhoods 00110111, off from the other 22, which meet all 8");109    println!("popcount is not an H invariant: the H class of 110 carries popcounts 5, 5, 3, 3, because conjugation complements the output");110}111112fn amplitudes(rule: usize) -> Vec<(u32, i64)> {113    let mut out: Vec<(u32, i64)> = walsh_spectrum(rule as u128, 3)114        .into_iter()115        .enumerate()116        .map(|(s, w)| (s.count_ones(), w.abs()))117        .collect();118    out.sort();119    out120}