use num_traits::Float;
use strafe_type::{FloatConstraint, Positive64, Probability64, Real64};
use crate::{
distribution::{gamma::rgamma, pois::rpois},
traits::RNG,
};
pub fn rnbinom<PO: Into<Positive64>, PR: Into<Probability64>, R: RNG>(
size: PO,
prob: PR,
rng: &mut R,
) -> Real64 {
let mut size = size.into().unwrap();
let prob = prob.into().unwrap();
if !prob.is_finite() || size <= 0.0 || prob <= 0.0 {
return f64::nan().into();
}
if !size.is_finite() {
size = f64::MAX / 2.0
}
if prob == 1.0 {
0.0.into()
} else {
let a = size;
let scale = (1.0 - prob) / prob;
let mu = rgamma(a, scale, rng).unwrap();
rpois(mu, rng)
}
}
pub fn rnbinom_mu<PO1: Into<Positive64>, PO2: Into<Positive64>, R: RNG>(
size: PO1,
mu: PO2,
rng: &mut R,
) -> Real64 {
let mut size = size.into().unwrap();
let mu = mu.into().unwrap();
if !mu.is_finite() || size <= 0.0 {
return f64::nan().into();
}
if !size.is_finite() {
size = f64::MAX / 2.0
}
if mu == 0.0 {
0.0.into()
} else {
let mu = rgamma(size, mu / size, rng).unwrap();
rpois(mu, rng)
}
}