1 /++ 2 This module contains algorithms for the $(LINK2 https://en.wikipedia.org/wiki/Weibull_distribution, Weibull Distribution). 3 4 License: $(HTTP www.apache.org/licenses/LICENSE-2.0, Apache-2.0) 5 6 Authors: John Michael Hall 7 8 Copyright: 2023 Mir Stat Authors. 9 10 +/ 11 12 module mir.stat.distribution.weibull; 13 14 import mir.internal.utility: isFloatingPoint; 15 16 /++ 17 Computes the Weibull probability density function (PDF). 18 19 Params: 20 x = value to evaluate PDF 21 shape = shape parameter 22 scale = scale parameter 23 24 See_also: 25 $(LINK2 https://en.wikipedia.org/wiki/Weibull_distribution, Weibull Distribution) 26 +/ 27 @safe pure nothrow @nogc 28 T weibullPDF(T)(const T x, const T shape, const T scale = 1) 29 if (isFloatingPoint!T) 30 in (x >= 0, "x must be greater than or equal to zero") 31 in (shape > 0, "shape must be greater than zero") 32 in (scale > 0, "scale must be greater than zero") 33 { 34 import mir.math.common: exp, pow; 35 36 const T x_scale = x / scale; 37 return (shape / scale) * pow(x_scale, shape - 1) * exp(-pow(x_scale, shape)); 38 } 39 40 /// 41 version(mir_stat_test) 42 @safe pure nothrow @nogc 43 unittest 44 { 45 import mir.test: shouldApprox; 46 47 0.0.weibullPDF(3.0).shouldApprox == 0; 48 0.5.weibullPDF(3.0).shouldApprox == 0.6618727; 49 1.0.weibullPDF(3.0).shouldApprox == 1.103638; 50 1.5.weibullPDF(3.0).shouldApprox == 0.2309723; 51 52 // Can also provide scale parameter 53 0.5.weibullPDF(2.0, 3.0).shouldApprox == 0.1080672; 54 1.0.weibullPDF(2.0, 3.0).shouldApprox == 0.1988532; 55 1.5.weibullPDF(2.0, 3.0).shouldApprox == 0.2596003; 56 } 57 58 // 59 version(mir_stat_test) 60 @safe pure nothrow @nogc 61 unittest 62 { 63 import mir.test: shouldApprox; 64 65 0.0.weibullPDF(1.0, 3.0).shouldApprox == 0.3333333; 66 } 67 68 /++ 69 Computes the Weibull cumulative distribution function (CDF). 70 71 Params: 72 x = value to evaluate CDF 73 shape = shape parameter 74 scale = scale parameter 75 76 See_also: 77 $(LINK2 https://en.wikipedia.org/wiki/Weibull_distribution, Weibull Distribution) 78 +/ 79 @safe pure nothrow @nogc 80 T weibullCDF(T)(const T x, const T shape, const T scale = 1) 81 if (isFloatingPoint!T) 82 in (x >= 0, "x must be greater than or equal to zero") 83 in (shape > 0, "shape must be greater than zero") 84 in (scale > 0, "scale must be greater than zero") 85 { 86 import mir.math.common: exp, pow; 87 88 return 1 - exp(-pow(x / scale, shape)); 89 } 90 91 /// 92 version(mir_stat_test) 93 @safe pure nothrow @nogc 94 unittest 95 { 96 import mir.test: shouldApprox; 97 98 0.0.weibullCDF(3.0).shouldApprox == 0; 99 0.5.weibullCDF(3.0).shouldApprox == 0.1175031; 100 1.0.weibullCDF(3.0).shouldApprox == 0.6321206; 101 1.5.weibullCDF(3.0).shouldApprox == 0.9657819; 102 103 // Can also provide scale parameter 104 0.5.weibullCDF(2.0, 3.0).shouldApprox == 0.02739552; 105 1.0.weibullCDF(2.0, 3.0).shouldApprox == 0.1051607; 106 1.5.weibullCDF(2.0, 3.0).shouldApprox == 0.2211992; 107 } 108 109 /++ 110 Computes the Weibull complementary cumulative distribution function (CCDF). 111 112 Params: 113 x = value to evaluate CCDF 114 shape = shape parameter 115 scale = scale parameter 116 117 See_also: 118 $(LINK2 https://en.wikipedia.org/wiki/Weibull_distribution, Weibull Distribution) 119 +/ 120 @safe pure nothrow @nogc 121 T weibullCCDF(T)(const T x, const T shape, const T scale = 1) 122 if (isFloatingPoint!T) 123 in (x >= 0, "x must be greater than or equal to zero") 124 in (shape > 0, "shape must be greater than zero") 125 in (scale > 0, "scale must be greater than zero") 126 { 127 import mir.math.common: exp, pow; 128 129 return exp(-pow(x / scale, shape)); 130 } 131 132 /// 133 version(mir_stat_test) 134 @safe pure nothrow @nogc 135 unittest 136 { 137 import mir.test: shouldApprox; 138 139 0.0.weibullCCDF(3.0).shouldApprox == 1; 140 0.5.weibullCCDF(3.0).shouldApprox == 0.8824969; 141 1.0.weibullCCDF(3.0).shouldApprox == 0.3678794; 142 1.5.weibullCCDF(3.0).shouldApprox == 0.03421812; 143 144 // Can also provide scale parameter 145 0.5.weibullCCDF(2.0, 3.0).shouldApprox == 0.9726045; 146 1.0.weibullCCDF(2.0, 3.0).shouldApprox == 0.8948393; 147 1.5.weibullCCDF(2.0, 3.0).shouldApprox == 0.7788008; 148 } 149 150 /++ 151 Computes the Weibull inverse cumulative distribution function (InvCDF). 152 153 Params: 154 p = value to evaluate InvCDF 155 shape = shape parameter 156 scale = scale parameter 157 158 See_also: 159 $(LINK2 https://en.wikipedia.org/wiki/Weibull_distribution, Weibull Distribution) 160 +/ 161 @safe pure nothrow @nogc 162 T weibullInvCDF(T)(const T p, const T shape, const T scale = 1) 163 if (isFloatingPoint!T) 164 in (p >= 0, "p must be greater than or equal to 0") 165 in (p <= 1, "p must be less than or equal to 1") 166 in (shape > 0, "shape must be greater than zero") 167 in (scale > 0, "scale must be greater than zero") 168 { 169 import mir.math.common: log, pow; 170 171 return scale * pow(-log(1 - p), T(1) / shape); 172 } 173 174 /// 175 version(mir_stat_test) 176 @safe pure nothrow @nogc 177 unittest { 178 import mir.test: shouldApprox; 179 180 weibullInvCDF(0.0, 3).shouldApprox == 0.0; 181 weibullInvCDF(0.25, 3).shouldApprox == 0.6601424; 182 weibullInvCDF(0.5, 3).shouldApprox == 0.884997; 183 weibullInvCDF(0.75, 3).shouldApprox == 1.115026; 184 weibullInvCDF(1.0, 3).shouldApprox == double.infinity; 185 186 // Can also provide scale parameter 187 weibullInvCDF(0.2, 2, 3).shouldApprox == 1.417142; 188 weibullInvCDF(0.4, 2, 3).shouldApprox == 2.144162; 189 weibullInvCDF(0.6, 2, 3).shouldApprox == 2.871692; 190 weibullInvCDF(0.8, 2, 3).shouldApprox == 3.805909; 191 } 192 193 194 /++ 195 Computes the Weibull log probability density function (LPDF). 196 197 Params: 198 x = value to evaluate LPDF 199 shape = shape parameter 200 scale = scale parameter 201 202 See_also: 203 $(LINK2 https://en.wikipedia.org/wiki/Weibull_distribution, Weibull Distribution) 204 +/ 205 @safe pure nothrow @nogc 206 T weibullLPDF(T)(const T x, const T shape, const T scale = 1) 207 if (isFloatingPoint!T) 208 in (x >= 0, "x must be greater than or equal to zero") 209 in (shape > 0, "shape must be greater than zero") 210 in (scale > 0, "scale must be greater than zero") 211 { 212 import mir.math.common: log, pow; 213 import mir.math.internal.xlogy: xlogy; 214 215 const T x_scale = x / scale; 216 return log(shape / scale) + xlogy(shape - 1, x_scale) - pow(x_scale, shape); 217 } 218 219 /// 220 version(mir_stat_test) 221 @safe pure nothrow @nogc 222 unittest 223 { 224 import mir.math.common: log; 225 import mir.test: shouldApprox; 226 227 0.0.weibullLPDF(3.0).shouldApprox == log(0.0); 228 0.5.weibullLPDF(3.0).shouldApprox == log(0.6618727); 229 1.0.weibullLPDF(3.0).shouldApprox == log(1.103638); 230 1.5.weibullLPDF(3.0).shouldApprox == log(0.2309723); 231 232 // Can also provide scale parameter 233 0.5.weibullLPDF(2.0, 3.0).shouldApprox == log(0.1080672); 234 1.0.weibullLPDF(2.0, 3.0).shouldApprox == log(0.1988532); 235 1.5.weibullLPDF(2.0, 3.0).shouldApprox == log(0.2596003); 236 }