1 /++ 2 This module contains algorithms for the $(LINK2 https://en.wikipedia.org/wiki/Bernoulli_distribution, Bernoulli 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.bernoulli; 13 14 import mir.internal.utility: isFloatingPoint; 15 16 /++ 17 Computes the bernoulli probability mass function (PMF). 18 19 Params: 20 x = value to evaluate PMF 21 p = `true` probability 22 23 See_also: 24 $(LINK2 https://en.wikipedia.org/wiki/Bernoulli_distribution, Bernoulli Distribution) 25 +/ 26 @safe pure nothrow @nogc 27 T bernoulliPMF(T)(const bool x, const T p) 28 if (isFloatingPoint!T) 29 in (p >= 0, "p must be greater than or equal to 0") 30 in (p <= 1, "p must be less than or equal to 1") 31 { 32 return p * x + (1 - p) * (1 - x); 33 } 34 35 /// 36 version(mir_stat_test) 37 @safe pure nothrow @nogc 38 unittest { 39 import mir.math.common: approxEqual; 40 41 assert(true.bernoulliPMF(0.5) == 0.5); 42 assert(false.bernoulliPMF(0.5) == 0.5); 43 44 assert(true.bernoulliPMF(0.7).approxEqual(0.7)); 45 assert(false.bernoulliPMF(0.7).approxEqual(0.3)); 46 } 47 48 /++ 49 Computes the bernoulli cumulatve distribution function (CDF). 50 51 Params: 52 x = value to evaluate CDF 53 p = `true` probability 54 55 See_also: 56 $(LINK2 https://en.wikipedia.org/wiki/Bernoulli_distribution, Bernoulli Distribution) 57 +/ 58 @safe pure nothrow @nogc 59 T bernoulliCDF(T)(const bool x, const T p) 60 if (isFloatingPoint!T) 61 in (p >= 0, "p must be greater than or equal to 0") 62 in (p <= 1, "p must be less than or equal to 1") 63 { 64 return x + (1 - x) * (1 - p); 65 } 66 67 /// 68 version(mir_stat_test) 69 @safe pure nothrow @nogc 70 unittest { 71 import mir.math.common: approxEqual; 72 73 assert(true.bernoulliCDF(0.5) == 1); 74 assert(false.bernoulliCDF(0.5) == 0.5); 75 76 assert(true.bernoulliCDF(0.7) == 1); 77 assert(false.bernoulliCDF(0.7).approxEqual(0.3)); 78 } 79 80 /++ 81 Computes the bernoulli complementary cumulative distribution function (CCDF). 82 83 Params: 84 x = value to evaluate CCDF 85 p = `true` probability 86 87 See_also: 88 $(LINK2 https://en.wikipedia.org/wiki/Bernoulli_distribution, Bernoulli Distribution) 89 +/ 90 @safe pure nothrow @nogc 91 T bernoulliCCDF(T)(const bool x, const T p) 92 if (isFloatingPoint!T) 93 in (p >= 0, "p must be greater than or equal to 0") 94 in (p <= 1, "p must be less than or equal to 1") 95 { 96 return (1 - x) * p; 97 } 98 99 /// 100 version(mir_stat_test) 101 @safe pure nothrow @nogc 102 unittest { 103 import mir.math.common: approxEqual; 104 105 assert(true.bernoulliCCDF(0.5) == 0); 106 assert(false.bernoulliCCDF(0.5) == 0.5); 107 108 assert(true.bernoulliCCDF(0.7) == 0); 109 assert(false.bernoulliCCDF(0.7).approxEqual(0.7)); 110 } 111 112 /++ 113 Computes the bernoulli inverse cumulative distribution function (InvCDF). 114 115 Params: 116 q = value to evaluate InvCDF 117 p = `true` probability 118 119 See_also: 120 $(LINK2 https://en.wikipedia.org/wiki/Bernoulli_distribution, Bernoulli Distribution) 121 +/ 122 @safe pure nothrow @nogc 123 bool bernoulliInvCDF(T)(const T q, const T p) 124 if (isFloatingPoint!T) 125 in (q >= 0, "q must be greater than or equal to 0") 126 in (q <= 1, "q must be less than or equal to 1") 127 in (p >= 0, "p must be greater than or equal to 0") 128 in (p <= 1, "p must be less than or equal to 1") 129 { 130 return q > p; // this ensures bernoulliInvCDF(a, a) == false, which is consistent with bernoulliCDF(false, a) == a 131 } 132 133 /// 134 version(mir_stat_test) 135 @safe pure nothrow @nogc 136 unittest { 137 assert(0.25.bernoulliInvCDF(0.5) == false); 138 assert(0.5.bernoulliInvCDF(0.5) == false); 139 assert(0.75.bernoulliInvCDF(0.5) == true); 140 141 assert(0.3.bernoulliInvCDF(0.7) == false); 142 assert(0.7.bernoulliInvCDF(0.7) == false); 143 assert(0.9.bernoulliInvCDF(0.7) == true); 144 } 145 146 version(mir_stat_test) 147 @safe pure nothrow @nogc 148 unittest { 149 assert(0.0.bernoulliInvCDF(0.5) == false); 150 assert(1.0.bernoulliInvCDF(0.5) == true); 151 assert(0.0.bernoulliInvCDF(0.7) == false); 152 assert(1.0.bernoulliInvCDF(0.7) == true); 153 } 154 155 /++ 156 Computes the bernoulli log probability mass function (LPMF). 157 158 Params: 159 x = value to evaluate LPDF 160 p = `true` probability 161 162 See_also: 163 $(LINK2 https://en.wikipedia.org/wiki/Bernoulli_distribution, Bernoulli Distribution) 164 +/ 165 @safe pure nothrow @nogc 166 T bernoulliLPMF(T)(const bool x, const T p) 167 if (isFloatingPoint!T) 168 in (p >= 0, "p must be greater than or equal to 0") 169 in (p <= 1, "p must be less than or equal to 1") 170 { 171 import mir.math.internal.xlogy: xlogy, xlog1py; 172 173 return xlogy(x, p) + xlog1py(1 - x, -p); 174 } 175 176 /// 177 version(mir_stat_test) 178 @safe pure nothrow @nogc 179 unittest { 180 import mir.math.common: approxEqual, log; 181 182 assert(true.bernoulliLPMF(0.5).approxEqual(log(bernoulliPMF(true, 0.5)))); 183 assert(false.bernoulliLPMF(0.5).approxEqual(log(bernoulliPMF(false, 0.5)))); 184 185 assert(true.bernoulliLPMF(0.7).approxEqual(log(bernoulliPMF(true, 0.7)))); 186 assert(false.bernoulliLPMF(0.7).approxEqual(log(bernoulliPMF(false, 0.7)))); 187 }