#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn factorial(n: u64) -> f64 {
if n > 170 {
return f64::INFINITY;
}
(1..=n).map(|i| i as f64).product()
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn permutations(
n: u64,
k: u64,
) -> f64 {
if k > n {
return 0.0;
}
(n - k + 1..=n).map(|i| i as f64).product()
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn combinations(
n: u64,
k: u64,
) -> f64 {
if k > n {
return 0.0;
}
if k == 0 || k == n {
return 1.0;
}
if k > n / 2 {
return combinations(n, n - k);
}
let mut res = 1.0;
for i in 1..=k {
res = res * (n - i + 1) as f64 / i as f64;
}
res
}
pub fn solve_recurrence_numerical(
coeffs: &[f64],
initial_conditions: &[f64],
target_n: usize,
) -> Result<f64, String> {
let order = coeffs.len();
if initial_conditions.len() != order {
return Err("Number of initial \
conditions must match \
the order of the \
recurrence."
.to_string());
}
if target_n < order {
return Ok(initial_conditions[target_n]);
}
let mut values = initial_conditions.to_vec();
for n in order..=target_n {
let mut next_val = 0.0;
for i in 0..order {
next_val += coeffs[i] * values[n - 1 - i];
}
values.push(next_val);
}
match values.last() {
| Some(v) => Ok(*v),
| None => {
Err("Failed to compute \
the recurrence \
relation, values \
vector was empty."
.to_string())
},
}
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn stirling_second(
n: u64,
k: u64,
) -> f64 {
if k > n {
return 0.0;
}
if k == 0 {
return if n == 0 { 1.0 } else { 0.0 };
}
if k == n {
return 1.0;
}
if k == 1 {
return 1.0;
}
let mut sum = 0.0;
for j in 0..=k {
let term = combinations(k, j) * (j as f64).powf(n as f64);
if (k - j) % 2 == 1 {
sum -= term;
} else {
sum += term;
}
}
sum / factorial(k)
}
#[must_use]
pub fn bell(n: u64) -> f64 {
(0..=n).map(|k| stirling_second(n, k)).sum()
}
#[must_use]
pub fn catalan(n: u64) -> f64 {
combinations(2 * n, n) / ((n + 1) as f64)
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn rising_factorial(
x: f64,
n: u64,
) -> f64 {
if n == 0 {
return 1.0;
}
let mut res = 1.0;
for i in 0..n {
res *= x + (i as f64);
}
res
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn falling_factorial(
x: f64,
n: u64,
) -> f64 {
if n == 0 {
return 1.0;
}
let mut res = 1.0;
for i in 0..n {
res *= x - (i as f64);
}
res
}