root/branches/0.2/random.py

Revision 1, 4.5 kB (checked in by davison, 2 years ago)

initial import of PyNN to neuralensemble svn

Line 
1 """
2 Provides wrappers for several random number generators, giving them all a
3 common interface so that they can be used interchangeably in PyNN.
4
5 Note however that we have so far made no effort to implement parameter translation,
6 and parameter names/order may be different for the different RNGs.
7
8 $Id: random.py 14 2007-01-30 13:09:03Z apdavison $
9 """
10
11 import numpy.random, pygsl.rng, time
12
13 # The following two functions taken from
14 # http://www.nedbatchelder.com/text/pythonic-interfaces.html
15 def _functionId(obj, nFramesUp):
16     """ Create a string naming the function n frames up on the stack. """
17     fr = sys._getframe(nFramesUp+1)
18     co = fr.f_code
19     return "%s.%s" % (obj.__class__, co.co_name)
20  
21 def abstractMethod(obj=None):
22     """ Use this instead of 'pass' for the body of abstract methods. """
23     raise Exception("Unimplemented abstract method: %s" % _functionId(obj, 1))
24  
25  
26 class AbstractRNG:
27     """Abstract class for wrapping random number generators. The idea is to be able
28     to use either simulator-native rngs, which may be more efficient, or a
29     standard python rng, e.g. a numpy.random.RandomState object, which would
30     allow the same random numbers to be used across different simulators, or
31     simply to read externally-generated numbers from files."""
32    
33     def __init__(self,seed=None):
34         if seed:
35             assert isinstance(seed,int)
36         self.seed = seed
37         # define some aliases
38         self.random = self.next
39         self.sample = self.next
40    
41     def next(self,n=1,distribution='uniform',parameters=[]):
42         """Return n random numbers from the distribution.
43         
44         If n is 1, return a float, if n > 1, return a numpy array,
45         if n <= 0, raise an Exception."""
46         abstractMethod(self)
47
48    
49 class NumpyRNG(AbstractRNG):
50     """Wrapper for the numpy.random.RandomState class (Mersenne Twister PRNG)."""
51    
52     def __init__(self,seed=None):
53         AbstractRNG.__init__(self,seed)
54         self.rng = numpy.random.RandomState()
55         if self.seed  :
56             self.rng.seed(self.seed)
57         else:
58             self.rng.seed()
59            
60     def __getattr__(self, name):
61         """This is to give NumpyRNG the same methods as numpy.random.RandomState."""
62         return getattr(self.rng,name)
63    
64     def next(self,n=1,distribution='uniform',parameters=[]):
65         """Return n random numbers from the distribution.
66         
67         If n is 1, return a float, if n > 1, return a numpy array,
68         if n <= 0, raise an Exception."""
69         if n > 1:
70            return getattr(self.rng,distribution)(size=n,*parameters)
71         elif n == 1:
72             return getattr(self.rng,distribution)(size=1,*parameters)[0]
73         else:
74             raise ValueError, "The sample number must be positive"
75
76
77 class GSLRNG(AbstractRNG):
78     """Wrapper for the GSL random number generators."""
79        
80     def __init__(self,seed=None,type='mt19937'):
81         AbstractRNG.__init__(self,seed)
82         self.rng = getattr(pygsl.rng,type)()
83         if self.seed  :
84             self.rng.set(self.seed)
85         else:
86             self.seed = int(time.time())
87             self.rng.set(self.seed)
88    
89     def __getattr__(self, name):
90         """This is to give GSLRNG the same methods as the GSL RNGs."""
91         return getattr(self.rng,name)
92    
93     def next(self,n=1,distribution='uniform',parameters=[]):
94         """Return n random numbers from the distribution.
95         
96         If n is 1, return a float, if n > 1, return a numpy array,
97         if n <= 0, raise an Exception."""
98         p = parameters + [n]
99         return getattr(self.rng,distribution)(*p)
100
101    
102 class NativeRNG(AbstractRNG):
103     """Signals that the simulator's own native RNG should be used.
104     Each simulator module should implement a class of the same name which
105     inherits from this and which sets the seed appropriately."""
106     pass
107
108
109 class RandomDistribution:
110     """Class which defines a next(n) method which returns an array of n random
111        numbers from a given distribution."""
112        
113     def __init__(self,rng=None,distribution='uniform',parameters=[]):
114         self.name = distribution
115         self.parameters = parameters
116         if rng:
117             assert isinstance(rng,AbstractRNG)
118             self.rng = rng
119         else: # use numpy.random.RandomState() by default
120             self.rng = numpy.random.RandomState()
121        
122     def next(self,n=1):
123         """Return n random numbers from the distribution."""
124         return self.rng.next(n=n,distribution=self.name,parameters=self.parameters)
125        
Note: See TracBrowser for help on using the browser.