Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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()
12 changes: 6 additions & 6 deletions integration_tests/test_scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Comment on lines -54 to -59
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to get rid of these as well?

def test_examples_synfire_if_curr_exp_random(self):
self.check_script("examples/synfire_if_curr_exp_random.py")

Expand Down Expand Up @@ -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")

Expand All @@ -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")

Expand Down
13 changes: 13 additions & 0 deletions integration_tests/test_split/__init__.py
Original file line number Diff line number Diff line change
@@ -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.
8 changes: 8 additions & 0 deletions integration_tests/test_split/spynnaker.cfg
Original file line number Diff line number Diff line change
@@ -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

Comment on lines +3 to +8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason this couldn't just be done in the script that uses them?

58 changes: 58 additions & 0 deletions integration_tests/test_split/test_scripts.py
Original file line number Diff line number Diff line change
@@ -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")
Loading