def test_loop(): ''' Somewhat realistic test with a loop of magic networks ''' def run_simulation(): G = NeuronGroup(10, 'dv/dt = -v / (10*ms) : 1', reset='v=0', threshold='v>1') G.v = np.linspace(0, 1, 10) run(1*ms) # We return potentially problematic references to a VariableView return G.v # First run with catch_logs(log_level=logging.INFO) as l: v = run_simulation() assert v[0] == 0 and 0 < v[-1] < 1 # Check the debug messages for the number of included objects magic_objects = [msg[2] for msg in l if msg[1] == 'brian2.core.magic.magic_objects'][0] assert '4 objects' in magic_objects # Second run with catch_logs(log_level=logging.INFO) as l: v = run_simulation() assert v[0] == 0 and 0 < v[-1] < 1 # Check the debug messages for the number of included objects magic_objects = [msg[2] for msg in l if msg[1] == 'brian2.core.magic.magic_objects'][0] assert '4 objects' in magic_objects
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(UnsupportedEquationsException, 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(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='linear', 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='linear') 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='linear') 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='linear') net = Network(G) net.run(0*ms)
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_set_interval_warning(): clock = Clock(dt=0.1*ms) with catch_logs() as logs: clock.set_interval(0*second, 1000*second) # no problem assert len(logs) == 0 with catch_logs() as logs: clock.set_interval(0*second, 10000000000*second) # too long assert len(logs) == 1 assert logs[0][1].endswith('many_timesteps')
def test_schedule_warning(): previous_device = get_device() from uuid import uuid4 # TestDevice1 supports arbitrary schedules, TestDevice2 does not class TestDevice1(Device): # These functions are needed during the setup of the defaultclock def get_value(self, var): return np.array([0.0001]) def add_array(self, var): pass def init_with_zeros(self, var, dtype): pass def fill_with_array(self, var, arr): pass class TestDevice2(TestDevice1): def __init__(self): super(TestDevice2, self).__init__() self.network_schedule = ['start', 'groups', 'synapses', 'thresholds', 'resets', 'end'] # Unique names are important for getting the warnings again for multiple # runs of the test suite name1 = 'testdevice_' + str(uuid4()) name2 = 'testdevice_' + str(uuid4()) all_devices[name1] = TestDevice1() all_devices[name2] = TestDevice2() set_device(name1) assert schedule_propagation_offset() == 0*ms net = Network() assert schedule_propagation_offset(net) == 0*ms # Any schedule should work net.schedule = list(reversed(net.schedule)) with catch_logs() as l: net.run(0*ms) assert len(l) == 0, 'did not expect a warning' assert schedule_propagation_offset(net) == defaultclock.dt set_device(name2) assert schedule_propagation_offset() == defaultclock.dt # Using the correct schedule should work net.schedule = ['start', 'groups', 'synapses', 'thresholds', 'resets', 'end'] with catch_logs() as l: net.run(0*ms) assert len(l) == 0, 'did not expect a warning' assert schedule_propagation_offset(net) == defaultclock.dt # Using another (e.g. the default) schedule should raise a warning net.schedule = None with catch_logs() as l: net.run(0*ms) assert len(l) == 1 and l[0][1].endswith('schedule_conflict') reset_device(previous_device)
def test_schedule_warning(): previous_device = get_device() from uuid import uuid4 # TestDevice1 supports arbitrary schedules, TestDevice2 does not class TestDevice1(Device): # These functions are needed during the setup of the defaultclock def get_value(self, var): return np.array([0.0001]) def add_array(self, var): pass def init_with_zeros(self, var, dtype): pass def fill_with_array(self, var, arr): pass class TestDevice2(TestDevice1): def __init__(self): super(TestDevice2, self).__init__() self.network_schedule = [ 'start', 'groups', 'synapses', 'thresholds', 'resets', 'end' ] # Unique names are important for getting the warnings again for multiple # runs of the test suite name1 = 'testdevice_' + str(uuid4()) name2 = 'testdevice_' + str(uuid4()) all_devices[name1] = TestDevice1() all_devices[name2] = TestDevice2() set_device(name1) net = Network() # Any schedule should work net.schedule = list(reversed(net.schedule)) with catch_logs() as l: net.run(0 * ms) assert len(l) == 0, 'did not expect a warning' set_device(name2) # Using the correct schedule should work net.schedule = [ 'start', 'groups', 'synapses', 'thresholds', 'resets', 'end' ] with catch_logs() as l: net.run(0 * ms) assert len(l) == 0, 'did not expect a warning' # Using another (e.g. the default) schedule should raise a warning net.schedule = None with catch_logs() as l: net.run(0 * ms) assert len(l) == 1 and l[0][1].endswith('schedule_conflict') reset_device(previous_device)
def test_resolution_warnings(): ''' Test that certain calls to resolve generate a warning. ''' I = 3 * mV tau = 5 * ms another_I = 5 * mV # Only specifying part of the namespace expr = Expression('-(v + I) / tau', namespace={'I' : another_I}, exhaustive=False) # make sure this triggers a warning (the 'I' in the namespace shadows the # I variable defined above with catch_logs() as logs: namespace = expr.resolve(['v']) assert len(logs) == 1 assert logs[0][0] == 'WARNING' assert logs[0][1].endswith('resolution_conflict') assert namespace['I'] == another_I and namespace['tau'] == tau freq = 300 * Hz t = 5 * second # This expression treats t as a special variable and is not actually using # the t above! expr = Expression('sin(2 * 3.141 * freq * t)') with catch_logs() as logs: namespace = expr.resolve([]) assert len(logs) == 1 assert logs[0][0] == 'WARNING' assert logs[0][1].endswith('resolution_conflict') assert namespace['freq'] == freq and not 't' in namespace I = 3 * mV tau = 5 * ms expr = Expression('-(v + I)/ tau') # If we claim that I is an internal variable, it shadows the variable # defined in the local namespace -- this should trigger a warning with catch_logs() as logs: namespace = expr.resolve(['v', 'I']) assert len(logs) == 1 assert logs[0][0] == 'WARNING' assert logs[0][1].endswith('resolution_conflict') assert namespace['tau'] == tau and not 'I' in namespace # A more extreme example: I is defined above, but also in the namespace and # is claimed to be an internal variable expr = Expression('-(v + I)/ tau', namespace={'I': 5 * mV}, exhaustive=False) with catch_logs() as logs: namespace = expr.resolve(['v', 'I']) assert len(logs) == 1 assert logs[0][0] == 'WARNING' assert logs[0][1].endswith('resolution_conflict') assert namespace['tau'] == tau and not 'I' in namespace
def test_warning_internal_variables(): group1 = SimpleGroup(namespace=None, variables={'N': Constant('N', Unit(1), 5)}) group2 = SimpleGroup(namespace=None, variables={'N': Constant('N', Unit(1), 7)}) with catch_logs() as l: group1.resolve_all(['N'], run_namespace={'N': 5}) # should not raise a warning assert len(l) == 0, 'got warnings: %s' % str(l) with catch_logs() as l: group2.resolve_all(['N'], run_namespace={'N': 5}) # should raise a warning assert len(l) == 1, 'got warnings: %s' % str(l) assert l[0][1].endswith('.resolution_conflict')
def test_warning_internal_variables(): group1 = SimpleGroup(namespace=None, variables={'N': Constant('N', 5)}) group2 = SimpleGroup(namespace=None, variables={'N': Constant('N', 7)}) with catch_logs() as l: group1.resolve_all(['N'], run_namespace={'N': 5}) # should not raise a warning assert len(l) == 0, 'got warnings: %s' % str(l) with catch_logs() as l: group2.resolve_all(['N'], run_namespace={'N': 5}) # should raise a warning assert len(l) == 1, 'got warnings: %s' % str(l) assert l[0][1].endswith('.resolution_conflict')
def test_explicit_namespace(): ''' Test resolution with an explicitly provided namespace ''' group = SimpleGroup(namespace={'variable': 42}, variables={}) # Explicitly provided with catch_logs() as l: assert group._resolve('variable', {}).get_value_with_unit() == 42 assert len(l) == 0 # Value from an explicit run namespace with catch_logs() as l: assert group._resolve('yet_another_var', run_namespace={'yet_another_var': 17}).get_value_with_unit() == 17 assert len(l) == 0
def test_semantics_floor_division(): # See Brian2 github issues #815 and #661 G = NeuronGroup(11, '''a : integer b : integer x : 1 y : 1 fvalue : 1 ivalue : integer''', dtype={ 'a': np.int32, 'b': np.int64, 'x': np.float, 'y': np.double }) int_values = np.arange(-5, 6) float_values = np.arange(-5.0, 6.0, dtype=np.double) G.ivalue = int_values G.fvalue = float_values with catch_logs() as l: G.run_regularly(''' a = ivalue//3 b = ivalue//3 x = fvalue//3 y = fvalue//3 ''') run(defaultclock.dt) # XXX: brian2 test adapted here for 1 warning assert len(l) == 1 assert_equal(G.a[:], int_values // 3) assert_equal(G.b[:], int_values // 3) assert_allclose(G.x[:], float_values // 3) assert_allclose(G.y[:], float_values // 3)
def test_math_functions(func): ''' Test that math functions give the same result, regardless of whether used directly or in generated Python or C++ code. ''' test_array = np.array([-1, -0.5, 0, 0.5, 1]) with catch_logs() as _: # Let's suppress warnings about illegal values # Calculate the result directly numpy_result = func(test_array) # Calculate the result in a somewhat complicated way by using a # subexpression in a NeuronGroup if func.__name__ == 'absolute': # we want to use the name abs instead of absolute func_name = 'abs' else: func_name = func.__name__ G = NeuronGroup( len(test_array), '''func = {func}(variable) : 1 variable : 1'''.format(func=func_name)) G.variable = test_array mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) net.run(defaultclock.dt) assert_allclose( numpy_result, mon.func_.flatten(), err_msg='Function %s did not return the correct values' % func.__name__)
def test_math_functions_short(): ''' Test that math functions give the same result, regardless of whether used directly or in generated Python or C++ code. Test only a few functions ''' default_dt = defaultclock.dt test_array = np.array([-1, -0.5, 0, 0.5, 1]) with catch_logs() as _: # Let's suppress warnings about illegal values # Functions with a single argument for func in [exp, np.sqrt]: # Calculate the result directly numpy_result = func(test_array) # Calculate the result in a somewhat complicated way by using a # subexpression in a NeuronGroup if func.__name__ == 'absolute': # we want to use the name abs instead of absolute func_name = 'abs' else: func_name = func.__name__ G = NeuronGroup( len(test_array), '''func = {func}(variable) : 1 variable : 1'''.format(func=func_name)) G.variable = test_array mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) net.run(default_dt) assert_allclose( numpy_result, mon.func_.flatten(), err_msg='Function %s did not return the correct values' % func.__name__) # Functions/operators scalar = 3 # TODO: We are not testing the modulo operator here since it does # not work for double values in C for func, operator in [(np.power, '**')]: # Calculate the result directly numpy_result = func(test_array, scalar) # Calculate the result in a somewhat complicated way by using a # subexpression in a NeuronGroup G = NeuronGroup( len(test_array), '''func = variable {op} scalar : 1 variable : 1'''.format(op=operator)) G.variable = test_array mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) net.run(default_dt) assert_allclose( numpy_result, mon.func_.flatten(), err_msg='Function %s did not return the correct values' % func.__name__)
def test_missing_refractory_warning(): # Forgotten refractory argument with catch_logs() as l: group = NeuronGroup(1, 'dv/dt = -v / (10*ms) : 1 (unless refractory)', threshold='v > 1', reset='v = 0') assert len(l) == 1 assert l[0][0] == 'WARNING' and l[0][1].endswith('no_refractory')
def test_check_for_invalid_values_linear_integrator(): # A differential equation that cannot be solved by the linear # integrator should return nan values to warn the user, and not silently # return incorrect values. See discussion on # https://github.com/brian-team/brian2/issues/626 a = 0.0 / ms b = 1.0 / ms c = -0.5 / ms d = -0.1 / ms eqs = ''' dx/dt = a * x + b * y : 1 dy/dt = c * x + d * y : 1 ''' G = NeuronGroup(1, eqs, threshold='x > 100', reset='x = 0', method='exact') G.x = 1 BrianLogger._log_messages.clear( ) # because the log message is set to be shown only once with catch_logs() as clog: try: run(1 * ms) # this check allows for the possibility that we improve the linear # integrator in the future so that it can handle this equation if numpy.isnan(G.x[0]): assert 'invalid_values' in repr(clog) else: assert G.x[0] != 0 except UnsupportedEquationsException: pass
def test_compiler_error(): # In particular on OSX with clang in a conda environment, compilation might fail. # Switching to a system gcc might help in such cases. Make sure that the error # message mentions that. old_CC = os.environ.get('CC', None) old_CXX = os.environ.get('CXX', None) os.environ.update({ 'CC': 'non-existing-compiler', 'CXX': 'non-existing-compiler++' }) try: with catch_logs() as l: assert not CythonCodeObject.is_available() assert len(l) > 0 # There are additional warnings about compiler flags last_warning = l[-1] assert last_warning[1].endswith('.failed_compile_test') assert 'CC' in last_warning[2] and 'CXX' in last_warning[2] finally: if old_CC: os.environ['CC'] = old_CC else: del os.environ['CC'] if old_CXX: os.environ['CXX'] = old_CXX else: del os.environ['CXX']
def test_math_functions(func, needs_c99_support): ''' Test that math functions give the same result, regardless of whether used directly or in generated Python or C++ code. ''' if not get_device() == RuntimeDevice or prefs.codegen.target != 'numpy': if needs_c99_support and not compiler_supports_c99(): pytest.skip('Support for function "{}" needs a compiler with C99 ' 'support.') test_array = np.array([-1, -0.5, 0, 0.5, 1]) with catch_logs() as _: # Let's suppress warnings about illegal values # Calculate the result directly numpy_result = func(test_array) # Calculate the result in a somewhat complicated way by using a # subexpression in a NeuronGroup if func.__name__ == 'absolute': # we want to use the name abs instead of absolute func_name = 'abs' else: func_name = func.__name__ G = NeuronGroup( len(test_array), '''func = {func}(variable) : 1 variable : 1'''.format(func=func_name)) G.variable = test_array mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) net.run(defaultclock.dt) assert_allclose( numpy_result, mon.func_.flatten(), err_msg='Function %s did not return the correct values' % func.__name__)
def test_transmission_scalar_delay_different_clocks(): inp = SpikeGeneratorGroup( 2, [0, 1], [0, 1] * ms, dt=0.5 * ms, # give the group a unique name to always # get a 'fresh' warning name='sg_%d' % uuid.uuid4()) target = NeuronGroup(2, 'v:1', dt=0.1 * ms) S = Synapses(inp, target, pre='v+=1', delay=0.5 * ms, connect='i==j') mon = StateMonitor(target, 'v', record=True) net = Network(inp, target, S, mon) # We should get a warning when using inconsistent dts with catch_logs() as l: net.run(2 * ms) assert len(l) == 1, 'expected a warning, got %d' % len(l) assert l[0][1].endswith('synapses_dt_mismatch') assert_equal(mon[0].v[mon.t < 0.5 * ms], 0) assert_equal(mon[0].v[mon.t >= 0.5 * ms], 1) assert_equal(mon[1].v[mon.t < 1.5 * ms], 0) assert_equal(mon[1].v[mon.t >= 1.5 * ms], 1)
def test_dependency_check(): def create_net(): G = NeuronGroup(10, 'v: 1', threshold='False') dependent_objects = [ StateMonitor(G, 'v', record=True), SpikeMonitor(G), PopulationRateMonitor(G), Synapses(G, G, pre='v+=1', connect=True) ] return dependent_objects dependent_objects = create_net() # Trying to simulate the monitors/synapses without the group should fail for obj in dependent_objects: assert_raises(ValueError, lambda: Network(obj).run(0*ms)) # simulation with a magic network should work when we have an explicit # reference to one of the objects, but the object should be inactive and # we should get a warning assert all(obj.active for obj in dependent_objects) for obj in dependent_objects: # obj is our explicit reference with catch_logs() as l: run(0*ms) dependency_warnings = [msg[2] for msg in l if msg[1] == 'brian2.core.magic.dependency_warning'] assert len(dependency_warnings) == 1 assert not obj.active
def test_synapses_access_subgroups_problematic(): G1 = NeuronGroup(5, 'x:1') G2 = NeuronGroup(10, 'y:1') SG1 = G1[2:5] SG2 = G2[4:9] S = Synapses(G1, G2, 'w:1') S.connect() # Note that "j" is not ambiguous, because the equivalent in the target group # is called "i" (this previously raised a warning) tests = [ ((SG1, slice(None)), 'i', 1), ((SG1, slice(None)), 'i + N_pre', 2), ((SG1, slice(None)), 'N_pre', 1), ((slice(None), SG2), 'j', 0), ((slice(None), SG2), 'N_post', 1), ((slice(None), SG2), 'N', 1), ((SG1, SG2), 'i', 1), ((SG1, SG2), 'i + j', 1), ((SG1, SG2), 'N_pre', 1), ((SG1, SG2), 'j', 0), ((SG1, SG2), 'N_post', 1), ((SG1, SG2), 'N', 1), # These should not raise a warning ((SG1, SG2), 'w', 0), ((SG1, SG2), 'x_pre', 0), ((SG1, SG2), 'y_post', 0), ((SG1, SG2), 'y', 0) ] for item, value, n_warnings in tests: with catch_logs() as l: S.w.__setitem__(item, value) assert len(l) == n_warnings, 'expected %d, got %d warnings' % (n_warnings, len(l)) assert all([entry[1].endswith('ambiguous_string_expression') for entry in l])
def test_math_functions(): ''' Test that math functions give the same result, regardless of whether used directly or in generated Python or C++ code. ''' default_dt = defaultclock.dt test_array = np.array([-1, -0.5, 0, 0.5, 1]) def int_(x): return array(x, dtype=int) int_.__name__ = 'int' with catch_logs() as _: # Let's suppress warnings about illegal values # Functions with a single argument for func in [cos, tan, sinh, cosh, tanh, arcsin, arccos, arctan, log, log10, exp, np.sqrt, np.ceil, np.floor, np.sign, int_]: # Calculate the result directly numpy_result = func(test_array) # Calculate the result in a somewhat complicated way by using a # subexpression in a NeuronGroup if func.__name__ == 'absolute': # we want to use the name abs instead of absolute func_name = 'abs' else: func_name = func.__name__ G = NeuronGroup(len(test_array), '''func = {func}(variable) : 1 variable : 1'''.format(func=func_name)) G.variable = test_array mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) net.run(default_dt) assert_allclose(numpy_result, mon.func_.flatten(), err_msg='Function %s did not return the correct values' % func.__name__) # Functions/operators scalar = 3 for func, operator in [(np.power, '**'), (np.mod, '%')]: # Calculate the result directly numpy_result = func(test_array, scalar) # Calculate the result in a somewhat complicated way by using a # subexpression in a NeuronGroup G = NeuronGroup(len(test_array), '''func = variable {op} scalar : 1 variable : 1'''.format(op=operator)) G.variable = test_array mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) net.run(default_dt) assert_allclose(numpy_result, mon.func_.flatten(), err_msg='Function %s did not return the correct values' % func.__name__)
def test_multiple_noise_variables_deterministic_noise(): # The "random" values are always 0.5 @implementation('cpp', ''' double randn(int vectorisation_idx) { return 0.5; } ''') @implementation('cython', ''' cdef double randn(int vectorisation_idx): return 0.5 ''') @check_units(N=Unit(1), result=Unit(1)) def fake_randn(N): return 0.5*ones(N) old_randn = DEFAULT_FUNCTIONS['randn'] DEFAULT_FUNCTIONS['randn'] = fake_randn all_eqs = ['''dx/dt = y : 1 dy/dt = -y / (10*ms) + dt**-.5*0.5*ms**-1.5 + dt**-.5*0.5*ms**-1.5: Hz ''', '''dx/dt = y + dt**-.5*0.5*ms**-0.5: 1 dy/dt = -y / (10*ms) + dt**-.5*0.5 * ms**-1.5 : Hz '''] all_eqs_noise = ['''dx/dt = y : 1 dy/dt = -y / (10*ms) + xi_1 * ms**-1.5 + xi_2 * ms**-1.5: Hz ''', '''dx/dt = y + xi_1*ms**-0.5: 1 dy/dt = -y / (10*ms) + xi_2 * ms**-1.5 : Hz '''] for eqs, eqs_noise in zip(all_eqs, all_eqs_noise): G = NeuronGroup(2, eqs, method='euler') G.x = [5, 17] G.y = [25, 5 ] * Hz mon = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon) net.run(10*ms) no_noise_x, no_noise_y = mon.x[:], mon.y[:] for method_name, method in [('euler', euler), ('milstein', milstein)]: # Note that for milstein, the check for diagonal noise will fail, but # it should still work since the two noise variables really do only # present a single variable with catch_logs('WARNING'): G = NeuronGroup(2, eqs_noise, method=method) G.x = [5, 17] G.y = [25, 5 ] * Hz mon = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon) # We run it deterministically, but still we'd detect major errors (e.g. # non-stochastic terms that are added twice, see #330 net.run(10*ms, namespace={'noise_factor': 0}) assert_allclose(mon.x[:], no_noise_x, err_msg='Method %s gave incorrect results' % method_name) assert_allclose(mon.y[:], no_noise_y, err_msg='Method %s gave incorrect results' % method_name)
def test_explicit_namespace(): ''' Test resolution with an explicitly provided namespace ''' explicit_namespace = {'variable': 'explicit_var', 'randn': 'explicit_randn'} # Explicitly provided namespace = create_namespace( explicit_namespace) with catch_logs() as l: assert namespace['variable'] == 'explicit_var' assert len(l) == 0 with catch_logs() as l: # The explicitly provided namespace should not overwrite functions assert isinstance(namespace['randn'], RandnFunction) _assert_one_warning(l)
def test_warning(): from brian2.core.functions import DEFAULT_FUNCTIONS from brian2.units.stdunits import cm as brian_cm # Name in external namespace clashes with unit/function name exp = 23 cm = 42 group = SimpleGroup(namespace=None, variables={}) with catch_logs() as l: resolved = group.resolve_all(['exp'])['exp'] assert resolved == DEFAULT_FUNCTIONS['exp'] assert len(l) == 1, 'got warnings: %s' % str(l) assert l[0][1].endswith('.resolution_conflict') with catch_logs() as l: resolved = group.resolve_all(['cm'])['cm'] assert resolved.get_value_with_unit() == brian_cm assert len(l) == 1, 'got warnings: %s' % str(l) assert l[0][1].endswith('.resolution_conflict')
def test_warning(): from brian2.core.functions import DEFAULT_FUNCTIONS from brian2.units.stdunits import cm as brian_cm # Name in external namespace clashes with unit/function name exp = 23 cm = 42 namespace = create_namespace() local_ns = get_local_namespace(level=0) with catch_logs() as l: resolved = namespace.resolve('exp', ('implicit namespace', local_ns)) assert resolved == DEFAULT_FUNCTIONS['exp'] assert len(l) == 1 assert l[0][1].endswith('.resolution_conflict') with catch_logs() as l: resolved = namespace.resolve('cm', ('implicit namespace', local_ns)) assert resolved == brian_cm assert len(l) == 1 assert l[0][1].endswith('.resolution_conflict')
def test_namespace_warnings(): G = NeuronGroup(1, '''x : 1 y : 1''') # conflicting variable in namespace y = 5 with catch_logs() as l: G.x = 'y' assert len(l) == 1 assert l[0][1].endswith('.resolution_conflict') # conflicting variables with special meaning i = 5 N = 3 with catch_logs() as l: G.x = 'i / N' assert len(l) == 2 assert l[0][1].endswith('.resolution_conflict') assert l[1][1].endswith('.resolution_conflict')
def test_delete_directory(): set_device('cpp_standalone', build_on_run=True, directory=None) group = NeuronGroup(10, 'dv/dt = -v / (10*ms) : volt', method='exact') group.v = np.arange(10) * mV # uses the static array mechanism run(defaultclock.dt) # Add a new file dummy_file = os.path.join(device.project_dir, 'results', 'dummy.txt') open(dummy_file, 'w').flush() assert os.path.isfile(dummy_file) with catch_logs() as logs: device.delete(directory=True) assert len(logs) == 1 assert os.path.isfile(dummy_file) with catch_logs() as logs: device.delete(directory=True, force=True) assert len(logs) == 0 # everything should be deleted assert not os.path.exists(device.project_dir)
def test_explicit_namespace(): ''' Test resolution with an explicitly provided namespace ''' explicit_namespace = { 'variable': 'explicit_var', 'randn': 'explicit_randn' } # Explicitly provided namespace = create_namespace(explicit_namespace) with catch_logs() as l: assert namespace['variable'] == 'explicit_var' assert len(l) == 0 with catch_logs() as l: # The explicitly provided namespace should not overwrite functions assert isinstance(namespace['randn'], RandnFunction) _assert_one_warning(l)
def test_no_synapses(): # Synaptic pathway but no synapses G1 = NeuronGroup(1, '', threshold='True') G2 = NeuronGroup(1, 'v:1') S = Synapses(G1, G2, pre='v+=1', name='synapses_'+str(uuid.uuid4()).replace('-', '_')) net = Network(G1, G2, S) with catch_logs() as l: net.run(defaultclock.dt) assert len(l) == 1, 'expected 1 warning, got %d' % len(l) assert l[0][1].endswith('.no_synapses')
def test_explicit_namespace(): ''' Test resolution with an explicitly provided namespace ''' explicit_namespace = {'variable': 'explicit_var'} # Explicitly provided namespace = create_namespace( explicit_namespace) with catch_logs() as l: assert namespace['variable'] == 'explicit_var' assert len(l) == 0
def test_multiple_noise_variables_deterministic_noise( fake_randn_randn_fixture): all_eqs = [ '''dx/dt = y : 1 dy/dt = -y / (10*ms) + dt**-.5*0.5*ms**-1.5 + dt**-.5*0.5*ms**-1.5: Hz ''', '''dx/dt = y + dt**-.5*0.5*ms**-0.5: 1 dy/dt = -y / (10*ms) + dt**-.5*0.5 * ms**-1.5 : Hz ''' ] all_eqs_noise = [ '''dx/dt = y : 1 dy/dt = -y / (10*ms) + xi_1 * ms**-1.5 + xi_2 * ms**-1.5: Hz ''', '''dx/dt = y + xi_1*ms**-0.5: 1 dy/dt = -y / (10*ms) + xi_2 * ms**-1.5 : Hz ''' ] monitors_no_noise = [] monitors = [] for eqs, eqs_noise in zip(all_eqs, all_eqs_noise): G = NeuronGroup(2, eqs, method='euler') G.x = [5, 17] G.y = [25, 5] * Hz mon = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon) net.run(10 * ms) monitors_no_noise.append(mon) monitors.append(dict()) for method_name, method in [('euler', euler), ('heun', heun)]: with catch_logs('WARNING'): G = NeuronGroup(2, eqs_noise, method=method) G.x = [5, 17] G.y = [25, 5] * Hz mon = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon) net.run(10 * ms) monitors[-1][method_name] = mon device.build(direct_call=False, **device.build_options) for i in range(len(all_eqs)): mon = monitors_no_noise[i] no_noise_x, no_noise_y = mon.x[:], mon.y[:] for method_name in ['euler', 'heun']: mon = monitors[i][method_name] assert_allclose( mon.x[:], no_noise_x, err_msg=f'Method {method_name} gave incorrect results') assert_allclose( mon.y[:], no_noise_y, err_msg=f'Method {method_name} gave incorrect results')
def test_multiple_noise_variables_deterministic_noise(): # The "random" values are always 0.5 @implementation('cpp', ''' double randn(int vectorisation_idx) { return 0.5; } ''') @implementation('cython', ''' cdef double randn(int vectorisation_idx): return 0.5 ''') @check_units(N=Unit(1), result=Unit(1)) def fake_randn(N): return 0.5*ones(N) old_randn = DEFAULT_FUNCTIONS['randn'] DEFAULT_FUNCTIONS['randn'] = fake_randn all_eqs = ['''dx/dt = y : 1 dy/dt = -y / (10*ms) + dt**-.5*0.5*ms**-1.5 + dt**-.5*0.5*ms**-1.5: Hz ''', '''dx/dt = y + dt**-.5*0.5*ms**-0.5: 1 dy/dt = -y / (10*ms) + dt**-.5*0.5 * ms**-1.5 : Hz '''] all_eqs_noise = ['''dx/dt = y : 1 dy/dt = -y / (10*ms) + xi_1 * ms**-1.5 + xi_2 * ms**-1.5: Hz ''', '''dx/dt = y + xi_1*ms**-0.5: 1 dy/dt = -y / (10*ms) + xi_2 * ms**-1.5 : Hz '''] for eqs, eqs_noise in zip(all_eqs, all_eqs_noise): G = NeuronGroup(2, eqs, method='euler') G.x = [5, 17] G.y = [25, 5 ] * Hz mon = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon) net.run(10*ms) no_noise_x, no_noise_y = mon.x[:], mon.y[:] for method_name, method in [('euler', euler), ('heun', heun)]: with catch_logs('WARNING'): G = NeuronGroup(2, eqs_noise, method=method) G.x = [5, 17] G.y = [25, 5 ] * Hz mon = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon) net.run(10*ms) assert_allclose(mon.x[:], no_noise_x, err_msg='Method %s gave incorrect results' % method_name) assert_allclose(mon.y[:], no_noise_y, err_msg='Method %s gave incorrect results' % method_name)
def test_math_functions_short(): ''' Test that math functions give the same result, regardless of whether used directly or in generated Python or C++ code. Test only a few functions ''' default_dt = defaultclock.dt test_array = np.array([-1, -0.5, 0, 0.5, 1]) with catch_logs() as _: # Let's suppress warnings about illegal values # Functions with a single argument for func in [exp, np.sqrt]: # Calculate the result directly numpy_result = func(test_array) # Calculate the result in a somewhat complicated way by using a # subexpression in a NeuronGroup if func.__name__ == 'absolute': # we want to use the name abs instead of absolute func_name = 'abs' else: func_name = func.__name__ G = NeuronGroup(len(test_array), '''func = {func}(variable) : 1 variable : 1'''.format(func=func_name)) G.variable = test_array mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) net.run(default_dt) assert_allclose(numpy_result, mon.func_.flatten(), err_msg='Function %s did not return the correct values' % func.__name__) # Functions/operators scalar = 3 # TODO: We are not testing the modulo operator here since it does # not work for double values in C for func, operator in [(np.power, '**')]: # Calculate the result directly numpy_result = func(test_array, scalar) # Calculate the result in a somewhat complicated way by using a # subexpression in a NeuronGroup G = NeuronGroup(len(test_array), '''func = variable {op} scalar : 1 variable : 1'''.format(op=operator)) G.variable = test_array mon = StateMonitor(G, 'func', record=True) net = Network(G, mon) net.run(default_dt) assert_allclose(numpy_result, mon.func_.flatten(), err_msg='Function %s did not return the correct values' % func.__name__)
def test_schedule_warning(): previous_device = get_device() from uuid import uuid4 # TestDevice1 supports arbitrary schedules, TestDevice2 does not class TestDevice1(Device): pass class TestDevice2(Device): def __init__(self): super(TestDevice2, self).__init__() self.network_schedule = ['start', 'groups', 'synapses', 'thresholds', 'resets', 'end'] # Unique names are important for getting the warnings again for multiple # runs of the test suite name1 = 'testdevice_' + str(uuid4()) name2 = 'testdevice_' + str(uuid4()) all_devices[name1] = TestDevice1() all_devices[name2] = TestDevice2() set_device(name1) net = Network() # Any schedule should work net.schedule = list(reversed(net.schedule)) with catch_logs() as l: net.run(0*ms) assert len(l) == 0, 'did not expect a warning' set_device(name2) # Using the correct schedule should work net.schedule = ['start', 'groups', 'synapses', 'thresholds', 'resets', 'end'] with catch_logs() as l: net.run(0*ms) assert len(l) == 0, 'did not expect a warning' # Using another (e.g. the default) schedule should raise a warning net.schedule = None with catch_logs() as l: net.run(0*ms) assert len(l) == 1 and l[0][1].endswith('schedule_conflict') set_device(previous_device)
def test_state_variables_group_as_index_problematic(): G = NeuronGroup(10, 'v : 1') SG = G[4:9] G.v = 1 tests = [('i', 1), ('N', 1), ('N + i', 2), ('v', 0)] for value, n_warnings in tests: with catch_logs() as l: G.v.__setitem__(SG, value) assert len(l) == n_warnings, 'expected %d, got %d warnings' % ( n_warnings, len(l)) assert all([ entry[1].endswith('ambiguous_string_expression') for entry in l ])
def test_no_synapses(): # Synaptic pathway but no synapses G1 = NeuronGroup(1, '', threshold='True') G2 = NeuronGroup(1, 'v:1') S = Synapses(G1, G2, pre='v+=1', name='synapses_' + str(uuid.uuid4()).replace('-', '_')) net = Network(G1, G2, S) with catch_logs() as l: net.run(defaultclock.dt) assert len(l) == 1, 'expected 1 warning, got %d' % len(l) assert l[0][1].endswith('.no_synapses')
def test_poissongroup_namespace(): rate_const = 0*Hz P = PoissonGroup(1, rates='rate_const', namespace={'rate_const': 1/defaultclock.dt}, name='poissongroup_%s' % (uuid.uuid4().hex)) P2 = PoissonGroup(1, rates='rate_const') mon = SpikeMonitor(P) mon2 = SpikeMonitor(P2) with catch_logs() as l: run(2*defaultclock.dt) assert len(l) == 1 assert l[0][1].endswith('resolution_conflict') assert mon.num_spikes == 2 assert mon2.num_spikes == 0
def test_multiple_noise_variables_extended(): # Some actual simulations with multiple noise variables eqs = '''dx/dt = y : 1 dy/dt = - 1*ms**-1*y - 40*ms**-2*x : Hz ''' all_eqs_noise = [ '''dx/dt = y : 1 dy/dt = noise_factor*ms**-1.5*xi_1 + noise_factor*ms**-1.5*xi_2 - 1*ms**-1*y - 40*ms**-2*x : Hz ''', '''dx/dt = y + noise_factor*ms**-0.5*xi_1: 1 dy/dt = noise_factor*ms**-1.5*xi_2 - 1*ms**-1*y - 40*ms**-2*x : Hz ''' ] G = NeuronGroup(2, eqs, method='euler') G.x = [0.5, 1] G.y = [0, 0.5] * Hz mon1 = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon1) net.run(10 * ms) monitors = [] for eqs_noise in all_eqs_noise: monitors.append(dict()) for method_name, method in [('euler', euler), ('heun', heun)]: with catch_logs('WARNING'): G = NeuronGroup(2, eqs_noise, method=method) G.x = [0.5, 1] G.y = [0, 0.5] * Hz mon = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon) # We run it deterministically, but still we'd detect major errors (e.g. # non-stochastic terms that are added twice, see #330 net.run(10 * ms, namespace={'noise_factor': 0}) monitors[-1][method_name] = mon device.build(direct_call=False, **device.build_options) no_noise_x, no_noise_y = mon1.x[:], mon1.y[:] for i in range(len(all_eqs_noise)): for method_name in ['euler', 'heun']: mon = monitors[i][method_name] assert_allclose( mon.x[:], no_noise_x, err_msg=f'Method {method_name} gave incorrect results') assert_allclose( mon.y[:], no_noise_y, err_msg=f'Method {method_name} gave incorrect results')
def test_state_variables_group_as_index_problematic(): G = NeuronGroup(10, 'v : 1') SG = G[4:9] G.v = 1 tests = [('i', 1), ('N', 1), ('N + i', 2), ('v', 0)] for value, n_warnings in tests: with catch_logs() as l: G.v.__setitem__(SG, value) assert len(l) == n_warnings, 'expected %d, got %d warnings' % (n_warnings, len(l)) assert all([entry[1].endswith('ambiguous_string_expression') for entry in l])
def test_spikegenerator_extreme_period(): ''' Basic test for `SpikeGeneratorGroup`. ''' indices = np.array([0, 1, 2]) times = np.array([0, 1, 2]) * ms SG = SpikeGeneratorGroup(5, indices, times, period=1e6 * second) s_mon = SpikeMonitor(SG) with catch_logs() as l: run(10 * ms) assert_equal(s_mon.i, np.array([0, 1, 2])) assert_allclose(s_mon.t, [0, 1, 2] * ms) assert len(l) == 1 and l[0][1].endswith('spikegenerator_long_period')
def test_spikegenerator_extreme_period(): ''' Basic test for `SpikeGeneratorGroup`. ''' indices = np.array([0, 1, 2]) times = np.array([0, 1, 2]) * ms SG = SpikeGeneratorGroup(5, indices, times, period=1e6*second) s_mon = SpikeMonitor(SG) with catch_logs() as l: run(10*ms) assert_equal(s_mon.i, np.array([0, 1, 2])) assert_allclose(s_mon.t, [0, 1, 2]*ms) assert len(l) == 1 and l[0][1].endswith('spikegenerator_long_period')
def test_spikegenerator_multiple_runs(): indices = np.zeros(5) times = np.arange(5) * ms spike_gen = SpikeGeneratorGroup(1, indices, times) # all good spike_mon = SpikeMonitor(spike_gen) run(5 * ms) # Setting the same spike times again should not do anything, since they are # before the start of the current simulation spike_gen.set_spikes(indices, times) # however, a warning should be raised with catch_logs() as l: run(5 * ms) device.build(direct_call=False, **device.build_options) assert len(l) == 1 and l[0][1].endswith('ignored_spikes') assert spike_mon.num_spikes == 5
def test_spikegenerator_multiple_runs(): indices = np.zeros(5) times = np.arange(5)*ms spike_gen = SpikeGeneratorGroup(1, indices, times) # all good spike_mon = SpikeMonitor(spike_gen) run(5*ms) # Setting the same spike times again should not do anything, since they are # before the start of the current simulation spike_gen.set_spikes(indices, times) # however, a warning should be raised with catch_logs() as l: run(5*ms) device.build(direct_call=False, **device.build_options) assert len(l) == 1 and l[0][1].endswith('ignored_spikes') assert spike_mon.num_spikes == 5
def test_profile_warning(): # Test that profiling info is not 0 set_device('cuda_standalone', directory=None) prefs.devices.cuda_standalone.profile = True G = NeuronGroup(1, 'v:1', threshold='True') BrianLogger._log_messages.clear() with catch_logs() as logs: run(defaultclock.dt, profile=True) assert len(logs) == 1, len(logs) assert logs[0][0] == 'WARNING' assert logs[0][1] == 'brian2.devices.cuda_standalone'
def test_magic_weak_reference(): ''' Test that holding a weak reference to an object does not make it get simulated.''' G1 = NeuronGroup(1, 'v:1') # this object should not be included G2 = weakref.ref(NeuronGroup(1, 'v:1')) with catch_logs(log_level=logging.DEBUG) as l: run(1*ms) # Check the debug messages for the number of included objects magic_objects = [msg[2] for msg in l if msg[1] == 'brian2.core.magic.magic_objects'][0] assert '2 objects' in magic_objects, 'Unexpected log message: %s' % magic_objects
def test_magic_unused_object(): '''Test that creating unused objects does not affect the magic system.''' def create_group(): # Produce two objects but return only one G1 = NeuronGroup(1, 'v:1') # no Thresholder or Resetter G2 = NeuronGroup(1, 'v:1') # This object should be garbage collected return G1 G = create_group() with catch_logs(log_level=logging.INFO) as l: run(1*ms) # Check the debug messages for the number of included objects magic_objects = [msg[2] for msg in l if msg[1] == 'brian2.core.magic.magic_objects'][0] assert '2 objects' in magic_objects, 'Unexpected log message: %s' % magic_objects
def test_transmission_scalar_delay_different_clocks(): inp = SpikeGeneratorGroup(2, [0, 1], [0, 1]*ms, dt=0.5*ms, # give the group a unique name to always # get a 'fresh' warning name='sg_%d' % uuid.uuid4()) target = NeuronGroup(2, 'v:1', dt=0.1*ms) S = Synapses(inp, target, pre='v+=1', delay=0.5*ms, connect='i==j') mon = StateMonitor(target, 'v', record=True) net = Network(inp, target, S, mon) # We should get a warning when using inconsistent dts with catch_logs() as l: net.run(2*ms) assert len(l) == 1, 'expected a warning, got %d' % len(l) assert l[0][1].endswith('synapses_dt_mismatch') assert_equal(mon[0].v[mon.t<0.5*ms], 0) assert_equal(mon[0].v[mon.t>=0.5*ms], 1) assert_equal(mon[1].v[mon.t<1.5*ms], 0) assert_equal(mon[1].v[mon.t>=1.5*ms], 1)
def test_multiple_noise_variables_deterministic_noise(): DEFAULT_FUNCTIONS["randn"] = fake_randn all_eqs = [ """dx/dt = y : 1 dy/dt = -y / (10*ms) + dt**-.5*0.5*ms**-1.5 + dt**-.5*0.5*ms**-1.5: Hz """, """dx/dt = y + dt**-.5*0.5*ms**-0.5: 1 dy/dt = -y / (10*ms) + dt**-.5*0.5 * ms**-1.5 : Hz """, ] all_eqs_noise = [ """dx/dt = y : 1 dy/dt = -y / (10*ms) + xi_1 * ms**-1.5 + xi_2 * ms**-1.5: Hz """, """dx/dt = y + xi_1*ms**-0.5: 1 dy/dt = -y / (10*ms) + xi_2 * ms**-1.5 : Hz """, ] for eqs, eqs_noise in zip(all_eqs, all_eqs_noise): G = NeuronGroup(2, eqs, method="euler") G.x = [5, 17] G.y = [25, 5] * Hz mon = StateMonitor(G, ["x", "y"], record=True) net = Network(G, mon) net.run(10 * ms) no_noise_x, no_noise_y = mon.x[:], mon.y[:] for method_name, method in [("euler", euler), ("heun", heun)]: with catch_logs("WARNING"): G = NeuronGroup(2, eqs_noise, method=method) G.x = [5, 17] G.y = [25, 5] * Hz mon = StateMonitor(G, ["x", "y"], record=True) net = Network(G, mon) net.run(10 * ms) assert_allclose(mon.x[:], no_noise_x, err_msg="Method %s gave incorrect results" % method_name) assert_allclose(mon.y[:], no_noise_y, err_msg="Method %s gave incorrect results" % method_name)
def test_multiple_noise_variables_extended(): # Some actual simulations with multiple noise variables eqs = '''dx/dt = y : 1 dy/dt = - 1*ms**-1*y - 40*ms**-2*x : Hz ''' all_eqs_noise = ['''dx/dt = y : 1 dy/dt = noise_factor*ms**-1.5*xi_1 + noise_factor*ms**-1.5*xi_2 - 1*ms**-1*y - 40*ms**-2*x : Hz ''', '''dx/dt = y + noise_factor*ms**-0.5*xi_1: 1 dy/dt = noise_factor*ms**-1.5*xi_2 - 1*ms**-1*y - 40*ms**-2*x : Hz '''] G = NeuronGroup(2, eqs, method='euler') G.x = [0.5, 1] G.y = [0, 0.5] * Hz mon = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon) net.run(10*ms) no_noise_x, no_noise_y = mon.x[:], mon.y[:] for eqs_noise in all_eqs_noise: for method_name, method in [('euler', euler), ('heun', heun), ('milstein', milstein)]: # Note that for milstein, the check for diagonal noise will fail, but # it should still work since the two noise variables really do only # present a single variable with catch_logs('WARNING'): G = NeuronGroup(2, eqs_noise, method=method) G.x = [0.5, 1] G.y = [0, 0.5] * Hz mon = StateMonitor(G, ['x', 'y'], record=True) net = Network(G, mon) # We run it deterministically, but still we'd detect major errors (e.g. # non-stochastic terms that are added twice, see #330 net.run(10*ms, namespace={'noise_factor': 0}) assert_allclose(mon.x[:], no_noise_x, err_msg='Method %s gave incorrect results' % method_name) assert_allclose(mon.y[:], no_noise_y, err_msg='Method %s gave incorrect results' % method_name)