The OpenD Programming Language

1 /++
2 This module contains algorithms for the $(LINK2 https://en.wikipedia.org/wiki/Beta_distribution, Beta Distribution).
3 
4 An alternate parameterization of this distribution is provided in $(MREF mir,stat,distribution,beta_proportion).
5 
6 License: $(HTTP www.apache.org/licenses/LICENSE-2.0, Apache-2.0)
7 
8 Authors: John Michael Hall
9 
10 Copyright: 2022-3 Mir Stat Authors.
11 
12 +/
13 
14 module mir.stat.distribution.beta;
15 
16 import mir.internal.utility: isFloatingPoint;
17 
18 /++
19 Computes the beta probability density function (PDF).
20 
21 Params:
22     x = value to evaluate PDF
23     alpha = shape parameter #1
24     beta = shape parameter #2
25 
26 See_also:
27     $(LINK2 https://en.wikipedia.org/wiki/Beta_distribution, Beta Distribution)
28 +/
29 @safe pure nothrow @nogc
30 T betaPDF(T)(const T x, const T alpha, const T beta)
31     if (isFloatingPoint!T)
32     in (x >= 0, "x must be greater than or equal to 0")
33     in (x <= 1, "x must be less than or equal to 1")
34     in (alpha > 0, "alpha must be greater than zero")
35     in (beta > 0, "beta must be greater than zero")
36 {
37     import mir.math.common: pow;
38     import std.mathspecial: betaFunc = beta;
39 
40     return pow(x, (alpha - 1)) * pow((1 - x), (beta - 1)) / betaFunc(alpha, beta);
41 }
42 
43 ///
44 version(mir_stat_test)
45 @safe pure nothrow @nogc
46 unittest {
47     import mir.math.common: approxEqual;
48 
49     assert(0.5.betaPDF(1, 1) == 1);
50     assert(0.75.betaPDF(1, 2).approxEqual(0.5));
51     assert(0.25.betaPDF(0.5, 4).approxEqual(0.9228516));
52 }
53 
54 /++
55 Computes the beta cumulatve distribution function (CDF).
56 
57 Params:
58     x = value to evaluate CDF
59     alpha = shape parameter #1
60     beta = shape parameter #2
61 
62 See_also:
63     $(LINK2 https://en.wikipedia.org/wiki/Beta_distribution, Beta Distribution)
64 +/
65 @safe pure nothrow @nogc
66 T betaCDF(T)(const T x, const T alpha, const T beta)
67     if (isFloatingPoint!T)
68     in (x >= 0, "x must be greater than or equal to 0")
69     in (x <= 1, "x must be less than or equal to 1")
70     in (alpha > 0, "alpha must be greater than zero")
71     in (beta > 0, "beta must be greater than zero")
72 {
73     import std.mathspecial: betaIncomplete;
74 
75     return betaIncomplete(alpha, beta, x);
76 }
77 
78 ///
79 version(mir_stat_test)
80 @safe pure nothrow @nogc
81 unittest {
82     import mir.math.common: approxEqual;
83 
84     assert(0.5.betaCDF(1, 1).approxEqual(0.5));
85     assert(0.75.betaCDF(1, 2).approxEqual(0.9375));
86     assert(0.25.betaCDF(0.5, 4).approxEqual(0.8588867));
87 }
88 
89 /++
90 Computes the beta complementary cumulative distribution function (CCDF).
91 
92 Params:
93     x = value to evaluate CCDF
94     alpha = shape parameter #1
95     beta = shape parameter #2
96 
97 See_also:
98     $(LINK2 https://en.wikipedia.org/wiki/Beta_distribution, Beta Distribution)
99 +/
100 @safe pure nothrow @nogc
101 T betaCCDF(T)(const T x, const T alpha, const T beta)
102     if (isFloatingPoint!T)
103     in (x >= 0, "x must be greater than or equal to 0")
104     in (x <= 1, "x must be less than or equal to 1")
105     in (alpha > 0, "alpha must be greater than zero")
106     in (beta > 0, "beta must be greater than zero")
107 {
108     import std.mathspecial: betaIncomplete;
109 
110     return betaIncomplete(beta, alpha, 1 - x);
111 }
112 
113 ///
114 version(mir_stat_test)
115 @safe pure nothrow @nogc
116 unittest {
117     import mir.math.common: approxEqual;
118 
119     assert(0.5.betaCCDF(1, 1).approxEqual(0.5));
120     assert(0.75.betaCCDF(1, 2).approxEqual(0.0625));
121     assert(0.25.betaCCDF(0.5, 4).approxEqual(0.1411133));
122 }
123 
124 /++
125 Computes the beta inverse cumulative distribution function (InvCDF).
126 
127 Params:
128     p = value to evaluate InvCDF
129     alpha = shape parameter #1
130     beta = shape parameter #2
131 
132 See_also:
133     $(LINK2 https://en.wikipedia.org/wiki/Beta_distribution, Beta Distribution)
134 +/
135 @safe pure nothrow @nogc
136 T betaInvCDF(T)(const T p, const T alpha, const T beta)
137     if (isFloatingPoint!T)
138     in (p >= 0, "p must be greater than or equal to 0")
139     in (p <= 1, "p must be less than or equal to 1")
140     in (alpha > 0, "alpha must be greater than zero")
141     in (beta > 0, "beta must be greater than zero")
142 {
143     import std.mathspecial: betaIncompleteInverse;
144 
145     return betaIncompleteInverse(alpha, beta, p);
146 }
147 
148 ///
149 version(mir_stat_test)
150 @safe pure nothrow @nogc
151 unittest {
152     import mir.math.common: approxEqual;
153 
154     assert(0.5.betaInvCDF(1, 1).approxEqual(0.5));
155     assert(0.9375.betaInvCDF(1, 2).approxEqual(0.75));
156     assert(0.8588867.betaInvCDF(0.5, 4).approxEqual(0.25));
157 }
158 
159 /++
160 Computes the beta log probability density function (LPDF).
161 
162 Params:
163     x = value to evaluate LPDF
164     alpha = shape parameter #1
165     beta = shape parameter #2
166 
167 See_also:
168     $(LINK2 https://en.wikipedia.org/wiki/Beta_distribution, Beta Distribution)
169 +/
170 @safe pure nothrow @nogc
171 T betaLPDF(T)(const T x, const T alpha, const T beta)
172     if (isFloatingPoint!T)
173     in (x >= 0, "x must be greater than or equal to 0")
174     in (x <= 1, "x must be less than or equal to 1")
175     in (alpha > 0, "alpha must be greater than zero")
176     in (beta > 0, "beta must be greater than zero")
177 {
178     import mir.math.internal.log_beta: logBeta;
179     import mir.math.internal.xlogy: xlogy, xlog1py;
180 
181     return xlogy(alpha - 1, x) + xlog1py(beta - 1, -x) - logBeta(alpha, beta);
182 }
183 
184 ///
185 version(mir_stat_test)
186 @safe pure nothrow @nogc
187 unittest {
188     import mir.math.common: approxEqual, log;
189 
190     assert(0.5.betaLPDF(1, 1).approxEqual(log(betaPDF(0.5, 1, 1))));
191     assert(0.75.betaLPDF(1, 2).approxEqual(log(betaPDF(0.75, 1, 2))));
192     assert(0.25.betaLPDF(0.5, 4).approxEqual(log(betaPDF(0.25, 0.5, 4))));
193 }