use std::collections::BTreeMap;
use std::collections;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Factors(BTreeMap<u64, u8>);
impl Factors {
pub fn of(n: u64, primes: &Primes) -> Option<Self> {
let mut factors = BTreeMap::new();
match n {
0 => None,
1 => Some(Factors(factors)),
_ => {
let mut n = n;
for p in &primes.0 {
let p = *p;
while n % p == 0 {
*factors.entry(p).or_insert(0) += 1;
n /= p;
}
if p > n {
return Some(Factors(factors)); }
}
None }
}
}
pub fn is_empty(&self) -> bool {
return self.0.is_empty();
}
pub fn mul(&self, rhs: &Self) -> Self {
let mut product = self.0.clone();
for (k, v) in &rhs.0 {
*product.entry(*k).or_insert(0) += v;
}
Factors(product)
}
pub fn totient(&self) -> u64 {
if self.is_empty() {
return 0;
}
let mut totient = 1;
for (p, exp) in &self.0 {
totient *= p.pow(*exp as u32) - p.pow(*exp as u32 - 1)
}
totient
}
pub fn is_subset(&self, other: &Self) -> bool {
for (base, exp) in &self.0 {
if other.get(*base) <= *exp {
return false;
}
}
true
}
pub fn is_superset(&self, other: &Self) -> bool {
return other.is_subset(self);
}
pub fn get(&self, k: u64) -> u8 {
if let Some(exp) = self.0.get(&k) {
*exp
} else {
0
}
}
pub fn divisor_count(&self) -> u64 {
let mut divisors = 1;
for (_, exp) in &self.0 {
divisors *= *exp as u64 + 1;
}
divisors
}
pub fn union(&self, b: &Factors) -> Factors {
let mut union = self.0.clone();
for (k, v) in &b.0 {
if !union.contains_key(k) {
union.insert(*k, *v);
} else {
let m = union[k];
union.insert(*k, m.max(*v));
}
}
Factors(union)
}
pub fn intersection(&self, b: &Factors) -> Factors {
let b = &b.0;
let mut intersection = BTreeMap::new();
for (k, v) in &self.0 {
if b.contains_key(&k) {
let min = v.min(&b[&k]);
intersection.insert(*k, *min);
}
}
Factors(intersection)
}
}
impl IntoIterator for Factors {
type Item = (u64, u8);
type IntoIter = collections::btree_map::IntoIter<u64, u8>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl Into<u64> for Factors {
fn into(self) -> u64 {
self.into_iter()
.fold(1, |n, (base, exp)| n * (base.pow(exp as u32)))
}
}
impl Into<BTreeMap<u64, u8>> for Factors {fn into(self) -> BTreeMap<u64, u8> {self.0}}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Primes(Vec<u64>);
impl Primes {
pub fn max(&self) -> Option<u64> {
if self.0.len() == 0 {
None
} else {
Some(self.0[self.0.len() - 1])
}
}
pub fn under(max: u64) -> Self {
let mut primes = Primes(Vec::new());
if max < 2 {
return primes;
}
primes.0.push(2);
let mut n = 3;
while n < max {
let mut isprime = true;
for p in &primes.0 {
if n % p == 0 {
isprime = false;
break;
}
}
if isprime {
primes.0.push(n);
}
n += 2
}
primes
}
pub fn first_n(size: usize) -> Self {
let mut primes = Vec::new();
if size == 0 {
return Primes(primes);
}
primes.push(2);
let mut m = 3;
while primes.len() < size {
let mut isprime = true;
for p in &primes {
if m % p == 0 {
isprime = false;
break;
}
}
if isprime {
primes.push(m);
}
m += 2
}
Primes(primes)
}
pub fn lcm(&self, m: u64, n: u64) -> Option<u64> {
match (m, n) {
(0, 0) => Some(0),
(0, _) | (_, 0) => None,
(m, 1) => Some(m),
(1, n) => Some(n),
(m, n) => {
let m_factors = Factors::of(m, self)?;
let n_factors = Factors::of(n, self)?;
let mut lcm = 1;
for (p, exp) in m_factors.union(&n_factors) {
lcm *= p.pow(exp as u32);
}
Some(lcm)
}
}
}
pub fn gcd(&self, m: u64, n: u64) -> Option<u64> {
match (m, n) {
(0, _) | (_, 0) => None,
(1, _) | (_, 1) => Some(1),
(m, n) => {
let mut gcd = 1;
let (m_factors, n_factors) = (&Factors::of(m, self)?, &Factors::of(n, self)?);
for (p, exp) in m_factors.intersection(n_factors){
gcd *= p.pow(exp as u32);
}
Some(gcd)
}
}
}
pub unsafe fn from_raw_vec(v: Vec<u64>) -> Self {
Primes(v)
}
}
impl Into<Vec<u64>> for Primes {
fn into(self) -> Vec<u64> {
self.0
}
}