census.rs
4.2 kB · rust · 156 lines
1use mrlynum::factor::gcd;23pub struct Ray {4 pub a: u64,5 pub b: u64,6 pub weight: u64,7}89fn octave(a: u64, b: u64) -> usize {10 let top = a.max(b);11 if top == 1 {12 return 0;13 }14 let mut j = 1;15 while 3u64.pow(j as u32) <= top {16 j += 1;17 }18 j19}2021pub fn rays(level: u32) -> (u64, Vec<Ray>) {22 let size = 1usize << level;23 let value: Vec<u64> = (0..size)24 .map(|mask| {25 (0..level)26 .filter(|j| mask >> j & 1 == 1)27 .map(|j| 3u64.pow(j))28 .sum()29 })30 .collect();31 let mut keys: Vec<u64> = Vec::with_capacity(3usize.pow(level));32 let mut coprime = 0u64;33 for x in 0..size {34 let free = !x & (size - 1);35 let mut y = free;36 loop {37 let (a, b) = (value[x], value[y]);38 let g = gcd(a as usize, b as usize) as u64;39 if g == 1 {40 coprime += 1;41 }42 if g > 0 {43 keys.push((a / g) << 32 | (b / g));44 }45 if y == 0 {46 break;47 }48 y = (y - 1) & free;49 }50 }51 keys.sort_unstable();52 let mut out = Vec::new();53 let mut index = 0;54 while index < keys.len() {55 let key = keys[index];56 let mut end = index;57 while end < keys.len() && keys[end] == key {58 end += 1;59 }60 out.push(Ray {61 a: key >> 32,62 b: key & 0xffff_ffff,63 weight: (end - index) as u64,64 });65 index = end;66 }67 (coprime, out)68}6970pub fn report(level: u32, detail: bool) {71 let (coprime, rays) = rays(level);72 let points = 3f64.powi(level as i32);73 let mut bins = vec![0u64; level as usize + 1];74 let mut z = 0u128;75 let mut mass = 0u64;76 let mut peak = 0u64;77 let mut singles = 0u64;78 let mut light = 0u64;79 let mut light_z = 0u128;80 for ray in rays.iter() {81 bins[octave(ray.a, ray.b)] += 1;82 if ray.a == 0 || ray.b == 0 {83 continue;84 }85 z += (ray.weight as u128).pow(2);86 mass += ray.weight;87 peak = peak.max(ray.weight);88 if ray.weight == 1 {89 singles += 1;90 }91 if (2..=5).contains(&ray.weight) {92 light += 1;93 light_z += (ray.weight as u128).pow(2);94 }95 }96 println!(97 "census n {} gasket points {} primitive {}",98 level,99 3u64.pow(level),100 coprime101 );102 println!(103 "occupied rays {} with fibres {} without",104 rays.len(),105 rays.len() - 2106 );107 println!(108 "Z {} Z/3^n {:.6} sum M {} 3^n-2^(n+1)+1 {} max M {}",109 z,110 z as f64 / points,111 mass,112 3u64.pow(level) - 2u64.pow(level + 1) + 1,113 peak114 );115 let octaves: Vec<String> = bins116 .iter()117 .enumerate()118 .filter(|(_, c)| **c > 0)119 .map(|(j, c)| format!("{}:{}", j, c))120 .collect();121 println!("octaves {}", octaves.join(" "));122 println!("occ(8,n)/3^8 {:.3}", bins[8] as f64 / 6561.0);123 let cut = |j: usize| (bins[..=j].iter().sum::<u64>() as f64).ln() / 3f64.ln() / level as f64;124 if level % 2 == 0 {125 println!("band exponent j <= n/2 {:.4}", cut(level as usize / 2));126 } else {127 println!(128 "band exponent j <= floor(n/2) {:.4} or ceil {:.4}",129 cut(level as usize / 2),130 cut(level as usize / 2 + 1)131 );132 }133 if !detail {134 return;135 }136 let share = |part: u128| 100.0 * part as f64 / z as f64;137 println!(138 "M = 1 rays {} ({:.0}% of Z), M in [2,5] rays {} ({:.0}% of Z)",139 singles,140 share(singles as u128),141 light,142 share(light_z)143 );144 let mut heavy: Vec<&Ray> = rays.iter().filter(|r| r.a > 0 && r.b > 0).collect();145 heavy.sort_by(|p, q| q.weight.cmp(&p.weight).then(p.a.cmp(&q.a)));146 let top: Vec<String> = heavy[..10]147 .iter()148 .map(|r| format!("({},{}):{}", r.a, r.b, r.weight))149 .collect();150 let top_z: u128 = heavy[..10].iter().map(|r| (r.weight as u128).pow(2)).sum();151 println!(152 "ten heaviest {} carry {:.0}% of Z",153 top.join(" "),154 share(top_z)155 );156}