paper-erdos-125-upper-density.rs
4.2 kB · rust · 149 lines
1use figures::{ink, save, Board};2use mrlyrs::core::error::Result;3use mrlyrs::num::sumset::Pair;45const LEVEL: u32 = 6;6const SAMPLES: usize = 3072;78// THE MEASURE910fn cantor(mut y: f64) -> f64 {11 let mut out = 0.0;12 let mut w = 1.0;13 for _ in 0..40 {14 if y < 0.0 {15 return out;16 }17 if y >= 0.5 {18 return out + w;19 }20 y *= 3.0;21 w /= 2.0;22 if y >= 0.5 {23 out += w;24 y -= 1.0;25 }26 }27 out + w / 2.028}2930fn energy(tau: f64, level: u32) -> f64 {31 let t = tau * 3f64.powi(level as i32);32 let digits = (t.log(4.0).ceil() as i32).max(0) + 7;33 let mut atoms = vec![0.0f64];34 for l in 1..=digits {35 let step = t * 4f64.powi(-l);36 let more: Vec<f64> = atoms.iter().map(|c| c + step).collect();37 atoms.extend(more);38 }39 let tail = t * 4f64.powi(-digits) / 6.0;40 let weight = 1.0 / atoms.len() as f64;41 let mut p = vec![0.0f64; (t / 3.0).ceil() as usize + 3];42 for c in atoms {43 let c = c + tail;44 let n = c.floor();45 let g = cantor(n + 1.0 - c);46 p[n as usize] += weight * g;47 p[n as usize + 1] += weight * (1.0 - g);48 }49 for j in 0..level {50 let s = 3usize.pow(j);51 let mut q = vec![0.0f64; p.len() + s];52 for (i, v) in p.iter().enumerate() {53 q[i] += v / 2.0;54 q[i + s] += v / 2.0;55 }56 p = q;57 }58 3f64.powi(level as i32) * p.iter().map(|v| v * v).sum::<f64>()59}6061fn chain(k: u32) -> Pair {62 let p = 3u64.pow(k);63 let mut m = 0;64 while 4u64.pow(m) < p {65 m += 1;66 }67 Pair { three: k, four: m }68}6970// THE CHECKS7172fn lattice(pair: Pair) -> f64 {73 3f64.powi(pair.three as i32) * pair.energy() as f64 / 4f64.powi((pair.three + pair.four) as i32)74}7576fn main() -> Result<()> {77 let taus: Vec<f64> = (0..=SAMPLES)78 .map(|i| 4f64.powf(i as f64 / SAMPLES as f64))79 .collect();80 let curves: Vec<Vec<f64>> = (0..=LEVEL)81 .map(|k| taus.iter().map(|&t| energy(t, k)).collect())82 .collect();83 assert_eq!(curves[0][0], 1.0);84 assert_eq!(curves[0][SAMPLES], 0.5);85 for k in 0..LEVEL as usize {86 assert!((0..=SAMPLES).all(|i| curves[k + 1][i] >= curves[k][i] - 1e-12));87 }88 for hs in &curves {89 let area: f64 = (0..SAMPLES)90 .map(|i| (taus[i + 1] - taus[i]) * (hs[i] + hs[i + 1]) / 2.0)91 .sum();92 assert!(area > 2.0 && area < 4.0);93 }9495 let orbit: Vec<(f64, f64)> = (0..=LEVEL)96 .map(|k| {97 if k == 0 {98 return (1.0, energy(1.0, 0));99 }100 let pair = chain(k);101 let tau = pair.scale();102 assert!((1.0..4.0).contains(&tau));103 let h = energy(tau, k);104 assert!((h - lattice(pair)).abs() < 1e-12 * h);105 (tau, h)106 })107 .collect();108 for k in 0..LEVEL as usize {109 let step = orbit[k + 1].1 / orbit[k].1;110 assert!((9.0 / 16.0..=4.5).contains(&step));111 }112 let least = chain(6);113 assert_eq!(least.four, 5);114 assert!((least.ratio(least.energy()) - 858849.0 / 524288.0).abs() < 1e-15);115116 let mut board = Board::square();117 let frame = board.frame(0.08);118 let lo = 0.5 * 0.92;119 let hi = curves[LEVEL as usize]120 .iter()121 .copied()122 .fold(0.0f64, f64::max)123 * 1.03;124 let at = |tau: f64, h: f64| {125 (126 frame.x + frame.w * tau.log(4.0),127 frame.y + frame.h * (hi - h) / (hi - lo),128 )129 };130 let foot = frame.y + frame.h;131 for &(tau, h) in &orbit {132 let (x, y) = at(tau, h);133 board.segment((x, foot), (x, y), 1.4, ink::line());134 }135 board.segment((frame.x, foot), (frame.x + frame.w, foot), 1.4, ink::line());136 for (k, hs) in curves.iter().enumerate() {137 let pts: Vec<(f64, f64)> = taus.iter().zip(hs).map(|(&t, &h)| at(t, h)).collect();138 let t = k as f64 / LEVEL as f64;139 let color = ink::mix(ink::dim(), ink::blue(), t * t);140 board.polyline(&pts, 1.3 + 1.3 * t, color);141 }142 for &(tau, h) in &orbit {143 let (x, y) = at(tau, h);144 board.disc(x, y, 9.0, ink::ground());145 board.disc(x, y, 6.5, ink::orange());146 }147 save("paper-erdos-125-upper-density", &board)?;148 Ok(())149}