fixture.rs
68.4 kB · rust · 1763 lines
1use demos::automata::*;2use demos::bang::*;3use demos::blend::*;4use demos::census::*;5use demos::gauss::*;6use demos::graph::*;7use demos::lab::*;8use demos::lattice::*;9use demos::ledger::*;10use demos::life::*;11use demos::magic::*;12use demos::morse::*;13use demos::partials::*;14use demos::prime::*;15use demos::race::Race;16use demos::sieve::*;17use demos::six::*;18use demos::spectrum::*;19use demos::spin::*;20use demos::spiral::*;21use demos::three::*;22use demos::tile::*;23use demos::two::*;24use demos::volume::*;25use demos::zeta::*;26use mrlyrs::core::colors::{Color, DARK};27use mrlyrs::core::error::parse;2829fn column(rows: &mrlyrs::core::Json, key: &str) -> String {30 rows.as_array()31 .unwrap()32 .iter()33 .map(|row| row[key].to_string())34 .collect::<Vec<String>>()35 .join(",")36}3738fn ink(c: Color) -> [u8; 3] {39 [c.r, c.g, c.b]40}4142fn blinker() -> Vec<u8> {43 let mut types = vec![0u8; 25];44 for site in [7, 12, 17] {45 types[site] = 1;46 }47 types48}4950#[test]51fn the_fixture_the_page_prints() {52 let grid = two_grid("7", 3, 3, 0, 2).unwrap();53 assert_eq!((grid.width, grid.height), (27, 27));54 assert_eq!(grid.types.iter().map(|&b| b as usize).sum::<usize>(), 512);55 assert_eq!(fills("23", 3, 3, 3, 2).unwrap(), "8000");56 assert_eq!(voids("23", 3, 3, 3, 2).unwrap(), "11683");57 assert_eq!(counting_sequence(4).unwrap(), ["3", "6", "22", "402"]);58 assert_eq!(baseq_sequence(3, 2).unwrap(), ["4", "26"]);59 assert_eq!(classes_sequence(4), ["4", "12", "64", "700"]);60 let faces = three_faces("23", 3, 3, 2).unwrap();61 assert_eq!(faces[0] as usize / 36, 18048);62 assert_eq!(faces.len(), 2 + faces[0] as usize);63 assert_eq!(three_surface("23", 3, 3, 2).unwrap(), "18048");64 assert_eq!(three_cells("23", 3, 1, 2).unwrap().len() / 3, 20);65 let tally = parse(&three_census("23", 3, 1, 2).unwrap()).unwrap();66 assert_eq!(67 (tally["fills"].clone(), tally["euler"].clone()),68 (20.into(), (-4).into())69 );70 assert_eq!(parse(&universe(3).unwrap()).unwrap()["distinct"], 22);71 assert_eq!(72 parse(&universe(2).unwrap()).unwrap()["designs"][1]["orbit"],73 474 );75 assert_eq!(76 name_of("127", 2, 3).unwrap(),77 "bang dim 2, base 3, code 127"78 );79 assert_eq!(80 parse(&name_parse("bang_dim=3_code=23").unwrap()).unwrap()["code"],81 "23"82 );83 assert_eq!(84 press_members("2", 1, 2, 5).unwrap(),85 ["1", "3", "7", "15", "31"]86 );87 assert_eq!(press_count_below("7", 2, 2, "27").unwrap(), "18");88 let run = parse(&life_run(&blinker(), 5, 5, &[3], &[2, 3], false, 16).unwrap()).unwrap();89 assert_eq!(90 (run["fate"].clone(), run["loop"].clone()),91 ("loop".into(), 2.into())92 );93 assert_eq!(life_sequence("primes", 8).unwrap(), vec![2, 3, 5, 7]);94 assert_eq!(95 moire("heatmap", 9, 32, "fire", 64, false)96 .unwrap()97 .rgba98 .len(),99 4096100 );101 assert!(hex_svg("23", 3, 1, 2, "iso", 10)102 .unwrap()103 .contains("<polygon"));104 let slice = parse(&slice_census("23", 3, 1, 2).unwrap()).unwrap();105 assert_eq!(106 (slice["triangles"].clone(), slice["fills"].clone()),107 (54.into(), 42.into())108 );109 assert_eq!(110 (slice["vertices"].clone(), slice["euler"].clone()),111 (37.into(), 1.into())112 );113 assert_eq!(114 (slice["components"].clone(), slice["holes"].clone()),115 (1.into(), 1.into())116 );117 assert_eq!(slice["closed"]["vertices"], "37");118 assert_eq!(119 parse(&slice_census("232", 3, 1, 2).unwrap()).unwrap()["fills"],120 12121 );122 let deep = parse(&slice_census("23", 3, 2, 2).unwrap()).unwrap();123 assert_eq!(124 (deep["fills"].clone(), deep["holes"].clone()),125 (306.into(), 7.into())126 );127 let series = parse(&slice_series("23", 6).unwrap()).unwrap();128 let column = |key: &str| {129 series130 .as_array()131 .unwrap()132 .iter()133 .map(|row| row[key].to_string())134 .collect::<Vec<String>>()135 .join(",")136 };137 assert_eq!(column("components"), "1,1,7,1,19,1");138 assert_eq!(column("holes"), "0,1,0,7,0,19");139 let carpet = parse(&walsh_spectrum("23", 6).unwrap()).unwrap();140 assert_eq!(carpet["spectrum"].to_string(), "[0,-4,-4,0,-4,0,0,4]");141 assert_eq!(carpet["weights"].to_string(), "[1,3,0,0]");142 assert_eq!(crate::column(&carpet["levels"], "sixteenths"), "8,12,0,-4");143 assert_eq!(144 crate::column(&carpet["law"], "fills"),145 "6,42,72,204,210,486"146 );147 assert_eq!(crate::column(&carpet["law"], "s"), "-1,1,-1,1,-1,1");148 let skew = parse(&walsh_spectrum("11", 6).unwrap()).unwrap();149 assert_eq!(skew["spectrum"].to_string(), "[2,2,-2,-2,-6,2,-2,-2]");150 assert_eq!(skew["weights"].to_string(), "[1,1,1,0]");151 assert_eq!(crate::column(&skew["levels"], "sixteenths"), "6,6,2,2");152 assert_eq!(crate::column(&skew["law"], "fills"), "6,20,76,100,230,240");153 for design in [&carpet, &skew] {154 let code = design["code"].as_str().unwrap();155 let counted = (1..=6)156 .map(|k| {157 parse(&slice_census(code, 2 * k - 1, 1, 2).unwrap()).unwrap()["fills"].to_string()158 })159 .collect::<Vec<String>>()160 .join(",");161 assert_eq!(crate::column(&design["law"], "fills"), counted);162 }163 let flat = parse(&spectrum("flat", "7", 2, 4, true, 0.1).unwrap()).unwrap();164 assert_eq!(165 (flat["nodes"].clone(), flat["distinct"].clone()),166 (81.into(), 43.into())167 );168 assert_eq!(169 (flat["classes"].clone(), flat["one"].clone()),170 (9.into(), 27.into())171 );172 assert_eq!(flat["pair"], parse("[4,4]").unwrap());173 let piece = parse(&spectrum("slice", "23", 3, 1, true, 0.1).unwrap()).unwrap();174 assert_eq!(piece["nodes"], 42);175 let stair = piece["stair"].as_array().unwrap();176 assert_eq!(stair.last().unwrap()[1], 1.0);177 assert!(stair.len() >= piece["distinct"].as_u64().unwrap() as usize && stair.len() < 42);178 assert_eq!(piece["fitted"], 4);179 assert_eq!(180 format!("{:.2}", piece["exponent"].as_f64().unwrap()),181 "0.91"182 );183 assert_eq!(184 format!("{:.4}", piece["fit"][1].as_f64().unwrap() * 2.0),185 format!("{:.4}", piece["exponent"].as_f64().unwrap())186 );187 let plain = parse(&spectrum("flat", "7", 2, 2, false, 0.1).unwrap()).unwrap();188 assert_eq!(189 (plain["nodes"].clone(), plain["distinct"].clone()),190 (9.into(), 8.into())191 );192 assert_eq!(193 (plain["classes"].clone(), plain["one"].clone()),194 (1.into(), 2.into())195 );196 let cut = parse(&diagonal_profile("126", 2, 4, 2).unwrap()).unwrap();197 assert_eq!(cut["side"], 16);198 assert_eq!(cut["support"], parse("[15,30]").unwrap());199 assert_eq!(cut["central"], parse("[22,23]").unwrap());200 assert_eq!(201 (cut["min"].clone(), cut["max"].clone()),202 ("81".into(), "81".into())203 );204 assert_eq!(cut["constant"], true);205 assert_eq!(diagonal_count("126", 2, 7, 2, 190).unwrap(), "2187");206 let art = diagonal_svg("126", 2, 3, 2, vec![10, 11], 4).unwrap();207 assert!(art.contains("<circle"));208 assert_eq!(art.matches("<circle").count(), 54);209 assert_eq!(210 parse(&diagonal_profile("127", 2, 4, 2).unwrap()).unwrap()["max"],211 "162"212 );213 assert_eq!(Race::new("127", 3, 4, 3, 300, 1).unwrap().side(), 81);214 assert_eq!(parse(&farey(5)).unwrap().as_array().unwrap().len(), 11);215 assert_eq!(totients(6), vec![0, 1, 1, 2, 2, 4, 2]);216 let terms: Vec<String> = (1..=8)217 .map(|n| {218 parse(&visible_read(n, 2).unwrap()).unwrap()["lit"]219 .as_str()220 .unwrap()221 .to_string()222 })223 .collect();224 assert_eq!(terms.join(","), "1,3,7,11,19,23,35,43");225 let corner = parse(&visible_read(100, 2).unwrap()).unwrap();226 assert_eq!(corner["lit"], "6087");227 assert_eq!(corner["total"], "10000");228 assert_eq!(corner["name"], "pi");229 assert!((corner["density"].as_f64().unwrap() - 0.6087).abs() < 1e-12);230 assert!((corner["limit"].as_f64().unwrap() - 0.607_927_101_8).abs() < 1e-9);231 assert!((corner["constant"].as_f64().unwrap() - 3.139_597_50).abs() < 1e-8);232 let cube = parse(&visible_read(1000, 3).unwrap()).unwrap();233 assert_eq!(cube["lit"], "832046137");234 assert_eq!(cube["name"], "zeta(3)");235 assert!((cube["constant"].as_f64().unwrap() - 1.201_856_43).abs() < 1e-8);236 let quartic = parse(&visible_read(1000, 4).unwrap()).unwrap();237 assert!((quartic["constant"].as_f64().unwrap() - 3.141_549_67).abs() < 1e-8);238 let lattice = visible_pixels(100, 200, true).unwrap();239 let blue = lattice240 .rgba241 .chunks(4)242 .filter(|dot| dot[..3] == ink(DARK.blue))243 .count();244 assert_eq!((lattice.width, lattice.height, blue), (200, 200, 4 * 6087));245 let flat = visible_pixels(100, 200, false).unwrap();246 assert_eq!(247 flat.rgba248 .chunks(4)249 .filter(|dot| dot[..3] == ink(DARK.line))250 .count(),251 4 * (10000 - 6087)252 );253 let walk = visible_walk(100, 2, 8).unwrap();254 assert_eq!(walk.len(), 16);255 assert_eq!(walk[14], 100.0);256 assert!((walk[15] - 3.139_597_50).abs() < 1e-8);257 assert!(visible_read(0, 2).is_err() && visible_read(10, 9).is_err());258 assert!((dimension("127", 3, 2, 3).unwrap() - 1.7712).abs() < 1e-4);259 let carpet: Vec<f32> = two_grid("495", 3, 3, 0, 3)260 .unwrap()261 .types262 .iter()263 .map(|&b| b as f32)264 .collect();265 let rings = profile(&carpet, 27, 1000).unwrap();266 assert_eq!(rings.len(), 1000);267 assert_eq!(rings[0], 0.0);268 assert_eq!(rings.iter().position(|&v| v > 0.0), Some(236));269 assert!((rings[600] - 0.8972).abs() < 1e-4);270 let stats = parse(&spin_stats(&rings, 27)).unwrap();271 assert!((stats["mass"].as_f64().unwrap() - 512.0).abs() < 0.1);272 assert!((stats["disc"].as_f64().unwrap() - 4.5).abs() < 0.02);273 assert_eq!(274 wheel(&rings, 64, "fire", 16, false).unwrap().rgba.len(),275 64 * 64 * 4276 );277 let hexagon = slice_grid("23", 3, 1, 2, 101).unwrap();278 assert_eq!((hexagon.width, hexagon.types[50 * 101 + 50]), (101, 0));279 let cut: Vec<f32> = hexagon.types.iter().map(|&b| b as f32).collect();280 assert_eq!(profile(&cut, 101, 10).unwrap()[0], 0.0);281 assert_eq!(282 profile(&moire_field("heatmap", 9, 32).unwrap(), 32, 16)283 .unwrap()284 .len(),285 16286 );287 let square = vec![1.0f32; 64];288 let star = radial(&square, 8, 64, 2, 45.0, "union", 1).unwrap();289 assert_eq!((star.len(), star[32 * 64 + 32]), (4096, 1.0));290 assert_eq!(turns(&harmonics(&square, 8, 64, 8).unwrap()), 4);291 assert_eq!(petals(6, 4), 12);292 assert_eq!(293 sheet(&star, 64, "heat", 8, false).unwrap().rgba.len(),294 16384295 );296 assert_eq!(moire_field("heatmap", 9, 32).unwrap().len(), 1024);297 let v = volume("23", 2, 3, "sum", 1, 9).unwrap();298 assert_eq!((v.len(), volume_count(&v, 9, 2.0).unwrap()), (729, 540));299 assert_eq!(volume_faces(&v, 9, 2.0).unwrap()[0] as usize / 36, 648);300 assert_eq!(volume_surface(&v, 9, 2.0).unwrap(), 648);301 let f = parse(&plane_frame(&[1.0, 1.0, 1.0], 0.5).unwrap()).unwrap();302 assert!((f["width"].as_f64().unwrap() - 3.2660).abs() < 1e-3);303 let cut = plane_field(&v, 9, &[1.0, 1.0, 1.0], 0.5, 64).unwrap();304 assert!(cut[0].is_nan() && cut[32 * 64 + 32] == 1.0);305 let sheet = paint_span(&cut, 64, 0.0, 2.0, "fire", 8, false).unwrap();306 assert_eq!(307 (308 sheet.rgba.len(),309 sheet.rgba[3],310 sheet.rgba[(32 * 64 + 32) * 4 + 3]311 ),312 (16384, 0, 255)313 );314 assert_eq!(parse(&volume_stats(&v, 9).unwrap()).unwrap()["max"], 2.0);315 assert_eq!(random_code(3, 2, 7).unwrap(), "84");316 assert_eq!(random_codes(3, 2, 7, 3).unwrap(), ["84", "17", "216"]);317 assert_eq!(random_between(7, &[0, 0, 1], &[3, 1800, 36]), [2, 936, 23]);318 assert_eq!(319 (320 level_cap(3, 1, 128),321 level_cap(2, 1, 512),322 level_cap(3, 3, 60000)323 ),324 (4, 9, 3)325 );326 assert_eq!(fill_cap("7", 2, 2, 2, 1100).unwrap(), 6);327 assert_eq!(grid_total(3, 2, 4).unwrap(), "6561");328 assert_eq!(odd_scales(9), [1, 3, 5, 7, 9]);329 let stack = parse(&farey_novelty(5)).unwrap();330 assert_eq!(331 (332 stack["lit"].clone(),333 stack["novel"].clone(),334 stack["match"].clone()335 ),336 (11.into(), 11.into(), true.into())337 );338 assert_eq!(stack["primes"], parse("[2,3,5]").unwrap());339 let split = parse(&slice_partition(3).unwrap()).unwrap();340 assert_eq!(341 (342 split["carpet"].clone(),343 split["net"].clone(),344 split["exact"].clone()345 ),346 (42.into(), 12.into(), true.into())347 );348 let shape = parse(&volume_shape(7, 64)).unwrap();349 assert_eq!(350 (shape["layers"].clone(), shape["voxels"].clone()),351 (4.into(), 262144.into())352 );353 assert_eq!(354 format!(355 "{:.1}",356 radial_share(&harmonics(&square, 8, 64, 8).unwrap())357 ),358 "95.3"359 );360 assert_eq!(full_turn(6), 60.0);361 assert_eq!(frame_step(900.0, 60.0), 90.0);362 assert_eq!(diagonal_digits("126", 2, 4, 2, 20).unwrap(), "101");363 assert_eq!(diagonal_total("126", 2, 3, 2, vec![10, 11]).unwrap(), "54");364 let mut sieve = Sieve::new(30).unwrap();365 let mut sweeps = 0;366 while !sieve.done() {367 sieve.step();368 sweeps += 1;369 }370 assert_eq!((sweeps, sieve.count()), (3, 10));371 let mut hundred = Sieve::new(100).unwrap();372 hundred.finish();373 assert_eq!(hundred.count(), 25);374 let stones = parse(&factor("360").unwrap()).unwrap();375 assert_eq!(stones["factors"], parse("[[2,3],[3,2],[5,1]]").unwrap());376 assert_eq!(stones["prime"], false);377 assert_eq!(378 parse(&factor("6").unwrap()).unwrap()["rectangles"],379 parse("[[1,6],[2,3]]").unwrap()380 );381 let chart = parse(&prime_chart(10_000, 400).unwrap()).unwrap();382 assert_eq!(chart["pi"].as_array().unwrap().last().unwrap(), 1229);383 let wide = parse(&prime_chart(100_000, 100).unwrap()).unwrap();384 assert_eq!(wide["pi"].as_array().unwrap().last().unwrap(), 9592);385 let square = parse(&carpet_witness(169).unwrap()).unwrap();386 assert!((square["max"].as_f64().unwrap() - 0.0517383).abs() < 1e-7);387 assert_eq!(square["at"], 13);388 let clear = parse(&carpet_witness(197).unwrap()).unwrap();389 assert_eq!(390 (clear["max"].clone(), clear["prime"].clone()),391 (0.0.into(), true.into())392 );393 assert_eq!(clear["row"].as_array().unwrap().len(), 97);394}395396#[test]397fn the_rest_of_the_exports_answer() {398 assert_eq!(399 parse(&two_census("7", 3, 1, 0, 2).unwrap()).unwrap()["voids"],400 1401 );402 assert!((ratio("23", 3, 3, 3, 2).unwrap() - 8000.0 / 19683.0).abs() < 1e-12);403 let next = life_next(&blinker(), 5, 5, &[3], &[2, 3], false).unwrap();404 assert_eq!(&next[10..15], &[0, 1, 1, 1, 0]);405 assert_eq!(life_noise(8, 8, 0.0, 1).iter().sum::<u8>(), 0);406 assert_eq!(life_noise(8, 8, 1.0, 1).iter().sum::<u8>(), 64);407 assert_eq!(life_noise(64, 64, 0.5, 7), life_noise(64, 64, 0.5, 7));408 assert_eq!(life_sequences().len(), 23);409 assert_eq!(moire_names(), ["heatmap", "weave", "hive", "carpet"]);410 let mut race = Race::new("239", 3, 3, 3, 40, 9).unwrap();411 let mut twin = Race::new("239", 3, 3, 3, 40, 9).unwrap();412 assert_eq!(race.step(30), twin.step(30));413 assert_eq!(race.positions(), twin.positions());414 assert_eq!(race.steps(), 30);415 assert!(race.distance() > 0.0);416 assert!(race417 .positions()418 .iter()419 .all(|&p| race.types()[p as usize] != 0));420 assert!(race.trail().iter().map(|&v| v as usize).sum::<usize>() <= 40 * 30);421 assert_eq!(race.home(), Race::new("239", 3, 3, 3, 1, 1).unwrap().home());422 let mut sieve = Sieve::new(150).unwrap();423 assert_eq!(sieve.step(), 2);424 assert_eq!((sieve.struck(), sieve.rank(), sieve.count()), (74, 1, 1));425 sieve.finish();426 let sheet = sieve.grid(15).unwrap();427 assert_eq!((sheet.width, sheet.height), (15, 10));428 assert_eq!(sheet.types.iter().map(|&b| b as u32).sum::<u32>(), 35);429 assert_eq!(&sheet.types[..7], &[0, 1, 1, 0, 1, 0, 1]);430}431432#[test]433fn the_faults_come_back_as_messages() {434 assert!(two_grid("16", 3, 1, 0, 2).is_err());435 assert!(two_grid("7.5", 3, 1, 0, 2).is_err());436 assert!(three_cells("256", 3, 1, 2).is_err());437 assert!(universe(4).is_err());438 assert!(name_of("16", 2, 2).is_err());439 assert!(name_parse("sequence_dim=3_code=23_measure=fills_axis=side").is_err());440 assert!(press_members("16", 2, 2, 5).is_err());441 assert!(press_count_below("7", 2, 2, "x").is_err());442 assert!(life_next(&blinker(), 4, 5, &[3], &[2, 3], false).is_err());443 assert!(life_sequence("soup", 8).is_err());444 assert!(moire("soup", 9, 32, "fire", 64, false).is_err());445 assert!(profile(&[1.0; 60], 8, 10).is_err());446 assert!(moire_field("soup", 9, 32).is_err());447 assert!(wheel(&[1.0, 0.0], 0, "fire", 8, false).is_err());448 assert!(radial(&[1.0; 64], 8, 64, 2, 45.0, "soup", 1).is_err());449 assert!(radial(&[1.0; 60], 8, 64, 2, 45.0, "mean", 1).is_err());450 assert!(harmonics(&[1.0; 60], 8, 16, 4).is_err());451 assert!(volume("23", 2, 3, "soup", 1, 9).is_err());452 assert!(volume_faces(&[1.0; 8], 3, 1.0).is_err());453 assert!(plane_frame(&[0.0, 0.0, 0.0], 0.5).is_err());454 assert!(plane_frame(&[1.0, 1.0], 0.5).is_err());455 assert!(paint_span(&[1.0; 8], 3, 0.0, 1.0, "fire", 8, false).is_err());456 assert!(hex_svg("256", 3, 1, 2, "iso", 10).is_err());457 assert!(slice_census("23", 4, 1, 2).is_err());458 assert!(slice_series("23", 17).is_err());459 assert!(walsh_spectrum("256", 6).is_err());460 assert!(walsh_spectrum("23", 17).is_err());461 assert!(diagonal_profile("0", 2, 2, 2).is_err());462 assert!(diagonal_count("126", 2, 0, 2, 1).is_err());463 assert!(Race::new("0", 3, 2, 3, 4, 1).is_err());464 assert!(spectrum("flat", "7", 2, 7, true, 0.1).is_err());465 assert!(spectrum("wobble", "7", 2, 2, true, 0.1).is_err());466 assert!(random_code(3, 6, 1).is_err());467 assert!(fill_cap("256", 3, 3, 2, 10).is_err());468 assert!(grid_total(3, 3, 40).is_err());469 assert!(diagonal_digits("0", 2, 2, 2, 1).is_err());470 assert!(Sieve::new(401).is_err());471 assert!(Sieve::new(10).unwrap().grid(0).is_err());472 assert!(factor("x").is_err());473 assert!(factor("1000000000001").is_err());474 assert!(prime_chart(1_000_001, 10).is_err());475 assert!(carpet_witness(4).is_err());476 assert!(carpet_witness(1001).is_err());477}478479#[test]480fn the_spiral_exports_answer() {481 assert_eq!(spiral_xy("square", 10).unwrap(), vec![2, -1, 2]);482 assert_eq!(spiral_xy("square", 25).unwrap(), vec![2, -2, 2]);483 assert_eq!(spiral_xy("hex", 8).unwrap(), vec![1, 1, 2]);484 assert_eq!(spiral_xy("hex", 19).unwrap(), vec![0, 2, 2]);485 assert_eq!(spiral_xy("hex", 20).unwrap(), vec![1, 2, 3]);486 let euler = parse(&spiral_polynomial("square", 201, 4, -2, 41).unwrap()).unwrap();487 assert_eq!(euler["top"], 40401);488 assert_eq!(euler["primes"], 4236);489 assert_eq!(490 (euler["count"].clone(), euler["hits"].clone()),491 (101.into(), 80.into())492 );493 assert_eq!(euler["streak"], 21);494 assert!((euler["density"].as_f64().unwrap() - 4236.0 / 40401.0).abs() < 1e-12);495 assert!((euler["share"].as_f64().unwrap() - 80.0 / 101.0).abs() < 1e-12);496 assert_eq!(euler["values"].as_array().unwrap()[20], 1601);497 assert_eq!(498 euler["cells"].as_array().unwrap()[100],499 parse("[60,100]").unwrap()500 );501 let spoke = parse(&spiral_polynomial("hex", 41, 3, 3, 1).unwrap()).unwrap();502 assert_eq!(spoke["top"], 1261);503 assert_eq!(504 spoke["cells"].as_array().unwrap()[20],505 parse("[0,20]").unwrap()506 );507 let sheet = spiral_pixels("square", 61, 4, -2, 41, "prime", false, 180).unwrap();508 assert_eq!(509 (sheet.width, sheet.height, sheet.rgba.len()),510 (180, 180, 129_600)511 );512 let at =513 |px: usize, py: usize| sheet.rgba[(py * 180 + px) * 4..(py * 180 + px) * 4 + 3].to_vec();514 assert_eq!(at(90, 90), ink(DARK.ground));515 assert_eq!(at(92, 90), ink(DARK.yellow));516 assert_eq!(at(81, 92), ink(DARK.orange));517 let hexes = spiral_pixels("hex", 21, 3, 3, 1, "mobius", true, 200).unwrap();518 assert_eq!(hexes.rgba[..3], ink(DARK.ground));519 assert_eq!(520 hexes.rgba[(100 * 200 + 100) * 4..(100 * 200 + 100) * 4 + 3],521 ink(DARK.blue)522 );523 let centre = parse(&spiral_at("square", 201, 384.0, 384.0, 768).unwrap()).unwrap();524 assert_eq!(525 (centre["n"].clone(), centre["ring"].clone()),526 (1.into(), 0.into())527 );528 let hit = parse(&spiral_at("square", 61, 81.5, 92.5, 180).unwrap()).unwrap();529 assert_eq!(530 (hit["n"].clone(), hit["prime"].clone()),531 (41.into(), true.into())532 );533 assert_eq!(hit["factors"], parse("[[41,1]]").unwrap());534 assert!((hit["span"].as_f64().unwrap() - 180.0 / 61.0).abs() < 1e-12);535 let corner = parse(&spiral_at("hex", 21, 195.0, 100.0, 200).unwrap()).unwrap();536 assert_eq!(537 (corner["x"].clone(), corner["y"].clone()),538 (10.into(), 0.into())539 );540 assert_eq!(corner["n"], 281);541 let centres = spiral_centers("square", 21, 420).unwrap();542 assert_eq!((centres.len(), centres[0], centres[1]), (882, 210.0, 210.0));543 assert_eq!((centres[2], centres[3]), (230.0, 210.0));544 assert_eq!(spiral_centers("hex", 21, 420).unwrap().len(), 662);545 assert_eq!(prime_from(90), 97);546 assert!(spiral_pixels("cube", 21, 1, 0, 2, "prime", true, 100).is_err());547 assert!(spiral_pixels("square", 20, 1, 0, 2, "prime", true, 100).is_err());548 assert!(spiral_pixels("square", 403, 1, 0, 2, "prime", true, 100).is_err());549 assert!(spiral_pixels("square", 21, 0, 0, 2, "prime", true, 100).is_err());550 assert!(spiral_pixels("square", 21, 1, 0, 2, "odd", true, 100).is_err());551 assert!(spiral_pixels("square", 21, 1, 0, 2, "prime", true, 2000).is_err());552 assert!(spiral_polynomial("square", 21, 1, 2_000_000, 2).is_err());553 assert!(spiral_at("hex", 21, 1.0, 1.0, 200).is_err());554 assert!(spiral_centers("square", 101, 400).is_err());555 assert!(spiral_xy("tri", 5).is_err());556}557558#[test]559fn the_gauss_exports_answer() {560 let two = parse(&ring_census("gaussian", 2).unwrap()).unwrap();561 assert_eq!(562 (563 two["points"].clone(),564 two["primes"].clone(),565 two["split"].clone()566 ),567 (25.into(), 12.into(), 8.into())568 );569 assert_eq!(570 (571 two["ramified"].clone(),572 two["inert"].clone(),573 two["units"].clone()574 ),575 (4.into(), 0.into(), 4.into())576 );577 assert_eq!(578 (579 two["composites"].clone(),580 two["symmetry"].clone(),581 two["top"].clone()582 ),583 (8.into(), 8.into(), 8.into())584 );585 let three = parse(&ring_census("gaussian", 3).unwrap()).unwrap();586 assert_eq!(587 (three["primes"].clone(), three["inert"].clone()),588 (24.into(), 4.into())589 );590 let hex = parse(&ring_census("eisenstein", 2).unwrap()).unwrap();591 assert_eq!(592 (593 hex["points"].clone(),594 hex["primes"].clone(),595 hex["composites"].clone()596 ),597 (19.into(), 12.into(), 0.into())598 );599 assert_eq!(600 (601 hex["ramified"].clone(),602 hex["inert"].clone(),603 hex["symmetry"].clone()604 ),605 (6.into(), 6.into(), 12.into())606 );607 let r2 = ring_weights("gaussian", 25).unwrap();608 assert_eq!((r2[3], r2[5], r2[25]), (0, 8, 12));609 assert_eq!(610 ring_weights("eisenstein", 7).unwrap(),611 vec![1, 6, 0, 6, 6, 0, 0, 12]612 );613 assert_eq!(ring_peak("gaussian", 60).unwrap(), vec![25, 12]);614 assert_eq!(ring_peak("eisenstein", 60).unwrap(), vec![49, 18]);615 assert_eq!(616 ring_fates("gaussian", 7).unwrap(),617 vec![0, 0, 3, 2, 0, 1, 0, 2]618 );619 assert_eq!(620 ring_fates("eisenstein", 7).unwrap(),621 vec![0, 0, 2, 3, 0, 2, 0, 1]622 );623 let sheet = ring_pixels("gaussian", 2, "class", true, 100).unwrap();624 let pixel =625 |px: usize, py: usize| sheet.rgba[(py * 100 + px) * 4..(py * 100 + px) * 4 + 3].to_vec();626 assert_eq!((sheet.width, sheet.height), (100, 100));627 assert_eq!(pixel(70, 30), ink(DARK.pink));628 assert_eq!(pixel(90, 30), ink(DARK.blue));629 assert_eq!(pixel(90, 50), ink(DARK.line));630 assert_eq!(pixel(50, 50), ink(DARK.ground));631 assert_eq!(pixel(60, 30), ink(DARK.ground));632 let hexes = ring_pixels("eisenstein", 2, "class", false, 100).unwrap();633 let cell =634 |px: usize, py: usize| hexes.rgba[(py * 100 + px) * 4..(py * 100 + px) * 4 + 3].to_vec();635 assert_eq!(cell(80, 67), ink(DARK.pink));636 assert_eq!(cell(90, 50), ink(DARK.orange));637 assert_eq!(cell(70, 50), ink(DARK.green));638 assert_eq!(cell(50, 50), ink(DARK.ground));639 let plain = ring_pixels("gaussian", 3, "plain", false, 70).unwrap();640 assert_eq!(641 plain.rgba[(25 * 70 + 45) * 4..(25 * 70 + 45) * 4 + 3],642 ink(DARK.yellow)643 );644 let glow = ring_pixels("gaussian", 3, "norm", false, 70).unwrap();645 assert_ne!(646 glow.rgba[(25 * 70 + 45) * 4..(25 * 70 + 45) * 4 + 3],647 ink(DARK.yellow)648 );649 let hit = parse(&ring_at("gaussian", 40, 403.0, 374.0, 768).unwrap()).unwrap();650 assert_eq!(651 (652 hit["a"].clone(),653 hit["b"].clone(),654 hit["norm"].clone(),655 hit["class"].clone()656 ),657 (2.into(), 1.into(), 5.into(), "split".into())658 );659 assert_eq!(hit["prime"], true);660 assert_eq!(hit["associates"].as_array().unwrap().len(), 4);661 assert_eq!(hit["associates"][1][0], -1.0);662 assert_eq!(hit["associates"][1][1], 2.0);663 assert_eq!(hit["conjugate"][1], -1.0);664 assert!((hit["px"].as_f64().unwrap() - 402.963).abs() < 1e-3);665 assert!((hit["py"].as_f64().unwrap() - 374.519).abs() < 1e-3);666 let flake = parse(&ring_at("eisenstein", 5, 140.0, 127.0, 220).unwrap()).unwrap();667 assert_eq!(668 (669 flake["a"].clone(),670 flake["b"].clone(),671 flake["norm"].clone(),672 flake["class"].clone()673 ),674 (1.into(), (-1).into(), 3.into(), "ramified".into())675 );676 assert_eq!(flake["associates"].as_array().unwrap().len(), 6);677 assert_eq!(flake["conjugate"][0], 2.0);678 assert_eq!(flake["conjugate"][1], 1.0);679 assert_eq!(flake["factors"], parse("[[3,1]]").unwrap());680 assert!(ring_pixels("quaternion", 2, "class", true, 100).is_err());681 assert!(ring_pixels("gaussian", 0, "class", true, 100).is_err());682 assert!(ring_pixels("gaussian", 201, "class", true, 100).is_err());683 assert!(ring_pixels("gaussian", 2, "bad", true, 100).is_err());684 assert!(ring_pixels("gaussian", 2, "class", true, 2000).is_err());685 assert!(ring_weights("gaussian", 20_000).is_err());686 assert!(ring_fates("eisenstein", 20_000).is_err());687 assert!(ring_at("eisenstein", 5, 1.0, 1.0, 220).is_err());688 assert!(ring_census("gaussian", 300).is_err());689}690691#[test]692fn the_zeta_exports_answer() {693 let zeros = zeta_zeros(5).unwrap();694 let known = [14.134_725, 21.022_040, 25.010_858, 30.424_876, 32.935_062];695 for (got, want) in zeros.iter().zip(known) {696 assert!((got - want).abs() < 1e-6, "{got} {want}");697 }698 assert_eq!(zeta_count(100.0).unwrap(), 29);699 assert_eq!(zeta_count(200.0).unwrap(), 79);700 let root = zeta_at(14.134_725).unwrap();701 assert!(root[0].hypot(root[1]) < 1e-5);702 assert!(root[2].abs() < 1e-5);703 let half = zeta_at(0.0).unwrap();704 assert!((half[0] + 1.460_354_5).abs() < 1e-7);705 assert_eq!(half[3], 0.0);706 let walk = zeta_line(0.0, 50.0, 600).unwrap();707 assert_eq!(walk.len(), 2404);708 assert_eq!(walk[0], 0.0);709 assert_eq!(walk[2400], 50.0);710 assert!((walk[1] + 1.460_354_5).abs() < 1e-7);711 let seam = zeta_seam(250.0, 500).unwrap();712 assert_eq!(seam[0], 20.0);713 assert!(seam[1] < 5e-5);714 let stair = psi_stair(100).unwrap();715 assert!((stair[9] - 7.832_0).abs() < 1e-4);716 assert!((stair[99] - 94.045_3).abs() < 1e-4);717 let smooth = psi_formula(10.0, &[], 3).unwrap();718 assert_eq!(smooth.len(), 6);719 assert!((smooth[5] - 8.167_1).abs() < 1e-4);720 let hundred = zeta_zeros(100).unwrap();721 let folded = psi_formula(100.0, &hundred, 2).unwrap();722 assert!((folded[3] - stair[99]).abs() < 1.0);723 let gap = psi_gap(100, &hundred).unwrap();724 assert!((gap - (stair[99] - folded[3])).abs() < 1e-12);725 assert!(zeta_line(0.0, 300.0, 10).is_err());726 assert!(zeta_line(0.0, 10.0, 0).is_err());727 assert!(zeta_at(-1.0).is_err());728 assert!(zeta_zeros(101).is_err());729 assert!(zeta_count(251.0).is_err());730 assert!(zeta_seam(100.0, 0).is_err());731 assert!(psi_stair(1).is_err());732 assert!(psi_stair(1001).is_err());733 assert!(psi_formula(10.0, &[], 1).is_err());734 assert!(psi_formula(10.0, &vec![14.0; 101], 10).is_err());735 assert!(psi_gap(1, &[]).is_err());736}737738#[test]739fn the_graph_exports_answer() {740 let carpet = parse(&graph_census("flat", "7", 3, 1, 2, "core").unwrap()).unwrap();741 assert_eq!(742 (carpet["nodes"].clone(), carpet["branches"].clone()),743 (8.into(), 8.into())744 );745 assert_eq!(carpet["components"], 1);746 let knots = graph_nodes("flat", "7", 3, 1, 2, "core").unwrap();747 assert_eq!((knots[0], knots[1], knots.len()), (2.0, 8.0, 18));748 assert_eq!(749 graph_branches("flat", "7", 3, 1, 2, "core").unwrap().len(),750 16751 );752 assert_eq!(753 graph_roles("flat", "7", 3, 1, 2, "core").unwrap(),754 vec![2; 8]755 );756 let sponge = graph_nodes("cube", "23", 3, 1, 2, "core").unwrap();757 assert_eq!((sponge[0], sponge[1], sponge.len()), (3.0, 20.0, 62));758 assert_eq!(759 graph_branches("cube", "255", 1, 1, 2, "edge")760 .unwrap()761 .len(),762 24763 );764 let tally = parse(&graph_census("cube", "23", 3, 1, 2, "core").unwrap()).unwrap();765 assert_eq!(tally["nodes"], 20);766 assert_eq!(tally["branches"], 24);767 assert_eq!(tally["junctions"], 8);768 assert_eq!(tally["euler"], -4);769 let slice = parse(&graph_census("hex", "23", 3, 1, 2, "core").unwrap()).unwrap();770 assert_eq!(771 (slice["nodes"].clone(), slice["branches"].clone()),772 (42.into(), 48.into())773 );774 assert!((slice["length"].as_f64().unwrap() - 48.0 / 3f64.sqrt()).abs() < 1e-9);775 let rim = parse(&graph_census("hex", "23", 3, 1, 2, "edge").unwrap()).unwrap();776 assert_eq!(777 (rim["nodes"].clone(), rim["length"].clone()),778 (36.into(), 78.0.into())779 );780 assert_eq!(graph_size("flat", "495", 3, 2, 3, "core").unwrap(), "64");781 assert_eq!(graph_size("cube", "23", 3, 2, 2, "tunnel").unwrap(), "329");782 assert_eq!(graph_cap("flat", "7", 3, 2, "core", 20000).unwrap(), 4);783 assert_eq!(graph_cap("cube", "23", 3, 2, "core", 2000).unwrap(), 2);784 assert_eq!(graph_cap("hex", "23", 3, 2, "edge", 2000).unwrap(), 2);785 let ring = graph_nodes("flat", "15", 2, 1, 2, "core").unwrap();786 let loop_ = graph_branches("flat", "15", 2, 1, 2, "core").unwrap();787 let mut relax = Layout::new(&ring[2..], &loop_, 2, 1).unwrap();788 let rest = relax.step(500);789 assert!(rest < 1e-3, "energy {rest}");790 let p = relax.positions();791 let gaps: Vec<f32> = loop_792 .chunks(2)793 .map(|b| {794 let (a, c) = (b[0] as usize, b[1] as usize);795 ((p[2 * a] - p[2 * c]).powi(2) + (p[2 * a + 1] - p[2 * c + 1]).powi(2)).sqrt()796 })797 .collect();798 let spread = gaps.iter().cloned().fold(0.0, f32::max)799 - gaps.iter().cloned().fold(f32::INFINITY, f32::min);800 assert!(spread < 1e-3, "gaps {gaps:?}");801 assert_eq!(relax.ticks(), 500);802 assert!(relax.moved() < relax.temperature());803 assert!(graph_nodes("wobble", "7", 3, 1, 2, "core").is_err());804 assert!(graph_roles("flat", "7", 3, 1, 2, "dual").is_err());805 assert!(graph_census("hex", "23", 3, 1, 2, "tunnel").is_err());806 assert!(graph_nodes("flat", "7", 3, 9, 2, "core").is_err());807 assert!(graph_cap("flat", "16", 3, 2, "core", 100).is_err());808 assert!(Layout::new(&[0.0, 0.0, 1.0, 1.0], &[0, 2], 2, 1).is_err());809}810811#[test]812fn the_ledger_exports_answer() {813 assert_eq!(ledger_measures().len(), 12);814 assert_eq!(ledger_measures()[0], "fills");815 assert_eq!(816 ledger_designs(2, 2).unwrap(),817 ["0", "1", "3", "6", "7", "15"]818 );819 assert_eq!(ledger_designs(2, 3).unwrap().len(), 26);820 assert!(ledger_designs(3, 3).is_err());821 let budget = "500000";822 assert_eq!(823 ledger_terms("7", 2, 2, "fills", "level", 3, budget).unwrap(),824 ["8", "64", "512"]825 );826 assert_eq!(827 ledger_terms("23", 3, 2, "surface", "level", 3, budget).unwrap(),828 ["72", "1056", "18048"]829 );830 assert_eq!(831 ledger_terms("7", 2, 2, "fills", "side", 4, budget).unwrap(),832 ["8", "21", "40", "65"]833 );834 assert_eq!(835 ledger_terms("3", 2, 2, "fills", "side", 3, budget).unwrap(),836 ["6", "15", "28"]837 );838 assert_eq!(839 ledger_terms("23", 3, 2, "euler", "level", 8, "1000").unwrap(),840 ["-4", "-80"]841 );842 assert!(ledger_terms("7", 2, 2, "faces", "level", 1, budget).is_err());843 let found = parse(&ledger_identify("6, 42, 306, 2250")).unwrap();844 assert_eq!(845 (found[0]["id"].clone(), found[0]["shift"].clone()),846 ("A299916".into(), 1.into())847 );848 let octagonal = parse(&ledger_identify("8, 21, 40, 65")).unwrap();849 assert_eq!(850 (octagonal[0]["id"].clone(), octagonal[0]["shift"].clone()),851 ("A000567".into(), 2.into())852 );853 assert!(parse(&ledger_identify("x"))854 .unwrap()855 .as_array()856 .unwrap()857 .is_empty());858 assert_eq!(859 ledger_closed("7", 2, 2, "fills", "side").unwrap(),860 "3k^2 - 2k"861 );862 assert_eq!(863 ledger_closed("23", 3, 2, "surface", "level").unwrap(),864 "a(level) = 28 a(level-1) - 160 a(level-2)"865 );866 assert_eq!(ledger_closed("7", 2, 2, "euler", "level").unwrap(), "");867 let records = parse(&ledger_records()).unwrap();868 let records = records.as_array().unwrap();869 assert_eq!(records.len(), 60);870 let octagonal = records.iter().find(|r| r["id"] == "A000567").unwrap();871 assert_eq!(872 (octagonal["key"].clone(), octagonal["shift"].clone()),873 (874 "sequence_dim=2_code=7_measure=fills_axis=side".into(),875 0.into()876 )877 );878 assert_eq!(ledger_build("closed", 4).unwrap(), 7692);879 assert_eq!(ledger_build("closed", 4).unwrap(), 7692);880 assert!(ledger_build("deep", 4).is_err());881 let hits = parse(&ledger_search("8, 21, 40, 65", "", 2, 2, 0, 25)).unwrap();882 assert_eq!(hits["total"], 1);883 let row = &hits["rows"][0];884 assert_eq!(row["name"], "sequence_dim=2_code=7_measure=fills_axis=side");885 assert_eq!(886 (887 row["oeis"].clone(),888 row["shift"].clone(),889 row["tag"].clone()890 ),891 ("A000567".into(), 0.into(), "Proved".into())892 );893 assert_eq!(row["closed"], "3k^2 - 2k");894 let surfaces = parse(&ledger_search("", "surface", 3, 2, 0, 5)).unwrap();895 assert_eq!(surfaces["total"], 44);896 assert_eq!(surfaces["rows"].as_array().unwrap().len(), 5);897 assert_eq!(898 parse(&ledger_search("sequence_dim=3_code=23_", "", 0, 0, 0, 100)).unwrap()["total"],899 6900 );901 assert_eq!(902 parse(&ledger_search("A381517", "", 0, 0, 0, 100)).unwrap()["rows"][0]["terms"][1],903 "80"904 );905 let grown = parse(&ledger_grow("convolved", 4, 100).unwrap()).unwrap();906 assert_eq!(907 (908 grown["rows"].clone(),909 grown["done"].clone(),910 grown["total"].clone()911 ),912 (7792.into(), 100.into(), 5044.into())913 );914 assert!(ledger_grow("deep", 4, 100).is_err());915 let void = parse(&ledger_row("9", 2, 2, "voids", "side", 3, "500000").unwrap()).unwrap();916 assert_eq!(917 void["name"],918 "sequence_dim=2_code=9_measure=voids_axis=side"919 );920 assert_eq!(void["terms"], parse(r#"["4", "12", "24"]"#).unwrap());921 assert_eq!(void["closed"], "2k^2 - 2k");922 assert_eq!(void["number"], 3);923 assert!(ledger_row("7", 2, 2, "faces", "level", 3, "500000").is_err());924 let gasket = ledger_profile("126", 3, 2, 2, 4).unwrap();925 assert_eq!(gasket.len(), 46);926 assert!(gasket[15..=30].iter().all(|count| count == "81"));927 assert_eq!(928 ledger_profile("1", 1, 2, 3, 2).unwrap().join(""),929 "101000101"930 );931}932933#[test]934fn the_tour_exports_answer() {935 let farey = parse(&farey_novelty(7)).unwrap();936 assert_eq!(937 (farey["lit"].clone(), farey["novel"].clone()),938 (19.into(), 19.into())939 );940 let cut = parse(&diagonal_profile("126", 2, 5, 2).unwrap()).unwrap();941 assert_eq!(942 (cut["max"].clone(), cut["constant"].clone()),943 ("243".into(), true.into())944 );945 assert_eq!(946 parse(&slice_census("23", 9, 1, 2).unwrap()).unwrap()["vertices"],947 271948 );949 assert_eq!(950 parse(&slice_census("23", 1, 1, 2).unwrap()).unwrap()["fills"],951 6952 );953 assert_eq!(954 parse(&two_census("9", 5, 1, 0, 2).unwrap()).unwrap()["fills"],955 13956 );957 assert_eq!(baseq_sequence(5, 2).unwrap(), ["8", "172112"]);958 let first = |terms: &str| {959 let found = parse(&ledger_identify(terms)).unwrap();960 (found[0]["id"].clone(), found[0]["shift"].clone())961 };962 assert_eq!(first("3, 9, 27, 81"), ("A000244".into(), 1.into()));963 assert_eq!(first("2, 3, 5, 7, 11, 13"), ("A005728".into(), 1.into()));964 assert_eq!(first("7, 37, 91, 169"), ("A154105".into(), 0.into()));965 assert_eq!(first("4, 12, 64, 700"), ("A129824".into(), 1.into()));966 assert_eq!(first("20, 81, 208"), ("A103532".into(), 1.into()));967}968969#[test]970fn the_census_exports_answer() {971 let window = parse(&census_window()).unwrap();972 assert_eq!(window["registry"], 18066);973 assert_eq!(window["cap"], 48);974 assert_eq!(window["cells"], "100000");975 assert_eq!(window["ceiling"], "1000");976 assert_eq!(window["head"], 8);977 assert_eq!(window["depths"], parse("[8, 16, 32, 48]").unwrap());978 let tiers = window["tiers"].as_array().unwrap();979 let keyed: Vec<(String, u64)> = tiers980 .iter()981 .map(|tier| {982 (983 tier["tier"].as_str().unwrap().to_string(),984 tier["keys"].as_u64().unwrap(),985 )986 })987 .collect();988 assert_eq!(989 keyed,990 [991 ("closed".to_string(), 7692),992 ("convolved".to_string(), 5044),993 ("side".to_string(), 2665),994 ("level".to_string(), 2665),995 ]996 );997 let walk = parse(&census_walk(7692)).unwrap();998 assert_eq!(999 (1000 walk["depth"].clone(),1001 walk["done"].clone(),1002 walk["total"].clone()1003 ),1004 (8.into(), 7692.into(), 18066.into())1005 );1006 assert_eq!(1007 (1008 walk["never"].clone(),1009 walk["once"].clone(),1010 walk["multiple"].clone()1011 ),1012 (396.into(), 102.into(), 502.into())1013 );1014 let report = parse(&census_report()).unwrap();1015 assert_eq!(report["rows"], 7692);1016 assert_eq!(report["written"], 604);1017 assert_eq!(report["first_miss"], 83);1018 assert_eq!(report["incidences"], 30865);1019 assert_eq!(report["low"], 452);1020 assert_eq!(report["ceiling_stopped"], 5048);1021 assert_eq!(report["cap_stopped"], 2644);1022 assert_eq!(report["blank"], 54);1023 assert_eq!(report["bands"][1]["missed"], 2);1024 assert_eq!(report["tiers"][0]["written"], 604);1025 let counts = census_counts();1026 assert_eq!(counts.len(), 1000);1027 assert_eq!((counts[0], counts[15]), (102, 633));1028 let writers = parse(&census_writers(16, 0, 2)).unwrap();1029 assert_eq!(1030 (writers["inside"].clone(), writers["rows"].clone()),1031 (true.into(), 633.into())1032 );1033 assert_eq!(writers["tiers"][0]["rows"], 633);1034 let first = &writers["shown"][0];1035 assert_eq!(1036 first["name"],1037 "sequence_dim=1_code=1_measure=fills_axis=level"1038 );1039 assert_eq!(first["closed"], "2^level");1040 assert_eq!(1041 (first["index"].clone(), first["term"].clone()),1042 (3.into(), 4.into())1043 );1044 assert_eq!(first["head"][3], "16");1045 assert_eq!(1046 writers["shown"][1]["closed"],1047 "a(level) = 3 a(level-1) - 2 a(level-2)"1048 );1049 let paged = parse(&census_writers(16, 0, 633)).unwrap();1050 let sided = paged["shown"]1051 .as_array()1052 .unwrap()1053 .iter()1054 .find(|row| row["axis"] == "side")1055 .unwrap();1056 assert_eq!(1057 (1058 sided["name"].clone(),1059 sided["term"].clone(),1060 sided["side"].clone()1061 ),1062 (1063 "sequence_dim=1_code=1_measure=surface_axis=side".into(),1064 8.into(),1065 15.into()1066 )1067 );1068 let outside = parse(&census_writers(1001, 0, 1)).unwrap();1069 assert_eq!(1070 (outside["inside"].clone(), outside["rows"].clone()),1071 (false.into(), 0.into())1072 );1073 let champions = parse(&census_champions(2)).unwrap();1074 assert_eq!(1075 (champions[0]["value"].clone(), champions[0]["rows"].clone()),1076 (16.into(), 633.into())1077 );1078 let misses = parse(&census_misses(3)).unwrap();1079 assert_eq!(misses, parse("[83, 86, 107]").unwrap());1080}10811082fn word(codes: &[&str], numbers: &[u32], bases: &[u32]) -> (Vec<String>, Vec<u32>, Vec<u32>) {1083 (1084 codes.iter().map(|c| c.to_string()).collect(),1085 numbers.to_vec(),1086 bases.to_vec(),1087 )1088}10891090fn census(codes: &[&str], numbers: &[u32], dimension: usize, bases: &[u32]) -> mrlyrs::core::Json {1091 let (codes, numbers, bases) = word(codes, numbers, bases);1092 parse(&magic_census(codes, numbers, dimension, bases).unwrap()).unwrap()1093}10941095#[test]1096fn the_word_fixture_the_page_prints() {1097 let doctest = census(&["7", "14", "9"], &[3, 7, 5], 2, &[2, 2, 2]);1098 assert_eq!(doctest["side"], "105");1099 assert_eq!(doctest["cells"], "11025");1100 assert_eq!(doctest["fill"], "3432");1101 assert_eq!(1102 format!("{:.9}", doctest["dimension"].as_f64().unwrap()),1103 "1.749241044"1104 );1105 assert_eq!(doctest["components"], "2496");1106 assert_eq!(doctest["counted"], "drawn");1107 let (codes, numbers, bases) = word(&["7", "14", "9"], &[3, 7, 5], &[2, 2, 2]);1108 assert_eq!(1109 word_count(codes.clone(), numbers.clone(), 2, bases.clone()).unwrap(),1110 doctest["fill"].as_str().unwrap()1111 );1112 assert_eq!(1113 word_profile(codes.clone(), numbers.clone(), 2, bases.clone())1114 .unwrap()1115 .len(),1116 2091117 );1118 assert_eq!(1119 magic_name(codes.clone(), numbers.clone(), bases.clone(), 2).unwrap(),1120 "word dim 2, magic [7 14 9], side [3 7 5]"1121 );1122 assert_eq!(1123 magic_key(codes, numbers, bases, 2).unwrap(),1124 "word_dim=2_magic=[7,14,9]_side=[3,7,5]"1125 );1126 let back = parse(&magic_parse("word_dim=2_magic=[7,14,9]_side=[3,7,5]").unwrap()).unwrap();1127 assert_eq!(back["codes"][1], "14");1128 assert_eq!(back["numbers"][2], 5);11291130 let one = census(&["7", "9"], &[3, 5], 2, &[2, 2]);1131 let twice = census(&["7", "9", "7", "9"], &[3, 5, 3, 5], 2, &[2, 2, 2, 2]);1132 let square = |text: &str| text.parse::<u128>().unwrap().pow(2).to_string();1133 assert_eq!(twice["side"], square(one["side"].as_str().unwrap()));1134 assert_eq!(twice["fill"], square(one["fill"].as_str().unwrap()));1135 assert_eq!(twice["dimension"], one["dimension"]);1136 assert_eq!(1137 (twice["periodic"].clone(), one["periodic"].clone()),1138 (true.into(), false.into())1139 );11401141 let ahead = census(&["3", "6"], &[2, 2], 2, &[2, 2]);1142 let behind = census(&["6", "3"], &[2, 2], 2, &[2, 2]);1143 assert_eq!(ahead["fill"], behind["fill"]);1144 assert_eq!(ahead["side"], behind["side"]);1145 assert_eq!(1146 (ahead["components"].clone(), behind["components"].clone()),1147 ("4".into(), "2".into())1148 );1149 assert_eq!(ahead["counted"], "closed");11501151 let ladder = census(1152 &["7", "7", "7", "7", "7"],1153 &[3, 5, 7, 9, 11],1154 2,1155 &[2, 2, 2, 2, 2],1156 );1157 for letter in ladder["letters"].as_array().unwrap() {1158 let side = letter["number"].as_u64().unwrap();1159 let law = side * side - ((side - 1) / 2).pow(2);1160 assert_eq!(letter["fill"], law.to_string(), "side {side}");1161 }1162 let stair = parse(&magic_staircase(5).unwrap()).unwrap();1163 let read = |row: usize| format!("{:.9}", stair["rows"][row]["dimension"].as_f64().unwrap());1164 assert_eq!(read(0), "1.892789261");1165 assert_eq!(read(1), "1.892315261");1166 assert_eq!(stair["rows"][2]["length"], 6);1167 assert!(stair["rows"][1]["dimension"].as_f64() < stair["rows"][0]["dimension"].as_f64());1168 assert_eq!(1169 format!("{:.9}", stair["constant"].as_f64().unwrap()),1170 read(0)1171 );11721173 assert_eq!(magic_cap(vec![3, 7, 5, 3], 2, 243).unwrap(), 3);1174 assert_eq!(magic_cap(vec![3, 3, 3, 3, 3], 3, 128).unwrap(), 4);1175 let menger = census(&["23", "23", "23"], &[3, 3, 3], 3, &[2, 2, 2]);1176 assert_eq!(menger["fill"], "8000");1177 assert_eq!(menger["constant"], true);1178 let (codes, numbers, bases) = word(&["23", "23", "23"], &[3, 3, 3], &[2, 2, 2]);1179 assert_eq!(1180 magic_cells(codes.clone(), numbers.clone(), bases.clone())1181 .unwrap()1182 .len()1183 / 3,1184 80001185 );1186 assert_eq!(magic_surface(codes, numbers, bases).unwrap(), "18048");11871188 let rates = parse(1189 &magic_rates(1190 vec!["3".into(), "7".into()],1191 vec![2, 2],1192 vec![2, 2],1193 "thue-morse",1194 64,1195 )1196 .unwrap(),1197 )1198 .unwrap();1199 assert_eq!(1200 format!("{:.15}", rates["limit"].as_f64().unwrap()),1201 "1.292481250360578"1202 );1203 assert_eq!(rates["phi"], 0.0);1204 assert_eq!(rates["length"], 64);1205 let last = rates["rows"][63][0].as_f64().unwrap();1206 assert_eq!(1207 rates["rows"][63][1].as_f64().unwrap(),1208 rates["limit"].as_f64().unwrap()1209 );1210 assert!(last < rates["limit"].as_f64().unwrap());1211 assert!(last > rates["rows"][31][0].as_f64().unwrap());1212 assert!(rates["control"][63].as_f64().unwrap() > 0.0);12131214 let ahead = magic_grid(vec!["9".into(), "273".into()], vec![2, 3], vec![2, 3]).unwrap();1215 let behind = magic_grid(vec!["273".into(), "9".into()], vec![3, 2], vec![3, 2]).unwrap();1216 assert_eq!((ahead.width, behind.width), (6, 6));1217 assert_eq!(ahead.types, behind.types);1218 assert_eq!(ahead.types.iter().map(|&b| b as usize).sum::<usize>(), 6);1219}12201221fn lift(kind: &str, level: usize) -> Vec<u8> {1222 morse_lift(kind, level).unwrap().types1223}12241225#[test]1226fn the_morse_fixture_the_page_prints() {1227 let read = parse(&morse_word(64).unwrap()).unwrap();1228 assert_eq!(read["agree"], true);1229 assert_eq!(read["ones"], 32);1230 assert_eq!(read["longest"], 2);1231 assert_eq!(read["cube_free"], true);1232 assert_eq!(read["singles"], 22);1233 assert_eq!(read["doubles"], 21);1234 assert_eq!(read["doubling_agree"], true);1235 assert_eq!(read["digits"].as_array().unwrap().len(), 64);1236 assert_eq!(read["boundary"].as_array().unwrap().len(), 63);1237 assert_eq!(read["boundary"][0], 1);1238 assert_eq!(morse_stage(3).unwrap(), vec![0, 1, 1, 0, 1, 0, 0, 1]);1239 assert_eq!(morse_stage(6).unwrap().len(), 64);12401241 let gallery = parse(&morse_gallery(6).unwrap()).unwrap();1242 let row = |at: usize| gallery[at].clone();1243 assert_eq!(row(0)["formula"], "t(i) xor t(j)");1244 assert_eq!(row(0)["folds"], true);1245 assert_eq!(row(0)["tile"], parse("[0,1,1,0]").unwrap());1246 assert_eq!(row(0)["design"], "9");1247 assert_eq!(row(1)["formula"], "t(i and j)");1248 assert_eq!(row(1)["folds"], true);1249 assert_eq!(row(1)["tile"], parse("[0,0,0,1]").unwrap());1250 assert_eq!(row(1)["design"], "7");1251 assert_eq!(row(2)["formula"], "t(i xor j)");1252 assert_eq!(row(2)["folds"], true);1253 assert_eq!(row(2)["twin"], "parity");1254 assert_eq!(row(3)["formula"], "t(i + j)");1255 assert_eq!(row(3)["folds"], false);1256 assert_eq!(row(3)["faults"], 1376);1257 assert_eq!(row(3)["first"], parse("[1,3]").unwrap());1258 assert_eq!(row(3)["design"], mrlyrs::core::Json::Null);12591260 for level in 1..10 {1261 let rows = parse(&morse_gallery(level).unwrap()).unwrap();1262 assert_eq!(rows[2]["twin"], "parity", "level {level}");1263 assert_eq!(rows[3]["folds"], level == 1, "level {level}");1264 }12651266 let side = morse_lift("parity", 6).unwrap();1267 assert_eq!((side.width, side.height), (64, 64));1268 assert_eq!(lift("xor", 6), lift("parity", 6));1269 assert_eq!(morse_signs("9", 2, 2, 6).unwrap().types, lift("parity", 6));1270 assert_eq!(morse_signs("7", 2, 2, 6).unwrap().types, lift("and", 6));1271 assert_eq!(1272 lift("parity", 6).iter().map(|&b| b as usize).sum::<usize>(),1273 20481274 );12751276 let sign = parse(&morse_filter("9", 2, 2, 3, "sign").unwrap()).unwrap();1277 assert_eq!(sign["morse_tile"], true);1278 assert_eq!(sign["form"], "the base tile repeated");1279 assert_eq!(sign["closed_exact"], true);1280 assert_eq!(sign["morse_exact"], false);1281 assert_eq!(sign["side"], 16);1282 assert_eq!(sign["morse_faults"], 128);1283 assert_eq!(sign["lit"], 128);1284 for code in 0..16u32 {1285 for level in 1..5 {1286 let read =1287 parse(&morse_filter(&code.to_string(), 2, 2, level, "sign").unwrap()).unwrap();1288 let side = read["side"].as_u64().unwrap();1289 assert_eq!(read["closed_exact"], true, "code {code} level {level}");1290 assert_eq!(1291 read["morse_faults"],1292 side * side / 2,1293 "code {code} level {level}"1294 );1295 }1296 }12971298 let flat = parse(&morse_filter("7", 2, 2, 3, "design").unwrap()).unwrap();1299 assert_eq!(1300 flat["form"],1301 "the level below, punched by the tile's complement"1302 );1303 assert_eq!(flat["closed_exact"], true);1304 assert_eq!(flat["morse_exact"], false);1305 assert_eq!(1306 (flat["side"].clone(), flat["lit"].clone()),1307 (16.into(), 27.into())1308 );1309 assert_eq!(flat["morse_faults"], 127);1310 let wide = parse(&morse_filter("495", 3, 3, 2, "design").unwrap()).unwrap();1311 assert_eq!(wide["closed_exact"], true);1312 assert_eq!(wide["morse_faults"], mrlyrs::core::Json::Null);1313 assert_eq!(wide["side"], 27);13141315 assert!(morse_word(0).is_err());1316 assert!(morse_lift("cube", 4).is_err());1317 assert!(morse_lift("parity", 10).is_err());1318 assert!(morse_filter("7", 2, 2, 3, "product").is_err());1319}13201321#[test]1322fn the_tile_fixture_the_page_prints() {1323 let read = |dimension: usize,1324 code: &str,1325 number: usize,1326 level: usize,1327 base: usize,1328 projection: &str,1329 reps: Vec<u32>,1330 crop: bool| {1331 parse(&tile_census(code, number, level, base, dimension, projection, reps, crop).unwrap())1332 .unwrap()1333 };1334 let count = |cell: &mrlyrs::core::Json, key: &str| cell[key].as_str().unwrap().to_string();13351336 let wide = read(2, "495", 3, 2, 3, "", vec![5, 5], false);1337 assert_eq!(wide["tile"], parse("[9,9]").unwrap());1338 assert_eq!(wide["sheet"], parse("[45,45]").unwrap());1339 assert_eq!(count(&wide, "fills"), "1600");1340 assert_eq!(count(&wide, "voids"), "425");1341 assert_eq!(count(&wide, "exposed"), "1280");1342 assert_eq!(count(&wide, "tile_exposed"), "80");1343 assert_eq!(count(&wide, "buried"), "720");1344 assert_eq!(1345 (wide["vertices"].clone(), wide["euler"].clone()),1346 (2016.into(), (-224).into())1347 );13481349 let tall = read(2, "495", 3, 2, 3, "", vec![3, 9], false);1350 assert_eq!(tall["sheet"], parse("[27,81]").unwrap());1351 assert_eq!(count(&tall, "fills"), "1728");1352 assert_eq!(count(&tall, "exposed"), "1404");1353 assert_eq!(count(&tall, "buried"), "756");1354 assert_eq!(1355 (tall["vertices"].clone(), tall["euler"].clone()),1356 (2188.into(), (-242).into())1357 );13581359 let block = read(3, "23", 3, 1, 2, "", vec![5, 5, 5], false);1360 assert_eq!(block["sheet"], parse("[15,15,15]").unwrap());1361 assert_eq!(count(&block, "fills"), "2500");1362 assert_eq!(count(&block, "voids"), "875");1363 assert_eq!(count(&block, "exposed"), "4200");1364 assert_eq!(count(&block, "tile_exposed"), "72");1365 assert_eq!(count(&block, "buried"), "4800");1366 assert_eq!(1367 (block["faces"].clone(), block["euler"].clone()),1368 (9600.into(), (-324).into())1369 );13701371 let slab = read(3, "23", 3, 1, 2, "", vec![3, 9, 3], false);1372 assert_eq!(slab["sheet"], parse("[9,27,9]").unwrap());1373 assert_eq!(count(&slab, "fills"), "1620");1374 assert_eq!(count(&slab, "exposed"), "2952");1375 assert_eq!(count(&slab, "buried"), "2880");1376 assert_eq!(1377 (slab["faces"].clone(), slab["euler"].clone()),1378 (6336.into(), (-224).into())1379 );13801381 let mesh = read(6, "23", 3, 1, 2, "cut", vec![5, 5], false);1382 assert_eq!(mesh["tile"], parse("[11,6]").unwrap());1383 assert_eq!(mesh["sheet"], parse("[47,33]").unwrap());1384 assert_eq!(mesh["triangles"], 1350);1385 assert_eq!(count(&mesh, "fills"), "1050");1386 assert_eq!(count(&mesh, "voids"), "300");1387 assert_eq!(count(&mesh, "exposed"), "414");1388 assert_eq!(count(&mesh, "tile_exposed"), "30");1389 assert_eq!(count(&mesh, "buried"), "336");1390 assert_eq!(mesh["euler"], 1);13911392 let strip = read(6, "23", 3, 1, 2, "cut", vec![3, 9], false);1393 assert_eq!(strip["sheet"], parse("[29,57]").unwrap());1394 assert_eq!(strip["triangles"], 1458);1395 assert_eq!(count(&strip, "fills"), "1134");1396 assert_eq!(count(&strip, "exposed"), "462");1397 assert_eq!(strip["euler"], 1);13981399 let trimmed = read(6, "23", 3, 1, 2, "cut", vec![5, 5], true);1400 assert_eq!(trimmed["sheet"], parse("[43,27]").unwrap());1401 assert_eq!(trimmed["triangles"], 1161);1402 assert_eq!(count(&trimmed, "fills"), "891");1403 assert_eq!(count(&trimmed, "exposed"), "357");1404 assert_eq!(trimmed["euler"], 1);14051406 let narrow = read(6, "23", 3, 1, 2, "cut", vec![3, 9], true);1407 assert_eq!(narrow["sheet"], parse("[25,51]").unwrap());1408 assert_eq!(narrow["triangles"], 1275);1409 assert_eq!(count(&narrow, "fills"), "969");1410 assert_eq!(narrow["euler"], 1);14111412 let grid = tile_grid("495", 3, 2, 3, 5, 5).unwrap();1413 assert_eq!((grid.width, grid.height), (45, 45));1414 assert_eq!(grid.types.iter().map(|&b| b as usize).sum::<usize>(), 1600);1415 assert_eq!(tile_cells("23", 3, 1, 2, 5, 5, 5).unwrap().len() / 3, 2500);1416 let art = tile_svg("23", 3, 1, 2, "cut", 5, 5, true, 6).unwrap();1417 assert_eq!(art.matches("<polygon").count(), 1161);14181419 assert!(tile_census("495", 3, 2, 3, 4, "", vec![5, 5], false).is_err());1420 assert!(tile_census("495", 3, 2, 3, 2, "", vec![5, 5, 5], false).is_err());1421 assert!(tile_svg("23", 3, 1, 2, "cut", 1, 5, true, 6).is_err());1422 assert!(tile_grid("495", 3, 6, 3, 5, 5).is_err());1423}14241425#[test]1426fn the_blend_exports_answer() {1427 let budget = "500000";1428 let surface = ledger_terms("23", 3, 2, "surface", "level", 8, budget).unwrap();1429 assert_eq!(surface[7], "51267108864");1430 let rule = parse(&blend_recurrence(surface.clone()).unwrap()).unwrap();1431 assert_eq!(rule["order"], 2);1432 assert_eq!(rule["coefficients"], parse("[[28,1],[-160,1]]").unwrap());1433 assert_eq!(rule["recurrence"], "a(n) = 28 a(n-1) - 160 a(n-2)");1434 let poly = blend_characteristic(&rule["coefficients"].to_string()).unwrap();1435 assert_eq!(1436 parse(&poly).unwrap(),1437 parse("[[1,1],[-28,1],[160,1]]").unwrap()1438 );1439 let root = blend_growth(&rule["coefficients"].to_string()).unwrap();1440 assert!((root - 20.0).abs() < 1e-12, "root {root}");1441 assert_eq!(1442 blend_recurrence(vec![1443 "2".into(),1444 "3".into(),1445 "5".into(),1446 "7".into(),1447 "11".into(),1448 "13".into(),1449 "17".into(),1450 "19".into()1451 ])1452 .unwrap(),1453 "null"1454 );14551456 let series =1457 parse(&blend_series("23", 3, 2, "surface", "level", 8, budget, 4).unwrap()).unwrap();1458 assert_eq!(1459 series["name"],1460 "sequence_dim=3_code=23_measure=surface_axis=level"1461 );1462 assert_eq!(series["oeis"], "A332705");1463 assert_eq!(1464 series["closed"],1465 "a(level) = 28 a(level-1) - 160 a(level-2)"1466 );1467 assert_eq!(series["recurrence"], "a(n) = 28 a(n-1) - 160 a(n-2)");1468 assert_eq!(series["polynomial"], "x^2 - 28 x + 160");1469 assert_eq!(series["growth_from"], "the recurrence root");1470 assert_eq!(series["order"], 2);1471 assert_eq!(series["ratios"][0], "14.6667");1472 assert_eq!(series["differences"][1][0], "984");1473 assert_eq!(series["differences"].as_array().unwrap().len(), 4);1474 let growth = series["growth"].as_f64().unwrap();1475 let exponent = series["exponent"].as_f64().unwrap();1476 assert!((growth - 20.0).abs() < 1e-12, "growth {growth}");1477 assert!(1478 (exponent - 20f64.log10()).abs() < 1e-12,1479 "exponent {exponent}"1480 );1481 let logs = series["log10"].as_array().unwrap();1482 assert!((logs[0].as_f64().unwrap() - 72f64.log10()).abs() < 1e-12);14831484 let side = parse(&blend_series("7", 2, 2, "fills", "side", 12, budget, 5).unwrap()).unwrap();1485 assert_eq!(side["closed"], "3k^2 - 2k");1486 assert_eq!(side["order"], 3);1487 assert_eq!(side["coefficients"], parse("[[3,1],[-3,1],[1,1]]").unwrap());1488 assert_eq!(side["polynomial"], "x^3 - 3 x^2 + 3 x - 1");1489 assert_eq!(side["differences"][3][0], "0");14901491 let family = parse(&blend_family(2, 2, "fills", "level", 3, budget).unwrap()).unwrap();1492 let family = family.as_array().unwrap();1493 assert_eq!(family.len(), 6);1494 assert_eq!(family[4]["code"], "7");1495 assert_eq!(1496 family[4]["name"],1497 "sequence_dim=2_code=7_measure=fills_axis=level"1498 );1499 assert_eq!(family[4]["terms"], parse(r#"["8", "64", "512"]"#).unwrap());1500 assert_eq!(1501 parse(&blend_family(2, 3, "fills", "level", 2, budget).unwrap())1502 .unwrap()1503 .as_array()1504 .unwrap()1505 .len(),1506 261507 );15081509 let fills = ledger_terms("7", 2, 2, "fills", "level", 8, budget).unwrap();1510 let faces = ledger_terms("7", 2, 2, "surface", "level", 8, budget).unwrap();1511 let mix = parse(&blend_mix(faces.clone(), fills.clone(), "hadamard", 0, 3).unwrap()).unwrap();1512 assert_eq!(mix["terms"][0], "128");1513 assert_eq!(mix["terms"][3], "14483456");1514 assert_eq!(mix["order"], 2);1515 assert_eq!(mix["coefficients"], parse("[[88,1],[-1536,1]]").unwrap());1516 assert_eq!(mix["polynomial"], "x^2 - 88 x + 1536");1517 assert_eq!(mix["recurrence"], "a(n) = 88 a(n-1) - 1536 a(n-2)");1518 let mixed = mix["growth"].as_f64().unwrap();1519 assert!((mixed - 64.0).abs() < 1e-12, "growth {mixed}");1520 let sums = parse(&blend_mix(fills.clone(), vec![], "sigma", 0, 2).unwrap()).unwrap();1521 assert_eq!(sums["terms"][2], "584");1522 assert_eq!(sums["order"], 2);1523 let cut = parse(&blend_mix(fills.clone(), vec![], "decimate", 2, 2).unwrap()).unwrap();1524 assert_eq!(1525 cut["terms"],1526 parse(r#"["8", "512", "32768", "2097152"]"#).unwrap()1527 );15281529 assert_eq!(blend_ops().len(), 9);1530 assert_eq!(moire_correlation(3, 5), 0.0);1531 let paired = moire_correlation(3, 9);1532 assert!(1533 (paired - 0.219_264_504_826_757_3).abs() < 1e-12,1534 "r {paired}"1535 );1536 assert_eq!(moire_correlation(1, 9), 0.0);15371538 assert!(blend_recurrence(vec!["x".into()]).is_err());1539 assert!(blend_characteristic("[[1,0]]").is_err());1540 assert!(blend_growth("nonsense").is_err());1541 assert!(blend_series("7", 2, 2, "faces", "level", 3, budget, 3).is_err());1542 assert!(blend_family(3, 3, "fills", "level", 3, budget).is_err());1543 assert!(blend_mix(fills, faces, "twist", 0, 3).is_err());1544}15451546#[test]1547fn the_automata_exports_answer() {1548 assert_eq!(1549 eca_next(&[0, 0, 1, 0, 0], 110, false).unwrap(),1550 vec![0, 1, 1, 0, 0]1551 );1552 assert_eq!(1553 eca_next(&[1, 0, 0, 0, 0], 170, true).unwrap(),1554 vec![0, 0, 0, 0, 1]1555 );1556 let run = eca_history(&[0, 0, 1, 0, 0], 110, 3, false).unwrap();1557 assert_eq!((run.width, run.height), (5, 4));1558 assert_eq!(&run.types[5..10], &[0, 1, 1, 0, 0]);1559 let cone = eca_seed(110, 31).unwrap();1560 assert_eq!((cone.width, cone.height), (63, 32));1561 assert_eq!(cone.types.iter().map(|&b| b as u32).sum::<u32>(), 326);1562 assert_eq!(1563 eca_seed(90, 8)1564 .unwrap()1565 .types1566 .iter()1567 .map(|&b| b as u32)1568 .sum::<u32>(),1569 291570 );1571 let card = parse(&eca_card(110)).unwrap();1572 assert_eq!(card["name"], "bang dim 3, code 110");1573 assert_eq!(1574 (card["popcount"].clone(), card["degree"].clone()),1575 (5.into(), 3.into())1576 );1577 assert_eq!(card["lambda"], 0.625);1578 assert_eq!(card["genus"], "comp");1579 assert_eq!(1580 (card["b3_rep"].clone(), card["wolfram_rep"].clone()),1581 (61.into(), 110.into())1582 );1583 assert_eq!(card["npn_rep"], 25);1584 assert_eq!(card["b3_orbit"].as_array().unwrap().len(), 24);1585 assert_eq!(card["wolfram_class"].to_string(), "[110,124,137,193]");1586 assert!(!card["surjective"].as_bool().unwrap());1587 assert!(!card["reversible"].as_bool().unwrap());1588 assert!(card["outer_totalistic"].is_null());1589 assert!(card["gasket"].is_null());1590 let gasket = parse(&eca_card(60)).unwrap();1591 assert_eq!(gasket["gasket"], "bang dim 2, code 13");1592 assert_eq!(gasket["b3_rep"], 60);1593 let conway = parse(&eca_card(90)).unwrap();1594 assert_eq!(conway["outer_totalistic"]["birth"].to_string(), "[1]");1595 assert_eq!(conway["outer_totalistic"]["survive"].to_string(), "[1]");1596 assert!(conway["surjective"].as_bool().unwrap());1597 assert_eq!(eca_soup(64, 0.0, 1).iter().sum::<u8>(), 0);1598 assert_eq!(eca_soup(64, 1.0, 1).iter().sum::<u8>(), 64);1599 assert_eq!(eca_soup(64, 0.5, 7), eca_soup(64, 0.5, 7));1600 let moore = life_mask(2, "7", 3, 1).unwrap();1601 assert_eq!((moore.width, moore.height), (3, 3));1602 assert_eq!(moore.types.iter().map(|&b| b as u32).sum::<u32>(), 8);1603 let deep = life_mask(2, "7", 3, 2).unwrap();1604 assert_eq!((deep.width, deep.height), (9, 9));1605 assert_eq!(deep.types.iter().map(|&b| b as u32).sum::<u32>(), 64);1606 let line = life_mask(1, "1", 3, 1).unwrap();1607 assert_eq!((line.width, line.height), (3, 1));1608 assert_eq!(line.types, vec![1, 0, 1]);1609 let wide = life_mask(1, "1", 5, 1).unwrap();1610 assert_eq!(wide.types, vec![1, 0, 0, 0, 1]);1611 assert_eq!(life_mask_index(&deep.types, 9, 9).unwrap(), 1);1612 assert_eq!(life_mask_index(&line.types, 3, 1).unwrap(), 1);1613 assert_eq!(life_mask_index(&wide.types, 5, 1).unwrap(), 2);1614 let diagonal = life_mask(2, "9", 3, 1).unwrap();1615 assert_eq!(life_mask_index(&diagonal.types, 3, 3).unwrap(), 2);1616 let row = [0, 1, 1, 0, 1, 0, 0];1617 let stepped = life_next_masked(&row, 7, 1, &[1], &[0, 1], &line.types, 3, 1, false).unwrap();1618 assert_eq!(stepped, eca_next(&row, 94, false).unwrap());1619 let paced = parse(1620 &life_run_masked(1621 &blinker(),1622 5,1623 5,1624 &[3],1625 &[2, 3],1626 &moore.types,1627 3,1628 3,1629 false,1630 16,1631 )1632 .unwrap(),1633 )1634 .unwrap();1635 assert_eq!(1636 (paced["fate"].clone(), paced["loop"].clone()),1637 ("loop".into(), 2.into())1638 );1639 assert!(life_mask(3, "7", 3, 1).is_err());1640 assert!(life_mask(2, "7", 4, 1).is_err());1641 assert!(life_mask_index(&[1, 0, 1], 2, 2).is_err());1642 assert!(life_next_masked(&row, 7, 1, &[1], &[], &line.types, 4, 1, false).is_err());1643 assert!(life_next_masked(&row, 7, 1, &[1], &[], &wide.types, 5, 1, false).is_ok());1644}16451646#[test]1647fn the_formulas_exports_answer() {1648 let read = parse(&formulas_read(1000).unwrap()).unwrap();1649 let constants = &read["constants"];1650 assert!((constants["pi"].as_f64().unwrap() - std::f64::consts::PI).abs() < 1e-15);1651 assert!((constants["e"].as_f64().unwrap() - std::f64::consts::E).abs() < 1e-15);1652 assert!((constants["gamma"].as_f64().unwrap() - 0.577_215_664_901_532_9).abs() < 1e-15);1653 let cards = &read["cards"];1654 assert!((cards["wallis"]["value"].as_f64().unwrap() - 1.570_403_873_015_201).abs() < 1e-12);1655 assert!((cards["leibniz"]["value"].as_f64().unwrap() - 0.785_148_163_459_948_3).abs() < 1e-12);1656 assert!((cards["basel"]["value"].as_f64().unwrap() - 1.643_934_566_681_559_7).abs() < 1e-12);1657 assert!((cards["gamma"]["value"].as_f64().unwrap() - 0.577_715_581_568_208_2).abs() < 1e-12);1658 assert!((cards["e"]["value"].as_f64().unwrap() - 2.716_923_932_235_593_6).abs() < 1e-12);1659 for key in ["wallis", "leibniz", "basel", "gamma", "e"] {1660 let card = &cards[key];1661 let value = card["value"].as_f64().unwrap();1662 let limit = card["limit"].as_f64().unwrap();1663 assert!((card["error"].as_f64().unwrap() - (value - limit).abs()).abs() < 1e-15);1664 assert!(card["rel"].as_f64().unwrap() < 1e-3);1665 }1666 assert_eq!(cards["primes"]["value"], 168);1667 assert!((cards["primes"]["li"].as_f64().unwrap() - 177.609_657_990_152_2).abs() < 1e-9);1668 assert!((cards["primes"]["ratio"].as_f64().unwrap() - 144.764_827_301_083_95).abs() < 1e-9);1669 assert!((cards["primes"]["gauge"].as_f64().unwrap() - 0.945_894_507_658_558_8).abs() < 1e-12);1670 assert_eq!(cards["goldbach"]["even"], 2000);1671 assert_eq!(cards["goldbach"]["value"], 37);1672 assert_eq!(cards["goldbach"]["floor"], 1);1673 assert_eq!(cards["mertens"]["value"], 2);1674 assert!((cards["mertens"]["root"].as_f64().unwrap() - 31.622_776_601_683_793).abs() < 1e-12);16751676 let half = parse(&formulas_read(500).unwrap()).unwrap();1677 assert_eq!(half["cards"]["goldbach"]["even"], 1000);1678 assert_eq!(half["cards"]["goldbach"]["value"], 28);1679 assert_eq!(half["cards"]["primes"]["value"], 95);1680 assert_eq!(half["cards"]["mertens"]["value"], -6);16811682 let walk = formulas_walk("basel", 1000, 4).unwrap();1683 assert_eq!(walk.len(), 12);1684 assert_eq!((walk[0], walk[9]), (2.0, 1000.0));1685 assert!((walk[1] - 1.25).abs() < 1e-15);1686 assert!((walk[10] - 1.643_934_566_681_559_7).abs() < 1e-12);1687 let comet = formulas_walk("goldbach", 500, 2).unwrap();1688 assert_eq!((comet[0], comet[3], comet[4]), (4.0, 1000.0, 28.0));1689 assert!((comet[5] - 1.0 / 28.0).abs() < 1e-15);1690 let meter = formulas_walk("mertens", 100, 2).unwrap();1691 assert_eq!((meter[1], meter[4]), (0.0, 1.0));1692 assert!((meter[5] - 0.1).abs() < 1e-15);1693 assert!(formulas_read(1).is_err() && formulas_read(2001).is_err());1694 assert!(formulas_walk("basel", 100, 1).is_err() && formulas_walk("basil", 100, 4).is_err());1695}16961697#[test]1698fn the_wallis_exports_answer() {1699 assert_eq!(wallis_cap("odd", 3, 2).unwrap(), 4);1700 assert_eq!(wallis_cap("odd", 3, 3).unwrap(), 3);1701 assert_eq!(wallis_cap("flat", 3, 2).unwrap(), 6);1702 assert_eq!(wallis_cap("flat", 3, 3).unwrap(), 4);1703 assert_eq!(wallis_cap("flat", 5, 2).unwrap(), 4);17041705 let read = parse(&wallis_read("odd", 3, 4, 2).unwrap()).unwrap();1706 assert_eq!(read["word"].to_string(), "[3,5,7,9]");1707 assert_eq!(read["side"], "945");1708 assert_eq!(read["cells"], "737280");1709 assert_eq!(read["holes"], "9417");1710 assert!((read["ratio"].as_f64().unwrap() - 0.825_598_387_503_149_3).abs() < 1e-15);1711 assert!((read["limit"].as_f64().unwrap() - std::f64::consts::FRAC_PI_4).abs() < 1e-15);1712 assert!((read["exponent"].as_f64().unwrap() - 1.972_027_198_301_296_2).abs() < 1e-12);1713 assert_eq!(read["closed"], true);1714 assert_eq!(column(&read["levels"], "side"), r#""3","15","105","945""#);1715 assert_eq!(1716 column(&read["levels"], "cells"),1717 r#""8","192","9216","737280""#1718 );1719 assert_eq!(1720 column(&read["levels"], "ratio"),1721 "0.8888888888888888,0.8533333333333333,0.8359183673469387,0.8255983875031493"1722 );17231724 let solid = parse(&wallis_read("odd", 3, 3, 3).unwrap()).unwrap();1725 assert_eq!(solid["cells"], "1102608");1726 assert_eq!(solid["holes"], "3251");1727 assert!((solid["ratio"].as_f64().unwrap() - 0.952_474_246_841_593_9).abs() < 1e-15);1728 assert!((solid["limit"].as_f64().unwrap() - 0.948_815_485_719_679_7).abs() < 1e-15);1729 assert!((solid["gap"].as_f64().unwrap() - 0.003_658_761_121_914_21).abs() < 1e-15);17301731 let carpet = parse(&wallis_read("flat", 3, 5, 2).unwrap()).unwrap();1732 assert_eq!(carpet["side"], "243");1733 assert_eq!(carpet["cells"], "32768");1734 assert_eq!(carpet["limit"], 0.0);1735 assert_eq!(carpet["closed"], false);1736 assert!((carpet["exponent"].as_f64().unwrap() - 1.892_789_260_714_372).abs() < 1e-12);17371738 let walk = wallis_walk("odd", 3, 2, 200).unwrap();1739 assert_eq!(walk.len(), 200);1740 assert!((walk[0] - 8.0 / 9.0).abs() < 1e-15);1741 assert!((walk[199] - 0.786_375_633_530_097_9).abs() < 1e-12);1742 let fixed = wallis_walk("flat", 3, 2, 6).unwrap();1743 assert!((fixed[5] - (8.0f64 / 9.0).powi(6)).abs() < 1e-15);17441745 let grid = wallis_grid("odd", 3, 3).unwrap();1746 assert_eq!((grid.width, grid.height), (105, 105));1747 assert_eq!(grid.types.iter().filter(|&&b| b == 1).count(), 9216);17481749 let boxes = wallis_faces("odd", 3, 3).unwrap();1750 assert_eq!(boxes[0] as usize, 3251 * 216);1751 assert_eq!(boxes.len(), 2 + boxes[0] as usize);1752 assert_eq!(1753 &boxes[2..8],1754 &[-1.0 / 3.0, -1.0 / 3.0, -1.0 / 3.0, -1.0, 0.0, 0.0]1755 );17561757 assert!(wallis_read("odd", 3, 17, 2).is_err());1758 assert!(wallis_read("wallis", 3, 2, 2).is_err());1759 assert!(wallis_read("odd", 3, 2, 4).is_err());1760 assert!(wallis_read("flat", 4, 2, 2).is_err());1761 assert!(wallis_grid("odd", 3, 5).is_err());1762 assert!(wallis_faces("odd", 3, 4).is_err());1763}