probability/distribution/
logistic.rs1use alloc::{vec, vec::Vec};
2#[allow(unused_imports)]
3use special::Primitive;
4
5use distribution;
6use source::Source;
7
8#[derive(Clone, Copy, Debug)]
10pub struct Logistic {
11 mu: f64,
12 s: f64,
13}
14
15impl Logistic {
16 #[inline]
20 pub fn new(mu: f64, s: f64) -> Self {
21 should!(s > 0.0);
22 Logistic { mu, s }
23 }
24
25 #[inline(always)]
27 pub fn mu(&self) -> f64 {
28 self.mu
29 }
30
31 #[inline(always)]
33 pub fn s(&self) -> f64 {
34 self.s
35 }
36}
37
38impl Default for Logistic {
39 #[inline]
40 fn default() -> Self {
41 Logistic::new(0.0, 1.0)
42 }
43}
44
45impl distribution::Continuous for Logistic {
46 #[inline]
47 fn density(&self, x: f64) -> f64 {
48 let exp = (-(x - self.mu) / self.s).exp();
49 exp / (self.s * (1.0 + exp).powi(2))
50 }
51}
52
53impl distribution::Distribution for Logistic {
54 type Value = f64;
55
56 #[inline]
57 fn distribution(&self, x: f64) -> f64 {
58 1.0 / (1.0 + (-(x - self.mu) / self.s).exp())
59 }
60}
61
62impl distribution::Entropy for Logistic {
63 #[inline]
64 fn entropy(&self) -> f64 {
65 self.s.ln() + 2.0
66 }
67}
68
69impl distribution::Inverse for Logistic {
70 #[inline]
71 fn inverse(&self, p: f64) -> f64 {
72 should!((0.0..=1.0).contains(&p));
73 self.mu - self.s * (1.0 / p - 1.0).ln()
74 }
75}
76
77impl distribution::Kurtosis for Logistic {
78 #[inline]
79 fn kurtosis(&self) -> f64 {
80 1.2
81 }
82}
83
84impl distribution::Mean for Logistic {
85 #[inline]
86 fn mean(&self) -> f64 {
87 self.mu
88 }
89}
90
91impl distribution::Median for Logistic {
92 #[inline]
93 fn median(&self) -> f64 {
94 self.mu
95 }
96}
97
98impl distribution::Modes for Logistic {
99 #[inline]
100 fn modes(&self) -> Vec<f64> {
101 vec![self.mu]
102 }
103}
104
105impl distribution::Sample for Logistic {
106 #[inline]
107 fn sample<S>(&self, source: &mut S) -> f64
108 where
109 S: Source,
110 {
111 use distribution::Inverse;
112 self.inverse(source.read::<f64>())
113 }
114}
115
116impl distribution::Skewness for Logistic {
117 #[inline]
118 fn skewness(&self) -> f64 {
119 0.0
120 }
121}
122
123impl distribution::Variance for Logistic {
124 #[inline]
125 fn variance(&self) -> f64 {
126 use core::f64::consts::PI;
127 (PI * self.s).powi(2) / 3.0
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use alloc::{vec, vec::Vec};
134 use assert;
135 use core::f64::{INFINITY, NEG_INFINITY};
136 use prelude::*;
137
138 macro_rules! new(
139 ($mu:expr, $s:expr) => (Logistic::new($mu, $s));
140 );
141
142 #[test]
143 fn density() {
144 let d = new!(5.0, 5.0);
145 let x = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
146 let p = vec![
147 3.9322386648296369e-02,
148 4.2781939304058887e-02,
149 4.5756848091331452e-02,
150 4.8052149148305828e-02,
151 4.9503314542371987e-02,
152 5.0000000000000003e-02,
153 4.9503314542371987e-02,
154 4.8052149148305828e-02,
155 4.5756848091331452e-02,
156 4.2781939304058887e-02,
157 3.9322386648296369e-02,
158 ];
159
160 assert::close(
161 &x.iter().map(|&x| d.density(x)).collect::<Vec<_>>(),
162 &p,
163 1e-15,
164 );
165 }
166
167 #[test]
168 fn distribution() {
169 let d = new!(5.0, 5.0);
170 let x = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
171 let p = vec![
172 2.6894142136999510e-01,
173 3.1002551887238755e-01,
174 3.5434369377420455e-01,
175 4.0131233988754800e-01,
176 4.5016600268752216e-01,
177 5.0000000000000000e-01,
178 5.4983399731247795e-01,
179 5.9868766011245200e-01,
180 6.4565630622579540e-01,
181 6.8997448112761250e-01,
182 7.3105857863000490e-01,
183 ];
184
185 assert::close(
186 &x.iter().map(|&x| d.distribution(x)).collect::<Vec<_>>(),
187 &p,
188 1e-7,
189 );
190 }
191
192 #[test]
193 fn entropy() {
194 assert_eq!(new!(0.0, (-2f64).exp()).entropy(), 0.0);
195 }
196
197 #[test]
198 fn inverse() {
199 let d = new!(5.0, 5.0);
200 let p = vec![0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0];
201 let x = vec![
202 NEG_INFINITY,
203 -5.9861228866810947e+00,
204 -1.9314718055994531e+00,
205 7.6351069806398275e-01,
206 2.9726744594591787e+00,
207 5.0000000000000000e+00,
208 7.0273255405408239e+00,
209 9.2364893019360199e+00,
210 1.1931471805599454e+01,
211 1.5986122886681098e+01,
212 INFINITY,
213 ];
214
215 assert::close(
216 &p.iter().map(|&p| d.inverse(p)).collect::<Vec<_>>(),
217 &x,
218 1e-14,
219 );
220 }
221
222 #[test]
223 fn kurtosis() {
224 assert_eq!(new!(2.0, 1.0).kurtosis(), 1.2);
225 }
226
227 #[test]
228 fn mean() {
229 assert_eq!(new!(2.0, 1.0).mean(), 2.0);
230 }
231
232 #[test]
233 fn median() {
234 assert_eq!(new!(2.0, 1.0).median(), 2.0);
235 }
236
237 #[test]
238 fn modes() {
239 assert_eq!(new!(2.0, 1.0).modes(), vec![2.0]);
240 }
241
242 #[test]
243 fn skewness() {
244 assert_eq!(new!(2.0, 1.0).skewness(), 0.0);
245 }
246
247 #[test]
248 fn variance() {
249 use core::f64::consts::PI;
250 assert_eq!(new!(1.0, 3.0 / PI).variance(), 3.0);
251 }
252
253 #[test]
254 fn deviation() {
255 use core::f64::consts::PI;
256 assert_eq!(new!(1.0, 3.0 / PI).deviation(), 3f64.sqrt());
257 }
258}