def __init__(self, group, template, code='', user_code=None, dt=None, clock=None, when='start', order=0, name='coderunner*', check_units=True, template_kwds=None, needed_variables=None, override_conditional_write=None, codeobj_class=None, generate_empty_code=True ): BrianObject.__init__(self, clock=clock, dt=dt, when=when, order=order, name=name) self.group = weakproxy_with_fallback(group) self.template = template self.user_code = user_code self.abstract_code = code self.check_units = check_units if needed_variables is None: needed_variables = [] self.needed_variables = needed_variables self.template_kwds = template_kwds self.override_conditional_write = override_conditional_write if codeobj_class is None: codeobj_class = group.codeobj_class self.codeobj_class = codeobj_class self.generate_empty_code = generate_empty_code self.codeobj = None
def _update_magic_objects(self): # check whether we should restart time, continue time, or raise an # error valid_refs = set(r for r in BrianObject.__instances__() if r().invalidates_magic_network) inter = valid_refs.intersection(self._previous_refs) if len(inter) == 0: # reset time self.t = 0 * second elif len(self._previous_refs) == len(valid_refs): # continue time pass else: raise MagicError( "Brian cannot guess what you intend to do here, see docs for MagicNetwork for details" ) self._previous_refs = valid_refs self.objects[:] = [ weakref.proxy(obj()) for obj in BrianObject.__instances__() ] logger.debug("Updated MagicNetwork to include {numobjs} objects " "with names {names}".format( numobjs=len(self.objects), names=', '.join(obj.name for obj in self.objects)))
def __init__(self, source, variables, record=None, when=None, name='statemonitor*', codeobj_class=None): self.source = weakref.proxy(source) self.codeobj_class = codeobj_class # run by default on source clock at the end scheduler = Scheduler(when) if not scheduler.defined_clock: scheduler.clock = source.clock if not scheduler.defined_when: scheduler.when = 'end' BrianObject.__init__(self, when=scheduler, name=name) # variables should always be a list of strings if variables is True: variables = source.equations.names elif isinstance(variables, str): variables = [variables] #: The variables to record self.record_variables = variables # record should always be an array of ints self.record_all = False if record is True: self.record_all = True record = source.item_mapping[:] elif record is None or record is False: record = np.array([], dtype=np.int32) elif isinstance(record, int): record = np.array([source.item_mapping[record]], dtype=np.int32) else: record = np.array(source.item_mapping[record], dtype=np.int32) #: The array of recorded indices self.indices = record # create data structures self.reinit() # Setup variables self.variables = {} for varname in variables: var = source.variables[varname] if not (np.issubdtype(var.dtype, np.float64) and np.issubdtype(np.float64, var.dtype)): raise NotImplementedError(('Cannot record %s with data type ' '%s, currently only values stored as ' 'doubles can be recorded.') % (varname, var.dtype)) self.variables[varname] = var self.variables['_recorded_'+varname] = Variable(Unit(1), self._values[varname]) self.variables['_t'] = Variable(Unit(1), self._t) self.variables['_clock_t'] = AttributeVariable(second, self.clock, 't_') self.variables['_indices'] = ArrayVariable('_indices', Unit(1), self.indices, constant=True) self._group_attribute_access_active = True
def __init__(self, source, variables, record=None, when=None, name='statemonitor*', codeobj_class=None): self.source = weakref.proxy(source) self.codeobj_class = codeobj_class # run by default on source clock at the end scheduler = Scheduler(when) if not scheduler.defined_clock: scheduler.clock = source.clock if not scheduler.defined_when: scheduler.when = 'end' BrianObject.__init__(self, when=scheduler, name=name) # variables should always be a list of strings if variables is True: variables = source.equations.names elif isinstance(variables, str): variables = [variables] #: The variables to record self.record_variables = variables # record should always be an array of ints self.record_all = False if record is True: self.record_all = True record = np.arange(len(source), dtype=np.int32) elif record is None or record is False: record = np.array([], dtype=np.int32) elif isinstance(record, int): record = np.array([record], dtype=np.int32) else: record = np.asarray(record, dtype=np.int32) #: The array of recorded indices self.indices = record # Setup variables self.variables = Variables(self) for varname in variables: var = source.variables[varname] self.variables.add_reference(varname, var, index=source.variables.indices[varname]) self.variables.add_dynamic_array('_recorded_' + varname, size=(0, len(self.indices)), unit=var.unit, dtype=var.dtype, constant=False, constant_size=False, is_bool=var.is_bool) self.variables.add_dynamic_array('_t', size=0, unit=Unit(1), constant=False, constant_size=False) self.variables.add_attribute_variable('_clock_t', second, self.clock, 't_') self.variables.add_array('_indices', size=len(self.indices), unit=Unit(1), dtype=self.indices.dtype, constant=True, read_only=True) self.variables['_indices'].set_value(self.indices) self._group_attribute_access_active = True
def __init__(self, source, when=None, name='ratemonitor*', codeobj_class=None): self.source = weakref.proxy(source) # run by default on source clock at the end scheduler = Scheduler(when) if not scheduler.defined_clock: scheduler.clock = source.clock if not scheduler.defined_when: scheduler.when = 'end' self.codeobj_class = codeobj_class BrianObject.__init__(self, when=scheduler, name=name) # create data structures self.reinit() self.variables = {'t': AttributeVariable(second, self.clock, 't'), 'dt': AttributeVariable(second, self.clock, 'dt', constant=True), '_spikes': AttributeVariable(Unit(1), self.source, 'spikes'), # The template needs to have access to the # DynamicArray here, having access to the underlying # array is not enough since we want to do the resize # in the template '_rate': Variable(Unit(1), self._rate), '_t': Variable(Unit(1), self._t), '_num_source_neurons': Variable(Unit(1), len(self.source))}
def __init__(self, source, when=None, name='ratemonitor*', codeobj_class=None): self.source = weakref.proxy(source) # run by default on source clock at the end scheduler = Scheduler(when) if not scheduler.defined_clock: scheduler.clock = source.clock if not scheduler.defined_when: scheduler.when = 'end' self.codeobj_class = codeobj_class BrianObject.__init__(self, when=scheduler, name=name) # create data structures self.reinit() self.variables = { 't': AttributeVariable(second, self.clock, 't'), 'dt': AttributeVariable(second, self.clock, 'dt', constant=True), '_spikes': AttributeVariable(Unit(1), self.source, 'spikes'), # The template needs to have access to the # DynamicArray here, having access to the underlying # array is not enough since we want to do the resize # in the template '_rate': Variable(Unit(1), self._rate), '_t': Variable(Unit(1), self._t), '_num_source_neurons': Variable(Unit(1), len(self.source)) }
def __init__( self, group, template, code="", user_code=None, dt=None, clock=None, when="start", order=0, name="coderunner*", check_units=True, template_kwds=None, needed_variables=None, override_conditional_write=None, codeobj_class=None, ): BrianObject.__init__(self, clock=clock, dt=dt, when=when, order=order, name=name) self.group = weakref.proxy(group) self.template = template self.user_code = user_code self.abstract_code = code self.check_units = check_units if needed_variables is None: needed_variables = [] self.needed_variables = needed_variables self.template_kwds = template_kwds self.override_conditional_write = override_conditional_write if codeobj_class is None: codeobj_class = group.codeobj_class self.codeobj_class = codeobj_class self.codeobj = None
def __init__(self, group, template, code=None, when=None, name='coderunner*', check_units=True, template_kwds=None): BrianObject.__init__(self, when=when, name=name) self.group = weakref.proxy(group) self.template = template self.abstract_code = code self.check_units = check_units self.template_kwds = template_kwds
def __init__(self, codeobj, init=None, pre=None, post=None, when=None, name=None): BrianObject.__init__(self, when=when, name=name) self.codeobj = codeobj self.pre = pre self.post = post if init is not None: init(self)
def __init__(self, function, dt=None, clock=None, when='start', order=0, name='networkoperation*'): BrianObject.__init__(self, dt=dt, clock=clock, when=when, order=order, name=name) #: The function to be called each time step self.function = function is_method = inspect.ismethod(function) if (hasattr(function, 'func_code') or # Python 2 hasattr(function, '__code__')): # Python 3: argcount = function.__code__.co_argcount if is_method: if argcount == 2: self._has_arg = True elif argcount == 1: self._has_arg = False else: raise TypeError( ('Method "%s" cannot be used as a network ' 'operation, it needs to have either only ' '"self" or "self, t" as arguments, but it ' 'has %d arguments.' % (function.__name__, argcount))) else: if (argcount >= 1 and function.__code__.co_varnames[0] == 'self'): raise TypeError('The first argument of the function "%s" ' 'is "self", suggesting it is an instance ' 'method and not a function. Did you use ' '@network_operation on a class method? ' 'This will not work, explicitly create a ' 'NetworkOperation object instead -- see ' 'the documentation for more ' 'details.' % function.__name__) if argcount == 1: self._has_arg = True elif argcount == 0: self._has_arg = False else: raise TypeError( ('Function "%s" cannot be used as a ' 'network operation, it needs to have ' 'either only "t" as an argument or have ' 'no arguments, but it has %d ' 'arguments.' % (function.__name__, argcount))) else: self._has_arg = False
def __init__(self, function, dt=None, clock=None, when='start', order=0): BrianObject.__init__(self, dt=dt, clock=clock, when=when, order=order, name='networkoperation*') #: The function to be called each time step self.function = function if hasattr(function, 'func_code'): self._has_arg = (self.function.func_code.co_argcount==1) else: self._has_arg = False
def __init__(self, function, when=None): BrianObject.__init__(self, when=when, name='networkoperation*') #: The function to be called each time step self.function = function if hasattr(function, 'func_code'): self._has_arg = (self.function.func_code.co_argcount==1) else: self._has_arg = False
def __init__(self, function, when=None): BrianObject.__init__(self, when=when, name='networkoperation*') #: The function to be called each time step self.function = function if hasattr(function, 'func_code'): self._has_arg = (self.function.func_code.co_argcount == 1) else: self._has_arg = False
def __init__(self, group, template, code='', when=None, name='coderunner*', check_units=True, template_kwds=None, needed_variables=None): BrianObject.__init__(self, when=when, name=name) self.group = weakref.proxy(group) self.template = template self.abstract_code = code self.check_units = check_units if needed_variables is None: needed_variables = [] self.needed_variables = needed_variables self.template_kwds = template_kwds
def __init__(self, function, dt=None, clock=None, when="start", order=0): BrianObject.__init__(self, dt=dt, clock=clock, when=when, order=order, name="networkoperation*") #: The function to be called each time step self.function = function is_method = inspect.ismethod(function) if hasattr(function, "func_code") or hasattr(function, "__code__"): # Python 2 # Python 3: argcount = function.func_code.co_argcount if is_method: if argcount == 2: self._has_arg = True elif argcount == 1: self._has_arg = False else: raise TypeError( ( 'Method "%s" cannot be used as a network ' "operation, it needs to have either only " '"self" or "self, t" as arguments, but it ' "has %d arguments." % (function.__name__, argcount) ) ) else: if argcount >= 1 and function.func_code.co_varnames[0] == "self": raise TypeError( 'The first argument of the function "%s" ' 'is "self", suggesting it is an instance ' "method and not a function. Did you use " "@network_operation on a class method? " "This will not work, explicitly create a " "NetworkOperation object instead -- see " "the documentation for more " "details." % function.__name__ ) if argcount == 1: self._has_arg = True elif argcount == 0: self._has_arg = False else: raise TypeError( ( 'Function "%s" cannot be used as a ' "network operation, it needs to have " 'either only "t" as an argument or have ' "no arguments, but it has %d " "arguments." % (function.__name__, argcount) ) ) else: self._has_arg = False
def __init__(self, N, rates, when=None, name=None): # TODO: sort out the default values in Scheduler scheduler = Scheduler(when) scheduler.when = 'thresholds' BrianObject.__init__(self, when=scheduler, name=name) #: The array of spikes from the most recent time step self.spikes = array([], dtype=int) self.rates = rates self.N = N = int(N) self.pthresh = array(rates*self.clock.dt)
def __init__(self, source, start, end, name=None): self.source = weakref.proxy(source) # We want to update the spikes attribute after it has been updated # by the parent, we do this in slot 'thresholds' with an order # one higher than the parent order to ensure it takes place after the # parent threshold operation schedule = Scheduler(clock=source.clock, when='thresholds', order=source.order+1) BrianObject.__init__(self, when=schedule, name=name) self.spikes = array([], dtype=int) self.N = end-start self.start = start self.end = end
def __init__(self, group, template, code='', when=None, name='coderunner*', check_units=True, template_kwds=None, needed_variables=None, override_conditional_write=None, ): BrianObject.__init__(self, when=when, name=name) self.group = weakref.proxy(group) self.template = template self.abstract_code = code self.check_units = check_units if needed_variables is None: needed_variables = [] self.needed_variables = needed_variables self.template_kwds = template_kwds self.override_conditional_write = override_conditional_write
def __init__(self, source, record=True, when=None, name=None): self.source = weakref.proxy(source) self.record = bool(record) # run by default on source clock at the end scheduler = Scheduler(when) if not scheduler.defined_clock: scheduler.clock = source.clock if not scheduler.defined_when: scheduler.when = 'end' BrianObject.__init__(self, when=scheduler, name=name) # create data structures self.reinit()
def __init__(self, function, dt=None, clock=None, when='start', order=0): BrianObject.__init__(self, dt=dt, clock=clock, when=when, order=order, name='networkoperation*') #: The function to be called each time step self.function = function if hasattr(function, 'func_code'): self._has_arg = (self.function.func_code.co_argcount == 1) else: self._has_arg = False
def __init__(self, function, dt=None, clock=None, when='start', order=0, name='networkoperation*'): BrianObject.__init__(self, dt=dt, clock=clock, when=when, order=order, name=name) #: The function to be called each time step self.function = function is_method = inspect.ismethod(function) if (hasattr(function, 'func_code') or # Python 2 hasattr(function, '__code__')): # Python 3: argcount = function.func_code.co_argcount if is_method: if argcount == 2: self._has_arg = True elif argcount == 1: self._has_arg = False else: raise TypeError(('Method "%s" cannot be used as a network ' 'operation, it needs to have either only ' '"self" or "self, t" as arguments, but it ' 'has %d arguments.' % (function.__name__, argcount))) else: if (argcount >= 1 and function.func_code.co_varnames[0] == 'self'): raise TypeError('The first argument of the function "%s" ' 'is "self", suggesting it is an instance ' 'method and not a function. Did you use ' '@network_operation on a class method? ' 'This will not work, explicitly create a ' 'NetworkOperation object instead -- see ' 'the documentation for more ' 'details.' % function.__name__) if argcount == 1: self._has_arg = True elif argcount == 0: self._has_arg = False else: raise TypeError(('Function "%s" cannot be used as a ' 'network operation, it needs to have ' 'either only "t" as an argument or have ' 'no arguments, but it has %d ' 'arguments.' % (function.__name__, argcount))) else: self._has_arg = False
def __init__(self, N, rates, when=None, name='poissongroup*'): # TODO: sort out the default values in Scheduler scheduler = Scheduler(when) scheduler.when = 'thresholds' BrianObject.__init__(self, when=scheduler, name=name) #: The array of spikes from the most recent time step self.spikes = np.array([], dtype=int) self._rates = np.asarray(rates) self.N = N = int(N) self.pthresh = self._calc_threshold() self.variables = {'rates': ArrayVariable('rates', Hz, self._rates, group_name=self.name, constant=True)} Group.__init__(self)
def _update_magic_objects(self): # check whether we should restart time, continue time, or raise an # error valid_refs = set(r for r in BrianObject.__instances__() if r().invalidates_magic_network) inter = valid_refs.intersection(self._previous_refs) if len(inter)==0: # reset time self.t = 0*second elif len(self._previous_refs)==len(valid_refs): # continue time pass else: raise MagicError("Brian cannot guess what you intend to do here, see docs for MagicNetwork for details") self._previous_refs = valid_refs self.objects[:] = [weakref.proxy(obj()) for obj in BrianObject.__instances__()] logger.debug("Updated MagicNetwork to include {numobjs} objects " "with names {names}".format( numobjs=len(self.objects), names=', '.join(obj.name for obj in self.objects)))
def __init__(self, function, dt=None, clock=None, when='start', order=0, name='networkoperation*'): BrianObject.__init__(self, dt=dt, clock=clock, when=when, order=order, name=name) #: The function to be called each time step self.function = function is_method = inspect.ismethod(function) if hasattr(function, '__code__'): argcount = function.__code__.co_argcount if is_method: if argcount == 2: self._has_arg = True elif argcount == 1: self._has_arg = False else: raise TypeError(f"Method '{function.__name__}' cannot be used as a " f"network operation, it needs to have either " f"only 'self' or 'self, t' as arguments, but it " f"has {argcount} arguments.") else: if argcount >= 1 and function.__code__.co_varnames[0] == 'self': raise TypeError("The first argument of the function " "'{function.__name__}' is 'self', suggesting it " "is an instance method and not a function. Did " "you use @network_operation on a class method? " "This will not work, explicitly create a " "NetworkOperation object instead -- see " "the documentation for more " "details.") if argcount == 1: self._has_arg = True elif argcount == 0: self._has_arg = False else: raise TypeError(f"Function '{function.__name__}' cannot be used as " f"a network operation, it needs to have either " f"only 't' as an argument or have no arguments, " f"but it has {argcount} arguments.") else: self._has_arg = False
def __init__(self, source, start, end, name=None): self.source = weakref.proxy(source) if name is None: name = source.name + '_subgroup*' # We want to update the spikes attribute after it has been updated # by the parent, we do this in slot 'thresholds' with an order # one higher than the parent order to ensure it takes place after the # parent threshold operation schedule = Scheduler(clock=source.clock, when='thresholds', order=source.order+1) BrianObject.__init__(self, when=schedule, name=name) self.N = end-start self.start = start self.end = end self.offset = start self.variables = self.source.variables self.variable_indices = self.source.variable_indices self.namespace = self.source.namespace self.codeobj_class = self.source.codeobj_class Group.__init__(self)
def __init__(self, source, when=None, name='ratemonitor*', codeobj_class=None): # run by default on source clock at the end scheduler = Scheduler(when) if not scheduler.defined_clock: scheduler.clock = source.clock if not scheduler.defined_when: scheduler.when = 'end' self.codeobj_class = codeobj_class BrianObject.__init__(self, when=scheduler, name=name) self.variables = Variables(self) self.variables.add_clock_variables(self.clock) self.variables.add_dynamic_array('_rate', size=0, unit=hertz, constant_size=False) self.variables.add_dynamic_array('_t', size=0, unit=second, constant_size=False) self.variables.add_constant('_num_source_neurons', unit=Unit(1), value=len(source)) GroupCodeRunner.__init__(self, source, 'ratemonitor', when=scheduler)
def __init__(self, source, start, end, name=None): self.source = weakref.proxy(source) if name is None: name = source.name + '_subgroup*' # We want to update the spikes attribute after it has been updated # by the parent, we do this in slot 'thresholds' with an order # one higher than the parent order to ensure it takes place after the # parent threshold operation schedule = Scheduler(clock=source.clock, when='thresholds', order=source.order + 1) BrianObject.__init__(self, when=schedule, name=name) self.N = end - start self.start = start self.end = end self.offset = start self.variables = self.source.variables self.variable_indices = self.source.variable_indices self.namespace = self.source.namespace self.codeobj_class = self.source.codeobj_class Group.__init__(self)
def __init__(self, N, rates, when=None, name='poissongroup*'): # TODO: sort out the default values in Scheduler scheduler = Scheduler(when) scheduler.when = 'thresholds' BrianObject.__init__(self, when=scheduler, name=name) #: The array of spikes from the most recent time step self.spikes = np.array([], dtype=int) self._rates = np.asarray(rates) self.N = N = int(N) self.pthresh = self._calc_threshold() self.variables = { 'rates': ArrayVariable('rates', Hz, self._rates, group_name=self.name, constant=True) } Group.__init__(self)
def __init__(self, source, record=True, when=None, name='spikemonitor*', codeobj_class=None): self.source = weakref.proxy(source) self.record = bool(record) # run by default on source clock at the end scheduler = Scheduler(when) if not scheduler.defined_clock: scheduler.clock = source.clock if not scheduler.defined_when: scheduler.when = 'end' self.codeobj_class = codeobj_class BrianObject.__init__(self, when=scheduler, name=name) # create data structures self.reinit() # Handle subgroups correctly start = getattr(self.source, 'start', 0) end = getattr(self.source, 'end', len(self.source)) self.variables = {'t': AttributeVariable(second, self.clock, 't'), '_spikes': AttributeVariable(Unit(1), self.source, 'spikes'), # The template needs to have access to the # DynamicArray here, having access to the underlying # array is not enough since we want to do the resize # in the template '_i': Variable(Unit(1), self._i), '_t': Variable(Unit(1), self._t), '_count': ArrayVariable('_count', Unit(1), self.count), '_source_start': Variable(Unit(1), start, constant=True), '_source_end': Variable(Unit(1), end, constant=True)}
def __init__(self, source, variables, record=None, when=None, name=None): self.source = weakref.proxy(source) # run by default on source clock at the end scheduler = Scheduler(when) if not scheduler.defined_clock: scheduler.clock = source.clock if not scheduler.defined_when: scheduler.when = 'end' BrianObject.__init__(self, when=scheduler, name=name) # variables should always be a list of strings if variables is True: variables = source.units.keys() elif isinstance(variables, str): variables = [variables] self.variables = variables # record should always be an array of ints if record is None or record is False: record = array([], dtype=int) elif record is True: record = arange(len(source)) else: record = array(record, dtype=int) #: The array of recorded indices self.indices = record # create data structures self.reinit() # initialise Group access self.units = dict((var, source.units[var]) for var in variables) self.arrays = {} Group.__init__(self)
def __init__(self, source, target=None, model=None, pre=None, post=None, connect=False, delay=None, namespace=None, dtype=None, codeobj_class=None, clock=None, method=None, name='synapses*'): BrianObject.__init__(self, when=clock, name=name) self.codeobj_class = codeobj_class self.source = weakref.proxy(source) if target is None: self.target = self.source else: self.target = weakref.proxy(target) ##### Prepare and validate equations if model is None: model = '' if isinstance(model, basestring): model = Equations(model) if not isinstance(model, Equations): raise TypeError(('model has to be a string or an Equations ' 'object, is "%s" instead.') % type(model)) # Check flags model.check_flags({DIFFERENTIAL_EQUATION: ['event-driven', 'lumped'], STATIC_EQUATION: ['lumped'], PARAMETER: ['constant', 'lumped']}) # Separate the equations into event-driven and continuously updated # equations event_driven = [] continuous = [] for single_equation in model.itervalues(): if 'event-driven' in single_equation.flags: if 'lumped' in single_equation.flags: raise ValueError(('Event-driven variable %s cannot be ' 'a lumped variable.') % single_equation.varname) event_driven.append(single_equation) else: continuous.append(single_equation) # Add the lastupdate variable, used by event-driven equations continuous.append(SingleEquation(PARAMETER, 'lastupdate', second)) if len(event_driven): self.event_driven = Equations(event_driven) else: self.event_driven = None self.equations = Equations(continuous) ##### Setup the memory self.arrays = self._allocate_memory(dtype=dtype) # Setup the namespace self._given_namespace = namespace self.namespace = create_namespace(namespace) self._queues = {} self._delays = {} self.item_mapping = SynapticItemMapping(self) self.indices = {'_idx': self.item_mapping, '_presynaptic_idx': self.item_mapping.synaptic_pre, '_postsynaptic_idx': self.item_mapping.synaptic_post} # Allow S.i instead of S.indices.i, etc. self.i = self.item_mapping.i self.j = self.item_mapping.j self.k = self.item_mapping.k # Setup variables self.variables = self._create_variables() #: List of names of all updaters, e.g. ['pre', 'post'] self._updaters = [] for prepost, argument in zip(('pre', 'post'), (pre, post)): if not argument: continue if isinstance(argument, basestring): self._add_updater(argument, prepost) elif isinstance(argument, collections.Mapping): for key, value in argument.iteritems(): if not isinstance(key, basestring): err_msg = ('Keys for the "{}" argument' 'have to be strings, got ' '{} instead.').format(prepost, type(key)) raise TypeError(err_msg) self._add_updater(value, prepost, objname=key) # If we have a pathway called "pre" (the most common use case), provide # direct access to its delay via a delay attribute (instead of having # to use pre.delay) if 'pre' in self._updaters: self.variables['delay'] = self.pre.variables['delay'] if delay is not None: if isinstance(delay, Quantity): if not 'pre' in self._updaters: raise ValueError(('Cannot set delay, no "pre" pathway exists.' 'Use a dictionary if you want to set the ' 'delay for a pathway with a different name.')) delay = {'pre': delay} if not isinstance(delay, collections.Mapping): raise TypeError('Delay argument has to be a quantity or a ' 'dictionary, is type %s instead.' % type(delay)) for pathway, pathway_delay in delay.iteritems(): if not pathway in self._updaters: raise ValueError(('Cannot set the delay for pathway ' '"%s": unknown pathway.') % pathway) if not isinstance(pathway_delay, Quantity): raise TypeError(('Cannot set the delay for pathway "%s": ' 'expected a quantity, got %s instead.') % (pathway, type(pathway_delay))) if pathway_delay.size != 1: raise TypeError(('Cannot set the delay for pathway "%s": ' 'expected a scalar quantity, got a ' 'quantity with shape %s instead.') % str(pathway_delay.shape)) fail_for_dimension_mismatch(pathway_delay, second, ('Delay has to be ' 'specified in units ' 'of seconds')) updater = getattr(self, pathway) self.item_mapping.unregister_variable(updater._delays) del updater._delays # For simplicity, store the delay as a one-element array # so that for example updater._delays[:] works. updater._delays = np.array([float(pathway_delay)]) variable = ArrayVariable('delay', second, updater._delays, group_name=self.name, scalar=True) updater.variables['delay'] = variable if pathway == 'pre': self.variables['delay'] = variable #: Performs numerical integration step self.state_updater = StateUpdater(self, method) self.contained_objects.append(self.state_updater) #: "Lumped variable" mechanism -- sum over all synapses of a #: postsynaptic target self.lumped_updaters = {} for single_equation in self.equations.itervalues(): if 'lumped' in single_equation.flags: varname = single_equation.varname # For a lumped variable, we need an equivalent parameter in the # target group if not varname in self.target.variables: raise ValueError(('The lumped variable %s needs a variable ' 'of the same name in the target ' 'group ') % single_equation.varname) fail_for_dimension_mismatch(self.variables[varname].unit, self.target.variables[varname], ('Lumped variables need to have ' 'the same units in Synapses ' 'and the target group')) # TODO: Add some more stringent check about the type of # variable in the target group updater = LumpedUpdater(varname, self, self.target) self.lumped_updaters[varname] = updater self.contained_objects.append(updater) # Do an initial connect, if requested if not isinstance(connect, (bool, basestring)): raise TypeError(('"connect" keyword has to be a boolean value or a ' 'string, is type %s instead.' % type(connect))) self._initial_connect = connect if not connect is False: self.connect(connect, level=1) # Activate name attribute access Group.__init__(self)
def __init__(self, N, equations, method=euler, threshold=None, reset=None, dtype=None, language=None, clock=None, name=None, level=0): BrianObject.__init__(self, when=clock, name=name) ##### VALIDATE ARGUMENTS AND STORE ATTRIBUTES self.method = method self.level = level = int(level) try: self.N = N = int(N) except ValueError: if isinstance(N, str): raise TypeError("First NeuronGroup argument should be size, not equations.") raise if N<1: raise ValueError("NeuronGroup size should be at least 1, was "+str(N)) # Validate equations if isinstance(equations, basestring): equations = Equations(equations, level=level+1) if not isinstance(equations, Equations): raise ValueError(('equations has to be a string or an Equations ' 'object, is "%s" instead.') % type(equations)) # add refractoriness equations = add_refractoriness(equations) self.equations = equations logger.debug("Creating NeuronGroup of size {self.N}, " "equations {self.equations}.".format(self=self)) # Check flags equations.check_flags({DIFFERENTIAL_EQUATION: ('active'), PARAMETER: ('constant')}) # Set dtypes and units self.prepare_dtypes(dtype=dtype) self.units = dict((var, equations.units[var]) for var in equations.equations.keys()) # Allocate memory (TODO: this should be refactored somewhere at some point) self.allocate_memory() #: The array of spikes from the most recent threshold operation self.spikes = array([], dtype=int) # Set these for documentation purposes #: Performs numerical integration step self.state_updater = None #: Performs thresholding step, sets the value of `spikes` self.thresholder = None #: Resets neurons which have spiked (`spikes`) self.resetter = None # Code generation (TODO: this should be refactored and modularised) # Temporary, set default language to Python if language is None: language = PythonLanguage() self.language = language self.create_state_updater() self.create_thresholder(threshold, level=level+1) self.create_resetter(reset, level=level+1) # Creation of contained_objects that do the work self.contained_objects.append(self.state_updater) if self.thresholder is not None: self.contained_objects.append(self.thresholder) if self.resetter is not None: self.contained_objects.append(self.resetter) # Activate name attribute access Group.__init__(self)
def __init__(self, N, model, method=None, threshold=None, reset=None, refractory=False, namespace=None, dtype=None, clock=None, name='neurongroup*', codeobj_class=None): BrianObject.__init__(self, when=clock, name=name) self.codeobj_class = codeobj_class try: self.N = N = int(N) except ValueError: if isinstance(N, str): raise TypeError( "First NeuronGroup argument should be size, not equations." ) raise if N < 1: raise ValueError("NeuronGroup size should be at least 1, was " + str(N)) ##### Prepare and validate equations if isinstance(model, basestring): model = Equations(model) if not isinstance(model, Equations): raise TypeError(('model has to be a string or an Equations ' 'object, is "%s" instead.') % type(model)) # Check flags model.check_flags({ DIFFERENTIAL_EQUATION: ('unless-refractory'), PARAMETER: ('constant') }) # add refractoriness model = add_refractoriness(model) self.equations = model uses_refractoriness = len(model) and any([ 'unless-refractory' in eq.flags for eq in model.itervalues() if eq.type == DIFFERENTIAL_EQUATION ]) logger.debug("Creating NeuronGroup of size {self.N}, " "equations {self.equations}.".format(self=self)) ##### Setup the memory self.arrays = self._allocate_memory(dtype=dtype) self._spikespace = np.zeros(N + 1, dtype=np.int32) # Setup the namespace self.namespace = create_namespace(namespace) # Setup variables self.variables = self._create_variables() # All of the following will be created in pre_run #: The threshold condition self.threshold = threshold #: The reset statement(s) self.reset = reset #: The refractory condition or timespan self._refractory = refractory if uses_refractoriness and refractory is False: logger.warn( 'Model equations use the "unless-refractory" flag but ' 'no refractory keyword was given.', 'no_refractory') #: The state update method selected by the user self.method_choice = method #: Performs thresholding step, sets the value of `spikes` self.thresholder = None if self.threshold is not None: self.thresholder = Thresholder(self) #: Resets neurons which have spiked (`spikes`) self.resetter = None if self.reset is not None: self.resetter = Resetter(self) # We try to run a pre_run already now. This might fail because of an # incomplete namespace but if the namespace is already complete we # can spot unit or syntax errors already here, at creation time. try: self.pre_run(None) except KeyError: pass #: Performs numerical integration step self.state_updater = StateUpdater(self, method) # Creation of contained_objects that do the work self.contained_objects.append(self.state_updater) if self.thresholder is not None: self.contained_objects.append(self.thresholder) if self.resetter is not None: self.contained_objects.append(self.resetter) # Activate name attribute access Group.__init__(self) # Set the refractoriness information self.lastspike = -np.inf * second self.not_refractory = True
def __init__(self, source, target=None, model=None, pre=None, post=None, connect=False, delay=None, namespace=None, dtype=None, codeobj_class=None, clock=None, method=None, name='synapses*'): BrianObject.__init__(self, when=clock, name=name) self.codeobj_class = codeobj_class self.source = weakref.proxy(source) if target is None: self.target = self.source else: self.target = weakref.proxy(target) ##### Prepare and validate equations if model is None: model = '' if isinstance(model, basestring): model = Equations(model) if not isinstance(model, Equations): raise TypeError(('model has to be a string or an Equations ' 'object, is "%s" instead.') % type(model)) # Check flags model.check_flags({ DIFFERENTIAL_EQUATION: ['event-driven', 'lumped'], STATIC_EQUATION: ['lumped'], PARAMETER: ['constant', 'lumped'] }) # Separate the equations into event-driven and continuously updated # equations event_driven = [] continuous = [] for single_equation in model.itervalues(): if 'event-driven' in single_equation.flags: if 'lumped' in single_equation.flags: raise ValueError( ('Event-driven variable %s cannot be ' 'a lumped variable.') % single_equation.varname) event_driven.append(single_equation) else: continuous.append(single_equation) # Add the lastupdate variable, used by event-driven equations continuous.append(SingleEquation(PARAMETER, 'lastupdate', second)) if len(event_driven): self.event_driven = Equations(event_driven) else: self.event_driven = None self.equations = Equations(continuous) ##### Setup the memory self.arrays = self._allocate_memory(dtype=dtype) # Setup the namespace self._given_namespace = namespace self.namespace = create_namespace(namespace) self._queues = {} self._delays = {} self.item_mapping = SynapticItemMapping(self) self.indices = { '_idx': self.item_mapping, '_presynaptic_idx': self.item_mapping.synaptic_pre, '_postsynaptic_idx': self.item_mapping.synaptic_post } # Allow S.i instead of S.indices.i, etc. self.i = self.item_mapping.i self.j = self.item_mapping.j self.k = self.item_mapping.k # Setup variables self.variables = self._create_variables() #: List of names of all updaters, e.g. ['pre', 'post'] self._updaters = [] for prepost, argument in zip(('pre', 'post'), (pre, post)): if not argument: continue if isinstance(argument, basestring): self._add_updater(argument, prepost) elif isinstance(argument, collections.Mapping): for key, value in argument.iteritems(): if not isinstance(key, basestring): err_msg = ('Keys for the "{}" argument' 'have to be strings, got ' '{} instead.').format(prepost, type(key)) raise TypeError(err_msg) self._add_updater(value, prepost, objname=key) # If we have a pathway called "pre" (the most common use case), provide # direct access to its delay via a delay attribute (instead of having # to use pre.delay) if 'pre' in self._updaters: self.variables['delay'] = self.pre.variables['delay'] if delay is not None: if isinstance(delay, Quantity): if not 'pre' in self._updaters: raise ValueError( ('Cannot set delay, no "pre" pathway exists.' 'Use a dictionary if you want to set the ' 'delay for a pathway with a different name.')) delay = {'pre': delay} if not isinstance(delay, collections.Mapping): raise TypeError('Delay argument has to be a quantity or a ' 'dictionary, is type %s instead.' % type(delay)) for pathway, pathway_delay in delay.iteritems(): if not pathway in self._updaters: raise ValueError(('Cannot set the delay for pathway ' '"%s": unknown pathway.') % pathway) if not isinstance(pathway_delay, Quantity): raise TypeError(('Cannot set the delay for pathway "%s": ' 'expected a quantity, got %s instead.') % (pathway, type(pathway_delay))) if pathway_delay.size != 1: raise TypeError(('Cannot set the delay for pathway "%s": ' 'expected a scalar quantity, got a ' 'quantity with shape %s instead.') % str(pathway_delay.shape)) fail_for_dimension_mismatch(pathway_delay, second, ('Delay has to be ' 'specified in units ' 'of seconds')) updater = getattr(self, pathway) self.item_mapping.unregister_variable(updater._delays) del updater._delays # For simplicity, store the delay as a one-element array # so that for example updater._delays[:] works. updater._delays = np.array([float(pathway_delay)]) variable = ArrayVariable('delay', second, updater._delays, group_name=self.name, scalar=True) updater.variables['delay'] = variable if pathway == 'pre': self.variables['delay'] = variable #: Performs numerical integration step self.state_updater = StateUpdater(self, method) self.contained_objects.append(self.state_updater) #: "Lumped variable" mechanism -- sum over all synapses of a #: postsynaptic target self.lumped_updaters = {} for single_equation in self.equations.itervalues(): if 'lumped' in single_equation.flags: varname = single_equation.varname # For a lumped variable, we need an equivalent parameter in the # target group if not varname in self.target.variables: raise ValueError( ('The lumped variable %s needs a variable ' 'of the same name in the target ' 'group ') % single_equation.varname) fail_for_dimension_mismatch(self.variables[varname].unit, self.target.variables[varname], ('Lumped variables need to have ' 'the same units in Synapses ' 'and the target group')) # TODO: Add some more stringent check about the type of # variable in the target group updater = LumpedUpdater(varname, self, self.target) self.lumped_updaters[varname] = updater self.contained_objects.append(updater) # Do an initial connect, if requested if not isinstance(connect, (bool, basestring)): raise TypeError( ('"connect" keyword has to be a boolean value or a ' 'string, is type %s instead.' % type(connect))) self._initial_connect = connect if not connect is False: self.connect(connect, level=1) # Activate name attribute access Group.__init__(self)
def __init__(self, N, model, method=None, threshold=None, reset=None, refractory=False, namespace=None, dtype=None, clock=None, name='neurongroup*', codeobj_class=None): BrianObject.__init__(self, when=clock, name=name) self.codeobj_class = codeobj_class try: self.N = N = int(N) except ValueError: if isinstance(N, str): raise TypeError("First NeuronGroup argument should be size, not equations.") raise if N < 1: raise ValueError("NeuronGroup size should be at least 1, was " + str(N)) ##### Prepare and validate equations if isinstance(model, basestring): model = Equations(model) if not isinstance(model, Equations): raise TypeError(('model has to be a string or an Equations ' 'object, is "%s" instead.') % type(model)) # Check flags model.check_flags({DIFFERENTIAL_EQUATION: ('unless-refractory'), PARAMETER: ('constant')}) # add refractoriness model = add_refractoriness(model) self.equations = model uses_refractoriness = len(model) and any(['unless-refractory' in eq.flags for eq in model.itervalues() if eq.type == DIFFERENTIAL_EQUATION]) logger.debug("Creating NeuronGroup of size {self.N}, " "equations {self.equations}.".format(self=self)) ##### Setup the memory self.arrays = self._allocate_memory(dtype=dtype) self._spikespace = np.zeros(N+1, dtype=np.int32) # Setup the namespace self.namespace = create_namespace(namespace) # Setup variables self.variables = self._create_variables() # All of the following will be created in pre_run #: The threshold condition self.threshold = threshold #: The reset statement(s) self.reset = reset #: The refractory condition or timespan self._refractory = refractory if uses_refractoriness and refractory is False: logger.warn('Model equations use the "unless-refractory" flag but ' 'no refractory keyword was given.', 'no_refractory') #: The state update method selected by the user self.method_choice = method #: Performs thresholding step, sets the value of `spikes` self.thresholder = None if self.threshold is not None: self.thresholder = Thresholder(self) #: Resets neurons which have spiked (`spikes`) self.resetter = None if self.reset is not None: self.resetter = Resetter(self) # We try to run a pre_run already now. This might fail because of an # incomplete namespace but if the namespace is already complete we # can spot unit or syntax errors already here, at creation time. try: self.pre_run(None) except KeyError: pass #: Performs numerical integration step self.state_updater = StateUpdater(self, method) # Creation of contained_objects that do the work self.contained_objects.append(self.state_updater) if self.thresholder is not None: self.contained_objects.append(self.thresholder) if self.resetter is not None: self.contained_objects.append(self.resetter) # Activate name attribute access Group.__init__(self) # Set the refractoriness information self.lastspike = -np.inf*second self.not_refractory = True