gaussian.rs

4.2 kB · rust · 160 lines

1use std::collections::HashSet;23pub fn least_factors(limit: usize) -> Vec<u32> {4    let mut out = vec![0u32; limit + 1];5    for value in 2..=limit {6        if out[value] == 0 {7            let mut multiple = value;8            while multiple <= limit {9                if out[multiple] == 0 {10                    out[multiple] = value as u32;11                }12                multiple += value;13            }14        }15    }16    out17}1819pub fn factorise(mut value: usize, least: &[u32]) -> Vec<(usize, usize)> {20    let mut out: Vec<(usize, usize)> = Vec::new();21    while value > 1 {22        let prime = least[value] as usize;23        let mut power = 0;24        while value % prime == 0 {25            value /= prime;26            power += 1;27        }28        out.push((prime, power));29    }30    out31}3233pub fn two_square(value: usize, least: &[u32]) -> bool {34    factorise(value, least)35        .iter()36        .all(|(prime, power)| prime % 4 != 3 || power % 2 == 0)37}3839pub fn primitive_norm(value: usize, least: &[u32]) -> bool {40    if value == 1 || value == 2 {41        return true;42    }43    let parts = factorise(value, least);44    parts.iter().all(|(prime, power)| match prime % 4 {45        1 => true,46        2 => *power == 1,47        _ => false,48    })49}5051pub fn new_disc(scale: usize, least: &[u32]) -> usize {52    let cap = 2 * scale * scale;53    let primes: Vec<usize> = factorise(scale, least).iter().map(|(p, _)| *p).collect();54    (1..=cap)55        .filter(|norm| two_square(*norm, least))56        .filter(|norm| primes.iter().all(|prime| norm % (prime * prime) != 0))57        .count()58}5960pub fn two_square_prefix(cap: usize, least: &[u32]) -> Vec<usize> {61    let mut out = vec![0usize; cap + 1];62    for norm in 1..=cap {63        out[norm] = out[norm - 1] + usize::from(two_square(norm, least));64    }65    out66}6768pub fn mobius_count(scale: usize, prefix: &[usize], least: &[u32]) -> usize {69    let primes: Vec<usize> = factorise(scale, least).iter().map(|(p, _)| *p).collect();70    let cap = 2 * scale * scale;71    let mut total = 0i64;72    for mask in 0..1usize << primes.len() {73        let mut divisor = 1usize;74        let mut sign = 1i64;75        for (index, prime) in primes.iter().enumerate() {76            if mask >> index & 1 == 1 {77                divisor *= prime;78                sign = -sign;79            }80        }81        total += sign * prefix[cap / (divisor * divisor)] as i64;82    }83    total as usize84}8586pub fn jordan(scale: usize, least: &[u32]) -> f64 {87    factorise(scale, least)88        .iter()89        .map(|(prime, _)| 1.0 - 1.0 / (prime * prime) as f64)90        .product()91}9293fn reduce(mut top: u64, mut bottom: u64) -> (u64, u64) {94    let mut a = top;95    let mut b = bottom;96    while b != 0 {97        let next = a % b;98        a = b;99        b = next;100    }101    top /= a;102    bottom /= a;103    (top, bottom)104}105106pub fn disc_norms(scale: usize) -> Vec<u64> {107    let cap = 2 * scale * scale;108    let mut seen = vec![false; cap + 1];109    let reach = (cap as f64).sqrt() as usize + 1;110    for a in 0..=reach {111        for b in 0..=reach {112            let norm = a * a + b * b;113            if norm >= 1 && norm <= cap {114                seen[norm] = true;115            }116        }117    }118    (1..=cap)119        .filter(|norm| seen[*norm])120        .map(|norm| norm as u64)121        .collect()122}123124pub fn box_norms(scale: usize) -> Vec<u64> {125    let cap = 2 * scale * scale;126    let mut seen = vec![false; cap + 1];127    for a in 0..=scale {128        for b in 0..=scale {129            let norm = a * a + b * b;130            if norm >= 1 {131                seen[norm] = true;132            }133        }134    }135    (1..=cap)136        .filter(|norm| seen[*norm])137        .map(|norm| norm as u64)138        .collect()139}140141pub fn union_counts(top: usize, boxed: bool) -> Vec<usize> {142    let mut seen: HashSet<(u64, u64)> = HashSet::new();143    let mut out = Vec::new();144    for scale in 1..=top {145        let norms = if boxed {146            box_norms(scale)147        } else {148            disc_norms(scale)149        };150        let square = (scale * scale) as u64;151        let mut fresh = 0;152        for norm in norms {153            if seen.insert(reduce(norm, square)) {154                fresh += 1;155            }156        }157        out.push(fresh);158    }159    out160}