use crate::number::{
instances::int::Int,
traits::{fractional::Fractional, integral::Integral, number::Number, real::Real},
};
pub fn i8_div_mod(lhs: i8, rhs: i8) -> (i8, i8) {
let quot = lhs / rhs;
let rem = lhs % rhs;
if rem == 0i8 || (quot >= 0i8 && rem > 0i8) {
(quot, rem)
} else {
(quot - 1, lhs - (quot - 1) * rhs)
}
}
pub fn permutation<N>(elements: &[N]) -> Vec<Vec<N>>
where
N: Clone + PartialEq,
{
let mut all_permutations = Vec::new();
fn permutation_inner<N>(elements: &[N], permu: &[N], acc: &mut Vec<Vec<N>>)
where
N: Clone + PartialEq,
{
if elements.is_empty() {
acc.push(permu.to_vec());
} else {
for elem in elements {
let mut next = permu.to_vec();
next.push(elem.clone());
permutation_inner(
&elements
.iter()
.filter(|e| e != &elem)
.cloned()
.collect::<Vec<N>>(),
&next,
acc,
);
}
}
}
permutation_inner(elements, &[], &mut all_permutations);
all_permutations
}
pub fn inversion_count<N>(elements: &[N]) -> usize
where
N: Clone + PartialOrd,
{
let mut exchange = 0;
if !elements.is_empty() {
let mut cloned = elements.to_vec();
for idx in 0..(elements.len() - 1) {
let mut min = idx;
for p in (idx + 1)..elements.len() {
if cloned[p] < cloned[min] {
min = p;
}
}
if min != idx {
(cloned[idx], cloned[min]) = (cloned[min].clone(), cloned[idx].clone());
exchange += 1;
}
}
}
exchange
}
pub fn non_negative_integral_power<N: Number, I: Integral>(base: N, exponents: I) -> Option<N> {
fn inner_power<N: Number, I: Integral>(base: N, exponents: I) -> N {
if exponents.is_even() {
inner_power(base.clone() * base, exponents.quotient(I::one() + I::one()))
} else if exponents.is_one() {
base
} else {
inner_power_acc(
base.clone() * base.clone(),
exponents.quotient(I::one() + I::one()),
base,
)
}
}
fn inner_power_acc<N: Number, I: Integral>(base: N, exponents: I, acc: N) -> N {
if exponents.is_even() {
inner_power_acc(
base.clone() * base,
exponents.quotient(I::one() + I::one()),
acc,
)
} else if exponents.is_one() {
acc * base
} else {
inner_power_acc(
base.clone() * base.clone(),
exponents.quotient(I::one() + I::one()),
acc * base,
)
}
}
if exponents < I::zero() {
eprintln!(
concat!(
"Error[number::utils::non_negative_integral_power]: ",
"Negative exponents ({}) are not allowed."
),
exponents
);
None
} else if exponents == I::zero() {
Some(N::one())
} else if base == N::zero() {
Some(N::zero())
} else {
Some(inner_power(base, exponents))
}
}
pub fn clamp(first: Int, second: Int) -> Int { (-first.clone()).max(first.min(second)) }
pub fn integral_power<F: Fractional, I: Integral>(base: F, exponents: I) -> Option<F> {
if exponents < I::zero() {
non_negative_integral_power(base, -exponents).map(|v| v.reciprocal())
} else {
non_negative_integral_power(base, exponents)
}
}
pub fn gcd<I: Integral>(lhs: I, rhs: I) -> I {
fn inner_gcd<I: Integral>(lhs: I, rhs: I) -> I {
if rhs == I::zero() || lhs == rhs {
lhs
} else {
inner_gcd(rhs.clone(), lhs.remainder(rhs))
}
}
inner_gcd(lhs.absolute_value(), rhs.absolute_value())
}
pub fn lcm<I: Integral>(lhs: I, rhs: I) -> I {
if lhs.is_zero() || rhs.is_zero() {
I::zero()
} else {
lhs.clone().quotient(gcd(lhs, rhs.clone())) * rhs
}
}
pub fn from_integral<N: Number, I: Integral>(integral_number: I) -> N { N::from_integer(integral_number.to_integer()) }
pub fn real_to_frac<R: Real, F: Fractional>(real_number: R) -> F { F::from_rational(real_number.to_rational()) }
pub fn integral_to_binary<I: Integral>(int_val: I) -> Vec<u8> {
fn integral_to_binary_inner<I: Integral>(int: I, acc: &mut Vec<u8>) {
if int == I::zero() {
acc.insert(0, 0u8);
} else if int == I::one() {
acc.insert(0, 1u8);
} else {
let two: I = I::one() + I::one();
let (d, m) = int.div_mod(two);
format!("{m}").chars().next().map_or_else(
|| {
eprintln!(
concat!(
"Error[number::utils::decimal_to_binary]: ",
"Failed to retrieve the value of the modulus ({})"
),
m
)
},
|c| acc.insert(0, c as u8 - b'0'),
);
integral_to_binary_inner(d, acc);
}
}
let mut bin = Vec::new();
let val = int_val.absolute_value();
integral_to_binary_inner(val, &mut bin);
bin.insert(0, 0u8);
if int_val < I::zero() {
let mut complement = vec![0u8; bin.len()];
let mut sup = 1u8;
for (idx, e) in bin
.iter()
.map(|&e| if e == 1u8 { 0u8 } else { 1u8 })
.enumerate()
.rev()
{
if sup == 1u8 && e == 1u8 {
complement[idx] = 0u8;
} else if sup == 1u8 && e == 0u8 {
complement[idx] = 1u8;
sup = 0u8;
} else if sup == 1u8 && idx == 0usize {
complement.insert(1usize, 1u8);
} else {
complement[idx] = e;
}
}
bin = complement;
}
bin
}