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 }