1use num_traits::Float;
12use crate::{Distribution, OpenClosed01};
13use rand::Rng;
14use core::fmt;
15
16#[derive(Clone, Copy, Debug)]
27#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
28pub struct Weibull<F>
29where F: Float, OpenClosed01: Distribution<F>
30{
31 inv_shape: F,
32 scale: F,
33}
34
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub enum Error {
38 ScaleTooSmall,
40 ShapeTooSmall,
42}
43
44impl fmt::Display for Error {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 f.write_str(match self {
47 Error::ScaleTooSmall => "scale is not positive in Weibull distribution",
48 Error::ShapeTooSmall => "shape is not positive in Weibull distribution",
49 })
50 }
51}
52
53#[cfg(feature = "std")]
54#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
55impl std::error::Error for Error {}
56
57impl<F> Weibull<F>
58where F: Float, OpenClosed01: Distribution<F>
59{
60 pub fn new(scale: F, shape: F) -> Result<Weibull<F>, Error> {
62 if !(scale > F::zero()) {
63 return Err(Error::ScaleTooSmall);
64 }
65 if !(shape > F::zero()) {
66 return Err(Error::ShapeTooSmall);
67 }
68 Ok(Weibull {
69 inv_shape: F::from(1.).unwrap() / shape,
70 scale,
71 })
72 }
73}
74
75impl<F> Distribution<F> for Weibull<F>
76where F: Float, OpenClosed01: Distribution<F>
77{
78 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> F {
79 let x: F = rng.sample(OpenClosed01);
80 self.scale * (-x.ln()).powf(self.inv_shape)
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 #[should_panic]
90 fn invalid() {
91 Weibull::new(0., 0.).unwrap();
92 }
93
94 #[test]
95 fn sample() {
96 let scale = 1.0;
97 let shape = 2.0;
98 let d = Weibull::new(scale, shape).unwrap();
99 let mut rng = crate::test::rng(1);
100 for _ in 0..1000 {
101 let r = d.sample(&mut rng);
102 assert!(r >= 0.);
103 }
104 }
105
106 #[test]
107 fn value_stability() {
108 fn test_samples<F: Float + core::fmt::Debug, D: Distribution<F>>(
109 distr: D, zero: F, expected: &[F],
110 ) {
111 let mut rng = crate::test::rng(213);
112 let mut buf = [zero; 4];
113 for x in &mut buf {
114 *x = rng.sample(&distr);
115 }
116 assert_eq!(buf, expected);
117 }
118
119 test_samples(Weibull::new(1.0, 1.0).unwrap(), 0f32, &[
120 0.041495778,
121 0.7531094,
122 1.4189332,
123 0.38386202,
124 ]);
125 test_samples(Weibull::new(2.0, 0.5).unwrap(), 0f64, &[
126 1.1343478702739669,
127 0.29470010050655226,
128 0.7556151370284702,
129 7.877212340241561,
130 ]);
131 }
132}