1 module des.math.method.stat.moment; 2 3 import std.algorithm; 4 import std.traits; 5 import std.range; 6 import std..string : format; 7 8 import des.ts; 9 10 /// expected value 11 auto mean(R)( R r ) pure nothrow @property @nogc 12 if( isInputRange!R ) 13 in { assert( !r.empty ); } body 14 { 15 alias T = Unqual!(ElementType!R); 16 17 static assert( canSumWithSelfAndMulWithFloat!T, 18 "range elements must can sum with selfs and mul with float" ); 19 20 size_t cnt = 0; 21 T res = r.front * 0.0f; // neitral value for summate ( a + b*0 == a ) 22 foreach( v; r ) 23 { 24 res = res + v; 25 cnt++; 26 } 27 assert( cnt > 0, "no elements in range" ); 28 return res * ( 1.0f / cnt ); 29 } 30 31 template canSumWithSelfAndMulWithFloat(T) 32 { 33 enum canSumWithSelfAndMulWithFloat = is( typeof( T.init + T.init ) == T ) && 34 is( typeof( T.init * 0.0f ) == T ); 35 } 36 37 /// 38 unittest 39 { 40 auto a = [ 1.0f, 2, 3 ]; 41 assertEq( a.mean, 2.0f ); 42 43 static assert( !__traits(compiles,mean(a[0])) ); 44 static assert( !__traits(compiles,[1,2,3].mean) ); 45 static assert( __traits(compiles,[1.0f,2,3].mean) ); 46 47 import std.conv : to; 48 49 assertEq( iota(11).map!(a=>to!float(a)).mean, 5 ); 50 } 51 52 /// 53 unittest 54 { 55 import des.math.linear.vector; 56 57 auto a = [ vec3(1,2,3), vec3(2,3,4), vec3(3,4,5) ]; 58 assertEq( a.mean, vec3(2,3,4) ); 59 } 60 61 /// 62 auto variance(bool return_mean=false,R)( R r ) pure nothrow @property @nogc 63 if( isInputRange!R ) 64 { 65 alias T = Unqual!(ElementType!R); 66 67 static assert( canSumWithSelfAndMulWithFloat!T, 68 "range elements must can sum with selfs and mul with float" ); 69 70 T res = r.front * 0.0f; // neitral value for summate ( a + b*0 == a ) 71 size_t cnt = 0; 72 auto m = r.mean; 73 T buf; 74 foreach( val; r ) 75 { 76 static if( is( typeof( T.init - T.init ) == T ) ) 77 buf = m - val; 78 else 79 buf = m + val * (-1.0f); 80 81 res = res + buf * buf; 82 cnt++; 83 } 84 85 assert( cnt > 1, "only one elements in range, must be greater 1" ); 86 87 static if( return_mean ) 88 return cast(T[2])[ m, res * ( 1.0f / (cnt-1) ) ]; 89 else 90 return res * ( 1.0f / (cnt-1) ); 91 } 92 93 /// 94 unittest 95 { 96 auto a = [ 1.0f, 1, 1 ]; 97 assertEq( a.variance, 0.0f ); 98 99 auto b = [ 1.0f, 2, 3 ]; 100 assertEq( b.variance, 1.0f ); 101 } 102 103 /// 104 unittest 105 { 106 import des.math.linear.vector; 107 108 auto a = [ vec3(1,2,3), vec3(2,3,4), vec3(3,4,5) ]; 109 assertEq( a.variance, vec3(1,1,1) ); 110 } 111 112 /++ returns: 113 mean (0 element), variance (1 element) 114 +/ 115 auto mean_variance(R)( R r ) pure nothrow @property @nogc 116 if( isInputRange!R ) { return variance!true(r); } 117 118 /// 119 unittest 120 { 121 auto a = [ 1.0f, 1, 1 ]; 122 assertEq( a.mean_variance, [ 1.0f, 0.0f ] ); 123 124 auto b = [ 1.0f, 2, 3 ]; 125 assertEq( b.mean_variance, [ 2.0f, 1.0f ] ); 126 } 127 128 /// 129 unittest 130 { 131 import des.math.linear.vector; 132 133 auto a = [ vec3(1,2,3), vec3(2,3,4), vec3(3,4,5) ]; 134 assertEq( a.mean_variance, [ vec3(2,3,4), vec3(1,1,1) ] ); 135 } 136 137 /// 138 auto rawMoment(R)( R r, size_t k=1 ) pure nothrow @property @nogc 139 if( isInputRange!R ) 140 in { assert( !r.empty ); } body 141 { 142 alias T = Unqual!(ElementType!R); 143 144 static assert( canSumWithSelfAndMulWithFloat!T, 145 "range elements must can sum with selfs and mul with float" ); 146 147 T res = r.front * 0.0f; 148 size_t cnt = 0; 149 foreach( v; r ) 150 { 151 res = res + spow( v, k ); 152 cnt++; 153 } 154 return res * ( 1.0f / cnt ); 155 } 156 157 /// 158 unittest 159 { 160 auto a = [ 1.0f, 2 ]; 161 assertEq( a.rawMoment, 1.5 ); 162 assertEq( a.rawMoment(2), 2.5 ); 163 } 164 165 /// power ( works with vectors ) 166 T spow(T)( in T val, size_t k ) 167 if( is( typeof( T.init / T.init ) == T ) && is( typeof( T.init * T.init ) == T ) ) 168 { 169 if( k == 0 ) return val / val; 170 if( k == 1 ) return val; 171 if( k == 2 ) return val * val; 172 173 /+ small types (numbers,vectors) 174 + recursion is faster 175 + on BigInt logarifmic is faster 176 +/ 177 178 // recursion 179 T ret = spow( val*val, k/2 ); 180 if( k % 2 ) ret = ret * val; 181 return ret; 182 183 // logarifmic 184 //auto n = k; 185 //T buf = val / val; 186 //T ret = val; 187 //while( n > 1 ) 188 //{ 189 // if( n % 2 ) buf = buf * ret; 190 // ret = ret * ret; 191 // n /= 2; 192 //} 193 //return ret * buf; 194 } 195 196 /// 197 unittest 198 { 199 import des.math.linear.vector; 200 assertEq( spow( vec3( 1, 2, 3 ), 3 ), vec3( 1, 8, 27 ) ); 201 foreach( i; 0 .. 16 ) assertEq( spow( 10, i ), 10 ^^ i, 202 format( "spow fails (%%s != %%s) with i: %s", i ) ); 203 } 204 205 /// 206 auto centralMoment(R)( R r, size_t k=1 ) pure nothrow @property @nogc 207 if( isInputRange!R ) 208 { 209 alias T = Unqual!(ElementType!R); 210 211 static assert( canSumWithSelfAndMulWithFloat!T, 212 "range elements must can sum with selfs and mul with float" ); 213 214 T res = r.front * 0.0f; // neitral value for summate ( a + b*0 == a ) 215 size_t cnt = 0; 216 auto m = r.mean; 217 T buf; 218 foreach( val; r ) 219 { 220 static if( is( typeof( T.init - T.init ) == T ) ) 221 buf = val - m; 222 else 223 buf = val + m * (-1.0f); 224 225 res = res + spow( buf, k ); 226 cnt++; 227 } 228 229 return res * ( 1.0f / cnt ); 230 } 231 232 /// 233 unittest 234 { 235 auto a = [ 1.0f, 2, 3, 4 ]; 236 assertEq( a.centralMoment(1), 0 ); 237 assertEq( a.centralMoment(2), 1.25 ); 238 assertEq( a.centralMoment(3), 0 ); 239 } 240 241 /// 242 class MovingAverage(T) if( is(typeof(T[].init.mean)) ) 243 { 244 /// 245 T[] array; 246 247 size_t cur = 0; 248 size_t fill = 0; 249 250 /// 251 this( size_t mlen ) { array.length = mlen; } 252 253 invariant() 254 { 255 assert( array.length > 0 ); 256 assert( array.length >= fill ); 257 } 258 259 /// 260 void put( in T val ) 261 { 262 if( array.length > fill ) 263 { 264 array[fill] = val; 265 cur++; 266 fill++; 267 } 268 else array[cur++%$] = val; 269 } 270 271 /// 272 T avg() const @property 273 { return array[0..fill].mean; } 274 } 275 276 /// 277 unittest 278 { 279 auto ma = new MovingAverage!float( 3 ); 280 assertThrown!AssertError( ma.avg ); 281 ma.put( 1 ); 282 assertEq( ma.avg, 1 ); 283 ma.put( 1 ); 284 assertEq( ma.avg, 1 ); 285 ma.put( 4 ); 286 assertEq( ma.avg, 2 ); 287 ma.put( 4 ); 288 ma.put( 4 ); 289 assertEq( ma.avg, 4 ); 290 assertEq( ma.array.length, 3 ); 291 }