def test_queryengine_io(self, fn): skip_if_no_external("h5py") from mvpa2.base.hdf5 import h5save, h5load vol_shape = (10, 10, 10, 1) vol_affine = np.identity(4) vg = volgeom.VolGeom(vol_shape, vol_affine) # generate some surfaces, # and add some noise to them sphere_density = 10 outer = surf.generate_sphere(sphere_density) * 5 + 8 inner = surf.generate_sphere(sphere_density) * 3 + 8 radius = 5.0 add_fa = ["center_distances", "grey_matter_position"] qe = disc_surface_queryengine(radius, vg, inner, outer, add_fa=add_fa) ds = fmri_dataset(vg.get_masked_nifti_image()) # the following is not really a strong requirement. XXX remove? assert_raises(ValueError, lambda: qe[qe.ids[0]]) # check that after training it behaves well qe.train(ds) i = qe.ids[0] try: m = qe[i] except ValueError, e: raise AssertionError( "Failed to query %r from %r after training on %r. " "Exception was: %r" % (i, qe, ds, e) )
def test_permutation_analysis(): # Examples that should work for example in permutation_analysis_good_examples: if SANITY_CHECK_PERMUTATION_ANALYSIS_EXAMPLE: try: numerically_check_permutation_code(example) except OrderDependenceError: raise AssertionError(('Test unexpectedly raised a numerical ' 'OrderDependenceError on these ' 'statements:\n') + example) try: check_permutation_code(example) except OrderDependenceError: raise AssertionError(('Test unexpectedly raised an ' 'OrderDependenceError on these ' 'statements:\n') + example) for example in permutation_analysis_bad_examples: if SANITY_CHECK_PERMUTATION_ANALYSIS_EXAMPLE: try: assert_raises(OrderDependenceError, numerically_check_permutation_code, example) except AssertionError: raise AssertionError("Order dependence not raised numerically for example: "+example) try: assert_raises(OrderDependenceError, check_permutation_code, example) except AssertionError: raise AssertionError("Order dependence not raised for example: "+example)
def test_errors(): # No explicit namespace group = SimpleGroup(namespace=None, variables={}) assert_raises(KeyError, lambda: group._resolve('nonexisting_variable', {})) # Empty explicit namespace group = SimpleGroup(namespace={}, variables={}) assert_raises(KeyError, lambda: group._resolve('nonexisting_variable', {}))
def test_linked_synapses(): ''' Test linking to a synaptic variable (should raise an error). ''' G = NeuronGroup(10, '') S = Synapses(G, G, 'w:1', connect=True) G2 = NeuronGroup(100, 'x : 1 (linked)') assert_raises(NotImplementedError, lambda: setattr(G2, 'x', linked_var(S, 'w')))
def test_invalid_custom_event(): group1 = NeuronGroup(2, 'v : 1', events={'custom': 't>=(2-i)*ms and t<(2-i)*ms + dt'}) group2 = NeuronGroup(2, 'v : 1', threshold='v>1') assert_raises(ValueError, lambda: Synapses(group1, group1, pre='v+=1', on_event='spike')) assert_raises(ValueError, lambda: Synapses(group2, group2, pre='v+=1', on_event='custom'))
def test_errors(): # No explicit namespace namespace = create_namespace() assert_raises(KeyError, lambda: namespace['nonexisting_variable']) # Empty explicit namespace namespace = create_namespace({}) assert_raises(KeyError, lambda: namespace['nonexisting_variable'])
def test_locally_constant_check(): default_dt = defaultclock.dt # The linear state update can handle additive time-dependent functions # (e.g. a TimedArray) but only if it can be safely assumed that the function # is constant over a single time check ta0 = TimedArray(np.array([1]), dt=default_dt) # ok ta1 = TimedArray(np.array([1]), dt=2*default_dt) # ok ta2 = TimedArray(np.array([1]), dt=default_dt/2) # not ok ta3 = TimedArray(np.array([1]), dt=default_dt*1.5) # not ok for ta_func, ok in zip([ta0, ta1, ta2, ta3], [True, True, False, False]): # additive G = NeuronGroup(1, 'dv/dt = -v/(10*ms) + ta(t)*Hz : 1', method='linear', namespace={'ta': ta_func}) net = Network(G) if ok: # This should work net.run(0*ms) else: # This should not with catch_logs(): assert_raises(ValueError, lambda: net.run(0*ms)) # multiplicative G = NeuronGroup(1, 'dv/dt = -v*ta(t)/(10*ms) : 1', method='linear', namespace={'ta': ta_func}) net = Network(G) if ok: # This should work net.run(0*ms) else: # This should not with catch_logs(): assert_raises(ValueError, lambda: net.run(0*ms)) # If the argument is more than just "t", we cannot guarantee that it is # actually locally constant G = NeuronGroup(1, 'dv/dt = -v*ta(t/2.0)/(10*ms) : 1', method='linear', namespace={'ta': ta0}) net = Network(G) assert_raises(ValueError, lambda: net.run(0*ms)) # Arbitrary functions are not constant over a time step G = NeuronGroup(1, 'dv/dt = -v/(10*ms) + sin(2*pi*100*Hz*t)*Hz : 1', method='linear') net = Network(G) assert_raises(ValueError, lambda: net.run(0*ms)) # Neither is "t" itself G = NeuronGroup(1, 'dv/dt = -v/(10*ms) + t/second**2 : 1', method='linear') net = Network(G) assert_raises(ValueError, lambda: net.run(0*ms)) # But if the argument is not referring to t, all should be well G = NeuronGroup(1, 'dv/dt = -v/(10*ms) + sin(2*pi*100*Hz*5*second)*Hz : 1', method='linear') net = Network(G) net.run(0*ms)
def test_construction(): BrianLogger.suppress_name('resolution_conflict') morpho = Soma(diameter=30*um) morpho.L = Cylinder(length=10*um, diameter=1*um, n=10) morpho.LL = Cylinder(length=5*um, diameter=2*um, n=5) morpho.LR = Cylinder(length=5*um, diameter=2*um, n=10) morpho.right = Cylinder(length=3*um, diameter=1*um, n=7) morpho.right.nextone = Cylinder(length=2*um, diameter=1*um, n=3) gL=1e-4*siemens/cm**2 EL=-70*mV eqs=''' Im=gL*(EL-v) : amp/meter**2 I : meter (point current) ''' # Check units of currents assert_raises(DimensionMismatchError, lambda: SpatialNeuron(morphology=morpho, model=eqs)) eqs=''' Im=gL*(EL-v) : amp/meter**2 ''' neuron = SpatialNeuron(morphology=morpho, model=eqs, Cm=1 * uF / cm ** 2, Ri=100 * ohm * cm) # Test initialization of values neuron.LL.v = EL assert_allclose(neuron.L.main.v, 0) assert_allclose(neuron.LL.v, EL) neuron.LL[2*um:3.1*um].v = 0*mV assert_allclose(neuron.LL.v, Quantity([EL, 0*mV, 0*mV, EL, EL])) assert_allclose(neuron.Cm, 1 * uF / cm ** 2) # Test morphological variables assert_allclose(neuron.main.x_, morpho.x) assert_allclose(neuron.L.main.x_, morpho.L.x) assert_allclose(neuron.LL.main.x_, morpho.LL.x) assert_allclose(neuron.right.main.x_, morpho.right.x) assert_allclose(neuron.L.main.distance_, morpho.L.distance) assert_allclose(neuron.L.main.diameter_, morpho.L.diameter) assert_allclose(neuron.L.main.area_, morpho.L.area) assert_allclose(neuron.L.main.length_, morpho.L.length) # Check basic consistency of the flattened representation assert len(np.unique(neuron.diffusion_state_updater._morph_i[:])) == len(neuron.diffusion_state_updater._morph_i) assert all(neuron.diffusion_state_updater._ends[:].flat >= neuron.diffusion_state_updater._starts[:].flat) # Check that length and distances make sense after compression assert_allclose(sum(morpho.L.length)*metre, 10*um) assert_allclose(morpho.L.distance*metre, (1 + np.arange(10))*um) assert_allclose(sum(morpho.LL.length)*metre, 5*um) assert_allclose(morpho.LL.distance*metre, 10*um + (1 + np.arange(5))*um) assert_allclose(sum(morpho.LR.length)*metre, 5*um) assert_allclose(morpho.LR.distance*metre, 10*um + (1 + np.arange(10))*0.5*um) assert_allclose(sum(morpho.right.length)*metre, 3*um) assert_allclose(morpho.right.distance*metre, (1 + np.arange(7))*3./7.*um) assert_allclose(sum(morpho.right.nextone.length)*metre, 2*um) assert_allclose(morpho.right.nextone.distance*metre, 3*um+(1 + np.arange(3))*2./3.*um)
def test_unit_errors(): ''' Test that units are checked for a complete namespace. ''' # Unit error in model equations assert_raises(DimensionMismatchError, lambda: NeuronGroup(1, 'dv/dt = -v : 1')) assert_raises(DimensionMismatchError, lambda: NeuronGroup(1, 'dv/dt = -v/(10*ms) + 2*mV: 1'))
def test_allowed_integration(): morph = Soma(diameter=30 * um) EL = -70 * mV gL = 1e-4 * siemens / cm ** 2 ENa = 115 * mV gNa = 120 * msiemens / cm ** 2 VT = -50.4 * mV DeltaT = 2 * mV ENMDA = 0. * mV @check_units(voltage=volt, result=volt) def user_fun(voltage): return voltage # could be an arbitrary function and is therefore unsafe allowed_eqs = ['Im = gL*(EL-v) : amp/meter**2', '''Im = gl * (El-v) + gNa * m**3 * h * (ENa-v) : amp/meter**2 dm/dt = alpham * (1-m) - betam * m : 1 dh/dt = alphah * (1-h) - betah * h : 1 alpham = (0.1/mV) * (-v+25*mV) / (exp((-v+25*mV) / (10*mV)) - 1)/ms : Hz betam = 4 * exp(-v/(18*mV))/ms : Hz alphah = 0.07 * exp(-v/(20*mV))/ms : Hz betah = 1/(exp((-v+30*mV) / (10*mV)) + 1)/ms : Hz''', '''Im = gl * (El-v) : amp/meter**2 I_ext = 1*nA + sin(2*pi*100*Hz*t)*nA : amp (point current)''', '''Im = I_leak + I_spike : amp/meter**2 I_leak = gL*(EL - v) : amp/meter**2 I_spike = gL*DeltaT*exp((v - VT)/DeltaT): amp/meter**2 (constant over dt) ''', ''' Im = gL*(EL-v) : amp/meter**2 I_NMDA = gNMDA*(ENMDA-v)*Mgblock : amp (point current) gNMDA : siemens Mgblock = 1./(1. + exp(-0.062*v/mV)/3.57) : 1 (constant over dt) ''', 'Im = gL*(EL - v) + gL*DeltaT*exp((v - VT)/DeltaT) : amp/meter**2', '''Im = I_leak + I_spike : amp/meter**2 I_leak = gL*(EL - v) : amp/meter**2 I_spike = gL*DeltaT*exp((v - VT)/DeltaT): amp/meter**2 ''', ''' Im = gL*(EL-v) : amp/meter**2 I_NMDA = gNMDA*(ENMDA-v)*Mgblock : amp (point current) gNMDA : siemens Mgblock = 1./(1. + exp(-0.062*v/mV)/3.57) : 1 ''', ] forbidden_eqs = [ '''Im = gl * (El-v + user_fun(v)) : amp/meter**2''', '''Im = gl * clip(El-v, -100*mV, 100*mV) : amp/meter**2''', ] for eqs in allowed_eqs: # Should not raise an error neuron = SpatialNeuron(morph, eqs) for eqs in forbidden_eqs: # Should raise an error assert_raises(TypeError, SpatialNeuron, morph, eqs)
def test_GSL_error_nonODE_variable(): eqs = ''' dv/dt = (v0 - v)/(10*ms) : volt v0 : volt ''' options = {'absolute_error_per_variable': {'v0': 1e-3*mV}} neuron = NeuronGroup(1, eqs, threshold='v > 10*mV', reset='v = 0*mV', method='gsl', method_options=options) net = Network(neuron) assert_raises(KeyError, net.run, 0*ms, namespace={})
def test_GSL_error_dimension_mismatch_dimensionless2(): eqs = ''' dv/dt = (v0 - v)/(10*ms) : volt v0 : volt ''' options = {'absolute_error_per_variable': {'v': 1e-3}} neuron = NeuronGroup(1, eqs, threshold='v > 10*mV', reset='v = 0*mV', method='gsl', method_options=options) net = Network(neuron) assert_raises(DimensionMismatchError, net.run, 0*ms, namespace={})
def test_spikegenerator_incorrect_values(): assert_raises(TypeError, lambda: SpikeGeneratorGroup(0, [], []*second)) # Floating point value for N assert_raises(TypeError, lambda: SpikeGeneratorGroup(1.5, [], []*second)) # Negative index assert_raises(ValueError, lambda: SpikeGeneratorGroup(5, [0, 3, -1], [0, 1, 2]*ms)) # Too high index assert_raises(ValueError, lambda: SpikeGeneratorGroup(5, [0, 5, 1], [0, 1, 2]*ms)) # Negative time assert_raises(ValueError, lambda: SpikeGeneratorGroup(5, [0, 1, 2], [0, -1, 2]*ms))
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")
def test_GSL_fixed_timestep_big_dt_small_error(): # should raise integration error neuron = NeuronGroup(1, model=HH_eqs, threshold='v > -40*mV', refractory='v > -40*mV', method='gsl', method_options={'adaptable_timestep': False, 'absolute_error': 1e-12}, dt=.001*ms, namespace=HH_namespace) neuron.I = 0.7*nA/(20000*umetre**2) neuron.v = HH_namespace['El'] net = Network(neuron) assert_raises((RuntimeError, IntegrationError), net.run, 10*ms)
def test_write_to_subexpression(): variables = { 'a': Subexpression(name='a', dtype=np.float32, owner=FakeGroup(variables={}), device=None, expr='2*z'), 'z': Variable(name='z') } # Writing to a subexpression is not allowed code = 'a = z' assert_raises(SyntaxError, make_statements, code, variables, np.float32)
def test_GSL_stochastic(): tau = 20*ms sigma = .015 eqs = ''' dx/dt = (1.1 - x) / tau + sigma * (2 / tau)**.5 * xi : 1 ''' neuron = NeuronGroup(1, eqs, method='gsl') net = Network(neuron) assert_raises(UnsupportedEquationsException, net.run, 0*ms, namespace={'tau': tau, 'sigma': sigma})
def test_name_clashes(): # Using identical names for synaptic and pre- or post-synaptic variables # is confusing and should be forbidden G1 = NeuronGroup(1, 'a : 1') G2 = NeuronGroup(1, 'b : 1') assert_raises(ValueError, lambda: Synapses(G1, G2, 'a : 1')) assert_raises(ValueError, lambda: Synapses(G1, G2, 'b : 1')) # this should all be ok Synapses(G1, G2, 'c : 1') Synapses(G1, G2, 'a_syn : 1') Synapses(G1, G2, 'b_syn : 1')
def test_clear_cache_cython(): if prefs.codegen.target != 'cython': raise SkipTest('Cython-only test') assert 'cython' in _cache_dirs_and_extensions cache_dir, _ = _cache_dirs_and_extensions['cython'] # Create a file that should not be there fname = os.path.join(cache_dir, 'some_file.py') open(fname, 'w').close() # clear_cache should refuse to clear the directory assert_raises(IOError, clear_cache, 'cython') os.remove(fname)
def test_state_monitor(): G = NeuronGroup(10, 'v : volt') G.v = np.arange(10) * volt SG = G[5:] mon_all = StateMonitor(SG, 'v', record=True) mon_0 = StateMonitor(SG, 'v', record=0) run(defaultclock.dt) assert_allclose(mon_0[0].v, mon_all[0].v) assert_allclose(mon_0[0].v, np.array([5]) * volt) assert_allclose(mon_all.v.flatten(), np.arange(5, 10) * volt) assert_raises(IndexError, lambda: mon_all[5])
def test_linked_var_in_reset_incorrect(): # Raise an error if a scalar variable (linked variable from a group of size # 1 is set in a reset statement of a group with size > 1) G1 = NeuronGroup(1, 'x:1') G2 = NeuronGroup(2, '''x_linked : 1 (linked) y:1''', threshold='y>1', reset='y=0; x_linked += 1') G2.x_linked = linked_var(G1, 'x') G2.y = 1.1 net = Network(G1, G2) # It is not well-defined what x_linked +=1 means in this context # (as for any other shared variable) assert_raises(SyntaxError, lambda: net.run(0*ms))
def test_scalar_subexpression(): G = NeuronGroup(10, '''v : 1 number : 1 (shared)''', threshold='False') S = Synapses(G, G, '''s : 1 (shared) sub = number_post + s : 1 (shared)''', pre='v+=s', connect=True) S.s = 100 G.number = 50 assert S.sub[:] == 150 assert_raises(SyntaxError, lambda: Synapses(G, G, '''s : 1 (shared) sub = v_post + s : 1 (shared)''', pre='v+=s', connect=True))
def test_surface_outside_volume_voxel_selection(self, fn): skip_if_no_external('h5py') from mvpa2.base.hdf5 import h5save, h5load vol_shape = (10, 10, 10, 1) vol_affine = np.identity(4) vg = volgeom.VolGeom(vol_shape, vol_affine) # make surfaces that are far away from all voxels # in the volume sphere_density = 4 far = 10000. outer = surf.generate_sphere(sphere_density) * 10 + far inner = surf.generate_sphere(sphere_density) * 5 + far vs = volsurf.VolSurfMaximalMapping(vg, inner, outer) radii = [10., 10] # fixed and variable radii outside_node_margins = [0, far, True] for outside_node_margin in outside_node_margins: for radius in radii: selector = lambda: surf_voxel_selection.voxel_selection(vs, radius, outside_node_margin=outside_node_margin) if type(radius) is int and outside_node_margin is True: assert_raises(ValueError, selector) else: sel = selector() if outside_node_margin is True: # it should have all the keys, but they should # all be empty assert_array_equal(sel.keys(), range(inner.nvertices)) for k, v in sel.iteritems(): assert_equal(v, []) else: assert_array_equal(sel.keys(), []) if outside_node_margin is True and \ externals.versions['hdf5'] < '1.8.7': raise SkipTest("Versions of hdf5 before 1.8.7 have " "problems with empty arrays") h5save(fn, sel) sel_copy = h5load(fn) assert_array_equal(sel.keys(), sel_copy.keys()) for k in sel.keys(): assert_equal(sel[k], sel_copy[k]) assert_equal(sel, sel_copy)
def test_state_monitor_record_single_timestep(): G = NeuronGroup(1, 'dv/dt = -v/(5*ms) : 1') G.v = 1 mon = StateMonitor(G, 'v', record=True) # Recording before a run should not work assert_raises(TypeError, lambda: mon.record_single_timestep()) run(0.5*ms) mon.record_single_timestep() device.build(direct_call=False, **device.build_options) assert mon.t[0] == 0*ms assert mon[0].v[0] == 1 assert_allclose(mon.t[-1], 0.5*ms) assert len(mon.t) == 6 assert mon[0].v[-1] == G.v
def test_state_monitor_indexing(): # Check indexing semantics G = NeuronGroup(10, 'v:volt') G.v = np.arange(10) * volt mon = StateMonitor(G, 'v', record=[5, 6, 7]) run(2 * defaultclock.dt) assert_array_equal(mon.v, np.array([[5, 5], [6, 6], [7, 7]]) * volt) assert_array_equal(mon.v_, np.array([[5, 5], [6, 6], [7, 7]])) assert_array_equal(mon[5].v, mon.v[0]) assert_array_equal(mon[7].v, mon.v[2]) assert_array_equal(mon[[5, 7]].v, mon.v[[0, 2]]) assert_array_equal(mon[np.array([5, 7])].v, mon.v[[0, 2]]) assert_allclose(mon.t[1:], Quantity([defaultclock.dt])) assert_raises(IndexError, lambda: mon[8]) assert_raises(TypeError, lambda: mon['string']) assert_raises(TypeError, lambda: mon[5.0]) assert_raises(TypeError, lambda: mon[[5.0, 6.0]])
def test_delay_specification(): # By default delays are state variables (i.e. arrays), but if they are # specified in the initializer, they are scalars. G = NeuronGroup(10, 'v:1', threshold='False') # Array delay S = Synapses(G, G, 'w:1', pre='v+=w') S.connect('i==j') assert len(S.delay[:]) == len(G) S.delay = 'i*ms' assert_equal(S.delay[:], np.arange(len(G))*ms) S.delay = 5*ms assert_equal(S.delay[:], np.ones(len(G))*5*ms) # Scalar delay S = Synapses(G, G, 'w:1', pre='v+=w', delay=5*ms) assert_equal(S.delay[:], 5*ms) S.connect('i==j') S.delay = 10*ms assert_equal(S.delay[:], 10*ms) # S.delay = '3*ms' # assert_equal(S.delay[:], 3*ms) # Invalid arguments assert_raises(DimensionMismatchError, lambda: Synapses(G, G, 'w:1', pre='v+=w', delay=5*mV)) assert_raises(TypeError, lambda: Synapses(G, G, 'w:1', pre='v+=w', delay=object())) assert_raises(ValueError, lambda: Synapses(G, G, 'w:1', delay=5*ms)) assert_raises(ValueError, lambda: Synapses(G, G, 'w:1', pre='v+=w', delay={'post': 5*ms}))
def test_state_variables(): ''' Test the setting and accessing of state variables in subgroups. ''' for codeobj_class in codeobj_classes: G = NeuronGroup(10, 'v : volt', codeobj_class=codeobj_class) SG = G[4:9] assert_raises(DimensionMismatchError, lambda: SG.__setattr__('v', -70)) SG.v_ = float(-80*mV) assert_allclose(G.v, np.array([0, 0, 0, 0, -80, -80, -80, -80, -80, 0])*mV) assert_allclose(SG.v, np.array([-80, -80, -80, -80, -80])*mV) assert_allclose(G.v_, np.array([0, 0, 0, 0, -80, -80, -80, -80, -80, 0])*mV) assert_allclose(SG.v_, np.array([-80, -80, -80, -80, -80])*mV) # You should also be able to set variables with a string SG.v = 'v + i*mV' assert_allclose(SG.v[0], -80*mV) assert_allclose(SG.v[4], -76*mV) assert_allclose(G.v[4:9], -80*mV + np.arange(5)*mV) # Calculating with state variables should work too assert all(G.v[4:9] - SG.v == 0) # And in-place modification should work as well SG.v += 10*mV assert_allclose(G.v[4:9], -70*mV + np.arange(5)*mV) SG.v *= 2 assert_allclose(G.v[4:9], 2*(-70*mV + np.arange(5)*mV)) # with unit checking assert_raises(DimensionMismatchError, lambda: SG.v.__iadd__(3*second)) assert_raises(DimensionMismatchError, lambda: SG.v.__iadd__(3)) assert_raises(DimensionMismatchError, lambda: SG.v.__imul__(3*second))
def test_delay_specification(): # By default delays are state variables (i.e. arrays), but if they are # specified in the initializer, they are scalars. G = NeuronGroup(10, 'v:1') # Array delay S = Synapses(G, G, 'w:1', pre='v+=w') S.connect('i==j') assert len(S.delay[:]) == len(G) S.delay = 'i*ms' assert_equal(S.delay[:], np.arange(len(G))*ms) S.delay = 5*ms assert_equal(S.delay[:], np.ones(len(G))*5*ms) # Scalar delay S = Synapses(G, G, 'w:1', pre='v+=w', delay=5*ms) S.connect('i==j') S.delay = 10*ms assert_equal(S.delay[:], 10*ms) S.delay = '3*ms' assert_equal(S.delay[:], 3*ms) # TODO: Assignment with strings or arrays is currently possible, it only # takes into account the first value # Invalid arguments assert_raises(DimensionMismatchError, lambda: Synapses(G, G, 'w:1', pre='v+=w', delay=5*mV)) assert_raises(TypeError, lambda: Synapses(G, G, 'w:1', pre='v+=w', delay=object())) assert_raises(ValueError, lambda: Synapses(G, G, 'w:1', delay=5*ms)) assert_raises(ValueError, lambda: Synapses(G, G, 'w:1', pre='v+=w', delay={'post': 5*ms}))
def test_state_variable_access(): for codeobj_class in codeobj_classes: G = NeuronGroup(10, 'v:volt', codeobj_class=codeobj_class) G.v = np.arange(10) * volt assert_equal(np.asarray(G.v[:]), np.arange(10)) assert have_same_dimensions(G.v[:], volt) assert_equal(np.asarray(G.v[:]), G.v_[:]) # Accessing single elements, slices and arrays assert G.v[5] == 5 * volt assert G.v_[5] == 5 assert_equal(G.v[:5], np.arange(5) * volt) assert_equal(G.v_[:5], np.arange(5)) assert_equal(G.v[[0, 5]], [0, 5] * volt) assert_equal(G.v_[[0, 5]], np.array([0, 5])) # Illegal indexing assert_raises(IndexError, lambda: G.v[0, 0]) assert_raises(IndexError, lambda: G.v_[0, 0]) assert_raises(TypeError, lambda: G.v[object()]) assert_raises(TypeError, lambda: G.v_[object()]) # A string representation should not raise any error assert len(str(G.v)) assert len(repr(G.v)) assert len(str(G.v_)) assert len(repr(G.v_))
def test_state_variable_indexing(): G1 = NeuronGroup(5, 'v:volt') G1.v = 'i*mV' G2 = NeuronGroup(7, 'v:volt') G2.v= '10*mV + i*mV' S = Synapses(G1, G2, 'w:1') S.connect(True, n=2) S.w[:, :, 0] = '5*i + j' S.w[:, :, 1] = '35 + 5*i + j' #Slicing assert len(S.w[:]) == len(S.w[:, :]) == len(S.w[:, :, :]) == len(G1)*len(G2)*2 assert len(S.w[0:, 0:]) == len(S.w[0:, 0:, 0:]) == len(G1)*len(G2)*2 assert len(S.w[0::2, 0:]) == 3*len(G2)*2 assert len(S.w[0, :]) == len(S.w[0, :, :]) == len(G2)*2 assert len(S.w[0:2, :]) == len(S.w[0:2, :, :]) == 2*len(G2)*2 assert len(S.w[:2, :]) == len(S.w[:2, :, :]) == 2*len(G2)*2 assert len(S.w[0:4:2, :]) == len(S.w[0:4:2, :, :]) == 2*len(G2)*2 assert len(S.w[:4:2, :]) == len(S.w[:4:2, :, :]) == 2*len(G2)*2 assert len(S.w[:, 0]) == len(S.w[:, 0, :]) == len(G1)*2 assert len(S.w[:, 0:2]) == len(S.w[:, 0:2, :]) == 2*len(G1)*2 assert len(S.w[:, :2]) == len(S.w[:, :2, :]) == 2*len(G1)*2 assert len(S.w[:, 0:4:2]) == len(S.w[:, 0:4:2, :]) == 2*len(G1)*2 assert len(S.w[:, :4:2]) == len(S.w[:, :4:2, :]) == 2*len(G1)*2 assert len(S.w[:, :, 0]) == len(G1)*len(G2) assert len(S.w[:, :, 0:2]) == len(G1)*len(G2)*2 assert len(S.w[:, :, :2]) == len(G1)*len(G2)*2 assert len(S.w[:, :, 0:2:2]) == len(G1)*len(G2) assert len(S.w[:, :, :2:2]) == len(G1)*len(G2) # 1d indexing is directly indexing synapses! assert len(S.w[:]) == len(S.w[0:]) assert len(S.w[[0, 1]]) == len(S.w[3:5]) == 2 assert len(S.w[:]) == len(S.w[np.arange(len(G1)*len(G2)*2)]) #Array-indexing (not yet supported for synapse index) assert_equal(S.w[:, 0:3], S.w[:, [0, 1, 2]]) assert_equal(S.w[:, 0:3], S.w[np.arange(len(G1)), [0, 1, 2]]) #string-based indexing assert_equal(S.w[0:3, :], S.w['i<3']) assert_equal(S.w[:, 0:3], S.w['j<3']) # TODO: k is not working yet # assert_equal(S.w[:, :, 0], S.w['k==0']) assert_equal(S.w[0:3, :], S.w['v_pre < 3*mV']) assert_equal(S.w[:, 0:3], S.w['v_post < 13*mV']) #invalid indices assert_raises(IndexError, lambda: S.w.__getitem__((1, 2, 3, 4))) assert_raises(IndexError, lambda: S.w.__getitem__(object()))
def test_spikegenerator_incorrect_period(): ''' Test that you cannot provide incorrect period arguments or combine inconsistent period and dt arguments. ''' # Period is negative assert_raises(ValueError, lambda: SpikeGeneratorGroup(1, [], []*second, period=-1*ms)) # Period is smaller than the highest spike time assert_raises(ValueError, lambda: SpikeGeneratorGroup(1, [0], [2]*ms, period=1*ms)) # Period is not an integer multiple of dt SG = SpikeGeneratorGroup(1, [], []*second, period=1.25*ms, dt=0.1*ms) net = Network(SG) assert_raises(NotImplementedError, lambda: net.run(0*ms)) # Period is smaller than dt SG = SpikeGeneratorGroup(1, [], []*second, period=1*ms, dt=2*ms) net = Network(SG) assert_raises(ValueError, lambda: net.run(0*ms))
def test_poissoninput_errors(): # Targeting non-existing variable G = NeuronGroup(10, '''x : volt y : 1''') assert_raises(KeyError, lambda: PoissonInput(G, 'z', 100, 100 * Hz, weight=1.0)) # Incorrect units assert_raises(DimensionMismatchError, lambda: PoissonInput(G, 'x', 100, 100 * Hz, weight=1.0)) assert_raises( DimensionMismatchError, lambda: PoissonInput(G, 'y', 100, 100 * Hz, weight=1.0 * volt)) # dt change old_dt = defaultclock.dt inp = PoissonInput(G, 'x', 100, 100 * Hz, weight=1 * volt) defaultclock.dt = 2 * old_dt net = Network(collect()) assert_raises(NotImplementedError, lambda: net.run(0 * ms)) defaultclock.dt = old_dt
def test_get_dtype(): ''' Check the utility function get_dtype ''' eqs = Equations('''dv/dt = -v / (10*ms) : volt x : 1 b : boolean n : integer''') # Test standard dtypes assert get_dtype(eqs['v']) == prefs['core.default_float_dtype'] assert get_dtype(eqs['x']) == prefs['core.default_float_dtype'] assert get_dtype(eqs['n']) == prefs['core.default_integer_dtype'] assert get_dtype(eqs['b']) == np.bool # Test a changed default (float) dtype assert get_dtype(eqs['v'], np.float32) == np.float32, get_dtype( eqs['v'], np.float32) assert get_dtype(eqs['x'], np.float32) == np.float32 # integer and boolean variables should be unaffected assert get_dtype(eqs['n']) == prefs['core.default_integer_dtype'] assert get_dtype(eqs['b']) == np.bool # Explicitly provide a dtype for some variables dtypes = {'v': np.float32, 'x': np.float64, 'n': np.int64} for varname in dtypes: assert get_dtype(eqs[varname], dtypes) == dtypes[varname] # Not setting some dtypes should use the standard dtypes dtypes = {'n': np.int64} assert get_dtype(eqs['n'], dtypes) == np.int64 assert get_dtype(eqs['v'], dtypes) == prefs['core.default_float_dtype'] # Test that incorrect types raise an error # incorrect general dtype assert_raises(TypeError, lambda: get_dtype(eqs['v'], np.int32)) # incorrect specific types assert_raises(TypeError, lambda: get_dtype(eqs['v'], {'v': np.int32})) assert_raises(TypeError, lambda: get_dtype(eqs['n'], {'n': np.float32})) assert_raises(TypeError, lambda: get_dtype(eqs['b'], {'b': np.int32}))
def test_unit_errors_threshold_reset(): ''' Test that unit errors in thresholds and resets are detected. ''' # Unit error in threshold assert_raises(DimensionMismatchError, lambda: NeuronGroup(1, 'dv/dt = -v/(10*ms) : 1', threshold='v > -20*mV')) # Unit error in reset assert_raises(DimensionMismatchError, lambda: NeuronGroup(1, 'dv/dt = -v/(10*ms) : 1', reset='v = -65*mV')) # More complicated unit reset with an intermediate variable # This should pass NeuronGroup(1, 'dv/dt = -v/(10*ms) : 1', reset='''temp_var = -65 v = temp_var''') # throw in an empty line (should still pass) NeuronGroup(1, 'dv/dt = -v/(10*ms) : 1', reset='''temp_var = -65 v = temp_var''') # This should fail assert_raises(DimensionMismatchError, lambda: NeuronGroup(1, 'dv/dt = -v/(10*ms) : 1', reset='''temp_var = -65*mV v = temp_var''')) # Resets with an in-place modification # This should work NeuronGroup(1, 'dv/dt = -v/(10*ms) : 1', reset='''v /= 2''') # This should fail assert_raises(DimensionMismatchError, lambda: NeuronGroup(1, 'dv/dt = -v/(10*ms) : 1', reset='''v -= 60*mV'''))
def test_illegal_calls(): 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']} 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']))
def test_creation(): ''' A basic test that creating a NeuronGroup works. ''' G = NeuronGroup(42, model='dv/dt = -v/(10*ms) : 1', reset='v=0', threshold='v>1') assert len(G) == 42 # Test some error conditions # -------------------------- # Model equations as first argument (no number of neurons) assert_raises(TypeError, lambda: NeuronGroup('dv/dt = 5*Hz : 1', 1)) # Not a number as first argument assert_raises(TypeError, lambda: NeuronGroup(object(), 'dv/dt = 5*Hz : 1')) # Illegal number assert_raises(ValueError, lambda: NeuronGroup(0, 'dv/dt = 5*Hz : 1')) # neither string nor Equations object as model description assert_raises(TypeError, lambda: NeuronGroup(1, object()))
def test_namespace_errors(): # model equations use unknown identifier G = NeuronGroup(1, 'dv/dt = -v/tau : 1') net = Network(G) assert_raises(KeyError, lambda: net.run(1*ms)) # reset uses unknown identifier G = NeuronGroup(1, 'dv/dt = -v/tau : 1', threshold='False', reset='v = v_r') net = Network(G) assert_raises(KeyError, lambda: net.run(1*ms)) # threshold uses unknown identifier G = NeuronGroup(1, 'dv/dt = -v/tau : 1', threshold='v > v_th') net = Network(G) assert_raises(KeyError, lambda: net.run(1*ms))
def test_spike_monitor(): G = NeuronGroup(3, '''dv/dt = rate : 1 rate: Hz''', threshold='v>1', reset='v=0') # We don't use 100 and 1000Hz, because then the membrane potential would # be exactly at 1 after 10 resp. 100 timesteps. Due to floating point # issues this will not be exact, G.rate = [101, 0, 1001] * Hz mon = SpikeMonitor(G) assert_raises(ValueError, lambda: SpikeMonitor(G, order=1)) # need to specify 'when' as well run(10*ms) spike_trains = mon.spike_trains() assert_allclose(mon.t[mon.i == 0], [9.9]*ms) assert len(mon.t[mon.i == 1]) == 0 assert_allclose(mon.t[mon.i == 2], np.arange(10)*ms + 0.9*ms) assert_allclose(mon.t_[mon.i == 0], np.array([9.9*float(ms)])) assert len(mon.t_[mon.i == 1]) == 0 assert_allclose(mon.t_[mon.i == 2], (np.arange(10) + 0.9)*float(ms)) assert_allclose(spike_trains[0], [9.9]*ms) assert len(spike_trains[1]) == 0 assert_allclose(spike_trains[2], np.arange(10)*ms + 0.9*ms) assert_array_equal(mon.count, np.array([1, 0, 10])) i, t = mon.it i_, t_ = mon.it_ assert_array_equal(i, mon.i) assert_array_equal(i, i_) assert_array_equal(t, mon.t) assert_array_equal(t_, mon.t_) assert_raises(KeyError, lambda: spike_trains[3]) assert_raises(KeyError, lambda: spike_trains[-1]) assert_raises(KeyError, lambda: spike_trains['string'])
def test_state_variables(): ''' Test the setting and accessing of state variables in subgroups. ''' G = NeuronGroup(10, 'v : volt') SG = G[4:9] assert_raises(DimensionMismatchError, lambda: SG.__setattr__('v', -70)) SG.v_ = float(-80*mV) assert_allclose(G.v, np.array([0, 0, 0, 0, -80, -80, -80, -80, -80, 0])*mV) assert_allclose(SG.v, np.array([-80, -80, -80, -80, -80])*mV) assert_allclose(G.v_, np.array([0, 0, 0, 0, -80, -80, -80, -80, -80, 0])*float(mV)) assert_allclose(SG.v_, np.array([-80, -80, -80, -80, -80])*float(mV)) # You should also be able to set variables with a string SG.v = 'v + i*mV' assert_allclose(SG.v[0], -80*mV) assert_allclose(SG.v[4], -76*mV) assert_allclose(G.v[4:9], -80*mV + np.arange(5)*mV) # Calculating with state variables should work too assert all(G.v[4:9] - SG.v == 0) # And in-place modification should work as well SG.v += 10*mV assert_allclose(G.v[4:9], -70*mV + np.arange(5)*mV) SG.v *= 2 assert_allclose(G.v[4:9], 2*(-70*mV + np.arange(5)*mV)) # with unit checking assert_raises(DimensionMismatchError, lambda: SG.v.__iadd__(3*second)) assert_raises(DimensionMismatchError, lambda: SG.v.__iadd__(3)) assert_raises(DimensionMismatchError, lambda: SG.v.__imul__(3*second)) # Indexing with subgroups assert_equal(G.v[SG], SG.v[:])
def test_initialize_nevergrad(): n_opt = NevergradOptimizer() n_opt.initialize({'g'}, g=[1, 30], popsize=30) assert isinstance(n_opt.optim, NOptimzer) assert_equal(n_opt.optim.dimension, 1) n_opt.initialize(['g', 'E'], g=[1, 30], E=[2, 20], popsize=30) assert isinstance(n_opt.optim, NOptimzer) assert_equal(n_opt.optim.dimension, 2) assert_raises(AssertionError, n_opt.initialize, ['g'], g=[1], popsize=30) assert_raises(AssertionError, n_opt.initialize, ['g'], g=[[1, 2]], popsize=30) assert_raises(Exception, n_opt.initialize, ['g'], g=[1, 2], E=[1, 2], popsize=30) assert_raises(Exception, n_opt.initialize, ['g', 'E'], g=[1, 2], popsize=30)
def test_initialize_skopt(): s_opt = SkoptOptimizer() s_opt.initialize({'g'}, g=[1, 30], popsize=30) assert isinstance(s_opt.optim, SOptimizer) assert_equal(len(s_opt.optim.space.dimensions), 1) s_opt.initialize({'g', 'E'}, g=[1, 30], E=[2, 20], popsize=30) assert isinstance(s_opt.optim, SOptimizer) assert_equal(len(s_opt.optim.space.dimensions), 2) assert_raises(TypeError, s_opt.initialize, ['g'], g=[1], popsize=30) assert_raises(Exception, s_opt.initialize, ['g'], g=[1, 2], E=[1, 2], popsize=30) assert_raises(Exception, s_opt.initialize, ['g', 'E'], g=[1, 2], popsize=30)
def test_event_monitor(): G = NeuronGroup(3, '''dv/dt = rate : 1 rate: Hz''', events={'my_event': 'v>1'}) G.run_on_event('my_event', 'v=0') # We don't use 100 and 1000Hz, because then the membrane potential would # be exactly at 1 after 10 resp. 100 timesteps. Due to floating point # issues this will not be exact, G.rate = [101, 0, 1001] * Hz mon = EventMonitor(G, 'my_event') net = Network(G, mon) net.run(10 * ms) event_trains = mon.event_trains() assert_allclose(mon.t[mon.i == 0], [9.9] * ms) assert len(mon.t[mon.i == 1]) == 0 assert_allclose(mon.t[mon.i == 2], np.arange(10) * ms + 0.9 * ms) assert_allclose(mon.t_[mon.i == 0], np.array([9.9 * float(ms)])) assert len(mon.t_[mon.i == 1]) == 0 assert_allclose(mon.t_[mon.i == 2], (np.arange(10) + 0.9) * float(ms)) assert_allclose(event_trains[0], [9.9] * ms) assert len(event_trains[1]) == 0 assert_allclose(event_trains[2], np.arange(10) * ms + 0.9 * ms) assert_array_equal(mon.count, np.array([1, 0, 10])) i, t = mon.it i_, t_ = mon.it_ assert_array_equal(i, mon.i) assert_array_equal(i, i_) assert_array_equal(t, mon.t) assert_array_equal(t_, mon.t_) assert_raises(KeyError, lambda: event_trains[3]) assert_raises(KeyError, lambda: event_trains[-1]) assert_raises(KeyError, lambda: event_trains['string'])
def test_explicit_stateupdater_parsing(): ''' Test the parsing of explicit state updater descriptions. ''' # These are valid descriptions and should not raise errors updater = ExplicitStateUpdater('x_new = x + dt * f(x, t)') updater(Equations('dv/dt = -v / tau : 1')) updater = ExplicitStateUpdater('''x2 = x + dt * f(x, t) x_new = x2''') updater(Equations('dv/dt = -v / tau : 1')) updater = ExplicitStateUpdater('''x1 = g(x, t) * dW x2 = x + dt * f(x, t) x_new = x1 + x2''', stochastic='multiplicative') updater(Equations('dv/dt = -v / tau + v * xi * tau**-.5: 1')) updater = ExplicitStateUpdater( '''x_support = x + dt*f(x, t) + dt**.5 * g(x, t) g_support = g(x_support, t) k = 1/(2*dt**.5)*(g_support - g(x, t))*(dW**2) x_new = x + dt*f(x,t) + g(x, t) * dW + k''', stochastic='multiplicative') updater(Equations('dv/dt = -v / tau + v * xi * tau**-.5: 1')) # Examples of failed parsing # No x_new = ... statement assert_raises(SyntaxError, lambda: ExplicitStateUpdater('x = x + dt * f(x, t)')) # Not an assigment assert_raises( SyntaxError, lambda: ExplicitStateUpdater('''2 * x x_new = x + dt * f(x, t)''' )) # doesn't separate into stochastic and non-stochastic part updater = ExplicitStateUpdater( '''x_new = x + dt * f(x, t) * g(x, t) * dW''') assert_raises(ValueError, lambda: updater(Equations('')))
def test_calc_gf(): assert_raises(TypeError, GammaFactor) assert_raises(DimensionMismatchError, GammaFactor, delta=10 * mV) assert_raises(DimensionMismatchError, GammaFactor, time=10) model_spikes = [ [np.array([1, 5, 8]), np.array([2, 3, 8, 9])], # Correct rate [np.array([1, 5]), np.array([0, 2, 3, 8, 9])] ] # Wrong rate data_spikes = [np.array([0, 5, 9]), np.array([1, 3, 5, 6])] gf = GammaFactor(delta=0.5 * ms, time=10 * ms) errors = gf.calc([data_spikes] * 5, data_spikes, 0.1 * ms) assert_almost_equal(errors, np.ones(5) * -1) errors = gf.calc(model_spikes, data_spikes, 0.1 * ms) assert errors[0] > -1 # correct rate assert errors[1] > errors[0] gf = GammaFactor(delta=0.5 * ms, time=10 * ms, rate_correction=False) errors = gf.calc([data_spikes] * 5, data_spikes, 0.1 * ms) assert_almost_equal(errors, np.zeros(5)) errors = gf.calc(model_spikes, data_spikes, 0.1 * ms) assert all(errors > 0)
def test_determination(): ''' Test the determination of suitable state updaters. ''' # To save some typing apply_stateupdater = StateUpdateMethod.apply_stateupdater eqs = Equations('dv/dt = -v / (10*ms) : 1') # Just make sure that state updaters know about the two state variables variables = {'v': Variable(name='v'), 'w': Variable(name='w')} # all methods should work for these equations. # First, specify them explicitly (using the object) for integrator in ( linear, euler, exponential_euler, #TODO: Removed "independent" here due to the issue in sympy 0.7.4 rk2, rk4, heun, milstein): with catch_logs() as logs: returned = apply_stateupdater(eqs, variables, method=integrator) assert len(logs) == 0, 'Got %d unexpected warnings: %s' % ( len(logs), str([l[2] for l in logs])) # Equation with multiplicative noise, only milstein and heun should work eqs = Equations('dv/dt = -v / (10*ms) + v*xi*second**-.5: 1') for integrator in (linear, independent, euler, exponential_euler, rk2, rk4): assert_raises(UnsupportedEquationsException, lambda: apply_stateupdater(eqs, variables, integrator)) for integrator in (heun, milstein): with catch_logs() as logs: returned = apply_stateupdater(eqs, variables, method=integrator) assert len(logs) == 0, 'Got %d unexpected warnings: %s' % ( len(logs), str([l[2] for l in logs])) # Arbitrary functions (converting equations into abstract code) should # always work my_stateupdater = lambda eqs, vars, options: 'x_new = x' with catch_logs() as logs: returned = apply_stateupdater(eqs, variables, method=my_stateupdater) # No warning here assert len(logs) == 0 # Specification with names eqs = Equations('dv/dt = -v / (10*ms) : 1') for name, integrator in [ ('exact', exact), ('linear', linear), ('euler', euler), #('independent', independent), #TODO: Removed "independent" here due to the issue in sympy 0.7.4 ('exponential_euler', exponential_euler), ('rk2', rk2), ('rk4', rk4), ('heun', heun), ('milstein', milstein) ]: with catch_logs() as logs: returned = apply_stateupdater(eqs, variables, method=name) # No warning here assert len(logs) == 0 # Now all except heun and milstein should refuse to work eqs = Equations('dv/dt = -v / (10*ms) + v*xi*second**-.5: 1') for name in [ 'linear', 'exact', 'independent', 'euler', 'exponential_euler', 'rk2', 'rk4' ]: assert_raises(UnsupportedEquationsException, lambda: apply_stateupdater(eqs, variables, method=name)) # milstein should work with catch_logs() as logs: apply_stateupdater(eqs, variables, method='milstein') assert len(logs) == 0 # heun should work with catch_logs() as logs: apply_stateupdater(eqs, variables, method='heun') assert len(logs) == 0 # non-existing name assert_raises( ValueError, lambda: apply_stateupdater(eqs, variables, method='does_not_exist')) # Automatic state updater choice should return linear for linear equations, # euler for non-linear, non-stochastic equations and equations with # additive noise, heun for equations with multiplicative noise # Because it is somewhat fragile, the "independent" state updater is not # included in this list all_methods = [ 'linear', 'exact', 'exponential_euler', 'euler', 'heun', 'milstein' ] eqs = Equations('dv/dt = -v / (10*ms) : 1') with catch_logs(log_level=logging.INFO) as logs: apply_stateupdater(eqs, variables, all_methods) assert len(logs) == 1 assert ('linear' in logs[0][2]) or ('exact' in logs[0][2]) # This is conditionally linear eqs = Equations('''dv/dt = -(v + w**2)/ (10*ms) : 1 dw/dt = -w/ (10*ms) : 1''') with catch_logs(log_level=logging.INFO) as logs: apply_stateupdater(eqs, variables, all_methods) assert len(logs) == 1 assert 'exponential_euler' in logs[0][2] # # Do not test for now # eqs = Equations('dv/dt = sin(t) / (10*ms) : 1') # assert apply_stateupdater(eqs, variables) is independent eqs = Equations('dv/dt = -sqrt(v) / (10*ms) : 1') with catch_logs(log_level=logging.INFO) as logs: apply_stateupdater(eqs, variables, all_methods) assert len(logs) == 1 assert "'euler'" in logs[0][2] eqs = Equations('dv/dt = -v / (10*ms) + 0.1*second**-.5*xi: 1') with catch_logs(log_level=logging.INFO) as logs: apply_stateupdater(eqs, variables, all_methods) assert len(logs) == 1 assert "'euler'" in logs[0][2] eqs = Equations('dv/dt = -v / (10*ms) + v*0.1*second**-.5*xi: 1') with catch_logs(log_level=logging.INFO) as logs: apply_stateupdater(eqs, variables, all_methods) assert len(logs) == 1 assert "'heun'" in logs[0][2]
def test_locally_constant_check(): default_dt = defaultclock.dt # The linear state update can handle additive time-dependent functions # (e.g. a TimedArray) but only if it can be safely assumed that the function # is constant over a single time check ta0 = TimedArray(np.array([1]), dt=default_dt) # ok ta1 = TimedArray(np.array([1]), dt=2 * default_dt) # ok ta2 = TimedArray(np.array([1]), dt=default_dt / 2) # not ok ta3 = TimedArray(np.array([1]), dt=default_dt * 1.5) # not ok for ta_func, ok in zip([ta0, ta1, ta2, ta3], [True, True, False, False]): # additive G = NeuronGroup(1, 'dv/dt = -v/(10*ms) + ta(t)*Hz : 1', method='exact', namespace={'ta': ta_func}) net = Network(G) if ok: # This should work net.run(0 * ms) else: # This should not with catch_logs(): assert_raises(UnsupportedEquationsException, lambda: net.run(0 * ms)) # multiplicative G = NeuronGroup(1, 'dv/dt = -v*ta(t)/(10*ms) : 1', method='exact', namespace={'ta': ta_func}) net = Network(G) if ok: # This should work net.run(0 * ms) else: # This should not with catch_logs(): assert_raises(UnsupportedEquationsException, lambda: net.run(0 * ms)) # If the argument is more than just "t", we cannot guarantee that it is # actually locally constant G = NeuronGroup(1, 'dv/dt = -v*ta(t/2.0)/(10*ms) : 1', method='exact', namespace={'ta': ta0}) net = Network(G) assert_raises(UnsupportedEquationsException, lambda: net.run(0 * ms)) # Arbitrary functions are not constant over a time step G = NeuronGroup(1, 'dv/dt = -v/(10*ms) + sin(2*pi*100*Hz*t)*Hz : 1', method='exact') net = Network(G) assert_raises(UnsupportedEquationsException, lambda: net.run(0 * ms)) # Stateful functions aren't either G = NeuronGroup(1, 'dv/dt = -v/(10*ms) + rand()*Hz : 1', method='exact') net = Network(G) assert_raises(UnsupportedEquationsException, lambda: net.run(0 * ms)) # Neither is "t" itself G = NeuronGroup(1, 'dv/dt = -v/(10*ms) + t/second**2 : 1', method='exact') net = Network(G) assert_raises(UnsupportedEquationsException, lambda: net.run(0 * ms)) # But if the argument is not referring to t, all should be well G = NeuronGroup(1, 'dv/dt = -v/(10*ms) + sin(2*pi*100*Hz*5*second)*Hz : 1', method='exact') net = Network(G) net.run(0 * ms)
def test_profile_build_raises(): # Test that profiling info is not 0 set_device('cuda_standalone', directory=None, build_on_run=False) assert_raises(TypeError, lambda: device.build(profile=True)) assert_raises(TypeError, lambda: device.build(profile=False)) assert_raises(TypeError, lambda: device.build(profile='string'))
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)
def test_subgroup(): morpho = Soma(diameter=30 * um) morpho.L = Cylinder(length=10 * um, diameter=1 * um, n=10) morpho.LL = Cylinder(length=5 * um, diameter=2 * um, n=5) morpho.right = Cylinder(length=3 * um, diameter=1 * um, n=7) # Getting a single compartment by index assert_allclose(morpho.L[2].distance, 3 * um) # Getting a single compartment by position assert_allclose(morpho.LL[0 * um].distance, 11 * um) assert_allclose(morpho.LL[1 * um].distance, 11 * um) assert_allclose(morpho.LL[1.5 * um].distance, 12 * um) assert_allclose(morpho.LL[5 * um].distance, 15 * um) # Getting a segment assert_allclose(morpho.L[3 * um:5.1 * um].distance, [3 * um, 4 * um, 5 * um]) # Indices cannot be obtained at this stage assert_raises(AttributeError, lambda: morpho.L.indices[:]) # Compress the morphology and get absolute compartment indices N = len(morpho) morpho.compress(MorphologyData(N)) assert_equal(morpho.LL.indices[:], [11, 12, 13, 14, 15]) assert_equal(morpho.L.indices[3 * um:5.1 * um], [3, 4, 5]) assert_equal(morpho.L.indices[3 * um:5.1 * um], morpho.L[3 * um:5.1 * um].indices[:]) assert_equal(morpho.L.indices[:5.1 * um], [1, 2, 3, 4, 5]) assert_equal(morpho.L.indices[3 * um:], [3, 4, 5, 6, 7, 8, 9, 10]) assert_equal(morpho.L.indices[3.5 * um], 4) assert_equal(morpho.L.indices[3], 4) assert_equal(morpho.L.indices[-1], 10) assert_equal(morpho.L.indices[3:5], [4, 5]) assert_equal(morpho.L.indices[3:], [4, 5, 6, 7, 8, 9, 10]) assert_equal(morpho.L.indices[:5], [1, 2, 3, 4, 5]) # Main branch assert_equal(len(morpho.L.main), 10) # Non-existing branch assert_raises(AttributeError, lambda: morpho.axon) # Incorrect indexing # wrong units or mixing units assert_raises(TypeError, lambda: morpho.indices[3 * second:5 * second]) assert_raises(TypeError, lambda: morpho.indices[3.4:5.3]) assert_raises(TypeError, lambda: morpho.indices[3:5 * um]) assert_raises(TypeError, lambda: morpho.indices[3 * um:5]) # providing a step assert_raises(TypeError, lambda: morpho.indices[3 * um:5 * um:2 * um]) assert_raises(TypeError, lambda: morpho.indices[3:5:2]) # incorrect type assert_raises(TypeError, lambda: morpho.indices[object()])
def test_construction_coordinates(): # Same as test_construction, but uses coordinates instead of lengths to # set up everything # Note that all coordinates here are relative to the origin of the # respective cylinder BrianLogger.suppress_name('resolution_conflict') morpho = Soma(diameter=30*um) morpho.L = Cylinder(x=[0, 10]*um, diameter=1*um, n=10) morpho.LL = Cylinder(y=[0, 5]*um, diameter=2*um, n=5) morpho.LR = Cylinder(z=[0, 5]*um, diameter=2*um, n=10) morpho.right = Cylinder(x=[0, sqrt(2)*1.5]*um, y=[0, sqrt(2)*1.5]*um, diameter=1*um, n=7) morpho.right.nextone = Cylinder(y=[0, sqrt(2)]*um, z=[0, sqrt(2)]*um, diameter=1*um, n=3) gL=1e-4*siemens/cm**2 EL=-70*mV eqs=''' Im=gL*(EL-v) : amp/meter**2 I : meter (point current) ''' # Check units of currents assert_raises(DimensionMismatchError, lambda: SpatialNeuron(morphology=morpho, model=eqs)) eqs=''' Im=gL*(EL-v) : amp/meter**2 ''' neuron = SpatialNeuron(morphology=morpho, model=eqs, Cm=1 * uF / cm ** 2, Ri=100 * ohm * cm) # Test initialization of values neuron.LL.v = EL assert_allclose(neuron.L.main.v, 0) assert_allclose(neuron.LL.v, EL) neuron.LL[1*um:3*um].v = 0*mV assert_allclose(neuron.LL.v, Quantity([EL, 0*mV, 0*mV, EL, EL])) assert_allclose(neuron.Cm, 1 * uF / cm ** 2) # Test morphological variables assert_allclose(neuron.L.main.x, morpho.L.x) assert_allclose(neuron.LL.main.x, morpho.LL.x) assert_allclose(neuron.right.main.x, morpho.right.x) assert_allclose(neuron.L.main.distance, morpho.L.distance) # assert_allclose(neuron.L.main.diameter, morpho.L.diameter) assert_allclose(neuron.L.main.area, morpho.L.area) assert_allclose(neuron.L.main.length, morpho.L.length) # Check basic consistency of the flattened representation assert all(neuron.diffusion_state_updater._ends[:].flat >= neuron.diffusion_state_updater._starts[:].flat) # Check that length and distances make sense assert_allclose(sum(morpho.L.length), 10*um) assert_allclose(morpho.L.distance, (0.5 + np.arange(10))*um) assert_allclose(sum(morpho.LL.length), 5*um) assert_allclose(morpho.LL.distance, (10 + .5 + np.arange(5))*um) assert_allclose(sum(morpho.LR.length), 5*um) assert_allclose(morpho.LR.distance, (10 + 0.25 + np.arange(10)*0.5)*um) assert_allclose(sum(morpho.right.length), 3*um) assert_allclose(morpho.right.distance, (0.5 + np.arange(7))*3./7.*um) assert_allclose(sum(morpho.right.nextone.length), 2*um) assert_allclose(morpho.right.nextone.distance, 3*um + (0.5 + np.arange(3))*2./3.*um)
def test_determination(): ''' Test the determination of suitable state updaters. ''' # To save some typing determine_stateupdater = StateUpdateMethod.determine_stateupdater # Save state before tests before = list(StateUpdateMethod.stateupdaters) eqs = Equations('dv/dt = -v / (10*ms) : 1') # Just make sure that state updaters know about the two state variables variables = {'v': Variable(name='v', unit=None), 'w': Variable(name='w', unit=None)} # all methods should work for these equations. # First, specify them explicitly (using the object) for integrator in (linear, euler, exponential_euler, #TODO: Removed "independent" here due to the issue in sympy 0.7.4 rk2, rk4, milstein): with catch_logs() as logs: returned = determine_stateupdater(eqs, variables, method=integrator) assert returned is integrator, 'Expected state updater %s, got %s' % (integrator, returned) assert len(logs) == 0, 'Got %d unexpected warnings: %s' % (len(logs), str([l[2] for l in logs])) # Equation with multiplicative noise, only milstein should work without # a warning eqs = Equations('dv/dt = -v / (10*ms) + v*xi*second**-.5: 1') for integrator in (linear, independent, euler, exponential_euler, rk2, rk4): with catch_logs() as logs: returned = determine_stateupdater(eqs, variables, method=integrator) assert returned is integrator, 'Expected state updater %s, got %s' % (integrator, returned) # We should get a warning here assert len(logs) == 1, 'Got %d warnings but expected 1: %s' % (len(logs), str([l[2] for l in logs])) with catch_logs() as logs: returned = determine_stateupdater(eqs, variables, method=milstein) assert returned is milstein, 'Expected state updater milstein, got %s' % (integrator, returned) # No warning here assert len(logs) == 0, 'Got %d unexpected warnings: %s' % (len(logs), str([l[2] for l in logs])) # Arbitrary functions (converting equations into abstract code) should # always work my_stateupdater = lambda eqs: 'x_new = x' with catch_logs() as logs: returned = determine_stateupdater(eqs, variables, method=my_stateupdater) assert returned is my_stateupdater # No warning here assert len(logs) == 0 # Specification with names eqs = Equations('dv/dt = -v / (10*ms) : 1') for name, integrator in [('linear', linear), ('euler', euler), #('independent', independent), #TODO: Removed "independent" here due to the issue in sympy 0.7.4 ('exponential_euler', exponential_euler), ('rk2', rk2), ('rk4', rk4), ('milstein', milstein)]: with catch_logs() as logs: returned = determine_stateupdater(eqs, variables, method=name) assert returned is integrator # No warning here assert len(logs) == 0 # Now all except milstein should refuse to work eqs = Equations('dv/dt = -v / (10*ms) + v*xi*second**-.5: 1') for name in ['linear', 'independent', 'euler', 'exponential_euler', 'rk2', 'rk4']: assert_raises(ValueError, lambda: determine_stateupdater(eqs, variables, method=name)) # milstein should work with catch_logs() as logs: determine_stateupdater(eqs, variables, method='milstein') assert len(logs) == 0 # non-existing name assert_raises(ValueError, lambda: determine_stateupdater(eqs, variables, method='does_not_exist')) # Automatic state updater choice should return linear for linear equations, # euler for non-linear, non-stochastic equations and equations with # additive noise, milstein for equations with multiplicative noise eqs = Equations('dv/dt = -v / (10*ms) : 1') assert determine_stateupdater(eqs, variables) is linear # This is conditionally linear eqs = Equations('''dv/dt = -(v + w**2)/ (10*ms) : 1 dw/dt = -w/ (10*ms) : 1''') assert determine_stateupdater(eqs, variables) is exponential_euler eqs = Equations('dv/dt = sin(t) / (10*ms) : 1') assert determine_stateupdater(eqs, variables) is independent eqs = Equations('dv/dt = -sqrt(v) / (10*ms) : 1') assert determine_stateupdater(eqs, variables) is euler eqs = Equations('dv/dt = -v / (10*ms) + 0.1*second**-.5*xi: 1') assert determine_stateupdater(eqs, variables) is euler eqs = Equations('dv/dt = -v / (10*ms) + v*0.1*second**-.5*xi: 1') assert determine_stateupdater(eqs, variables) is milstein # remove all registered state updaters --> automatic choice no longer works StateUpdateMethod.stateupdaters = {} assert_raises(ValueError, lambda: determine_stateupdater(eqs, variables)) # reset to state before the test StateUpdateMethod.stateupdaters = before
def test_wrong_indexing(): G = NeuronGroup(10, 'v:1') assert_raises(TypeError, lambda: G['string']) assert_raises(IndexError, lambda: G[10]) assert_raises(IndexError, lambda: G[10:]) assert_raises(IndexError, lambda: G[::2]) assert_raises(IndexError, lambda: G[3:2]) assert_raises(IndexError, lambda: G[[5, 4, 3]]) assert_raises(IndexError, lambda: G[[2, 4, 6]]) assert_raises(IndexError, lambda: G[[-1, 0, 1]]) assert_raises(IndexError, lambda: G[[9, 10, 11]]) assert_raises(IndexError, lambda: G[[9, 10]]) assert_raises(IndexError, lambda: G[[10, 11]]) assert_raises(TypeError, lambda: G[[2.5, 3.5, 4.5]])
def test_wrong_indexing(): G = NeuronGroup(10, 'v:1') assert_raises(TypeError, lambda: G[0]) assert_raises(TypeError, lambda: G[[0, 1]]) assert_raises(TypeError, lambda: G['string']) assert_raises(IndexError, lambda: G[10:]) assert_raises(IndexError, lambda: G[::2]) assert_raises(IndexError, lambda: G[3:2])
def test_rate_monitor_smoothed_rate_incorrect(): # Test the filter response by having a single spiking neuron G = SpikeGeneratorGroup(1, [0], [1]*ms) r_mon = PopulationRateMonitor(G) run(2*ms) assert_raises(TypeError, lambda: r_mon.smooth_rate(window='flat')) # no width assert_raises(TypeError, lambda: r_mon.smooth_rate(window=np.ones(5), width=1*ms)) assert_raises(NotImplementedError, lambda: r_mon.smooth_rate(window='unknown', width=1*ms)) assert_raises(TypeError, lambda: r_mon.smooth_rate(window=object())) assert_raises(TypeError, lambda: r_mon.smooth_rate(window=np.ones(5, 2))) assert_raises(TypeError, lambda: r_mon.smooth_rate(window=np.ones(4))) # even number
def test_scalar_parameter_access(): for codeobj_class in codeobj_classes: G = NeuronGroup(10, '''dv/dt = freq : 1 freq : Hz (shared) number : 1 (shared) array : 1''', codeobj_class=codeobj_class) # Try setting a scalar variable G.freq = 100*Hz assert_equal(G.freq[:], 100*Hz) G.freq[:] = 200*Hz assert_equal(G.freq[:], 200*Hz) G.freq = 'freq - 50*Hz + number*Hz' assert_equal(G.freq[:], 150*Hz) G.freq[:] = '50*Hz' assert_equal(G.freq[:], 50*Hz) # Check the second method of accessing that works assert_equal(np.asanyarray(G.freq), 50*Hz) # Check error messages assert_raises(IndexError, lambda: G.freq[0]) assert_raises(IndexError, lambda: G.freq[1]) assert_raises(IndexError, lambda: G.freq[0:1]) assert_raises(IndexError, lambda: G.freq['i>5']) assert_raises(ValueError, lambda: G.freq.set_item(slice(None), [0, 1]*Hz)) assert_raises(IndexError, lambda: G.freq.set_item(0, 100*Hz)) assert_raises(IndexError, lambda: G.freq.set_item(1, 100*Hz)) assert_raises(IndexError, lambda: G.freq.set_item('i>5', 100*Hz))
def test_state_variable_access_strings(): for codeobj_class in codeobj_classes: G = NeuronGroup(10, 'v:volt', codeobj_class=codeobj_class) G.v = np.arange(10) * volt # Indexing with strings assert G.v['i==2'] == G.v[2] assert G.v_['i==2'] == G.v_[2] assert_equal(G.v['v >= 3*volt'], G.v[3:]) assert_equal(G.v_['v >= 3*volt'], G.v_[3:]) # Should also check for units assert_raises(DimensionMismatchError, lambda: G.v['v >= 3']) assert_raises(DimensionMismatchError, lambda: G.v['v >= 3*second']) # Setting with strings # -------------------- # String value referring to i G.v = '2*i*volt' assert_equal(G.v[:], 2*np.arange(10)*volt) # String value referring to i G.v[:5] = '3*i*volt' assert_equal(G.v[:], np.array([0, 3, 6, 9, 12, 10, 12, 14, 16, 18])*volt) G.v = np.arange(10) * volt # String value referring to a state variable G.v = '2*v' assert_equal(G.v[:], 2*np.arange(10)*volt) G.v[:5] = '2*v' assert_equal(G.v[:], np.array([0, 4, 8, 12, 16, 10, 12, 14, 16, 18])*volt) G.v = np.arange(10) * volt # String value referring to state variables, i, and an external variable ext = 5*volt G.v = 'v + ext + (N + i)*volt' assert_equal(G.v[:], 2*np.arange(10)*volt + 15*volt) G.v = np.arange(10) * volt G.v[:5] = 'v + ext + (N + i)*volt' assert_equal(G.v[:], np.array([15, 17, 19, 21, 23, 5, 6, 7, 8, 9])*volt) G.v = 'v + randn()*volt' # only check that it doesn't raise an error G.v[:5] = 'v + randn()*volt' # only check that it doesn't raise an error G.v = np.arange(10) * volt # String index using a random number G.v['rand() <= 1'] = 0*mV assert_equal(G.v[:], np.zeros(10)*volt) G.v = np.arange(10) * volt # String index referring to i and setting to a scalar value G.v['i>=5'] = 0*mV assert_equal(G.v[:], np.array([0, 1, 2, 3, 4, 0, 0, 0, 0, 0])*volt) # String index referring to a state variable G.v['v<3*volt'] = 0*mV assert_equal(G.v[:], np.array([0, 0, 0, 3, 4, 0, 0, 0, 0, 0])*volt) # String index referring to state variables, i, and an external variable ext = 2*volt G.v['v>=ext and i==(N-6)'] = 0*mV assert_equal(G.v[:], np.array([0, 0, 0, 3, 0, 0, 0, 0, 0, 0])*volt) G.v = np.arange(10) * volt # Strings for both condition and values G.v['i>=5'] = 'v*2' assert_equal(G.v[:], np.array([0, 1, 2, 3, 4, 10, 12, 14, 16, 18])*volt) G.v['v>=5*volt'] = 'i*volt' assert_equal(G.v[:], np.arange(10)*volt)
def test_array_cache(): # Check that variables are only accessible from Python when they should be set_device('cpp_standalone', build_on_run=False) G = NeuronGroup(10, '''dv/dt = -v / (10*ms) : 1 w : 1 x : 1 y : 1 z : 1 (shared)''', threshold='v>1') S = Synapses(G, G, 'weight: 1', on_pre='w += weight') S.connect(p=0.2) S.weight = 7 # All neurongroup values should be known assert_allclose(G.v, 0) assert_allclose(G.w, 0) assert_allclose(G.x, 0) assert_allclose(G.y, 0) assert_allclose(G.z, 0) assert_allclose(G.i, np.arange(10)) # But the synaptic variable is not -- we don't know the number of synapses assert_raises(NotImplementedError, lambda: S.weight[:]) # Setting variables with explicit values should not change anything G.v = np.arange(10)+1 G.w = 2 G.y = 5 G.z = 7 assert_allclose(G.v, np.arange(10)+1) assert_allclose(G.w, 2) assert_allclose(G.y, 5) assert_allclose(G.z, 7) # But setting with code should invalidate them G.x = 'i*2' assert_raises(NotImplementedError, lambda: G.x[:]) # Make sure that the array cache does not allow to use incorrectly sized # values to pass assert_raises(ValueError, lambda: setattr(G, 'w', [0, 2])) assert_raises(ValueError, lambda: G.w.__setitem__(slice(0, 4), [0, 2])) run(10*ms) # v is now no longer known without running the network assert_raises(NotImplementedError, lambda: G.v[:]) # Neither is w, it is updated in the synapse assert_raises(NotImplementedError, lambda: G.w[:]) # However, no code touches y or z assert_allclose(G.y, 5) assert_allclose(G.z, 7) # i is read-only anyway assert_allclose(G.i, np.arange(10)) # After actually running the network, everything should be accessible device.build(directory=None, with_output=False) assert all(G.v > 0) assert all(G.w > 0) assert_allclose(G.x, np.arange(10)*2) assert_allclose(G.y, 5) assert_allclose(G.z, 7) assert_allclose(G.i, np.arange(10)) assert_allclose(S.weight, 7)
def test_state_variables(): ''' Test the setting and accessing of state variables. ''' for codeobj_class in codeobj_classes: G = NeuronGroup(10, 'v : volt', codeobj_class=codeobj_class) # The variable N should be always present assert G.N == 10 # But it should be read-only assert_raises(TypeError, lambda: G.__setattr__('N', 20)) assert_raises(TypeError, lambda: G.__setattr__('N_', 20)) G.v = -70*mV assert_raises(DimensionMismatchError, lambda: G.__setattr__('v', -70)) G.v_ = float(-70*mV) assert_allclose(G.v[:], -70*mV) G.v = -70*mV + np.arange(10)*mV assert_allclose(G.v[:], -70*mV + np.arange(10)*mV) G.v = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] * volt assert_allclose(G.v[:], np.arange(10) * volt) # incorrect size assert_raises(ValueError, lambda: G.__setattr__('v', [0, 1]*volt)) assert_raises(ValueError, lambda: G.__setattr__('v', np.arange(11)*volt)) G.v = -70*mV # Numpy methods should be able to deal with state variables # (discarding units) assert_allclose(np.mean(G.v), float(-70*mV)) # Getting the content should return a Quantity object which then natively # supports numpy functions that access a method assert_allclose(np.mean(G.v[:]), -70*mV) # You should also be able to set variables with a string G.v = '-70*mV + i*mV' assert_allclose(G.v[0], -70*mV) assert_allclose(G.v[9], -61*mV) assert_allclose(G.v[:], -70*mV + np.arange(10)*mV) # And it should raise an unit error if the units are incorrect assert_raises(DimensionMismatchError, lambda: G.__setattr__('v', '70 + i')) assert_raises(DimensionMismatchError, lambda: G.__setattr__('v', '70 + i*mV')) # Calculating with state variables should work too # With units assert all(G.v - G.v == 0) assert all(G.v - G.v[:] == 0*mV) assert all(G.v[:] - G.v == 0*mV) assert all(G.v + 70*mV == G.v[:] + 70*mV) assert all(70*mV + G.v == G.v[:] + 70*mV) assert all(G.v + G.v == 2*G.v) assert all(G.v / 2.0 == 0.5*G.v) assert all(1.0 / G.v == 1.0 / G.v[:]) assert_equal((-G.v)[:], -G.v[:]) assert_equal((+G.v)[:], G.v[:]) #Without units assert all(G.v_ - G.v_ == 0) assert all(G.v_ - G.v_[:] == 0) assert all(G.v_[:] - G.v_ == 0) assert all(G.v_ + float(70*mV) == G.v_[:] + float(70*mV)) assert all(float(70*mV) + G.v_ == G.v_[:] + float(70*mV)) assert all(G.v_ + G.v_ == 2*G.v_) assert all(G.v_ / 2.0 == 0.5*G.v_) assert all(1.0 / G.v_ == 1.0 / G.v_[:]) assert_equal((-G.v)[:], -G.v[:]) assert_equal((+G.v)[:], G.v[:]) # And in-place modification should work as well G.v += 10*mV G.v -= 10*mV G.v *= 2 G.v /= 2.0 # with unit checking assert_raises(DimensionMismatchError, lambda: G.v.__iadd__(3*second)) assert_raises(DimensionMismatchError, lambda: G.v.__iadd__(3)) assert_raises(DimensionMismatchError, lambda: G.v.__imul__(3*second)) # in-place modification with strings should not work assert_raises(TypeError, lambda: G.v.__iadd__('string')) assert_raises(TypeError, lambda: G.v.__imul__('string')) assert_raises(TypeError, lambda: G.v.__idiv__('string')) assert_raises(TypeError, lambda: G.v.__isub__('string'))
def test_clear_cache_numpy(): if prefs.codegen.target != 'numpy': raise SkipTest('numpy-only test') assert 'numpy' not in _cache_dirs_and_extensions assert_raises(ValueError, clear_cache, 'numpy')