research-dimensions.rs
3.1 kB · rust · 115 lines
1use mrlycore::errors::Result;2use mrlyfig::{ink, plot, save, Board};34const RE_LO: f64 = -1.0;5const RE_HI: f64 = 1.0;6const IM_REACH: f64 = 40.0;78fn cexp(z: (f64, f64)) -> (f64, f64) {9 let e = z.0.exp();10 (e * z.1.cos(), e * z.1.sin())11}1213fn cdiv(a: (f64, f64), b: (f64, f64)) -> (f64, f64) {14 let d = b.0 * b.0 + b.1 * b.1;15 ((a.0 * b.0 + a.1 * b.1) / d, (a.1 * b.0 - a.0 * b.1) / d)16}1718fn power(base: f64, s: (f64, f64)) -> (f64, f64) {19 let l = base.ln();20 cexp((-s.0 * l, -s.1 * l))21}2223fn residual(s: (f64, f64)) -> (f64, f64) {24 let a = power(3.0, s);25 let b = power(5.0, s);26 (a.0 + b.0 - 1.0, a.1 + b.1)27}2829fn slope(s: (f64, f64)) -> (f64, f64) {30 let a = power(3.0, s);31 let b = power(5.0, s);32 let (l3, l5) = (3f64.ln(), 5f64.ln());33 (-l3 * a.0 - l5 * b.0, -l3 * a.1 - l5 * b.1)34}3536fn newton(seed: (f64, f64)) -> Option<(f64, f64)> {37 let mut s = seed;38 for _ in 0..80 {39 if s.0.abs() > 6.0 || s.1.abs() > 200.0 {40 return None;41 }42 let d = slope(s);43 if d.0.hypot(d.1) < 1e-14 {44 return None;45 }46 let step = cdiv(residual(s), d);47 s = (s.0 - step.0, s.1 - step.1);48 }49 let r = residual(s);50 if r.0.hypot(r.1) > 1e-10 {51 return None;52 }53 if s.0 < RE_LO || s.0 > RE_HI || s.1.abs() > IM_REACH {54 return None;55 }56 Some(s)57}5859fn control_poles() -> Vec<(f64, f64)> {60 let mut out: Vec<(f64, f64)> = Vec::new();61 for i in 0..=80 {62 for j in 0..=320 {63 let seed = (64 RE_LO + (RE_HI - RE_LO) * i as f64 / 80.0,65 -IM_REACH + 2.0 * IM_REACH * j as f64 / 320.0,66 );67 if let Some(root) = newton(seed) {68 if !out69 .iter()70 .any(|p| (p.0 - root.0).hypot(p.1 - root.1) < 1e-6)71 {72 out.push(root);73 }74 }75 }76 }77 out78}7980fn main() -> Result<()> {81 let real = 2f64.ln() / 3f64.ln();82 let omega = 2.0 * std::f64::consts::PI / 3f64.ln();83 let lattice: Vec<(f64, f64)> = (-6..=6).map(|m| (real, m as f64 * omega)).collect();84 let control = control_poles();85 assert_eq!(lattice.len(), 13);86 assert_eq!(control.len(), 21);8788 let mut board = Board::square();89 let frame = board.frame(0.08);90 plot::axis(&mut board, frame, ink::line());91 let at = |re: f64, im: f64| {92 (93 frame.x + frame.w * (re - RE_LO) / (RE_HI - RE_LO),94 frame.y + frame.h * (1.0 - (im + IM_REACH) / (2.0 * IM_REACH)),95 )96 };97 board.segment(at(0.0, -IM_REACH), at(0.0, IM_REACH), 1.6, ink::line());98 board.segment(at(RE_LO, 0.0), at(RE_HI, 0.0), 1.6, ink::line());99 board.segment(100 at(real, -IM_REACH),101 at(real, IM_REACH),102 1.8,103 ink::fade(ink::blue(), 0.35),104 );105 for pole in &control {106 let (x, y) = at(pole.0, pole.1);107 board.disc(x, y, 7.0, ink::orange());108 }109 for pole in &lattice {110 let (x, y) = at(pole.0, pole.1);111 board.disc(x, y, 9.0, ink::blue());112 }113 save("research-dimensions", &board)?;114 Ok(())115}