def test_GSL_error_incorrect_error_format(): eqs = """ dv/dt = (v0 - v)/(10*ms) : volt v0 : volt """ options = {'absolute_error_per_variable': object()} neuron = NeuronGroup(1, eqs, threshold='v > 10*mV', reset='v = 0*mV', method='gsl', method_options=options) net = Network(neuron) options2 = {'absolute_error': 'not a float'} neuron2 = NeuronGroup(1, eqs, threshold='v > 10*mV', reset='v = 0*mV', method='gsl', method_options=options2) net2 = Network(neuron2) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms, namespace={}) assert exc_isinstance(exc, TypeError, raise_not_implemented=True) with pytest.raises(BrianObjectException) as exc: net2.run(0 * ms, namespace={}) assert exc_isinstance(exc, TypeError, raise_not_implemented=True)
def test_multiple_stateless_function_calls(): # Check that expressions such as rand() + rand() (which might be incorrectly # simplified to 2*rand()) raise an error G = NeuronGroup(1, 'dv/dt = (rand() - rand())/second : 1') net = Network(G) with pytest.raises(BrianObjectException) as exc: net.run(0*ms) assert exc_isinstance(exc, NotImplementedError) G2 = NeuronGroup(1, 'v:1', threshold='v>1', reset='v=rand() - rand()') net2 = Network(G2) with pytest.raises(BrianObjectException) as exc: net2.run(0*ms) assert exc_isinstance(exc, NotImplementedError) G3 = NeuronGroup(1, 'v:1') G3.run_regularly('v = rand() - rand()') net3 = Network(G3) with pytest.raises(BrianObjectException) as exc: net3.run(0*ms) assert exc_isinstance(exc, NotImplementedError) G4 = NeuronGroup(1, 'x : 1') # Verify that synaptic equations are checked as well, see #1146 S = Synapses(G4, G4, 'dy/dt = (rand() - rand())/second : 1 (clock-driven)') S.connect() net = Network(G4, S) with pytest.raises(BrianObjectException) as exc: net.run(0*ms) assert exc_isinstance(exc, NotImplementedError)
def test_multiplicative_noise(): # Noise is not multiplicative (constant over time step) ta = TimedArray([0, 1], dt=defaultclock.dt * 10) Eq = Equations('dv/dt = ta(t)*xi*(5*ms)**-0.5 :1') group = NeuronGroup(1, Eq, method='euler') net = Network(group) net.run(0 * ms) # no error # Noise is multiplicative (multiplied with time-varying variable) Eq1 = Equations('dv/dt = v*xi*(5*ms)**-0.5 :1') group1 = NeuronGroup(1, Eq1, method='euler') net1 = Network(group1) with pytest.raises(BrianObjectException) as exc: net1.run(0 * ms) assert exc_isinstance(exc, UnsupportedEquationsException) # Noise is multiplicative (multiplied with time) Eq2 = Equations('dv/dt = (t/ms)*xi*(5*ms)**-0.5 :1') group2 = NeuronGroup(1, Eq2, method='euler') net2 = Network(group2) with pytest.raises(BrianObjectException) as exc: net2.run(0 * ms) assert exc_isinstance(exc, UnsupportedEquationsException) # Noise is multiplicative (multiplied with time-varying variable) Eq3 = Equations("""dv/dt = w*xi*(5*ms)**-0.5 :1 dw/dt = -w/(10*ms) : 1""") group3 = NeuronGroup(1, Eq3, method='euler') net3 = Network(group3) with pytest.raises(BrianObjectException) as exc: net3.run(0 * ms) assert exc_isinstance(exc, UnsupportedEquationsException) # One of the equations has multiplicative noise Eq4 = Equations("""dv/dt = xi_1*(5*ms)**-0.5 : 1 dw/dt = (t/ms)*xi_2*(5*ms)**-0.5 :1""") group4 = NeuronGroup(1, Eq4, method='euler') net4 = Network(group4) with pytest.raises(BrianObjectException) as exc: net4.run(0 * ms) assert exc_isinstance(exc, UnsupportedEquationsException) # One of the equations has multiplicative noise Eq5 = Equations("""dv/dt = xi_1*(5*ms)**-0.5 : 1 dw/dt = v*xi_2*(5*ms)**-0.5 :1""") group5 = NeuronGroup(1, Eq5, method='euler') net5 = Network(group4) with pytest.raises(BrianObjectException) as exc: net5.run(0 * ms) assert exc_isinstance(exc, UnsupportedEquationsException)
def test_rate_unit_check(): with pytest.raises(DimensionMismatchError): PoissonGroup(1, np.array([1, 2])) with pytest.raises(DimensionMismatchError): PoissonGroup(1, np.array([1, 2]) * ms) P = PoissonGroup(1, 'i*mV') net = Network(P) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, DimensionMismatchError) P = PoissonGroup(1, 'i') net = Network(P) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, DimensionMismatchError)
def test_spikegenerator_incorrect_period(): """ Test that you cannot provide incorrect period arguments or combine inconsistent period and dt arguments. """ # Period is negative with pytest.raises(ValueError): SpikeGeneratorGroup(1, [], [] * second, period=-1 * ms) # Period is smaller than the highest spike time with pytest.raises(ValueError): 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) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, NotImplementedError) SG = SpikeGeneratorGroup(1, [], [] * second, period=0.101 * ms, dt=0.1 * ms) net = Network(SG) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, NotImplementedError) SG = SpikeGeneratorGroup(1, [], [] * second, period=3.333 * ms, dt=0.1 * ms) net = Network(SG) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, NotImplementedError) # This should not raise an error (see #1041) SG = SpikeGeneratorGroup(1, [], [] * ms, period=150 * ms, dt=0.1 * ms) net = Network(SG) net.run(0 * ms) # Period is smaller than dt SG = SpikeGeneratorGroup(1, [], [] * second, period=1 * ms, dt=2 * ms) net = Network(SG) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, ValueError)
def test_refractoriness_types(): # make sure that using a wrong type of refractoriness does not work group = NeuronGroup(1, '', refractory='3*Hz') with pytest.raises(BrianObjectException) as exc: Network(group).run(0 * ms) assert exc_isinstance(exc, TypeError) group = NeuronGroup(1, 'ref: Hz', refractory='ref') with pytest.raises(BrianObjectException) as exc: Network(group).run(0 * ms) assert exc_isinstance(exc, TypeError) group = NeuronGroup(1, '', refractory='3') with pytest.raises(BrianObjectException) as exc: Network(group).run(0 * ms) assert exc_isinstance(exc, TypeError) group = NeuronGroup(1, 'ref: 1', refractory='ref') with pytest.raises(BrianObjectException) as exc: Network(group).run(0 * ms) assert exc_isinstance(exc, TypeError)
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) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms, namespace={'tau': tau, 'sigma': sigma}) assert exc_isinstance(exc, UnsupportedEquationsException, raise_not_implemented=True)
def test_spikegenerator_multiple_spikes_per_bin(): # Multiple spikes per bin are of course fine if they don't belong to the # same neuron SG = SpikeGeneratorGroup(2, [0, 1], [0, 0.05] * ms, dt=0.1 * ms) net = Network(SG) net.run(0 * ms) # This should raise an error SG = SpikeGeneratorGroup(2, [0, 0], [0, 0.05] * ms, dt=0.1 * ms) net = Network(SG) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) print(exc.value.__cause__) assert exc_isinstance(exc, ValueError) # More complicated scenario where dt changes between runs defaultclock.dt = 0.1 * ms SG = SpikeGeneratorGroup(2, [0, 0], [0.05, 0.15] * ms) net = Network(SG) net.run(0 * ms) # all is fine defaultclock.dt = 0.2 * ms # Now the two spikes fall into the same bin with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, ValueError)
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) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms, namespace={}) assert exc_isinstance(exc, KeyError, raise_not_implemented=True)
def test_GSL_error_dimension_mismatch_dimensionless1(): eqs = """ dv/dt = (v0 - v)/(10*ms) : 1 v0 : 1 """ options = {'absolute_error_per_variable': {'v': 1 * mV}} neuron = NeuronGroup(1, eqs, threshold='v > 10', reset='v = 0', method='gsl', method_options=options) net = Network(neuron) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms, namespace={}) assert exc_isinstance(exc, DimensionMismatchError, raise_not_implemented=True)
def test_spikegenerator_period_rounding(): # See discussion in PR #1042 # The last spike will be considered to be in the time step *after* 1s, due # to the way our rounding works. Although probably not what the user # expects, this should therefore raise an error. In previous versions of # Brian, this did not raise any error but silently discarded the spike. with pytest.raises(ValueError): SpikeGeneratorGroup(1, [0, 0, 0], [0 * ms, .9 * ms, .99999 * ms], period=1 * ms, dt=0.1 * ms) # This should also raise a ValueError, since the last two spikes fall into # the same bin s = SpikeGeneratorGroup(1, [0, 0, 0], [0 * ms, .9 * ms, .96 * ms], period=1 * ms, dt=0.1 * ms) net = Network(s) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, ValueError)
def test_manual_user_defined_function_cython_wrong_compiler_args2(): if prefs.codegen.target != 'cython': pytest.skip('Cython-only test') @implementation('cython', """ cdef double foo(double x, const double y): return x + y + 3 """, libraries='cstdio') # existing argument, wrong value type @check_units(x=volt, y=volt, result=volt) def foo(x, y): return x + y + 3*volt G = NeuronGroup(1, """ func = foo(x, y) : volt x : volt y : volt""") mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) with pytest.raises(BrianObjectException) as exc: net.run(defaultclock.dt, namespace={'foo': foo}) assert exc_isinstance(exc, TypeError)
def test_manual_user_defined_function_cpp_standalone_wrong_compiler_args2(): set_device('cpp_standalone', directory=None) @implementation('cpp', """ static inline double foo(const double x, const double y) { return x + y + _THREE; }""", headers='<stdio.h>') # existing argument, wrong value type @check_units(x=volt, y=volt, result=volt) def foo(x, y): return x + y + 3*volt G = NeuronGroup(1, """ func = foo(x, y) : volt x : volt y : volt""") mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) with pytest.raises(BrianObjectException) as exc: net.run(defaultclock.dt, namespace={'foo': foo}) assert exc_isinstance(exc, TypeError)
def test_poissoninput_errors(): # Targeting non-existing variable G = NeuronGroup(10, """x : volt y : 1""") with pytest.raises(KeyError): PoissonInput(G, 'z', 100, 100 * Hz, weight=1.0) # Incorrect units with pytest.raises(DimensionMismatchError): PoissonInput(G, 'x', 100, 100 * Hz, weight=1.0) with pytest.raises(DimensionMismatchError): 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()) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, NotImplementedError) defaultclock.dt = old_dt
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(): with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc.errisinstance(UnsupportedEquationsException) # 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(): with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc.errisinstance(UnsupportedEquationsException) # 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) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, UnsupportedEquationsException) # 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) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, UnsupportedEquationsException) # Stateful functions aren't either G = NeuronGroup(1, 'dv/dt = -v/(10*ms) + rand()*Hz : 1', method='exact') net = Network(G) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, UnsupportedEquationsException) # Neither is "t" itself G = NeuronGroup(1, 'dv/dt = -v/(10*ms) + t/second**2 : 1', method='exact') net = Network(G) with pytest.raises(BrianObjectException) as exc: net.run(0 * ms) assert exc_isinstance(exc, UnsupportedEquationsException) # 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_declare_types(): if prefs.codegen.target != 'numpy': pytest.skip('numpy-only test') @declare_types(a='integer', b='float', result='highest') def f(a, b): return a*b assert f._arg_types==['integer', 'float'] assert f._return_type == 'highest' @declare_types(b='float') def f(a, b, c): return a*b*c assert f._arg_types==['any', 'float', 'any'] assert f._return_type == 'float' def bad_argtype(): @declare_types(b='floating') def f(a, b, c): return a*b*c with pytest.raises(ValueError): bad_argtype() def bad_argname(): @declare_types(d='floating') def f(a, b, c): return a*b*c with pytest.raises(ValueError): bad_argname() @check_units(a=volt, b=1) @declare_types(a='float', b='integer') def f(a, b): return a*b @declare_types(a='float', b='integer') @check_units(a=volt, b=1) def f(a, b): return a*b def bad_units(): @declare_types(a='integer', b='float') @check_units(a=volt, b=1, result=volt) def f(a, b): return a*b eqs = """ dv/dt = f(v, 1)/second : 1 """ G = NeuronGroup(1, eqs) Network(G).run(1*ms) with pytest.raises(BrianObjectException) as exc: bad_units() assert exc_isinstance(exc, TypeError) def bad_type(): @implementation('numpy', discard_units=True) @declare_types(a='float', result='float') @check_units(a=1, result=1) def f(a): return a eqs = """ a : integer dv/dt = f(a)*v/second : 1 """ G = NeuronGroup(1, eqs) Network(G).run(1*ms) with pytest.raises(BrianObjectException) as exc: bad_type() assert exc_isinstance(exc, TypeError)
def test_manual_user_defined_function(): if prefs.codegen.target != 'numpy': pytest.skip('numpy-only test') default_dt = defaultclock.dt # User defined function without any decorators def foo(x, y): return x + y + 3*volt orig_foo = foo # Since the function is not annotated with check units, we need to specify # both the units of the arguments and the return unit with pytest.raises(ValueError): Function(foo, return_unit=volt) with pytest.raises(ValueError): Function(foo, arg_units=[volt, volt]) # If the function uses the string syntax for "same units", it needs to # specify the names of the arguments with pytest.raises(TypeError): Function(foo, arg_units=[volt, 'x']) with pytest.raises(TypeError): Function(foo, arg_units=[volt, 'x'], arg_names=['x']) # Needs two entries foo = Function(foo, arg_units=[volt, volt], return_unit=volt) assert foo(1*volt, 2*volt) == 6*volt # a can be any unit, b and c need to be the same unit def bar(a, b, c): return a*(b + c) bar = Function(bar, arg_units=[None, None, 'b'], arg_names=['a', 'b', 'c'], return_unit=lambda a, b, c: a*b) assert bar(2, 3*volt, 5*volt) == 16*volt assert bar(2*amp, 3*volt, 5*volt) == 16*watt assert bar(2*volt, 3*amp, 5*amp) == 16*watt with pytest.raises(DimensionMismatchError): bar(2, 3 * volt, 5 * amp) # Incorrect argument units group = NeuronGroup(1, """ dv/dt = foo(x, y)/ms : volt x : 1 y : 1""") net = Network(group) with pytest.raises(BrianObjectException) as exc: net.run(0*ms, namespace={'foo': foo}) assert exc_isinstance(exc, DimensionMismatchError) # Incorrect output unit group = NeuronGroup(1, """ dv/dt = foo(x, y)/ms : 1 x : volt y : volt""") net = Network(group) with pytest.raises(BrianObjectException) as exc: net.run(0*ms, namespace={'foo': foo}) assert exc_isinstance(exc, DimensionMismatchError) G = NeuronGroup(1, """ func = foo(x, y) : volt x : volt y : volt""") G.x = 1*volt G.y = 2*volt mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) net.run(default_dt) assert mon[0].func == [6] * volt # discard units foo.implementations.add_numpy_implementation(orig_foo, discard_units=True) G = NeuronGroup(1, """ func = foo(x, y) : volt x : volt y : volt""") G.x = 1*volt G.y = 2*volt mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) net.run(default_dt) assert mon[0].func == [6] * volt