census.rs

4.7 kB · rust · 202 lines

1use crate::factor::mobius;23// FAMILIES45pub struct Family {6    pub q: u64,7    pub digits: Vec<u64>,8    pub label: String,9    pub lmax: usize,10    pub children: Vec<u64>,11}1213pub struct Outcome {14    pub counts: Vec<u64>,15    pub meter: Vec<i64>,16    pub mmax: Vec<u64>,17    pub twisted: Vec<(u64, Vec<i64>)>,18}1920fn depth(q: u64, k: usize) -> usize {21    match (q, k) {22        (3, 2) => 24,23        (4, 2) => 22,24        (4, 3) => 14,25        (5, 2) => 21,26        (5, 3) => 13,27        (5, 4) => 11,28        _ => panic!("no depth for q={q} k={k}"),29    }30}3132fn gcd(mut a: u64, mut b: u64) -> u64 {33    while b != 0 {34        let t = a % b;35        a = b;36        b = t;37    }38    a39}4041pub fn digit_gcd(digits: &[u64]) -> u64 {42    digits.iter().fold(0, |g, &d| gcd(g, d))43}4445pub fn make_family(q: u64, digits: Vec<u64>) -> Family {46    let lmax = depth(q, digits.len());47    make_family_depth(q, digits, lmax)48}4950pub fn make_family_depth(q: u64, digits: Vec<u64>, lmax: usize) -> Family {51    let label: String = digits.iter().map(|d| d.to_string()).collect();52    let mut children = Vec::new();53    if digit_gcd(&digits) == 1 {54        let top = *digits.iter().max().unwrap();55        let mut a = 2;56        while a * top <= q - 1 {57            children.push(a);58            a += 1;59        }60    }61    Family {62        q,63        digits,64        label,65        lmax,66        children,67    }68}6970pub fn families() -> Vec<Family> {71    let mut out = Vec::new();72    for q in [3u64, 4, 5] {73        for k in 2..=(q as usize - 1) {74            for mask in 0u64..(1 << q) {75                if mask.count_ones() as usize != k {76                    continue;77                }78                let digits: Vec<u64> = (0..q).filter(|d| mask >> d & 1 == 1).collect();79                out.push(make_family(q, digits));80            }81        }82    }83    out84}8586// SWEEP8788pub fn sweep(q: u64, digits: &[u64], lmax: usize, visit: &mut impl FnMut(u64, usize)) {89    fn rec(90        v: u64,91        len: usize,92        q: u64,93        digits: &[u64],94        lmax: usize,95        visit: &mut impl FnMut(u64, usize),96    ) {97        visit(v, len);98        if len < lmax {99            for &d in digits {100                rec(v * q + d, len + 1, q, digits, lmax, visit);101            }102        }103    }104    for &d in digits {105        if d != 0 {106            rec(d, 1, q, digits, lmax, visit);107        }108    }109}110111fn twist(a: u64, v: u64, mu_v: i8) -> i64 {112    match a {113        2 => {114            if v % 2 == 0 {115                0116            } else {117                -(mu_v as i64)118            }119        }120        3 => {121            if v % 3 == 0 {122                0123            } else {124                -(mu_v as i64)125            }126        }127        4 => 0,128        _ => panic!("no twist for a={a}"),129    }130}131132// ORDERED SWEEP133134pub fn sweep_length(q: u64, digits: &[u64], length: usize, visit: &mut impl FnMut(u64)) {135    fn rec(v: u64, len: usize, q: u64, digits: &[u64], length: usize, visit: &mut impl FnMut(u64)) {136        if len == length {137            visit(v);138            return;139        }140        for &d in digits {141            rec(v * q + d, len + 1, q, digits, length, visit);142        }143    }144    for &d in digits {145        if d != 0 {146            rec(d, 1, q, digits, length, visit);147        }148    }149}150151// METER152153pub fn run_family(fam: &Family, primes: &[u64]) -> Outcome {154    let l = fam.lmax;155    let has01 = fam.digits.contains(&0) && fam.digits.contains(&1);156    let mut counts = vec![0u64; l + 1];157    let mut meter = vec![0i64; l + 1];158    let mut mmax = vec![0u64; l + 1];159    let mut twisted: Vec<(u64, Vec<i64>)> = fam160        .children161        .iter()162        .map(|&a| (a, vec![0i64; l + 1]))163        .collect();164    let mut run = 0i64;165    let mut peak = 0u64;166    let mut total = 0u64;167    let mut boundary = 1u64;168    for lev in 1..=l {169        let skip = boundary;170        boundary *= fam.q;171        let mut tw_len: Vec<i64> = vec![0; fam.children.len()];172        sweep_length(fam.q, &fam.digits, lev, &mut |v| {173            let mu = mobius(v, primes);174            for (slot, a) in tw_len.iter_mut().zip(fam.children.iter()) {175                *slot += twist(*a, v, mu);176            }177            if has01 && lev > 1 && v == skip {178                return;179            }180            total += 1;181            run += mu as i64;182            peak = peak.max(run.unsigned_abs());183        });184        if has01 {185            total += 1;186            run += mobius(boundary, primes) as i64;187            peak = peak.max(run.unsigned_abs());188        }189        counts[lev] = total;190        meter[lev] = run;191        mmax[lev] = peak;192        for (slot, tl) in twisted.iter_mut().zip(tw_len.iter()) {193            slot.1[lev] = slot.1[lev - 1] + tl;194        }195    }196    Outcome {197        counts,198        meter,199        mmax,200        twisted,201    }202}