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}