Package pype :: Module prand
[frames] | no frames]

Source Code for Module pype.prand

  1  # -*- Mode: Python; tab-width: 4; py-indent-offset: 4; -*- 
  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   
35 -class MTRandom(object):
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
78 - def getstate(self):
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
87 - def setstate(self, state):
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
115 -def validate(exit=False):
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