#![doc = include_str!("../README.md")]
pub mod digits;
pub mod factors;
pub mod linalg;
pub mod primes;
pub mod probability;
pub mod sequences;
pub mod statistics;
use std::borrow::Borrow;
use std::collections::HashSet;
use std::hash::Hash;
use std::iter;
use std::mem;
use factors::distinct_prime_factors;
use malachite::Integer;
use malachite::base::num::basic::traits::{One, Zero};
use malachite::rational::Rational;
use num_traits::{ConstOne, ConstZero, PrimInt, ToPrimitive};
use primes::sieve_of_eratosthenes;
#[cfg_attr(doc, katexit::katexit)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct SimpleContinuedFraction<T> {
non_periodic: Vec<T>,
periodic: Option<Vec<T>>,
}
impl<T> SimpleContinuedFraction<T>
where
T: PrimInt + ConstZero + ConstOne + Into<Integer>,
{
pub fn new<U, V>(non_periodic: U, periodic: Option<U>) -> Self
where
U: IntoIterator<Item = V>,
V: Borrow<T>,
{
let non_periodic = non_periodic.into_iter().map(|x| *x.borrow()).collect();
let periodic = periodic.map(|p| p.into_iter().map(|x| *x.borrow()).collect());
Self {
non_periodic,
periodic,
}
}
pub fn from_sqrt(n: T) -> Self
where
T: Hash,
{
if n < T::ZERO {
panic!("Cannot calculate square root of a negative integer.");
}
let root = T::from(n.to_f64().expect("Cannot convert n to f64.").sqrt().floor()).unwrap();
let non_periodic = vec![root];
let mut periodic = None;
if root * root != n {
periodic = Some(Vec::new());
let mut set = HashSet::new();
let mut num = root;
let mut denom = T::ONE;
while !set.contains(&(num, denom)) {
set.insert((num, denom));
denom = (n - num * num) / denom;
let expanded_val = (num + root) / denom;
periodic.as_mut().unwrap().push(expanded_val);
num = denom * expanded_val - num; }
}
Self {
non_periodic,
periodic,
}
}
pub fn non_periodic(&self) -> &[T] {
&self.non_periodic
}
pub fn periodic(&self) -> Option<&[T]> {
self.periodic.as_deref()
}
pub fn convergents(&self) -> impl Iterator<Item = Rational> {
let mut prev_num = Integer::ZERO;
let mut prev_den = Integer::ONE;
let mut num = Integer::ONE;
let mut den = Integer::ZERO;
let mut values = self
.non_periodic
.iter()
.chain(self.periodic.iter().flat_map(|v| v.iter().cycle()));
iter::from_fn(move || {
let next_value = values.next()?;
let next_num = (*next_value).into() * &num + &prev_num;
let next_den = (*next_value).into() * &den + &prev_den;
prev_num = mem::replace(&mut num, next_num);
prev_den = mem::replace(&mut den, next_den);
Some(Rational::from_integers_ref(&num, &den))
})
}
}
#[cfg_attr(doc, katexit::katexit)]
pub fn ord<T>(a: T, n: T) -> T
where
T: PrimInt + ConstOne,
{
let t2 = T::from(2).unwrap();
if n < t2 || a < t2 {
panic!("a and n must be greater than or equal to 2.");
}
let mut result = T::ONE;
let mut k = T::ONE;
while k < n {
result = (result * a) % n;
if result == T::ONE {
return k;
}
k = k + T::ONE;
}
panic!("a and n are not coprime.");
}
#[cfg_attr(doc, katexit::katexit)]
pub fn partition_p<T>(n: T) -> T
where
T: PrimInt + ConstZero + ConstOne,
{
if n < T::ZERO {
return T::ZERO;
}
partition_p_0_to_n(n).pop().unwrap()
}
pub fn partition_p_0_to_n<T>(n: T) -> Vec<T>
where
T: PrimInt + ConstZero + ConstOne,
{
let n = n.to_usize().expect("Cannot convert n to usize.");
if n == 0 {
return vec![T::ONE];
}
let mut partitions = Vec::with_capacity(n + 1);
partitions.push(T::ONE); partitions.push(T::ONE);
while partitions.len() <= n {
let curr_n = partitions.len();
let mut next_val = T::ZERO;
for k in 1..=curr_n {
let left_value = match curr_n.checked_sub((k * (3 * k - 1)) / 2) {
Some(ind) => partitions[ind],
None => break, };
let right_value = match curr_n.checked_sub((k * (3 * k + 1)) / 2) {
Some(ind) => partitions[ind],
None => T::ZERO,
};
let value = left_value + right_value;
if k % 2 == 0 {
next_val = next_val - value;
} else {
next_val = next_val + value;
}
}
partitions.push(next_val);
}
partitions
}
#[cfg_attr(doc, katexit::katexit)]
pub fn partition_prime<T>(n: T) -> T
where
T: PrimInt + ConstZero + ConstOne,
{
if n < T::ZERO {
return T::ZERO;
}
partition_prime_0_to_n(n).pop().unwrap()
}
pub fn partition_prime_0_to_n<T>(n: T) -> Vec<T>
where
T: PrimInt + ConstZero + ConstOne,
{
let n = n.to_usize().expect("Cannot convert n to usize.");
let primes = sieve_of_eratosthenes(n);
let mut dp = vec![T::ZERO; n + 1];
dp[0] = T::ONE;
for prime in primes {
for i in prime..=n {
dp[i] = dp[i] + dp[i - prime];
}
}
dp
}
#[cfg_attr(doc, katexit::katexit)]
pub fn factorial<T>(n: T) -> T
where
T: PrimInt + ConstOne,
{
let mut fact = T::ONE;
let mut i = T::ONE;
while i < n {
i = i + T::ONE;
fact = fact * i;
}
fact
}
pub fn factorial_0_to_n<T>(n: T) -> Vec<T>
where
T: PrimInt + ConstOne,
{
let n = n.to_usize().expect("Cannot convert n to usize.");
let mut factorials = vec![T::ONE; n + 1];
for i in 2..=n {
factorials[i] = factorials[i - 1] * T::from(i).unwrap();
}
factorials
}
pub fn isqrt<T>(n: T) -> T
where
T: PrimInt + ConstZero + ConstOne,
{
if n < T::ZERO {
panic!("Cannot calculate square root of a negative integer.");
} else if n <= T::ONE {
n
} else {
let t2 = T::from(2).unwrap();
let mut x0 = t2.pow((n.to_u128().unwrap().ilog2() / 2) + 1);
let mut x1 = (x0 + n / x0) / t2;
while x1 < x0 {
x0 = x1;
x1 = (x0 + n / x0) / t2;
}
x0
}
}
pub fn gcd<T>(mut num1: T, mut num2: T) -> T
where
T: PrimInt + ConstZero,
{
if num1 < T::ZERO || num2 < T::ZERO {
panic!("Cannot calculate GCD of negative numbers.");
}
if num1 < num2 {
(num1, num2) = (num2, num1);
}
while num2 > T::ZERO {
(num1, num2) = (num2, num1 % num2);
}
num1
}
pub fn gcd_multiple<T, U, I>(nums: I) -> T
where
T: PrimInt + ConstZero,
U: Borrow<T>,
I: IntoIterator<Item = U>,
{
let mut nums = nums.into_iter();
let n1 = match nums.next() {
Some(x) => *x.borrow(),
None => T::ZERO,
};
let n2 = match nums.next() {
Some(x) => *x.borrow(),
None => T::ZERO,
};
let mut result = gcd(n1, n2);
for n in nums {
result = gcd(result, *n.borrow());
}
result
}
pub fn lcm<T>(n1: T, n2: T) -> T
where
T: PrimInt + ConstZero,
{
let gcd = gcd(n1, n2);
if gcd == T::ZERO {
T::ZERO
} else {
(n1 / gcd) * n2
}
}
pub fn lcm_multiple<T, U, I>(nums: I) -> T
where
T: PrimInt + ConstZero,
U: Borrow<T>,
I: IntoIterator<Item = U>,
{
let mut nums = nums.into_iter();
let n1 = match nums.next() {
Some(x) => *x.borrow(),
None => T::ZERO,
};
let n2 = match nums.next() {
Some(x) => *x.borrow(),
None => T::ZERO,
};
let mut result = lcm(n1, n2);
for n in nums {
result = lcm(result, *n.borrow());
}
result
}
pub fn newtons_method<T, F, D>(x0: T, precision: f64, function: F, derivative: D) -> Option<f64>
where
T: ToPrimitive,
F: Fn(f64) -> f64,
D: Fn(f64) -> f64,
{
let mut x = x0.to_f64().expect("Cannot convert x0 to f64.");
let mut prev_x = f64::NEG_INFINITY;
while (x - prev_x).abs() > precision {
prev_x = x;
let derivative_value = derivative(prev_x);
if derivative_value == 0.0 {
return None; }
x = prev_x - function(prev_x) / derivative_value;
}
Some(x)
}
pub fn phi<T>(n: T) -> T
where
T: PrimInt + ConstZero + ConstOne,
{
distinct_prime_factors(n)
.map(|(factor, _)| factor)
.fold(n, |acc, factor| acc - (acc / factor))
}
pub fn phi_0_to_n<T>(n: T) -> Vec<T>
where
T: PrimInt + ConstZero + ConstOne,
{
let n = n.to_usize().expect("Cannot convert n to usize.");
let mut phi_values = Vec::with_capacity(n + 1);
phi_values.push(T::ZERO);
for _ in 0..n {
phi_values.push(*phi_values.last().unwrap() + T::ONE);
}
for i in 2..=n {
let ti = T::from(i).unwrap();
if phi_values[i] == ti {
for j in (i..=n).step_by(i) {
phi_values[j] = phi_values[j] - phi_values[j] / ti;
}
}
}
phi_values
}