statrs/distribution/mod.rs
1//! Defines common interfaces for interacting with statistical distributions
2//! and provides
3//! concrete implementations for a variety of distributions.
4use super::statistics::{Max, Min};
5use ::num_traits::{Float, Num};
6use num_traits::NumAssignOps;
7
8pub use self::bernoulli::Bernoulli;
9pub use self::beta::{Beta, BetaError};
10pub use self::binomial::{Binomial, BinomialError};
11pub use self::categorical::{Categorical, CategoricalError};
12pub use self::cauchy::{Cauchy, CauchyError};
13pub use self::chi::{Chi, ChiError};
14pub use self::chi_squared::ChiSquared;
15pub use self::dirac::{Dirac, DiracError};
16#[cfg(feature = "nalgebra")]
17pub use self::dirichlet::{Dirichlet, DirichletError};
18pub use self::discrete_uniform::{DiscreteUniform, DiscreteUniformError};
19pub use self::empirical::Empirical;
20pub use self::erlang::Erlang;
21pub use self::exponential::{Exp, ExpError};
22pub use self::fisher_snedecor::{FisherSnedecor, FisherSnedecorError};
23pub use self::gamma::{Gamma, GammaError};
24pub use self::geometric::{Geometric, GeometricError};
25pub use self::gumbel::{Gumbel, GumbelError};
26pub use self::hypergeometric::{Hypergeometric, HypergeometricError};
27pub use self::inverse_gamma::{InverseGamma, InverseGammaError};
28pub use self::laplace::{Laplace, LaplaceError};
29pub use self::log_normal::{LogNormal, LogNormalError};
30#[cfg(feature = "nalgebra")]
31pub use self::multinomial::{Multinomial, MultinomialError};
32#[cfg(feature = "nalgebra")]
33pub use self::multivariate_normal::{MultivariateNormal, MultivariateNormalError};
34#[cfg(feature = "nalgebra")]
35pub use self::multivariate_students_t::{MultivariateStudent, MultivariateStudentError};
36pub use self::negative_binomial::{NegativeBinomial, NegativeBinomialError};
37pub use self::normal::{Normal, NormalError};
38pub use self::pareto::{Pareto, ParetoError};
39pub use self::poisson::{Poisson, PoissonError};
40pub use self::students_t::{StudentsT, StudentsTError};
41pub use self::triangular::{Triangular, TriangularError};
42pub use self::uniform::{Uniform, UniformError};
43pub use self::weibull::{Weibull, WeibullError};
44
45mod bernoulli;
46mod beta;
47mod binomial;
48mod categorical;
49mod cauchy;
50mod chi;
51mod chi_squared;
52mod dirac;
53#[cfg(feature = "nalgebra")]
54#[cfg_attr(docsrs, doc(cfg(feature = "nalgebra")))]
55mod dirichlet;
56mod discrete_uniform;
57mod empirical;
58mod erlang;
59mod exponential;
60mod fisher_snedecor;
61mod gamma;
62mod geometric;
63mod gumbel;
64mod hypergeometric;
65#[macro_use]
66mod internal;
67mod inverse_gamma;
68mod laplace;
69mod log_normal;
70#[cfg(feature = "nalgebra")]
71#[cfg_attr(docsrs, doc(cfg(feature = "nalgebra")))]
72mod multinomial;
73#[cfg(feature = "nalgebra")]
74#[cfg_attr(docsrs, doc(cfg(feature = "nalgebra")))]
75mod multivariate_normal;
76#[cfg(feature = "nalgebra")]
77#[cfg_attr(docsrs, doc(cfg(feature = "nalgebra")))]
78mod multivariate_students_t;
79mod negative_binomial;
80mod normal;
81mod pareto;
82mod poisson;
83mod students_t;
84mod triangular;
85mod uniform;
86mod weibull;
87#[cfg(feature = "rand")]
88#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
89mod ziggurat;
90#[cfg(feature = "rand")]
91#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
92mod ziggurat_tables;
93
94/// The `ContinuousCDF` trait is used to specify an interface for univariate
95/// distributions for which cdf float arguments are sensible.
96pub trait ContinuousCDF<K: Float, T: Float>: Min<K> + Max<K> {
97 /// Returns the cumulative distribution function calculated
98 /// at `x` for a given distribution. May panic depending
99 /// on the implementor.
100 ///
101 /// # Examples
102 ///
103 /// ```
104 /// use statrs::distribution::{ContinuousCDF, Uniform};
105 ///
106 /// let n = Uniform::new(0.0, 1.0).unwrap();
107 /// assert_eq!(0.5, n.cdf(0.5));
108 /// ```
109 fn cdf(&self, x: K) -> T;
110
111 /// Returns the survival function calculated
112 /// at `x` for a given distribution. May panic depending
113 /// on the implementor.
114 ///
115 /// # Examples
116 ///
117 /// ```
118 /// use statrs::distribution::{ContinuousCDF, Uniform};
119 ///
120 /// let n = Uniform::new(0.0, 1.0).unwrap();
121 /// assert_eq!(0.5, n.sf(0.5));
122 /// ```
123 fn sf(&self, x: K) -> T {
124 T::one() - self.cdf(x)
125 }
126
127 /// Due to issues with rounding and floating-point accuracy the default
128 /// implementation may be ill-behaved.
129 /// Specialized inverse cdfs should be used whenever possible.
130 /// Performs a binary search on the domain of `cdf` to obtain an approximation
131 /// of `F^-1(p) := inf { x | F(x) >= p }`. Needless to say, performance may
132 /// may be lacking.
133 #[doc(alias = "quantile function")]
134 #[doc(alias = "quantile")]
135 fn inverse_cdf(&self, p: T) -> K {
136 if p == T::zero() {
137 return self.min();
138 };
139 if p == T::one() {
140 return self.max();
141 };
142 let two = K::one() + K::one();
143 let mut high = two;
144 let mut low = -high;
145 while self.cdf(low) > p {
146 low = low + low;
147 }
148 while self.cdf(high) < p {
149 high = high + high;
150 }
151 let mut i = 16;
152 while i != 0 {
153 let mid = (high + low) / two;
154 if self.cdf(mid) >= p {
155 high = mid;
156 } else {
157 low = mid;
158 }
159 i -= 1;
160 }
161 (high + low) / two
162 }
163}
164
165/// The `DiscreteCDF` trait is used to specify an interface for univariate
166/// discrete distributions.
167pub trait DiscreteCDF<K: Sized + Num + Ord + Clone + NumAssignOps, T: Float>:
168 Min<K> + Max<K>
169{
170 /// Returns the cumulative distribution function calculated
171 /// at `x` for a given distribution. May panic depending
172 /// on the implementor.
173 ///
174 /// # Examples
175 ///
176 /// ```
177 /// use statrs::distribution::{DiscreteCDF, DiscreteUniform};
178 ///
179 /// let n = DiscreteUniform::new(1, 10).unwrap();
180 /// assert_eq!(0.6, n.cdf(6));
181 /// ```
182 fn cdf(&self, x: K) -> T;
183
184 /// Returns the survival function calculated at `x` for
185 /// a given distribution. May panic depending on the implementor.
186 ///
187 /// # Examples
188 ///
189 /// ```
190 /// use statrs::distribution::{DiscreteCDF, DiscreteUniform};
191 ///
192 /// let n = DiscreteUniform::new(1, 10).unwrap();
193 /// assert_eq!(0.4, n.sf(6));
194 /// ```
195 fn sf(&self, x: K) -> T {
196 T::one() - self.cdf(x)
197 }
198
199 /// Due to issues with rounding and floating-point accuracy the default implementation may be ill-behaved
200 /// Specialized inverse cdfs should be used whenever possible.
201 ///
202 /// # Panics
203 /// this default impl panics if provided `p` not on interval [0.0, 1.0]
204 fn inverse_cdf(&self, p: T) -> K {
205 if p == T::zero() {
206 return self.min();
207 } else if p == T::one() {
208 return self.max();
209 } else if !(T::zero()..=T::one()).contains(&p) {
210 panic!("p must be on [0, 1]")
211 }
212
213 let two = K::one() + K::one();
214 let mut ub = two.clone();
215 let lb = self.min();
216 while self.cdf(ub.clone()) < p {
217 ub *= two.clone();
218 }
219
220 internal::integral_bisection_search(|p| self.cdf(p.clone()), p, lb, ub).unwrap()
221 }
222}
223
224/// The `Continuous` trait provides an interface for interacting with
225/// continuous statistical distributions
226///
227/// # Remarks
228///
229/// All methods provided by the `Continuous` trait are unchecked, meaning
230/// they can panic if in an invalid state or encountering invalid input
231/// depending on the implementing distribution.
232pub trait Continuous<K, T> {
233 /// Returns the probability density function calculated at `x` for a given
234 /// distribution.
235 /// May panic depending on the implementor.
236 ///
237 /// # Examples
238 ///
239 /// ```
240 /// use statrs::distribution::{Continuous, Uniform};
241 ///
242 /// let n = Uniform::new(0.0, 1.0).unwrap();
243 /// assert_eq!(1.0, n.pdf(0.5));
244 /// ```
245 fn pdf(&self, x: K) -> T;
246
247 /// Returns the log of the probability density function calculated at `x`
248 /// for a given distribution.
249 /// May panic depending on the implementor.
250 ///
251 /// # Examples
252 ///
253 /// ```
254 /// use statrs::distribution::{Continuous, Uniform};
255 ///
256 /// let n = Uniform::new(0.0, 1.0).unwrap();
257 /// assert_eq!(0.0, n.ln_pdf(0.5));
258 /// ```
259 fn ln_pdf(&self, x: K) -> T;
260}
261
262/// The `Discrete` trait provides an interface for interacting with discrete
263/// statistical distributions
264///
265/// # Remarks
266///
267/// All methods provided by the `Discrete` trait are unchecked, meaning
268/// they can panic if in an invalid state or encountering invalid input
269/// depending on the implementing distribution.
270pub trait Discrete<K, T> {
271 /// Returns the probability mass function calculated at `x` for a given
272 /// distribution.
273 /// May panic depending on the implementor.
274 ///
275 /// # Examples
276 ///
277 /// ```
278 /// use statrs::distribution::{Discrete, Binomial};
279 /// use statrs::prec;
280 ///
281 /// let n = Binomial::new(0.5, 10).unwrap();
282 /// assert!(prec::almost_eq(n.pmf(5), 0.24609375, 1e-15));
283 /// ```
284 fn pmf(&self, x: K) -> T;
285
286 /// Returns the log of the probability mass function calculated at `x` for
287 /// a given distribution.
288 /// May panic depending on the implementor.
289 ///
290 /// # Examples
291 ///
292 /// ```
293 /// use statrs::distribution::{Discrete, Binomial};
294 /// use statrs::prec;
295 ///
296 /// let n = Binomial::new(0.5, 10).unwrap();
297 /// assert!(prec::almost_eq(n.ln_pmf(5), (0.24609375f64).ln(), 1e-15));
298 /// ```
299 fn ln_pmf(&self, x: K) -> T;
300}