probability/distribution/
laplace.rs1use alloc::{vec, vec::Vec};
2#[allow(unused_imports)]
3use special::Primitive;
4
5use distribution;
6use distribution::Inverse;
7use source::Source;
8
9#[derive(Clone, Copy, Debug)]
11pub struct Laplace {
12 mu: f64,
13 b: f64,
14}
15
16impl Laplace {
17 #[inline]
21 pub fn new(mu: f64, b: f64) -> Self {
22 should!(b > 0.0);
23 Laplace { mu, b }
24 }
25
26 #[inline(always)]
28 pub fn mu(&self) -> f64 {
29 self.mu
30 }
31
32 #[inline(always)]
34 pub fn b(&self) -> f64 {
35 self.b
36 }
37}
38
39impl distribution::Continuous for Laplace {
40 #[inline]
41 fn density(&self, x: f64) -> f64 {
42 self.b.recip() * 0.5 * (-(x - self.mu).abs() / self.b).exp()
43 }
44}
45
46impl distribution::Distribution for Laplace {
47 type Value = f64;
48
49 #[inline]
50 fn distribution(&self, x: f64) -> f64 {
51 if x <= self.mu {
52 0.5 * ((x - self.mu) / self.b).exp()
53 } else {
54 1.0 - 0.5 * (-(x - self.mu) / self.b).exp()
55 }
56 }
57}
58
59impl distribution::Entropy for Laplace {
60 #[inline]
61 fn entropy(&self) -> f64 {
62 (core::f64::consts::E * 2.0 * self.b).ln()
63 }
64}
65
66impl distribution::Inverse for Laplace {
67 #[inline]
68 fn inverse(&self, p: f64) -> f64 {
69 should!((0.0..=1.0).contains(&p));
70 if p > 0.5 {
71 if p == 1.0 {
72 return core::f64::INFINITY;
73 }
74 self.mu - self.b * (2.0 - 2.0 * p).ln()
75 } else {
76 if p == 0.0 {
77 return core::f64::NEG_INFINITY;
78 }
79 self.mu + self.b * (2.0 * p).ln()
80 }
81 }
82}
83
84impl distribution::Kurtosis for Laplace {
85 #[inline]
86 fn kurtosis(&self) -> f64 {
87 3.0
88 }
89}
90
91impl distribution::Mean for Laplace {
92 #[inline]
93 fn mean(&self) -> f64 {
94 self.mu
95 }
96}
97
98impl distribution::Median for Laplace {
99 #[inline]
100 fn median(&self) -> f64 {
101 self.mu
102 }
103}
104
105impl distribution::Modes for Laplace {
106 #[inline]
107 fn modes(&self) -> Vec<f64> {
108 vec![self.mu]
109 }
110}
111
112impl distribution::Sample for Laplace {
113 #[inline]
114 fn sample<S>(&self, source: &mut S) -> f64
115 where
116 S: Source,
117 {
118 self.inverse(source.read::<f64>())
119 }
120}
121
122impl distribution::Skewness for Laplace {
123 #[inline]
124 fn skewness(&self) -> f64 {
125 0.0
126 }
127}
128
129impl distribution::Variance for Laplace {
130 #[inline]
131 fn variance(&self) -> f64 {
132 2.0 * self.b.powi(2)
133 }
134
135 #[inline]
136 fn deviation(&self) -> f64 {
137 f64::sqrt(2.0) * self.b
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use alloc::{vec, vec::Vec};
144 use assert;
145 use prelude::*;
146
147 macro_rules! new(
148 ($mu:expr, $b:expr) => (Laplace::new($mu, $b));
149 );
150
151 #[test]
152 fn density() {
153 let d = new!(2.0, 8.0);
154 let x = vec![-1.0, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 6.0, 12.0];
155 let p = vec![
156 0.042955579924435765,
157 0.048675048941962805,
158 0.05181431988627502,
159 0.055156056411537216,
160 0.05871331642584224,
161 0.0625,
162 0.05871331642584224,
163 0.055156056411537216,
164 0.048675048941962805,
165 0.03790816623203959,
166 0.01790654980376188,
167 ];
168
169 assert::close(
170 &x.iter().map(|&x| d.density(x)).collect::<Vec<_>>(),
171 &p,
172 1e-15,
173 );
174 }
175
176 #[test]
177 fn distribution() {
178 let d = new!(2.0, 8.0);
179 let x = vec![
180 -1.0, 0.0, 0.01, 0.05, 0.1, 0.15, 0.25, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0,
181 ];
182 let p = vec![
183 0.3436446393954861,
184 0.38940039153570244,
185 0.3898874463709755,
186 0.39184176532872866,
187 0.39429844549053833,
188 0.39677052798551266,
189 0.4017612868445304,
190 0.4145145590902002,
191 0.4412484512922977,
192 0.4697065314067379,
193 0.5,
194 0.5587515487077023,
195 0.6105996084642975,
196 ];
197
198 assert::close(
199 &x.iter().map(|&x| d.distribution(x)).collect::<Vec<_>>(),
200 &p,
201 1e-15,
202 );
203 }
204
205 #[test]
206 fn entropy() {
207 use core::f64::consts::E;
208 assert_eq!(new!(2.0, 1.0).entropy(), (2.0 * 1.0 * E).ln());
209 }
210
211 #[test]
212 fn inverse() {
213 let d = new!(2.0, 3.0);
214 let x = vec![
215 core::f64::NEG_INFINITY,
216 -2.8283137373023006,
217 -0.07944154167983575,
218 2.0,
219 4.079441541679836,
220 6.8283137373023015,
221 core::f64::INFINITY,
222 ];
223 let p = vec![0.0, 0.1, 0.25, 0.5, 0.75, 0.9, 1.00];
224
225 assert::close(
226 &p.iter().map(|&p| d.inverse(p)).collect::<Vec<_>>(),
227 &x,
228 1e-14,
229 );
230 }
231
232 #[test]
233 fn kurtosis() {
234 assert_eq!(new!(2.0, 9.0).kurtosis(), 3.0);
235 }
236
237 #[test]
238 fn mean() {
239 assert_eq!(new!(2.0, 1.0).mean(), 2.0);
240 }
241
242 #[test]
243 fn median() {
244 assert_eq!(new!(2.0, 1.0).median(), 2.0);
245 }
246
247 #[test]
248 fn modes() {
249 assert_eq!(new!(2.0, 1.0).modes(), vec![2.0]);
250 }
251
252 #[test]
253 fn skewness() {
254 assert_eq!(new!(2.0, 1.0).skewness(), 0.0);
255 }
256
257 #[test]
258 fn variance() {
259 assert_eq!(new!(2.0, 3.0).variance(), 18.0);
260 }
261
262 #[test]
263 fn deviation() {
264 assert::close(new!(2.0, 3.0).deviation(), 4.242640687119286, 1e-7);
265 }
266}