pub fn sieve(limit: usize) -> Sieve {
let primes = Vec::new();
let mut is_composite = vec![false; limit + 1];
is_composite[0] = true;
is_composite[1] = true;
Sieve {
primes,
is_composite,
}
}
pub struct Sieve {
primes: Vec<usize>,
is_composite: Vec<bool>,
}
impl Sieve {
pub fn primes<'a>(&'a mut self) -> Primes<'a> {
Primes {
idx_next_prime: 0,
sieve: self,
}
}
pub fn prime_factorization(&mut self, mut n: usize) -> Vec<(usize, usize)> {
let mut factorization: Vec<(usize, usize)> = Vec::new();
for p in self.prime_factors(n) {
let mut e = 0;
while n % p == 0 {
n /= p;
e += 1;
}
factorization.push((p, e));
}
factorization
}
pub fn prime_factors<'a>(&'a mut self, n: usize) -> PrimeFactors<'a> {
let limit = self.is_composite.len() - 1;
assert!(0 < n && n <= limit);
let primes = self.primes();
PrimeFactors { n, primes }
}
pub fn count_divisors(&mut self, n: usize) -> usize {
self.prime_factorization(n)
.into_iter()
.map(|(_, exp)| exp + 1)
.product()
}
pub fn euler_totient(&mut self, n: usize) -> usize {
if n > 0 {
self.prime_factors(n).fold(n, |m, p| m / p * (p - 1))
} else {
0
}
}
}
pub struct Primes<'a> {
idx_next_prime: usize,
sieve: &'a mut Sieve,
}
impl Iterator for Primes<'_> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
while self.idx_next_prime >= self.sieve.primes.len() {
self.sieve.next_prime()?;
}
let next_prime = self.sieve.primes.get(self.idx_next_prime).copied();
self.idx_next_prime += 1;
next_prime
}
}
pub struct PrimeFactors<'a> {
n: usize,
primes: Primes<'a>,
}
impl Iterator for PrimeFactors<'_> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
loop {
let p = self.primes.next()?;
if p > self.n {
return None;
} else if self.n % p == 0 {
return Some(p);
}
}
}
}
impl Sieve {
fn next_prime(&mut self) -> Option<usize> {
let limit = self.is_composite.len() - 1;
let start = self.primes.last().unwrap_or(&1) + 1;
let next_prime = (start..=limit).find(|i| !self.is_composite[*i]);
if let Some(p) = next_prime {
self.primes.push(p);
if let Some(p_square) = p.checked_mul(p) {
for i in (p_square..=limit).step_by(p) {
self.is_composite[i] = true;
}
}
}
next_prime
}
}