paper-sparse-mertens-under-grh.rs

2.3 kB · rust · 76 lines

1use mrlycore::errors::Result;2use mrlyfig::{ink, save, Board, Ramp};34const BASE: i64 = 7;5const DROP: i64 = 3;6const LEVEL: u32 = 3;78fn kept() -> Vec<i64> {9    (0..BASE).filter(|d| *d != DROP).collect()10}1112fn symbol(kept: &[i64], t: f64) -> f64 {13    let (mut re, mut im) = (0.0, 0.0);14    for d in kept {15        let angle = std::f64::consts::TAU * (*d as f64) * t;16        re += angle.cos();17        im += angle.sin();18    }19    re.hypot(im)20}2122fn transform(kept: &[i64], a: i64, span: i64) -> f64 {23    let mut mass = 1.0;24    let mut scale = 1i64;25    for _ in 0..LEVEL {26        let t = (a * scale).rem_euclid(span) as f64 / span as f64;27        mass *= symbol(kept, t);28        scale *= BASE;29    }30    mass31}3233fn proved() -> f64 {34    let q = BASE as f64;35    let n = ((BASE - 2) as f64 / 2.0).ceil();36    let harmonic = n.ln() + 0.577_215_664_901_532_9 + 1.0 / (2.0 * n);37    let pi = std::f64::consts::PI;38    let phi = (4.0 / pi) * q + (2.0 * q / pi) * harmonic + (1.0 - 2.0 / pi) * (q - 2.0) + 0.727;39    1.0 + phi / q40}4142fn main() -> Result<()> {43    let kept = kept();44    let span = BASE.pow(LEVEL);45    let peak = (kept.len() as f64).powi(LEVEL as i32);46    let half = (span - 1) / 2;47    let mass: Vec<f64> = (-half..=half).map(|a| transform(&kept, a, span)).collect();4849    assert_eq!(mass.len(), span as usize);50    assert_eq!(kept.len() as i64, BASE - 1);51    assert!((mass[half as usize] - peak).abs() < 1e-9);52    let energy: f64 = mass.iter().map(|v| v * v).sum();53    assert!((energy - span as f64 * peak).abs() < 1e-6 * span as f64 * peak);54    let total: f64 = mass.iter().sum();55    assert!(total < (BASE as f64 * proved()).powi(LEVEL as i32));56    assert!(total >= span as f64);5758    let mut board = Board::square();59    let frame = board.frame(0.07);60    let ramp = Ramp::tone(ink::blue(), ink::yellow());61    let slot = frame.w / mass.len() as f64;62    let pad = slot * 0.18;63    let axis = frame.y + frame.h / 2.0;64    for (i, value) in mass.iter().enumerate() {65        let reach = frame.h / 2.0 * (value / peak).powf(1.0 / LEVEL as f64);66        board.rect(67            frame.x + i as f64 * slot + pad,68            axis - reach,69            slot - 2.0 * pad,70            2.0 * reach,71            ramp.at(2.0 * reach / frame.h),72        );73    }74    save("paper-sparse-mertens-under-grh", &board)?;75    Ok(())76}