def __init__(self, geometry, name=None, copied=False): """ :param geometry: population geometry as tuple. It must correspond to the image size and be fixed through the whole simulation. :param name: unique name of the population (optional). """ # Check geometry if isinstance(geometry, int) or len(geometry) == 1: Global._error( 'The geometry of an ImagePopulation should be 2D (grayscale) or 3D (color).' ) if len(geometry) == 3 and (geometry[2] != 3 and geometry[2] != 1): Global._error( 'The third dimension of an ImagePopulation should be either 1 (grayscale) or 3 (color).' ) if len(geometry) == 3 and geometry[2] == 1: geometry = (int(geometry[0]), int(geometry[1])) # Create the population Population.__init__(self, geometry=geometry, name=name, neuron=Neuron(parameters="r = 0.0"), copied=copied)
def __init__(self, spike_times, name=None): if not isinstance(spike_times, list): Global._error('in SpikeSourceArray, spike_times must be a Python list.') exit(0) if isinstance(spike_times[0], list): # several neurons nb_neurons = len(spike_times) else: # a single Neuron nb_neurons = 1 spike_times = [ spike_times ] # Create a fake neuron just to be sure the description has the correct parameters neuron = Neuron( parameters=""" spike_times = 0.0 """, equations="", spike=" t == spike_times", reset="", name="Spike source", description="Spikes source array." ) Population.__init__(self, geometry=nb_neurons, neuron=neuron, name=name) # Do some sorting to save C++ complexity times = [] for neur_times in spike_times: times.append(sorted(list(set(neur_times)))) # suppress doublons and sort self.init['spike_times'] = times
def __init__(self, geometry, name=None): """ *Parameters*: * *geometry*: population geometry as tuple. It must correspond to the image size and be fixed through the whole simulation. * If the geometry is 2D, it corresponds to the (height, width) of the image. Only the luminance of the pixels will be represented (grayscale image). * If the geometry is 3D, the third dimension can be either 1 (grayscale) or 3 (color). If the third dimension is 3, each will correspond to the RGB values of the pixels. .. warning:: Due to the indexing system of Numpy, a 640*480 image should be fed into a (480, 640) or (480, 640, 3) population. * *name*: unique name of the population (optional). """ # Check geometry if isinstance(geometry, int) or len(geometry)==1: Global._error('The geometry of an ImagePopulation should be 2D (grayscale) or 3D (color).') exit(0) if len(geometry)==3 and (geometry[2]!=3 and geometry[2]!=1): Global._error('The third dimension of an ImagePopulation should be either 1 (grayscale) or 3 (color).') exit(0) if len(geometry)==3 and geometry[2]==1: geometry = (geometry[0], geometry[1]) # Create the population Population.__init__(self, geometry = geometry, name=name, neuron = Neuron(parameters="r = 0.0") )
def __setattr__(self, name, value): " Method called when setting an attribute." Population.__setattr__(self, name, value) if name in ['rates', 'corr', 'tau'] and hasattr(self, 'initialized'): # Correction of mu and sigma everytime r, c or tau is changed self.mu, self.sigma = self._rectify(self.rates, self.corr, self.tau)
def __init__(self, geometry, name=None, copied=False): """ *Parameters*: * *geometry*: population geometry as tuple. It must correspond to the image size and be fixed through the whole simulation. * *name*: unique name of the population (optional). About the geometry: * If the geometry is 2D, it corresponds to the (height, width) of the image. Only the luminance of the pixels will be represented (grayscale image). * If the geometry is 3D, the third dimension can be either 1 (grayscale) or 3 (color). If the third dimension is 3, each will correspond to the RGB values of the pixels. .. warning:: Due to the indexing system of Numpy, a 640*480 image should be fed into a (480, 640) or (480, 640, 3) population. """ # Check geometry if isinstance(geometry, int) or len(geometry)==1: Global._error('The geometry of an ImagePopulation should be 2D (grayscale) or 3D (color).') if len(geometry)==3 and (geometry[2]!=3 and geometry[2]!=1): Global._error('The third dimension of an ImagePopulation should be either 1 (grayscale) or 3 (color).') if len(geometry)==3 and geometry[2]==1: geometry = (int(geometry[0]), int(geometry[1])) # Create the population Population.__init__(self, geometry = geometry, name=name, neuron = Neuron(parameters="r = 0.0"), copied=copied)
def __init__(self, population, name=None, scaling=1.0, refractory=None, copied=False): """ :param population: the Population to convert. Its neuron type must be spiking. :param name: the (optional) name of the hybrid population. :param scaling: the scaling of the firing rate. Defines what a rate ``r`` of 1.0 means in Hz (default: 1.0). :param refractory: a refractory period in ms to ensure the ISI is not too high (default: None) """ self.population = population self.refractory_init = refractory if not self.population.neuron_type.description['type'] == 'rate': Global._error('the population ' + self.population.name + ' must contain rate-coded neurons.') # Create the description, but it will not be used for generation Population.__init__( self, geometry = self.population.geometry, name=name, neuron = Neuron( parameters=""" scaling = %(scaling)s : population """ % {'scaling': scaling} , equations=""" p = Uniform(0.0, 1.0) rates = p """, spike="rates>p", refractory=refractory ) , copied=self.copied ) self._specific = True
def __init__(self, population, name=None, scaling=1.0, refractory=None): """ *Parameters*: * **population**: the Population to convert. Its neuron type must be spiking. * **name**: the (optional) name of the hybrid population. * **scaling**: the scaling of the firing rate. Defines what a rate ``r`` of 1.0 means in Hz (default: 1.0). * **refractory**: a refractory period in ms to ensure the ISI is not too high (default: None) """ self.population = population if not self.population.neuron_type.description['type'] == 'rate': Global._error('the population ' + self.population.name + ' must contain rate-coded neurons.') # Create the description, but it will not be used for generation Population.__init__( self, geometry = self.population.geometry, name=name, neuron = Neuron( parameters=""" scaling = %(scaling)s : population """ % {'scaling': scaling} , equations=""" p = Uniform(0.0, 1.0) rates = p """, spike="rates>p", refractory=refractory ) ) self._specific = True
def __init__(self, spike_times, name=None): if not isinstance(spike_times, list): Global._error('In a SpikeSourceArray, spike_times must be a Python list.') if isinstance(spike_times[0], list): # several neurons nb_neurons = len(spike_times) else: # a single Neuron nb_neurons = 1 spike_times = [ spike_times ] # Create a fake neuron just to be sure the description has the correct parameters neuron = Neuron( parameters=""" spike_times = 0.0 : int """, equations="", spike=" t == spike_times", reset="", name="Spike source", description="Spikes source array." ) Population.__init__(self, geometry=nb_neurons, neuron=neuron, name=name) self.init['spike_times'] = spike_times
def __setattr__(self, name, value): if name == 'spike_times': if self.initialized: self.cyInstance.set_spike_times(value) else: object.__setattr__(self, name, value) else: Population.__setattr__(self, name, value)
def __init__(self, geometry, neuron, name=None, copied=False): """ Initialization, receive default arguments of Population objects. """ Population.__init__(self, geometry=geometry, neuron=neuron, name=name, stop_condition=None, storage_order='post_to_pre', copied=copied)
def __setattr__(self, name, value): if name == 'spike_times': if not isinstance(value[0], list): # several neurons value = [ value ] if not len(value) == self.size: Global._error('SpikeSourceArray: the size of the spike_times attribute must match the number of neurons in the population.') self.init['spike_times'] = value # when reset is called if self.initialized: self.cyInstance.set_spike_times(self._sort_spikes(value)) else: Population.__setattr__(self, name, value)
def __setattr__(self, name, value): if name == 'spike_times': if not isinstance(value[0], list): # several neurons value = [value] if not len(value) == self.size: Global._error( 'SpikeSourceArray: the size of the spike_times attribute must match the number of neurons in the population.' ) self.init['spike_times'] = value # when reset is called if self.initialized: self.cyInstance.set_spike_times(self._sort_spikes(value)) else: Population.__setattr__(self, name, value)
def __getattr__(self, name): if name == 'schedule': if self.initialized: return Global.config['dt'] * self.cyInstance.get_schedule() else: return self.init['schedule'] elif name == 'rates': if self.initialized: if len(self.geometry) > 1: # unflatten the data flat_values = self.cyInstance.get_rates() values = np.zeros( tuple( [len(self.schedule)] + list(self.geometry) ) ) for x in range(len(self.schedule)): values[x] = np.reshape( flat_values[x], self.geometry) return values else: return self.cyInstance.get_rates() else: return self.init['rates'] elif name == 'period': if self.initialized: return self.cyInstance.get_period() * Global.config['dt'] else: return self.init['period'] else: return Population.__getattribute__(self, name)
def __getattr__(self, name): if name == 'schedule': if self.initialized: return Global.config['dt'] * self.cyInstance.get_schedule() else: return self.init['schedule'] elif name == 'rates': if self.initialized: if len(self.geometry) > 1: # unflatten the data flat_values = self.cyInstance.get_rates() values = np.zeros( tuple([len(self.schedule)] + list(self.geometry))) for x in range(len(self.schedule)): values[x] = np.reshape(flat_values[x], self.geometry) return values else: return self.cyInstance.get_rates() else: return self.init['rates'] elif name == 'period': if self.initialized: return self.cyInstance.get_period() * Global.config['dt'] else: return self.init['period'] else: return Population.__getattribute__(self, name)
def __getattr__(self, name): if name == 'spike_times': if self.initialized: return [ [Global.config['dt']*time for time in neur] for neur in self.cyInstance.get_spike_times()] else: return self.init['spike_times'] else: return Population.__getattribute__(self, name)
def __getattr__(self, name): if name == 'spike_times': if self.initialized: return self.cyInstance.get_spike_times() else: return object.__getattribute__(self, name) else: return Population.__getattribute__(self, name)
def __getattr__(self, name): if name == 'spike_times': if self.initialized: return [[Global.config['dt'] * time for time in neur] for neur in self.cyInstance.get_spike_times()] else: return self.init['spike_times'] else: return Population.__getattribute__(self, name)
def __init__(self, geometry, rates, corr, tau, name=None, refractory=None): """ *Parameters*: * **geometry**: population geometry as tuple. * **rates**: rate in Hz of the population (must be a positive float) * **corr**: total correlation strength (float in [0, 1]) * **tau**: correlation time constant in ms. * **name**: unique name of the population (optional). * **refractory**: refractory period in ms (careful: may break the correlation) """ # Store parameters self.rates = float(rates) self.corr = corr # Correction of mu and sigma mu, sigma = self._rectify(self.rates, self.corr, tau) # Create the neuron corr_neuron = Neuron( parameters = """ tau = %(tau)s : population mu = %(mu)s : population sigma = %(sigma)s : population """ % {'tau': tau, 'mu': mu, 'sigma': sigma}, equations = """ x += dt*(mu - x)/tau + sqrt(dt/tau) * sigma * Normal(0., 1.) : population, init=%(mu)s p = Uniform(0.0, 1.0) * 1000.0 / dt """ % {'mu': mu}, spike = "p < x", refractory=refractory, name="HomogeneousCorrelated", description="Homogeneous correlated spike trains." ) Population.__init__(self, geometry=geometry, neuron=corr_neuron, name=name)
def __setattr__(self, name, value): if name == 'schedule': if self.initialized: self.cyInstance.set_schedule( np.array(value) / Global.config['dt'] ) else: self.init['schedule'] = value elif name == 'rates': if self.initialized: if len(value.shape) > 2: # we need to flatten the provided data flat_values = value.reshape( (value.shape[0], self.size) ) self.cyInstance.set_rates( flat_values ) else: self.cyInstance.set_rates( value ) else: self.init['rates'] = value elif name == "period": if self.initialized: self.cyInstance.set_period(int(value /Global.config['dt'])) else: self.init['period'] = value else: Population.__setattr__(self, name, value)
def __setattr__(self, name, value): if name == 'schedule': if self.initialized: self.cyInstance.set_schedule( np.array(value) / Global.config['dt']) else: self.init['schedule'] = value elif name == 'rates': if self.initialized: if len(value.shape) > 2: # we need to flatten the provided data flat_values = value.reshape((value.shape[0], self.size)) self.cyInstance.set_rates(flat_values) else: self.cyInstance.set_rates(value) else: self.init['rates'] = value elif name == "period": if self.initialized: self.cyInstance.set_period(int(value / Global.config['dt'])) else: self.init['period'] = value else: Population.__setattr__(self, name, value)
def __init__(self, geometry, name=None, rates=None, target=None, parameters=None, refractory=None): """ *Parameters*: * *geometry*: population geometry as tuple. * *name*: unique name of the population (optional). * *rates*: mean firing rate of each neuron. It can be a single value (e.g. 10.0) or an equation (as string). * *parameters*: additional parameters which can be used in the *rates* equation. * *refractory*: refractory period in ms. """ if rates == None and target==None: Global._error('A PoissonPopulation must define either rates or target.') exit(0) if target is not None: # hybrid population # Create the neuron poisson_neuron = Neuron( parameters = """ %(params)s """ % {'params': parameters if parameters else ''}, equations = """ rates = sum(%(target)s) p = Uniform(0.0, 1.0) * 1000.0 / dt _sum_%(target)s = 0.0 """ % {'target': target}, spike = """ p < rates """, refractory=refractory, name="Hybrid", description="Hybrid spiking neuron emitting spikes according to a Poisson distribution at a frequency determined by the weighted sum of inputs." ) elif isinstance(rates, str): # Create the neuron poisson_neuron = Neuron( parameters = """ %(params)s """ % {'params': parameters if parameters else ''}, equations = """ rates = %(rates)s p = Uniform(0.0, 1.0) * 1000.0 / dt _sum_exc = 0.0 """ % {'rates': rates}, spike = """ p < rates """, refractory=refractory, name="Poisson", description="Spiking neuron with spikes emitted according to a Poisson distribution." ) elif isinstance(rates, np.ndarray): poisson_neuron = Neuron( parameters = """ rates = 10.0 """, equations = """ p = Uniform(0.0, 1.0) * 1000.0 / dt """, spike = """ p < rates """, refractory=refractory, name="Poisson", description="Spiking neuron with spikes emitted according to a Poisson distribution." ) else: poisson_neuron = Neuron( parameters = """ rates = %(rates)s """ % {'rates': rates}, equations = """ p = Uniform(0.0, 1.0) * 1000.0 / dt """, spike = """ p < rates """, refractory=refractory, name="Poisson", description="Spiking neuron with spikes emitted according to a Poisson distribution." ) Population.__init__(self, geometry=geometry, neuron=poisson_neuron, name=name) if isinstance(rates, np.ndarray): self.rates = rates
def _create_adaptive(self): # Create the description, but it will not be used for generation Population.__init__( self, geometry = self.population.geometry, name=self.name, neuron = Neuron( parameters=""" window = %(window)s : population scaling = %(scaling)s : population smooth = %(smooth)s : population """ % {'window': self.window, 'scaling': self.scaling, 'smooth': self.smooth} , equations="r = 0.0" ) ) # Generate specific code omp_code = "#pragma omp parallel for private(pop%(id)s_nb, pop%(id)s_out)" if Global.config['num_threads'] > 1 else "" code = """#pragma once #include "pop%(id_pre)s.hpp" extern PopStruct%(id_pre)s pop%(id_pre)s; struct PopStruct%(id)s{ // Number of neurons int size; bool _active; // Local parameter window double window ; std::vector< double > ad_window ; // Global parameter scaling double scaling ; // Global parameter smooth double smooth ; // Local variable r std::vector< double > r ; std::vector< std::vector< double > > recorded_r ; bool record_r ; // Store the last spikes std::vector< std::vector<long int> > last_spikes; std::vector< double > isi; int get_size() { return size; } void set_size(int value) { size = value; } bool is_active() { return _active; } void set_active(bool value) { _active = value; } double get_window() { return window; } void set_window(double value) { window = value; } double get_scaling() { return scaling; } void set_scaling(double value) { scaling = value; } double get_smooth() { return smooth; } void set_smooth(double value) { smooth = value; } std::vector< double > get_r() { return r; } void set_r(std::vector< double > value) { r = value; } double get_single_r(int rk) { return r[rk]; } void set_single_r(int rk, double value) { r[rk] = value; } void init_population() { size = %(size)s; _active = true; last_spikes = std::vector< std::vector<long int> >(size, std::vector<long int>()); ad_window = std::vector< double >(size, window); isi = std::vector< double >(size, 10000.0); } void update_rng() { } void update() { // Updating the local variables of Spike2Rate population %(id)s if(_active){ int pop%(id)s_nb, pop%(id)s_out; %(omp_code)s for(int i = 0; i < size; i++){ // Increase when spiking if (pop%(id_pre)s.last_spike[i] == t-1){ if(last_spikes[i].size() > 0) isi[i] = double(t-1 - last_spikes[i][last_spikes[i].size()-1]); else isi[i] = 10000.0; last_spikes[i].push_back(t-1); } pop%(id)s_nb = 0; pop%(id)s_out = -1; for(int j=0; j < last_spikes[i].size(); j++){ if(last_spikes[i][j] >= t -1 - (long int)(ad_window[i]/dt) ){ pop%(id)s_nb++; } else{ pop%(id)s_out = j; } } if (pop%(id)s_out > -1){ last_spikes[i].erase(last_spikes[i].begin(), last_spikes[i].begin()+pop%(id)s_out); } r[i] += dt*(1000.0/scaling / ad_window[i] * double(pop%(id)s_nb) - r[i] ) / smooth; //ad_window[i] = clip(5.0*isi[i], 20.0*dt, window) ; ad_window[i] += dt * (clip(5.0*isi[i], 20.0*dt, window) - ad_window[i])/100.0; if (i==0) std::cout << ad_window[i] << " " << isi[i] << std::endl; } } } }; """ % {'id' : self.id, 'id_pre': self.population.id, 'omp_code': omp_code, 'size': self.size} return code
def _create_isi(self): # Create the description, but it will not be used for generation Population.__init__( self, geometry = self.population.geometry, name=self.name, neuron = Neuron( parameters=""" cut = %(cut)s : population scaling = %(scaling)s : population smooth = %(smooth)s : population """ % {'cut': self.cut, 'scaling': self.scaling, 'smooth': self.smooth} , equations="r = 0.0" ) ) # Generate specific code omp_code = "#pragma omp parallel for" if Global.config['num_threads'] > 1 else "" code = """#pragma once #include "pop%(id_pre)s.hpp" extern PopStruct%(id_pre)s pop%(id_pre)s; struct PopStruct%(id)s{ // Number of neurons int size; bool _active; // Global parameter cut double cut ; // Global parameter scaling double scaling ; // Global parameter smooth double smooth ; // Local variable r std::vector< double > r ; // Store the last spike std::vector< long int > last_spike; std::vector< double > isi; std::vector< double > support; int get_size() { return size; } void set_size(int value) { size = value; } bool is_active() { return _active; } void set_active(bool value) { _active = value; } double get_cut() { return cut; } void set_cut(double value) { cut = value; } double get_scaling() { return scaling; } void set_scaling(double value) { scaling = value; } double get_smooth() { return smooth; } void set_smooth(double value) { smooth = value; } std::vector< double > get_r() { return r; } void set_r(std::vector< double > value) { r = value; } double get_single_r(int rk) { return r[rk]; } void set_single_r(int rk, double value) { r[rk] = value; } void init_population() { size = %(size)s; _active = true; last_spike = std::vector< long int >(size, -10000L); isi = std::vector< double >(size, 10000.0); support = std::vector< double >(size, 10000.0); } void update_rng() { } void update() { // Updating the local variables of Spike2Rate population %(id)s if(_active){ %(omp_code)s for(int i = 0; i < size; i++){ // Increase when spiking if (pop%(id_pre)s.last_spike[i] == t-1){ isi[i] = double(t-1 - last_spike[i]); support[i] = double(t-1 - last_spike[i]); last_spike[i] = t-1; } else if( double(t - last_spike[i]) <= isi[i]){ // do nothing } else if( double(t - last_spike[i]) <= cut*isi[i]){ support[i] += 1.0 ; } else{ support[i] = 10000.0 ; } r[i] += dt*(1000.0/scaling/support[i]/dt - r[i])/smooth; } } } }; """ % {'id' : self.id, 'id_pre': self.population.id, 'omp_code': omp_code, 'size': self.size } return code
def _create_adaptive(self): # Create the description, but it will not be used for generation Population.__init__(self, geometry=self.population.geometry, name=self.name, neuron=Neuron(parameters=""" window = %(window)s : population scaling = %(scaling)s : population smooth = %(smooth)s : population """ % { 'window': self.window, 'scaling': self.scaling, 'smooth': self.smooth }, equations="r = 0.0"), copied=self.copied) # Generate specific code omp_code = "#pragma omp parallel for private(pop%(id)s_nb, pop%(id)s_out)" if Global.config[ 'num_threads'] > 1 else "" code = """#pragma once #include "pop%(id_pre)s.hpp" extern PopStruct%(id_pre)s pop%(id_pre)s; struct PopStruct%(id)s{ // Number of neurons int size; bool _active; // Local parameter window %(float_prec)s window ; std::vector< %(float_prec)s > ad_window ; // Global parameter scaling %(float_prec)s scaling ; // Global parameter smooth %(float_prec)s smooth ; // Local variable r std::vector< %(float_prec)s > r ; std::vector< std::vector< %(float_prec)s > > recorded_r ; bool record_r ; // Store the last spikes std::vector< std::vector<long int> > last_spikes; std::vector< %(float_prec)s > isi; int get_size() { return size; } void set_size(int value) { size = value; } bool is_active() { return _active; } void set_active(bool value) { _active = value; } %(float_prec)s get_window() { return window; } void set_window(%(float_prec)s value) { window = value; } %(float_prec)s get_scaling() { return scaling; } void set_scaling(%(float_prec)s value) { scaling = value; } %(float_prec)s get_smooth() { return smooth; } void set_smooth(%(float_prec)s value) { smooth = value; } std::vector< %(float_prec)s > get_r() { return r; } void set_r(std::vector< %(float_prec)s > value) { r = value; } %(float_prec)s get_single_r(int rk) { return r[rk]; } void set_single_r(int rk, %(float_prec)s value) { r[rk] = value; } void init_population() { size = %(size)s; _active = true; last_spikes = std::vector< std::vector<long int> >(size, std::vector<long int>()); ad_window = std::vector< %(float_prec)s >(size, window); isi = std::vector< %(float_prec)s >(size, 10000.0); } void update_rng() { } void update() { // Updating the local variables of Spike2Rate population %(id)s if(_active){ int pop%(id)s_nb, pop%(id)s_out; %(omp_code)s for(int i = 0; i < size; i++){ // Increase when spiking if (pop%(id_pre)s.last_spike[i] == t-1){ if(last_spikes[i].size() > 0) isi[i] = %(float_prec)s(t-1 - last_spikes[i][last_spikes[i].size()-1]); else isi[i] = 10000.0; last_spikes[i].push_back(t-1); } pop%(id)s_nb = 0; pop%(id)s_out = -1; for(int j=0; j < last_spikes[i].size(); j++){ if(last_spikes[i][j] >= t -1 - (long int)(ad_window[i]/dt) ){ pop%(id)s_nb++; } else{ pop%(id)s_out = j; } } if (pop%(id)s_out > -1){ last_spikes[i].erase(last_spikes[i].begin(), last_spikes[i].begin()+pop%(id)s_out); } r[i] += dt*(1000.0/scaling / ad_window[i] * %(float_prec)s(pop%(id)s_nb) - r[i] ) / smooth; //ad_window[i] = clip(5.0*isi[i], 20.0*dt, window) ; ad_window[i] += dt * (clip(5.0*isi[i], 20.0*dt, window) - ad_window[i])/100.0; if (i==0) std::cout << ad_window[i] << " " << isi[i] << std::endl; } } } }; """ % { 'id': self.id, 'id_pre': self.population.id, 'omp_code': omp_code, 'size': self.size, 'float_prec': Global.config['precision'] } return code
def __init__(self, populations=None, bold_model=balloon_RN, mapping={'I_CBF': 'r'}, scale_factor=None, normalize_input=None, recorded_variables=None, start=False, net_id=0, copied=False): """ :param populations: list of recorded populations. :param bold_model: computational model for BOLD signal defined as a BoldModel class/object (see ANNarchy.extensions.bold.PredefinedModels for more predefined examples). Default is `balloon_RN`. :param mapping: mapping dictionary between the inputs of the BOLD model (`I_CBF` for single inputs, `I_CBF` and `I_CMRO2` for double inputs in the provided examples) and the variables of the input populations. By default, `{'I_CBF': 'r'}` maps the firing rate `r` of the input population(s) to the variable `I_CBF` of the BOLD model. :param scale_factor: list of float values to allow a weighting of signals between populations. By default, the input signal is weighted by the ratio of the population size to all populations within the recorded region. :param normalize_input: list of integer values which represent a optional baseline per population. The input signals will require an additional normalization using a baseline value. A value different from 0 represents the time period for determing this baseline in milliseconds (biological time). :param recorded_variables: which variables of the BOLD model should be recorded? (by default, the output variable of the BOLD model is added, e.g. ["BOLD"] for the provided examples). """ self.net_id = net_id # instantiate if necessary, please note # that population will make a deepcopy on this objects if inspect.isclass(bold_model): bold_model = bold_model() # for reporting bold_model._model_instantiated = True # The usage of [] as default arguments in the __init__ call lead to strange side effects. # We decided therefore to use None as default and create the lists locally. if populations is None: Global._error( "Either a population or a list of populations must be provided to the BOLD monitor (populations=...)" ) if scale_factor is None: scale_factor = [] if normalize_input is None: normalize_input = [] if recorded_variables is None: recorded_variables = [] # argument check if not (isinstance(populations, list)): populations = [populations] if not (isinstance(scale_factor, list)): scale_factor = [scale_factor] * len(populations) if not (isinstance(normalize_input, list)): normalize_input = [normalize_input] * len(populations) if isinstance(recorded_variables, str): recorded_variables = [recorded_variables] if len(scale_factor) > 0: if len(populations) != len(scale_factor): Global._error( "BoldMonitor: Length of scale_factor must be equal to number of populations" ) if len(normalize_input) > 0: if len(populations) != len(normalize_input): Global._error( "BoldMonitor: Length of normalize_input must be equal to number of populations" ) # Check mapping for target, input_var in mapping.items(): if not target in bold_model._inputs: Global._error("BoldMonitor: the key " + target + " of mapping is not part of the BOLD model.") # Check recorded variables if len(recorded_variables) == 0: recorded_variables = bold_model._output else: # Add the output variables (and remove doublons) l1 = bold_model._output l2 = [recorded_variables] if isinstance( recorded_variables, str) else recorded_variables recorded_variables = list(set(l2 + l1)) recorded_variables.sort() if not copied: # Add the container to the object management Global._network[0]['extensions'].append(self) self.id = len(Global._network[self.net_id]['extensions']) # create the population self._bold_pop = Population(1, neuron=bold_model, name=bold_model.name) self._bold_pop.enabled = start # create the monitor self._monitor = Monitor(self._bold_pop, recorded_variables, start=start) # create the projection(s) self._acc_proj = [] if len(scale_factor) == 0: pop_overall_size = 0 for _, pop in enumerate(populations): pop_overall_size += pop.size # the conductance is normalized between [0 .. 1]. This scale factor # should balance different population sizes for _, pop in enumerate(populations): scale_factor_conductance = float( pop.size) / float(pop_overall_size) scale_factor.append(scale_factor_conductance) if len(normalize_input) == 0: normalize_input = [0] * len(populations) # TODO: can we check if users used NormProjections? If not, this will crash ... for target, input_var in mapping.items(): for pop, scale, normalize in zip(populations, scale_factor, normalize_input): tmp_proj = AccProjection(pre=pop, post=self._bold_pop, target=target, variable=input_var, scale_factor=scale, normalize_input=normalize) tmp_proj.connect_all_to_all(weights=1.0) self._acc_proj.append(tmp_proj) else: # Add the container to the object management Global._network[net_id]['extensions'].append(self) self.id = len(Global._network[self.net_id]['extensions']) # instances are assigned by the copying instance self._bold_pop = None self._monitor = None self._acc_proj = [] self.name = "bold_monitor" # store arguments for copy self._populations = populations self._mapping = mapping self._recorded_variables = recorded_variables self._bold_model = bold_model self._start = start # Finalize initialization self._initialized = True if not copied else False
def __init__(self, geometry, name=None, rates=None, target=None, parameters=None, refractory=None): """ *Parameters*: * **geometry**: population geometry as tuple. * **name**: unique name of the population (optional). * **rates**: mean firing rate of each neuron. It can be a single value (e.g. 10.0) or an equation (as string). * **target**: the mean firing rate will be the weighted sum of inputs having this target name (e.g. "exc"). * **parameters**: additional parameters which can be used in the *rates* equation. * **refractory**: refractory period in ms. """ if rates is None and target is None: Global._error('A PoissonPopulation must define either rates or target.') if target is not None: # hybrid population # Create the neuron poisson_neuron = Neuron( parameters = """ %(params)s """ % {'params': parameters if parameters else ''}, equations = """ rates = sum(%(target)s) p = Uniform(0.0, 1.0) * 1000.0 / dt _sum_%(target)s = 0.0 """ % {'target': target}, spike = """ p < rates """, refractory=refractory, name="Hybrid", description="Hybrid spiking neuron emitting spikes according to a Poisson distribution at a frequency determined by the weighted sum of inputs." ) elif isinstance(rates, str): # Create the neuron poisson_neuron = Neuron( parameters = """ %(params)s """ % {'params': parameters if parameters else ''}, equations = """ rates = %(rates)s p = Uniform(0.0, 1.0) * 1000.0 / dt _sum_exc = 0.0 """ % {'rates': rates}, spike = """ p < rates """, refractory=refractory, name="Poisson", description="Spiking neuron with spikes emitted according to a Poisson distribution." ) elif isinstance(rates, np.ndarray): poisson_neuron = Neuron( parameters = """ rates = 10.0 """, equations = """ p = Uniform(0.0, 1.0) * 1000.0 / dt """, spike = """ p < rates """, refractory=refractory, name="Poisson", description="Spiking neuron with spikes emitted according to a Poisson distribution." ) else: poisson_neuron = Neuron( parameters = """ rates = %(rates)s """ % {'rates': rates}, equations = """ p = Uniform(0.0, 1.0) * 1000.0 / dt """, spike = """ p < rates """, refractory=refractory, name="Poisson", description="Spiking neuron with spikes emitted according to a Poisson distribution." ) Population.__init__(self, geometry=geometry, neuron=poisson_neuron, name=name) if isinstance(rates, np.ndarray): self.rates = rates
def _create_isi(self): # Create the description, but it will not be used for generation Population.__init__(self, geometry=self.population.geometry, name=self.name, neuron=Neuron(parameters=""" cut = %(cut)s : population scaling = %(scaling)s : population smooth = %(smooth)s : population """ % { 'cut': self.cut, 'scaling': self.scaling, 'smooth': self.smooth }, equations="r = 0.0"), copied=self.copied) # Generate specific code omp_code = "#pragma omp parallel for" if Global.config[ 'num_threads'] > 1 else "" code = """#pragma once #include "pop%(id_pre)s.hpp" extern PopStruct%(id_pre)s pop%(id_pre)s; struct PopStruct%(id)s{ // Number of neurons int size; bool _active; // Global parameter cut %(float_prec)s cut; // Global parameter scaling %(float_prec)s scaling; // Global parameter smooth %(float_prec)s smooth ; // Local variable r std::vector< %(float_prec)s > r ; // Store the last spike std::vector< long int > last_spike; std::vector< %(float_prec)s > isi; std::vector< %(float_prec)s > support; int get_size() { return size; } void set_size(int value) { size = value; } bool is_active() { return _active; } void set_active(bool value) { _active = value; } %(float_prec)s get_cut() { return cut; } void set_cut(%(float_prec)s value) { cut = value; } %(float_prec)s get_scaling() { return scaling; } void set_scaling(%(float_prec)s value) { scaling = value; } %(float_prec)s get_smooth() { return smooth; } void set_smooth(%(float_prec)s value) { smooth = value; } std::vector< %(float_prec)s > get_r() { return r; } void set_r(std::vector< %(float_prec)s > value) { r = value; } %(float_prec)s get_single_r(int rk) { return r[rk]; } void set_single_r(int rk, %(float_prec)s value) { r[rk] = value; } void init_population() { size = %(size)s; _active = true; last_spike = std::vector< long int >(size, -10000L); isi = std::vector< %(float_prec)s >(size, 10000.0); support = std::vector< %(float_prec)s >(size, 10000.0); } void update_rng() { } void update() { // Updating the local variables of Spike2Rate population %(id)s if(_active){ %(omp_code)s for(int i = 0; i < size; i++){ // Increase when spiking if (pop%(id_pre)s.last_spike[i] == t-1){ isi[i] = %(float_prec)s(t-1 - last_spike[i]); support[i] = %(float_prec)s(t-1 - last_spike[i]); last_spike[i] = t-1; } else if( %(float_prec)s(t - last_spike[i]) <= isi[i]){ // do nothing } else if( %(float_prec)s(t - last_spike[i]) <= cut*isi[i]){ support[i] += 1.0 ; } else{ support[i] = 10000.0 ; } r[i] += dt*(1000.0/scaling/support[i]/dt - r[i])/smooth; } } } }; """ % { 'id': self.id, 'id_pre': self.population.id, 'omp_code': omp_code, 'size': self.size, 'float_prec': Global.config['precision'] } return code
def _create_window(self): # Create the description, but it will not be used for generation Population.__init__( self, geometry = self.population.geometry, name=self.name, neuron = Neuron( parameters=""" window = %(window)s : population scaling = %(scaling)s : population smooth = %(smooth)s : population """ % {'window': self.window, 'scaling': self.scaling, 'smooth': self.smooth} , equations="r = 0.0" ) , copied=self.copied ) # Generate specific code omp_code = "#pragma omp parallel for" if Global.config['num_threads'] > 1 else "" code = """#pragma once #include "pop%(id_pre)s.hpp" extern PopStruct%(id_pre)s pop%(id_pre)s; struct PopStruct%(id)s{ // Number of neurons int size; bool _active; // Global parameter window %(float_prec)s window ; // Global parameter scaling %(float_prec)s scaling ; // Global parameter smooth %(float_prec)s smooth ; // Local variable r std::vector< %(float_prec)s > r ; // Store the last spikes std::vector< std::vector<long int> > last_spikes; int get_size() { return size; } void set_size(int value) { size = value; } bool is_active() { return _active; } void set_active(bool value) { _active = value; } %(float_prec)s get_window() { return window; } void set_window(%(float_prec)s value) { window = value; } %(float_prec)s get_scaling() { return scaling; } void set_scaling(%(float_prec)s value) { scaling = value; } %(float_prec)s get_smooth() { return smooth; } void set_smooth(%(float_prec)s value) { smooth = value; } std::vector< %(float_prec)s > get_r() { return r; } void set_r(std::vector< %(float_prec)s > value) { r = value; } %(float_prec)s get_single_r(int rk) { return r[rk]; } void set_single_r(int rk, %(float_prec)s value) { r[rk] = value; } void init_population() { size = %(size)s; _active = true; last_spikes = std::vector< std::vector<long int> >(size, std::vector<long int>()); } void update_rng() { } void update() { // Updating the local variables of Spike2Rate population %(id)s if(_active){ int pop%(id)s_nb, pop%(id)s_out; %(omp_code)s for(int i = 0; i < size; i++){ // Increase when spiking if (pop%(id_pre)s.last_spike[i] == t-1){ last_spikes[i].push_back(t-1); } pop%(id)s_nb = 0; pop%(id)s_out = -1; for(int j=0; j < last_spikes[i].size(); j++){ if(last_spikes[i][j] >= t -1 - (long int)(window/dt) ){ pop%(id)s_nb++; } else{ pop%(id)s_out = j; } } if (pop%(id)s_out > -1){ last_spikes[i].erase(last_spikes[i].begin()); } r[i] += dt*(1000.0/scaling / window * %(float_prec)s(pop%(id)s_nb) - r[i] ) / smooth; } } } }; """ % {'id' : self.id, 'id_pre': self.population.id, 'omp_code': omp_code, 'size': self.size, 'float_prec': Global.config['precision']} return code