1 module lbfgsd.distribution; 2 3 import std.math : PI; 4 import lbfgsd.math; 5 6 struct NormalDistribution(T) 7 { 8 public: 9 this(T mu, T sigma) 10 { 11 this.mu = mu; 12 this.sigma = sigma; 13 } 14 15 public: 16 auto pdf(U)(U x) 17 { 18 return exp(-square(x - mu) / square(sigma)) / sqrt(2 * PI * square(sigma)); 19 } 20 21 auto cdf(U)(U x) 22 { 23 import std.mathspecial: normalDistribution; 24 return normalDistribution(x); 25 } 26 27 auto cdfInverse(U)(U p) 28 { 29 import std.mathspecial: normalDistributionInverse; 30 return normalDistributionInverse(x); 31 } 32 33 auto logLikehood(U)(U x) 34 { 35 return -square(x - mu) / square(sigma) - log(sigma) - (log(PI) + log(2)) / 2; 36 } 37 public: 38 T mu; //average 39 T sigma; //standard devision 40 } 41 42 struct JohnsonSUDistribution(T) 43 { 44 public: 45 this(T gamma, T delta, T lambda, T xi) 46 { 47 this.gamma = gamma; 48 this.delta = delta; 49 this.lambda = lambda; 50 this.xi = xi; 51 } 52 53 public: 54 auto pdf(U)(U x) 55 { 56 auto z = (x - xi) / lambda; 57 return delta * exp(-0.5 * square(gamma + delta * asinh(z))) / (sqrt(2 * PI) * (lambda * sqrt(square(z) + 1))); 58 } 59 60 auto cdf(U)(U x) 61 { 62 import std.mathspecial: normalDistribution; 63 return normalDistribution(gamma + delta * asinh((x - xi) / lambda)); 64 } 65 66 auto cdfInverse(U)(U p) 67 { 68 import std.mathspecial : normalDistributionInverse; 69 auto x = normalDistributionInverse(p); 70 return xi + lambda * sinh((x - gamma) / delta); 71 } 72 73 auto logLikehood(U)(U x) 74 { 75 auto xs = xi - x; 76 return -0.5 * (log((2 * PI * (square(lambda) + square(xs))) / square(delta)) + square(delta * asinh(xs / lambda) - gamma)); 77 } 78 79 public: 80 T gamma; 81 T delta; 82 T lambda; 83 T xi; 84 } 85 86 JohnsonSUDistribution!T johnsonSUDistribution(T)(T gamma, T delta, T lambda, T xi) 87 { 88 return typeof(return)(gamma, delta, lambda, xi); 89 } 90 91 unittest 92 { 93 auto dist = johnsonSUDistribution(1.0, 1.0, 1.0, 1.0); 94 auto x = dist.pdf(0.0); 95 auto p = dist.cdf(0.5); 96 auto c = dist.cdfInverse(p); 97 auto l = dist.logLikehood(0.0); 98 99 import std.math; 100 assert(approxEqual(log(x), l)); 101 assert(approxEqual(c, 0.5)); 102 } 103 unittest 104 { 105 import lbfgsd.autodiff; 106 alias Var = Variable!(double, 4); 107 108 auto gamma = Var(1, 0); 109 auto lambda = Var(1, 0); 110 auto delta = Var(1, 0); 111 auto xi = Var(1, 0); 112 auto x = Var(0); 113 114 auto dist = johnsonSUDistribution(gamma, lambda, delta, xi); 115 auto tx = log(dist.pdf(x)); 116 auto tl = dist.logLikehood(x); 117 118 import std.algorithm, std.math : approxEqual; 119 assert(approxEqual(tx.a, tl.a)); 120 assert(equal!approxEqual(tx.d[], tl.d[])); 121 122 auto x1 = log(dist.pdf(0.0)); 123 auto x2 = dist.logLikehood(0.0); 124 assert(approxEqual(x1.a, x2.a)); 125 assert(equal!approxEqual(x1.d[], x2.d[])); 126 } 127 128 struct GumbelDistribution(T) 129 { 130 public: 131 this(in T mu, in T eta) 132 { 133 this.mu = mu; 134 this.eta = eta; 135 } 136 137 public: 138 auto pdf(U)(U x) 139 { 140 auto y = exp((mu - x) / eta); 141 return exp(-y) * y / eta; 142 } 143 144 auto cdf(U)(U p) 145 { 146 return exp(-exp((mu - p) / eta)); 147 } 148 149 auto cdfInverse(U)(U x) 150 { 151 return mu - eta * log(-log(x)); 152 } 153 154 auto logLikehood(U)(U x) 155 { 156 auto z = (mu - x) / eta; 157 return z - exp(z) - log(eta); 158 } 159 160 public: 161 T mu; 162 T eta; 163 } 164 165 GumbelDistribution!T gumbelDistribution(T)(T mu, T eta) 166 { 167 return typeof(return)(mu, eta); 168 } 169 170 unittest 171 { 172 auto dist = gumbelDistribution(1.0, 1.0); 173 auto p = dist.pdf(0.0); 174 auto x = dist.cdf(0.5); 175 auto c = dist.cdfInverse(x); 176 auto l = dist.logLikehood(0.0); 177 178 import std.math; 179 assert(approxEqual(log(p), l)); 180 assert(approxEqual(c, 0.5)); 181 } 182 183 unittest 184 { 185 import lbfgsd.autodiff; 186 alias Var = Variable!(double, 4); 187 188 auto mu = Var(1, 0); 189 auto eta = Var(1, 0); 190 auto x = Var(0.1); 191 auto p = Var(0.25); 192 193 auto dist = gumbelDistribution(mu, eta); 194 auto tx = dist.pdf(x); 195 auto tl = dist.logLikehood(x); 196 197 auto lx = log(tx); 198 import std.algorithm, std.math : approxEqual; 199 assert(approxEqual(lx.a, tl.a)); 200 assert(equal!approxEqual(lx.d[], tl.d[])); 201 202 auto x1 = log(dist.pdf(0.30)); 203 auto x2 = dist.logLikehood(0.30); 204 assert(approxEqual(x1.a, x2.a)); 205 assert(equal!approxEqual(x1.d[], x2.d[])); 206 207 auto c = dist.cdf(p); 208 auto tp = dist.cdfInverse(c); 209 assert(approxEqual(p.a, tp.a)); 210 assert(equal!approxEqual(p.d[], tp.d[])); 211 }