check.rs

8.0 kB · rust · 255 lines

1use coprime_terms::brute;2use coprime_terms::design::Design;3use coprime_terms::engine::{caps, count_one, methods, terms_with, Mode};4fn parse(args: &[String], index: usize, fallback: u32) -> u32 {5    args.get(index)6        .map(|s| s.parse().unwrap())7        .unwrap_or(fallback)8}910pub fn run(args: &[String]) {11    let args: Vec<String> = args.to_vec();12    let name = args.get(1).map(|s| s.as_str()).unwrap_or("menger");13    let brute_top = parse(&args, 2, 6);14    let sample_level = parse(&args, 3, 14);15    let threads: usize = args.get(4).map(|s| s.parse().unwrap()).unwrap_or_else(|| {16        std::thread::available_parallelism()17            .map(|n| n.get())18            .unwrap_or(1)19    });20    let design = Design::named(name).expect("unknown design");21    let fill = design.fill();22    println!("design {} D {} k {}", design.name, design.dimension, fill);2324    let engine = terms_with(&design, brute_top, threads, Mode::Auto);25    for level in engine.iter() {26        let direct = brute::count(&design, level.level, threads);27        println!(28            "brute level {} engine {} enumerated {} {}",29            level.level,30            level.value,31            direct,32            if level.value == direct as i128 {33                "MATCH"34            } else {35                "FAIL"36            }37        );38    }3940    for level in 3..=8u32 {41        let span = 3u64.pow(level);42        let mut bad = 0;43        let mut seen = 0;44        for modulus in 1..span {45            if modulus % 3 == 0 {46                continue;47            }48            let all = methods(&design, level, modulus);49            seen += 1;50            if all.iter().any(|v| *v != all[0]) {51                bad += 1;52                if bad == 1 {53                    println!("  first split at modulus {} {:?}", modulus, all);54                }55            }56        }57        println!(58            "methods level {} moduli {} splits {} {}",59            level,60            seen,61            bad,62            if bad == 0 { "MATCH" } else { "FAIL" }63        );64    }6566    let pinned: [(Mode, u32); 6] = [67        (Mode::Direct, 10),68        (Mode::Convolve, 10),69        (Mode::Zeta, 11),70        (Mode::Bitset, 8),71        (Mode::Rows, 10),72        (Mode::Cube, 10),73    ];74    let reference = terms_with(&design, 11, threads, Mode::Auto);75    for (mode, top) in pinned.iter() {76        let run = terms_with(&design, *top, threads, *mode);77        let same = run78            .iter()79            .zip(reference.iter())80            .all(|(a, b)| a.value == b.value);81        println!(82            "pinned {:?} levels 1..{} {}",83            mode,84            top,85            if same { "MATCH" } else { "FAIL" }86        );87    }8889    let span = 3u64.pow(sample_level);90    let bounds = caps(sample_level, design.dimension);91    println!(92        "sample level {} caps residue {} bitset {} rows {}",93        sample_level, bounds.residue, bounds.bitset, bounds.rows94    );95    let mut probes: Vec<u64> = Vec::new();96    for shift in 0..14u32 {97        let base = span >> shift;98        for step in 0..3u64 {99            let candidate = base.saturating_sub(step * 7).max(1);100            if candidate % 3 != 0 && !probes.contains(&candidate) {101                probes.push(candidate);102            }103        }104    }105    let wide = 3u64.pow(sample_level.saturating_sub(11)) + 1;106    for extra in [107        1u64, 2, 5, 7, 11, 13, 17, 41, 61, 101, 157, 437, 439, 440, 443, 446, wide,108    ] {109        if !probes.contains(&extra) {110            probes.push(extra);111        }112    }113    probes.sort_unstable();114    let mut bad = 0;115    for modulus in probes.iter() {116        let reach = span / modulus + 1;117        let middle = reach <= 20_000 || *modulus == wide;118        let mut seen: Vec<(String, u128)> = Vec::new();119        if design.dimension == 3 {120            seen.push((121                "convolve".to_string(),122                count_one(&design, sample_level, *modulus, Mode::Convolve),123            ));124            seen.push((125                "cube".to_string(),126                count_one(&design, sample_level, *modulus, Mode::Cube),127            ));128            if middle {129                seen.push((130                    "zeta".to_string(),131                    count_one(&design, sample_level, *modulus, Mode::Zeta),132                ));133                seen.push((134                    "rows".to_string(),135                    count_one(&design, sample_level, *modulus, Mode::Rows),136                ));137            }138            if reach <= 4_000 {139                seen.push((140                    "direct".to_string(),141                    count_one(&design, sample_level, *modulus, Mode::Direct),142                ));143                seen.push((144                    "bitset".to_string(),145                    count_one(&design, sample_level, *modulus, Mode::Bitset),146                ));147            }148        } else {149            seen.push((150                "zeta".to_string(),151                count_one(&design, sample_level, *modulus, Mode::Zeta),152            ));153            if reach <= 40_000 {154                seen.push((155                    "direct".to_string(),156                    count_one(&design, sample_level, *modulus, Mode::Direct),157                ));158            }159        }160        if modulus161            .checked_pow(design.dimension as u32)162            .map(|v| v <= 8_000_000)163            .unwrap_or(false)164        {165            seen.push((166                "residue".to_string(),167                count_one(&design, sample_level, *modulus, Mode::Residue),168            ));169        }170        let agree = seen.iter().all(|(_, v)| *v == seen[0].1);171        if !agree {172            bad += 1;173            println!("  modulus {} {:?}", modulus, seen);174        }175    }176    println!(177        "probes level {} count {} splits {} {}",178        sample_level,179        probes.len(),180        bad,181        if bad == 0 { "MATCH" } else { "FAIL" }182    );183184    if design.dimension == 3 {185        let deep = 19u32;186        let shelf = 3u64.pow(deep - 11) + 1;187        let mut ring_bad = 0;188        for (modulus, pinned, with_rows) in [189            (shelf, 58164940132507u128, true),190            (440, 61610728675376604u128, false),191        ] {192            let mut seen: Vec<(String, u128)> = vec![193                (194                    "cube".to_string(),195                    count_one(&design, deep, modulus, Mode::Cube),196                ),197                ("pinned".to_string(), pinned),198            ];199            if with_rows {200                seen.push((201                    "rows".to_string(),202                    count_one(&design, deep, modulus, Mode::Rows),203                ));204            }205            if !seen.iter().all(|(_, v)| *v == seen[0].1) {206                ring_bad += 1;207                println!("  ring modulus {} {:?}", modulus, seen);208            }209        }210        println!(211            "ring level {} moduli 2 splits {} {}",212            deep,213            ring_bad,214            if ring_bad == 0 { "MATCH" } else { "FAIL" }215        );216    }217218    let mut peel = 0;219    let mut peel_bad = 0;220    if design.zero_filled() {221        for modulus in [1u64, 2, 5, 7, 11, 23, 47, 101, 1009, 20011] {222            if modulus >= 3u64.pow(sample_level - 1) {223                continue;224            }225            let mode = if design.dimension == 3 {226                Mode::Convolve227            } else {228                Mode::Zeta229            };230            let high = count_one(&design, sample_level, 3 * modulus, mode);231            let low = count_one(&design, sample_level - 1, modulus, mode);232            peel += 1;233            if high != low {234                peel_bad += 1;235                println!("  peel modulus {} {} vs {}", modulus, high, low);236            }237        }238    }239    println!(240        "peel checks {} splits {} {}",241        peel,242        peel_bad,243        if peel_bad == 0 { "MATCH" } else { "FAIL" }244    );245246    let whole = count_one(&design, sample_level, 1, Mode::Residue);247    let expect = (fill as u128).pow(sample_level);248    println!(249        "fill level {} residue {} k^n {} {}",250        sample_level,251        whole,252        expect,253        if whole == expect { "MATCH" } else { "FAIL" }254    );255}