1 // Written in the D programming language. 2 3 /** 4 * Implements algorithms for uniform pseudo-random number generation. 5 * Following the definition used in the C++11 Standard Template Library 6 * $(D $(LESS)_random$(GREATER)) header, a $(I uniform random number 7 * generator) is defined to be an Input Range whose values are unsigned 8 * integer values drawn from the closed interval $(D [min, max]), such 9 * that each value among the possible set of results has (ideally) equal 10 * probability of being next in the sequence. Pseudo-random number 11 * generators are typically implemented as Forward Ranges, but this is 12 * not a requirement. 13 * 14 * The uniform random number generators provided by this module are 15 * implemented as final classes to ensure reference type semantics. 16 * These semantics are assumed by all other functions in the package, 17 * so user-defined value-type RNGs may fail in unexpected ways. 18 * 19 * Non-deterministic random number generators, or $(I random devices), 20 * are provided in a separate module (currently experimental). 21 * 22 * Copyright: © 2008-2011 Andrei Alexandrescu, 23 * 2011 Masahiro Nakagawa, 24 * 2013-2014 Joseph Rushton Wakeling 25 * 26 * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 27 * 28 * Authors: $(WEB erdani.org, Andrei Alexandrescu), 29 * Masahiro Nakagawa (Xorshift random _generator), 30 * $(WEB braingam.es, Joseph Rushton Wakeling) 31 * 32 * Credits: The Mersenne Twister implementation is adapted from 33 * the C++ implementation in 34 * $(WEB boost.org/doc/libs/1_63_0/doc/html/boost_random.html, Boost.Random) 35 * by Jens Maurer and Steven Watanabe, similarly licensed 36 * under the Boost Software License 1.0. 37 * 38 * Source: $(HAPSRC hap/random/_generator.d) 39 */ 40 module hap.random.generator; 41 42 import hap.random.traits; 43 44 import std.range, std.traits, std.typetuple; 45 46 /// $(D TypeTuple) of all uniform RNGs defined in this module. 47 alias UniformRNGTypes = 48 TypeTuple!(MinstdRand0, MinstdRand, 49 Mt11213b, Mt19937, Mt19937_64, 50 Xorshift32, Xorshift64, Xorshift128, Xorshift160, Xorshift192); 51 52 /** 53 * The "default", "recommended" RNG type for the current platform, implemented 54 * as an alias to one of the generators defined elsewhere in this module. 55 * Its use is suggested if you want to generate good-quality random numbers 56 * without caring about the minutiae of the method being used. The default 57 * thread-local RNG instance $(D_PARAM rndGen) is of type $(D Random). 58 */ 59 alias Random = Mt19937; 60 61 /** 62 * Global random number generator used by various functions in this package 63 * whenever no other generator is specified. It is allocated per-thread and 64 * initialized with a different unpredictable seed for each thread. 65 */ 66 ref Random rndGen() @property 67 { 68 static Random result = null; 69 70 if (result is null) 71 { 72 import std.algorithm; 73 74 result = new Random; 75 76 static if (isSeedable!(Random, typeof(repeat(0).map!((a) => unpredictableSeed)))) 77 { 78 result.seed(repeat(0).map!((a) => unpredictableSeed)); 79 } 80 else 81 { 82 result.seed(unpredictableSeed); 83 } 84 } 85 86 return result; 87 } 88 89 unittest 90 { 91 assert(isUniformRNG!(typeof(rndGen))); 92 auto a = rndGen; 93 assert(a.front == rndGen.front); 94 } 95 96 // General unittests that all uniform RNGs should pass 97 unittest 98 { 99 foreach (UniformRNG; UniformRNGTypes) 100 { 101 assert(isUniformRNG!UniformRNG); 102 assert(isSeedable!UniformRNG); 103 104 /* Ensure that popFront() actually changes the RNG state. 105 * Note that this test makes the assumption that RNGs of 106 * the same type that are initialized without being 107 * explicitly seeded will have the same internal state. 108 */ 109 typeof(UniformRNG.front) a, b; 110 { 111 auto gen = new UniformRNG; 112 a = gen.front; 113 } 114 { 115 auto gen = new UniformRNG; 116 gen.popFront(); 117 b = gen.front; 118 } 119 assert(a != b); 120 121 // if a forward range, check .save works 122 static if (isForwardRange!UniformRNG) 123 { 124 auto gen1 = new UniformRNG(unpredictableSeed); 125 auto gen2 = gen1.save; 126 assert(gen1 == gen2); 127 assert(gen1 !is gen2); 128 assert(gen1.take(100).array() == gen2.take(100).array()); 129 auto gen3 = gen1; 130 gen1.popFrontN(9999); 131 assert(gen3 == gen1); 132 assert(gen3 is gen1); 133 assert(gen3.front == gen1.front); 134 assert(gen2 != gen1); 135 assert(gen2 !is gen1); 136 assert(gen2.front != gen1.front); 137 } 138 139 // check that allocation with 'scoped' works 140 import std.typecons : scoped; 141 { 142 auto gen = scoped!UniformRNG(unpredictableSeed); 143 } 144 { 145 auto gen = scoped!UniformRNG; 146 a = gen.front; 147 } 148 { 149 auto gen = scoped!UniformRNG; 150 assert(gen.front == a); 151 gen.popFront(); 152 b = gen.front; 153 } 154 assert(a != b); 155 } 156 157 // Ensure different RNGs don't evaluate as equal 158 foreach (i, UniformRNG1; UniformRNGTypes) 159 { 160 foreach (j, UniformRNG2; UniformRNGTypes) 161 { 162 auto gen1 = new UniformRNG1; 163 auto gen2 = new UniformRNG2; 164 165 if (i == j) 166 { 167 /* Should both seed with default config, 168 * and therefore be equal. 169 */ 170 assert(gen1 == gen2); 171 } 172 else 173 { 174 assert(gen1 != gen2); 175 } 176 } 177 } 178 } 179 180 /** 181 * Linear congruential generators are some of the oldest algorithms for 182 * generating pseudo-random numbers. They tend to be fast but not of 183 * particularly high statistical quality, so their use is recommended 184 * only in very constrained circumstances, e.g. where memory is very 185 * severely restricted. Even then, consider using an $(D_PARAM Xorshift) 186 * generator instead, as this should provide much higher statistical 187 * quality. 188 */ 189 @safe final class LinearCongruentialEngine(UIntType, 190 UIntType a, UIntType c, UIntType m) 191 if (isUnsigned!UIntType && isIntegral!UIntType) 192 { 193 private: 194 UIntType _x = m ? (a + c) % m : (a + c); 195 196 static ulong primeFactorsOnly(ulong n) @safe nothrow pure 197 { 198 ulong result = 1; 199 ulong iter = 2; 200 for(; n >= iter * iter; iter += 2 - (iter == 2)) 201 { 202 if (n % iter) continue; 203 result *= iter; 204 do 205 { 206 n /= iter; 207 } 208 while (n % iter == 0); 209 } 210 return result * n; 211 } 212 213 unittest 214 { 215 static assert(primeFactorsOnly(100) == 10); 216 static assert(primeFactorsOnly(11) == 11); 217 static assert(primeFactorsOnly(7 * 7 * 7 * 11 * 15 * 11) == 3 * 5 * 7 * 11); 218 static assert(primeFactorsOnly(129 * 2) == 129 * 2); 219 } 220 221 static bool properParameters(ulong m, ulong a, ulong c) @safe nothrow pure 222 { 223 if (m == 0) 224 { 225 static if (is(UIntType == uint)) 226 { 227 // assume m is uint.max + 1 228 m = 1uL << 32; 229 } 230 else 231 { 232 return false; 233 } 234 } 235 236 import std.numeric : gcd; 237 238 // Bounds checking 239 if (a == 0 || a >= m || c >= m) return false; 240 // c and m are relatively prime 241 if (c > 0 && gcd(c, m) != 1) return false; 242 // a - 1 is divisible by all prime factors of m 243 if ((a - 1) % primeFactorsOnly(m)) return false; 244 // if a - 1 is a multiple of 4, then m is a multiple of 4 too 245 if ((a - 1) % 4 == 0 && m % 4) return false; 246 247 // Passed all tests 248 return true; 249 } 250 251 static assert(c == 0 || properParameters(m, a, c), "Incorrect instantiation of " ~ typeof(this).stringof); 252 253 public: 254 enum bool isUniformRandom = true; 255 enum UIntType min = (c == 0 ? 1 : 0); 256 enum UIntType max = m - 1; 257 258 enum UIntType multiplier = a; 259 enum UIntType increment = c; 260 enum UIntType modulus = m; 261 262 static assert(m == 0 || a < m); 263 static assert(m == 0 || c < m); 264 static assert(m == 0 || (cast(ulong) a * (m - 1) + c) % m == (c < a ? c - a + m : c - a)); 265 266 /// Constructs a $(D LinearCongruentialEngine) using the default seed configuration. 267 this() @safe 268 { 269 // Default seed already set to m ? (a + c) % m : (a + c) 270 } 271 272 /// Constructs a $(D LinearCongruentialEngine) seeded with $(D_PARAM x0). 273 this(in UIntType x0) @safe 274 { 275 seed(x0); 276 } 277 278 void seed(in UIntType x0 = 1) @safe pure 279 { 280 static if (c == 0) 281 { 282 import std.exception; 283 enforce(x0, "Invalid (zero) seed for " ~ typeof(this).stringof); 284 } 285 _x = m ? (x0 % m) : x0; 286 popFront(); 287 } 288 289 // ----- Range primitives ------------------------------------------------- 290 291 /// Always $(D false) (random number generators are infinite ranges). 292 enum bool empty = false; 293 294 /// Returns the current pseudo-random value. 295 UIntType front() @property @safe const nothrow pure 296 { 297 return _x; 298 } 299 300 /// Advances the pseudo-random sequence. 301 void popFront() @safe nothrow pure 302 { 303 static if (m) 304 { 305 static if (is(UInttype == uint) && m == uint.max) 306 { 307 immutable ulong x = (cast(ulong) a * _x + c), 308 v = x >> 32, 309 w = x & uint.max; 310 immutable y = cast(uint)(v + w); 311 _x = (y < v || y = uint.max) ? (y + 1) : y; 312 } 313 else static if (is(UIntType == uint) && m == int.max) 314 { 315 immutable ulong x = (cast(ulong) a * _x + c), 316 v = x >> 31, 317 w = x & int.max; 318 immutable uint y = cast(uint)(v + w); 319 _x = (y >= int.max) ? (y - int.max) : y; 320 } 321 else 322 { 323 _x = cast(UIntType) ((cast(ulong) a * _x + c) % m); 324 } 325 } 326 else 327 { 328 _x = a * _x + c; 329 } 330 } 331 332 typeof(this) save() @property @safe 333 { 334 auto ret = new typeof(this); 335 ret._x = this._x; 336 return ret; 337 } 338 339 override bool opEquals(Object rhs) @safe const nothrow pure 340 { 341 auto that = cast(typeof(this)) rhs; 342 343 if (that is null) 344 { 345 return false; 346 } 347 else if (this._x != that._x) 348 { 349 return false; 350 } 351 else 352 { 353 return true; 354 } 355 } 356 } 357 358 /** 359 * $(D_PARAM LinearCongruentialEngine) generators with well-chosen parameters. 360 * $(D MinstdRand0) implements Park and Miller's $(HTTPS 361 * en.wikipedia.org/wiki/Lehmer_random_number_generator, "minimal standard" 362 * generator), which uses 16807 for the multiplier. $(D MinstdRand) implements 363 * a variant that has slightly better spectral behaviour by using the multiplier 364 * 48271. Both generators are rather simplistic. 365 * 366 * Example: 367 * -------- 368 * // Initialize generator seeded with constant default value 369 * auto rng0 = new MinstdRand0; 370 * auto n = rng0.front; // same for each run 371 * // Seed with an unpredictable value 372 * rng0.seed(unpredictableSeed); 373 * n = rng0.front; // different across runs 374 * 375 * // Initialize a different generator with an unpredictable seed 376 * auto rng = new MinstdRand(unpredictableSeed); 377 * -------- 378 */ 379 alias MinstdRand0 = LinearCongruentialEngine!(uint, 16807, 0, 2147483647); 380 alias MinstdRand = LinearCongruentialEngine!(uint, 48271, 0, 2147483647); /// ditto 381 382 unittest 383 { 384 foreach (LCGen; TypeTuple!(MinstdRand0, MinstdRand)) 385 { 386 assert(isUniformRNG!(LCGen, uint)); 387 assert(isSeedable!(LCGen, uint)); 388 assert(isForwardRange!LCGen); 389 } 390 391 // The correct numbers are taken from The Database of Integer Sequences 392 // http://www.research.att.com/~njas/sequences/eisBTfry00128.txt 393 auto checking0 = [ 394 16807UL,282475249,1622650073,984943658,1144108930,470211272, 395 101027544,1457850878,1458777923,2007237709,823564440,1115438165, 396 1784484492,74243042,114807987,1137522503,1441282327,16531729, 397 823378840,143542612 ]; 398 auto gen0 = new MinstdRand0; 399 400 foreach (e; checking0) 401 { 402 assert(gen0.front == e); 403 gen0.popFront(); 404 } 405 // Test the 10000th invocation 406 // Correct value taken from: 407 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf 408 gen0.seed(); 409 popFrontN(gen0, 9999); 410 assert(gen0.front == 1043618065); 411 412 // Test MinstdRand 413 auto checking = [48271UL,182605794,1291394886,1914720637,2078669041, 407355683]; 414 auto gen = new MinstdRand; 415 416 foreach (e; checking) 417 { 418 assert(gen.front == e); 419 gen.popFront(); 420 } 421 422 // Test the 10000th invocation 423 // Correct value taken from: 424 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf 425 gen.seed(); 426 popFrontN(gen, 9999); 427 assert(gen.front == 399268537); 428 429 // Check we don't get equality if 2 LC generators of different type are compared. 430 gen._x = 1; 431 gen0._x = 1; 432 assert(gen._x == gen0._x); 433 assert(gen !is gen0); 434 assert(gen != gen0); 435 } 436 437 /** 438 * The Mersenne Twister generator, developed by $(HTTP dx.doi.org/10.1145%2F272991.272995, 439 * Makoto Matsumoto and Takuji Nishimura (1997)), allows for fast generation of high-quality 440 * pseudorandom numbers, and is widely used as a default random number generator by many 441 * programming languages, including D. The current implementation is adapted from that of 442 * Boost.Random and supports both 32- and 64-bit datatypes. 443 */ 444 final class MersenneTwisterEngine(UIntType, 445 size_t w, size_t n, size_t m, size_t r, 446 UIntType a, size_t u, UIntType d, size_t s, 447 UIntType b, size_t t, 448 UIntType c, size_t l, UIntType f) 449 if (isUnsigned!UIntType) 450 { 451 private: 452 UIntType[n] mt; 453 UIntType _y; 454 size_t mti = size_t.max; // means mt is not initialized 455 456 public: 457 /// Mark this as a uniform RNG 458 enum bool isUniformRandom = true; 459 460 /// Parameters for the generator 461 enum size_t wordSize = w; 462 enum size_t stateSize = n; 463 enum size_t shiftSize = m; 464 enum size_t maskBits = r; 465 enum UIntType xorMask = a; 466 enum size_t temperingU = u; 467 enum UIntType temperingD = d; 468 enum size_t temperingS = s; 469 enum UIntType temperingB = b; 470 enum size_t temperingT = t; 471 enum UIntType temperingC = c; 472 enum size_t temperingL = l; 473 enum UIntType initializationMultiplier = f; 474 475 /// Smallest generated value (0) 476 enum UIntType min = 0; 477 478 /// Largest generated value 479 enum UIntType max = UIntType.max >> (UIntType.sizeof * 8u - w); 480 481 /// Default seed value 482 enum UIntType defaultSeed = 5489U; 483 484 /// Constructs a $(D MersenneTwisterEngine) using the default seed. 485 this() @safe 486 { 487 seed(this.defaultSeed); 488 } 489 490 /// Constructs a $(D MersenneTwisterEngine) seeded with $(D_PARAM value). 491 this(in UIntType value) @safe 492 { 493 seed(value); 494 } 495 496 void seed()(in UIntType value) @safe nothrow pure 497 { 498 enum UIntType mask = this.max; 499 mt[0] = value & mask; 500 for (mti = 1; mti < n; ++mti) 501 { 502 mt[mti] = (f * (mt[mti - 1] ^ (mt[mti - 1] >> (w - 2))) + mti) & mask; 503 } 504 popFront(); 505 } 506 507 void seed(Range)(Range range) 508 if (isInputRange!Range && is(Unqual!(ElementType!Range) : UIntType)) 509 { 510 size_t j; 511 for (j = 0; j < n && !range.empty; ++j, range.popFront()) 512 { 513 mt[j] = range.front; 514 } 515 516 mti = n; 517 if (range.empty && j < n) 518 { 519 import std.exception, std.string : format; 520 throw new Exception(format("%s.seed: Input range only provided %s elements, " ~ 521 "need at least %s.", typeof(this).stringof, j, n)); 522 } 523 524 popFront(); 525 } 526 527 // ----- Range primitives ------------------------------------------------- 528 529 /// Always $(D false) (random number generators are infinite ranges). 530 enum bool empty = false; 531 532 /// Returns the current pseudo-random value. 533 UIntType front() @property @safe const nothrow pure 534 in 535 { 536 assert(mti < size_t.max); 537 } 538 body 539 { 540 return _y; 541 } 542 543 /// Advances the pseudo-random sequence. 544 void popFront() @safe nothrow pure 545 in 546 { 547 assert(mti < size_t.max); 548 } 549 body 550 { 551 enum UIntType upperMask = (~(cast(UIntType) 0)) << r; 552 enum UIntType lowerMask = ~upperMask; 553 554 enum size_t unrollFactor = 6; 555 enum size_t unrollExtra1 = (n - m) % unrollFactor; 556 enum size_t unrollExtra2 = (m - 1) % unrollFactor; 557 558 UIntType y = void; 559 560 if (mti >= n) 561 { 562 foreach (j; 0 .. n - m - unrollExtra1) 563 { 564 y = (mt[j] & upperMask) | (mt[j + 1] & lowerMask); 565 mt[j] = mt[j + m] ^ (y >> 1) ^ ((mt[j + 1] & 1) * a); 566 } 567 568 foreach (j; n - m - unrollExtra1 .. n - m) 569 { 570 y = (mt[j] & upperMask) | (mt[j + 1] & lowerMask); 571 mt[j] = mt[j + m] ^ (y >> 1) ^ ((mt[j + 1] & 1) * a); 572 } 573 574 foreach (j; n - m .. n - 1 - unrollExtra2) 575 { 576 y = (mt[j] & upperMask) | (mt[j + 1] & lowerMask); 577 mt[j] = mt[j - (n - m)] ^ (y >> 1) ^ ((mt[j + 1] & 1) * a); 578 } 579 580 foreach (j; n - 1 - unrollExtra2 .. n - 1) 581 { 582 y = (mt[j] & upperMask) | (mt[j + 1] & lowerMask); 583 mt[j] = mt[j - (n - m)] ^ (y >> 1) ^ ((mt[j + 1] & 1) * a); 584 } 585 586 y = (mt[n - 1] & upperMask) | (mt[0] & lowerMask); 587 mt[n - 1] = mt[m - 1] ^ (y >> 1) ^ ((mt[0] & 1) * a); 588 589 mti = 0; 590 } 591 592 y = mt[mti]; 593 mti++; 594 y ^= ((y >> u) & d); 595 y ^= ((y << s) & b); 596 y ^= ((y << t) & c); 597 y ^= (y >> l); 598 599 _y = y; 600 } 601 602 typeof(this) save() @property @safe 603 { 604 auto ret = new typeof(this); 605 ret.mt[] = this.mt[]; 606 ret._y = this._y; 607 ret.mti = this.mti; 608 return ret; 609 } 610 611 override bool opEquals(Object rhs) @safe const nothrow pure 612 { 613 auto that = cast(typeof(this)) rhs; 614 615 if (that is null) 616 { 617 return false; 618 } 619 else if (this.mt != that.mt || this._y != that._y || this.mti != that.mti) 620 { 621 return false; 622 } 623 else 624 { 625 return true; 626 } 627 } 628 } 629 630 /** 631 * Mersenne Twister generators with well-chosen parameters. $(D_PARAM Mt11213b) 632 * offers a generator with a period of 2^11213 - 1 and a 32-bit datatype, while 633 * $(D_PARAM Mt19937) and $(D_PARAM Mt19937_64) offer generators with 32- and 64-bit 634 * datatypes respectively, both having a period of 2^19937 - 1. The three generators 635 * offer a good uniform distribution in up to 350, 623 and 311 dimensions respectively. 636 * $(D_PARAM Mt19937) is the most typical configuration, widely used in many different 637 * programming languages as a high-quality default random number generator. 638 * 639 * Example: 640 * -------- 641 * // Initialize a Mersenne Twister seeded with constant default value 642 * auto rng = new Mt19937; 643 * auto n = rng.front; // same for each run 644 * // Seed with a thread-safe unpredictable value 645 * rng.seed(unpredictableSeed); 646 * n = rng.front; // different across runs 647 * -------- 648 * 649 * For extensive information on the Mersenne Twister generator and the choices of 650 * parameters, see the $(HTTP http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html, 651 * Mersenne Twister homepage) hosted by the Department of Mathematics at Hiroshima 652 * University. 653 */ 654 alias Mt11213b = 655 MersenneTwisterEngine!(uint, 656 32, 351, 175, 19, 657 0xccab8ee7U, 11, 0xffffffffU, 7, 658 0x31b6ab00U, 15, 659 0xffe50000U, 17, 1812433253U); 660 661 /// ditto 662 alias Mt19937 = 663 MersenneTwisterEngine!(uint, 664 32, 624, 397, 31, 665 0x9908b0dfU, 11, 0xffffffffU, 7, 666 0x9d2c5680U, 15, 667 0xefc60000U, 18, 1812433253U); 668 669 /// ditto 670 alias Mt19937_64 = 671 MersenneTwisterEngine!(ulong, 672 64, 312, 156, 31, 673 0xb5026f5aa96619e9UL, 29, 0x5555555555555555UL, 17, 674 0x71d67fffeda60000UL, 37, 675 0xfff7eee000000000UL, 43, 6364136223846793005UL); 676 677 unittest 678 { 679 auto gen11213b = new Mt11213b; 680 gen11213b.popFrontN(9999); 681 assert(gen11213b.front == 3809585648U); 682 683 auto gen19937 = new Mt19937; 684 gen19937.popFrontN(9999); 685 assert(gen19937.front == 4123659995U); 686 687 auto gen19937_64 = new Mt19937_64; 688 gen19937_64.popFrontN(9999); 689 assert(gen19937_64.front == 9981545732273789042UL); 690 } 691 692 unittest 693 { 694 import std.algorithm, std.exception; 695 696 foreach (MtGen; TypeTuple!(Mt11213b, Mt19937)) 697 { 698 assert(isUniformRNG!(MtGen, uint)); 699 } 700 701 assert(isUniformRNG!(Mt19937_64, ulong)); 702 assert(isSeedable!(Mt19937_64, ulong)); 703 704 foreach (MtGen; TypeTuple!(Mt11213b, Mt19937, Mt19937_64)) 705 { 706 assert(isSeedable!(MtGen, uint)); 707 assert(isForwardRange!MtGen); 708 709 auto gen = new MtGen; 710 711 // range too small to seed the generator 712 assertThrown(gen.seed(repeat(0, gen.stateSize - 1).map!((a) => (a + 1)))); 713 714 // range the absolute minimum size necessary 715 gen.seed(repeat(0, gen.stateSize).map!((a) => (a + 1))); 716 717 // infinite range 718 gen.seed(repeat(0).map!((a) => (a + 1))); 719 } 720 } 721 722 /** 723 * The Xorshift family of generators, developed by $(HTTP www.jstatsoft.org/v08/i14/paper, 724 * George Marsaglia (2003)), offer high-quality random number generation with minimal 725 * storage requirements and computational cost. They are therefore highly suitable for 726 * use in low-memory environments or slower processors. The current implementation 727 * supports Xorshift random number generation with a 32-bit datatype only. 728 * 729 * The total number of $(D bits) used to store the internal state is reflected in the 730 * statistical quality of the resulting generator. The table below lists the number of 731 * bits used by each Xorshift generator (which must be a multiple of the datatype size) 732 * and the corresponding period of the generator. 733 * 734 * $(BOOKTABLE $(TEXTWITHCOMMAS Number of $(D bits) used (2nd parameter of $(D_PARAM XorshiftEngine)) 735 * and corresponding period of the resulting generator), 736 * $(TR $(TH bits) $(TH period)) 737 * $(TR $(TD 32) $(TD 2^32 - 1)) 738 * $(TR $(TD 64) $(TD 2^64 - 1)) 739 * $(TR $(TD 96) $(TD 2^96 - 1)) 740 * $(TR $(TD 128) $(TD 2^128 - 1)) 741 * $(TR $(TD 160) $(TD 2^160 - 1)) 742 * $(TR $(TD 192) $(TD 2^192 - 2^32)) 743 * ) 744 */ 745 @safe final class XorshiftEngine(UIntType, 746 UIntType bits, UIntType a, UIntType b, UIntType c) 747 if (isUnsigned!UIntType) 748 { 749 private: 750 enum size = bits / 32; 751 752 static if (bits == 32) 753 { 754 UIntType[size] _seeds = [2463534242]; 755 } 756 else static if (bits == 64) 757 { 758 UIntType[size] _seeds = [123456789, 362436069]; 759 } 760 else static if (bits == 96) 761 { 762 UIntType[size] _seeds = [123456789, 362436069, 521288629]; 763 } 764 else static if (bits == 128) 765 { 766 UIntType[size] _seeds = [123456789, 362436069, 521288629, 88675123]; 767 } 768 else static if (bits == 160) 769 { 770 UIntType[size] _seeds = [123456789, 362436069, 521288629, 88675123, 5783321]; 771 } 772 else static if (bits == 192) 773 { 774 UIntType[size] _seeds = [123456789, 362436069, 521288629, 88675123, 5783321, 6615241]; 775 UIntType _value; 776 } 777 else 778 { 779 static assert(false, format("Phobos Error: Xorshift has no instantiation rule for %s bits.", bits)); 780 } 781 782 static assert(bits == 32 || bits == 64 || bits == 96 || bits == 128 || bits == 160 || bits == 192, 783 format("Xorshift supports only 32, 64, 96, 128, 160 and 192 bit versions. %s is not supported.", bits)); 784 785 static void sanitizeSeeds(ref UIntType[size] seeds) @safe nothrow pure 786 { 787 for (uint i; i < seeds.length; i++) 788 { 789 if (seeds[i] == 0) 790 seeds[i] = i + 1; 791 } 792 } 793 794 unittest 795 { 796 static if (size == 4) // Other bits too 797 { 798 UIntType[size] seeds = [1, 0, 0, 4]; 799 800 sanitizeSeeds(seeds); 801 802 assert(seeds == [1, 2, 3, 4]); 803 } 804 } 805 806 public: 807 ///Mark this as a Rng 808 enum bool isUniformRandom = true; 809 /// Smallest generated value (0). 810 enum UIntType min = 0; 811 /// Largest generated value. 812 enum UIntType max = UIntType.max; 813 814 /// Constructs an $(D XorshiftEngine) using the default seed configuration. 815 this() @safe 816 { 817 // seed values are already set, nothing to do :-) 818 } 819 820 /// Constructs an $(D XorshiftEngine) generator seeded with $(D_PARAM x0). 821 this(in UIntType x0) @safe 822 { 823 seed(x0); 824 } 825 826 827 /// (Re)seeds the generator with $(D_PARAM x0). 828 void seed(UIntType x0) @safe nothrow pure 829 { 830 // Initialization routine from MersenneTwisterEngine. 831 foreach (i, e; _seeds) 832 { 833 _seeds[i] = x0 = cast(UIntType)(1812433253U * (x0 ^ (x0 >> 30)) + i + 1); 834 } 835 836 // All seeds must not be 0. 837 sanitizeSeeds(_seeds); 838 839 popFront(); 840 } 841 842 // ----- Range primitives ------------------------------------------------- 843 844 /// Always $(D false) (random number generators are infinite ranges). 845 enum bool empty = false; 846 847 /// Returns the current pseudo-random value. 848 UIntType front() @property @safe const nothrow pure 849 { 850 static if (bits == 192) 851 { 852 return _value; 853 } 854 else 855 { 856 return _seeds[size - 1]; 857 } 858 } 859 860 /// Advances the pseudo-random sequence. 861 void popFront() @safe nothrow pure 862 { 863 UIntType temp; 864 865 static if (bits == 32) 866 { 867 temp = _seeds[0] ^ (_seeds[0] << a); 868 temp = temp ^ (temp >> b); 869 _seeds[0] = temp ^ (temp << c); 870 } 871 else static if (bits == 64) 872 { 873 temp = _seeds[0] ^ (_seeds[0] << a); 874 _seeds[0] = _seeds[1]; 875 _seeds[1] = _seeds[1] ^ (_seeds[1] >> c) ^ temp ^ (temp >> b); 876 } 877 else static if (bits == 96) 878 { 879 temp = _seeds[0] ^ (_seeds[0] << a); 880 _seeds[0] = _seeds[1]; 881 _seeds[1] = _seeds[2]; 882 _seeds[2] = _seeds[2] ^ (_seeds[2] >> c) ^ temp ^ (temp >> b); 883 } 884 else static if (bits == 128) 885 { 886 temp = _seeds[0] ^ (_seeds[0] << a); 887 _seeds[0] = _seeds[1]; 888 _seeds[1] = _seeds[2]; 889 _seeds[2] = _seeds[3]; 890 _seeds[3] = _seeds[3] ^ (_seeds[3] >> c) ^ temp ^ (temp >> b); 891 } 892 else static if (bits == 160) 893 { 894 temp = _seeds[0] ^ (_seeds[0] << a); 895 _seeds[0] = _seeds[1]; 896 _seeds[1] = _seeds[2]; 897 _seeds[2] = _seeds[3]; 898 _seeds[3] = _seeds[4]; 899 _seeds[4] = _seeds[4] ^ (_seeds[4] >> c) ^ temp ^ (temp >> b); 900 } 901 else static if (bits == 192) 902 { 903 temp = _seeds[0] ^ (_seeds[0] >> a); 904 _seeds[0] = _seeds[1]; 905 _seeds[1] = _seeds[2]; 906 _seeds[2] = _seeds[3]; 907 _seeds[3] = _seeds[4]; 908 _seeds[4] = _seeds[4] ^ (_seeds[4] << c) ^ temp ^ (temp << b); 909 _value = _seeds[4] + (_seeds[5] += 362437); 910 } 911 else 912 { 913 static assert(false, format("Phobos Error: Xorshift has no popFront() update for %s bits.", bits)); 914 } 915 } 916 917 918 /** 919 * Captures a range state. 920 */ 921 typeof(this) save() @property @safe 922 { 923 auto ret = new typeof(this); 924 assert(ret._seeds.length == this._seeds.length); 925 ret._seeds[] = this._seeds[]; 926 static if (bits == 192) 927 { 928 ret._value = this._value; 929 } 930 return ret; 931 } 932 933 934 /** 935 * Compares against $(D_PARAM rhs) for equality. 936 */ 937 override bool opEquals(Object rhs) @safe const nothrow pure 938 { 939 auto that = cast(typeof(this)) rhs; 940 941 if (that is null) 942 { 943 return false; 944 } 945 else 946 { 947 static if (bits == 192) 948 { 949 if (this._value != that._value) 950 { 951 return false; 952 } 953 } 954 955 return this._seeds == that._seeds; 956 } 957 } 958 } 959 960 961 /** 962 * Define $(D XorshiftEngine) generators with well-chosen parameters as provided by 963 * $(HTTP www.jstatsoft.org/v08/i14/paper, Marsaglia (2003)). The default provided 964 * by $(D_PARAM Xorshift) corresponds to the 128-bit generator as an optimal balance 965 * of statistical quality and speed. 966 * 967 * Example: 968 * ----- 969 * // Initialize an Xorshift generator seeded with constant default value 970 * auto rng = new Xorshift; 971 * auto n = rng.front; // same for each run 972 * 973 * // Seed with an unpredictable value 974 * rng.seed(unpredictableSeed); 975 * n = rng.front; // different across runs 976 * ----- 977 */ 978 alias Xorshift32 = XorshiftEngine!(uint, 32, 13, 17, 15); 979 alias Xorshift64 = XorshiftEngine!(uint, 64, 10, 13, 10); /// ditto 980 alias Xorshift96 = XorshiftEngine!(uint, 96, 10, 5, 26); /// ditto 981 alias Xorshift128 = XorshiftEngine!(uint, 128, 11, 8, 19); /// ditto 982 alias Xorshift160 = XorshiftEngine!(uint, 160, 2, 1, 4); /// ditto 983 alias Xorshift192 = XorshiftEngine!(uint, 192, 2, 1, 4); /// ditto 984 alias Xorshift = Xorshift128; /// ditto 985 986 unittest 987 { 988 // Result from reference implementation. 989 auto checking = [ 990 [2463534242UL, 901999875, 3371835698, 2675058524, 1053936272, 3811264849, 472493137, 3856898176, 2131710969, 2312157505], 991 [362436069UL, 2113136921, 19051112, 3010520417, 951284840, 1213972223, 3173832558, 2611145638, 2515869689, 2245824891], 992 [521288629UL, 1950277231, 185954712, 1582725458, 3580567609, 2303633688, 2394948066, 4108622809, 1116800180, 3357585673], 993 [88675123UL, 3701687786, 458299110, 2500872618, 3633119408, 516391518, 2377269574, 2599949379, 717229868, 137866584], 994 [5783321UL, 393427209, 1947109840, 565829276, 1006220149, 971147905, 1436324242, 2800460115, 1484058076, 3823330032], 995 [0UL, 246875399, 3690007200, 1264581005, 3906711041, 1866187943, 2481925219, 2464530826, 1604040631, 3653403911] 996 ]; 997 998 alias XorshiftTypes = TypeTuple!(Xorshift32, Xorshift64, Xorshift96, Xorshift128, Xorshift160, Xorshift192); 999 1000 foreach (i, XorGen; XorshiftTypes) 1001 { 1002 assert(isUniformRNG!(XorGen, uint)); 1003 assert(isSeedable!(XorGen, uint)); 1004 assert(isForwardRange!XorGen); 1005 1006 auto gen = new XorGen; 1007 1008 foreach (e; checking[i]) 1009 { 1010 assert(gen.front == e); 1011 gen.popFront(); 1012 } 1013 } 1014 } 1015 1016 /** 1017 * A "good" seed for initializing random number generators. Initializing 1018 * with $(D_PARAM unpredictableSeed) ensures that RNGs produce different 1019 * pseudo-random sequences each time they are run. 1020 * 1021 * Example: 1022 * -------- 1023 * auto rng = Random(unpredictableSeed); 1024 * auto n = rng.front; 1025 * -------- 1026 */ 1027 uint unpredictableSeed() @property 1028 { 1029 import core.thread; 1030 1031 static MinstdRand0 rand = null; 1032 1033 if (rand is null) 1034 { 1035 rand = new MinstdRand0; 1036 uint threadID = cast(uint) cast(void*) Thread.getThis(); 1037 rand.seed((getpid() + threadID) ^ cast(uint) TickDuration.currSystemTick.length); 1038 } 1039 rand.popFront(); 1040 return cast(uint) TickDuration.currSystemTick.length ^ rand.front; 1041 } 1042 1043 unittest 1044 { 1045 auto a = unpredictableSeed; 1046 assert(is(typeof(a) == uint)); 1047 }