1
2
3 """Mersenne Twister based random number generator
4
5 This module is intended to provide a reasonable fast random number
6 generator object that allows for (1) multiple generators running in
7 parallel and (2) saving/restoring of generator state to allow
8 easy regeneration of number sequences and (3) use a welll documented
9 algorithm (Mersenne Twister) that can easily be implemented or
10 exists in Matlab.
11
12 Starting with Matlab 7.1 the built in RAND() function uses the
13 same Mersenne Twister engine that python's (2.4 on) random.Random()
14 object uses. This means you can go back and forth pretty easily.
15 The only catach is that python's state vector is composed of signed
16 long's, while matlab's is unsigned. This means that to take the
17 python state vector into matlab you need to add 2^32 to all negative
18 values in the state vector before passing to the RAND function:
19
20 >> s = [state vector from puthon..]
21 >> s(s<0)=s(s<0)+(2^32); rand('twister', s);
22
23 Will put the generator at the same state the python generator was
24 at when the state was saved. RAND(100) in matlab will now generate
25 the same random sequence the python call:
26
27 >> PypeRandom(seed=statevector).rand(100)
28
29 would. At least to about +- 1.0e-11 as far as I can tell..
30
31 Author -- Matt Krause (matthew.krause@yale.edu)
32
33 """
34
36 - def __init__(self, seed=None, state=None):
37 """Uniform random number generator object.
38
39 Instantiate a uniform random number generator. This *should*
40 be the Mersenne Twister based generator that is standard in
41 Python (at least up to version 2.6).
42
43 Generates floating point numbers in the range [0-1].
44
45 If neither seed nor state are supplied, this will use the current
46 time to generate a seed.
47
48 *NB* To set the matlab random number generator to the same
49 known state as the python generator, you need to convert the
50 signed values of the seed into unsigned values as follows:
51
52 >> seed = [get me from file etc..];
53 >> seed(seed < 0 ) = seed(seed < 0) + (2^32);
54 >> rand('twister', seed);
55
56 :param seed: (int) single integer seed value
57
58 :param state: (int array) length 624 SIGNED 2-byte integer
59 vector that completely captures the state of the
60 random number generator. Note that these are SIGNED
61 values -- matlab expects UNSIGNED values; see notes
62 below. This comes from .getstate() method below
63
64 """
65 import random
66
67 self.mt = random.Random()
68 if state and len(state) == 625:
69 self.setstate(state)
70 elif seed:
71 self.mt.seed(seed)
72 else:
73 import time
74 t = time.time()
75 seed = int(1e6*(t-int(t)))
76 self.mt.seed(seed)
77
79 """Get signed/unsigned state vector for current generator state.
80
81 :return: (array) state vector
82
83 """
84 (rtype, seed, other) = self.mt.getstate()
85 return seed
86
88 """Restore generator to saved state.
89
90 :param state: (array) state vector from getstate()
91
92 :return: nothing
93
94 """
95 self.mt.setstate((2, state, None))
96
97 - def rand(self, count=None):
98 """Generate random numbers.
99
100 With no arguments generates a single floating point random
101 number on the range [0-1]. If count is specified, then returns
102 a list of count random numbers.
103
104 :param count: (None or int) if not None, number of numbers to generate
105
106 :return: (float) random floats on range [0-1]
107
108 """
109
110 if count:
111 return map(lambda x,s=self: s.mt.random(), [0] * int(count))
112 else:
113 return self.mt.random()
114
116 """Valid Mersenne Twister engine.
117
118 Check to see if python is still using the expected Mersenne Twister
119 random number generator. This will almost certainly fail if anything
120 changes..
121
122 """
123 import sys
124
125 r = MTRandom(seed=31415926)
126 for n in range(10000):
127 v = r.rand()
128 if abs(v-0.603852477186) < 1e-12:
129 return True
130 else:
131 if exit:
132 sys.stderr.write('error - Mersenne Twister test failed!\n')
133 sys.exit(1)
134 else:
135 return False
136
137 if __name__ == '__main__':
138 import time, sys
139
140 if validate():
141 sys.stderr.write('Mersenne Twister: OK\n')
142 else:
143 sys.stderr.write('Mersenne Twister: INVALID!\n')
144 sys.exit(1)
145