Ejemplo n.º 1
0
    def __init__(self, source, name='ratemonitor*', codeobj_class=None,
                 dtype=np.float64):

        #: The group we are recording from
        self.source = source

        self.codeobj_class = codeobj_class
        CodeRunner.__init__(self, group=self, code='', template='ratemonitor',
                            clock=source.clock, when='end', order=0, name=name)

        self.add_dependency(source)

        self.variables = Variables(self)
        # Handle subgroups correctly
        start = getattr(source, 'start', 0)
        stop = getattr(source, 'stop', len(source))
        self.variables.add_constant('_source_start', start)
        self.variables.add_constant('_source_stop', stop)
        self.variables.add_reference('_spikespace', source)
        self.variables.add_dynamic_array('rate', size=0, dimensions=hertz.dim,
                                         read_only=True, dtype=dtype)
        self.variables.add_dynamic_array('t', size=0, dimensions=second.dim,
                                         read_only=True,
                                         dtype=self._clock.variables['t'].dtype)
        self.variables.add_reference('_num_source_neurons', source, 'N')
        self.variables.add_array('N', dtype=np.int32, size=1,
                                 scalar=True, read_only=True)
        self.variables.create_clock_variables(self._clock,
                                              prefix='_clock_')
        self._enable_group_attributes()
Ejemplo n.º 2
0
 def __init__(self, dt, name='clock*'):
     # We need a name right away because some devices (e.g. cpp_standalone)
     # need a name for the object when creating the variables
     Nameable.__init__(self, name=name)
     #: Note that right after a change of dt, this
     #: will not equal the new dt (which is stored in `Clock._new_dt`). Call
     #: `Clock._set_t_update_t` to update the internal clock representation.
     self._new_dt = None
     self.variables = Variables(self)
     self.variables.add_array('timestep',
                              unit=Unit(1),
                              size=1,
                              dtype=np.uint64,
                              read_only=True,
                              scalar=True)
     self.variables.add_array('t',
                              unit=second,
                              size=1,
                              dtype=np.double,
                              read_only=True,
                              scalar=True)
     self.variables.add_array('dt',
                              unit=second,
                              size=1,
                              values=float(dt),
                              dtype=np.float,
                              read_only=True,
                              constant=True,
                              scalar=True)
     self.variables.add_constant('N', unit=Unit(1), value=1)
     self._enable_group_attributes()
     self.dt = dt
     logger.diagnostic("Created clock {name} with dt={dt}".format(
         name=self.name, dt=self.dt))
Ejemplo n.º 3
0
    def __getitem__(self, item):
        if isinstance(item, basestring):
            variables = Variables(None)
            variables.add_auxiliary_variable('_indices',
                                             unit=Unit(1),
                                             dtype=np.int32)
            variables.add_auxiliary_variable('_cond',
                                             unit=Unit(1),
                                             dtype=np.bool)

            abstract_code = '_cond = ' + item
            check_code_units(abstract_code,
                             self.group,
                             additional_variables=variables,
                             level=1)
            from brian2.devices.device import get_default_codeobject_class
            codeobj = create_runner_codeobj(
                self.group,
                abstract_code,
                'group_get_indices',
                additional_variables=variables,
                level=1,
                codeobj_class=get_default_codeobject_class(
                    'codegen.string_expression_target'))
            return codeobj()
        else:
            return self.indices(item)
Ejemplo n.º 4
0
 def __init__(self, dt, name='clock*'):
     # We need a name right away because some devices (e.g. cpp_standalone)
     # need a name for the object when creating the variables
     Nameable.__init__(self, name=name)
     self._old_dt = None
     self.variables = Variables(self)
     self.variables.add_array('timestep',
                              size=1,
                              dtype=np.int64,
                              read_only=True,
                              scalar=True)
     self.variables.add_array('t',
                              dimensions=second.dim,
                              size=1,
                              dtype=np.double,
                              read_only=True,
                              scalar=True)
     self.variables.add_array('dt',
                              dimensions=second.dim,
                              size=1,
                              values=float(dt),
                              dtype=np.float,
                              read_only=True,
                              constant=True,
                              scalar=True)
     self.variables.add_constant('N', value=1)
     self._enable_group_attributes()
     self.dt = dt
     logger.diagnostic("Created clock {name} with dt={dt}".format(
         name=self.name, dt=self.dt))
Ejemplo n.º 5
0
 def __init__(self, group, when='thresholds', event='spike'):
     self.event = event
     if group._refractory is False or event != 'spike':
         template_kwds = {'_uses_refractory': False}
         needed_variables = []
     else:
         template_kwds = {'_uses_refractory': True}
         needed_variables = ['t', 'not_refractory', 'lastspike']
     # Since this now works for general events not only spikes, we have to
     # pass the information about which variable to use to the template,
     # it can not longer simply refer to "_spikespace"
     eventspace_name = '_{}space'.format(event)
     template_kwds['eventspace_variable'] = group.variables[eventspace_name]
     needed_variables.append(eventspace_name)
     self.variables = Variables(self)
     self.variables.add_auxiliary_variable('_cond', dtype=np.bool)
     CodeRunner.__init__(
         self,
         group,
         'threshold',
         code='',  # will be set in update_abstract_code
         clock=group.clock,
         when=when,
         order=group.order,
         name=group.name + '_thresholder*',
         needed_variables=needed_variables,
         template_kwds=template_kwds)
Ejemplo n.º 6
0
    def __init__(self,
                 N,
                 rates,
                 dt=None,
                 clock=None,
                 when='thresholds',
                 order=0,
                 namespace=None,
                 name='poissongroup*',
                 codeobj_class=None):

        Group.__init__(self,
                       dt=dt,
                       clock=clock,
                       when=when,
                       order=order,
                       namespace=namespace,
                       name=name)

        self.codeobj_class = codeobj_class

        self._N = N = int(N)

        # TODO: In principle, it would be nice to support Poisson groups with
        # refactoriness, but we can't currently, since the refractoriness
        # information is reset in the state updater which we are not using
        # We could either use a specific template or simply not bother and make
        # users write their own NeuronGroup (with threshold rand() < rates*dt)
        # for more complex use cases.

        self.variables = Variables(self)
        # standard variables
        self.variables.add_constant('N', value=self._N)
        self.variables.add_arange('i', self._N, constant=True, read_only=True)
        self.variables.add_array('_spikespace', size=N + 1, dtype=np.int32)
        self.variables.create_clock_variables(self._clock)

        # The firing rates
        if isinstance(rates, str):
            self.variables.add_subexpression('rates',
                                             dimensions=Hz.dim,
                                             expr=rates)
        else:
            self.variables.add_array('rates', size=N, dimensions=Hz.dim)
        self._rates = rates

        self.start = 0
        self.stop = N

        self._refractory = False

        self.events = {'spike': 'rand() < rates * dt'}
        self.thresholder = {'spike': Thresholder(self)}
        self.contained_objects.append(self.thresholder['spike'])

        self._enable_group_attributes()

        if not isinstance(rates, str):
            self.rates = rates
Ejemplo n.º 7
0
    def __init__(self,
                 N,
                 indices,
                 times,
                 when=None,
                 name='spikegeneratorgroup*',
                 codeobj_class=None):
        if when is None:
            when = Scheduler(when='thresholds')
        Group.__init__(self, when=when, name=name)

        self.codeobj_class = codeobj_class

        if N < 1 or int(N) != N:
            raise ValueError('N has to be an integer >=1.')

        if len(indices) != len(times):
            raise ValueError(
                ('Length of the indices and times array must '
                 'match, but %d != %d') % (len(indices), len(times)))

        self.start = 0
        self.stop = N

        # sort times and indices first by time, then by indices
        rec = np.rec.fromarrays([times, indices], names=['t', 'i'])
        rec.sort()
        times = np.ascontiguousarray(rec.t)
        indices = np.ascontiguousarray(rec.i)

        self.variables = Variables(self)

        # standard variables
        self.variables.add_clock_variables(self.clock)
        self.variables.add_constant('N', unit=Unit(1), value=N)
        self.variables.add_arange('i', N)
        self.variables.add_arange('spike_number', len(indices))
        self.variables.add_array('neuron_index',
                                 values=indices,
                                 size=len(indices),
                                 unit=Unit(1),
                                 dtype=np.int32,
                                 index='spike_number',
                                 read_only=True)
        self.variables.add_array('spike_time',
                                 values=times,
                                 size=len(times),
                                 unit=second,
                                 index='spike_number',
                                 read_only=True)
        self.variables.add_array('_spikespace',
                                 size=N + 1,
                                 unit=Unit(1),
                                 dtype=np.int32)
        # Activate name attribute access
        self._enable_group_attributes()

        CodeRunner.__init__(self, self, 'spikegenerator', when=when, name=None)
Ejemplo n.º 8
0
    def __init__(self,
                 N,
                 rates,
                 dt=None,
                 clock=None,
                 when='thresholds',
                 order=0,
                 name='poissongroup*',
                 codeobj_class=None):

        Group.__init__(self,
                       dt=dt,
                       clock=clock,
                       when=when,
                       order=order,
                       name=name)

        self.codeobj_class = codeobj_class

        self._N = N = int(N)

        # TODO: In principle, it would be nice to support Poisson groups with
        # refactoriness, but we can't currently, since the refractoriness
        # information is reset in the state updater which we are not using
        # We could either use a specific template or simply not bother and make
        # users write their own NeuronGroup (with threshold rand() < rates*dt)
        # for more complex use cases.

        self.variables = Variables(self)
        # standard variables
        self.variables.add_constant('N', unit=Unit(1), value=self._N)
        self.variables.add_arange('i', self._N, constant=True, read_only=True)
        self.variables.add_array('_spikespace',
                                 size=N + 1,
                                 unit=Unit(1),
                                 dtype=np.int32)
        self.variables.create_clock_variables(self._clock)

        # The firing rates
        self.variables.add_array('rates', size=N, unit=Hz)

        self.start = 0
        self.stop = N

        self._refractory = False

        # To avoid a warning about the local variable rates, we set the real
        # threshold condition only after creating the object
        self.events = {'spike': 'False'}
        self.thresholder = {'spike': Thresholder(self)}
        self.events = {'spike': 'rand() < rates * dt'}
        self.contained_objects.append(self.thresholder['spike'])

        self._enable_group_attributes()

        # Here we want to use the local namespace, but at the level where the
        # constructor was called
        self.rates.set_item(slice(None), rates, level=2)
Ejemplo n.º 9
0
    def __init__(self, source, start, stop, name=None):
        # First check if the source is itself a Subgroup
        # If so, then make this a Subgroup of the original Group
        if isinstance(source, Subgroup):
            source = source.source
            start = start + source.start
            stop = stop + source.start
            self.source = source
        else:
            self.source = weakproxy_with_fallback(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)
        Group.__init__(self, when=schedule, name=name)
        self._N = stop - start
        self.start = start
        self.stop = stop

        # All the variables have to go via the _sub_idx to refer to the
        # appropriate values in the source group
        self.variables = Variables(self, default_index='_sub_idx')

        # overwrite the meaning of N and i
        self.variables.add_constant('_offset', unit=Unit(1), value=self.start)
        self.variables.add_reference('_source_i', source, 'i')
        self.variables.add_subexpression('i',
                                         unit=Unit(1),
                                         dtype=source.variables['i'].dtype,
                                         expr='_source_i - _offset')
        self.variables.add_constant('N', unit=Unit(1), value=self._N)
        # add references for all variables in the original group
        self.variables.add_references(source, source.variables.keys())

        # Only the variable _sub_idx itself is stored in the subgroup
        # and needs the normal index for this group
        self.variables.add_arange('_sub_idx',
                                  size=self._N,
                                  start=self.start,
                                  index='_idx')

        for key, value in self.source.variables.indices.iteritems():
            if value not in ('_idx', '0'):
                raise ValueError(
                    ('Do not know how to deal with variable %s '
                     'using  index %s in a subgroup') % (key, value))

        self.namespace = self.source.namespace
        self.codeobj_class = self.source.codeobj_class

        self._enable_group_attributes()
Ejemplo n.º 10
0
    def __init__(self,
                 source,
                 record=True,
                 when=None,
                 name='spikemonitor*',
                 codeobj_class=None):
        self.record = bool(record)
        #: The source we are recording from
        self.source = 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
        CodeRunner.__init__(self,
                            group=self,
                            template='spikemonitor',
                            name=name,
                            when=scheduler)

        # Handle subgroups correctly
        start = getattr(source, 'start', 0)
        stop = getattr(source, 'stop', len(source))

        self.variables = Variables(self)
        self.variables.add_clock_variables(scheduler.clock, prefix='_clock_')
        self.variables.add_reference('_spikespace',
                                     source.variables['_spikespace'])
        self.variables.add_dynamic_array('i',
                                         size=0,
                                         unit=Unit(1),
                                         dtype=np.int32,
                                         constant_size=False)
        self.variables.add_dynamic_array('t',
                                         size=0,
                                         unit=second,
                                         constant_size=False)
        self.variables.add_array('_count',
                                 size=len(source),
                                 unit=Unit(1),
                                 dtype=np.int32)
        self.variables.add_constant('_source_start', Unit(1), start)
        self.variables.add_constant('_source_stop', Unit(1), stop)
        self.variables.add_attribute_variable('N',
                                              unit=Unit(1),
                                              obj=self,
                                              attribute='_N',
                                              dtype=np.int32)
        self._N = 0

        self._enable_group_attributes()
Ejemplo n.º 11
0
    def __init__(self,
                 target,
                 target_var,
                 N,
                 rate,
                 weight,
                 when='synapses',
                 order=0):
        if target_var not in target.variables:
            raise KeyError('%s is not a variable of %s' %
                           (target_var, target.name))

        self._weight = weight
        self._target_var = target_var

        if isinstance(weight, str):
            weight = '(%s)' % weight
        else:
            weight_dims = get_dimensions(weight)
            target_dims = target.variables[target_var].dim
            # This will be checked automatically in the abstract code as well
            # but doing an explicit check here allows for a clearer error
            # message
            if not have_same_dimensions(weight_dims, target_dims):
                raise DimensionMismatchError(
                    ('The provided weight does not '
                     'have the same unit as the '
                     'target variable "%s"') % target_var, weight_dims,
                    target_dims)
            weight = repr(weight)
        self._N = N
        self._rate = rate
        binomial_sampling = BinomialFunction(N,
                                             rate * target.clock.dt,
                                             name='poissoninput_binomial*')

        code = '{targetvar} += {binomial}()*{weight}'.format(
            targetvar=target_var,
            binomial=binomial_sampling.name,
            weight=weight)
        self._stored_dt = target.dt_[:]  # make a copy
        # FIXME: we need an explicit reference here for on-the-fly subgroups
        # For example: PoissonInput(group[:N], ...)
        self._group = target
        CodeRunner.__init__(self,
                            group=target,
                            template='stateupdate',
                            code=code,
                            user_code='',
                            when=when,
                            order=order,
                            name='poissoninput*',
                            clock=target.clock)
        self.variables = Variables(self)
        self.variables._add_variable(binomial_sampling.name, binomial_sampling)
Ejemplo n.º 12
0
    def __init__(self,
                 source,
                 record=True,
                 when='end',
                 order=0,
                 name='spikemonitor*',
                 codeobj_class=None):
        self.record = bool(record)
        #: The source we are recording from
        self.source = source

        self.codeobj_class = codeobj_class
        CodeRunner.__init__(self,
                            group=self,
                            code='',
                            template='spikemonitor',
                            name=name,
                            clock=source.clock,
                            when=when,
                            order=order)

        self.add_dependency(source)

        # Handle subgroups correctly
        start = getattr(source, 'start', 0)
        stop = getattr(source, 'stop', len(source))

        self.variables = Variables(self)
        self.variables.add_reference('_spikespace', source)
        self.variables.add_dynamic_array('i',
                                         size=0,
                                         unit=Unit(1),
                                         dtype=np.int32,
                                         constant_size=False)
        self.variables.add_dynamic_array('t',
                                         size=0,
                                         unit=second,
                                         constant_size=False)
        self.variables.add_arange('_source_i', size=len(source))
        self.variables.add_array('_count',
                                 size=len(source),
                                 unit=Unit(1),
                                 dtype=np.int32,
                                 read_only=True,
                                 index='_source_i')
        self.variables.add_constant('_source_start', Unit(1), start)
        self.variables.add_constant('_source_stop', Unit(1), stop)
        self.variables.add_attribute_variable('N',
                                              unit=Unit(1),
                                              obj=self,
                                              attribute='_N',
                                              dtype=np.int32)
        self.variables.create_clock_variables(self._clock, prefix='_clock_')
        self._enable_group_attributes()
Ejemplo n.º 13
0
    def get_with_expression(self, variable_name, variable, code,
                            level=0, run_namespace=None):
        '''
        Gets a variable using a string expression. Is called by
        `VariableView.get_item` for statements such as
        ``print G.v['g_syn > 0']``.

        Parameters
        ----------
        variable_name : str
            The name of the variable in its context (e.g. ``'g_post'`` for a
            variable with name ``'g'``)
        variable : `ArrayVariable`
            The `ArrayVariable` object for the variable to be set
        code : str
            An expression that states a condition for elements that should be
            selected. Can contain references to indices, such as ``i`` or ``j``
            and to state variables. For example: ``'i>3 and v>0*mV'``.
        level : int, optional
            How much farther to go up in the stack to find the implicit
            namespace (if used, see `run_namespace`).
        run_namespace : dict-like, optional
            An additional namespace that is used for variable lookup (if not
            defined, the implicit namespace of local variables is used).
        '''
        if variable.scalar:
            raise IndexError(('Cannot access the variable %s with a '
                              'string expression, it is a scalar '
                              'variable.') % variable_name)
        # Add the recorded variable under a known name to the variables
        # dictionary. Important to deal correctly with
        # the type of the variable in C++
        variables = Variables(None)
        variables.add_auxiliary_variable('_variable', unit=variable.unit,
                                         dtype=variable.dtype,
                                         scalar=variable.scalar)
        variables.add_auxiliary_variable('_cond', unit=Unit(1), dtype=np.bool)

        abstract_code = '_variable = ' + variable_name + '\n'
        abstract_code += '_cond = ' + code
        check_code_units(abstract_code, self,
                         additional_variables=variables,
                         level=level+2,
                         run_namespace=run_namespace)
        codeobj = create_runner_codeobj(self,
                                        abstract_code,
                                        'group_variable_get_conditional',
                                        additional_variables=variables,
                                        level=level+2,
                                        run_namespace=run_namespace,
                                        )
        return codeobj()
Ejemplo n.º 14
0
    def set_with_expression_conditional(self, varname, variable, cond,
                                        code, check_units=True, level=0,
                                        run_namespace=None):
        '''
        Sets a variable using a string expression and string condition. Is
        called by `VariableView.set_item` for statements such as
        ``S.var['i!=j'] = 'exp(-abs(i-j)/space_constant)*nS'``

        Parameters
        ----------
        varname : str
            The name of the variable to be set.
        variable : `ArrayVariable`
            The `ArrayVariable` object for the variable to be set.
        cond : str
            The string condition for which the variables should be set.
        code : str
            The code that should be executed to set the variable values.
        check_units : bool, optional
            Whether to check the units of the expression.
        level : int, optional
            How much farther to go up in the stack to find the implicit
            namespace (if used, see `run_namespace`).
        run_namespace : dict-like, optional
            An additional namespace that is used for variable lookup (if not
            defined, the implicit namespace of local variables is used).
        '''
        if variable.scalar and cond != 'True':
            raise IndexError(('Cannot conditionally set the scalar variable '
                              '%s.') % varname)
        abstract_code_cond = '_cond = '+cond
        abstract_code = varname + ' = ' + code
        variables = Variables(None)
        variables.add_auxiliary_variable('_cond', unit=Unit(1), dtype=np.bool)
        check_code_units(abstract_code_cond, self,
                         additional_variables=variables,
                         level=level+2,
                         run_namespace=run_namespace)
        # TODO: Have an additional argument to avoid going through the index
        # array for situations where iterate_all could be used
        codeobj = create_runner_codeobj(self,
                                        {'condition': abstract_code_cond,
                                         'statement': abstract_code},
                                        'group_variable_set_conditional',
                                        additional_variables=variables,
                                        check_units=check_units,
                                        level=level+2,
                                        run_namespace=run_namespace)
        codeobj()
Ejemplo n.º 15
0
    def get_with_index_array(self, variable_name, variable, item):
        if variable.scalar:
            if not (isinstance(item, slice) and item == slice(None)):
                raise IndexError(('Illegal index for variable %s, it is a '
                                  'scalar variable.') % variable_name)
            indices = np.array(0)
        else:
            indices = self.calc_indices(item)

        # For "normal" variables, we can directly access the underlying data
        # and use the usual slicing syntax. For subexpressions, however, we
        # have to evaluate code for the given indices
        if isinstance(variable, Subexpression):
            variables = Variables(None)
            variables.add_auxiliary_variable('_variable', unit=variable.unit,
                                             dtype=variable.dtype,
                                             scalar=variable.scalar)
            if indices.shape ==  ():
                single_index = True
                indices = np.array([indices])
            else:
                single_index = False
            variables.add_array('_group_idx', unit=Unit(1),
                                size=len(indices), dtype=np.int32)
            variables['_group_idx'].set_value(indices)

            abstract_code = '_variable = ' + variable_name + '\n'
            codeobj = create_runner_codeobj(self,
                                            abstract_code,
                                            'group_variable_get',
                                            additional_variables=variables
            )
            result = codeobj()
            if single_index and not variable.scalar:
                return result[0]
            else:
                return result
        else:
            if variable.scalar:
                return variable.get_value()[0]
            else:
                # We are not going via code generation so we have to take care
                # of correct indexing (in particular for subgroups) explicitly
                var_index = self.variables.indices[variable_name]
                if var_index != '_idx':
                    indices = self.variables[var_index].get_value()[indices]
                return variable.get_value()[indices]
Ejemplo n.º 16
0
    def set_with_expression(self, varname, variable, item, code,
                            check_units=True, level=0, run_namespace=None):
        '''
        Sets a variable using a string expression. Is called by
        `VariableView.set_item` for statements such as
        ``S.var[:, :] = 'exp(-abs(i-j)/space_constant)*nS'``

        Parameters
        ----------
        varname : str
            The name of the variable to be set
        variable : `ArrayVariable`
            The `ArrayVariable` object for the variable to be set.
        item : `ndarray`
            The indices for the variable (in the context of this `group`).
        code : str
            The code that should be executed to set the variable values.
            Can contain references to indices, such as `i` or `j`
        check_units : bool, optional
            Whether to check the units of the expression.
        level : int, optional
            How much farther to go up in the stack to find the implicit
            namespace (if used, see `run_namespace`).
        run_namespace : dict-like, optional
            An additional namespace that is used for variable lookup (if not
            defined, the implicit namespace of local variables is used).
        '''
        indices = self.calc_indices(item)
        abstract_code = varname + ' = ' + code
        variables = Variables(None)
        variables.add_array('_group_idx', unit=Unit(1),
                            size=len(indices), dtype=np.int32)
        variables['_group_idx'].set_value(indices)

        # TODO: Have an additional argument to avoid going through the index
        # array for situations where iterate_all could be used
        codeobj = create_runner_codeobj(self,
                                        abstract_code,
                                        'group_variable_set',
                                        additional_variables=variables,
                                        check_units=check_units,
                                        level=level+2,
                                        run_namespace=run_namespace)
        codeobj()
Ejemplo n.º 17
0
    def __getitem__(self, item):
        if isinstance(item, str):
            variables = Variables(None)
            variables.add_auxiliary_variable('_indices', dtype=np.int32)
            variables.add_auxiliary_variable('_cond', dtype=bool)

            abstract_code = '_cond = ' + item
            namespace = get_local_namespace(level=1)
            from brian2.devices.device import get_device
            device = get_device()
            codeobj = create_runner_codeobj(self.group,
                                            abstract_code,
                                            'group_get_indices',
                                            run_namespace=namespace,
                                            additional_variables=variables,
                                            codeobj_class=device.code_object_class(fallback_pref='codegen.string_expression_target')
                                            )
            return codeobj()
        else:
            return self.indices(item)
Ejemplo n.º 18
0
    def __init__(self, source, name='ratemonitor*', codeobj_class=None):

        #: The group we are recording from
        self.source = source

        scheduler = Scheduler(clock=source.clock, when='end')

        self.codeobj_class = codeobj_class
        CodeRunner.__init__(self,
                            group=self,
                            template='ratemonitor',
                            when=scheduler,
                            name=name)

        self.add_dependency(source)

        self.variables = Variables(self)
        # Handle subgroups correctly
        start = getattr(source, 'start', 0)
        stop = getattr(source, 'stop', len(source))
        self.variables.add_constant('_source_start', Unit(1), start)
        self.variables.add_constant('_source_stop', Unit(1), stop)
        self.variables.add_reference('_spikespace', source)
        self.variables.add_reference('_clock_t', source, 't')
        self.variables.add_reference('_clock_dt', source, 'dt')
        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_reference('_num_source_neurons', source, 'N')
        self.variables.add_attribute_variable('N',
                                              unit=Unit(1),
                                              obj=self,
                                              attribute='_N',
                                              dtype=np.int32)

        self._enable_group_attributes()
Ejemplo n.º 19
0
    def __getitem__(self, item):
        if isinstance(item, basestring):
            variables = Variables(None)
            variables.add_auxiliary_variable('_indices', unit=Unit(1),
                                             dtype=np.int32)
            variables.add_auxiliary_variable('_cond', unit=Unit(1),
                                             dtype=np.bool)

            abstract_code = '_cond = ' + item
            check_code_units(abstract_code, self.group,
                             additional_variables=variables,
                             level=1)
            codeobj = create_runner_codeobj(self.group,
                                            abstract_code,
                                            'group_get_indices',
                                            additional_variables=variables,
                                            level=1
                                            )
            return codeobj()
        else:
            return self.group.calc_indices(item)
Ejemplo n.º 20
0
    def __init__(self, source, name='ratemonitor*', codeobj_class=None):

        #: The group we are recording from
        self.source = source

        scheduler = Scheduler(clock=source.clock, when='end')

        self.codeobj_class = codeobj_class
        CodeRunner.__init__(self,
                            group=self,
                            template='ratemonitor',
                            when=scheduler,
                            name=name)

        self.variables = Variables(self)
        self.variables.add_reference('_spikespace',
                                     source.variables['_spikespace'])
        self.variables.add_reference('_clock_t', source.variables['t'])
        self.variables.add_reference('_clock_dt', source.variables['dt'])
        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_reference('_num_source_neurons',
                                     source.variables['N'])
        self.variables.add_attribute_variable('N',
                                              unit=Unit(1),
                                              obj=self,
                                              attribute='_N',
                                              dtype=np.int32)
        self._N = 0

        self._enable_group_attributes()
Ejemplo n.º 21
0
    def __init__(self,
                 source,
                 variables,
                 record,
                 dt=None,
                 clock=None,
                 when='start',
                 order=0,
                 name='statemonitor*',
                 codeobj_class=None):
        self.source = source
        # Make the monitor use the explicitly defined namespace of its source
        # group (if it exists)
        self.namespace = getattr(source, 'namespace', None)
        self.codeobj_class = codeobj_class

        # run by default on source clock at the end
        if dt is None and clock is None:
            clock = source.clock

        # 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 hasattr(record, '_indices'):
            # The ._indices method always returns absolute indices
            # If the source is already a subgroup of another group, we therefore
            # have to shift the indices to become relative to the subgroup
            record = record._indices() - getattr(source, '_offset', 0)
        if record is True:
            self.record_all = True
            try:
                record = np.arange(len(source), dtype=np.int32)
            except NotImplementedError:
                # In standalone mode, this is not possible for synaptic
                # variables because the number of synapses is not defined yet
                raise NotImplementedError(
                    ('Cannot determine the actual '
                     'indices to record for record=True. '
                     'This can occur for example in '
                     'standalone mode when trying to '
                     'record a synaptic variable. '
                     'Consider providing an explicit '
                     'array of indices for the record '
                     'argument.'))
        elif record is False:
            record = np.array([], dtype=np.int32)
        elif isinstance(record, numbers.Number):
            record = np.array([record], dtype=np.int32)
        else:
            record = np.asarray(record, dtype=np.int32)

        #: The array of recorded indices
        self.record = record
        self.n_indices = len(record)

        # Some dummy code so that code generation takes care of the indexing
        # and subexpressions
        code = ['_to_record_%s = _source_%s' % (v, v) for v in variables]
        code = '\n'.join(code)

        CodeRunner.__init__(self,
                            group=self,
                            template='statemonitor',
                            code=code,
                            name=name,
                            clock=clock,
                            dt=dt,
                            when=when,
                            order=order,
                            check_units=False)

        self.add_dependency(source)

        # Setup variables
        self.variables = Variables(self)

        self.variables.add_dynamic_array(
            't',
            size=0,
            dimensions=second.dim,
            constant=False,
            dtype=self._clock.variables['t'].dtype)
        self.variables.add_array('N',
                                 dtype=np.int32,
                                 size=1,
                                 scalar=True,
                                 read_only=True)
        self.variables.add_array('_indices',
                                 size=len(self.record),
                                 dtype=self.record.dtype,
                                 constant=True,
                                 read_only=True,
                                 values=self.record)
        self.variables.create_clock_variables(self._clock, prefix='_clock_')
        for varname in variables:
            var = source.variables[varname]
            if var.scalar and len(self.record) > 1:
                logger.warn(('Variable %s is a shared variable but it will be '
                             'recorded once for every target.' % varname),
                            once=True)
            index = source.variables.indices[varname]
            self.variables.add_reference('_source_%s' % varname,
                                         source,
                                         varname,
                                         index=index)
            if not index in ('_idx', '0') and index not in variables:
                self.variables.add_reference(index, source)
            self.variables.add_dynamic_array(varname,
                                             size=(0, len(self.record)),
                                             resize_along_first=True,
                                             dimensions=var.dim,
                                             dtype=var.dtype,
                                             constant=False,
                                             read_only=True)

        for varname in variables:
            var = self.source.variables[varname]
            self.variables.add_auxiliary_variable('_to_record_' + varname,
                                                  dimensions=var.dim,
                                                  dtype=var.dtype,
                                                  scalar=var.scalar)

        self.recorded_variables = dict([(varname, self.variables[varname])
                                        for varname in variables])
        recorded_names = [varname for varname in variables]

        self.needed_variables = recorded_names
        self.template_kwds = {'_recorded_variables': self.recorded_variables}
        self.written_readonly_vars = {
            self.variables[varname]
            for varname in self.record_variables
        }
        self._enable_group_attributes()
Ejemplo n.º 22
0
    def __init__(self, source, event, variables=None, record=True,
                 when=None, order=None, name='eventmonitor*',
                 codeobj_class=None):
        #: The source we are recording from
        self.source = source
        #: Whether to record times and indices of events
        self.record = record

        if when is None:
            if order is not None:
                raise ValueError('Cannot specify order if when is not specified.')
            if hasattr(source, 'thresholder'):
                parent_obj = source.thresholder[event]
            else:
                parent_obj = source
            when = parent_obj.when
            order = parent_obj.order + 1
        elif order is None:
            order = 0

        #: The event that we are listening to
        self.event = event

        if variables is None:
            variables = {}
        elif isinstance(variables, basestring):
            variables = {variables}

        #: The additional variables that will be recorded
        self.record_variables = set(variables)

        for variable in variables:
            if variable not in source.variables:
                raise ValueError(("'%s' is not a variable of the recorded "
                                  "group" % variable))

        if self.record:
            self.record_variables |= {'i', 't'}

        # Some dummy code so that code generation takes care of the indexing
        # and subexpressions
        code = ['_to_record_%s = _source_%s' % (v, v)
                for v in self.record_variables]
        code = '\n'.join(code)

        self.codeobj_class = codeobj_class

        # Since this now works for general events not only spikes, we have to
        # pass the information about which variable to use to the template,
        # it can not longer simply refer to "_spikespace"
        eventspace_name = '_{}space'.format(event)

        # Handle subgroups correctly
        start = getattr(source, 'start', 0)
        stop = getattr(source, 'stop', len(source))

        Nameable.__init__(self, name=name)

        self.variables = Variables(self)
        self.variables.add_reference(eventspace_name, source)

        for variable in self.record_variables:
            source_var = source.variables[variable]
            self.variables.add_reference('_source_%s' % variable,
                                         source, variable)
            self.variables.add_auxiliary_variable('_to_record_%s' % variable,
                                                   unit=source_var.unit,
                                                   dtype=source_var.dtype)
            self.variables.add_dynamic_array(variable, size=0,
                                             unit=source_var.unit,
                                             dtype=source_var.dtype,
                                             constant_size=False)
        self.variables.add_arange('_source_idx', size=len(source))
        self.variables.add_array('count', size=len(source), unit=Unit(1),
                                 dtype=np.int32, read_only=True,
                                 index='_source_idx')
        self.variables.add_constant('_source_start', Unit(1), start)
        self.variables.add_constant('_source_stop', Unit(1), stop)
        self.variables.add_array('N', unit=Unit(1), size=1, dtype=np.int32,
                                 read_only=True, scalar=True)

        record_variables = {varname: self.variables[varname]
                            for varname in self.record_variables}
        template_kwds = {'eventspace_variable': source.variables[eventspace_name],
                         'record_variables': record_variables,
                         'record': self.record}
        needed_variables = {eventspace_name} | self.record_variables
        CodeRunner.__init__(self, group=self, code=code, template='spikemonitor',
                            name=None,  # The name has already been initialized
                            clock=source.clock, when=when,
                            order=order, needed_variables=needed_variables,
                            template_kwds=template_kwds)

        self.variables.create_clock_variables(self._clock,
                                              prefix='_clock_')

        self.add_dependency(source)
        self._enable_group_attributes()
Ejemplo n.º 23
0
    def __init__(self,
                 N,
                 indices,
                 times,
                 dt=None,
                 clock=None,
                 period=0 * second,
                 when='thresholds',
                 order=0,
                 sorted=False,
                 name='spikegeneratorgroup*',
                 codeobj_class=None):

        Group.__init__(self,
                       dt=dt,
                       clock=clock,
                       when=when,
                       order=order,
                       name=name)

        # We store the indices and times also directly in the Python object,
        # this way we can use them for checks in `before_run` even in standalone
        # TODO: Remove this when the checks in `before_run` have been moved to the template
        #: Array of spiking neuron indices.
        self._neuron_index = None
        #: Array of spiking neuron times.
        self._spike_time = None
        #: "Dirty flag" that will be set when spikes are changed after the
        #: `before_run` check
        self._spikes_changed = True

        # Let other objects know that we emit spikes events
        self.events = {'spike': None}

        self.codeobj_class = codeobj_class

        if N < 1 or int(N) != N:
            raise TypeError('N has to be an integer >=1.')
        N = int(
            N)  # Make sure that it is an integer, values such as 10.0 would
        # otherwise make weave compilation fail
        self.start = 0
        self.stop = N

        self.variables = Variables(self)
        self.variables.create_clock_variables(self._clock)

        indices, times = self._check_args(indices, times, period, N, sorted,
                                          self._clock.dt)

        self.variables.add_constant('N', value=N)
        self.variables.add_array('period',
                                 dimensions=second.dim,
                                 size=1,
                                 constant=True,
                                 read_only=True,
                                 scalar=True,
                                 dtype=self._clock.variables['t'].dtype)
        self.variables.add_arange('i', N)
        self.variables.add_dynamic_array('spike_number',
                                         values=np.arange(len(indices)),
                                         size=len(indices),
                                         dtype=np.int32,
                                         read_only=True,
                                         constant=True,
                                         index='spike_number',
                                         unique=True)
        self.variables.add_dynamic_array('neuron_index',
                                         values=indices,
                                         size=len(indices),
                                         dtype=np.int32,
                                         index='spike_number',
                                         read_only=True,
                                         constant=True)
        self.variables.add_dynamic_array(
            'spike_time',
            values=times,
            size=len(times),
            dimensions=second.dim,
            index='spike_number',
            read_only=True,
            constant=True,
            dtype=self._clock.variables['t'].dtype)
        self.variables.add_dynamic_array('_timebins',
                                         size=len(times),
                                         index='spike_number',
                                         read_only=True,
                                         constant=True,
                                         dtype=np.int32)
        self.variables.add_array('_period_bins',
                                 size=1,
                                 constant=True,
                                 read_only=True,
                                 scalar=True,
                                 dtype=np.int32)
        self.variables.add_array('_spikespace', size=N + 1, dtype=np.int32)
        self.variables.add_array('_lastindex',
                                 size=1,
                                 values=0,
                                 dtype=np.int32,
                                 read_only=True,
                                 scalar=True)

        #: Remember the dt we used the last time when we checked the spike bins
        #: to not repeat the work for multiple runs with the same dt
        self._previous_dt = None

        CodeRunner.__init__(self,
                            self,
                            code='',
                            template='spikegenerator',
                            clock=self._clock,
                            when=when,
                            order=order,
                            name=None)

        # Activate name attribute access
        self._enable_group_attributes()

        self.variables['period'].set_value(period)
Ejemplo n.º 24
0
    def __init__(self, source, start, stop, name=None):
        # First check if the source is itself a Subgroup
        # If so, then make this a Subgroup of the original Group
        if isinstance(source, Subgroup):
            source = source.source
            start = start + source.start
            stop = stop + source.start
            self.source = source
        else:
            self.source = weakproxy_with_fallback(source)

        # Store a reference to the source's equations (if any)
        self.equations = None
        if hasattr(self.source, 'equations'):
            self.equations = weakproxy_with_fallback(self.source.equations)

        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
        Group.__init__(self,
                       clock=source._clock,
                       when='thresholds',
                       order=source.order + 1,
                       name=name)
        self._N = stop - start
        self.start = start
        self.stop = stop

        self.events = self.source.events

        # All the variables have to go via the _sub_idx to refer to the
        # appropriate values in the source group
        self.variables = Variables(self, default_index='_sub_idx')

        # overwrite the meaning of N and i
        if self.start > 0:
            self.variables.add_constant('_offset', value=self.start)
            self.variables.add_reference('_source_i', source, 'i')
            self.variables.add_subexpression('i',
                                             dtype=source.variables['i'].dtype,
                                             expr='_source_i - _offset',
                                             index='_idx')
        else:
            # no need to calculate anything if this is a subgroup starting at 0
            self.variables.add_reference('i', source)

        self.variables.add_constant('N', value=self._N)
        self.variables.add_constant('_source_N', value=len(source))
        # add references for all variables in the original group
        self.variables.add_references(source, list(source.variables.keys()))

        # Only the variable _sub_idx itself is stored in the subgroup
        # and needs the normal index for this group
        self.variables.add_arange('_sub_idx',
                                  size=self._N,
                                  start=self.start,
                                  index='_idx')

        # special indexing for subgroups
        self._indices = Indexing(self, self.variables['_sub_idx'])

        # Deal with special indices
        for key, value in self.source.variables.indices.items():
            if value == '0':
                self.variables.indices[key] = '0'
            elif value == '_idx':
                continue  # nothing to do, already uses _sub_idx correctly
            else:
                raise ValueError(
                    ('Do not know how to deal with variable %s '
                     'using  index %s in a subgroup') % (key, value))

        self.namespace = self.source.namespace
        self.codeobj_class = self.source.codeobj_class

        self._enable_group_attributes()
Ejemplo n.º 25
0
    def _add_synapses(self,
                      sources,
                      targets,
                      n,
                      p,
                      condition=None,
                      namespace=None,
                      level=0):

        if condition is None:
            sources = np.atleast_1d(sources).astype(np.int32)
            targets = np.atleast_1d(targets).astype(np.int32)
            n = np.atleast_1d(n)
            p = np.atleast_1d(p)
            if not len(p) == 1 or p != 1:
                use_connections = np.random.rand(len(sources)) < p
                sources = sources[use_connections]
                targets = targets[use_connections]
                n = n[use_connections]
            sources = sources.repeat(n)
            targets = targets.repeat(n)
            new_synapses = len(sources)

            old_N = len(self)
            new_N = old_N + new_synapses
            self._resize(new_N)

            # Deal with subgroups
            if '_sub_idx' in self.source.variables:
                real_sources = self.source.variables['_sub_idx'].get_value(
                )[sources]
            else:
                real_sources = sources
            if '_sub_idx' in self.target.variables:
                real_targets = self.target.variables['_sub_idx'].get_value(
                )[targets]
            else:
                real_targets = targets
            self.variables['_synaptic_pre'].get_value(
            )[old_N:new_N] = real_sources
            self.variables['_synaptic_post'].get_value(
            )[old_N:new_N] = real_targets

            self.variables['N_outgoing'].get_value()[:] += np.bincount(
                real_sources, minlength=self.variables['N_outgoing'].size)
            self.variables['N_incoming'].get_value()[:] += np.bincount(
                real_targets, minlength=self.variables['N_incoming'].size)
        else:
            abstract_code = '_pre_idx = _all_pre \n'
            abstract_code += '_post_idx = _all_post \n'
            abstract_code += '_cond = ' + condition + '\n'
            abstract_code += '_n = ' + str(n) + '\n'
            abstract_code += '_p = ' + str(p)
            # This overwrites 'i' and 'j' in the synapses' variables dictionary
            # This is necessary because in the context of synapse creation, i
            # and j do not correspond to the sources/targets of the existing
            # synapses but to all the possible sources/targets
            variables = Variables(None)
            # Will be set in the template
            variables.add_auxiliary_variable('_i', unit=Unit(1))
            variables.add_auxiliary_variable('_j', unit=Unit(1))
            # Make sure that variables have the correct type in the code
            variables.add_auxiliary_variable('_pre_idx',
                                             unit=Unit(1),
                                             dtype=np.int32)
            variables.add_auxiliary_variable('_post_idx',
                                             unit=Unit(1),
                                             dtype=np.int32)
            variables.add_auxiliary_variable('_cond',
                                             unit=Unit(1),
                                             dtype=np.bool)
            variables.add_auxiliary_variable('_n',
                                             unit=Unit(1),
                                             dtype=np.int32)
            variables.add_auxiliary_variable('_p', unit=Unit(1))

            if '_sub_idx' in self.source.variables:
                variables.add_reference('_all_pre',
                                        self.source.variables['_sub_idx'])
            else:
                variables.add_reference('_all_pre', self.source.variables['i'])

            if '_sub_idx' in self.target.variables:
                variables.add_reference('_all_post',
                                        self.target.variables['_sub_idx'])
            else:
                variables.add_reference('_all_post',
                                        self.target.variables['i'])

            variable_indices = defaultdict(lambda: '_idx')
            for varname in self.variables:
                if self.variables.indices[varname] == '_presynaptic_idx':
                    variable_indices[varname] = '_all_pre'
                elif self.variables.indices[varname] == '_postsynaptic_idx':
                    variable_indices[varname] = '_all_post'
            variable_indices['_all_pre'] = '_i'
            variable_indices['_all_post'] = '_j'
            codeobj = create_runner_codeobj(self,
                                            abstract_code,
                                            'synapses_create',
                                            variable_indices=variable_indices,
                                            additional_variables=variables,
                                            check_units=False,
                                            run_namespace=namespace,
                                            level=level + 1)
            codeobj()
Ejemplo n.º 26
0
    def __init__(self,
                 N,
                 indices,
                 times,
                 dt=None,
                 clock=None,
                 period=1e100 * second,
                 when='thresholds',
                 order=0,
                 sorted=False,
                 name='spikegeneratorgroup*',
                 codeobj_class=None):

        Group.__init__(self,
                       dt=dt,
                       clock=clock,
                       when=when,
                       order=order,
                       name=name)

        # Let other objects know that we emit spikes events
        self.events = {'spike': None}

        self.codeobj_class = codeobj_class

        times = Quantity(times)
        if N < 1 or int(N) != N:
            raise TypeError('N has to be an integer >=1.')
        N = int(
            N)  # Make sure that it is an integer, values such as 10.0 would
        # otherwise make weave compilation fail
        if len(indices) != len(times):
            raise ValueError(
                ('Length of the indices and times array must '
                 'match, but %d != %d') % (len(indices), len(times)))
        if period < 0 * second:
            raise ValueError('The period cannot be negative.')
        elif len(times) and period <= np.max(times):
            raise ValueError(
                'The period has to be greater than the maximum of '
                'the spike times')
        if len(times) and np.min(times) < 0 * second:
            raise ValueError('Spike times cannot be negative')
        if len(indices) and (np.min(indices) < 0 or np.max(indices) >= N):
            raise ValueError('Indices have to lie in the interval [0, %d[' % N)

        self.start = 0
        self.stop = N

        if not sorted:
            # sort times and indices first by time, then by indices
            rec = np.rec.fromarrays([times, indices], names=['t', 'i'])
            rec.sort()
            times = np.ascontiguousarray(rec.t)
            indices = np.ascontiguousarray(rec.i)

        self.variables = Variables(self)

        # We store the indices and times also directly in the Python object,
        # this way we can use them for checks in `before_run` even in standalone
        # TODO: Remove this when the checks in `before_run` have been moved to the template
        self._spike_time = times
        self._neuron_index = indices

        # standard variables
        self.variables.add_constant('N', unit=Unit(1), value=N)
        self.variables.add_array('period',
                                 unit=second,
                                 size=1,
                                 constant=True,
                                 read_only=True,
                                 scalar=True)
        self.variables.add_arange('i', N)
        self.variables.add_dynamic_array('spike_number',
                                         values=np.arange(len(indices)),
                                         size=len(indices),
                                         unit=Unit(1),
                                         dtype=np.int32,
                                         read_only=True,
                                         constant=True,
                                         index='spike_number',
                                         unique=True)
        self.variables.add_dynamic_array('neuron_index',
                                         values=indices,
                                         size=len(indices),
                                         unit=Unit(1),
                                         dtype=np.int32,
                                         index='spike_number',
                                         read_only=True,
                                         constant=True)
        self.variables.add_dynamic_array('spike_time',
                                         values=times,
                                         size=len(times),
                                         unit=second,
                                         index='spike_number',
                                         read_only=True,
                                         constant=True)
        self.variables.add_array('_spikespace',
                                 size=N + 1,
                                 unit=Unit(1),
                                 dtype=np.int32)
        self.variables.add_array('_lastindex',
                                 size=1,
                                 values=0,
                                 unit=Unit(1),
                                 dtype=np.int32,
                                 read_only=True,
                                 scalar=True)
        self.variables.create_clock_variables(self._clock)

        #: Remember the dt we used the last time when we checked the spike bins
        #: to not repeat the work for multiple runs with the same dt
        self._previous_dt = None

        #: "Dirty flag" that will be set when spikes are changed after the
        #: `before_run` check
        self._spikes_changed = True

        CodeRunner.__init__(self,
                            self,
                            code='',
                            template='spikegenerator',
                            clock=self._clock,
                            when=when,
                            order=order,
                            name=None)

        # Activate name attribute access
        self._enable_group_attributes()

        self.variables['period'].set_value(period)
Ejemplo n.º 27
0
    def __init__(self, source, variables, record=None, dt=None, clock=None,
                 when='start', order=0, name='statemonitor*', codeobj_class=None):
        self.source = source
        # Make the monitor use the explicitly defined namespace of its source
        # group (if it exists)
        self.namespace = getattr(source, 'namespace', None)
        self.codeobj_class = codeobj_class

        # run by default on source clock at the end
        if dt is None and clock is None:
            clock = source.clock

        # 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 hasattr(record, '_indices'):
            # The ._indices method always returns absolute indices
            # If the source is already a subgroup of another group, we therefore
            # have to shift the indices to become relative to the subgroup
            record = record._indices() - getattr(source, '_offset', 0)
        if record is True:
            self.record_all = True
            record = np.arange(len(source), dtype=np.int32)
        elif record is None or record is False:
            logger.warn(('The StateMonitor set up to record the variable(s) '
                         '{vars} of "{source}" is not recording any value. '
                         'Did you forget to provide the record '
                         'argument?').format(vars=', '.join('"%s"' % var
                                                            for var in variables),
                                             source=self.source.name),
                        once=True)
            record = np.array([], dtype=np.int32)
        elif isinstance(record, numbers.Number):
            record = np.array([record], dtype=np.int32)
        else:
            record = np.asarray(record, dtype=np.int32)
            
        #: The array of recorded indices
        self.record = record
        self.n_indices = len(record)

        # Some dummy code so that code generation takes care of the indexing
        # and subexpressions
        code = ['_to_record_%s = _source_%s' % (v, v)
                for v in variables]
        code = '\n'.join(code)

        CodeRunner.__init__(self, group=self, template='statemonitor',
                            code=code, name=name,
                            clock=clock,
                            dt=dt,
                            when=when,
                            order=order,
                            check_units=False)

        self.add_dependency(source)

        # Setup variables
        self.variables = Variables(self)

        self.variables.add_dynamic_array('t', size=0, unit=second,
                                         constant=False, constant_size=False)
        self.variables.add_attribute_variable('N', unit=Unit(1),
                                              dtype=np.int32,
                                              obj=self, attribute='_N')
        self.variables.add_array('_indices', size=len(self.record),
                                 unit=Unit(1), dtype=self.record.dtype,
                                 constant=True, read_only=True,
                                 values=self.record)
        self.variables.create_clock_variables(self._clock,
                                              prefix='_clock_')
        for varname in variables:
            var = source.variables[varname]
            if var.scalar and len(self.record) > 1:
                logger.warn(('Variable %s is a shared variable but it will be '
                             'recorded once for every target.' % varname),
                            once=True)
            index = source.variables.indices[varname]
            self.variables.add_reference('_source_%s' % varname,
                                         source, varname, index=index)
            if not index in ('_idx', '0') and index not in variables:
                self.variables.add_reference(index, source)
            self.variables.add_dynamic_array(varname,
                                             size=(0, len(self.record)),
                                             resize_along_first=True,
                                             unit=var.unit,
                                             dtype=var.dtype,
                                             constant=False,
                                             constant_size=False)

        for varname in variables:
            var = self.source.variables[varname]
            self.variables.add_auxiliary_variable('_to_record_' + varname,
                                                  unit=var.unit,
                                                  dtype=var.dtype,
                                                  scalar=var.scalar)

        self.recorded_variables = dict([(varname, self.variables[varname])
                                        for varname in variables])
        recorded_names = [varname for varname in variables]

        self.needed_variables = recorded_names
        self.template_kwds = {'_recorded_variables': self.recorded_variables}
        self._enable_group_attributes()
Ejemplo n.º 28
0
    def __init__(self, synapses, code, prepost, objname=None, delay=None):
        self.code = code
        self.prepost = prepost
        if prepost == 'pre':
            self.source = synapses.source
            self.target = synapses.target
            self.synapse_sources = synapses.variables['_synaptic_pre']
        elif prepost == 'post':
            self.source = synapses.target
            self.target = synapses.source
            self.synapse_sources = synapses.variables['_synaptic_post']
        else:
            raise ValueError('prepost argument has to be either "pre" or '
                             '"post"')
        self.synapses = synapses

        if objname is None:
            objname = prepost + '*'

        CodeRunner.__init__(self,
                            synapses,
                            'synapses',
                            code=code,
                            when=(synapses.clock, 'synapses'),
                            name=synapses.name + '_' + objname,
                            template_kwds={'pathway': self})

        self._pushspikes_codeobj = None

        self.spikes_start = self.source.start
        self.spikes_stop = self.source.stop

        self.spiking_synapses = []
        self.variables = Variables(self)
        self.variables.add_attribute_variable('_spiking_synapses',
                                              unit=Unit(1),
                                              obj=self,
                                              attribute='spiking_synapses',
                                              constant=False,
                                              scalar=False)
        self.variables.add_reference('_spikespace',
                                     self.source.variables['_spikespace'])
        self.variables.add_reference('N', synapses.variables['N'])
        if delay is None:  # variable delays
            self.variables.add_dynamic_array('delay',
                                             unit=second,
                                             size=synapses._N,
                                             constant=True,
                                             constant_size=True)
            # Register the object with the `SynapticIndex` object so it gets
            # automatically resized
            synapses.register_variable(self.variables['delay'])
        else:
            if not isinstance(delay, Quantity):
                raise TypeError(('Cannot set the delay for pathway "%s": '
                                 'expected a quantity, got %s instead.') %
                                (objname, type(delay)))
            if delay.size != 1:
                raise TypeError(
                    ('Cannot set the delay for pathway "%s": '
                     'expected a scalar quantity, got a '
                     'quantity with shape %s instead.') % str(delay.shape))
            fail_for_dimension_mismatch(delay, second, ('Delay has to be '
                                                        'specified in units '
                                                        'of seconds'))
            self.variables.add_array('delay',
                                     unit=second,
                                     size=1,
                                     constant=True,
                                     scalar=True)
            self.variables['delay'].set_value(delay)

        self._delays = self.variables['delay']

        # Re-extract the last part of the name from the full name
        self.objname = self.name[len(synapses.name) + 1:]

        #: The simulation dt (necessary for the delays)
        self.dt = self.synapses.clock.dt_

        #: The `SpikeQueue`
        self.queue = None

        #: The `CodeObject` initalising the `SpikeQueue` at the begin of a run
        self._initialise_queue_codeobj = None

        self.namespace = synapses.namespace
        # Enable access to the delay attribute via the specifier
        self._enable_group_attributes()
Ejemplo n.º 29
0
    def _create_variables(self, user_dtype, events):
        '''
        Create the variables dictionary for this `NeuronGroup`, containing
        entries for the equation variables and some standard entries.
        '''
        self.variables = Variables(self)
        self.variables.add_constant('N', self._N)

        # Standard variables always present
        for event in events:
            self.variables.add_array('_{}space'.format(event),
                                     size=self._N + 1,
                                     dtype=np.int32,
                                     constant=False)
        # Add the special variable "i" which can be used to refer to the neuron index
        self.variables.add_arange('i',
                                  size=self._N,
                                  constant=True,
                                  read_only=True)
        # Add the clock variables
        self.variables.create_clock_variables(self._clock)

        for eq in self.equations.values():
            dtype = get_dtype(eq, user_dtype)
            check_identifier_pre_post(eq.varname)
            if eq.type in (DIFFERENTIAL_EQUATION, PARAMETER):
                if 'linked' in eq.flags:
                    # 'linked' cannot be combined with other flags
                    if not len(eq.flags) == 1:
                        raise SyntaxError(('The "linked" flag cannot be '
                                           'combined with other flags'))
                    self._linked_variables.add(eq.varname)
                else:
                    constant = 'constant' in eq.flags
                    shared = 'shared' in eq.flags
                    size = 1 if shared else self._N
                    self.variables.add_array(eq.varname,
                                             size=size,
                                             dimensions=eq.dim,
                                             dtype=dtype,
                                             constant=constant,
                                             scalar=shared)
            elif eq.type == SUBEXPRESSION:
                self.variables.add_subexpression(eq.varname,
                                                 dimensions=eq.dim,
                                                 expr=str(eq.expr),
                                                 dtype=dtype,
                                                 scalar='shared' in eq.flags)
            else:
                raise AssertionError('Unknown type of equation: ' + eq.eq_type)

        # Add the conditional-write attribute for variables with the
        # "unless refractory" flag
        if self._refractory is not False:
            for eq in self.equations.values():
                if (eq.type == DIFFERENTIAL_EQUATION
                        and 'unless refractory' in eq.flags):
                    not_refractory_var = self.variables['not_refractory']
                    var = self.variables[eq.varname]
                    var.set_conditional_write(not_refractory_var)

        # Stochastic variables
        for xi in self.equations.stochastic_variables:
            self.variables.add_auxiliary_variable(
                xi, dimensions=(second**-0.5).dim)

        # Check scalar subexpressions
        for eq in self.equations.values():
            if eq.type == SUBEXPRESSION and 'shared' in eq.flags:
                var = self.variables[eq.varname]
                for identifier in var.identifiers:
                    if identifier in self.variables:
                        if not self.variables[identifier].scalar:
                            raise SyntaxError(
                                ('Shared subexpression %s refers '
                                 'to non-shared variable %s.') %
                                (eq.varname, identifier))
Ejemplo n.º 30
0
    def _create_variables(self, equations, user_dtype=None):
        '''
        Create the variables dictionary for this `Synapses`, containing
        entries for the equation variables and some standard entries.
        '''
        self.variables = Variables(self)

        # Standard variables always present
        self.variables.add_dynamic_array('_synaptic_pre',
                                         size=0,
                                         unit=Unit(1),
                                         dtype=np.int32,
                                         constant_size=True)
        self.variables.add_dynamic_array('_synaptic_post',
                                         size=0,
                                         unit=Unit(1),
                                         dtype=np.int32,
                                         constant_size=True)

        self.variables.add_reference('i',
                                     self.source.variables['i'],
                                     index='_presynaptic_idx')
        self.variables.add_reference('j',
                                     self.target.variables['i'],
                                     index='_postsynaptic_idx')

        if '_offset' in self.target.variables:
            target_offset = self.target.variables['_offset'].get_value()
        else:
            target_offset = 0
        if '_offset' in self.source.variables:
            source_offset = self.source.variables['_offset'].get_value()
        else:
            source_offset = 0
        self.variables.add_array('N_incoming',
                                 size=len(self.target) + target_offset,
                                 unit=Unit(1),
                                 dtype=np.int32,
                                 constant=True,
                                 read_only=True,
                                 index='_postsynaptic_idx')
        self.variables.add_array('N_outgoing',
                                 size=len(self.source) + source_offset,
                                 unit=Unit(1),
                                 dtype=np.int32,
                                 constant=True,
                                 read_only=True,
                                 index='_presynaptic_idx')

        # We have to make a distinction here between the indices
        # and the arrays (even though they refer to the same object)
        # the synaptic propagation template would otherwise overwrite
        # synaptic_post in its namespace with the value of the
        # postsynaptic index, leading to errors for the next
        # propagation.
        self.variables.add_reference('_presynaptic_idx',
                                     self.variables['_synaptic_pre'])
        self.variables.add_reference('_postsynaptic_idx',
                                     self.variables['_synaptic_post'])

        # Add the standard variables
        self.variables.add_clock_variables(self.clock)
        self.variables.add_attribute_variable('N',
                                              Unit(1),
                                              self,
                                              '_N',
                                              constant=True)

        for eq in equations.itervalues():
            dtype = get_dtype(eq, user_dtype)
            if eq.type in (DIFFERENTIAL_EQUATION, PARAMETER):
                constant = 'constant' in eq.flags
                scalar = 'scalar' in eq.flags
                if scalar:
                    self.variables.add_array(eq.varname,
                                             size=1,
                                             unit=eq.unit,
                                             dtype=dtype,
                                             constant=constant,
                                             scalar=True,
                                             index='0')
                else:
                    # We are dealing with dynamic arrays here, code generation
                    # shouldn't directly access the specifier.array attribute but
                    # use specifier.get_value() to get a reference to the underlying
                    # array
                    self.variables.add_dynamic_array(eq.varname,
                                                     size=0,
                                                     unit=eq.unit,
                                                     dtype=dtype,
                                                     constant=constant)
            elif eq.type == SUBEXPRESSION:
                if 'summed' in eq.flags:
                    # Give a special name to the subexpression for summed
                    # variables to avoid confusion with the pre/postsynaptic
                    # target variable
                    varname = '_summed_' + eq.varname
                else:
                    varname = eq.varname
                self.variables.add_subexpression(varname,
                                                 unit=eq.unit,
                                                 expr=str(eq.expr),
                                                 scalar='scalar' in eq.flags,
                                                 dtype=dtype)
            else:
                raise AssertionError('Unknown type of equation: ' + eq.eq_type)

        # Stochastic variables
        for xi in equations.stochastic_variables:
            self.variables.add_auxiliary_variable(xi, unit=second**-0.5)

        # Add all the pre and post variables with _pre and _post suffixes
        for name, var in getattr(self.source, 'variables', {}).iteritems():
            index = '0' if var.scalar else '_presynaptic_idx'
            self.variables.add_reference(name + '_pre', var, index=index)
        for name, var in getattr(self.target, 'variables', {}).iteritems():
            index = '0' if var.scalar else '_postsynaptic_idx'
            self.variables.add_reference(name + '_post', var, index=index)
            # Also add all the post variables without a suffix -- note that a
            # reference will never overwrite the name of an existing name
            self.variables.add_reference(name, var, index=index)

        # Check scalar subexpressions
        for eq in equations.itervalues():
            if eq.type == SUBEXPRESSION and 'scalar' in eq.flags:
                var = self.variables[eq.varname]
                for identifier in var.identifiers:
                    if identifier in self.variables:
                        if not self.variables[identifier].scalar:
                            raise SyntaxError(
                                ('Scalar subexpression %s refers '
                                 'to non-scalar variable %s.') %
                                (eq.varname, identifier))