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}