def test_network_operations(): # test NetworkOperation and network_operation seq = [] def f1(): seq.append('a') op1 = NetworkOperation(f1, when='start', order=1) @network_operation def f2(): seq.append('b') @network_operation(when='end', order=1) def f3(): seq.append('c') # In complex frameworks, network operations might be object methods that # access some common data class Container(object): def __init__(self): self.g1_data = 'B' self.g2_data = 'C' def g1(self): seq.append(self.g1_data) def g2(self): seq.append(self.g2_data) c = Container() c_op1 = NetworkOperation(c.g1) c_op2 = NetworkOperation(c.g2, when='end', order=1) net = Network(op1, f2, f3, c_op1, c_op2) net.run(1*ms) assert_equal(''.join(seq), 'bBacC'*10)
def run_network(traj): """Runs brian network consisting of 200 inhibitory IF neurons""" eqs = ''' dv/dt=(v0-v)/(5*ms) : volt (unless refractory) v0 : volt ''' group = NeuronGroup(100, model=eqs, threshold='v>10 * mV', reset='v = 0*mV', refractory=5*ms) group.v0 = traj.par.v0 group.v = np.random.rand(100) * 10.0 * mV syn = Synapses(group, group, on_pre='v-=1*mV') syn.connect('i != j', p=0.2) spike_monitor = SpikeMonitor(group, variables=['v']) voltage_monitor = StateMonitor(group, 'v', record=True) pop_monitor = PopulationRateMonitor(group, name='pop' + str(traj.v_idx)) net = Network(group, syn, spike_monitor, voltage_monitor, pop_monitor) net.run(0.25*second, report='text') traj.f_add_result(Brian2MonitorResult, 'spikes', spike_monitor) traj.f_add_result(Brian2MonitorResult, 'v', voltage_monitor) traj.f_add_result(Brian2MonitorResult, 'pop', pop_monitor)
def test_incorrect_dt_custom_clock(): clock = Clock(dt=0.5*ms) G = NeuronGroup(1, 'dv/dt = -v / (10*ms) : 1', clock=clock) net = Network(G) net.run(0.5*ms) clock.dt = 1*ms assert_raises(ValueError, lambda: net.run(0*ms))
def test_incorrect_dt_defaultclock(): defaultclock.dt = 0.5*ms G = NeuronGroup(1, 'dv/dt = -v / (10*ms) : 1') net = Network(G) net.run(0.5*ms) defaultclock.dt = 1*ms assert_raises(ValueError, lambda: net.run(0*ms))
def test_incorrect_dt_custom_clock(): clock = Clock(dt=0.5 * ms) G = NeuronGroup(1, 'dv/dt = -v / (10*ms) : 1', clock=clock) net = Network(G) net.run(0.5 * ms) clock.dt = 1 * ms assert_raises(ValueError, lambda: net.run(0 * ms))
def test_incorrect_dt_defaultclock(): defaultclock.dt = 0.5 * ms G = NeuronGroup(1, 'dv/dt = -v / (10*ms) : 1') net = Network(G) net.run(0.5 * ms) defaultclock.dt = 1 * ms assert_raises(ValueError, lambda: net.run(0 * ms))
def run_old_algorithm(params, network_objs): monitors = network_objs["monitors"] network_objs.pop("monitors") network_objs.update(monitors) @network_operation(dt=params["rate_interval"], order=1) def local_update(t): if t/ms == 0: # if this is t = 0, skip the computation return firing_rates = network_objs["Pi"].A / (params["rate_interval"] / second) network_objs["Pi"].A = 0 # apply the rate sensor to the single firing rates firing_rates = rate_sensor(firing_rates, params["x_NI"], params["sigma_s"]) temp_w_holder = np.array(network_objs["con_ei"].w) for neuron_idx in np.arange(params["NI"]): delta_w = params["eta"] * (firing_rates[neuron_idx] - params["rho_0"]) idxes = params["ei_conn_mat"][:,0] == neuron_idx temp_w_holder[idxes] += delta_w # set below 0 weights to zero. temp_w_holder = clip(temp_w_holder, params["wmin"], params["wmax"]) network_objs["con_ei"].w = temp_w_holder network_objs["local_update"] = local_update net = Network(list(set(network_objs.values()))) net.run(params["simtime"], report="stdout", profile= params["do_profiling"], namespace = params)
def test_network_different_clocks(): NameLister.updates[:] = [] # Check that a network with two different clocks functions correctly x = NameLister(name='x', dt=1*ms, order=0) y = NameLister(name='y', dt=3*ms, order=1) net = Network(x, y) net.run(10*ms) assert_equal(''.join(NameLister.updates), 'xyxxxyxxxyxxxy')
def test_network_different_when(): # Check that a network with different when attributes functions correctly NameLister.updates[:] = [] x = NameLister(name='x', when='start') y = NameLister(name='y', when='end') net = Network(x, y) net.run(0.3*ms) assert_equal(''.join(NameLister.updates), 'xyxyxy')
def test_progress_report_incorrect(): ''' Test wrong use of the report option ''' G = NeuronGroup(1, '') net = Network(G) assert_raises(ValueError, lambda: net.run(1*ms, report='unknown')) assert_raises(TypeError, lambda: net.run(1*ms, report=object()))
def test_profile_ipython_html(): G = NeuronGroup(10, 'dv/dt = -v / (10*ms) : 1', threshold='v>1', reset='v=0', name='profile_test') G.v = 1.1 net = Network(G) net.run(1*ms, profile=True) summary = profiling_summary(net) assert len(summary._repr_html_())
def test_network_t(): # test that Network.t works as expected c1 = Clock(dt=1 * ms) c2 = Clock(dt=2 * ms) x = Counter(when=c1) y = Counter(when=c2) net = Network(x, y) net.run(4 * ms) assert_equal(c1.t, 4 * ms) assert_equal(c2.t, 4 * ms) assert_equal(net.t, 4 * ms) net.run(1 * ms) assert_equal(c1.t, 5 * ms) assert_equal(c2.t, 6 * ms) assert_equal(net.t, 5 * ms) assert_equal(x.count, 5) assert_equal(y.count, 3) net.run(0.5 * ms) # should only update x assert_equal(c1.t, 6 * ms) assert_equal(c2.t, 6 * ms) assert_equal(net.t, 5.5 * ms) assert_equal(x.count, 6) assert_equal(y.count, 3) net.run(0.5 * ms) # shouldn't do anything assert_equal(c1.t, 6 * ms) assert_equal(c2.t, 6 * ms) assert_equal(net.t, 6 * ms) assert_equal(x.count, 6) assert_equal(y.count, 3) net.run(0.5 * ms) # should update x and y assert_equal(c1.t, 7 * ms) assert_equal(c2.t, 8 * ms) assert_equal(net.t, 6.5 * ms) assert_equal(x.count, 7) assert_equal(y.count, 4) del c1, c2, x, y, net # now test with magic run c1 = Clock(dt=1 * ms) c2 = Clock(dt=2 * ms) x = Counter(when=c1) y = Counter(when=c2) run(4 * ms) assert_equal(c1.t, 4 * ms) assert_equal(c2.t, 4 * ms) assert_equal(x.count, 4) assert_equal(y.count, 2) run(4 * ms) assert_equal(c1.t, 8 * ms) assert_equal(c2.t, 8 * ms) assert_equal(x.count, 8) assert_equal(y.count, 4) run(1 * ms) assert_equal(c1.t, 9 * ms) assert_equal(c2.t, 10 * ms) assert_equal(x.count, 9) assert_equal(y.count, 5)
def test_network_t(): # test that Network.t works as expected c1 = Clock(dt=1*ms) c2 = Clock(dt=2*ms) x = Counter(when=c1) y = Counter(when=c2) net = Network(x, y) net.run(4*ms) assert_equal(c1.t, 4*ms) assert_equal(c2.t, 4*ms) assert_equal(net.t, 4*ms) net.run(1*ms) assert_equal(c1.t, 5*ms) assert_equal(c2.t, 6*ms) assert_equal(net.t, 5*ms) assert_equal(x.count, 5) assert_equal(y.count, 3) net.run(0.5*ms) # should only update x assert_equal(c1.t, 6*ms) assert_equal(c2.t, 6*ms) assert_equal(net.t, 5.5*ms) assert_equal(x.count, 6) assert_equal(y.count, 3) net.run(0.5*ms) # shouldn't do anything assert_equal(c1.t, 6*ms) assert_equal(c2.t, 6*ms) assert_equal(net.t, 6*ms) assert_equal(x.count, 6) assert_equal(y.count, 3) net.run(0.5*ms) # should update x and y assert_equal(c1.t, 7*ms) assert_equal(c2.t, 8*ms) assert_equal(net.t, 6.5*ms) assert_equal(x.count, 7) assert_equal(y.count, 4) del c1, c2, x, y, net # now test with magic run c1 = Clock(dt=1*ms) c2 = Clock(dt=2*ms) x = Counter(when=c1) y = Counter(when=c2) run(4*ms) assert_equal(c1.t, 4*ms) assert_equal(c2.t, 4*ms) assert_equal(x.count, 4) assert_equal(y.count, 2) run(4*ms) assert_equal(c1.t, 8*ms) assert_equal(c2.t, 8*ms) assert_equal(x.count, 8) assert_equal(y.count, 4) run(1*ms) assert_equal(c1.t, 9*ms) assert_equal(c2.t, 10*ms) assert_equal(x.count, 9) assert_equal(y.count, 5)
def test_network_different_clocks(): NameLister.updates[:] = [] # Check that a network with two different clocks functions correctly x = NameLister(name='x', dt=.1 * ms, order=0) y = NameLister(name='y', dt=1 * ms, order=1) net = Network(x, y) net.run(100 * second + defaultclock.dt, report='text') updates = ''.join(NameLister.updates)[2:] # ignore the first time step assert updates == ('xxxxxxxxxxy' * 100000)
def test_network_different_clocks(): # Check that a network with two different clocks functions correctly clock1 = Clock(dt=1 * ms) clock3 = Clock(dt=3 * ms) x = NameLister(name='x', when=(clock1, 0)) y = NameLister(name='y', when=(clock3, 1)) net = Network(x, y) net.run(10 * ms) assert_equal(''.join(updates), 'xyxxxyxxxyxxxy')
def test_network_different_clocks(): # Check that a network with two different clocks functions correctly clock1 = Clock(dt=1*ms) clock3 = Clock(dt=3*ms) x = Updater(name='x', when=(clock1, 0)) y = Updater(name='y', when=(clock3, 1)) net = Network(x, y) net.run(10*ms) assert_equal(''.join(updates), 'xyxxxyxxxyxxxy')
def test_network_before_after_schedule(): # Test that before... and after... slot names can be used NameLister.updates[:] = [] x = NameLister(name='x', when='before_resets') y = NameLister(name='y', when='after_thresholds') net = Network(x, y) net.schedule = ['thresholds', 'resets'] net.run(0.3*ms) assert_equal(''.join(NameLister.updates), 'yxyxyx')
def test_network_different_clocks(): NameLister.updates[:] = [] # Check that a network with two different clocks functions correctly x = NameLister(name='x', dt=.1*ms, order=0) y = NameLister(name='y', dt=1*ms, order=1) net = Network(x, y) net.run(100*second+defaultclock.dt, report='text') updates = ''.join(NameLister.updates)[2:] # ignore the first time step assert updates == ('xxxxxxxxxxy'*100000)
def test_defaultclock_dt_changes(): BrianLogger.suppress_name('resolution_conflict') for dt in [0.1*ms, 0.01*ms, 0.5*ms, 1*ms, 3.3*ms]: defaultclock.dt = dt G = NeuronGroup(1, 'v:1') mon = StateMonitor(G, 'v', record=True) net = Network(G, mon) net.run(2*dt) assert_equal(mon.t[:], [0, dt/ms]*ms)
def test_network_copy(): x = Counter() net = Network(x) net2 = Network() for obj in net.objects: net2.add(obj) net2.run(1*ms) assert_equal(x.count, 10) net.run(1*ms) assert_equal(x.count, 20)
def test_network_custom_slots(): # Check that custom slots can be inserted into the schedule NameLister.updates[:] = [] x = NameLister(name='x', when='thresholds') y = NameLister(name='y', when='in_between') z = NameLister(name='z', when='resets') net = Network(x, y, z) net.schedule = ['start', 'groups', 'thresholds', 'in_between', 'synapses', 'resets', 'end'] net.run(0.3*ms) assert_equal(''.join(NameLister.updates), 'xyzxyzxyz')
def test_multiple_runs_defaultclock_incorrect(): defaultclock.dt = 0.1*ms G = NeuronGroup(1, 'dv/dt = -v / (10*ms) : 1') net = Network(G) net.run(0.5*ms) # The new dt is not compatible with the previous time since we cannot # continue at 0.5ms with a dt of 1ms defaultclock.dt = 1*ms assert_raises(ValueError, lambda: net.run(1*ms))
def test_network_copy(): x = Counter() net = Network(x) net2 = Network() for obj in net.objects: net2.add(obj) net2.run(1 * ms) assert_equal(x.count, 10) net.run(1 * ms) assert_equal(x.count, 20)
def test_network_from_dict(): # Check that a network from a dictionary works x = Counter() y = Counter() d = dict(a=x, b=y) net = Network() net.add(d) net.run(1 * ms) assert_equal(len(net.objects), 2) assert_equal(x.count, 10) assert_equal(y.count, 10)
def test_network_from_dict(): # Check that a network from a dictionary works x = Counter() y = Counter() d = dict(a=x, b=y) net = Network() net.add(d) net.run(1*ms) assert_equal(len(net.objects), 2) assert_equal(x.count, 10) assert_equal(y.count, 10)
def test_network_reinit_prepare(): # Check that reinit and prepare work x = Preparer() net = Network(x) assert_equal(x.did_reinit, False) assert_equal(x.did_prepare, False) net.run(1*ms) assert_equal(x.did_reinit, False) assert_equal(x.did_prepare, True) net.reinit() assert_equal(x.did_reinit, True)
def test_multiple_runs_defaultclock(): defaultclock.dt = 0.1*ms G = NeuronGroup(1, 'dv/dt = -v / (10*ms) : 1') net = Network(G) net.run(0.5*ms) # The new dt is not compatible with the previous time but it should not # raise an error because we start a new simulation at time 0 defaultclock.dt = 1*ms G = NeuronGroup(1, 'dv/dt = -v / (10*ms) : 1') net = Network(G) net.run(1*ms)
def test_network_stop(): # test that Network.stop and global stop() work correctly net = Network() x = Stopper(10, net.stop) net.add(x) net.run(10*ms) assert_equal(defaultclock.t, 1*ms) x = Stopper(10, stop) net = Network(x) net.run(10*ms) assert_equal(defaultclock.t, 1*ms)
def test_network_schedule_change(): # Check that a changed schedule is taken into account correctly NameLister.updates[:] = [] x = NameLister(name='x', when='thresholds') y = NameLister(name='y', when='resets') net = Network(x, y) net.run(0.3*ms) assert_equal(''.join(NameLister.updates), 'xyxyxy') NameLister.updates[:] = [] net.schedule = ['start', 'groups', 'synapses', 'resets', 'thresholds', 'end'] net.run(0.3*ms) assert_equal(''.join(NameLister.updates), 'yxyxyx')
def test_network_two_objects(): # Check that a network with two objects and the same clock function correctly x = Counter(order=5) y = Counter(order=6) net = Network() net.add([x, [y]]) # check that a funky way of adding objects work correctly assert_equal(net.objects[0].order, 5) assert_equal(net.objects[1].order, 6) assert_equal(len(net.objects), 2) net.run(1*ms) assert_equal(x.count, 10) assert_equal(y.count, 10)
def test_simple_syntax(): """ Simple example """ set_device('markdown') N = 10 tau = 10 * ms v_th = 0.9 * volt v_rest = -79 * mV eqn = 'dv/dt = (v_th - v)/tau :volt' refractory = 'randn() * tau / N' rates = 'rand() * 5 * Hz' group = NeuronGroup(N, eqn, method='euler', threshold='v > v_th', reset='v = v_rest; v = rand() * v_rest', refractory=refractory, events={'custom': 'v > v_th + 10 * mV', 'custom_1': 'v > v_th - 10 * mV'}) group.run_on_event('custom', 'v = v_rest') group.run_on_event('custom_1', 'v = v_rest - 0.001 * mV') spikegen = SpikeGeneratorGroup(N, [0, 1, 2], [1, 2, 3] * ms, period=5 * ms) po_grp = PoissonGroup(N - 1, rates=rates) syn = Synapses(spikegen, group, model='w :volt', on_pre='v = rand() * w + v_th; v = rand() * w', on_post='v = rand() * w + v_rest; v = rand() * w', delay=tau, method='euler') group.v[:] = v_rest group.v['i%2 == 0'] = 'rand() * v_rest' group.v[0:5] = 'v_rest + 10 * mV' condition = 'abs(i-j)<=5' syn.connect(condition=condition, p=0.999, n=2) syn.w = '1 * mV' net = Network(group, spikegen, po_grp, syn) mon = StateMonitor(syn, 'w', record=True) mon2 = SpikeMonitor(po_grp) mon3 = EventMonitor(group, 'custom') net.add(mon, mon2, mon3) net.run(0.01 * ms) md_str = device.md_text assert _markdown_lint(md_str) check = 'randn({sin({$w$}|$v_rest$ - $v$|/{\tau}})})' assert _markdown_lint(check) # check invalid strings with pytest.raises(SyntaxError): check = '**Initializing values at starting:*' assert _markdown_lint(check) check = '- Variable v$ of with $-79. mV$ to all members' assert _markdown_lint(check) check = 'randn({sin(})})' assert _markdown_lint(check) check = 'randn({sin({$w$}|$v_rest$ - $v$|/{\tau})})' assert _markdown_lint(check) device.reinit()
def test_network_reinit_pre_post_run(): # Check that reinit and before_run and after_run work x = Preparer() net = Network(x) assert_equal(x.did_reinit, False) assert_equal(x.did_pre_run, False) assert_equal(x.did_post_run, False) net.run(1*ms) assert_equal(x.did_reinit, False) assert_equal(x.did_pre_run, True) assert_equal(x.did_post_run, True) net.reinit() assert_equal(x.did_reinit, True)
def test_network_reinit_pre_post_run(): # Check that reinit and before_run and after_run work x = Preparer() net = Network(x) assert_equal(x.did_reinit, False) assert_equal(x.did_pre_run, False) assert_equal(x.did_post_run, False) net.run(1 * ms) assert_equal(x.did_reinit, False) assert_equal(x.did_pre_run, True) assert_equal(x.did_post_run, True) net.reinit() assert_equal(x.did_reinit, True)
def test_synapse_connect_generator(): # connector test 3 start_scope() set_device('exporter', build_on_run=False) tau = 1 * ms eqn = 'dv/dt = (1 - v)/tau :1' Source = NeuronGroup(10, eqn, method='exact', threshold='v>0.9') S1 = Synapses(Source, Source) nett2 = Network(Source, S1) S1.connect(j='k for k in range(0, i+1)') nett2.run(1 * ms) connect3 = device.runs[0]['initializers_connectors'][0] assert connect3['j'] == 'k for k in range(0, i+1)' device.reinit()
def test_store_restore(): source = NeuronGroup(10, '''dv/dt = rates : 1 rates : Hz''', threshold='v>1', reset='v=0') source.rates = 'i*100*Hz' target = NeuronGroup(10, 'v:1') synapses = Synapses(source, target, model='w:1', pre='v+=w', connect='i==j') synapses.w = 'i*1.0' synapses.delay = 'i*ms' state_mon = StateMonitor(target, 'v', record=True) spike_mon = SpikeMonitor(source) net = Network(source, target, synapses, state_mon, spike_mon) net.store() # default time slot net.run(10*ms) net.store('second') net.run(10*ms) v_values = state_mon.v[:, :] spike_indices, spike_times = spike_mon.it_ net.restore() # Go back to beginning assert defaultclock.t == 0*ms assert net.t == 0*ms net.run(20*ms) assert_equal(v_values, state_mon.v[:, :]) assert_equal(spike_indices, spike_mon.i[:]) assert_equal(spike_times, spike_mon.t_[:]) # Go back to middle net.restore('second') assert defaultclock.t == 10*ms assert net.t == 10*ms net.run(10*ms) assert_equal(v_values, state_mon.v[:, :]) assert_equal(spike_indices, spike_mon.i[:]) assert_equal(spike_times, spike_mon.t_[:])
def test_multiple_networks_invalid(): x = Counter() net = Network(x) net.run(1*ms) try: run(1*ms) raise AssertionError('Expected a RuntimeError') except RuntimeError: pass # this is expected try: net2 = Network(x) raise AssertionError('Expected a RuntimeError') except RuntimeError: pass # this is expected
def test_network_remove(): x = Counter() y = Counter() net = Network(x, y) net.remove(y) net.run(1*ms) assert_equal(x.count, 10) assert_equal(y.count, 0) # the relevance of this test is when we use weakref.proxy objects in # Network.objects, we should be able to add and remove these from # the Network just as much as the original objects for obj in copy.copy(net.objects): net.remove(obj) net.run(1*ms) assert_equal(x.count, 10) assert_equal(y.count, 0)
def test_network_reinit_pre_post_run(): # Check that reinit and before_run and after_run work x = Preparer() net = Network(x) assert_equal(x.did_reinit, False) assert_equal(x.did_pre_run, False) assert_equal(x.did_post_run, False) net.run(1 * ms) assert_equal(x.did_reinit, False) assert_equal(x.did_pre_run, True) assert_equal(x.did_post_run, True) net.reinit() assert_equal(x.did_reinit, True) # Make sure that running with "report" works net.run(1 * ms, report='stdout')
def test_profile(): G = NeuronGroup(10, 'dv/dt = -v / (10*ms) : 1', threshold='v>1', reset='v=0', name='profile_test') G.v = 1.1 net = Network(G) net.run(1*ms, profile=True) # The should be four simulated CodeObjects, one for the group and one each # for state update, threshold and reset info = net.profiling_info info_dict = dict(info) assert len(info) == 4 assert 'profile_test' in info_dict assert 'profile_test_stateupdater' in info_dict assert 'profile_test_thresholder' in info_dict assert 'profile_test_resetter' in info_dict assert all([t>=0*second for _, t in info])
def test_network_reinit_pre_post_run(): # Check that reinit and before_run and after_run work x = Preparer() net = Network(x) assert_equal(x.did_reinit, False) assert_equal(x.did_pre_run, False) assert_equal(x.did_post_run, False) net.run(1*ms) assert_equal(x.did_reinit, False) assert_equal(x.did_pre_run, True) assert_equal(x.did_post_run, True) net.reinit() assert_equal(x.did_reinit, True) # Make sure that running with "report" works net.run(1*ms, report='stdout')
def test_continuation(): defaultclock.dt = 1*ms G = NeuronGroup(1, 'dv/dt = -v / (10*ms) : 1') G.v = 1 mon = StateMonitor(G, 'v', record=True) net = Network(G, mon) net.run(2*ms) # Run the same simulation but with two runs that use sub-dt run times G2 = NeuronGroup(1, 'dv/dt = -v / (10*ms) : 1') G2.v = 1 mon2 = StateMonitor(G2, 'v', record=True) net2 = Network(G2, mon2) net2.run(0.5*ms) net2.run(1.5*ms) assert_equal(mon.t[:], mon2.t[:]) assert_equal(mon.v[:], mon2.v[:])
def test_network_remove(): x = Counter() y = Counter() net = Network(x, y) net.remove(y) net.run(1*ms) assert_equal(x.count, 10) assert_equal(y.count, 0) # the relevance of this test is when we use weakref.proxy objects in # Network.objects, we should be able to add and remove these from # the Network just as much as the original objects # TODO: Does this test make sense now that Network does not store weak # references by default? for obj in copy.copy(net.objects): net.remove(obj) net.run(1*ms) assert_equal(x.count, 10) assert_equal(y.count, 0)
def test_synapse_connect_ij(): # connector test 2 start_scope() set_device('exporter', build_on_run=False) tau = 10 * ms eqn = 'dv/dt = (1 - v)/tau :1' my_prob = -1 Source = NeuronGroup(10, eqn, method='exact', threshold='v>0.9') S1 = Synapses(Source, Source) nett = Network(Source, S1) S1.connect(i=[0, 1], j=[1, 2], p='my_prob') nett.run(1 * ms) connect2 = device.runs[0]['initializers_connectors'][0] assert connect2['i'] == [0, 1] assert connect2['j'] == [1, 2] assert connect2['identifiers']['my_prob'] == -1 with pytest.raises(KeyError): connect2['condition'] device.reinit()
def test_network_t(): # test that Network.t works as expected x = Counter(dt=1 * ms) y = Counter(dt=2 * ms) net = Network(x, y) net.run(4 * ms) assert_equal(net.t, 4 * ms) net.run(1 * ms) assert_equal(net.t, 5 * ms) assert_equal(x.count, 5) assert_equal(y.count, 3) net.run(0.5 * ms) # should only update x assert_equal(net.t, 5.5 * ms) assert_equal(x.count, 6) assert_equal(y.count, 3) net.run(0.5 * ms) # shouldn't do anything assert_equal(net.t, 6 * ms) assert_equal(x.count, 6) assert_equal(y.count, 3) net.run(0.5 * ms) # should update x and y assert_equal(net.t, 6.5 * ms) assert_equal(x.count, 7) assert_equal(y.count, 4) del x, y, net # now test with magic run x = Counter(dt=1 * ms) y = Counter(dt=2 * ms) run(4 * ms) assert_equal(magic_network.t, 4 * ms) assert_equal(x.count, 4) assert_equal(y.count, 2) run(4 * ms) assert_equal(magic_network.t, 8 * ms) assert_equal(x.count, 8) assert_equal(y.count, 4) run(1 * ms) assert_equal(magic_network.t, 9 * ms) assert_equal(x.count, 9) assert_equal(y.count, 5)