diff --git a/examples/extra_models_examples/stdp_mad_recurrent_pre_stochastic_multiplicative.py b/examples/extra_models_examples/stdp_mad_recurrent_pre_stochastic_multiplicative.py new file mode 100644 index 00000000..5bf6d371 --- /dev/null +++ b/examples/extra_models_examples/stdp_mad_recurrent_pre_stochastic_multiplicative.py @@ -0,0 +1,131 @@ +# 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. + +""" +stdp_mad_recurrent_pre_stochastic_multiplicative +""" +import matplotlib.pyplot as plt +import pyNN.spiNNaker as p +from pyNN.utility.plotting import Figure, Panel +# pylint: disable=wrong-spelling-in-comment + +p.setup(timestep=1.0, min_delay=1.0) +p.set_number_of_neurons_per_core(p.IF_curr_exp, 100) + +nSourceNeurons = 1 # number of input (excitatory) neurons +nExcitNeurons = 1 # number of excitatory neurons in the recurrent memory +nInhibNeurons = 10 # number of inhibitory neurons in the recurrent memory +nTeachNeurons = 1 +runTime = 3200 + +cell_params_lif = { + 'cm': 0.25, # nF was 0.25 + 'i_offset': 0.0, + 'tau_m': 10.0, + 'tau_refrac': 2.0, + 'tau_syn_E': 0.5, + 'tau_syn_I': 0.5, + 'v_reset': -70.0, + 'v_rest': -70.0, + 'v_thresh': -50.0} + +populations = list() +projections = list() + +stimulus = 0 +inhib = 1 +excit = 2 +teacher = 3 + +weight_to_force_firing = 15.0 +baseline_excit_weight = 2.0 + +spikes0 = list() +teachingSpikes = list() +for i in range(runTime//40): + spikes0.append(i*40) +for i in range(runTime//80): + teachingSpikes.append(i*40+5+120) + +arrayEntries = [] +for i in range(nSourceNeurons): + newEntry = [] + for spike in spikes0: + newEntry.append(spike + i*40.0/100.0) + arrayEntries.append(newEntry) +spikeArray = {'spike_times': arrayEntries} + +teachlist = list() +for i in range(nSourceNeurons): + teachlist.append(teachingSpikes) +teachingSpikeArray = {'spike_times': teachlist} +populations.append(p.Population(nSourceNeurons, + p.SpikeSourceArray(**spikeArray), + label='excit_pop_ss_array')) # 0 +populations.append(p.Population(nInhibNeurons, + p.IF_curr_exp(**cell_params_lif), + label='inhib_pop')) # 1 +populations.append(p.Population(nExcitNeurons, + p.IF_curr_exp(**cell_params_lif), + label='excit_pop')) # 2 +populations.append(p.Population(nTeachNeurons, + p.SpikeSourceArray(**teachingSpikeArray), + label='teaching_ss_array')) # 3 + +stdp_model = p.STDPMechanism( + timing_dependence=p.extra_models.RecurrentRule( + accumulator_depression=-6, accumulator_potentiation=3, + mean_pre_window=10.0, mean_post_window=10.0, dual_fsm=False, + A_plus=0.2, A_minus=0.2), + weight_dependence=p.MultiplicativeWeightDependence(w_min=0.0, w_max=16.0), + weight=baseline_excit_weight, delay=1) + +projections.append( + p.Projection(populations[stimulus], populations[excit], + p.AllToAllConnector(), synapse_type=stdp_model)) + +projections.append( + p.Projection(populations[teacher], populations[excit], + p.OneToOneConnector(), receptor_type='excitatory', + synapse_type=p.StaticSynapse( + weight=weight_to_force_firing, delay=1))) + +populations[inhib].record(['v', 'spikes']) +populations[excit].record(['v', 'spikes']) + +p.run(runTime) + +final_weights = projections[0].get('weight', 'list', with_address=False) +print(f"Final weights: {final_weights}") + +v = populations[excit].get_data('v') +spikes = populations[excit].get_data('spikes') +vInhib = populations[inhib].get_data('v') +spikesInhib = populations[inhib].get_data('spikes') + +Figure( + # plot of the neuron spike times + Panel(spikes.segments[0].spiketrains, + yticks=True, markersize=0.2, xlim=(0, runTime)), + # membrane potential of the neurons + Panel(v.segments[0].filter(name='v')[0], + ylabel="Membrane potential (mV)", + data_labels=[populations[excit].label], yticks=True, + xlim=(0, runTime), xticks=True), + title="Simple associative memory: spikes and membrane potential", + annotations=f"Simulated with {p.name()}" +) +plt.show() + +p.end() diff --git a/integration_tests/test_scripts.py b/integration_tests/test_scripts.py index a107aaba..f2862c8e 100644 --- a/integration_tests/test_scripts.py +++ b/integration_tests/test_scripts.py @@ -51,12 +51,6 @@ def test_examples_split_examples_pynnBrunnelSplit(self): def test_examples_split_examples_va_benchmark_split(self): self.check_script("examples/split_examples/va_benchmark_split.py") - def test_examples_balanced_random_balanced_random(self): - self.check_script("examples/balanced_random/balanced_random.py") - - def test_examples_balanced_random_split_balanced_random_split(self): - self.check_script("examples/balanced_random/split/balanced_random_split.py") - def test_examples_synfire_if_curr_exp_random(self): self.check_script("examples/synfire_if_curr_exp_random.py") @@ -165,6 +159,9 @@ def test_examples_extra_models_examples_vogel_2011_vogels_2011(self): def test_examples_extra_models_examples_stdp_associative_memory(self): self.check_script("examples/extra_models_examples/stdp_associative_memory.py") + def test_examples_extra_models_examples_stdp_mad_recurrent_pre_stochastic_multiplicative(self): + self.check_script("examples/extra_models_examples/stdp_mad_recurrent_pre_stochastic_multiplicative.py") + def test_examples_extra_models_examples_stdp_triplet(self): self.check_script("examples/extra_models_examples/stdp_triplet.py") @@ -186,6 +183,9 @@ def test_examples_extra_models_examples_IF_curr_exp_ca2_adaptive(self): def test_examples_extra_models_examples_IF_cond_exp_stoc(self): self.check_script("examples/extra_models_examples/IF_cond_exp_stoc.py") + def test_examples_wta_example(self): + self.check_script("examples/wta_example.py") + def test_balanced_random_balanced_random(self): self.check_script("balanced_random/balanced_random.py") diff --git a/integration_tests/test_split/__init__.py b/integration_tests/test_split/__init__.py new file mode 100644 index 00000000..6768dd38 --- /dev/null +++ b/integration_tests/test_split/__init__.py @@ -0,0 +1,13 @@ +# 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. diff --git a/integration_tests/test_split/spynnaker.cfg b/integration_tests/test_split/spynnaker.cfg new file mode 100644 index 00000000..4df5f7e4 --- /dev/null +++ b/integration_tests/test_split/spynnaker.cfg @@ -0,0 +1,8 @@ +[Simulation] + +n_synapse_cores = spynnaker.pyNN.models.neuron.builds.if_cond_exp_stoc:IFCondExpStoc:1, + spynnaker.pyNN.models.neuron.builds.if_curr_exp_ca2_adaptive:IFCurrExpCa2Adaptive:1, + spynnaker.pyNN.models.neuron.builds.if_curr_dual_exp_base:IFCurrDualExpBase:1, + spynnaker.pyNN.models.neuron.builds.if_curr_exp_semd_base:IFCurrExpSEMDBase:1, + spynnaker.pyNN.models.neuron.builds.if_curr_exp_base:IFCurrExpBase:1 + diff --git a/integration_tests/test_split/test_scripts.py b/integration_tests/test_split/test_scripts.py new file mode 100644 index 00000000..5fe0c822 --- /dev/null +++ b/integration_tests/test_split/test_scripts.py @@ -0,0 +1,58 @@ +# 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 +from spinnaker_testbase import ScriptChecker + + +class TestScripts(ScriptChecker): + """ + This file tests the scripts as configured in script_builder.py + + Please do not manually edit this file. + It is rebuilt each time SpiNNakerManchester/IntegrationTests is run + + If it is out of date please edit and run script_builder.py + Then the new file can be added to github for reference only. + """ +# flake8: noqa + + def setUp(self): + os.chdir(os.path.dirname(__file__)) + + def test_examples_extra_models_examples_IF_cond_exp_stoc(self): + self.check_script("../examples/extra_models_examples/IF_cond_exp_stoc.py", + use_script_dir=False) + self.check_binary_used("IF_cond_exp_stoc_neuron.aplx") + + def test_examples_extra_models_examples_IF_curr_exp_ca2_adaptive(self): + self.check_script("../examples/extra_models_examples/IF_curr_exp_ca2_adaptive.py", + use_script_dir=False) + self.check_binary_used("IF_curr_exp_ca2_adaptive_neuron.aplx") + + def test_examples_extra_models_examples_synfire_if_curr_dual_exp(self): + self.check_script("../examples/extra_models_examples/synfire_if_curr_dual_exp.py", + use_script_dir=False) + self.check_binary_used("IF_curr_exp_dual_neuron.aplx") + + def test_examples_extra_models_examples_IF_curr_exp_sEMD(self): + self.check_script("../examples/extra_models_examples/IF_curr_exp_sEMD.py", + use_script_dir=False) + self.check_binary_used("IF_curr_exp_sEMD_neuron.aplx") + + def test_examples_extra_models_examples_vogel_2011_vogels_2011_live(self): + self.check_script("../examples/extra_models_examples/vogel_2011/vogels_2011_live.py", + use_script_dir=False) + # test does not produce spikes in either mode + self.check_binary_used("synapses_stdp_mad_vogels_2011_additive.aplx")