research-erdos.rs
3.7 kB · rust · 130 lines
1use figures::{ink, save, Board, Color};2use mrlyrs::core::error::Result;34const BASES: [u64; 3] = [3, 4, 5];5const LEAST: u32 = 3;6const LIMIT: u64 = 10_000_000;7const TERMS: usize = 29;8const TOTAL: usize = 24_973_824;9const FROBENIUS: usize = 4_330_731;10const MISSING: usize = 45_704;11const WIDTH: usize = 860;12const PITCH: usize = 29;13const GAP: usize = 3;14const FLOOR: f64 = 0.15;15const REACH: f64 = 0.6;1617fn powers() -> Vec<usize> {18 let mut terms: Vec<usize> = BASES19 .iter()20 .flat_map(|&b| (LEAST..).map(move |j| b.pow(j)).take_while(|&p| p <= LIMIT))21 .map(|p| p as usize)22 .collect();23 terms.sort_unstable();24 terms25}2627fn shift_or(bits: &mut [u64], a: usize, top: usize) {28 let (q, r) = (a / 64, a % 64);29 for i in (q..=top / 64).rev() {30 let mut word = bits[i - q] << r;31 if r > 0 && i > q {32 word |= bits[i - q - 1] >> (64 - r);33 }34 bits[i] |= word;35 }36}3738fn has(bits: &[u64], k: usize) -> bool {39 bits[k / 64] >> (k % 64) & 1 == 140}4142fn count(bits: &[u64], lo: usize, hi: usize) -> usize {43 if lo >= hi {44 return 0;45 }46 let (a, b) = (lo / 64, (hi - 1) / 64);47 let head = !0u64 << (lo % 64);48 let tail = !0u64 >> (63 - (hi - 1) % 64);49 if a == b {50 return (bits[a] & head & tail).count_ones() as usize;51 }52 let inner: u32 = bits[a + 1..b].iter().map(|w| w.count_ones()).sum();53 (inner + (bits[a] & head).count_ones() + (bits[b] & tail).count_ones()) as usize54}5556fn shares(bits: &[u64], total: usize) -> Vec<f64> {57 let span = total + 1;58 let mut row = vec![0.0; WIDTH];59 for c in 0..WIDTH / 2 {60 let (lo, hi) = if span >= WIDTH {61 (c * span / WIDTH, ((c + 1) * span).div_ceil(WIDTH))62 } else {63 let k = (2 * c + 1) * span / (2 * WIDTH);64 (k, k + 1)65 };66 let share = count(bits, lo, hi) as f64 / (hi - lo) as f64;67 row[c] = share;68 row[WIDTH - 1 - c] = share;69 }70 row71}7273fn tone(share: f64) -> Option<Color> {74 if share >= 1.0 {75 Some(ink::blue())76 } else if share > 0.0 {77 Some(ink::mix(ink::ground(), ink::dim(), FLOOR + REACH * share))78 } else {79 None80 }81}8283fn paint(board: &mut Board, row: &[f64], x: usize, y: usize, h: usize) {84 let mut start = 0;85 for c in 1..=row.len() {86 if c < row.len() && tone(row[c]) == tone(row[start]) {87 continue;88 }89 if let Some(tone) = tone(row[start]) {90 board.rect(91 (x + start) as f64,92 y as f64,93 (c - start) as f64,94 h as f64,95 tone,96 );97 }98 start = c;99 }100}101102fn main() -> Result<()> {103 let terms = powers();104 assert_eq!(terms.len(), TERMS);105 assert_eq!((terms[0], terms[TERMS - 1]), (27, 9_765_625));106 let mut board = Board::square();107 let x = (board.width - WIDTH) / 2;108 let top = (board.height - (TERMS * PITCH - GAP)) / 2;109 let mut bits = vec![0u64; TOTAL / 64 + 2];110 bits[0] = 1;111 let mut total = 0;112 for (n, &a) in terms.iter().enumerate() {113 total += a;114 shift_or(&mut bits, a, total);115 assert!(has(&bits, 0) && has(&bits, total));116 let row = shares(&bits, total);117 paint(&mut board, &row, x, top + n * PITCH, PITCH - GAP);118 }119 assert_eq!(total, TOTAL);120 assert!((0..=TOTAL / 2).all(|k| has(&bits, k) == has(&bits, TOTAL - k)));121 let hole = (0..=TOTAL / 2).rev().find(|&k| !has(&bits, k));122 assert_eq!(hole, Some(FROBENIUS));123 assert_eq!(FROBENIUS - count(&bits, 1, FROBENIUS + 1), MISSING);124 assert_eq!(125 count(&bits, FROBENIUS + 1, TOTAL - FROBENIUS),126 TOTAL - 2 * FROBENIUS - 1127 );128 save("research-erdos", &board)?;129 Ok(())130}