| 1 |
/* |
|---|
| 2 |
Redistribution and use in source and binary forms, with or without |
|---|
| 3 |
modification, are permitted provided that the following conditions |
|---|
| 4 |
are met: |
|---|
| 5 |
|
|---|
| 6 |
Redistributions of source code must retain the above copyright |
|---|
| 7 |
notice, this list of conditions and the following disclaimer. |
|---|
| 8 |
|
|---|
| 9 |
Redistributions in binary form must reproduce the above |
|---|
| 10 |
copyright notice, this list of conditions and the following |
|---|
| 11 |
disclaimer in the documentation and/or other materials provided |
|---|
| 12 |
with the distribution. |
|---|
| 13 |
|
|---|
| 14 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|---|
| 15 |
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|---|
| 16 |
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|---|
| 17 |
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|---|
| 18 |
REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|---|
| 19 |
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|---|
| 20 |
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
|---|
| 21 |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|---|
| 22 |
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
|---|
| 23 |
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|---|
| 24 |
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
|---|
| 25 |
OF THE POSSIBILITY OF SUCH DAMAGE. |
|---|
| 26 |
|
|---|
| 27 |
Copyright (C) 2006. Victor Nakoryakov. |
|---|
| 28 |
*/ |
|---|
| 29 |
module helix.random; |
|---|
| 30 |
|
|---|
| 31 |
private import helix.basic; |
|---|
| 32 |
|
|---|
| 33 |
struct Rand48Engine |
|---|
| 34 |
{ |
|---|
| 35 |
const static uint min = 0; |
|---|
| 36 |
const static uint max = uint.max; |
|---|
| 37 |
|
|---|
| 38 |
/** |
|---|
| 39 |
Generates next pseudo-random number. |
|---|
| 40 |
Returns: |
|---|
| 41 |
Pseudo-random number in range [this.min; this.max] |
|---|
| 42 |
*/ |
|---|
| 43 |
uint pop() |
|---|
| 44 |
{ |
|---|
| 45 |
x = (a * x + b) & mask; |
|---|
| 46 |
return x >> 16; |
|---|
| 47 |
} |
|---|
| 48 |
|
|---|
| 49 |
/** |
|---|
| 50 |
Reinitializes engine. Sets new _seed used for pseudo-random numbers generation. |
|---|
| 51 |
|
|---|
| 52 |
If two different linear congruential engine would be initialized with the same |
|---|
| 53 |
_seed they will generate equivalent pseudo-number sequences. |
|---|
| 54 |
Params: |
|---|
| 55 |
nx = New _seed used for pseudo-random numbers generation. |
|---|
| 56 |
*/ |
|---|
| 57 |
void seed(ulong nx) |
|---|
| 58 |
{ |
|---|
| 59 |
x = nx & mask; |
|---|
| 60 |
} |
|---|
| 61 |
|
|---|
| 62 |
private: |
|---|
| 63 |
static const ulong a = 25214903917; |
|---|
| 64 |
static const ulong b = 11; |
|---|
| 65 |
static const ulong m = 1ul << 48; |
|---|
| 66 |
static const ulong mask = m - 1; |
|---|
| 67 |
ulong x = 0; |
|---|
| 68 |
} |
|---|
| 69 |
|
|---|
| 70 |
unittest |
|---|
| 71 |
{ |
|---|
| 72 |
Rand48Engine e1; |
|---|
| 73 |
e1.seed = 12345; |
|---|
| 74 |
for (int i = 0; i < 100; ++i) |
|---|
| 75 |
e1.pop(); |
|---|
| 76 |
|
|---|
| 77 |
Rand48Engine e2 = e1; |
|---|
| 78 |
|
|---|
| 79 |
// must generate the same sequence |
|---|
| 80 |
for (int i = 0; i < 100; ++i) |
|---|
| 81 |
assert(e1.pop() == e2.pop()); |
|---|
| 82 |
|
|---|
| 83 |
e1.seed = 54321; |
|---|
| 84 |
e2.seed = 54321; |
|---|
| 85 |
|
|---|
| 86 |
// must generate the same sequence |
|---|
| 87 |
for (int i = 0; i < 100; ++i) |
|---|
| 88 |
assert(e1.pop() == e2.pop()); |
|---|
| 89 |
} |
|---|
| 90 |
|
|---|
| 91 |
/*********************************************************************/ |
|---|
| 92 |
struct MersenneTwisterEngine |
|---|
| 93 |
{ |
|---|
| 94 |
static const uint min = 0; |
|---|
| 95 |
static const uint max = uint.max; |
|---|
| 96 |
|
|---|
| 97 |
static const uint n = 624; |
|---|
| 98 |
static const uint m = 397; |
|---|
| 99 |
|
|---|
| 100 |
uint pop() |
|---|
| 101 |
{ |
|---|
| 102 |
if (next >= n) // overflow, engine reload needed |
|---|
| 103 |
{ |
|---|
| 104 |
uint twist(uint m, uint u, uint v) |
|---|
| 105 |
{ |
|---|
| 106 |
return m ^ (((u & 0x8000_0000u) | (v & 0x7fff_ffffu)) >> 1) ^ |
|---|
| 107 |
(-(u & 0x1u) & 0x9908_b0dfu); |
|---|
| 108 |
} |
|---|
| 109 |
|
|---|
| 110 |
uint* p = s.ptr; |
|---|
| 111 |
|
|---|
| 112 |
for (int i = n - m; i--; ++p) |
|---|
| 113 |
*p = twist( p[m], p[0], p[1] ); |
|---|
| 114 |
|
|---|
| 115 |
for (int i = m; --i; ++p) |
|---|
| 116 |
*p = twist( p[m - n], p[0], p[1] ); |
|---|
| 117 |
|
|---|
| 118 |
*p = twist( p[m - n], p[0], s[0] ); |
|---|
| 119 |
|
|---|
| 120 |
next = 0; |
|---|
| 121 |
} |
|---|
| 122 |
|
|---|
| 123 |
// use 'state.ptr[next]' instead of 'state[next]' to |
|---|
| 124 |
// suppress array bound checks, namely performance penalty |
|---|
| 125 |
uint x = s.ptr[next]; |
|---|
| 126 |
++next; |
|---|
| 127 |
|
|---|
| 128 |
x ^= (x >> 11); |
|---|
| 129 |
x ^= (x << 7) & 0x9d2c_5680u; |
|---|
| 130 |
x ^= (x << 15) & 0xefc6_0000u; |
|---|
| 131 |
return x ^ (x >> 18); |
|---|
| 132 |
} |
|---|
| 133 |
|
|---|
| 134 |
void seed(uint x) |
|---|
| 135 |
{ |
|---|
| 136 |
s[0] = x; |
|---|
| 137 |
for (int i = 1; i < n; ++i) |
|---|
| 138 |
s[i] = 1_812_433_253u * (s[i-1] ^ (s[i-1] >> 30)) + i; |
|---|
| 139 |
|
|---|
| 140 |
next = 1; |
|---|
| 141 |
} |
|---|
| 142 |
|
|---|
| 143 |
private: |
|---|
| 144 |
uint[n] s = void; |
|---|
| 145 |
uint next = 0; |
|---|
| 146 |
} |
|---|
| 147 |
|
|---|
| 148 |
unittest |
|---|
| 149 |
{ |
|---|
| 150 |
MersenneTwisterEngine e1; |
|---|
| 151 |
e1.seed = 12345; |
|---|
| 152 |
for (int i = 0; i < 100; ++i) |
|---|
| 153 |
e1.pop(); |
|---|
| 154 |
|
|---|
| 155 |
MersenneTwisterEngine e2 = e1; |
|---|
| 156 |
|
|---|
| 157 |
// must generate the same sequence |
|---|
| 158 |
for (int i = 0; i < 100; ++i) |
|---|
| 159 |
assert(e1.pop() == e2.pop()); |
|---|
| 160 |
|
|---|
| 161 |
e1.seed = 54321; |
|---|
| 162 |
e2.seed = 54321; |
|---|
| 163 |
|
|---|
| 164 |
// must generate the same sequence |
|---|
| 165 |
for (int i = 0; i < 100; ++i) |
|---|
| 166 |
assert(e1.pop() == e2.pop()); |
|---|
| 167 |
} |
|---|
| 168 |
|
|---|
| 169 |
/********************************************************************/ |
|---|
| 170 |
struct UnitUniformEngine(BaseEngine, bool closedLeft, bool closedRight) |
|---|
| 171 |
{ |
|---|
| 172 |
private BaseEngine baseEngine; |
|---|
| 173 |
|
|---|
| 174 |
const static |
|---|
| 175 |
{ |
|---|
| 176 |
real min = (closedLeft ? 0 : increment) * (1/denominator); |
|---|
| 177 |
real max = (range + (closedLeft ? 0 : increment)) * (1/denominator); |
|---|
| 178 |
} |
|---|
| 179 |
|
|---|
| 180 |
private const static |
|---|
| 181 |
{ |
|---|
| 182 |
real range = cast(real)(baseEngine.max - baseEngine.min); |
|---|
| 183 |
real increment = (baseEngine.max > uint.max) ? 2.l : 0.2l; |
|---|
| 184 |
real denominator = range + (closedLeft ? 0 : increment) + (closedRight ? 0 : increment); |
|---|
| 185 |
} |
|---|
| 186 |
|
|---|
| 187 |
real pop() |
|---|
| 188 |
{ |
|---|
| 189 |
auto x = baseEngine.pop(); |
|---|
| 190 |
|
|---|
| 191 |
static if ( |
|---|
| 192 |
is (typeof(baseEngine.pop) : real) && // base engine pops float-type values |
|---|
| 193 |
cast(real)baseEngine.min == this.min && |
|---|
| 194 |
cast(real)baseEngine.max == this.max) |
|---|
| 195 |
{ |
|---|
| 196 |
// no manipulations required, return value as is. |
|---|
| 197 |
return cast(real)x; |
|---|
| 198 |
} |
|---|
| 199 |
else |
|---|
| 200 |
{ |
|---|
| 201 |
return (cast(real)(x - baseEngine.min) + (closedLeft ? 0 : increment)) * (1/denominator); |
|---|
| 202 |
} |
|---|
| 203 |
} |
|---|
| 204 |
|
|---|
| 205 |
void seed(uint x) |
|---|
| 206 |
{ |
|---|
| 207 |
baseEngine.seed = x; |
|---|
| 208 |
} |
|---|
| 209 |
} |
|---|
| 210 |
|
|---|
| 211 |
unittest |
|---|
| 212 |
{ |
|---|
| 213 |
alias UnitUniformEngine!(Rand48Engine, true, true) fullClosed; |
|---|
| 214 |
alias UnitUniformEngine!(Rand48Engine, true, false) closedLeft; |
|---|
| 215 |
alias UnitUniformEngine!(Rand48Engine, false, true) closedRight; |
|---|
| 216 |
alias UnitUniformEngine!(Rand48Engine, false, false) fullOpened; |
|---|
| 217 |
|
|---|
| 218 |
static assert(fullClosed.min == 0.l); |
|---|
| 219 |
static assert(fullClosed.max == 1.l); |
|---|
| 220 |
|
|---|
| 221 |
static assert(closedLeft.min == 0.l); |
|---|
| 222 |
static assert(closedLeft.max < 1.l); |
|---|
| 223 |
|
|---|
| 224 |
static assert(closedRight.min > 0.l); |
|---|
| 225 |
static assert(closedRight.max == 1.l); |
|---|
| 226 |
|
|---|
| 227 |
static assert(fullOpened.min > 0.l); |
|---|
| 228 |
static assert(fullOpened.max < 1.l); |
|---|
| 229 |
} |
|---|
| 230 |
|
|---|
| 231 |
/********************************************************************/ |
|---|
| 232 |
struct HighresUnitUniformEngine(BaseEngine, bool closedLeft, bool closedRight) |
|---|
| 233 |
{ |
|---|
| 234 |
private BaseEngine baseEngine; |
|---|
| 235 |
|
|---|
| 236 |
static const |
|---|
| 237 |
{ |
|---|
| 238 |
real min = (closedLeft ? 0 : increment) * (1 / denominator); |
|---|
| 239 |
real max = (rawMax + (closedLeft ? 0 : increment)) * (1 / denominator); |
|---|
| 240 |
} |
|---|
| 241 |
|
|---|
| 242 |
private const static |
|---|
| 243 |
{ |
|---|
| 244 |
real rawMax = uint.max * 0x1p32 + uint.max; |
|---|
| 245 |
real increment = 2.l; |
|---|
| 246 |
real denominator = rawMax + (closedLeft ? 0 : increment) + (closedRight ? 0 : increment); |
|---|
| 247 |
} |
|---|
| 248 |
|
|---|
| 249 |
real pop() |
|---|
| 250 |
{ |
|---|
| 251 |
static if ( |
|---|
| 252 |
is (typeof(baseEngine.pop) : real) && // base engine pops float-type values |
|---|
| 253 |
cast(real)baseEngine.min == this.min && |
|---|
| 254 |
cast(real)baseEngine.max == this.max) |
|---|
| 255 |
{ |
|---|
| 256 |
// no manipulations required, return value as is. |
|---|
| 257 |
return cast(real)baseEngine.pop(); |
|---|
| 258 |
} |
|---|
| 259 |
else |
|---|
| 260 |
{ |
|---|
| 261 |
// this is necessary condition to generate truly uniform |
|---|
| 262 |
// result. However it is possible to use base engine with any range, |
|---|
| 263 |
// but this feature isn't implemented for now and can be introduced |
|---|
| 264 |
// in future. |
|---|
| 265 |
static assert( baseEngine.min == 0 && baseEngine.max == uint.max ); |
|---|
| 266 |
|
|---|
| 267 |
uint a = cast(uint)baseEngine.pop(); |
|---|
| 268 |
uint b = cast(uint)baseEngine.pop(); |
|---|
| 269 |
return (a * 0x1p32 + b + (closedLeft ? 0 : increment)) * (1 / denominator); |
|---|
| 270 |
} |
|---|
| 271 |
} |
|---|
| 272 |
|
|---|
| 273 |
void seed(uint x) |
|---|
| 274 |
{ |
|---|
| 275 |
baseEngine.seed = x; |
|---|
| 276 |
} |
|---|
| 277 |
} |
|---|
| 278 |
|
|---|
| 279 |
unittest |
|---|
| 280 |
{ |
|---|
| 281 |
alias HighresUnitUniformEngine!(Rand48Engine, true, true) fullClosed; |
|---|
| 282 |
alias HighresUnitUniformEngine!(Rand48Engine, true, false) closedLeft; |
|---|
| 283 |
alias HighresUnitUniformEngine!(Rand48Engine, false, true) closedRight; |
|---|
| 284 |
alias HighresUnitUniformEngine!(Rand48Engine, false, false) fullOpened; |
|---|
| 285 |
|
|---|
| 286 |
static assert(fullClosed.min == 0.l); |
|---|
| 287 |
static assert(fullClosed.max == 1.l); |
|---|
| 288 |
|
|---|
| 289 |
static assert(closedLeft.min == 0.l); |
|---|
| 290 |
static assert(closedLeft.max < 1.l); |
|---|
| 291 |
|
|---|
| 292 |
static assert(closedRight.min > 0.l); |
|---|
| 293 |
static assert(closedRight.max == 1.l); |
|---|
| 294 |
|
|---|
| 295 |
static assert(fullOpened.min > 0.l); |
|---|
| 296 |
static assert(fullOpened.max < 1.l); |
|---|
| 297 |
} |
|---|