1 /** 2 Authors: [Ilya Yaroshenko](http://9il.github.io) 3 4 Copyright: © 2014-2015 [Ilya Yaroshenko](http://9il.github.io) 5 6 License: MIT 7 */ 8 module atmosphere.statistic; 9 10 import core.stdc.tgmath; 11 12 import std.traits; 13 import std.typecons; 14 import std.math : LN2; 15 import std.algorithm : map; 16 //import std.numeric : sumOfLog2s; 17 import atmosphere.math: sumOfLog2s; 18 19 /++ 20 Minimal sufficient and complete statistic for the generalized inverse Gaussin disributoin. 21 +/ 22 struct GeneralizedInverseGaussinStatistic(T) 23 if(isFloatingPoint!T) 24 { 25 ///`Σ weights[j] * sample[j] / Σ weights[j]` 26 T mean; 27 ///`Σ weights[j] / sample[j] / Σ weights[j]` 28 T meani; 29 ///`Σ weights[j] * log(sample[j]) / Σ weights[j]` 30 T meanl; 31 32 /// 33 this(in T[] sample) 34 in { 35 assert(positiveSampleCheck(sample)); 36 } 37 body { 38 immutable n = sample.length; 39 mean = sample.wfsum() / n; 40 meani = sample.map!"1/a".wfsum() / n; 41 meanl = T(LN2) * sample.map!(x => cast(Unqual!T)x).sumOfLog2s() / n; 42 } 43 44 /// 45 this(in T[] sample, in T[] weights) 46 in { 47 assert(positiveSampleCheck(sample, weights)); 48 } 49 body { 50 immutable n = weights.wfsum; 51 mean = sample.wfsum(weights) / n; 52 meani = sample.map!"1/a".wfsum(weights) / n; 53 meanl = T(LN2) * sample.map!log2.wfsum(weights) / n; 54 } 55 56 /// 57 C opCast(C : GeneralizedInverseGaussinFixedLambdaStatistic!T)() pure const 58 { 59 GeneralizedInverseGaussinFixedLambdaStatistic!T stat = void; 60 stat.mean = mean; 61 stat.meani = meani; 62 return stat; 63 } 64 65 /// 66 C opCast(C : GammaStatistic!T)() pure const 67 { 68 GammaStatistic!T stat = void; 69 stat.mean = mean; 70 stat.meanl = meanl; 71 return stat; 72 } 73 74 /// 75 C opCast(C : InverseGammaStatistic!T)() pure const 76 { 77 InverseGammaStatistic!T stat = void; 78 stat.meani = meani; 79 stat.meanl = meanl; 80 return stat; 81 } 82 } 83 84 unittest { 85 alias st = GeneralizedInverseGaussinStatistic!double; 86 } 87 88 /++ 89 Minimal sufficient and complete statistic for the generalized inverse Gaussin disributoin with fixed lambda. 90 +/ 91 struct GeneralizedInverseGaussinFixedLambdaStatistic(T) 92 if(isFloatingPoint!T) 93 { 94 ///`Σ weights[j] * sample[j] / Σ weights[j]` 95 T mean; 96 ///`Σ weights[j] / sample[j] / Σ weights[j]` 97 T meani; 98 99 /// 100 this(in T[] sample) 101 in { 102 assert(positiveSampleCheck(sample)); 103 } 104 body { 105 immutable n = sample.length; 106 mean = sample.wfsum() / n; 107 meani = sample.map!"1/a".wfsum() / n; 108 } 109 110 /// 111 this(in T[] sample, in T[] weights) 112 in { 113 assert(positiveSampleCheck(sample, weights)); 114 } 115 body { 116 immutable n = weights.wfsum; 117 mean = sample.wfsum(weights) / n; 118 meani = sample.map!"1/a".wfsum(weights) / n; 119 } 120 } 121 122 unittest { 123 alias st = GeneralizedInverseGaussinFixedLambdaStatistic!double; 124 } 125 126 127 /++ 128 Minimal sufficient and complete statistic for the generalized gamma disributoin with fixed `power` parameter. 129 +/ 130 struct GeneralizedGammaFixedPowerStatistic(T) 131 if(isFloatingPoint!T) 132 { 133 ///`Σ weights[j] * sample[j] ^^ power / Σ weights[j]` 134 T meanp; 135 ///`Σ weights[j] * log(sample[j]) / Σ weights[j]` 136 T meanl; 137 138 /// 139 this(T power, in T[] sample) 140 in { 141 assert(positiveSampleCheck(sample)); 142 } 143 body { 144 immutable n = sample.length; 145 meanp = sample.map!(x => x.pow(power)).wfsum / n; 146 meanl = T(LN2) * sample.map!log2.wfsum / n; 147 } 148 149 /// 150 this(T power, in T[] sample, in T[] weights) 151 in { 152 assert(positiveSampleCheck(sample, weights)); 153 } 154 body { 155 immutable n = weights.wfsum; 156 meanp = sample.map!(x => x.pow(power)).wfsum(weights) / n; 157 meanl = T(LN2) * sample.map!log2.wfsum(weights) / n; 158 } 159 } 160 161 unittest { 162 alias st = GeneralizedGammaFixedPowerStatistic!double; 163 } 164 165 166 /++ 167 Minimal sufficient and complete statistic for the gamma disributoin. 168 +/ 169 struct GammaStatistic(T) 170 if(isFloatingPoint!T) 171 { 172 ///`Σ weights[j] * sample[j] / Σ weights[j]` 173 T mean; 174 ///`Σ weights[j] * log(sample[j]) / Σ weights[j]` 175 T meanl; 176 177 /// 178 this(in T[] sample) 179 in { 180 assert(positiveSampleCheck(sample)); 181 } 182 body { 183 immutable n = sample.length; 184 mean = sample.wfsum / n; 185 meanl = T(LN2) * sample.map!(x => cast(Unqual!T)x).sumOfLog2s / n; 186 } 187 188 /// 189 this(in T[] sample, in T[] weights) 190 in { 191 assert(positiveSampleCheck(sample, weights)); 192 } 193 body { 194 immutable n = weights.wfsum; 195 mean = sample.wfsum(weights) / n; 196 meanl = T(LN2) * sample.map!log2.wfsum(weights) / n; 197 } 198 } 199 200 unittest { 201 alias st = GammaStatistic!double; 202 } 203 204 205 /++ 206 Minimal sufficient and complete statistic for the inverse-gamma disributoin. 207 +/ 208 struct InverseGammaStatistic(T) 209 if(isFloatingPoint!T) 210 { 211 ///`Σ weights[j] / sample[j] / Σ weights[j]` 212 T meani; 213 ///`Σ weights[j] * log(sample[j]) / Σ weights[j]` 214 T meanl; 215 216 /// 217 this(in T[] sample) 218 in { 219 assert(positiveSampleCheck(sample)); 220 } 221 body { 222 immutable n = sample.length; 223 meani = sample.map!"1/a".wfsum / n; 224 meanl = T(LN2) * sample.map!(x => cast(Unqual!T)x).sumOfLog2s / n; 225 } 226 227 /// 228 this(in T[] sample, in T[] weights) 229 in { 230 assert(positiveSampleCheck(sample, weights)); 231 } 232 body { 233 immutable n = weights.wfsum; 234 meani = sample.map!"1/a".wfsum(weights) / n; 235 meanl = T(LN2) * sample.map!log2.wfsum(weights) / n; 236 } 237 } 238 239 package: 240 241 unittest { 242 alias st = InverseGammaStatistic!double; 243 } 244 245 246 bool positiveSampleCheck(T)(in T[] sample) 247 { 248 import std.algorithm : all; 249 return sample.all!"a > 0 && isNormal(a)"; 250 } 251 252 bool positiveSampleCheck(T)(in T[] sample, in T[] weights) 253 { 254 import std.algorithm : all, any; 255 return 256 weights.length == sample.length 257 && sample.all!"a > 0 && isNormal(a)" 258 && weights.all!"a >= 0 && isFinite(a)" 259 && weights.any!"a > 0"; 260 } 261 262 auto wfsum(Range)(Range sample) 263 { 264 import atmosphere.summation; 265 return sample.fsum!(Summation.KB2); 266 } 267 268 unittest { 269 assert(wfsum([1.0, 2]) == 3); 270 } 271 272 T wfsum(Range, T)(Range sample, in T[] weights) 273 { 274 import atmosphere.summation; 275 import std.range; 276 assert(sample.length == weights.length); 277 Summator!(T, Summation.KB2) s = 0; 278 foreach(i, w; weights) 279 { 280 s += sample.front * w; 281 sample.popFront; 282 } 283 return s.sum; 284 } 285 286 unittest { 287 assert(wfsum([1.0, 2], [3.0, 4]) == 11); 288 }