mod d;
mod p;
mod q;
mod r;
use strafe_type::{FloatConstraint, LogProbability64, PositiveInteger64, Probability64, Real64};
pub(crate) use self::{d::*, p::*, q::*, r::*};
use crate::traits::{Distribution, RNG};
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = embed_doc_image::embed_image!("density", "src/distribution/hyper/doctest_out/density.svg")))]
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = "![Density][density]"))]
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = include_str!("doctest_out/difference.md")))]
pub struct HyperGeometric {
group_1: PositiveInteger64,
group_2: PositiveInteger64,
number_drawn: PositiveInteger64,
}
impl Distribution for HyperGeometric {
fn density<R: Into<Real64>>(&self, x: R) -> Real64 {
dhyper(x, self.group_1, self.group_2, self.number_drawn, false)
}
fn log_density<R: Into<Real64>>(&self, x: R) -> Real64 {
dhyper(x, self.group_1, self.group_2, self.number_drawn, true)
}
fn probability<R: Into<Real64>>(&self, q: R, lower_tail: bool) -> Probability64 {
phyper(q, self.group_1, self.group_2, self.number_drawn, lower_tail)
}
fn log_probability<R: Into<Real64>>(&self, q: R, lower_tail: bool) -> LogProbability64 {
log_phyper(q, self.group_1, self.group_2, self.number_drawn, lower_tail)
}
fn quantile<P: Into<Probability64>>(&self, p: P, lower_tail: bool) -> Real64 {
qhyper(p, self.group_1, self.group_2, self.number_drawn, lower_tail)
}
fn log_quantile<LP: Into<LogProbability64>>(&self, p: LP, lower_tail: bool) -> Real64 {
log_qhyper(p, self.group_1, self.group_2, self.number_drawn, lower_tail)
}
fn random_sample<R: RNG>(&self, rng: &mut R) -> Real64 {
rhyper(self.group_1, self.group_2, self.number_drawn, rng)
}
}
pub struct HyperGeometricBuilder {
group_1: Option<PositiveInteger64>,
group_2: Option<PositiveInteger64>,
number_drawn: Option<PositiveInteger64>,
}
impl HyperGeometricBuilder {
pub fn new() -> Self {
Self {
group_1: None,
group_2: None,
number_drawn: None,
}
}
pub fn with_group_1<P: Into<PositiveInteger64>>(&mut self, group_1: P) -> &mut Self {
self.group_1 = Some(group_1.into());
self
}
pub fn with_group_2<P: Into<PositiveInteger64>>(&mut self, group_2: P) -> &mut Self {
self.group_2 = Some(group_2.into());
self
}
pub fn with_number_drawn<P: Into<PositiveInteger64>>(&mut self, number_drawn: P) -> &mut Self {
self.number_drawn = Some(number_drawn.into());
self
}
pub fn build(&self) -> Result<HyperGeometric, String> {
let group_1 = self.group_1.unwrap_or(1.0.into());
let group_2 = self.group_2.unwrap_or(1.0.into());
let number_drawn = self.number_drawn.unwrap_or(1.0.into());
if number_drawn.unwrap() > group_1.unwrap() + group_2.unwrap() {
Err(format!(
"Number drawn must be less than the two group sizes combined: {} > {}",
number_drawn.unwrap(),
group_1.unwrap() + group_2.unwrap()
))
} else {
Ok(HyperGeometric {
group_1,
group_2,
number_drawn,
})
}
}
}
#[cfg(test)]
mod tests;
#[cfg(all(test, feature = "enable_proptest"))]
mod proptests;
#[cfg(all(test, feature = "enable_covtest"))]
mod covtests;