From 8469261d116a6574b49ee06155b9935d09369ccd Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 3 Feb 2026 15:59:15 +0000 Subject: [PATCH 01/12] cfg to set n_synaps_cores --- spynnaker/pyNN/spinnaker.py | 21 ++++++++++++++++++++- spynnaker/pyNN/spynnaker.cfg | 6 ++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/spynnaker/pyNN/spinnaker.py b/spynnaker/pyNN/spinnaker.py index 465d792e98..77ff2542ec 100644 --- a/spynnaker/pyNN/spinnaker.py +++ b/spynnaker/pyNN/spinnaker.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import importlib import logging import os from typing import Any, Collection, Optional, Type, Union, cast @@ -26,7 +27,7 @@ from spinn_utilities.log import FormatAdapter -from spinn_utilities.config_holder import get_config_bool +from spinn_utilities.config_holder import get_config_bool, get_config_str_list from spinn_utilities.overrides import overrides from spinn_front_end_common.interface.abstract_spinnaker_base import ( @@ -123,6 +124,24 @@ def __init__( # Clears all previously added ceiling on the number of neurons per # core, the number of synapse cores and allowing of delay extensions AbstractPyNNNeuronModel.reset_all() + self._add_test_cfg_settings() + + def _add_test_cfg_settings(self) -> None: + """ + Ideally this function will find nothing to do. + + This is designed for switching scripts like PyNNExamples + to split mode without the need to change the scripts. + + Better to call set_model_n_synapse_cores in the script + """ + n_synapse_cores = get_config_str_list("Simulation", "n_synapse_cores") + for n_synapse_cores in n_synapse_cores: + path, name, n = n_synapse_cores.split(":") + model_class = getattr(importlib.import_module(path), name) + model = model_class() + model.set_model_n_synapse_cores(int(n)) + logger.warning(f"{model=} {n_synapse_cores=} set from cfg") @overrides(AbstractSpinnakerBase._add_cfg_defaults_and_template) def _add_cfg_defaults_and_template(self) -> None: diff --git a/spynnaker/pyNN/spynnaker.cfg b/spynnaker/pyNN/spynnaker.cfg index 569ce8bede..59a06717ab 100644 --- a/spynnaker/pyNN/spynnaker.cfg +++ b/spynnaker/pyNN/spynnaker.cfg @@ -63,6 +63,12 @@ n_colour_bits = 4 error_on_non_spynnaker_pynn = True @error_on_non_spynnaker_pynn = Whether to error or just warn on non-spynnaker-compatible PyNN +n_synapse_cores = None +@n_synapse_cores = Testing Option! + A better way is to call set_model_n_synapse_cores on the model. + Mapping of a AbstractPyNNNeuronModel to n_synapse_cores to be set + In the format model:n_synapse_cores,model:n_synapse_cores + [Recording] @ = Section for the sending of live spikes. From 4d03247ef676d67646131ad3aef43eb98e36b48d Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Tue, 3 Feb 2026 15:59:31 +0000 Subject: [PATCH 02/12] test binaries at leat run --- .../test_various/test_binaries.py | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 spynnaker_integration_tests/test_various/test_binaries.py diff --git a/spynnaker_integration_tests/test_various/test_binaries.py b/spynnaker_integration_tests/test_various/test_binaries.py new file mode 100644 index 0000000000..509eeace70 --- /dev/null +++ b/spynnaker_integration_tests/test_various/test_binaries.py @@ -0,0 +1,120 @@ +# Copyright (c) 2026 The University of Manchester +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import pyNN.spiNNaker as sim +from spinnaker_testbase import BaseTestCase + +from spynnaker.pyNN.data import SpynnakerDataView +from spynnaker.pyNN.models.abstract_pynn_model import AbstractPyNNModel +from spynnaker.pyNN.models.populations import Population + +INTERVAL = 50 +N_NEURONS = 5 + + +class TestBinaries(BaseTestCase): + + def add_population(self, model: AbstractPyNNModel, weight:int, + input_pop: Population) -> None: + population = sim.Population( + N_NEURONS, model, label = model.name) + sim.Projection(input_pop, population, sim.OneToOneConnector(), + synapse_type=sim.StaticSynapse(weight=weight, delay=1)) + population.record("spikes") + return population + + def add_neuron_population(self, model: AbstractPyNNModel, weight:int, + input_pop: Population) -> None: + population = sim.Population( + N_NEURONS, model, label = model.name, n_synapse_cores=1) + sim.Projection(input_pop, population, sim.OneToOneConnector(), + synapse_type=sim.StaticSynapse(weight=weight, delay=1)) + population.record("spikes") + return population + + def check_population(self, population: Population)-> None: + neo = population.get_data(variables="spikes") + spikes_trains = neo.segments[0].spiketrains + print(population.label, spikes_trains) + self.assertEqual(len(spikes_trains), N_NEURONS) + for spike_trains in spikes_trains: + self.assertGreaterEqual(len(spikes_trains), 1) + + def check_binaries(self) -> None: + + sim.setup(timestep=1.0) + + spike_times = [] + for i in range(N_NEURONS): + spike_times.append([i, i + INTERVAL, i + INTERVAL * 2]) + input_pop = sim.Population( + N_NEURONS, sim.SpikeSourceArray(spike_times=spike_times), + label="input") + + # Ideally there should be better tests for these modules + # remove models tested elsewhere! + populations = [] + + # IF_curr_delta_ca2_adaptive.aplx + #populations.append(self.add_population( + # sim.extra_models.IFCurrDeltaCa2Adaptive(), 15, input_pop)) + + # IF_curr_delta_ca2_adaptive_neuron.aplx + #populations.append(self.add_neuron_population( + # sim.extra_models.IFCurrDeltaCa2Adaptive(), 15, input_pop)) + + #IF_curr_exp_ca2_adaptive_stdp_mad_pair_additive.aplx + + #IF_curr_exp_dual_neuron.aplx + #populations.append(self.add_neuron_population( + # sim.extra_models.IF_curr_dual_exp(), 5, input_pop)) + + #IF_curr_exp_sEMD_neuron.aplx + populations.append(self.add_population( + sim.extra_models.IF_curr_exp_sEMD(), 15, input_pop)) + + #IF_curr_exp_stdp_mad_recurrent_pre_stochastic_multiplicative.aplx + #IZK_cond_exp_dual.aplx + #IZK_cond_exp_dual_neuron.aplx + #IZK_cond_exp_dual_stdp_mad_pair_additive.aplx + #external_device_lif_control_neuron.aplx + #synapses_stdp_izhikevich_neuromodulation_pair_additive_structural_last_neuron_distance_weight.aplx + #synapses_stdp_izhikevich_neuromodulation_pair_multiplicative.aplx + #synapses_stdp_izhikevich_neuromodulation_vogels_2011_additive.aplx + #synapses_stdp_mad_nearest_pair_additive.aplx + #synapses_stdp_mad_nearest_pair_additive_structural_random_distance_weight.aplx + #synapses_stdp_mad_nearest_pair_multiplicative.aplx + #synapses_stdp_mad_pair_multiplicative.aplx + #synapses_stdp_mad_pfister_triplet_additive.aplx + #synapses_stdp_mad_recurrent_dual_fsm_multiplicative.aplx + #synapses_stdp_mad_vogels_2011_additive.aplx + + sim.run(N_NEURONS + INTERVAL * 3) + + for population in populations: + self.check_population(population) + sim.end() + + targets = SpynnakerDataView.get_executable_targets() + binaries = set() + for target in targets.binaries: + _, file = os.path.split(target) + binaries.add(file) + print(binaries) + + + def test_binaries(self) -> None: + self.runsafe(self.check_binaries) + From 52d97a7777d831aed43b118480f077d859d291bd Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 4 Feb 2026 08:02:57 +0000 Subject: [PATCH 03/12] test split --- .../test_live_neuron_voltage.py | 3 +++ .../test_various/test_binaries.py | 24 +++++-------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/spynnaker_integration_tests/test_external_devices/test_live_neuron_voltage.py b/spynnaker_integration_tests/test_external_devices/test_live_neuron_voltage.py index e72a435a9e..f6fd47b483 100644 --- a/spynnaker_integration_tests/test_external_devices/test_live_neuron_voltage.py +++ b/spynnaker_integration_tests/test_external_devices/test_live_neuron_voltage.py @@ -120,6 +120,7 @@ def live_neuron_voltage() -> None: translator_2 = Translator(devices_2) model_2 = p.external_devices.ExternalDeviceLifControl( devices_2, create_edges, translator_2) + model_2.set_model_n_synapse_cores(1) conn = p.external_devices.SpynnakerLiveSpikesConnection( receive_labels=["stim"], local_port=None) conn.add_receive_callback("stim", spike_receiver) @@ -160,6 +161,8 @@ class TestLiveNeuronVoltage(BaseTestCase): def test_live_neuron_voltage(self) -> None: self.runsafe(live_neuron_voltage) + self.check_binaries_used(["external_device_lif_control.aplx", + "external_device_lif_control_neuron.aplx"]) if __name__ == '__main__': diff --git a/spynnaker_integration_tests/test_various/test_binaries.py b/spynnaker_integration_tests/test_various/test_binaries.py index 509eeace70..a7514b43a8 100644 --- a/spynnaker_integration_tests/test_various/test_binaries.py +++ b/spynnaker_integration_tests/test_various/test_binaries.py @@ -68,23 +68,15 @@ def check_binaries(self) -> None: populations = [] # IF_curr_delta_ca2_adaptive.aplx - #populations.append(self.add_population( - # sim.extra_models.IFCurrDeltaCa2Adaptive(), 15, input_pop)) + populations.append(self.add_population( + sim.extra_models.IFCurrDeltaCa2Adaptive(), 15, input_pop)) # IF_curr_delta_ca2_adaptive_neuron.aplx - #populations.append(self.add_neuron_population( - # sim.extra_models.IFCurrDeltaCa2Adaptive(), 15, input_pop)) + populations.append(self.add_neuron_population( + sim.extra_models.IFCurrDeltaCa2Adaptive(), 15, input_pop)) #IF_curr_exp_ca2_adaptive_stdp_mad_pair_additive.aplx - #IF_curr_exp_dual_neuron.aplx - #populations.append(self.add_neuron_population( - # sim.extra_models.IF_curr_dual_exp(), 5, input_pop)) - - #IF_curr_exp_sEMD_neuron.aplx - populations.append(self.add_population( - sim.extra_models.IF_curr_exp_sEMD(), 15, input_pop)) - #IF_curr_exp_stdp_mad_recurrent_pre_stochastic_multiplicative.aplx #IZK_cond_exp_dual.aplx #IZK_cond_exp_dual_neuron.aplx @@ -107,12 +99,8 @@ def check_binaries(self) -> None: self.check_population(population) sim.end() - targets = SpynnakerDataView.get_executable_targets() - binaries = set() - for target in targets.binaries: - _, file = os.path.split(target) - binaries.add(file) - print(binaries) + self.check_binaries_used(["IF_curr_delta_ca2_adaptive.aplx", + "IF_curr_delta_ca2_adaptive_neuron.aplx"]) def test_binaries(self) -> None: From 8b56cbf1dedf168029bcbe05ce0d8f66480500f3 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 4 Feb 2026 11:14:26 +0000 Subject: [PATCH 04/12] test various binaries --- .../test_stdp_random_run.py | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py b/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py index 476ff32af9..6a1c433e10 100644 --- a/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py +++ b/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py @@ -12,9 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +import numpy import pyNN.spiNNaker as sim + from spinnaker_testbase import BaseTestCase -import numpy +from spynnaker.pyNN.models.abstract_pynn_model import AbstractPyNNModel class TestSTDPRandomRun(BaseTestCase): @@ -22,11 +24,11 @@ class TestSTDPRandomRun(BaseTestCase): # same thing being loaded twice, both with data generated off and on the # machine - def do_run(self) -> None: + def run_model(self, model: AbstractPyNNModel) -> None: sim.setup(1.0) pop = sim.Population(1, sim.IF_curr_exp(i_offset=5.0), label="pop") pop.record("spikes") - pop_2 = sim.Population(1, sim.IF_curr_exp(), label="pop_2") + pop_2 = sim.Population(1, model, label="pop_2") proj = sim.Projection( pop, pop_2, sim.AllToAllConnector(), sim.STDPMechanism( @@ -53,7 +55,28 @@ def do_run(self) -> None: assert numpy.array_equal(weights_1_1, weights_2_1) assert numpy.array_equal(weights_1_2, weights_2_2) + assert len(spikes_1[0]) > 0 assert numpy.array_equal(spikes_1, spikes_2) - def test_do_run(self) -> None: - self.runsafe(self.do_run) + def _do_if_curr_exp(self) -> None: + self.run_model(sim.IF_curr_exp()) + + def test_check_if_curr_exp(self) -> None: + self.runsafe(self._do_if_curr_exp) + self.check_binary_used("IF_curr_exp_stdp_mad_pair_additive.aplx") + + def _do_if_curr_exp_ca2_additive(self) -> None: + self.run_model(sim.extra_models.IFCurrExpCa2Adaptive()) + + def test_check_if_curr_exp(self) -> None: + self.runsafe(self._do_if_curr_exp_ca2_additive) + self.check_binary_used( + "IF_curr_exp_ca2_adaptive_stdp_mad_pair_additive.aplx") + + def _do_izk_cond_exp_dual(self) -> None: + self.run_model(sim.extra_models.Izhikevich_cond_dual()) + + def test_check_if_curr_exp(self) -> None: + self.runsafe(self._do_izk_cond_exp_dual) + self.check_binary_used( + "IZK_cond_exp_dual_stdp_mad_pair_additive.aplx") From 20d14d96a460bebd5c4e6ad78e67a3c1da2f88c5 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 4 Feb 2026 11:15:23 +0000 Subject: [PATCH 05/12] test IFCurrExpCa2Adaptive --- .../test_various/test_binaries.py | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/spynnaker_integration_tests/test_various/test_binaries.py b/spynnaker_integration_tests/test_various/test_binaries.py index a7514b43a8..4d34f90de8 100644 --- a/spynnaker_integration_tests/test_various/test_binaries.py +++ b/spynnaker_integration_tests/test_various/test_binaries.py @@ -12,11 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os import pyNN.spiNNaker as sim from spinnaker_testbase import BaseTestCase -from spynnaker.pyNN.data import SpynnakerDataView from spynnaker.pyNN.models.abstract_pynn_model import AbstractPyNNModel from spynnaker.pyNN.models.populations import Population @@ -75,23 +73,10 @@ def check_binaries(self) -> None: populations.append(self.add_neuron_population( sim.extra_models.IFCurrDeltaCa2Adaptive(), 15, input_pop)) - #IF_curr_exp_ca2_adaptive_stdp_mad_pair_additive.aplx - - #IF_curr_exp_stdp_mad_recurrent_pre_stochastic_multiplicative.aplx - #IZK_cond_exp_dual.aplx - #IZK_cond_exp_dual_neuron.aplx - #IZK_cond_exp_dual_stdp_mad_pair_additive.aplx - #external_device_lif_control_neuron.aplx - #synapses_stdp_izhikevich_neuromodulation_pair_additive_structural_last_neuron_distance_weight.aplx - #synapses_stdp_izhikevich_neuromodulation_pair_multiplicative.aplx - #synapses_stdp_izhikevich_neuromodulation_vogels_2011_additive.aplx - #synapses_stdp_mad_nearest_pair_additive.aplx - #synapses_stdp_mad_nearest_pair_additive_structural_random_distance_weight.aplx - #synapses_stdp_mad_nearest_pair_multiplicative.aplx - #synapses_stdp_mad_pair_multiplicative.aplx - #synapses_stdp_mad_pfister_triplet_additive.aplx - #synapses_stdp_mad_recurrent_dual_fsm_multiplicative.aplx - #synapses_stdp_mad_vogels_2011_additive.aplx + # IF_curr_exp_ca2_adaptive_stdp_mad_pair_additive.aplx + # currently does not spike + populations.append(self.add_population_stdp_mad_pair_additive( + sim.extra_models.IFCurrExpCa2Adaptive(), input_pop)) sim.run(N_NEURONS + INTERVAL * 3) @@ -99,8 +84,11 @@ def check_binaries(self) -> None: self.check_population(population) sim.end() - self.check_binaries_used(["IF_curr_delta_ca2_adaptive.aplx", - "IF_curr_delta_ca2_adaptive_neuron.aplx"]) + self.check_binaries_used([ + "IF_curr_delta_ca2_adaptive.aplx", + "IF_curr_delta_ca2_adaptive_neuron.aplx", + "IF_curr_exp_ca2_adaptive_stdp_mad_pair_additive.aplx", + ]) def test_binaries(self) -> None: From 417c742c5f5e6b10f31af3941216c04b8f6fbabc Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 4 Feb 2026 14:48:18 +0000 Subject: [PATCH 06/12] synapses_stdp_mad_pfister_triplet_additive.aplx --- .../test_stdp/test_STDP_triplet_additive.py | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py b/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py index 11b858d29c..e4c3bd65cb 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py @@ -18,7 +18,7 @@ import numpy -def triplet_additive() -> None: +def triplet_additive(n_synapse_cores: int) -> None: # ------------------------------------------------------------------- # This test uses a single data point from the Pfister/Gerstner example # which is described and evaluated in more detail in @@ -52,7 +52,8 @@ def triplet_additive() -> None: for t in delta_t: # Neuron populations pre_pop = sim.Population(1, model(**cell_params)) - post_pop = sim.Population(1, model(**cell_params)) + post_pop = sim.Population(1, model(**cell_params), + n_synapse_cores=n_synapse_cores) # Stimulating populations pre_times = [start_time - 1 + (s * int(1000.0 / float(freq))) @@ -119,8 +120,20 @@ def triplet_additive() -> None: class TestSTDPPairAdditive(BaseTestCase): - def test_triplet_additive(self) -> None: - self.runsafe(triplet_additive) + def do_synapses(self) -> None: + triplet_additive(1) + + def test_synapses(self) -> None: + self.runsafe(self.do_synapses) + self.check_binary_used("synapses_stdp_mad_pfister_triplet_additive.aplx") + + def do_combined(self) -> None: + triplet_additive(0) + + def test_combined(self) -> None: + self.runsafe(self.do_combined) + self.check_binary_used( + "IF_curr_exp_stdp_mad_pfister_triplet_additive.aplx") if __name__ == '__main__': From d8f201faa07424bf692b23f689f6e987995a8c15 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Wed, 4 Feb 2026 16:16:48 +0000 Subject: [PATCH 07/12] split testing --- .../test_STDP_nearest_pair_additive.py | 19 +++++++++++++++--- .../test_STDP_nearest_pair_multiplicative.py | 20 ++++++++++++++++--- .../test_STDP_pair_multiplicative.py | 20 ++++++++++++++++--- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_additive.py b/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_additive.py index 46708dfe65..0956a5abe7 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_additive.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_additive.py @@ -20,7 +20,7 @@ class TestSTDPNearestPairAdditive(BaseTestCase): - def potentiation_and_depression(self) -> None: + def potentiation_and_depression(self, n_synapse_cores: int) -> None: p.setup(1) runtime = 100 initial_run = 1000 # to negate any initial conditions @@ -54,7 +54,8 @@ def potentiation_and_depression(self) -> None: {'spike_times': extra_spikes}, label="extra") # Post-plastic-synapse population - post_pop = p.Population(1, p.IF_curr_exp(), label="post") + post_pop = p.Population(1, p.IF_curr_exp(), label="post", + n_synapse_cores=n_synapse_cores) # Create projections p.Projection( @@ -136,8 +137,20 @@ def potentiation_and_depression(self) -> None: self.assertTrue(numpy.allclose( weights[0], new_weight_exact, atol=0.001)) + def do_synapse(self): + self.potentiation_and_depression(1) + def test_potentiation_and_depression(self) -> None: - self.runsafe(self.potentiation_and_depression) + self.runsafe(self.do_synapse) + self.check_binary_used("synapses_stdp_mad_nearest_pair_additive.aplx") + + def do_combined(self): + self.potentiation_and_depression(0) + + def test_combined(self) -> None: + self.runsafe(self.do_combined) + self.check_binary_used( + "IF_curr_exp_stdp_mad_nearest_pair_additive.aplx") if __name__ == '__main__': diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_multiplicative.py b/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_multiplicative.py index 5d01e8ac3d..90b8b1aeaa 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_multiplicative.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_multiplicative.py @@ -20,7 +20,7 @@ class TestSTDPNearestPairAdditive(BaseTestCase): - def potentiation_and_depression(self) -> None: + def potentiation_and_depression(self, n_synapse_cores: int) -> None: p.setup(1) runtime = 100 initial_run = 1000 # to negate any initial conditions @@ -54,7 +54,8 @@ def potentiation_and_depression(self) -> None: {'spike_times': extra_spikes}, label="extra") # Post-plastic-synapse population - post_pop = p.Population(1, p.IF_curr_exp(), label="post") + post_pop = p.Population(1, p.IF_curr_exp(), label="post", + n_synapse_cores=n_synapse_cores) # Create projections p.Projection( @@ -136,8 +137,21 @@ def potentiation_and_depression(self) -> None: self.assertTrue(numpy.allclose( weights[0], new_weight_exact, atol=0.001)) + def do_synapse(self): + self.potentiation_and_depression(1) + def test_potentiation_and_depression(self) -> None: - self.runsafe(self.potentiation_and_depression) + self.runsafe(self.do_synapse) + self.check_binary_used( + "synapses_stdp_mad_nearest_pair_multiplicative.aplx") + + def do_combined(self): + self.potentiation_and_depression(0) + + def test_combined(self) -> None: + self.runsafe(self.do_combined) + self.check_binary_used( + "IF_curr_exp_stdp_mad_nearest_pair_multiplicative.aplx") if __name__ == '__main__': diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_pair_multiplicative.py b/spynnaker_integration_tests/test_stdp/test_STDP_pair_multiplicative.py index 4cb779513a..58753cb16f 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_pair_multiplicative.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_pair_multiplicative.py @@ -78,7 +78,7 @@ def post_spike_same_time() -> None: assert numpy.allclose(weights_1, new_weight_exact, rtol=0.001) -def potentiation_and_depression() -> None: +def potentiation_and_depression(n_synapse_cores: int) -> None: p.setup(1) runtime = 100 initial_run = 1000 # to negate any initial conditions @@ -112,7 +112,8 @@ def potentiation_and_depression() -> None: {'spike_times': extra_spikes}, label="extra") # Post-plastic-synapse population - post_pop = p.Population(1, p.IF_curr_exp(), label="post") + post_pop = p.Population(1, p.IF_curr_exp(), label="post", + n_synapse_cores=n_synapse_cores) # Create projections p.Projection( @@ -170,8 +171,21 @@ def potentiation_and_depression() -> None: class TestSTDPPairAdditive(BaseTestCase): + def do_synapse(self): + potentiation_and_depression(1) + def test_potentiation_and_depression(self) -> None: - self.runsafe(potentiation_and_depression) + self.runsafe(self.do_synapse) + self.check_binary_used( + "synapses_stdp_mad_pair_multiplicative.aplx") + + def do_combined(self): + potentiation_and_depression(0) + + def test_combined(self) -> None: + self.runsafe(self.do_combined) + self.check_binary_used( + "IF_curr_exp_stdp_mad_pair_multiplicative.aplx") def test_post_spike_same_time(self) -> None: self.runsafe(post_spike_same_time) From 41fd17c94021226f7e4c8fbc91ad973f96fae11b Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 5 Feb 2026 09:11:29 +0000 Subject: [PATCH 08/12] test pair_multiplicative --- .../test_stdp/test_STDP_neuromodulation.py | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py b/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py index 53b8707726..283625bc7b 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py @@ -21,7 +21,7 @@ class TestSTDPNeuromodulation(BaseTestCase): - def neuromodulation(self) -> None: + def neuromodulation(self, weight_dependence) -> None: """ Simple test for neuromodulated STDP. @@ -97,8 +97,7 @@ def neuromodulation(self) -> None: timing_dependence=sim.SpikePairRule( tau_plus=10, tau_minus=12, A_plus=1, A_minus=1), - weight_dependence=sim.AdditiveWeightDependence( - w_min=0, w_max=20), + weight_dependence=weight_dependence, weight=rewarded_syn_weight) # Create a plastic connection between pre and post neurons @@ -127,6 +126,13 @@ def neuromodulation(self) -> None: print(spikes) + return weights + + def do_additive(self): + weight_dependence=sim.AdditiveWeightDependence(w_min=0, w_max=20) + weights = self.neuromodulation(weight_dependence) + + DA_concentration = 0.1 pot = 1 * math.exp(-((1504 - 1500)/10)) decay = math.exp(-((1601 - 1504)/1000)) el = pot * decay @@ -135,15 +141,29 @@ def neuromodulation(self) -> None: decay_e = math.exp(-((2400 - 1601)/1000)) weight_exact = ( ((el * DA_concentration) * const)*((decay_d * decay_e) - 1)) - print(f"Weight calculated: {weight_exact}") print(f"Weight from SpiNNaker: {weights[0][2]}") + #self.assertTrue(numpy.allclose( + # weights[0][2], weight_exact, atol=0.02)) + + self.check_binary_used( + "synapses_stdp_izhikevich_neuromodulation_pair_additive.aplx") + + def test_additive(self) -> None: + self.runsafe(self.do_additive) + + def do_multiplicative(self) -> None: + weight_dependence=sim.MultiplicativeWeightDependence( + w_min=0, w_max=20) + self.neuromodulation(weight_dependence) + + # TODO Weights expected - self.assertTrue(numpy.allclose( - weights[0][2], weight_exact, atol=0.02)) + self.check_binary_used( + "synapses_stdp_izhikevich_neuromodulation_pair_multiplicative.aplx") - def test_neuromodulation(self) -> None: - self.runsafe(self.neuromodulation) + def test_multiplicative(self) -> None: + self.runsafe(self.do_multiplicative) if __name__ == '__main__': From d8bf04c933aa274bb7db6e408404e9ab7fdc390a Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 5 Feb 2026 11:33:31 +0000 Subject: [PATCH 09/12] typing fixes --- spynnaker/pyNN/spinnaker.py | 7 ++++--- .../test_stdp_random_run.py | 2 +- .../test_stdp/test_STDP_nearest_pair_additive.py | 4 ++-- .../test_STDP_nearest_pair_multiplicative.py | 4 ++-- .../test_stdp/test_STDP_neuromodulation.py | 15 ++++++++++----- .../test_stdp/test_STDP_pair_multiplicative.py | 4 ++-- .../test_stdp/test_STDP_triplet_additive.py | 2 +- .../test_various/test_binaries.py | 10 ++-------- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/spynnaker/pyNN/spinnaker.py b/spynnaker/pyNN/spinnaker.py index 77ff2542ec..74c3c4e893 100644 --- a/spynnaker/pyNN/spinnaker.py +++ b/spynnaker/pyNN/spinnaker.py @@ -136,12 +136,13 @@ def _add_test_cfg_settings(self) -> None: Better to call set_model_n_synapse_cores in the script """ n_synapse_cores = get_config_str_list("Simulation", "n_synapse_cores") - for n_synapse_cores in n_synapse_cores: - path, name, n = n_synapse_cores.split(":") + for n_synapse_core in n_synapse_cores: + path, name, n = n_synapse_core.split(":") model_class = getattr(importlib.import_module(path), name) model = model_class() model.set_model_n_synapse_cores(int(n)) - logger.warning(f"{model=} {n_synapse_cores=} set from cfg") + logger.warning(f"model:{name} n_synapse_core set to {n} " + f"based on cfg") @overrides(AbstractSpinnakerBase._add_cfg_defaults_and_template) def _add_cfg_defaults_and_template(self) -> None: diff --git a/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py b/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py index 6a1c433e10..959b3387bd 100644 --- a/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py +++ b/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py @@ -76,7 +76,7 @@ def test_check_if_curr_exp(self) -> None: def _do_izk_cond_exp_dual(self) -> None: self.run_model(sim.extra_models.Izhikevich_cond_dual()) - def test_check_if_curr_exp(self) -> None: + def test_check_izk_cond_exp_dual(self) -> None: self.runsafe(self._do_izk_cond_exp_dual) self.check_binary_used( "IZK_cond_exp_dual_stdp_mad_pair_additive.aplx") diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_additive.py b/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_additive.py index 0956a5abe7..f10464045a 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_additive.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_additive.py @@ -137,14 +137,14 @@ def potentiation_and_depression(self, n_synapse_cores: int) -> None: self.assertTrue(numpy.allclose( weights[0], new_weight_exact, atol=0.001)) - def do_synapse(self): + def do_synapse(self) -> None: self.potentiation_and_depression(1) def test_potentiation_and_depression(self) -> None: self.runsafe(self.do_synapse) self.check_binary_used("synapses_stdp_mad_nearest_pair_additive.aplx") - def do_combined(self): + def do_combined(self) -> None: self.potentiation_and_depression(0) def test_combined(self) -> None: diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_multiplicative.py b/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_multiplicative.py index 90b8b1aeaa..eb83eb72e9 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_multiplicative.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_nearest_pair_multiplicative.py @@ -137,7 +137,7 @@ def potentiation_and_depression(self, n_synapse_cores: int) -> None: self.assertTrue(numpy.allclose( weights[0], new_weight_exact, atol=0.001)) - def do_synapse(self): + def do_synapse(self) -> None: self.potentiation_and_depression(1) def test_potentiation_and_depression(self) -> None: @@ -145,7 +145,7 @@ def test_potentiation_and_depression(self) -> None: self.check_binary_used( "synapses_stdp_mad_nearest_pair_multiplicative.aplx") - def do_combined(self): + def do_combined(self) -> None: self.potentiation_and_depression(0) def test_combined(self) -> None: diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py b/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py index 283625bc7b..e32d062642 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py @@ -12,16 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. +import math +import unittest + import pyNN.spiNNaker as sim + from spinnaker_testbase import BaseTestCase -import numpy -import unittest -import math + +from spynnaker.pyNN.models.neuron.plasticity.stdp.weight_dependence import ( + AbstractWeightDependence) class TestSTDPNeuromodulation(BaseTestCase): - def neuromodulation(self, weight_dependence) -> None: + def neuromodulation( + self, weight_dependence: AbstractWeightDependence) -> None: """ Simple test for neuromodulated STDP. @@ -128,7 +133,7 @@ def neuromodulation(self, weight_dependence) -> None: return weights - def do_additive(self): + def do_additive(self) -> None: weight_dependence=sim.AdditiveWeightDependence(w_min=0, w_max=20) weights = self.neuromodulation(weight_dependence) diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_pair_multiplicative.py b/spynnaker_integration_tests/test_stdp/test_STDP_pair_multiplicative.py index 58753cb16f..995c663076 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_pair_multiplicative.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_pair_multiplicative.py @@ -171,7 +171,7 @@ def potentiation_and_depression(n_synapse_cores: int) -> None: class TestSTDPPairAdditive(BaseTestCase): - def do_synapse(self): + def do_synapse(self) -> None: potentiation_and_depression(1) def test_potentiation_and_depression(self) -> None: @@ -179,7 +179,7 @@ def test_potentiation_and_depression(self) -> None: self.check_binary_used( "synapses_stdp_mad_pair_multiplicative.aplx") - def do_combined(self): + def do_combined(self) -> None: potentiation_and_depression(0) def test_combined(self) -> None: diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py b/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py index e4c3bd65cb..e0e713bc61 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py @@ -137,4 +137,4 @@ def test_combined(self) -> None: if __name__ == '__main__': - triplet_additive() + triplet_additive(0) diff --git a/spynnaker_integration_tests/test_various/test_binaries.py b/spynnaker_integration_tests/test_various/test_binaries.py index 4d34f90de8..e15cdd0dda 100644 --- a/spynnaker_integration_tests/test_various/test_binaries.py +++ b/spynnaker_integration_tests/test_various/test_binaries.py @@ -25,7 +25,7 @@ class TestBinaries(BaseTestCase): def add_population(self, model: AbstractPyNNModel, weight:int, - input_pop: Population) -> None: + input_pop: Population) -> Population: population = sim.Population( N_NEURONS, model, label = model.name) sim.Projection(input_pop, population, sim.OneToOneConnector(), @@ -34,7 +34,7 @@ def add_population(self, model: AbstractPyNNModel, weight:int, return population def add_neuron_population(self, model: AbstractPyNNModel, weight:int, - input_pop: Population) -> None: + input_pop: Population) -> Population: population = sim.Population( N_NEURONS, model, label = model.name, n_synapse_cores=1) sim.Projection(input_pop, population, sim.OneToOneConnector(), @@ -73,11 +73,6 @@ def check_binaries(self) -> None: populations.append(self.add_neuron_population( sim.extra_models.IFCurrDeltaCa2Adaptive(), 15, input_pop)) - # IF_curr_exp_ca2_adaptive_stdp_mad_pair_additive.aplx - # currently does not spike - populations.append(self.add_population_stdp_mad_pair_additive( - sim.extra_models.IFCurrExpCa2Adaptive(), input_pop)) - sim.run(N_NEURONS + INTERVAL * 3) for population in populations: @@ -87,7 +82,6 @@ def check_binaries(self) -> None: self.check_binaries_used([ "IF_curr_delta_ca2_adaptive.aplx", "IF_curr_delta_ca2_adaptive_neuron.aplx", - "IF_curr_exp_ca2_adaptive_stdp_mad_pair_additive.aplx", ]) From e4616022318a3de6939dd49c3300f4b4b5557bbc Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 5 Feb 2026 11:56:22 +0000 Subject: [PATCH 10/12] extra typing fixes --- .../test_multi_call_examples/test_stdp_random_run.py | 2 +- .../test_stdp/test_STDP_neuromodulation.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py b/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py index 959b3387bd..eab45e5b1a 100644 --- a/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py +++ b/spynnaker_integration_tests/test_multi_call_examples/test_stdp_random_run.py @@ -68,7 +68,7 @@ def test_check_if_curr_exp(self) -> None: def _do_if_curr_exp_ca2_additive(self) -> None: self.run_model(sim.extra_models.IFCurrExpCa2Adaptive()) - def test_check_if_curr_exp(self) -> None: + def test_check_if_curr_exp_ca2_additive(self) -> None: self.runsafe(self._do_if_curr_exp_ca2_additive) self.check_binary_used( "IF_curr_exp_ca2_adaptive_stdp_mad_pair_additive.aplx") diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py b/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py index e32d062642..02362ea10d 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py @@ -19,15 +19,15 @@ from spinnaker_testbase import BaseTestCase +from spynnaker.pyNN.models.neuron import ConnectionHolder from spynnaker.pyNN.models.neuron.plasticity.stdp.weight_dependence import ( AbstractWeightDependence) class TestSTDPNeuromodulation(BaseTestCase): - def neuromodulation( - self, weight_dependence: AbstractWeightDependence) -> None: - + def neuromodulation(self, weight_dependence: AbstractWeightDependence + ) -> ConnectionHolder: """ Simple test for neuromodulated STDP. Two pre-synaptic spikes are added, at times 1500 and 2400ms. From 80b936573ec30b4c5e5588b28c0fb7dd6ab61520 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 5 Feb 2026 12:07:47 +0000 Subject: [PATCH 11/12] cast for mypy --- .../test_stdp/test_STDP_neuromodulation.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py b/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py index 02362ea10d..e0d1727474 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py @@ -13,8 +13,10 @@ # limitations under the License. import math +from typing import cast, List import unittest +import numpy import pyNN.spiNNaker as sim from spinnaker_testbase import BaseTestCase @@ -147,9 +149,10 @@ def do_additive(self) -> None: weight_exact = ( ((el * DA_concentration) * const)*((decay_d * decay_e) - 1)) print(f"Weight calculated: {weight_exact}") - print(f"Weight from SpiNNaker: {weights[0][2]}") - #self.assertTrue(numpy.allclose( - # weights[0][2], weight_exact, atol=0.02)) + weights0 = cast(List[float], weights[0]) + print(f"Weight from SpiNNaker: {weights0[2]}") + self.assertTrue(numpy.allclose( + weights0[2], weight_exact, atol=0.02)) self.check_binary_used( "synapses_stdp_izhikevich_neuromodulation_pair_additive.aplx") From 4d8c565d342074c57eee9ab94c4b90f15add0e89 Mon Sep 17 00:00:00 2001 From: "Christian Y. Brenninkmeijer" Date: Thu, 5 Feb 2026 12:25:52 +0000 Subject: [PATCH 12/12] flake8 --- .../test_stdp/test_STDP_neuromodulation.py | 8 ++++---- .../test_stdp/test_STDP_triplet_additive.py | 3 ++- .../test_various/test_binaries.py | 12 +++++------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py b/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py index e0d1727474..dfb1739bc5 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_neuromodulation.py @@ -136,7 +136,7 @@ def neuromodulation(self, weight_dependence: AbstractWeightDependence return weights def do_additive(self) -> None: - weight_dependence=sim.AdditiveWeightDependence(w_min=0, w_max=20) + weight_dependence = sim.AdditiveWeightDependence(w_min=0, w_max=20) weights = self.neuromodulation(weight_dependence) DA_concentration = 0.1 @@ -161,14 +161,14 @@ def test_additive(self) -> None: self.runsafe(self.do_additive) def do_multiplicative(self) -> None: - weight_dependence=sim.MultiplicativeWeightDependence( + weight_dependence = sim.MultiplicativeWeightDependence( w_min=0, w_max=20) self.neuromodulation(weight_dependence) # TODO Weights expected - self.check_binary_used( - "synapses_stdp_izhikevich_neuromodulation_pair_multiplicative.aplx") + "synapses_stdp_izhikevich_neuromodulation_" + "pair_multiplicative.aplx") def test_multiplicative(self) -> None: self.runsafe(self.do_multiplicative) diff --git a/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py b/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py index e0e713bc61..90d2172fd2 100644 --- a/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py +++ b/spynnaker_integration_tests/test_stdp/test_STDP_triplet_additive.py @@ -125,7 +125,8 @@ def do_synapses(self) -> None: def test_synapses(self) -> None: self.runsafe(self.do_synapses) - self.check_binary_used("synapses_stdp_mad_pfister_triplet_additive.aplx") + self.check_binary_used( + "synapses_stdp_mad_pfister_triplet_additive.aplx") def do_combined(self) -> None: triplet_additive(0) diff --git a/spynnaker_integration_tests/test_various/test_binaries.py b/spynnaker_integration_tests/test_various/test_binaries.py index e15cdd0dda..04bc1157b1 100644 --- a/spynnaker_integration_tests/test_various/test_binaries.py +++ b/spynnaker_integration_tests/test_various/test_binaries.py @@ -24,25 +24,25 @@ class TestBinaries(BaseTestCase): - def add_population(self, model: AbstractPyNNModel, weight:int, + def add_population(self, model: AbstractPyNNModel, weight: int, input_pop: Population) -> Population: population = sim.Population( - N_NEURONS, model, label = model.name) + N_NEURONS, model, label=model.name) sim.Projection(input_pop, population, sim.OneToOneConnector(), synapse_type=sim.StaticSynapse(weight=weight, delay=1)) population.record("spikes") return population - def add_neuron_population(self, model: AbstractPyNNModel, weight:int, + def add_neuron_population(self, model: AbstractPyNNModel, weight: int, input_pop: Population) -> Population: population = sim.Population( - N_NEURONS, model, label = model.name, n_synapse_cores=1) + N_NEURONS, model, label=model.name, n_synapse_cores=1) sim.Projection(input_pop, population, sim.OneToOneConnector(), synapse_type=sim.StaticSynapse(weight=weight, delay=1)) population.record("spikes") return population - def check_population(self, population: Population)-> None: + def check_population(self, population: Population) -> None: neo = population.get_data(variables="spikes") spikes_trains = neo.segments[0].spiketrains print(population.label, spikes_trains) @@ -84,7 +84,5 @@ def check_binaries(self) -> None: "IF_curr_delta_ca2_adaptive_neuron.aplx", ]) - def test_binaries(self) -> None: self.runsafe(self.check_binaries) -