use strafe_type::{FloatConstraint, Natural64, Probability64, Real64};
use crate::func::lgamma;
pub fn pbirthday<R: Into<Real64>, N1: Into<Natural64>, N2: Into<Natural64>>(
q: R,
classes: N1,
coincident: N2,
) -> Probability64 {
let n = q.into().unwrap();
let k = coincident.into().unwrap();
let c = classes.into().unwrap();
if k < 2.0 {
1.0.into()
} else if k == 2.0 {
let mut lhs = c as isize;
let mut rhs = c as isize - n as isize + 1;
if lhs > rhs {
std::mem::swap(&mut lhs, &mut rhs);
}
let temp = 1.0
- (lhs..rhs)
.map(|c1| c1 as f64 / c)
.fold(1.0, |acc, c1| acc * c1);
temp.into()
} else if k > n {
0.0.into()
} else if n > c * (k - 1.0) {
1.0.into()
} else {
let LHS = n * (-n / (c * k)).exp() / (1.0 - n / (c * (k + 1.0))).powf(1.0 / k);
let lxx = k * LHS.ln() - (k - 1.0) * c.ln() - lgamma(k + 1.0).unwrap();
(-(-lxx.exp()).exp_m1()).into()
}
}