witness.rs
4.4 kB · rust · 157 lines
1use crate::tile::{2 cuts, factorisations, gcd, incomparable, kron, lcm, line_cuts, line_kron, mask_tile, profile,3 unpack, Tile,4};5use std::collections::BTreeSet;67pub fn from_cells(side: usize, cells: &[(usize, usize)]) -> Tile {8 let mut tile = Tile::new(side);9 for (r, c) in cells {10 tile.set(*r, *c);11 }12 tile13}1415pub fn identity(side: usize) -> Tile {16 let cells: Vec<(usize, usize)> = (0..side).map(|i| (i, i)).collect();17 from_cells(side, &cells)18}1920pub fn antidiagonal(side: usize) -> Tile {21 let cells: Vec<(usize, usize)> = (0..side).map(|i| (i, side - 1 - i)).collect();22 from_cells(side, &cells)23}2425pub fn gcd_closed(list: &[usize]) -> bool {26 let set: BTreeSet<usize> = list.iter().copied().collect();27 for a in &set {28 for b in &set {29 if !set.contains(&gcd(*a, *b)) {30 return false;31 }32 }33 }34 true35}3637pub fn lcm_closed(list: &[usize], side: usize) -> bool {38 let set: BTreeSet<usize> = list.iter().copied().collect();39 for a in &set {40 for b in &set {41 let value = lcm(*a, *b);42 if value <= side && !set.contains(&value) {43 return false;44 }45 }46 }47 true48}4950pub struct LineClosure {51 pub gcd_violations: usize,52 pub lcm_violations: usize,53 pub first_lcm: Option<(usize, u128, Vec<usize>)>,54}5556pub fn line_closure(max_side: usize) -> LineClosure {57 let mut out = LineClosure {58 gcd_violations: 0,59 lcm_violations: 0,60 first_lcm: None,61 };62 for side in 1..=max_side {63 for mask in 1u128..1u128 << side {64 let list = line_cuts(mask, side);65 if !gcd_closed(&list) {66 out.gcd_violations += 1;67 }68 if !lcm_closed(&list, side) {69 out.lcm_violations += 1;70 if out.first_lcm.is_none() {71 out.first_lcm = Some((side, mask, list.clone()));72 }73 }74 }75 }76 out77}7879pub fn line_commuting(m: usize, n: usize) -> Vec<(u128, u128)> {80 let mut out = Vec::new();81 for a in 1u128..1u128 << m {82 for b in 1u128..1u128 << n {83 if line_kron(a, m, b, n) == line_kron(b, n, a, m) {84 out.push((a, b));85 }86 }87 }88 out89}9091pub struct TwelveSweep {92 pub tiles: usize,93 pub gcd_violations: usize,94 pub lcm_violations: usize,95 pub mismatches: usize,96 pub multiple: usize,97 pub unequal_length: usize,98 pub max_factorisations: usize,99}100101pub fn twelve_sweep(six: &[u64]) -> TwelveSweep {102 let small: Vec<Tile> = (1u32..16).map(|c| mask_tile(c as u64, 2)).collect();103 let mut out = TwelveSweep {104 tiles: 0,105 gcd_violations: 0,106 lcm_violations: 0,107 mismatches: 0,108 multiple: 0,109 unequal_length: 0,110 max_factorisations: 0,111 };112 let mut seen: std::collections::HashSet<[u64; 3]> = std::collections::HashSet::new();113 for key in six {114 let inner = unpack(*key, 6);115 for code in &small {116 for whole in [kron(code, &inner), kron(&inner, code)] {117 if !seen.insert(whole.key()) {118 continue;119 }120 out.tiles += 1;121 let list = cuts(&whole);122 if !gcd_closed(&list) {123 out.gcd_violations += 1;124 }125 if !lcm_closed(&list, 12) {126 out.lcm_violations += 1;127 }128 let words = factorisations(&whole);129 out.max_factorisations = out.max_factorisations.max(words.len());130 let many = words.len() > 1;131 if many {132 out.multiple += 1;133 }134 if many != incomparable(&list) {135 out.mismatches += 1;136 }137 let lengths: BTreeSet<usize> = words.iter().map(|word| word.len()).collect();138 if lengths.len() > 1 {139 out.unequal_length += 1;140 }141 }142 }143 }144 out145}146147pub fn profiles_text(tile: &Tile) -> String {148 let mut rows: Vec<String> = factorisations(tile)149 .iter()150 .map(|word| {151 let sides: Vec<String> = profile(word).iter().map(|s| format!("{s}")).collect();152 format!("({})", sides.join(" x "))153 })154 .collect();155 rows.sort();156 rows.join(" ")157}