demo-echo.rs

3.2 kB · rust · 108 lines

1use mrlycore::errors::Result;2use mrlyfig::{ink, plot, save, Board, Frame};3use mrlynum::design;45const BASE: u64 = 10;6const DIGITS: [u64; 9] = [0, 1, 2, 3, 4, 5, 6, 7, 8];7const DEPTH: usize = 5;8const SAMPLES: usize = 4096;9const FLOOR: usize = 101;10const BAND: (f64, f64) = (4.0, 60.0);11const THRESHOLD: f64 = 8.0;1213fn column(board: &mut Board, frame: Frame, x: f64, thick: f64, color: mrlycore::Color, dash: f64) {14    if dash <= 0.0 {15        board.segment((x, frame.y), (x, frame.y + frame.h), thick, color);16        return;17    }18    let mut y = frame.y;19    while y < frame.y + frame.h {20        let end = (y + dash).min(frame.y + frame.h);21        board.segment((x, y), (x, end), thick, color);22        y = end + dash * 0.8;23    }24}2526fn main() -> Result<()> {27    let values = design::elements(BASE, &DIGITS, DEPTH);28    let mu = design::mobius_of(&values);29    let running = design::meter(&mu);30    assert_eq!(values.len(), 59048);31    assert_eq!(running[values.len() - 1], 201);3233    let alpha = (DIGITS.len() as f64).ln() / (BASE as f64).ln();34    let logx = design::log_grid(&values, SAMPLES);35    let series = design::resample(&values, &running, alpha / 2.0, &logx);36    let (gamma, power) = design::spectrum(&logx, &series);37    let score = design::score(&power, FLOOR);38    let found = design::peaks(&gamma, &score, BAND, THRESHOLD);39    let bin = gamma[1];40    let zeros: Vec<f64> = design::ZETA_ORDINATES41        .iter()42        .copied()43        .filter(|g| *g > BAND.0 && *g < BAND.1)44        .collect();45    let lattice: Vec<f64> = design::pole_lattice(BASE, BAND.1)46        .into_iter()47        .filter(|g| *g > BAND.0)48        .collect();49    assert_eq!(found.len(), 5);50    assert_eq!(zeros.len(), 13);51    assert_eq!(lattice.len(), 20);52    assert_eq!(53        found54            .iter()55            .filter(|&&at| design::nearest(gamma[at], &zeros) <= bin)56            .count(),57        558    );5960    let mut board = Board::square();61    let frame = board.frame(0.08);62    let peak = found63        .iter()64        .map(|&at| score[at])65        .fold(0.0f64, |top, value| top.max(value));66    let x = |g: f64| frame.x + frame.w * (g - BAND.0) / (BAND.1 - BAND.0);67    let y = |v: f64| frame.y + frame.h * (1.0 - (v / peak).clamp(0.0, 1.0).sqrt());6869    for line in &lattice {70        column(71            &mut board,72            frame,73            x(*line),74            3.0,75            ink::fade(ink::pink(), 0.34),76            13.0,77        );78    }79    for zero in &zeros {80        column(81            &mut board,82            frame,83            x(*zero),84            7.0,85            ink::fade(ink::yellow(), 0.46),86            0.0,87        );88    }89    plot::baseline(&mut board, frame, ink::line());90    for at in 0..gamma.len() {91        if gamma[at] <= BAND.0 || gamma[at] >= BAND.1 {92            continue;93        }94        board.segment(95            (x(gamma[at]), frame.y + frame.h),96            (x(gamma[at]), y(score[at])),97            4.0,98            ink::blue(),99        );100    }101    let crowns: Vec<(f64, f64)> = found102        .iter()103        .map(|&at| (x(gamma[at]), y(score[at])))104        .collect();105    plot::dots(&mut board, &crowns, 11.0, ink::yellow());106    save("demo-echo", &board)?;107    Ok(())108}