Esempio n. 1
0
 def __init__(self, threshold=1 * mvolt, refractory=1 * msecond, state=0, clock=None):
     self.threshold = threshold # Threshold value
     self.state = state
     clock = guess_clock(clock)
     self.refractory = int(refractory / clock.dt)
     # this assumes that if the state stays over the threshold, and say
     # refractory=5ms the user wants spiking at 0ms 5ms 10ms 15ms etc.
     if is_approx_equal(self.refractory * clock.dt, refractory) and self.refractory > 0:
         self.refractory -= 1
Esempio n. 2
0
 def __init__(self, threshold=1 * mvolt, refractory=1 * msecond, state=0, clock=None):
     self.threshold = threshold # Threshold value
     self.state = state
     clock = guess_clock(clock)
     self.refractory = int(refractory / clock.dt)
     # this assumes that if the state stays over the threshold, and say
     # refractory=5ms the user wants spiking at 0ms 5ms 10ms 15ms etc.
     if is_approx_equal(self.refractory * clock.dt, refractory) and self.refractory > 0:
         self.refractory -= 1
Esempio n. 3
0
 def test_variable_threshold(G):    
     M = SpikeMonitor(G, True)
     net = Network(G, M)
     get_default_clock().reinit()
     G.state(2)[:] = array([1., 2., 3.]) # the thresholds
     G.state(1)[:] = array([4., 1., 2.]) # the values
     net.run(1 * msecond)
     i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
     assert (i == (0,))
     assert (is_approx_equal(t[0], 0 * second))
Esempio n. 4
0
 def test_variable_threshold(G):
     M = SpikeMonitor(G, True)
     net = Network(G, M)
     get_default_clock().reinit()
     G.state(2)[:] = array([1., 2., 3.])  # the thresholds
     G.state(1)[:] = array([4., 1., 2.])  # the values
     net.run(1 * msecond)
     i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
     assert (i == (0, ))
     assert (is_approx_equal(t[0], 0 * second))
Esempio n. 5
0
 def test_specified_state(G):
     M = SpikeMonitor(G, True)
     net = Network(G, M)
     net.run(1 * msecond)
     assert (len(M.spikes) == 0)
     net.reinit()
     G.state(0)[:] = array([0.5, 1.5, 2.5])
     net.run(1 * msecond)
     assert (len(M.spikes) == 0)
     net.reinit()
     G.state(1)[:] = array([0.5, 1.5, 2.5])
     net.run(1 * msecond)
     i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
     assert (i == (1, 2))
     for s in t: assert (is_approx_equal(s, 0 * msecond))
Esempio n. 6
0
 def test_specified_state(G):
     M = SpikeMonitor(G, True)
     net = Network(G, M)
     net.run(1 * msecond)
     assert (len(M.spikes) == 0)
     net.reinit()
     G.state(0)[:] = array([0.5, 1.5, 2.5])
     net.run(1 * msecond)
     assert (len(M.spikes) == 0)
     net.reinit()
     G.state(1)[:] = array([0.5, 1.5, 2.5])
     net.run(1 * msecond)
     i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
     assert (i == (1, 2))
     for s in t:
         assert (is_approx_equal(s, 0 * msecond))
Esempio n. 7
0
def test():
    """
    :class:`Reset`
    ~~~~~~~~~~~~~~
    
    Initialised as::
    
        R = Reset(resetvalue=0*mvolt, state=0)

    After a neuron from a group with this reset fires, it
    will set the specified state variable to the given value.
    State variable 0 is customarily the membrane voltage,
    but this isn't required. 
    
    :class:`FunReset`
    ~~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        R = FunReset(resetfun)
    
    Where resetfun is a function taking two arguments, the group
    it is acting on, and the indices of the spikes to be reset.
    The following is an example reset function::
    
        def f(P,spikeindices):
            P._S[0,spikeindices]=array([i/10. for i in range(len(spikeindices))])    
    
    :class:`Refractoriness`
    ~~~~~~~~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        R = Refractoriness(resetvalue=0*mvolt,period=5*msecond,state=0)
    
    After a neuron from a group with this reset fires, the specified state
    variable of the neuron will be set to the specified resetvalue for the
    specified period.
    
    :class:`NoReset`
    ~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        R = NoReset()
        
    Does nothing.
    """
    reinit_default_clock()


    # test that reset works as expected
    # the setup below is that group G starts with state values (1,1,1,1,1,0,0,0,0,0) threshold
    # value 0.5 (which should be initiated for the first 5 neurons) and reset 0.2 so that the
    # final state should be (0.2,0.2,0.2,0.2,0.2,0,0,0,0,0) 
    G = NeuronGroup(10, model=LazyStateUpdater(), reset=Reset(0.2), threshold=Threshold(0.5), init=(0.,))
    G1 = G.subgroup(5)
    G2 = G.subgroup(5)
    G1.state(0)[:] = array([1.] * 5)
    G2.state(0)[:] = array([0.] * 5)
    net = Network(G)
    net.run(1 * msecond)
    assert (all(G1.state(0) < 0.21) and all(0.19 < G1.state(0)) and all(G2.state(0) < 0.01))

    # recreate the same behaviour with a VariableReset
    eqs = '''
    v : 1
    r : 1
    '''
    G = NeuronGroup(10, model=eqs,
                    reset=VariableReset(resetvaluestate='r', state='v'),
                    threshold=Threshold(0.5))
    G.r = 0.2
    G1 = G.subgroup(5)
    G2 = G.subgroup(5)
    G1.v[:] = array([1.] * 5)
    G2.v[:] = array([0.] * 5)
    net = Network(G)
    net.run(1 * msecond)
    assert (all(G1.state(0) < 0.21) and all(0.19 < G1.state(0)) and all(G2.state(0) < 0.01))

    # test string reset that resets two variables
    eqs = '''v : 1
             w : 1
          '''
    G = NeuronGroup(2, model=eqs, reset='v = 0; w = -1', threshold=Threshold(0.5))
    G.v =[0.25, 1]
    G.w =[0, 0]
    # only second group crosses threshold
    net = Network(G)
    net.run(defaultclock.dt)
    # Check that the states of the first group are unchanged
    assert(G.v[0] == 0.25 and G.w[0] == 0)
    # Check that the states of the second group are reset correctly
    assert(G.v[1] == 0 and G.w[1] == -1)

    # check that function reset works as expected
    def f(P, spikeindices):
        P._S[0, spikeindices] = array([i / 10. for i in range(len(spikeindices))])
        P.called_f = True
    G = NeuronGroup(10, model=LazyStateUpdater(), reset=FunReset(f), threshold=Threshold(2.), init=(3.,))
    G.called_f = False
    net = Network(G)
    net.run(1 * msecond)
    assert (G.called_f)
    for i, v in enumerate(G.state(0)):
        assert (is_approx_equal(i / 10., v))

    # check that refractoriness works as expected
    # the network below should start at V=15, immediately spike as it is above threshold=1,
    # then should be clamped at V=-.5 until t=1ms at which point it should quickly evolve
    # via the DE to a value near 0 (and certainly between -.5 and 0). We test that the
    # value at t=0.5 is exactly -.5 and the value at t=1.5 is between -0.4 and 0.1 (to
    # avoid floating point problems)
    dV = 'dV/dt=-V/(.1*msecond):1.'
    G = NeuronGroup(1, model=dV, threshold=1., reset=Refractoriness(-.5, 1 * msecond))
    G.V = 15.
    net = Network(G)
    net.run(0.5 * msecond)
    for v in G.state(0):
        assert (is_approx_equal(v, -.5))
    net.run(1 * msecond)
    for v in G.state(0):
        assert (-0.4 < v < 0.1)

    get_default_clock().reinit()
Esempio n. 8
0
def test_spikemonitor():
    '''
    :class:`SpikeMonitor`
    ~~~~~~~~~~~~~~~~~~~~~
    
    Records spikes from a :class:`NeuronGroup`. Initialised as one of::
    
        SpikeMonitor(source(,record=True))
        SpikeMonitor(source,function=function)
    
    Where:
    
    source
        A :class:`NeuronGroup` to record from
    record
        True or False to record all the spikes or just summary
        statistics.
    function
        A function f(spikes) which is passed the array of spikes
        numbers that have fired called each step, to define
        custom spike monitoring.
    
    Has two attributes:
    
    nspikes
        The number of recorded spikes
    spikes
        A time ordered list of pairs (i,t) where neuron i fired
        at time t.
    
    :class:`StateMonitor`
    ~~~~~~~~~~~~~~~~~~~~~
    
    Records the values of a state variable from a :class:`NeuronGroup`.
    Initialise as::
    
        StateMonitor(P,varname(,record=False)
            (,when='end)(,timestep=1)(,clock=clock))
    
    Where:
    
    P
        The group to be recorded from
    varname
        The state variable name or number to be recorded
    record
        What to record. The default value is False and the monitor will
        only record summary statistics for the variable. You can choose
        record=integer to record every value of the neuron with that
        number, record=list of integers to record every value of each of
        those neurons, or record=True to record every value of every
        neuron (although beware that this may use a lot of memory).
    when
        When the recording should be made in the :class:`Network` update, possible
        values are any of the strings: 'start', 'before_groups', 'after_groups',
        'before_connections', 'after_connections', 'before_resets',
        'after_resets', 'end' (in order of when they are run).
    timestep
        A recording will be made each timestep clock updates (so timestep
        should be an integer).
    clock
        A clock for the update schedule, use this if you have specified a
        clock other than the default one in your network, or to update at a
        lower frequency than the update cycle. Note though that if the clock
        here is different from the main clock, the when parameter will not
        be taken into account, as network updates are done clock by clock.
        Use the timestep parameter if you need recordings to be made at a
        precise point in the network update step.

    The :class:`StateMonitor` object has the following properties:

    times
        The times at which recordings were made
    mean
        The mean value of the state variable for every neuron in the
        group (not just the ones specified in the record keyword)
    var
        The unbiased estimate of the variances, as in mean
    std
        The square root of var, as in mean
        
    In addition, if M is a :class:`StateMonitor` object, you write::
    
        M[i]
    
    for the recorded values of neuron i (if it was specified with the
    record keyword). It returns an array object.
    
    Others
    ~~~~~~
    
    The following monitors also exist, but are not part of the
    assured interface because their syntax is subject to change. See the documentation
    for each class for more details.
    
    * :class:`Monitor` (base class)
    * :class:`ISIHistogramMonitor`
    * :class:`FileSpikeMonitor`
    * :class:`PopulationRateMonitor`
    '''
    reinit_default_clock()

    # test that SpikeMonitor retrieves the spikes generator by SpikeGeneratorGroup

    spikes = [(0, 3 * ms), (1, 4 * ms), (0, 7 * ms)]

    G = SpikeGeneratorGroup(2, spikes, clock=defaultclock)
    M = SpikeMonitor(G)
    net = Network(G, M)
    net.run(10 * ms)

    assert (M.nspikes == 3)
    for (mi, mt), (i, t) in zip(M.spikes, spikes):
        assert (mi == i)
        assert (is_approx_equal(mt, t))

    # test that the spiketimes are saved and accessed correctly
    
    assert(len(M[0]) == len(M.spiketimes[0]) == 2 and 
           len(M[1]) == len(M.spiketimes[1]) == 1)
    assert((M.spiketimes[0] == M[0]).all() and (M.spiketimes[1] == M[1]).all())

    # test that spiketimes are cleared on reinit
    
    M.reinit()
    assert (M.nspikes == 0)
    assert (len(M.spikes) == 0)
    assert (len(M[0]) == 0 and len(M[1]) == 0)
    assert (len(M.spiketimes[0]) == 0 and len(M.spiketimes[1]) == 0)

    # test that SpikeMonitor function calling usage does what you'd expect    

    f_spikes = []

    def f(spikes):
        if len(spikes):
            f_spikes.extend(spikes)

    G = SpikeGeneratorGroup(2, spikes, clock=defaultclock)
    M = SpikeMonitor(G, function=f)
    net = Network(G, M)
    reinit_default_clock()
    net.run(10 * ms)
    assert (f_spikes == [0, 1, 0])

    # test that SpikeMonitors in MultiConnection objects do reinitialize
    # properly
    G = SpikeGeneratorGroup(2, spikes, clock=defaultclock)
    G2 = NeuronGroup(1, model='dv/dt = -v / (5*ms) : 1')
    C = Connection(G, G2, 'v', weight=0)
    M = SpikeMonitor(G)
    # Note: Because M and C share the source (G), they are replaced by a 
    #       MultiConnection 
    net = Network(G, G2, C, M)
    net.run(10 * ms)
    
    net.reinit() # make sure that the reinit propagates to the SpikeMonitor
    assert (M.nspikes == 0)
    assert (len(M.spikes) == 0)
    assert (len(M[0]) == 0 and len(M[1]) == 0)
    assert (len(M.spiketimes[0]) == 0 and len(M.spiketimes[1]) == 0)
    
    
    

    # test interface for StateMonitor object

    dV = 'dV/dt = 0*Hz : 1.'
    G = NeuronGroup(3, model=dV, reset=0., threshold=10.)
    @network_operation(when='start')
    def f(clock):
        if clock.t >= 1 * ms:
            G.V = [1., 2., 3.]
    M1 = StateMonitor(G, 'V')
    M2 = StateMonitor(G, 'V', record=0)
    M3 = StateMonitor(G, 'V', record=[0, 1])
    M4 = StateMonitor(G, 'V', record=True)
    reinit_default_clock()
    net = Network(G, f, M1, M2, M3, M4)
    net.run(2 * ms)
    assert (is_within_absolute_tolerance(M2[0][0], 0.))
    assert (is_within_absolute_tolerance(M2[0][-1], 1.))
    assert (is_within_absolute_tolerance(M3[1][0], 0.))
    assert (is_within_absolute_tolerance(M3[1][-1], 2.))
    assert (is_within_absolute_tolerance(M4[2][0], 0.))
    assert (is_within_absolute_tolerance(M4[2][-1], 3.))
    assert_raises(IndexError, M1.__getitem__, 0)
    assert_raises(IndexError, M2.__getitem__, 1)
    assert_raises(IndexError, M3.__getitem__, 2)
    assert_raises(IndexError, M4.__getitem__, 3)
    for M in [M3, M4]:
        assert (is_within_absolute_tolerance(float(max(abs(M.times - M2.times))), float(0 * ms)))
        assert (is_within_absolute_tolerance(float(max(abs(M.times_ - M2.times_))), 0.))
    assert (is_within_absolute_tolerance(float(M2.times[0]), float(0 * ms)))
    d = diff(M2.times)
    assert (is_within_absolute_tolerance(max(d), min(d)))
    assert (is_within_absolute_tolerance(float(max(d)), float(get_default_clock().dt)))
    # construct unbiased estimator from variances of recorded arrays
    v = array([ var(M4[0]), var(M4[1]), var(M4[2]) ]) * float(len(M4[0])) / float(len(M4[0]) - 1)
    m = array([0.5, 1.0, 1.5])
    assert (is_within_absolute_tolerance(abs(max(M1.mean - m)), 0.))
    assert (is_within_absolute_tolerance(abs(max(M1.var - v)), 0.))
    assert (is_within_absolute_tolerance(abs(max(M1.std - v ** 0.5)), 0.))

    # test when, timestep, clock for StateMonitor
    c = Clock(dt=0.1 * ms)
    cslow = Clock(dt=0.2 * ms)
    dV = 'dV/dt = 0*Hz : 1.'
    G = NeuronGroup(1, model=dV, reset=0., threshold=1., clock=c)
    @network_operation(when='start', clock=c)
    def f():
        G.V = 2.
    M1 = StateMonitor(G, 'V', record=True, clock=cslow)
    M2 = StateMonitor(G, 'V', record=True, timestep=2, clock=c)
    M3 = StateMonitor(G, 'V', record=True, when='before_groups', clock=c)
    net = Network(G, f, M1, M2, M3, M4)
    net.run(2 * ms)
    print M1[0], M3[0]
    assert (2 * len(M1[0]) == len(M3[0]))
    assert (len(M1[0]) == len(M2[0]))
    for i in range(len(M1[0])):
        assert (is_within_absolute_tolerance(M1[0][i], M2[0][i]))
        assert (is_within_absolute_tolerance(M1[0][i], 0.))
    for x in M3[0]:
        assert (is_within_absolute_tolerance(x, 2.))

    reinit_default_clock() # for next test
Esempio n. 9
0
def test():
    """
    :class:`Threshold`
    ~~~~~~~~~~~~~~~~~~
    
    Initialised as ``Threshold(threshold[,state=0])``
    
    Causes a spike whenever the given state variable is above
    the threshold value.
    
    :class:`NoThreshold`
    ~~~~~~~~~~~~~~~~~~~~
    
    Does nothing, initialised as ``NoThreshold()``
    
    Functional thresholds
    ~~~~~~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        FunThreshold(thresholdfun)
        SimpleFunThreshold(thresholdfun[,state=0])
    
    Threshold functions return a boolean array the same size as the
    number of neurons in the group, where if the returned array is
    True at index i then neuron i fires.
    
    The arguments passed to the :class:`FunThreshold` function are the
    full array of state variables for the group in order.
    
    The argument passed to the :class:`SimpleFunThreshold` function is the
    array of length N corresponding to the given state variable.
    
    :class:`VariableThreshold`
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Initialised as ``VariableThreshold(threshold_state[,state=0])``
    
    Causes a spike whenever the state variable defined by state
    is above the state variable defined by threshold_state.
    
    :class:`EmpiricalThreshold`
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        EmpiricalThreshold(threshold[,refractory=1*msecond[,state=0[,clock]]])
    
    Causes a spike when the given state variable exceeds the threshold value,
    but only if there has been no spike within the refractory period. Will
    use the given clock if specified, otherwise the standard guessing procedure
    is used.
    
    Poisson thresholds
    ~~~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        PoissonThreshold([state=0])
        HomogeneousPoissonThreshold([state=0])
    
    The Poisson process gets the rates from the specified state variable, the
    homogeneous version uses the rates from the specified variable of the first
    neuron in the group.      
    """
    reinit_default_clock()

    # test that Threshold works as expected with default state
    G = NeuronGroup(3, model=LazyStateUpdater(), reset=Reset(0.), threshold=Threshold(1.), init=(0.,))
    M = SpikeMonitor(G, True)
    net = Network(G, M)
    net.run(1 * msecond)
    assert (len(M.spikes) == 0)
    G.state(0)[:] = array([0.5, 1.5, 2.5])
    net.run(1 * msecond)
    i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
    assert (i == (1, 2))
    for s in t: assert (is_approx_equal(s, 1 * msecond))

    # test that Threshold works as expected with specified state
    def test_specified_state(G):
        M = SpikeMonitor(G, True)
        net = Network(G, M)
        net.run(1 * msecond)
        assert (len(M.spikes) == 0)
        net.reinit()
        G.state(0)[:] = array([0.5, 1.5, 2.5])
        net.run(1 * msecond)
        assert (len(M.spikes) == 0)
        net.reinit()
        G.state(1)[:] = array([0.5, 1.5, 2.5])
        net.run(1 * msecond)
        i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
        assert (i == (1, 2))
        for s in t: assert (is_approx_equal(s, 0 * msecond))
    G = NeuronGroup(3, model=LazyStateUpdater(numstatevariables=2),
                    reset=Reset(0., state=1), threshold=Threshold(1., state=1),
                    init=(0., 0.))
    test_specified_state(G)
    # use string threshold
    eqs = '''v : 1
             w : 1
          '''
    G = NeuronGroup(3, model=eqs, reset=Reset(0., state=1), threshold='w > 1')
    test_specified_state(G)
    
    # test that VariableThreshold works as expected
    def test_variable_threshold(G):    
        M = SpikeMonitor(G, True)
        net = Network(G, M)
        get_default_clock().reinit()
        G.state(2)[:] = array([1., 2., 3.]) # the thresholds
        G.state(1)[:] = array([4., 1., 2.]) # the values
        net.run(1 * msecond)
        i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
        assert (i == (0,))
        assert (is_approx_equal(t[0], 0 * second))

    G = NeuronGroup(3, model=LazyStateUpdater(numstatevariables=3),
                    reset=Reset(0., state=1),
                    threshold=VariableThreshold(2, state=1), init=(0., 0., 0.))
    test_variable_threshold(G)
    
    # use string threshold
    eqs = '''v : 1
             w : 1
             x : 1
          '''
    G = NeuronGroup(3, model=eqs, reset=Reset(0., state=1),
                    threshold='w > x')
    test_variable_threshold(G)
    
    # test that FunThreshold works as expected
    def f(S0, S1):
        return S0 > S1 * S1
    G = NeuronGroup(3, model=LazyStateUpdater(numstatevariables=2), reset=Reset(0.), threshold=FunThreshold(f), init=(0., 0.))
    G.state(0)[:] = array([2., 3., 10.])
    G.state(1)[:] = array([1., 2., 3.]) # the square root of the threshold values
    M = SpikeMonitor(G, True)
    net = Network(G, M)
    get_default_clock().reinit()
    net.run(1 * msecond)
    i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
    assert (i == (0, 2))
    for s in t: assert (is_approx_equal(s, 0 * msecond))

    # test that SimpleFunThreshold works as expected
    def f(S):
        return S > 1.
    G = NeuronGroup(3, model=LazyStateUpdater(), reset=Reset(0.), threshold=SimpleFunThreshold(f), init=(0.,))
    G.state(0)[:] = array([0.5, 1.5, 2.5])
    M = SpikeMonitor(G, True)
    net = Network(G, M)
    get_default_clock().reinit()
    net.run(1 * msecond)
    i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
    assert (i == (1, 2))
    for s in t: assert (is_approx_equal(s, 0 * msecond))

    # test that EmpiricalThreshold works as expected
    G = NeuronGroup(1, model=LazyStateUpdater(numstatevariables=2), reset=NoReset(), threshold=EmpiricalThreshold(1., refractory=0.5 * msecond, state=1), init=(0., 2.))
    M = SpikeMonitor(G, True)
    net = Network(G, M)
    get_default_clock().reinit()
    net.run(1.6 * msecond)
    i, t = zip(*sorted(M.spikes, key=itemgetter(1)))
    assert (i == (0, 0, 0, 0))
    for i, s in enumerate(t): assert (is_approx_equal(s, i * 0.5 * msecond))

    # test that PoissonThreshold works
    def test_poisson_threshold(G):
        init = float(1. / get_default_clock().dt) # should cause spiking at every time interval        
        G.state(0)[:] = array([0., init, 0.])
        M = SpikeMonitor(G, True)
        net = Network(G, M)
        net.run(1 * msecond)
        assert (len(M.spikes))
        i, t = zip(*sorted(M.spikes, key=itemgetter(1)))
        assert (all(j == 1 for j in i))
    
    G = NeuronGroup(3, model=LazyStateUpdater(), reset=NoReset(),
                    threshold=PoissonThreshold())
    test_poisson_threshold(G)
    
    # Poisson threshold via a string threshold using the rand() function
    eqs = '''v : 1
             w : 1
             x : 1
          '''
    
    # A threshold with rand in it is not supported by CThreshold
    if not (get_global_preference('usecodegen') and
            get_global_preference('usecodegenthreshold') and
            get_global_preference('useweave') and
            get_global_preference('usecodegenweave')):            
        G = NeuronGroup(3, model=eqs, reset=NoReset(), threshold='rand() < v')
        test_poisson_threshold(G)
        
    G = NeuronGroup(3, model=eqs, reset=NoReset(), threshold=StringThreshold('rand() < v'))
    test_poisson_threshold(G)



    # test that HomogeneousPoissonThreshold works
    init = float(1. / get_default_clock().dt) # should cause spiking at every time interval
    G = NeuronGroup(3, model=LazyStateUpdater(), reset=NoReset(), threshold=HomogeneousPoissonThreshold())
    M = SpikeMonitor(G, True)
    net = Network(G, M)
    G.state(0)[:] = array([0., init, 0.]) # should do nothing, because only first neuron is looked at 
    net.run(1 * msecond)
    assert (len(M.spikes) == 0)
    G.state(0)[:] = array([init, 0., 0.]) # should do nothing, because only first neuron is looked at 
    net.run(1 * msecond)
Esempio n. 10
0
def test():
    """
    :class:`Threshold`
    ~~~~~~~~~~~~~~~~~~
    
    Initialised as ``Threshold(threshold[,state=0])``
    
    Causes a spike whenever the given state variable is above
    the threshold value.
    
    :class:`NoThreshold`
    ~~~~~~~~~~~~~~~~~~~~
    
    Does nothing, initialised as ``NoThreshold()``
    
    Functional thresholds
    ~~~~~~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        FunThreshold(thresholdfun)
        SimpleFunThreshold(thresholdfun[,state=0])
    
    Threshold functions return a boolean array the same size as the
    number of neurons in the group, where if the returned array is
    True at index i then neuron i fires.
    
    The arguments passed to the :class:`FunThreshold` function are the
    full array of state variables for the group in order.
    
    The argument passed to the :class:`SimpleFunThreshold` function is the
    array of length N corresponding to the given state variable.
    
    :class:`VariableThreshold`
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Initialised as ``VariableThreshold(threshold_state[,state=0])``
    
    Causes a spike whenever the state variable defined by state
    is above the state variable defined by threshold_state.
    
    :class:`EmpiricalThreshold`
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        EmpiricalThreshold(threshold[,refractory=1*msecond[,state=0[,clock]]])
    
    Causes a spike when the given state variable exceeds the threshold value,
    but only if there has been no spike within the refractory period. Will
    use the given clock if specified, otherwise the standard guessing procedure
    is used.
    
    Poisson thresholds
    ~~~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        PoissonThreshold([state=0])
        HomogeneousPoissonThreshold([state=0])
    
    The Poisson process gets the rates from the specified state variable, the
    homogeneous version uses the rates from the specified variable of the first
    neuron in the group.      
    """
    reinit_default_clock()

    # test that Threshold works as expected with default state
    G = NeuronGroup(3,
                    model=LazyStateUpdater(),
                    reset=Reset(0.),
                    threshold=Threshold(1.),
                    init=(0., ))
    M = SpikeMonitor(G, True)
    net = Network(G, M)
    net.run(1 * msecond)
    assert (len(M.spikes) == 0)
    G.state(0)[:] = array([0.5, 1.5, 2.5])
    net.run(1 * msecond)
    i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
    assert (i == (1, 2))
    for s in t:
        assert (is_approx_equal(s, 1 * msecond))

    # test that Threshold works as expected with specified state
    def test_specified_state(G):
        M = SpikeMonitor(G, True)
        net = Network(G, M)
        net.run(1 * msecond)
        assert (len(M.spikes) == 0)
        net.reinit()
        G.state(0)[:] = array([0.5, 1.5, 2.5])
        net.run(1 * msecond)
        assert (len(M.spikes) == 0)
        net.reinit()
        G.state(1)[:] = array([0.5, 1.5, 2.5])
        net.run(1 * msecond)
        i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
        assert (i == (1, 2))
        for s in t:
            assert (is_approx_equal(s, 0 * msecond))

    G = NeuronGroup(3,
                    model=LazyStateUpdater(numstatevariables=2),
                    reset=Reset(0., state=1),
                    threshold=Threshold(1., state=1),
                    init=(0., 0.))
    test_specified_state(G)
    # use string threshold
    eqs = '''v : 1
             w : 1
          '''
    G = NeuronGroup(3, model=eqs, reset=Reset(0., state=1), threshold='w > 1')
    test_specified_state(G)

    # test that VariableThreshold works as expected
    def test_variable_threshold(G):
        M = SpikeMonitor(G, True)
        net = Network(G, M)
        get_default_clock().reinit()
        G.state(2)[:] = array([1., 2., 3.])  # the thresholds
        G.state(1)[:] = array([4., 1., 2.])  # the values
        net.run(1 * msecond)
        i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
        assert (i == (0, ))
        assert (is_approx_equal(t[0], 0 * second))

    G = NeuronGroup(3,
                    model=LazyStateUpdater(numstatevariables=3),
                    reset=Reset(0., state=1),
                    threshold=VariableThreshold(2, state=1),
                    init=(0., 0., 0.))
    test_variable_threshold(G)

    # use string threshold
    eqs = '''v : 1
             w : 1
             x : 1
          '''
    G = NeuronGroup(3, model=eqs, reset=Reset(0., state=1), threshold='w > x')
    test_variable_threshold(G)

    # test that FunThreshold works as expected
    def f(S0, S1):
        return S0 > S1 * S1

    G = NeuronGroup(3,
                    model=LazyStateUpdater(numstatevariables=2),
                    reset=Reset(0.),
                    threshold=FunThreshold(f),
                    init=(0., 0.))
    G.state(0)[:] = array([2., 3., 10.])
    G.state(1)[:] = array([1., 2.,
                           3.])  # the square root of the threshold values
    M = SpikeMonitor(G, True)
    net = Network(G, M)
    get_default_clock().reinit()
    net.run(1 * msecond)
    i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
    assert (i == (0, 2))
    for s in t:
        assert (is_approx_equal(s, 0 * msecond))

    # test that SimpleFunThreshold works as expected
    def f(S):
        return S > 1.

    G = NeuronGroup(3,
                    model=LazyStateUpdater(),
                    reset=Reset(0.),
                    threshold=SimpleFunThreshold(f),
                    init=(0., ))
    G.state(0)[:] = array([0.5, 1.5, 2.5])
    M = SpikeMonitor(G, True)
    net = Network(G, M)
    get_default_clock().reinit()
    net.run(1 * msecond)
    i, t = zip(*sorted(M.spikes, key=itemgetter(0)))
    assert (i == (1, 2))
    for s in t:
        assert (is_approx_equal(s, 0 * msecond))

    # test that EmpiricalThreshold works as expected
    G = NeuronGroup(1,
                    model=LazyStateUpdater(numstatevariables=2),
                    reset=NoReset(),
                    threshold=EmpiricalThreshold(1.,
                                                 refractory=0.5 * msecond,
                                                 state=1),
                    init=(0., 2.))
    M = SpikeMonitor(G, True)
    net = Network(G, M)
    get_default_clock().reinit()
    net.run(1.6 * msecond)
    i, t = zip(*sorted(M.spikes, key=itemgetter(1)))
    assert (i == (0, 0, 0, 0))
    for i, s in enumerate(t):
        assert (is_approx_equal(s, i * 0.5 * msecond))

    # test that PoissonThreshold works
    def test_poisson_threshold(G):
        init = float(1. / get_default_clock().dt
                     )  # should cause spiking at every time interval
        G.state(0)[:] = array([0., init, 0.])
        M = SpikeMonitor(G, True)
        net = Network(G, M)
        net.run(1 * msecond)
        assert (len(M.spikes))
        i, t = zip(*sorted(M.spikes, key=itemgetter(1)))
        assert (all(j == 1 for j in i))

    G = NeuronGroup(3,
                    model=LazyStateUpdater(),
                    reset=NoReset(),
                    threshold=PoissonThreshold())
    test_poisson_threshold(G)

    # Poisson threshold via a string threshold using the rand() function
    eqs = '''v : 1
             w : 1
             x : 1
          '''

    # A threshold with rand in it is not supported by CThreshold
    if not (get_global_preference('usecodegen')
            and get_global_preference('usecodegenthreshold')
            and get_global_preference('useweave')
            and get_global_preference('usecodegenweave')):
        G = NeuronGroup(3, model=eqs, reset=NoReset(), threshold='rand() < v')
        test_poisson_threshold(G)

    G = NeuronGroup(3,
                    model=eqs,
                    reset=NoReset(),
                    threshold=StringThreshold('rand() < v'))
    test_poisson_threshold(G)

    # test that HomogeneousPoissonThreshold works
    init = float(
        1. /
        get_default_clock().dt)  # should cause spiking at every time interval
    G = NeuronGroup(3,
                    model=LazyStateUpdater(),
                    reset=NoReset(),
                    threshold=HomogeneousPoissonThreshold())
    M = SpikeMonitor(G, True)
    net = Network(G, M)
    G.state(0)[:] = array(
        [0., init,
         0.])  # should do nothing, because only first neuron is looked at
    net.run(1 * msecond)
    assert (len(M.spikes) == 0)
    G.state(0)[:] = array(
        [init, 0.,
         0.])  # should do nothing, because only first neuron is looked at
    net.run(1 * msecond)
Esempio n. 11
0
def test_construction():
    '''
    :class:`Connection`
    ~~~~~~~~~~~~~~~~~~~
    
    **Initialised as:** ::
    
        Connection(source, target[, state=0[, delay=0*ms]])
    
    With arguments:
    
    ``source``
        The group from which spikes will be propagated.
    ``target``
        The group to which spikes will be propagated.
    ``state``
        The state variable name or number that spikes will be
        propagated to in the target group.
    ``delay``
        The delay between a spike being generated at the source
        and received at the target. At the moment, the mechanism
        for delays only works for relatively short delays (an
        error will be generated for delays that are too long), but
        this is subject to change. The exact behaviour then is
        not part of the assured interface, although it is very
        likely that the syntax will not change (or will at least
        be backwards compatible).
    
    **Methods**
    
    ``connect_random(P,Q,p[,weight=1])``
        Connects each neuron in ``P`` to each neuron in ``Q``.
    ``connect_full(P,Q[,weight=1])``
        Connect every neuron in ``P`` to every neuron in ``Q``.
    ``connect_one_to_one(P,Q)``
        If ``P`` and ``Q`` have the same number of neurons then neuron ``i``
        in ``P`` will be connected to neuron ``i`` in ``Q`` with weight 1.
    
    Additionally, you can directly access the matrix of weights by writing::
    
        C = Connection(P,Q)
        print C[i,j]
        C[i,j] = ...
    
    Where here ``i`` is the source neuron and ``j`` is the target neuron.
    Note: No unit checking is currently done if you use this method,
    but this is subject to change for future releases.

    The behaviour when a list of neuron ``spikes`` is received is to
    add ``W[i,:]`` to the target state variable for each ``i`` in ``spikes``. 
    '''
    reinit_default_clock()

    # test Connection object

    eqs = '''
    da/dt = 0.*hertz : 1.
    db/dt = 0.*hertz : 1.
    '''

    spikes = [(0, 1 * msecond), (1, 3 * msecond)]

    G1 = SpikeGeneratorGroup(2, spikes)
    G2 = NeuronGroup(2, model=eqs, threshold=10., reset=0.)

    # first test the methods
    # connect_full
    C = Connection(G1, G2)
    C.connect_full(G1, G2, weight=2.)
    for i in range(2):
        for j in range(2):
            assert (is_approx_equal(C[i, j], 2.))
    # connect_random
    C = Connection(G1, G2)
    C.connect_random(G1, G2, 0.5, weight=2.)
    # can't assert anything about that
    # connect_one_to_one
    C = Connection(G1, G2)
    C.connect_one_to_one(G1, G2)
    for i in range(2):
        for j in range(2):
            if i == j:
                assert (is_approx_equal(C[i, j], 1.))
            else:
                assert (is_approx_equal(C[i, j], 0.))
    del C
    # and we will use a specific set of connections in the next part
    Ca = Connection(G1, G2, 'a')
    Cb = Connection(G1, G2, 'b')
    Ca[0, 0] = 1.
    Ca[0, 1] = 1.
    Ca[1, 0] = 1.
    #Ca[1,1]=0 by default
    #Cb[0,0]=0 by default
    Cb[0, 1] = 1.
    Cb[1, 0] = 1.
    Cb[1, 1] = 1.
    net = Network(G1, G2, Ca, Cb)
    net.run(2 * msecond)
    # after 2 ms, neuron 0 will have fired, so a 0 and 1 should
    # have increased by 1 to [1,1], and b 1 should have increased
    # by 1 to 1
    assert (is_approx_equal(G2.a[0], 1.))
    assert (is_approx_equal(G2.a[1], 1.))
    assert (is_approx_equal(G2.b[0], 0.))
    assert (is_approx_equal(G2.b[1], 1.))
    net.run(2 * msecond)
    # after 4 ms, neuron 1 will have fired, so a 0 should have
    # increased by 1 to 2, and b 0 and 1 should have increased
    # by 1 to [1, 2]
    assert (is_approx_equal(G2.a[0], 2.))
    assert (is_approx_equal(G2.a[1], 1.))
    assert (is_approx_equal(G2.b[0], 1.))
    assert (is_approx_equal(G2.b[1], 2.))

    reinit_default_clock()
Esempio n. 12
0
def test_construction():
    '''
    :class:`Connection`
    ~~~~~~~~~~~~~~~~~~~
    
    **Initialised as:** ::
    
        Connection(source, target[, state=0[, delay=0*ms]])
    
    With arguments:
    
    ``source``
        The group from which spikes will be propagated.
    ``target``
        The group to which spikes will be propagated.
    ``state``
        The state variable name or number that spikes will be
        propagated to in the target group.
    ``delay``
        The delay between a spike being generated at the source
        and received at the target. At the moment, the mechanism
        for delays only works for relatively short delays (an
        error will be generated for delays that are too long), but
        this is subject to change. The exact behaviour then is
        not part of the assured interface, although it is very
        likely that the syntax will not change (or will at least
        be backwards compatible).
    
    **Methods**
    
    ``connect_random(P,Q,p[,weight=1])``
        Connects each neuron in ``P`` to each neuron in ``Q``.
    ``connect_full(P,Q[,weight=1])``
        Connect every neuron in ``P`` to every neuron in ``Q``.
    ``connect_one_to_one(P,Q)``
        If ``P`` and ``Q`` have the same number of neurons then neuron ``i``
        in ``P`` will be connected to neuron ``i`` in ``Q`` with weight 1.
    
    Additionally, you can directly access the matrix of weights by writing::
    
        C = Connection(P,Q)
        print C[i,j]
        C[i,j] = ...
    
    Where here ``i`` is the source neuron and ``j`` is the target neuron.
    Note: No unit checking is currently done if you use this method,
    but this is subject to change for future releases.

    The behaviour when a list of neuron ``spikes`` is received is to
    add ``W[i,:]`` to the target state variable for each ``i`` in ``spikes``. 
    '''
    reinit_default_clock()

    # test Connection object

    eqs = '''
    da/dt = 0.*hertz : 1.
    db/dt = 0.*hertz : 1.
    '''

    spikes = [(0, 1 * msecond), (1, 3 * msecond)]

    G1 = SpikeGeneratorGroup(2, spikes)
    G2 = NeuronGroup(2, model=eqs, threshold=10., reset=0.)

    # first test the methods
    # connect_full
    C = Connection(G1, G2)
    C.connect_full(G1, G2, weight=2.)
    for i in range(2):
        for j in range(2):
            assert (is_approx_equal(C[i, j], 2.))
    # connect_random
    C = Connection(G1, G2)
    C.connect_random(G1, G2, 0.5, weight=2.)
    # can't assert anything about that
    # connect_one_to_one
    C = Connection(G1, G2)
    C.connect_one_to_one(G1, G2)
    for i in range(2):
        for j in range(2):
            if i == j:
                assert (is_approx_equal(C[i, j], 1.))
            else:
                assert (is_approx_equal(C[i, j], 0.))
    del C
    # and we will use a specific set of connections in the next part
    Ca = Connection(G1, G2, 'a')
    Cb = Connection(G1, G2, 'b')
    Ca[0, 0] = 1.
    Ca[0, 1] = 1.
    Ca[1, 0] = 1.
    #Ca[1,1]=0 by default
    #Cb[0,0]=0 by default
    Cb[0, 1] = 1.
    Cb[1, 0] = 1.
    Cb[1, 1] = 1.
    net = Network(G1, G2, Ca, Cb)
    net.run(2 * msecond)
    # after 2 ms, neuron 0 will have fired, so a 0 and 1 should
    # have increased by 1 to [1,1], and b 1 should have increased
    # by 1 to 1
    assert (is_approx_equal(G2.a[0], 1.))
    assert (is_approx_equal(G2.a[1], 1.))
    assert (is_approx_equal(G2.b[0], 0.))
    assert (is_approx_equal(G2.b[1], 1.))
    net.run(2 * msecond)
    # after 4 ms, neuron 1 will have fired, so a 0 should have
    # increased by 1 to 2, and b 0 and 1 should have increased
    # by 1 to [1, 2]
    assert (is_approx_equal(G2.a[0], 2.))
    assert (is_approx_equal(G2.a[1], 1.))
    assert (is_approx_equal(G2.b[0], 1.))
    assert (is_approx_equal(G2.b[1], 2.))

    reinit_default_clock()
Esempio n. 13
0
def test():
    """
    :class:`Reset`
    ~~~~~~~~~~~~~~
    
    Initialised as::
    
        R = Reset(resetvalue=0*mvolt, state=0)

    After a neuron from a group with this reset fires, it
    will set the specified state variable to the given value.
    State variable 0 is customarily the membrane voltage,
    but this isn't required. 
    
    :class:`FunReset`
    ~~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        R = FunReset(resetfun)
    
    Where resetfun is a function taking two arguments, the group
    it is acting on, and the indices of the spikes to be reset.
    The following is an example reset function::
    
        def f(P,spikeindices):
            P._S[0,spikeindices]=array([i/10. for i in range(len(spikeindices))])    
    
    :class:`Refractoriness`
    ~~~~~~~~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        R = Refractoriness(resetvalue=0*mvolt,period=5*msecond,state=0)
    
    After a neuron from a group with this reset fires, the specified state
    variable of the neuron will be set to the specified resetvalue for the
    specified period.
    
    :class:`NoReset`
    ~~~~~~~~~~~~~~~~
    
    Initialised as::
    
        R = NoReset()
        
    Does nothing.
    """
    reinit_default_clock()

    # test that reset works as expected
    # the setup below is that group G starts with state values (1,1,1,1,1,0,0,0,0,0) threshold
    # value 0.5 (which should be initiated for the first 5 neurons) and reset 0.2 so that the
    # final state should be (0.2,0.2,0.2,0.2,0.2,0,0,0,0,0)
    G = NeuronGroup(10,
                    model=LazyStateUpdater(),
                    reset=Reset(0.2),
                    threshold=Threshold(0.5),
                    init=(0., ))
    G1 = G.subgroup(5)
    G2 = G.subgroup(5)
    G1.state(0)[:] = array([1.] * 5)
    G2.state(0)[:] = array([0.] * 5)
    net = Network(G)
    net.run(1 * msecond)
    assert (all(G1.state(0) < 0.21) and all(0.19 < G1.state(0))
            and all(G2.state(0) < 0.01))

    # recreate the same behaviour with a VariableReset
    eqs = '''
    v : 1
    r : 1
    '''
    G = NeuronGroup(10,
                    model=eqs,
                    reset=VariableReset(resetvaluestate='r', state='v'),
                    threshold=Threshold(0.5))
    G.r = 0.2
    G1 = G.subgroup(5)
    G2 = G.subgroup(5)
    G1.v[:] = array([1.] * 5)
    G2.v[:] = array([0.] * 5)
    net = Network(G)
    net.run(1 * msecond)
    assert (all(G1.state(0) < 0.21) and all(0.19 < G1.state(0))
            and all(G2.state(0) < 0.01))

    # test string reset that resets two variables
    eqs = '''v : 1
             w : 1
          '''
    G = NeuronGroup(2,
                    model=eqs,
                    reset='v = 0; w = -1',
                    threshold=Threshold(0.5))
    G.v = [0.25, 1]
    G.w = [0, 0]
    # only second group crosses threshold
    net = Network(G)
    net.run(defaultclock.dt)
    # Check that the states of the first group are unchanged
    assert (G.v[0] == 0.25 and G.w[0] == 0)
    # Check that the states of the second group are reset correctly
    assert (G.v[1] == 0 and G.w[1] == -1)

    # check that function reset works as expected
    def f(P, spikeindices):
        P._S[0,
             spikeindices] = array([i / 10. for i in range(len(spikeindices))])
        P.called_f = True

    G = NeuronGroup(10,
                    model=LazyStateUpdater(),
                    reset=FunReset(f),
                    threshold=Threshold(2.),
                    init=(3., ))
    G.called_f = False
    net = Network(G)
    net.run(1 * msecond)
    assert (G.called_f)
    for i, v in enumerate(G.state(0)):
        assert (is_approx_equal(i / 10., v))

    # check that refractoriness works as expected
    # the network below should start at V=15, immediately spike as it is above threshold=1,
    # then should be clamped at V=-.5 until t=1ms at which point it should quickly evolve
    # via the DE to a value near 0 (and certainly between -.5 and 0). We test that the
    # value at t=0.5 is exactly -.5 and the value at t=1.5 is between -0.4 and 0.1 (to
    # avoid floating point problems)
    dV = 'dV/dt=-V/(.1*msecond):1.'
    G = NeuronGroup(1,
                    model=dV,
                    threshold=1.,
                    reset=Refractoriness(-.5, 1 * msecond))
    G.V = 15.
    net = Network(G)
    net.run(0.5 * msecond)
    for v in G.state(0):
        assert (is_approx_equal(v, -.5))
    net.run(1 * msecond)
    for v in G.state(0):
        assert (-0.4 < v < 0.1)

    get_default_clock().reinit()
Esempio n. 14
0
def test_spikemonitor():
    '''
    :class:`SpikeMonitor`
    ~~~~~~~~~~~~~~~~~~~~~
    
    Records spikes from a :class:`NeuronGroup`. Initialised as one of::
    
        SpikeMonitor(source(,record=True))
        SpikeMonitor(source,function=function)
    
    Where:
    
    source
        A :class:`NeuronGroup` to record from
    record
        True or False to record all the spikes or just summary
        statistics.
    function
        A function f(spikes) which is passed the array of spikes
        numbers that have fired called each step, to define
        custom spike monitoring.
    
    Has two attributes:
    
    nspikes
        The number of recorded spikes
    spikes
        A time ordered list of pairs (i,t) where neuron i fired
        at time t.
    
    :class:`StateMonitor`
    ~~~~~~~~~~~~~~~~~~~~~
    
    Records the values of a state variable from a :class:`NeuronGroup`.
    Initialise as::
    
        StateMonitor(P,varname(,record=False)
            (,when='end)(,timestep=1)(,clock=clock))
    
    Where:
    
    P
        The group to be recorded from
    varname
        The state variable name or number to be recorded
    record
        What to record. The default value is False and the monitor will
        only record summary statistics for the variable. You can choose
        record=integer to record every value of the neuron with that
        number, record=list of integers to record every value of each of
        those neurons, or record=True to record every value of every
        neuron (although beware that this may use a lot of memory).
    when
        When the recording should be made in the :class:`Network` update, possible
        values are any of the strings: 'start', 'before_groups', 'after_groups',
        'before_connections', 'after_connections', 'before_resets',
        'after_resets', 'end' (in order of when they are run).
    timestep
        A recording will be made each timestep clock updates (so timestep
        should be an integer).
    clock
        A clock for the update schedule, use this if you have specified a
        clock other than the default one in your network, or to update at a
        lower frequency than the update cycle. Note though that if the clock
        here is different from the main clock, the when parameter will not
        be taken into account, as network updates are done clock by clock.
        Use the timestep parameter if you need recordings to be made at a
        precise point in the network update step.

    The :class:`StateMonitor` object has the following properties:

    times
        The times at which recordings were made
    mean
        The mean value of the state variable for every neuron in the
        group (not just the ones specified in the record keyword)
    var
        The unbiased estimate of the variances, as in mean
    std
        The square root of var, as in mean
        
    In addition, if M is a :class:`StateMonitor` object, you write::
    
        M[i]
    
    for the recorded values of neuron i (if it was specified with the
    record keyword). It returns an array object.
    
    Others
    ~~~~~~
    
    The following monitors also exist, but are not part of the
    assured interface because their syntax is subject to change. See the documentation
    for each class for more details.
    
    * :class:`Monitor` (base class)
    * :class:`ISIHistogramMonitor`
    * :class:`FileSpikeMonitor`
    * :class:`PopulationRateMonitor`
    '''
    reinit_default_clock()

    # test that SpikeMonitor retrieves the spikes generator by SpikeGeneratorGroup

    spikes = [(0, 3 * ms), (1, 4 * ms), (0, 7 * ms)]

    G = SpikeGeneratorGroup(2, spikes, clock=defaultclock)
    M = SpikeMonitor(G)
    net = Network(G, M)
    net.run(10 * ms)

    assert (M.nspikes == 3)
    for (mi, mt), (i, t) in zip(M.spikes, spikes):
        assert (mi == i)
        assert (is_approx_equal(mt, t))

    # test that the spiketimes are saved and accessed correctly

    assert (len(M[0]) == len(M.spiketimes[0]) == 2
            and len(M[1]) == len(M.spiketimes[1]) == 1)
    assert ((M.spiketimes[0] == M[0]).all()
            and (M.spiketimes[1] == M[1]).all())

    # test that spiketimes are cleared on reinit

    M.reinit()
    assert (M.nspikes == 0)
    assert (len(M.spikes) == 0)
    assert (len(M[0]) == 0 and len(M[1]) == 0)
    assert (len(M.spiketimes[0]) == 0 and len(M.spiketimes[1]) == 0)

    # test that SpikeMonitor function calling usage does what you'd expect

    f_spikes = []

    def f(spikes):
        if len(spikes):
            f_spikes.extend(spikes)

    G = SpikeGeneratorGroup(2, spikes, clock=defaultclock)
    M = SpikeMonitor(G, function=f)
    net = Network(G, M)
    reinit_default_clock()
    net.run(10 * ms)
    assert (f_spikes == [0, 1, 0])

    # test that SpikeMonitors in MultiConnection objects do reinitialize
    # properly
    G = SpikeGeneratorGroup(2, spikes, clock=defaultclock)
    G2 = NeuronGroup(1, model='dv/dt = -v / (5*ms) : 1')
    C = Connection(G, G2, 'v', weight=0)
    M = SpikeMonitor(G)
    # Note: Because M and C share the source (G), they are replaced by a
    #       MultiConnection
    net = Network(G, G2, C, M)
    net.run(10 * ms)

    net.reinit()  # make sure that the reinit propagates to the SpikeMonitor
    assert (M.nspikes == 0)
    assert (len(M.spikes) == 0)
    assert (len(M[0]) == 0 and len(M[1]) == 0)
    assert (len(M.spiketimes[0]) == 0 and len(M.spiketimes[1]) == 0)

    # test interface for StateMonitor object

    dV = 'dV/dt = 0*Hz : 1.'
    G = NeuronGroup(3, model=dV, reset=0., threshold=10.)

    @network_operation(when='start')
    def f(clock):
        if clock.t >= 1 * ms:
            G.V = [1., 2., 3.]

    M1 = StateMonitor(G, 'V')
    M2 = StateMonitor(G, 'V', record=0)
    M3 = StateMonitor(G, 'V', record=[0, 1])
    M4 = StateMonitor(G, 'V', record=True)
    reinit_default_clock()
    net = Network(G, f, M1, M2, M3, M4)
    net.run(2 * ms)
    assert (is_within_absolute_tolerance(M2[0][0], 0.))
    assert (is_within_absolute_tolerance(M2[0][-1], 1.))
    assert (is_within_absolute_tolerance(M3[1][0], 0.))
    assert (is_within_absolute_tolerance(M3[1][-1], 2.))
    assert (is_within_absolute_tolerance(M4[2][0], 0.))
    assert (is_within_absolute_tolerance(M4[2][-1], 3.))
    assert_raises(IndexError, M1.__getitem__, 0)
    assert_raises(IndexError, M2.__getitem__, 1)
    assert_raises(IndexError, M3.__getitem__, 2)
    assert_raises(IndexError, M4.__getitem__, 3)
    for M in [M3, M4]:
        assert (is_within_absolute_tolerance(
            float(max(abs(M.times - M2.times))), float(0 * ms)))
        assert (is_within_absolute_tolerance(
            float(max(abs(M.times_ - M2.times_))), 0.))
    assert (is_within_absolute_tolerance(float(M2.times[0]), float(0 * ms)))
    d = diff(M2.times)
    assert (is_within_absolute_tolerance(max(d), min(d)))
    assert (is_within_absolute_tolerance(float(max(d)),
                                         float(get_default_clock().dt)))
    # construct unbiased estimator from variances of recorded arrays
    v = array([var(M4[0]), var(M4[1]), var(M4[2])]) * float(len(
        M4[0])) / float(len(M4[0]) - 1)
    m = array([0.5, 1.0, 1.5])
    assert (is_within_absolute_tolerance(abs(max(M1.mean - m)), 0.))
    assert (is_within_absolute_tolerance(abs(max(M1.var - v)), 0.))
    assert (is_within_absolute_tolerance(abs(max(M1.std - v**0.5)), 0.))

    # test when, timestep, clock for StateMonitor
    c = Clock(dt=0.1 * ms)
    cslow = Clock(dt=0.2 * ms)
    dV = 'dV/dt = 0*Hz : 1.'
    G = NeuronGroup(1, model=dV, reset=0., threshold=1., clock=c)

    @network_operation(when='start', clock=c)
    def f():
        G.V = 2.

    M1 = StateMonitor(G, 'V', record=True, clock=cslow)
    M2 = StateMonitor(G, 'V', record=True, timestep=2, clock=c)
    M3 = StateMonitor(G, 'V', record=True, when='before_groups', clock=c)
    net = Network(G, f, M1, M2, M3, M4)
    net.run(2 * ms)
    print M1[0], M3[0]
    assert (2 * len(M1[0]) == len(M3[0]))
    assert (len(M1[0]) == len(M2[0]))
    for i in range(len(M1[0])):
        assert (is_within_absolute_tolerance(M1[0][i], M2[0][i]))
        assert (is_within_absolute_tolerance(M1[0][i], 0.))
    for x in M3[0]:
        assert (is_within_absolute_tolerance(x, 2.))

    reinit_default_clock()  # for next test