1 /*******************************************************************************
2 
3         copyright:      Copyright (C) 1997--2004, Makoto Matsumoto,
4                         Takuji Nishimura, and Eric Landry; All rights reserved
5         
6 
7         license:        BSD style: $(LICENSE)
8 
9         version:        Jan 2008: Initial release
10 
11         author:         KeYeR (D interface) keyer@team0xf.com
12                         fawzi (converted to engine)
13       
14 *******************************************************************************/
15 
16 module tango.math.random.engines.Twister;
17 private import Integer = tango.text.convert.Integer;
18 
19 /*******************************************************************************
20 
21         Wrapper for the Mersenne twister.
22         
23         The Mersenne twister is a pseudorandom number generator linked to
24         CR developed in 1997 by Makoto Matsumoto and Takuji Nishimura that
25         is based on a matrix linear recurrence over a finite binary field
26         F2. It provides for fast generation of very high quality pseudorandom
27         numbers, having been designed specifically to rectify many of the 
28         flaws found in older algorithms.
29         
30         Mersenne Twister has the following desirable properties:
31         ---
32         1. It was designed to have a period of 2^19937 - 1 (the creators
33            of the algorithm proved this property).
34            
35         2. It has a very high order of dimensional equidistribution.
36            This implies that there is negligible serial correlation between
37            successive values in the output sequence.
38            
39         3. It passes numerous tests for statistical randomness, including
40            the stringent Diehard tests.
41            
42         4. It is fast.
43         ---
44 
45 *******************************************************************************/
46 
47 struct Twister
48 {
49     private enum : uint {
50         // Period parameters
51         N          = 624,
52         M          = 397,
53         MATRIX_A   = 0x9908b0df,        // constant vector a 
54         UPPER_MASK = 0x80000000,        //  most significant w-r bits 
55         LOWER_MASK = 0x7fffffff,        // least significant r bits
56     }
57     enum int canCheckpoint=true;
58     enum int canSeed=true;
59 
60     private uint[N] mt;                     // the array for the state vector  
61     private uint mti=mt.length+1;           // mti==mt.length+1 means mt[] is not initialized 
62     
63     /// returns a random uint
64     uint next ()
65     {
66         uint y;
67         static uint mag01[2] =[0, MATRIX_A];
68 
69         if (mti >= mt.length) { 
70             int kk;
71 
72             for (kk=0;kk<mt.length-M;kk++)
73             {
74                 y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
75                 mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 1U];
76             }
77             for (;kk<mt.length-1;kk++) {
78                 y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
79                 mt[kk] = mt[kk+(M-mt.length)] ^ (y >> 1) ^ mag01[y & 1U];
80             }
81             y = (mt[mt.length-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
82             mt[mt.length-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 1U];
83 
84             mti = 0;
85         }
86 
87         y = mt[mti++];
88 
89         y ^= (y >> 11);
90         y ^= (y << 7)  &  0x9d2c5680UL;
91         y ^= (y << 15) &  0xefc60000UL;
92         y ^= (y >> 18);
93 
94         return y;
95     }
96     /// returns a random byte
97     ubyte nextB(){
98         return cast(ubyte)(next() & 0xFF);
99     }
100     /// returns a random long
101     ulong nextL(){
102         return ((cast(ulong)next())<<32)+cast(ulong)next();
103     }
104     
105     /// initializes the generator with a uint as seed
106     void seed (uint s)
107     {
108         mt[0]= s & 0xffff_ffffU;  // this is very suspicious, was the previous line incorrectly translated from C???
109         for (mti=1; mti<mt.length; mti++){
110             mt[mti] = cast(uint)(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
111             mt[mti] &= 0xffff_ffffUL; // this is very suspicious, was the previous line incorrectly translated from C???
112         }
113     }
114     /// adds entropy to the generator
115     void addEntropy(scope uint delegate() r){
116         int i, j, k;
117         i=1;
118         j=0;
119 
120         for (k = mt.length; k; k--)   {
121             mt[i] = cast(uint)((mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))+ r() + j); 
122             mt[i] &=  0xffff_ffffUL;  // this is very suspicious, was the previous line incorrectly translated from C???
123             i++;
124             j++;
125 
126             if (i >= mt.length){
127                     mt[0] = mt[mt.length-1];
128                     i=1;
129             }
130         }
131 
132         for (k=mt.length-1; k; k--)     {
133             mt[i] = cast(uint)((mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))- i); 
134             mt[i] &=  0xffffffffUL;  // this is very suspicious, was the previous line incorrectly translated from C???
135             i++;
136 
137             if (i>=mt.length){
138                     mt[0] = mt[mt.length-1];
139                     i=1;
140             }
141         }
142         mt[0] |=  0x80000000UL; 
143         mti=0;
144     }
145     /// seeds the generator
146     void seed(scope uint delegate() r){
147         seed (19650218UL);
148         addEntropy(r);
149     }
150     /// writes the current status in a string
151     immutable(char)[] toString(){
152         char[] res=new char[7+(N+1)*9];
153         int i=0;
154         res[i..i+7]="Twister"[];
155         i+=7;
156         res[i]='_';
157         ++i;
158         Integer.format(res[i..i+8],mti,cast(char[])"x8");
159         i+=8;
160         foreach (val;mt){
161             res[i]='_';
162             ++i;
163             Integer.format(res[i..i+8],val,cast(char[])"x8");
164             i+=8;
165         }
166         assert(i==res.length,"unexpected size");
167         return cast(immutable(char)[])res;
168     }
169     /// reads the current status from a string (that should have been trimmed)
170     /// returns the number of chars read
171     size_t fromString(const(char[]) s){
172         size_t i;
173         assert(s[0..7]=="Twister","unexpected kind, expected Twister");
174         i+=7;
175         assert(s[i]=='_',"no separator _ found");
176         ++i;
177         size_t ate;
178         mti=cast(uint)Integer.convert(s[i..i+8],16,&ate);
179         assert(ate==8,"unexpected read size");
180         i+=8;
181         foreach (ref val;mt){
182             assert(s[i]=='_',"no separator _ found");
183             ++i;
184             val=cast(uint)Integer.convert(s[i..i+8],16,&ate);
185             assert(ate==8,"unexpected read size");
186             i+=8;
187         }
188         return i;
189     }
190     
191 }
192