root/branches/0.2/common.py

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

initial import of PyNN to neuralensemble svn

Line 
1 """
2 Defines the PyNN classes and functions, and hence the FACETS API.
3 The simulator-specific classes should inherit from these and have the same
4 arguments.
5 $Id: common.py 14 2007-01-30 13:09:03Z apdavison $
6 """
7 __version__ = "$Revision: 14 $"
8
9 import types, time, copy
10
11
12 class InvalidParameterValueError(Exception): pass
13 class NonExistentParameterError(Exception): pass
14 class InvalidDimensionsError(Exception): pass
15 class ConnectionError(Exception): pass
16
17 dt = 0.1
18
19 # ==============================================================================
20 #   Standard cells
21 # ==============================================================================
22
23 class StandardCellType(object):
24     """Base class for standardized cell model classes."""
25    
26     translations = {}
27     default_parameters = {}
28    
29     def checkParameters(self, supplied_parameters, with_defaults=False):
30         """Checks that the parameters exist and have values of the correct type."""
31         default_parameters = self.__class__.default_parameters
32         if with_defaults:
33             parameters = copy.copy(default_parameters)
34         else:
35             parameters = {}
36         if supplied_parameters:
37             for k in supplied_parameters.keys():
38                 if default_parameters.has_key(k):
39                     if type(supplied_parameters[k]) == type(default_parameters[k]): # same type
40                         parameters[k] = supplied_parameters[k]
41                     elif type(default_parameters[k]) == types.FloatType: # float and something that can be converted to a float
42                         try:
43                             parameters[k] = float(supplied_parameters[k])
44                         except (ValueError, TypeError):
45                             raise InvalidParameterValueError, (type(supplied_parameters[k]), type(default_parameters[k]))
46                     elif type(default_parameters[k]) == types.ListType: # list and something that can be transformed to a list
47                         try:
48                             parameters[k] = list(supplied_parameters[k])
49                         except TypeError:
50                             raise InvalidParameterValueError, (type(supplied_parameters[k]), type(default_parameters[k]))
51                     else:
52                         raise InvalidParameterValueError, (type(supplied_parameters[k]), type(default_parameters[k]))
53                 else:
54                     raise NonExistentParameterError
55         return parameters
56
57     def translate(self,parameters):
58         """Translate standardized model names to simulator specific names."""
59         parameters = self.checkParameters(parameters)
60         translated_parameters = {}
61         for k in parameters.keys():
62             pname = self.__class__.translations[k][0]
63             pval = eval(self.__class__.translations[k][1])
64             translated_parameters[pname] = pval
65         return translated_parameters
66
67     def __init__(self,parameters):
68         self.parameters = self.checkParameters(parameters, with_defaults=True)
69    
70    
71 class IF_curr_alpha(StandardCellType):
72     """Leaky integrate and fire model with fixed threshold and alpha-function-
73     shaped post-synaptic current."""
74    
75     default_parameters = {
76         'v_rest'     : -65.0,   # Resting membrane potential in mV.
77         'cm'         :   1.0,   # Capacity of the membrane in nF
78         'tau_m'      :  20.0,   # Membrane time constant in ms.
79         'tau_refrac' :   0.0,   # Duration of refractory period in ms.
80         'tau_syn'    :   5.0,   # Rise time of the synaptic alpha function in ms.
81         'i_offset'   :   0.0,   # Offset current in nA
82         'v_reset'    : -65.0,   # Reset potential after a spike in mV.
83         'v_thresh'   : -50.0,   # Spike threshold in mV.
84         'v_init'     : -65.0,   # Membrane potential in mV at t = 0
85     }
86
87 class IF_curr_exp(StandardCellType):
88     """Leaky integrate and fire model with fixed threshold and
89     decaying-exponential post-synaptic current. (Separate synaptic currents for
90     excitatory and inhibitory synapses"""
91    
92     default_parameters = {
93         'v_rest'     : -65.0,   # Resting membrane potential in mV.
94         'cm'         : 1.0,     # Capacity of the membrane in nF
95         'tau_m'      : 20.0,    # Membrane time constant in ms.
96         'tau_refrac' : 0.0,     # Duration of refractory period in ms.
97         'tau_syn_E'  : 5.0,     # Decay time of excitatory synaptic current in ms.
98         'tau_syn_I'  : 5.0,     # Decay time of inhibitory synaptic current in ms.
99         'i_offset'   : 0.0,     # Offset current in nA
100         'v_reset'    : -65.0,   # Reset potential after a spike in mV.
101         'v_thresh'   : -50.0,    # Spike threshold in mV.
102         'v_init'     : -65.0,   # Membrane potential in mV at t = 0
103     }
104
105 #class IF_cond_alpha(StandardCellType):
106 #    """Leaky integrate and fire model with fixed threshold and alpha-function-
107 #    shaped post-synaptic conductance."""
108 #   
109 #    default_parameters = {
110 #        'v_rest'     : -65.0,   # Resting membrane potential in mV.
111 #        'cm'         : 1.0,     # Capacity of the membrane in nF
112 #        'tau_m'      : 20.0,    # Membrane time constant in ms.
113 #        'tau_refrac' : 0.0,     # Duration of refractory period in ms.
114 #        'tau_syn_E'  : 5.0,     # Rise time of the excitatory synaptic alpha function in ms.
115 #        'tau_syn_I'  : 5.0,     # Rise time of the inhibitory synaptic alpha function in ms.
116 #        'e_rev_E'    : 0.0,     # Reversal potential for excitatory input in mV
117 #        'e_rev_I'    : -70.0,   # Reversal potential for inhibitory input in mV
118 #        'v_thresh'   : -50.0    # Spike threshold in mV.
119 #    }   
120
121 class SpikeSourcePoisson(StandardCellType):
122     """Spike source, generating spikes according to a Poisson process."""
123
124     default_parameters = {
125         'rate'     : 0.0,       # Mean spike frequency (Hz)
126         'start'    : 0.0,       # Start time (ms)
127         'duration' : 1e9        # Duration of spike sequence (ms)
128     } 
129
130 class SpikeSourceArray(StandardCellType):
131     """Spike source generating spikes at the times given in the spike_times array."""
132    
133     default_parameters = { 'spike_times' : [] } # list or numpy array containing spike times in milliseconds.
134           
135
136 # ==============================================================================
137 #   Functions for simulation set-up and control
138 # ==============================================================================
139
140 def setup(timestep=0.1,min_delay=0.1,max_delay=0.1,debug=False):
141     """Should be called at the very beginning of a script."""
142     dt = timestep
143     pass
144
145 def end():
146     """Do any necessary cleaning up before exiting."""
147     pass
148    
149 def run(simtime):
150     """Run the simulation for simtime ms."""
151     pass
152
153 def setRNGseeds(seedList):
154     """Globally set rng seeds."""
155     pass
156
157 # ==============================================================================
158 #   Low-level API for creating, connecting and recording from individual neurons
159 # ==============================================================================
160
161 def create(cellclass,paramDict=None,n=1):
162     """Create n cells all of the same type.
163     If n > 1, return a list of cell ids/references.
164     If n==1, return just the single id.
165     """
166     pass
167
168 def connect(source,target,weight=1,delay=0,synapse_type=None,p=1,rng=None):
169     """Connect a source of spikes to a synaptic target. source and target can
170     both be individual cells or lists of cells, in which case all possible
171     connections are made with probability p, using either the random number
172     generator supplied, or the default rng otherwise."""
173     pass
174
175 def set(cells,cellclass,param,val=None):
176     """Set one or more parameters of an individual cell or list of cells.
177     param can be a dict, in which case val should not be supplied, or a string
178     giving the parameter name, in which case val is the parameter value.
179     cellclass must be supplied for doing translation of parameter names."""
180     pass
181
182 def record(source,filename):
183     """Record spikes to a file. source can be an individual cell or a list of
184     cells."""
185     # would actually like to be able to record to an array and choose later
186     # whether to write to a file.
187     pass
188
189 def record_v(source,filename):
190     """Record membrane potential to a file. source can be an individual cell or
191     a list of cells."""
192     # would actually like to be able to record to an array and choose later
193     # whether to write to a file.
194     pass
195
196 # ==============================================================================
197 #   High-level API for creating, connecting and recording from populations of
198 #   neurons.
199 # ==============================================================================
200
201 class Population:
202     """
203     An array of neurons all of the same type. `Population' is used as a generic
204     term intended to include layers, columns, nuclei, etc., of cells.
205     """
206    
207     def __init__(self,dims,cellclass,cellparams=None,label=None):
208         """
209         dims should be a tuple containing the population dimensions, or a single
210           integer, for a one-dimensional population.
211           e.g., (10,10) will create a two-dimensional population of size 10x10.
212         cellclass should either be a standardized cell class (a class inheriting
213         from common.StandardCellType) or a string giving the name of the
214         simulator-specific model that makes up the population.
215         cellparams should be a dict which is passed to the neuron model
216           constructor
217         label is an optional name for the population.
218         """
219        
220         self.dim      = dims
221         if isinstance(dims, int): # also allow a single integer, for a 1D population
222             print "Converting integer dims to tuple"
223             self.dim = (self.dim,)
224         self.label    = label
225         self.celltype = cellclass
226         self.ndim     = len(self.dim)
227         self.cellparams = cellparams
228         self.size = self.dim[0]
229         for i in range(1,self.ndim):
230             self.size *= self.dim[i]
231         self.cell = None # to be defined by child, simulator-specific classes
232     
233     def __getitem__(self,addr):
234         """Returns a representation of the cell with coordinates given by addr,
235            suitable for being passed to other methods that require a cell id.
236            Note that __getitem__ is called when using [] access, e.g.
237              p = Population(...)
238              p[2,3] is equivalent to p.__getitem__((2,3)).
239         """
240         pass
241    
242     def __len__(self):
243         """Returns the total number of cells in the population."""
244         return self.size
245    
246     def set(self,param,val=None):
247         """
248         Set one or more parameters for every cell in the population. param
249         can be a dict, in which case val should not be supplied, or a string
250         giving the parameter name, in which case val is the parameter value.
251         e.g. p.set("tau_m",20.0).
252              p.set({'tau_m':20,'v_rest':-65})
253         """
254         pass
255
256     def tset(self,parametername,valueArray):
257         """
258         'Topographic' set. Sets the value of parametername to the values in
259         valueArray, which must have the same dimensions as the Population.
260         """
261         pass
262    
263     def rset(self,parametername,rand_distr):
264         """
265         'Random' set. Sets the value of parametername to a value taken from
266         rand_distr, which should be a RandomDistribution object.
267         """
268         pass
269    
270     def _call(self,methodname,arguments):
271         """
272         Calls the method methodname(arguments) for every cell in the population.
273         e.g. p.call("set_background","0.1") if the cell class has a method
274         set_background().
275         """
276         pass
277    
278     def _tcall(self,methodname,objarr):
279         """
280         `Topographic' call. Calls the method methodname() for every cell in the
281         population. The argument to the method depends on the coordinates of the
282         cell. objarr is an array with the same dimensions as the Population.
283         e.g. p.tcall("memb_init",vinitArray) calls
284         p.cell[i][j].memb_init(vInitArray[i][j]) for all i,j.
285         """
286         pass
287
288     def randomInit(self,rand_distr):
289         """
290         Sets initial membrane potentials for all the cells in the population to
291         random values.
292         """
293         pass
294
295     def record(self,record_from=None,rng=None):
296         """
297         If record_from is not given, record spikes from all cells in the Population.
298         record_from can be an integer - the number of cells to record from, chosen
299         at random (in this case a random number generator can also be supplied)
300         - or a list containing the ids (e.g., (i,j,k) tuple for a 3D population)
301         of the cells to record.
302         """
303         pass
304
305     def record_v(self,record_from=None,rng=None):
306         """
307         If record_from is not given, record the membrane potential for all cells in
308         the Population.
309         record_from can be an integer - the number of cells to record from, chosen
310         at random (in this case a random number generator can also be supplied)
311         - or a list containing the ids of the cells to record.
312         """
313         pass
314
315     def printSpikes(self,filename,gather=True):
316         """
317         Prints spike times to file in the two-column format
318         "spiketime cell_id" where cell_id is the index of the cell counting
319         along rows and down columns (and the extension of that for 3-D).
320         This allows easy plotting of a `raster' plot of spiketimes, with one
321         line for each cell.
322         """
323         pass
324    
325     def print_v(self,filename,gather=True):
326         """
327         Write membrane potential traces to file.
328         """
329         pass
330    
331     def meanSpikeCount(self,gather=True):
332         """
333         Returns the mean number of spikes per neuron.
334         """
335         pass
336
337 # ==============================================================================
338
339 class Projection:
340     """
341     A container for all the connections between two populations, together with
342     methods to set parameters of those connections, including of plasticity
343     mechanisms.
344     """
345    
346     def __init__(self, presynaptic_population, postsynaptic_population,
347                  method='allToAll', methodParameters=None,
348                  source=None, target=None, label=None, rng=None):
349         """
350         presynaptic_population and postsynaptic_population - Population objects.
351         
352         source - string specifying which attribute of the presynaptic cell signals action potentials
353         
354         target - string specifying which synapse on the postsynaptic cell to connect to
355         If source and/or target are not given, default values are used.
356         
357         method - string indicating which algorithm to use in determining connections.
358         Allowed methods are 'allToAll', 'oneToOne', 'fixedProbability',
359         'distanceDependentProbability', 'fixedNumberPre', 'fixedNumberPost',
360         'fromFile', 'fromList'
361         
362         methodParameters - dict containing parameters needed by the connection method,
363         although we should allow this to be a number or string if there is only
364         one parameter.
365         
366         rng - since most of the connection methods need uniform random numbers,
367         it is probably more convenient to specify a RNG object here rather
368         than within methodParameters, particularly since some methods also use
369         random numbers to give variability in the number of connections per cell.
370         """
371        
372         self.pre    = presynaptic_population  # } these really       
373         self.source = source                  # } should be
374         self.post   = postsynaptic_population # } read-only
375         self.target = target                  # }
376         if label:
377             self.label = label
378         self.rng = rng
379         self.connection = None # access individual connections. To be defined by child, simulator-specific classes
380     
381     def __len__(self):
382         """Return the total number of connections."""
383         return self.nconn
384    
385     # --- Connection methods ---------------------------------------------------
386     
387     def _allToAll(self,parameters=None,synapse_type=None):
388         """
389         Connect all cells in the presynaptic population to all cells in the
390         postsynaptic population.
391         """
392         allow_self_connections = True # when pre- and post- are the same population,
393                                       # is a cell allowed to connect to itself?
394         if parameters and parameters.has_key('allow_self_connections'):
395             allow_self_connections = parameters['allow_self_connections']
396    
397     def _oneToOne(self,synapse_type=None):
398         """
399         Where the pre- and postsynaptic populations have the same size, connect
400         cell i in the presynaptic population to cell i in the postsynaptic
401         population for all i.
402         In fact, despite the name, this should probably be generalised to the
403         case where the pre and post populations have different dimensions, e.g.,
404         cell i in a 1D pre population of size n should connect to all cells
405         in row i of a 2D post population of size (n,m).
406         """
407         pass
408    
409     def _fixedProbability(self,parameters,synapse_type=None):
410         """
411         For each pair of pre-post cells, the connection probability is constant.
412         """
413         allow_self_connections = True
414         try:
415             p_connect = float(parameters)
416         except TypeError:
417             p_connect = parameters['p_connect']
418             if parameters.has_key('allow_self_connections'):
419                 allow_self_connections = parameters['allow_self_connections']
420    
421     def _distanceDependentProbability(self,parameters,synapse_type=None):
422         """
423         For each pair of pre-post cells, the connection probability depends on distance.
424         d_expression should be the right-hand side of a valid python expression
425         for probability, involving 'd', e.g. "exp(-abs(d))", or "float(d<3)"
426         """
427         allow_self_connections = True
428         if type(parameters) == types.StringType:
429             d_expression = parameters
430         else:
431             d_expression = parameters['d_expression']
432             if parameters.has_key('allow_self_connections'):
433                 allow_self_connections = parameters['allow_self_connections']
434    
435     def _fixedNumberPre(self,parameters,synapse_type=None):
436         """Each presynaptic cell makes a fixed number of connections."""
437         allow_self_connections = True
438         if type(parameters) == types.IntType:
439             n = parameters
440         elif type(parameters) == types.DictType:
441             if parameters.has_key['n']: # all cells have same number of connections
442                 n = parameters['n']
443             elif parameters.has_key['rng']: # number of connections per cell follows a distribution
444                 rng = parameters['rng']
445             if parameters.has_key('allow_self_connections'):
446                 allow_self_connections = parameters['allow_self_connections']
447         else : # assume parameters is a rng
448             rng = parameters
449    
450     def _fixedNumberPost(self,parameters,synapse_type=None):
451         """Each postsynaptic cell receives a fixed number of connections."""
452         allow_self_connections = True
453         if type(parameters) == types.IntType:
454             n = parameters
455         elif type(parameters) == types.DictType:
456             if parameters.has_key['n']: # all cells have same number of connections
457                 n = parameters['n']
458             elif parameters.has_key['rng']: # number of connections per cell follows a distribution
459                 rng = parameters['rng']
460             if parameters.has_key('allow_self_connections'):
461                 allow_self_connections = parameters['allow_self_connections']
462         else : # assume parameters is a rng
463             rng = parameters
464    
465     def _fromFile(self,parameters,synapse_type=None):
466         """
467         Load connections from a file.
468         """
469         if type(parameters) == types.FileType:
470             fileobj = parameters
471             # check fileobj is already open for reading
472         elif type(parameters) == types.StringType:
473             filename = parameters
474             # now open the file...
475         elif type(parameters) == types.DictType:
476             # dict could have 'filename' key or 'file' key
477             # implement this...
478             pass
479        
480     def _fromList(self,conn_list,synapse_type=None):
481         """
482         Read connections from a list of tuples,
483         containing ['src[x,y]', 'tgt[x,y]', 'weight', 'delay']
484         """
485         # Need to implement parameter parsing here...
486         pass
487    
488     # --- Methods for setting connection parameters ----------------------------
489     
490     def setWeights(self,w):
491         """
492         w can be a single number, in which case all weights are set to this
493         value, or an array with the same dimensions as the Projection array.
494         """
495         pass
496    
497     def randomizeWeights(self,rand_distr):
498         """
499         Set weights to random values taken from rand_distr.
500         """
501         # Arguably, we could merge this with set_weights just by detecting the
502         # argument type. It could make for easier-to-read simulation code to
503         # give it a separate name, though. Comments?
504         pass
505    
506     def setDelays(self,d):
507         """
508         d can be a single number, in which case all delays are set to this
509         value, or an array with the same dimensions as the Projection array.
510         """
511         pass
512    
513     def randomizeDelays(self,rand_distr):
514         """
515         Set delays to random values taken from rand_distr.
516         """
517         pass
518    
519     def setThreshold(self,threshold):
520         """
521         Where the emission of a spike is determined by watching for a
522         threshold crossing, set the value of this threshold.
523         """
524         # This is a bit tricky, because in NEST the spike threshold is a
525         # property of the cell model, whereas in NEURON it is a property of the
526         # connection (NetCon).
527         pass
528    
529    
530     # --- Methods relating to synaptic plasticity ------------------------------
531     
532     def setupSTDP(self,stdp_model,parameterDict):
533         """Set-up STDP."""
534         pass
535    
536     def toggleSTDP(self,onoff):
537         """Turn plasticity on or off."""
538         pass
539    
540     def setMaxWeight(self,wmax):
541         """Note that not all STDP models have maximum or minimum weights."""
542         pass
543    
544     def setMinWeight(self,wmin):
545         """Note that not all STDP models have maximum or minimum weights."""
546         pass
547    
548     # --- Methods for writing/reading information to/from file. ----------------
549     
550     def saveConnections(self,filename,gather=False):
551         """Save connections to file in a format suitable for reading in with the
552         'fromFile' method."""
553         pass
554    
555     def printWeights(self,filename,format=None,gather=True):
556         """Print synaptic weights to file."""
557         pass
558    
559     def weightHistogram(self,min=None,max=None,nbins=10):
560         """
561         Return a histogram of synaptic weights.
562         If min and max are not given, the minimum and maximum weights are
563         calculated automatically.
564         """
565         # it is arguable whether functions operating on the set of weights
566         # should be put here or in an external module.
567         pass
568
569
570 # ==============================================================================
571 #   Utility classes
572 # ==============================================================================
573   
574 class Timer:
575     """For timing script execution."""
576     # Note that this class only has static methods, i.e. there is only one timer.
577     # It might be nice to allow instances to be created, i.e. have the possibility
578     # of multiple independent timers.
579     
580     @staticmethod
581     def start():
582         """Start timing."""
583         global start_time
584         start_time = time.time()
585    
586     @staticmethod
587     def elapsedTime():
588         """Return the elapsed time but keep the clock running."""
589         return time.time() - start_time
590    
591     @staticmethod
592     def reset():
593         """Reset the time to zero, and start the clock."""
594         global start_time
595         start_time = time.time()
596    
597 # ==============================================================================
598
Note: See TracBrowser for help on using the browser.