research-multilayers.rs
4.6 kB · rust · 156 lines
1use figures::{ink, save, Board, Color, Frame};2use mrlyrs::core::error::Result;34const NA: f64 = 2.3;5const NB: f64 = 1.45;6const BASE: usize = 7;7const LEVELS: usize = 12;8const BINS: usize = 128;9const SAMPLES: usize = 48;1011type C = (f64, f64);12type M = [C; 4];1314fn cm(a: C, b: C) -> C {15 (a.0 * b.0 - a.1 * b.1, a.0 * b.1 + a.1 * b.0)16}1718fn ca(a: C, b: C) -> C {19 (a.0 + b.0, a.1 + b.1)20}2122fn mul(p: &M, q: &M) -> M {23 [24 ca(cm(p[0], q[0]), cm(p[1], q[2])),25 ca(cm(p[0], q[1]), cm(p[1], q[3])),26 ca(cm(p[2], q[0]), cm(p[3], q[2])),27 ca(cm(p[2], q[1]), cm(p[3], q[3])),28 ]29}3031fn lay(n: f64, ph: f64) -> M {32 let (s, c) = ph.sin_cos();33 [(c, 0.0), (0.0, s / n), (0.0, n * s), (c, 0.0)]34}3536fn ratio(m: &M) -> f64 {37 let re = NB * m[0].0 + NB * NB * m[1].0 - m[2].0 - NB * m[3].0;38 let im = NB * m[0].1 + NB * NB * m[1].1 - m[2].1 - NB * m[3].1;39 (re * re + im * im).sqrt() / (2.0 * NB)40}4142fn open_levels(digits: &[usize], delta: f64) -> Vec<bool> {43 let mut m = lay(NA, delta);44 let mut out = Vec::with_capacity(LEVELS);45 let mut dead = false;46 let mut span = delta;47 for _ in 0..LEVELS {48 let spacer = lay(NB, span.rem_euclid(std::f64::consts::TAU));49 let mut n = [(1.0, 0.0), (0.0, 0.0), (0.0, 0.0), (1.0, 0.0)];50 for d in 0..BASE {51 n = mul(&n, if digits.contains(&d) { &m } else { &spacer });52 }53 dead |= n.iter().any(|z| !(z.0.abs() < 1e100 && z.1.abs() < 1e100));54 m = n;55 span *= BASE as f64;56 out.push(!dead && ratio(&m) < 1.0);57 }58 out59}6061fn brute(digits: &[usize], level: u32, delta: f64) -> f64 {62 let mut m = [(1.0, 0.0), (0.0, 0.0), (0.0, 0.0), (1.0, 0.0)];63 for p in 0..BASE.pow(level) {64 let mut q = p;65 let mut on = true;66 for _ in 0..level {67 on &= digits.contains(&(q % BASE));68 q /= BASE;69 }70 m = mul(&m, &lay(if on { NA } else { NB }, delta));71 }72 ratio(&m)73}7475fn recursive(digits: &[usize], level: u32, delta: f64) -> f64 {76 let mut m = lay(NA, delta);77 let mut span = delta;78 for _ in 0..level {79 let spacer = lay(NB, span);80 let mut n = [(1.0, 0.0), (0.0, 0.0), (0.0, 0.0), (1.0, 0.0)];81 for d in 0..BASE {82 n = mul(&n, if digits.contains(&d) { &m } else { &spacer });83 }84 m = n;85 span *= BASE as f64;86 }87 ratio(&m)88}8990fn density(digits: &[usize]) -> Vec<Vec<f64>> {91 let width = std::f64::consts::FRAC_PI_2 / BINS as f64;92 let columns: Vec<Vec<f64>> = (0..BINS)93 .map(|bin| {94 let mut column = vec![0.0; LEVELS];95 for s in 0..SAMPLES {96 let delta = width * (bin as f64 + (s as f64 + 0.5) / SAMPLES as f64);97 for (k, open) in open_levels(digits, delta).into_iter().enumerate() {98 if open {99 column[k] += 1.0 / SAMPLES as f64;100 }101 }102 }103 column104 })105 .collect();106 (0..LEVELS)107 .map(|k| columns.iter().map(|column| column[k]).collect())108 .collect()109}110111fn panel(board: &mut Board, frame: &Frame, grid: &[Vec<f64>], hue: Color) {112 board.rect(frame.x, frame.y, frame.w, frame.h, ink::line());113 let gap = 3.0;114 for (row, cells) in frame.rows(LEVELS).iter().zip(grid) {115 let w = row.w / BINS as f64;116 for (i, t) in cells.iter().enumerate() {117 let c = ink::mix(ink::panel(), hue, *t);118 board.rect(119 row.x + i as f64 * w,120 row.y + gap / 2.0,121 w + 0.5,122 row.h - gap,123 c,124 );125 }126 }127}128129fn main() -> Result<()> {130 let critical = [0, 2, 4, 6];131 let dark = [0, 2, 3, 4, 6];132 for digits in [&critical[..], &dark[..]] {133 for delta in [0.37, 1.21] {134 let (a, b) = (brute(digits, 3, delta), recursive(digits, 3, delta));135 assert!((a - b).abs() <= 1e-9 * a.max(1.0));136 }137 }138 let light = density(&critical);139 let fading = density(&dark);140 assert_eq!(light.len(), LEVELS);141 assert!(light[LEVELS - 1].iter().sum::<f64>() > 1.6 * fading[LEVELS - 1].iter().sum::<f64>());142 let mut board = Board::square();143 let frame = board.frame(0.08);144 let side = frame.w * 0.47;145 let top = Frame::new(frame.x, frame.y, side, side);146 let low = Frame::new(147 frame.x + frame.w - side,148 frame.y + frame.h - side,149 side,150 side,151 );152 panel(&mut board, &top, &light, ink::blue());153 panel(&mut board, &low, &fading, ink::orange());154 save("research-multilayers", &board)?;155 Ok(())156}