Esempio n. 1
0
def test_automatic_augmented_assignments():
    # We test that statements that could be rewritten as augmented assignments
    # are correctly rewritten (using sympy to test for symbolic equality)
    variables = {
        'x': ArrayVariable('x', owner=None, size=10, device=device),
        'y': ArrayVariable('y', owner=None, size=10, device=device),
        'z': ArrayVariable('y', owner=None, size=10, device=device),
        'b': ArrayVariable('b', owner=None, size=10, dtype=bool,
                           device=device),
        'clip': DEFAULT_FUNCTIONS['clip'],
        'inf': DEFAULT_CONSTANTS['inf']
    }
    statements = [
        # examples that should be rewritten
        # Note that using our approach, we will never get -= or /= but always
        # the equivalent += or *= statements
        ('x = x + 1.0', 'x += 1.0'),
        ('x = 2.0 * x', 'x *= 2.0'),
        ('x = x - 3.0', 'x += -3.0'),
        ('x = x/2.0', 'x *= 0.5'),
        ('x = y + (x + 1.0)', 'x += y + 1.0'),
        ('x = x + x', 'x *= 2.0'),
        ('x = x + y + z', 'x += y + z'),
        ('x = x + y + z', 'x += y + z'),
        # examples that should not be rewritten
        ('x = 1.0/x', 'x = 1.0/x'),
        ('x = 1.0', 'x = 1.0'),
        ('x = 2.0*(x + 1.0)', 'x = 2.0*(x + 1.0)'),
        ('x = clip(x + y, 0.0, inf)', 'x = clip(x + y, 0.0, inf)'),
        ('b = b or False', 'b = b or False')
    ]
    for orig, rewritten in statements:
        scalar, vector = make_statements(orig, variables, np.float32)
        try:  # we augment the assertion error with the original statement
            assert len(
                scalar
            ) == 0, 'Did not expect any scalar statements but got ' + str(
                scalar)
            assert len(
                vector
            ) == 1, 'Did expect a single statement but got ' + str(vector)
            statement = vector[0]
            expected_var, expected_op, expected_expr, _ = parse_statement(
                rewritten)
            assert expected_var == statement.var, 'expected write to variable %s, not to %s' % (
                expected_var, statement.var)
            assert expected_op == statement.op, 'expected operation %s, not %s' % (
                expected_op, statement.op)
            # Compare the two expressions using sympy to allow for different order etc.
            sympy_expected = str_to_sympy(expected_expr)
            sympy_actual = str_to_sympy(statement.expr)
            assert sympy_expected == sympy_actual, (
                'RHS expressions "%s" and "%s" are not identical' %
                (sympy_to_str(sympy_expected), sympy_to_str(sympy_actual)))
        except AssertionError as ex:
            raise AssertionError(
                'Transformation for statement "%s" gave an unexpected result: %s'
                % (orig, str(ex)))
Esempio n. 2
0
    def _create_variables(self):
        '''
        Create the variables dictionary for this `NeuronGroup`, containing
        entries for the equation variables and some standard entries.
        '''
        # Get the standard variables for all groups
        s = Group._create_variables(self)

        # Standard variables always present
        s.update({
            '_spikespace':
            ArrayVariable('_spikespace',
                          Unit(1),
                          self._spikespace,
                          group_name=self.name)
        })
        s.update({
            '_spikes':
            AttributeVariable(Unit(1), self, 'spikes', constant=False)
        })

        for eq in self.equations.itervalues():
            if eq.type in (DIFFERENTIAL_EQUATION, PARAMETER):
                array = self.arrays[eq.varname]
                constant = ('constant' in eq.flags)
                s.update({
                    eq.varname:
                    ArrayVariable(eq.varname,
                                  eq.unit,
                                  array,
                                  group_name=self.name,
                                  constant=constant,
                                  is_bool=eq.is_bool)
                })

            elif eq.type == STATIC_EQUATION:
                s.update({
                    eq.varname:
                    Subexpression(eq.unit,
                                  brian_prefs['core.default_scalar_dtype'],
                                  str(eq.expr),
                                  variables=s,
                                  namespace=self.namespace,
                                  is_bool=eq.is_bool)
                })
            else:
                raise AssertionError('Unknown type of equation: ' + eq.eq_type)

        # Stochastic variables
        for xi in self.equations.stochastic_variables:
            s.update({xi: StochasticVariable()})

        return s
Esempio n. 3
0
def test_illegal_calls():
    eqs = Equations('dv/dt = -v / (10*ms) : 1')
    clock = Clock(dt=0.1 * ms)
    variables = {
        'v':
        ArrayVariable(name='name',
                      size=10,
                      owner=None,
                      device=None,
                      dtype=np.float64,
                      constant=False),
        't':
        clock.variables['t'],
        'dt':
        clock.variables['dt']
    }
    assert_raises(
        TypeError,
        lambda: StateUpdateMethod.apply_stateupdater(eqs, variables, object()))
    assert_raises(
        TypeError, lambda: StateUpdateMethod.apply_stateupdater(
            eqs, variables, group_name='my_name', method=object()))
    assert_raises(
        TypeError, lambda: StateUpdateMethod.apply_stateupdater(
            eqs, variables, [object(), 'euler']))
    assert_raises(
        TypeError, lambda: StateUpdateMethod.apply_stateupdater(
            eqs, variables, group_name='my_name', method=[object(), 'euler']))
Esempio n. 4
0
    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
Esempio n. 5
0
 def __init__(self, N, offset, group):
     self.N = N
     self.offset = int(offset)
     self.group = weakref.proxy(group)
     self._indices = np.arange(self.N + self.offset)
     self.variables = {'i': ArrayVariable('i',
                                           Unit(1),
                                           self._indices - self.offset)}
     Variable.__init__(self, Unit(1), value=self, constant=True)
Esempio n. 6
0
def check_permutation_code(code):
    from collections import defaultdict
    vars = get_identifiers(code)
    indices = defaultdict(lambda: '_idx')
    for var in vars:
        if var.endswith('_syn'):
            indices[var] = '_idx'
        elif var.endswith('_pre'):
            indices[var] = '_presynaptic_idx'
        elif var.endswith('_post'):
            indices[var] = '_postsynaptic_idx'
    variables = dict()
    for var in indices:
        variables[var] = ArrayVariable(var, 1, None, 10, device)
    variables['_presynaptic_idx'] = ArrayVariable(var, 1, None, 10, device)
    variables['_postsynaptic_idx'] = ArrayVariable(var, 1, None, 10, device)
    scalar_statements, vector_statements = make_statements(
        code, variables, float64)
    check_for_order_independence(vector_statements, variables, indices)
Esempio n. 7
0
    def _set_with_code(self, variable, group_indices, code,
                       check_units=True, level=0):
        '''
        Sets a variable using a string expression. Is called by
        `VariableView.__setitem__` for statements such as
        `S.var[:, :] = 'exp(-abs(i-j)/space_constant)*nS'`

        Parameters
        ----------
        variable : `ArrayVariable`
            The `Variable` for the variable to be set
        group_indices : ndarray of int
            The indices of the elements that are to be set.
        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 down in the stack to find the namespace.
            Necessary so that both `X.var = ` and `X.var[:] = ` have access
            to the surrounding namespace.
        '''
        abstract_code = variable.name + ' = ' + code
        namespace = get_local_namespace(level + 1)
        additional_namespace = ('implicit-namespace', namespace)
        # TODO: Find a name that makes sense for reset and variable setting
        # with code
        additional_variables = self.item_mapping.variables
        additional_variables['_spikes'] = ArrayVariable('_spikes',
                                                         Unit(1),
                                                         value=group_indices.astype(np.int32),
                                                         group_name=self.name)
        # 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,
                                 'reset',
                                 additional_variables=additional_variables,
                                 additional_namespace=additional_namespace,
                                 check_units=check_units)
        codeobj()
Esempio n. 8
0
    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)
Esempio n. 9
0
from pylab import *
from brian2 import *
from brian2.codegen.generators.cython_generator import CythonCodeGenerator
from brian2.codegen.statements import Statement
from brian2.codegen.translation import make_statements
from brian2.core.variables import Variable, ArrayVariable

owner = None

code = '''
x = a*b+c
'''

variables = {
    'a': ArrayVariable('a', Unit(1), owner, 10, get_device()),
    'b': ArrayVariable('b', Unit(1), owner, 10, get_device()),
    'x': ArrayVariable('x', Unit(1), owner, 10, get_device()),
}
namespace = {}
variable_indices = {'a': '_idx', 'b': '_idx', 'x': '_idx'}

gen = CythonCodeGenerator(variables,
                          variable_indices,
                          owner,
                          iterate_all=True,
                          codeobj_class=None)

#print gen.translate_expression('a*b+c')
#print gen.translate_statement(Statement('x', '=', 'a*b+c', '', float))

stmts = make_statements(code, variables, float)
Esempio n. 10
0
def test_priority():
    updater = ExplicitStateUpdater('x_new = x + dt * f(x, t)')
    # Equations that work for the state updater
    eqs = Equations('dv/dt = -v / (10*ms) : 1')
    clock = Clock(dt=0.1 * ms)
    variables = {
        'v':
        ArrayVariable(name='name',
                      size=10,
                      owner=None,
                      device=None,
                      dtype=np.float64,
                      constant=False),
        'w':
        ArrayVariable(name='name',
                      size=10,
                      owner=None,
                      device=None,
                      dtype=np.float64,
                      constant=False),
        't':
        clock.variables['t'],
        'dt':
        clock.variables['dt']
    }
    updater(eqs, variables)  # should not raise an error

    # External parameter in the coefficient, linear integration should work
    param = 1
    eqs = Equations('dv/dt = -param * v / (10*ms) : 1')
    updater(eqs, variables)  # should not raise an error
    can_integrate = {
        linear: True,
        euler: True,
        exponential_euler: True,
        rk2: True,
        rk4: True,
        heun: True,
        milstein: True
    }

    check_integration(eqs, variables, can_integrate)

    # Constant equation, should work for all except linear (see #1010)
    param = 1
    eqs = Equations('''dv/dt = 10*Hz : 1
                       dw/dt = -v/(10*ms) : 1''')
    updater(eqs, variables)  # should not raise an error
    can_integrate = {
        linear: None,
        euler: True,
        exponential_euler: True,
        rk2: True,
        rk4: True,
        heun: True,
        milstein: True
    }

    check_integration(eqs, variables, can_integrate)

    # Equations resulting in complex linear solution for older versions of sympy
    eqs = Equations('''dv/dt      = (ge+gi-(v+49*mV))/(20*ms) : volt
            dge/dt     = -ge/(5*ms) : volt
            dgi/dt     = Dgi/(5*ms) : volt
            dDgi/dt    = ((-2./5) * Dgi - (1./5**2)*gi)/(10*ms) : volt''')
    can_integrate = {
        linear: None,
        euler: True,
        exponential_euler: True,
        rk2: True,
        rk4: True,
        heun: True,
        milstein: True
    }
    check_integration(eqs, variables, can_integrate)

    # Equation with additive noise
    eqs = Equations('dv/dt = -v / (10*ms) + xi/(10*ms)**.5 : 1')
    assert_raises(UnsupportedEquationsException,
                  lambda: updater(eqs, variables))

    can_integrate = {
        linear: False,
        euler: True,
        exponential_euler: False,
        rk2: False,
        rk4: False,
        heun: True,
        milstein: True
    }

    check_integration(eqs, variables, can_integrate)

    # Equation with multiplicative noise
    eqs = Equations('dv/dt = -v / (10*ms) + v*xi/(10*ms)**.5 : 1')
    assert_raises(UnsupportedEquationsException,
                  lambda: updater(eqs, variables))

    can_integrate = {
        linear: False,
        euler: False,
        exponential_euler: False,
        rk2: False,
        rk4: False,
        heun: True,
        milstein: True
    }

    check_integration(eqs, variables, can_integrate)
Esempio n. 11
0
def test_priority():
    updater = ExplicitStateUpdater('x_new = x + dt * f(x, t)')
    # Equations that work for the state updater
    eqs = Equations('dv/dt = -v / (10*ms) : 1')
    # Fake clock class
    MyClock = namedtuple('MyClock', ['t_', 'dt_'])
    clock = MyClock(t_=0, dt_=0.0001)
    variables = {'v': ArrayVariable(name='name', unit=Unit(1), size=10,
                                    owner=None, device=None, dtype=np.float64,
                                    constant=False),
                  't': AttributeVariable(name='t', unit=second, obj=clock,
                                         attribute='t_', constant=False,
                                         dtype=np.float64),
                  'dt': AttributeVariable(name='dt', unit=second, obj=clock,
                                          attribute='dt_', constant=True,
                                          dtype=np.float64)}
    assert updater.can_integrate(eqs, variables)

    # Non-constant parameter in the coefficient, linear integration does not
    # work
    eqs = Equations('''dv/dt = -param * v / (10*ms) : 1
                       param : 1''')
    variables['param'] = ArrayVariable(name='name', unit=Unit(1), owner=None,
                                       size=10, dtype=np.float64,
                                       constant=False, device=None)
    assert updater.can_integrate(eqs, variables)
    can_integrate = {linear: False, euler: True, rk2: True, rk4: True, 
                     milstein: True}

    for integrator, able in can_integrate.iteritems():
        assert integrator.can_integrate(eqs, variables) == able

    # Constant parameter in the coefficient, linear integration should
    # work
    eqs = Equations('''dv/dt = -param * v / (10*ms) : 1
                       param : 1 (constant)''')
    variables['param'] = ArrayVariable(name='name', unit=Unit(1), owner=None,
                                       size=10, dtype=np.float64,
                                       device=None, constant=True)
    assert updater.can_integrate(eqs, variables)
    can_integrate = {linear: True, euler: True, rk2: True, rk4: True, 
                     milstein: True}
    del variables['param']

    for integrator, able in can_integrate.iteritems():
        assert integrator.can_integrate(eqs, variables) == able

    # External parameter in the coefficient, linear integration *should* work
    # (external parameters don't change during a run)
    param = 1
    eqs = Equations('dv/dt = -param * v / (10*ms) : 1')
    assert updater.can_integrate(eqs, variables)
    can_integrate = {linear: True, euler: True, rk2: True, rk4: True, 
                     milstein: True}
    for integrator, able in can_integrate.iteritems():
        assert integrator.can_integrate(eqs, variables) == able
    
    # Equation with additive noise
    eqs = Equations('dv/dt = -v / (10*ms) + xi/(10*ms)**.5 : 1')
    assert not updater.can_integrate(eqs, variables)
    
    can_integrate = {linear: False, euler: True, rk2: False, rk4: False, 
                     milstein: True}
    for integrator, able in can_integrate.iteritems():
        assert integrator.can_integrate(eqs, variables) == able
    
    # Equation with multiplicative noise
    eqs = Equations('dv/dt = -v / (10*ms) + v*xi/(10*ms)**.5 : 1')
    assert not updater.can_integrate(eqs, variables)
    
    can_integrate = {linear: False, euler: False, rk2: False, rk4: False, 
                     milstein: True}
    for integrator, able in can_integrate.iteritems():
        assert integrator.can_integrate(eqs, variables) == able
Esempio n. 12
0
def test_priority():
    updater = ExplicitStateUpdater('x_new = x + dt * f(x, t)')
    # Equations that work for the state updater
    eqs = Equations('dv/dt = -v / (10*ms) : 1')
    clock = Clock(dt=0.1*ms)
    variables = {'v': ArrayVariable(name='name', unit=Unit(1), size=10,
                                    owner=None, device=None, dtype=np.float64,
                                    constant=False),
                 't': clock.variables['t'],
                 'dt': clock.variables['dt']}
    updater(eqs, variables)  # should not raise an error

    # External parameter in the coefficient, linear integration should work
    param = 1
    eqs = Equations('dv/dt = -param * v / (10*ms) : 1')
    updater(eqs, variables)  # should not raise an error
    can_integrate = {linear: True, euler: True, rk2: True, rk4: True, 
                     heun: True, milstein: True}
    for integrator, able in can_integrate.iteritems():
        try:
            integrator(eqs, variables)
            if not able:
                raise AssertionError('Should not be able to integrate these '
                                     'equations')
        except UnsupportedEquationsException:
            if able:
                raise AssertionError('Should be able to integrate these '
                                     'equations')
    
    # Equation with additive noise
    eqs = Equations('dv/dt = -v / (10*ms) + xi/(10*ms)**.5 : 1')
    assert_raises(UnsupportedEquationsException,
                  lambda: updater(eqs, variables))
    
    can_integrate = {linear: False, euler: True, rk2: False, rk4: False, 
                     heun: True, milstein: True}
    for integrator, able in can_integrate.iteritems():
        try:
            integrator(eqs, variables)
            if not able:
                raise AssertionError('Should not be able to integrate these '
                                     'equations')
        except UnsupportedEquationsException:
            if able:
                raise AssertionError('Should be able to integrate these '
                                     'equations')
    
    # Equation with multiplicative noise
    eqs = Equations('dv/dt = -v / (10*ms) + v*xi/(10*ms)**.5 : 1')
    assert_raises(UnsupportedEquationsException,
                  lambda: updater(eqs, variables))
    
    can_integrate = {linear: False, euler: False, rk2: False, rk4: False, 
                     heun: True, milstein: True}
    for integrator, able in can_integrate.iteritems():
        try:
            integrator(eqs, variables)
            if not able:
                raise AssertionError('Should not be able to integrate these '
                                     'equations')
        except UnsupportedEquationsException:
            if able:
                raise AssertionError('Should be able to integrate these '
                                     'equations')
Esempio n. 13
0
        #                                           expr=statement.expr)
        #     line = word_substitute(line, subs)
        #     lines.append(line)
        # return '\n'.join(lines)


if __name__ == '__main__':
    from brian2.codegen.translation import make_statements
    from brian2.core.variables import ArrayVariable
    from brian2 import device
    from numpy import float64
    code = '''
    w_syn = v_pre
    v_pre += -a_syn # change operator -= or += to see efficient/inefficient code
    x_post = y_post
    '''
    indices = {
        'w_syn': '_idx',
        'a_syn': '_idx',
        'u_pre': '_presynaptic_idx',
        'v_pre': '_presynaptic_idx',
        'x_post': '_postsynaptic_idx',
        'y_post': '_postsynaptic_idx'
    }
    variables = dict()
    for var in indices:
        variables[var] = ArrayVariable(var, 1, None, 10, device)
    scalar_statements, vector_statements = make_statements(
        code, variables, float64)
    print vectorise_synapses_code(vector_statements, variables, indices)
Esempio n. 14
0
    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)
Esempio n. 15
0
    def __getitem__(self, index):
        '''
        Returns synaptic indices for `index`, which can be a tuple of indices
        (including arrays and slices), a single index or a string.

        '''
        if (not isinstance(index, (tuple, basestring)) and isinstance(
                index, (int, np.ndarray, slice, collections.Sequence))):
            index = (index, slice(None), slice(None))
        if isinstance(index, tuple):
            if len(index) == 2:  # two indices (pre- and postsynaptic cell)
                index = (index[0], index[1], slice(None))
            elif len(index) > 3:
                raise IndexError('Need 1, 2 or 3 indices, got %d.' %
                                 len(index))

            I, J, K = index

            pre_synapses = find_synapses(I, self.pre_synaptic,
                                         self.synaptic_pre)
            post_synapses = find_synapses(J, self.post_synaptic,
                                          self.synaptic_post)
            matching_synapses = np.intersect1d(pre_synapses,
                                               post_synapses,
                                               assume_unique=True)

            if K == slice(None):
                return matching_synapses
            elif isinstance(K, (int, slice)):
                test_k = slice_to_test(K)
            else:
                raise NotImplementedError(('Indexing synapses with arrays not'
                                           'implemented yet'))

            pre_neurons = self.synaptic_pre[pre_synapses]
            post_neurons = self.synaptic_post[post_synapses]
            synapse_numbers = _synapse_numbers(pre_neurons, post_neurons)
            return np.intersect1d(matching_synapses,
                                  np.flatnonzero(test_k(synapse_numbers)),
                                  assume_unique=True)

        elif isinstance(index, basestring):
            # interpret the string expression
            identifiers = get_identifiers(index)
            variables = dict(self.variables)
            if 'k' in identifiers:
                synapse_numbers = _synapse_numbers(self.synaptic_pre[:],
                                                   self.synaptic_post[:])
                variables['k'] = ArrayVariable('k', Unit(1), synapse_numbers)
            namespace = get_local_namespace(1)
            additional_namespace = ('implicit-namespace', namespace)
            abstract_code = '_cond = ' + index
            codeobj = create_runner_codeobj(
                self.synapses,
                abstract_code,
                'state_variable_indexing',
                additional_variables=variables,
                additional_namespace=additional_namespace,
            )

            result = codeobj()
            return result
        else:
            raise IndexError(
                'Unsupported index type {itype}'.format(itype=type(index)))
Esempio n. 16
0
    def _add_synapses(self, sources, targets, n, p, condition=None, level=0):

        if condition is None:
            sources = np.atleast_1d(sources)
            targets = np.atleast_1d(targets)
            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 = self.N
            new_N = old_N + new_synapses
            self._resize(new_N)

            self.synaptic_pre[old_N:new_N] = sources
            self.synaptic_post[old_N:new_N] = targets
            synapse_idx = old_N
            for source, target in zip(sources, targets):
                synapses = self.pre_synaptic[source]
                synapses.resize(len(synapses) + 1)
                synapses[-1] = synapse_idx
                synapses = self.post_synaptic[target]
                synapses.resize(len(synapses) + 1)
                synapses[-1] = synapse_idx
                synapse_idx += 1
        else:
            abstract_code = '_cond = ' + condition + '\n'
            abstract_code += '_n = ' + str(n) + '\n'
            abstract_code += '_p = ' + str(p)
            namespace = get_local_namespace(level + 1)
            additional_namespace = ('implicit-namespace', namespace)
            variables = {
                '_source_neurons':
                ArrayVariable('_source_neurons',
                              Unit(1),
                              self.source.item_mapping[:] - self.source.offset,
                              constant=True),
                '_target_neurons':
                ArrayVariable('_target_neurons',
                              Unit(1),
                              self.target.item_mapping[:] - self.target.offset,
                              constant=True),
                # The template needs to have access to the DynamicArray here,
                # having access to the underlying array (which would be much
                # faster), is not enough
                '_synaptic_pre':
                Variable(Unit(1), self.synaptic_pre, constant=True),
                '_synaptic_post':
                Variable(Unit(1), self.synaptic_post, constant=True),
                '_pre_synaptic':
                Variable(Unit(1), self.pre_synaptic, constant=True),
                '_post_synaptic':
                Variable(Unit(1), self.post_synaptic, constant=True),
                # Will be set in the template
                'i':
                Variable(unit=Unit(1), constant=True),
                'j':
                Variable(unit=Unit(1), constant=True)
            }
            codeobj = create_runner_codeobj(
                self.synapses,
                abstract_code,
                'synapses_create',
                additional_variables=variables,
                additional_namespace=additional_namespace,
                check_units=False)
            codeobj()
            number = len(self.synaptic_pre)
            for variable in self._registered_variables:
                variable.resize(number)