use crate::primes::sieve_of_eratosthenes;
use num_traits::{ConstOne, ConstZero, PrimInt};
use std::iter::Sum;
use std::iter::from_fn;
use std::vec::IntoIter;
#[derive(Clone)]
pub struct PrimeFactors<T> {
n: T,
factor: T,
prime_table: IntoIter<T>,
}
impl<T: PrimInt + ConstZero + ConstOne> PrimeFactors<T> {
pub fn new(n: T) -> Self {
if n < T::ZERO {
panic!("Cannot find prime factors of negative numbers.");
}
let mut prime_table = sieve_of_eratosthenes(
T::from(n.to_f64().expect("Cannot convert to f64").sqrt().floor()).unwrap(),
)
.into_iter();
let factor = prime_table.next().unwrap_or(T::from(2).unwrap());
Self {
n,
factor,
prime_table,
}
}
}
impl<T: PrimInt + ConstZero + ConstOne> Iterator for PrimeFactors<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
while self.n >= self.factor {
if self.n % self.factor == T::ZERO {
self.n = self.n / self.factor;
return Some(self.factor);
}
match self.prime_table.next() {
Some(next_factor) => {
self.factor = next_factor;
}
None => {
if self.n != T::ONE {
self.factor = self.n;
} else {
return None;
}
}
}
}
None
}
}
#[derive(Clone)]
pub struct DistinctPrimeFactors<T> {
prime_factors: PrimeFactors<T>,
factor: T,
factor_count: usize,
}
impl<T: PrimInt + ConstZero + ConstOne> DistinctPrimeFactors<T> {
pub fn new(n: T) -> Self {
let prime_factors = PrimeFactors::new(n);
let factor = T::ZERO;
let factor_count = 0;
Self {
prime_factors,
factor,
factor_count,
}
}
}
impl<T: PrimInt + ConstZero + ConstOne> Iterator for DistinctPrimeFactors<T> {
type Item = (T, usize);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.prime_factors.next() {
Some(next_factor) => {
if next_factor == self.factor {
self.factor_count += 1;
} else {
let ret = (self.factor, self.factor_count);
self.factor = next_factor;
self.factor_count = 1;
if ret.1 != 0 {
return Some(ret);
}
}
}
None => {
return if self.factor_count != 0 {
let ret = (self.factor, self.factor_count);
self.factor_count = 0;
Some(ret)
} else {
None
};
}
}
}
}
}
pub fn prime_factors<T: PrimInt + ConstZero + ConstOne>(n: T) -> PrimeFactors<T> {
PrimeFactors::new(n)
}
pub fn distinct_prime_factors<T: PrimInt + ConstZero + ConstOne>(n: T) -> DistinctPrimeFactors<T> {
DistinctPrimeFactors::new(n)
}
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct Divisors<T> {
factors: Vec<(T, usize, T, usize)>,
value: T,
num_of_divisors: usize,
curr_num: usize,
sum_of_divisors: T,
curr_sum: T,
}
impl<T: PrimInt + ConstZero + ConstOne> Divisors<T> {
pub fn new(n: T) -> Self {
let mut factors = DistinctPrimeFactors::new(n)
.map(|(prime, count)| (prime, count, T::ONE, 0))
.collect::<Vec<_>>();
let value = T::ONE;
let num_of_divisors = factors.iter().map(|(_, a, _, _)| a + 1).product();
let curr_num = if n == T::ZERO { 1 } else { 0 };
let sum_of_divisors = if n == T::ZERO {
T::ZERO
} else {
let mut current_sum = T::ONE;
for fact in &factors {
let p = fact.0;
let a = fact.1;
current_sum = current_sum * (p.pow(a as u32 + 1) - T::ONE) / (p - T::ONE);
}
current_sum
};
let curr_sum = T::ZERO;
if n == T::ONE {
factors.push((T::ONE, 1, T::ONE, 0));
}
Self {
factors,
value,
num_of_divisors,
curr_num,
sum_of_divisors,
curr_sum,
}
}
}
impl<T: PrimInt + ConstOne + Sum<T>> Iterator for Divisors<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.curr_num == self.num_of_divisors {
return None;
}
let ret_value = self.value;
self.curr_num += 1;
self.curr_sum = self.curr_sum + ret_value;
if self.curr_num < self.num_of_divisors {
let mut i = self.factors.len() - 1;
loop {
if self.factors[i].3 < self.factors[i].1 {
self.factors[i].3 += 1;
self.factors[i].2 = self.factors[i].2 * self.factors[i].0;
self.value = self.value * self.factors[i].0;
break;
} else {
self.factors[i].3 = 0;
self.value = self.value / self.factors[i].2;
self.factors[i].2 = T::ONE;
i -= 1;
}
}
}
Some(ret_value)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.num_of_divisors - self.curr_num;
(size, Some(size))
}
fn count(self) -> usize {
self.len()
}
fn sum<S: Sum<Self::Item>>(self) -> S {
let mut returned = false;
Sum::sum(from_fn(|| {
if returned {
None
} else {
returned = true;
Some(self.sum_of_divisors - self.curr_sum)
}
}))
}
}
impl<T: PrimInt + ConstOne + Sum<T>> ExactSizeIterator for Divisors<T> {}
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct ProperDivisors<T> {
n: T,
divisors: Divisors<T>,
}
impl<T: PrimInt + ConstZero + ConstOne> ProperDivisors<T> {
pub fn new(n: T) -> Self {
let divisors = Divisors::new(n);
Self { n, divisors }
}
}
impl<T: PrimInt + ConstZero + ConstOne + Sum<T>> Iterator for ProperDivisors<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match self.divisors.next() {
Some(val) => {
if val != self.n {
Some(val)
} else {
None
}
}
None => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.divisors.len().saturating_sub(1);
(size, Some(size))
}
fn count(self) -> usize {
self.len()
}
fn sum<S: Sum<Self::Item>>(self) -> S {
let mut divisors_sum = self.divisors.sum();
if divisors_sum > T::ZERO {
divisors_sum = divisors_sum - self.n;
}
let mut returned = false;
Sum::sum(from_fn(|| {
if returned {
None
} else {
returned = true;
Some(divisors_sum)
}
}))
}
}
impl<T: PrimInt + ConstZero + ConstOne + Sum<T>> ExactSizeIterator for ProperDivisors<T> {}
pub fn divisors<T: PrimInt + ConstZero + ConstOne>(n: T) -> Divisors<T> {
Divisors::new(n)
}
pub fn proper_divisors<T: PrimInt + ConstZero + ConstOne>(n: T) -> ProperDivisors<T> {
ProperDivisors::new(n)
}
pub fn num_of_divisors_0_to_n<T>(n: T) -> Vec<T>
where
T: PrimInt + ConstZero + ConstOne,
{
if n < T::ZERO {
panic!("Cannot find divisors of negative numbers.");
}
let n = n.to_usize().expect("Cannot convert n to usize.");
let mut divisors = vec![T::ONE; n + 1];
divisors[0] = T::ZERO;
for i in 2..=n {
for j in (i..=n).step_by(i) {
divisors[j] = divisors[j] + T::ONE;
}
}
divisors
}
pub fn num_of_proper_divisors_0_to_n<T>(n: T) -> Vec<T>
where
T: PrimInt + ConstZero + ConstOne,
{
if n < T::ZERO {
panic!("Cannot find proper divisors of negative numbers.");
}
let n = n.to_usize().expect("Cannot convert n to usize.");
let mut divisors = vec![T::ZERO; n + 1];
for i in 2..=n {
for j in (i..=n).step_by(i) {
divisors[j] = divisors[j] + T::ONE;
}
}
divisors
}
pub fn sum_of_divisors_0_to_n<T>(n: T) -> Vec<T>
where
T: PrimInt + ConstZero,
{
if n < T::ZERO {
panic!("Cannot find divisors of negative numbers.");
}
let n = n.to_usize().expect("Cannot convert n to usize.");
let mut divisors = vec![T::ZERO; n + 1];
for i in 1..=n {
for j in (i..=n).step_by(i) {
divisors[j] = divisors[j] + T::from(i).unwrap();
}
}
divisors
}
pub fn sum_of_proper_divisors_0_to_n<T>(n: T) -> Vec<T>
where
T: PrimInt + ConstZero,
{
if n < T::ZERO {
panic!("Cannot find proper divisors of negative numbers.");
}
let n = n.to_usize().expect("Cannot convert n to usize.");
let mut divisors = vec![T::ZERO; n + 1];
for i in 1..=n {
for j in ((2 * i)..=n).step_by(i) {
divisors[j] = divisors[j] + T::from(i).unwrap();
}
}
divisors
}