numeris/stats/
beta_dist.rs1use crate::FloatScalar;
2use crate::special::{lbeta, betainc};
3use super::{ContinuousDistribution, StatsError, quantile_newton};
4
5#[derive(Debug, Clone, Copy)]
18pub struct Beta<T> {
19 alpha: T,
20 beta: T,
21}
22
23impl<T: FloatScalar> Beta<T> {
24 pub fn new(alpha: T, beta: T) -> Result<Self, StatsError> {
27 if alpha <= T::zero() || beta <= T::zero() {
28 return Err(StatsError::InvalidParameter);
29 }
30 Ok(Self { alpha, beta })
31 }
32}
33
34impl<T: FloatScalar> Beta<T> {
35 pub fn sample(&self, rng: &mut super::Rng) -> T {
39 let x = rng.next_gamma(self.alpha);
40 let y = rng.next_gamma(self.beta);
41 x / (x + y)
42 }
43
44 pub fn sample_array<const K: usize>(&self, rng: &mut super::Rng) -> [T; K] {
46 let mut out = [T::zero(); K];
47 for v in out.iter_mut() {
48 *v = self.sample(rng);
49 }
50 out
51 }
52}
53
54impl<T: FloatScalar> ContinuousDistribution<T> for Beta<T> {
55 fn pdf(&self, x: T) -> T {
56 if x < T::zero() || x > T::one() {
57 return T::zero();
58 }
59 self.ln_pdf(x).exp()
60 }
61
62 fn ln_pdf(&self, x: T) -> T {
63 if x < T::zero() || x > T::one() {
64 return T::neg_infinity();
65 }
66 let one = T::one();
67 (self.alpha - one) * x.ln() + (self.beta - one) * (one - x).ln()
68 - lbeta(self.alpha, self.beta)
69 }
70
71 fn cdf(&self, x: T) -> T {
72 if x <= T::zero() {
73 return T::zero();
74 }
75 if x >= T::one() {
76 return T::one();
77 }
78 betainc(self.alpha, self.beta, x).unwrap_or(T::nan())
79 }
80
81 fn quantile(&self, p: T) -> T {
82 let x0 = self.mean();
83 let eps = T::epsilon();
84 quantile_newton(
85 |x| self.cdf(x),
86 |x| self.pdf(x),
87 p,
88 x0,
89 eps,
90 T::one() - eps,
91 )
92 }
93
94 fn mean(&self) -> T {
95 self.alpha / (self.alpha + self.beta)
96 }
97
98 fn variance(&self) -> T {
99 let ab = self.alpha + self.beta;
100 self.alpha * self.beta / (ab * ab * (ab + T::one()))
101 }
102}