count.rs
7.9 kB · rust · 285 lines
1use std::collections::BTreeMap;23pub struct Dsu {4 parent: Vec<u32>,5}67impl Dsu {8 pub fn new(size: usize) -> Dsu {9 Dsu {10 parent: (0..size as u32).collect(),11 }12 }1314 pub fn find(&mut self, mut i: u32) -> u32 {15 while self.parent[i as usize] != i {16 let up = self.parent[self.parent[i as usize] as usize];17 self.parent[i as usize] = up;18 i = up;19 }20 i21 }2223 pub fn union(&mut self, a: u32, b: u32) -> bool {24 let (ra, rb) = (self.find(a), self.find(b));25 if ra == rb {26 return false;27 }28 self.parent[ra as usize] = rb;29 true30 }31}3233pub fn arcs(side: usize, on: &[bool]) -> (u64, u64) {34 let rows = side * (side + 1);35 let h = |x: usize, y: usize| (y * side + x) as u32;36 let v = |x: usize, y: usize| (rows + y * (side + 1) + x) as u32;37 let mut dsu = Dsu::new(2 * rows);38 let mut degree = vec![0u8; 2 * rows];39 for y in 0..side {40 for x in 0..side {41 let (bottom, top, left, right) = (h(x, y), h(x, y + 1), v(x, y), v(x + 1, y));42 let pairs = if on[y * side + x] {43 [(left, bottom), (right, top)]44 } else {45 [(bottom, right), (left, top)]46 };47 for (a, b) in pairs {48 degree[a as usize] += 1;49 degree[b as usize] += 1;50 dsu.union(a, b);51 }52 }53 }54 let mut closed = vec![1u8; 2 * rows];55 let mut root = vec![false; 2 * rows];56 for i in 0..2 * rows {57 let r = dsu.find(i as u32) as usize;58 root[r] = true;59 if degree[i] != 2 {60 closed[r] = 0;61 }62 }63 let curves = root.iter().filter(|&&r| r).count() as u64;64 let loops = (0..2 * rows).filter(|&i| root[i] && closed[i] == 1).count() as u64;65 (loops, curves - loops)66}6768pub fn mirrors(side: usize, on: &[bool]) -> i64 {69 let w = side + 1;70 let p = |x: usize, y: usize| (y * w + x) as u32;71 let mut dsu = Dsu::new(w * w);72 let mut comp = (w * w) as i64;73 for y in 0..side {74 for x in 0..side {75 let (a, b) = if on[y * side + x] {76 (p(x + 1, y), p(x, y + 1))77 } else {78 (p(x, y), p(x + 1, y + 1))79 };80 if dsu.union(a, b) {81 comp -= 1;82 }83 }84 }85 comp - 2 * side as i64 - 186}8788pub struct Block {89 pub side: usize,90 pub partner: Vec<u32>,91 pub loops: u128,92 pub lengths: BTreeMap<u64, u64>,93}9495pub fn unit(on: bool) -> Block {96 let partner = if on {97 vec![3, 2, 1, 0]98 } else {99 vec![1, 0, 3, 2]100 };101 Block {102 side: 1,103 partner,104 loops: 0,105 lengths: BTreeMap::new(),106 }107}108109pub fn void_partner(s: usize, p: usize) -> usize {110 let t = p % s;111 match p / s {112 0 => 2 * s - 1 - t,113 1 => s - 1 - t,114 2 => 4 * s - 1 - t,115 _ => 3 * s - 1 - t,116 }117}118119pub fn void_block(s: usize) -> Block {120 Block {121 side: s,122 partner: (0..4 * s).map(|p| void_partner(s, p) as u32).collect(),123 loops: 0,124 lengths: BTreeMap::new(),125 }126}127128pub fn glue(n: usize, tile: &[bool], kept: &Block, keep: bool) -> Block {129 let s = kept.side;130 let big = n * s;131 let s4 = 4 * s;132 let mut seen = vec![0u64; (n * n * s4).div_ceil(64)];133 let mut partner = if keep {134 vec![u32::MAX; 4 * big]135 } else {136 Vec::new()137 };138 let inside = |b: usize, p: usize| {139 if tile[b] {140 kept.partner[p] as usize141 } else {142 void_partner(s, p)143 }144 };145 let outer = |i: usize, j: usize, p: usize| -> Option<usize> {146 let t = p % s;147 match p / s {148 0 => (i == 0).then_some(j * s + t),149 1 => (j == n - 1).then_some(big + i * s + t),150 2 => (i == n - 1).then_some(2 * big + j * s + t),151 _ => (j == 0).then_some(3 * big + i * s + t),152 }153 };154 let across = |i: usize, j: usize, p: usize| -> (usize, usize, usize) {155 let t = p % s;156 match p / s {157 0 => (i - 1, j, 2 * s + t),158 1 => (i, j + 1, 3 * s + t),159 2 => (i + 1, j, t),160 _ => (i, j - 1, s + t),161 }162 };163 let key = |i: usize, j: usize, p: usize| (i * n + j) * s4 + p;164 let mark = |seen: &mut Vec<u64>, k: usize| seen[k / 64] |= 1 << (k % 64);165 let is_seen = |seen: &Vec<u64>, k: usize| seen[k / 64] >> (k % 64) & 1 == 1;166 for i in 0..n {167 for j in 0..n {168 for p in 0..s4 {169 let Some(start) = outer(i, j, p) else {170 continue;171 };172 if is_seen(&seen, key(i, j, p)) {173 continue;174 }175 let (mut a, mut b, mut c) = (i, j, p);176 loop {177 mark(&mut seen, key(a, b, c));178 let q = inside(a * n + b, c);179 mark(&mut seen, key(a, b, q));180 if let Some(end) = outer(a, b, q) {181 if keep {182 partner[start] = end as u32;183 partner[end] = start as u32;184 }185 break;186 }187 (a, b, c) = across(a, b, q);188 }189 }190 }191 }192 let mut cycles = 0u128;193 let mut lengths = BTreeMap::new();194 for i in 0..n {195 for j in 0..n {196 for p in 0..s4 {197 if is_seen(&seen, key(i, j, p)) {198 continue;199 }200 cycles += 1;201 let mut length = 0u64;202 let (mut a, mut b, mut c) = (i, j, p);203 loop {204 length += 1;205 mark(&mut seen, key(a, b, c));206 let q = inside(a * n + b, c);207 mark(&mut seen, key(a, b, q));208 (a, b, c) = across(a, b, q);209 if (a, b, c) == (i, j, p) {210 break;211 }212 }213 *lengths.entry(length).or_insert(0) += 1;214 }215 }216 }217 let inner = tile.iter().filter(|&&on| on).count() as u128 * kept.loops;218 Block {219 side: big,220 partner,221 loops: inner + cycles,222 lengths,223 }224}225226pub fn series(n: usize, tile: &[bool], top: usize) -> Vec<u128> {227 let mut kept = unit(true);228 let mut out = vec![0];229 for level in 0..top {230 kept = glue(n, tile, &kept, level + 1 < top);231 out.push(kept.loops);232 }233 out234}235236pub fn blocks(n: usize, tile: &[bool], top: usize) -> Vec<Block> {237 let mut out = vec![unit(true)];238 for level in 0..top {239 let next = glue(n, tile, &out[level], true);240 out.push(next);241 }242 out243}244245#[cfg(test)]246mod tests {247 use super::*;248 use crate::design::Design;249250 #[test]251 fn three_counts_agree_at_base_two() {252 for code in 0..16u128 {253 let d = Design::full(code, 2);254 let blocks = series(2, &d.tile, 5);255 for level in 0..=5 {256 let (side, on) = d.cells(level);257 let (loops, strands) = arcs(side, &on);258 assert_eq!(loops as u128, blocks[level]);259 assert_eq!(mirrors(side, &on), loops as i64);260 assert_eq!(strands, 2 * side as u64);261 }262 }263 }264265 #[test]266 fn carpet_law() {267 let s = series(3, &Design::new(7, 3, 2).tile, 8);268 for (n, &x) in s.iter().enumerate() {269 let n = n as u32;270 assert_eq!(271 x as i128,272 (8i128.pow(n) - 1) / 7 - 3i128.pow(n) + n as i128 + 1273 );274 }275 }276277 #[test]278 fn void_block_glues_to_its_formula() {279 for n in 2..6 {280 let glued = glue(n, &vec![true; n * n], &void_block(n), true);281 assert_eq!(glued.partner, void_block(n * n).partner);282 assert_eq!(glued.loops, 0);283 }284 }285}