The OpenD Programming Language

1 /++
2 This module contains algorithms for the $(LINK2 https://en.wikipedia.org/wiki/Exponential_distribution, Exponential Distribution).
3 
4 License: $(HTTP www.apache.org/licenses/LICENSE-2.0, Apache-2.0)
5 
6 Authors: John Michael Hall
7 
8 Copyright: 2022-3 Mir Stat Authors.
9 
10 +/
11 
12 module mir.stat.distribution.exponential;
13 
14 import mir.internal.utility: isFloatingPoint;
15 
16 /++
17 Computes the exponential probability density function (PDF).
18 
19 Params:
20     x = value to evaluate PDF
21     lambda = number of events in an interval
22 
23 See_also:
24     $(LINK2 https://en.wikipedia.org/wiki/Exponential_distribution, Exponential Distribution)
25 +/
26 @safe pure nothrow @nogc
27 T exponentialPDF(T)(const T x, const T lambda)
28     if (isFloatingPoint!T)
29     in (x >= 0, "x must be greater than or equal to 0")
30     in (lambda > 0, "lambda must be greater than zero")
31 {
32     import mir.math.common: exp;
33 
34     return lambda * exp(-lambda * x);
35 }
36 
37 ///
38 version(mir_stat_test)
39 @safe pure nothrow @nogc
40 unittest {
41     import mir.math.common: approxEqual;
42 
43     assert(0.5.exponentialPDF(2.0).approxEqual(0.7357589));
44     assert(0.75.exponentialPDF(2.0).approxEqual(0.4462603));
45     assert(0.25.exponentialPDF(0.5).approxEqual(0.4412485));
46 }
47 
48 /++
49 Computes the exponential cumulative distribution function (CDF).
50 
51 Params:
52     x = value to evaluate CDF
53     lambda = number of events in an interval
54 
55 See_also:
56     $(LINK2 https://en.wikipedia.org/wiki/Exponential_distribution, Exponential Distribution)
57 +/
58 @safe pure nothrow @nogc
59 T exponentialCDF(T)(const T x, const T lambda)
60     if (isFloatingPoint!T)
61     in (x >= 0, "x must be greater than or equal to 0")
62     in (lambda > 0, "lambda must be greater than zero")
63 {
64     import mir.math.common: exp;
65 
66     return 1 - exp(-lambda * x);
67 }
68 
69 ///
70 version(mir_stat_test)
71 @safe pure nothrow @nogc
72 unittest {
73     import mir.math.common: approxEqual;
74 
75     assert(0.5.exponentialCDF(2.0).approxEqual(0.6321206));
76     assert(0.75.exponentialCDF(2.0).approxEqual(0.7768698));
77     assert(0.25.exponentialCDF(0.5).approxEqual(0.1175031));
78 }
79 
80 /++
81 Computes the exponential complementary cumulative distribution function (CCDF).
82 
83 Params:
84     x = value to evaluate CCDF
85     lambda = number of events in an interval
86 
87 See_also:
88     $(LINK2 https://en.wikipedia.org/wiki/Exponential_distribution, Exponential Distribution)
89 +/
90 @safe pure nothrow @nogc
91 T exponentialCCDF(T)(const T x, const T lambda)
92     if (isFloatingPoint!T)
93     in (x >= 0, "x must be greater than or equal to 0")
94     in (lambda > 0, "lambda must be greater than zero")
95 {
96     import mir.math.common: exp;
97 
98     return exp(-lambda * x);
99 }
100 
101 ///
102 version(mir_stat_test)
103 @safe pure nothrow @nogc
104 unittest {
105     import mir.math.common: approxEqual;
106 
107     assert(0.5.exponentialCCDF(2.0).approxEqual(1 - exponentialCDF(0.5, 2.0)));
108     assert(0.75.exponentialCCDF(2.0).approxEqual(1 - exponentialCDF(0.75, 2.0)));
109     assert(0.25.exponentialCCDF(0.5).approxEqual(1 - exponentialCDF(0.25, 0.5)));
110 }
111 
112 /++
113 Computes the exponential inverse cumulative distribution function (InvCDF).
114 
115 Params:
116     p = value to evaluate InvCDF
117     lambda = number of events in an interval
118 
119 See_also:
120     $(LINK2 https://en.wikipedia.org/wiki/Exponential_distribution, Exponential Distribution)
121 +/
122 
123 @safe pure nothrow @nogc
124 T exponentialInvCDF(T)(const T p, const T lambda)
125     if (isFloatingPoint!T)
126     in (p >= 0, "p must be greater than or equal to 0")
127     in (p < 1, "p must be less than or equal to 1")
128     in (lambda > 0, "lambda must be greater than zero")
129 {
130     import mir.math.internal.log1p: log1p;
131 
132     return -log1p(-p) / lambda;
133 }
134 
135 ///
136 version(mir_stat_test)
137 @safe pure nothrow @nogc
138 unittest {
139     import mir.math.common: approxEqual;
140 
141     assert(0.6321206.exponentialInvCDF(2.0).approxEqual(0.5));
142     assert(0.7768698.exponentialInvCDF(2.0).approxEqual(0.75));
143     assert(0.1175031.exponentialInvCDF(0.5).approxEqual(0.25));
144 }
145 
146 /++
147 Computes the exponential log probability density function (LPDF).
148 
149 Params:
150     x = value to evaluate LPDF
151     lambda = number of events in an interval
152 
153 See_also:
154     $(LINK2 https://en.wikipedia.org/wiki/Exponential_distribution, Exponential Distribution)
155 +/
156 @safe pure nothrow @nogc
157 T exponentialLPDF(T)(const T x, const T lambda)
158     if (isFloatingPoint!T)
159     in (x >= 0, "x must be greater than or equal to 0")
160     in (lambda > 0, "lambda must be greater than zero")
161 {
162     import mir.math.common: log;
163 
164     return log(lambda) - x * lambda;
165 }
166 
167 ///
168 version(mir_stat_test)
169 @safe pure nothrow @nogc
170 unittest {
171     import mir.math.common: approxEqual, log;
172 
173     assert(0.5.exponentialLPDF(2.0).approxEqual(log(exponentialPDF(0.5, 2.0))));
174     assert(0.75.exponentialLPDF(2.0).approxEqual(log(exponentialPDF(0.75, 2.0))));
175     assert(0.25.exponentialLPDF(0.5).approxEqual(log(exponentialPDF(0.25, 0.5))));
176 }