modes.rs
3.6 kB · rust · 107 lines
1use mrlydemo::modes::*;2use mrlydemo::two::two_grid;3use std::f64::consts::TAU;45fn direct(6 code: &str,7 number: usize,8 level: usize,9 base: usize,10 t1: usize,11 t2: usize,12) -> (f64, f64) {13 let grid = two_grid(code, number, level, 0, base).unwrap();14 let span = grid.width as usize;15 let (mut re, mut im) = (0.0, 0.0);16 for x1 in 0..span {17 for x2 in 0..span {18 if grid.types[x1 * span + x2] == 0 {19 continue;20 }21 let angle = TAU * ((t1 * x1 + t2 * x2) % span) as f64 / span as f64;22 re += angle.cos();23 im += angle.sin();24 }25 }26 (re, im)27}2829fn gap(code: &str, number: usize, level: usize, base: usize) -> f64 {30 let span = number.pow(level as u32);31 let mass = f64::from(32 two_grid(code, number, 1, 0, base)33 .unwrap()34 .types35 .iter()36 .map(|&b| u32::from(b != 0))37 .sum::<u32>(),38 )39 .powi(level as i32);40 let field = modes_field(code, number, level, base).unwrap();41 assert_eq!(field.len(), span * span);42 let mut worst: f64 = 0.0;43 for t1 in 0..span {44 for t2 in 0..span {45 let (re, im) = direct(code, number, level, base, t1, t2);46 let read = modes_value(code, number, level, base, t1, t2).unwrap();47 worst = worst.max((read[0] - re).abs());48 worst = worst.max((read[1] - im).abs());49 worst = worst.max((read[2] - re.hypot(im) / mass).abs());50 worst = worst.max((f64::from(field[t1 * span + t2]) - re.hypot(im) / mass).abs());51 }52 }53 worst54}5556#[test]57fn the_product_formula_is_the_masks_transform() {58 assert!(gap("7", 2, 3, 2) < 1e-6);59 assert!(gap("9", 2, 3, 2) < 1e-6);60 assert!(gap("495", 3, 2, 3) < 1e-6);61 assert!(gap("127", 3, 2, 3) < 1e-6);62}6364#[test]65fn the_modes_exports_answer() {66 let gasket = modes_field("7", 2, 3, 2).unwrap();67 let carpet = modes_field("495", 3, 2, 3).unwrap();68 let runner = modes_field("127", 3, 2, 3).unwrap();69 let top = |field: &[f32]| format!("{:.6}", field[1..].iter().copied().fold(f32::MIN, f32::max));70 assert_eq!(format!("{},{}", gasket.len(), carpet.len()), "64,81");71 assert_eq!(format!("{},{}", gasket[0], carpet[0]), "1,1");72 assert_eq!(format!("{:.6}", gasket[1]), "0.231717");73 assert_eq!(top(&gasket), "0.333333");74 assert_eq!(format!("{:.6}", carpet[1]), "0.103067");75 assert_eq!(top(&carpet), "0.125000");76 assert_eq!(format!("{:.6}", runner[9]), "0.253018");77 assert_eq!(top(&runner), "0.285714");7879 assert_eq!(modes_large("9", 2, 3, 2, 0.5).unwrap(), 8);80 assert_eq!(modes_large("7", 2, 3, 2, 0.25).unwrap(), 4);81 assert_eq!(modes_large("495", 3, 2, 3, 0.1).unwrap(), 13);82 assert_eq!(modes_large("127", 3, 2, 3, 0.1).unwrap(), 17);83 assert_eq!(modes_large("495", 3, 5, 3, 0.1).unwrap(), 25);8485 let one = modes_value("495", 3, 2, 3, 1, 1).unwrap();86 assert_eq!(87 format!("{:.6},{:.6},{:.6}", one[0], one[1], one[2]),88 "-4.145430,3.478429,0.084554"89 );90 let two = modes_value("127", 3, 2, 3, 1, 2).unwrap();91 assert_eq!(92 format!("{:.6},{:.6},{:.6}", two[0], two[1], two[2]),93 "3.145430,-1.508813,0.071196"94 );9596 let mode = modes_pattern("495", 3, 2, 3, 1, 2).unwrap();97 assert_eq!(format!("{},{}", mode.len(), mode[0]), "81,1");98 assert_eq!(modes_digits("495", 3, 3).unwrap(), 8);99 assert_eq!(modes_digits("127", 3, 3).unwrap(), 7);100 assert_eq!(modes_digits("7", 2, 2).unwrap(), 3);101}102103#[test]104fn the_torus_is_capped_and_the_empty_design_refused() {105 assert!(modes_field("495", 3, 6, 3).is_err());106 assert!(modes_field("0", 3, 2, 3).is_err());107}