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}