# -*- coding: utf-8 -*-
#
# test_vogels_sprekeler_synapse.py
#
# This file is part of NEST.
#
# Copyright (C) 2004 The NEST Initiative
#
# NEST is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# NEST is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with NEST. If not, see <http://www.gnu.org/licenses/>.
# This script tests the vogels_sprekeler_synapse in NEST.
import nest
import unittest
from math import exp
[docs]@nest.check_stack
class VogelsSprekelerConnectionTestCase(unittest.TestCase):
"""Check vogels_sprekeler_synapse model properties."""
[docs] def setUp(self):
"""Set up the test."""
nest.set_verbosity('M_WARNING')
nest.ResetKernel()
# settings
self.dendritic_delay = 1.0
self.decay_duration = 5.0
self.synapse_model = "vogels_sprekeler_synapse"
self.syn_spec = {
"model": self.synapse_model,
"delay": self.dendritic_delay,
"weight": 5.0,
"eta": 0.001,
"alpha": 0.1,
"tau": 20.,
"Kplus": 0.0,
"Wmax": 15.,
}
# setup basic circuit
self.pre_neuron = nest.Create("parrot_neuron")
self.post_neuron = nest.Create("parrot_neuron")
nest.Connect(self.pre_neuron, self.post_neuron,
syn_spec=self.syn_spec)
[docs] def generateSpikes(self, neuron, times):
"""Trigger spike to given neuron at specified times."""
delay = self.dendritic_delay
gen = nest.Create("spike_generator", 1,
{"spike_times": [t-delay for t in times]})
nest.Connect(gen, neuron, syn_spec={"delay": delay})
[docs] def status(self, which):
"""Get synapse parameter status."""
stats = nest.GetConnections(self.pre_neuron,
synapse_model=self.synapse_model)
return nest.GetStatus(stats, [which])[0][0]
[docs] def decay(self, time, Kvalue):
"""Decay variables."""
Kvalue *= exp(- time / self.syn_spec["tau"])
return Kvalue
[docs] def facilitate(self, w, Kplus):
"""Facilitate weight."""
new_w = w + (self.syn_spec['eta'] * Kplus)
return new_w if (new_w / self.status('Wmax') < 1.0) else \
self.syn_spec['Wmax']
[docs] def depress(self, w):
"""Depress weight."""
new_w = w - (self.syn_spec['alpha'] * self.syn_spec['eta'])
return new_w if (new_w / self.status('Wmax') > 0.0) else 0
[docs] def assertAlmostEqualDetailed(self, expected, given, message):
"""Improve assetAlmostEqual with detailed message."""
messageWithValues = ("%s (expected: `%s` was: `%s`" % (message,
str(expected),
str(given)))
self.assertAlmostEqual(given, expected, msg=messageWithValues)
[docs] def test_badPropertiesSetupsThrowExceptions(self):
"""Check that exceptions are thrown when setting bad parameters."""
def setupProperty(property):
bad_syn_spec = self.syn_spec.copy()
bad_syn_spec.update(property)
nest.Connect(self.pre_neuron, self.post_neuron,
syn_spec=bad_syn_spec)
def badPropertyWith(content, parameters):
self.assertRaisesRegexp(nest.NESTError, "BadProperty(.+)" +
content, setupProperty, parameters)
badPropertyWith("Kplus", {"Kplus": -1.0})
[docs] def test_varsZeroAtStart(self):
"""Check that pre and post-synaptic variables are zero at start."""
self.assertAlmostEqualDetailed(0.0, self.status("Kplus"),
"Kplus should be zero")
[docs] def test_preVarsIncreaseWithPreSpike(self):
"""
Check that pre-synaptic variable, Kplus increase after each
pre-synaptic spike.
"""
self.generateSpikes(self.pre_neuron, [2.0])
Kplus = self.status("Kplus")
nest.Simulate(20.0)
self.assertAlmostEqualDetailed(Kplus + 1.0, self.status("Kplus"),
"Kplus should have increased by 1")
[docs] def test_preVarsDecayAfterPreSpike(self):
"""
Check that pre-synaptic variables Kplus decay after each
pre-synaptic spike.
"""
self.generateSpikes(self.pre_neuron, [2.0])
self.generateSpikes(self.pre_neuron,
[2.0 + self.decay_duration]) # trigger computation
Kplus = self.decay(self.decay_duration, 1.0)
Kplus += 1.0
nest.Simulate(20.0)
self.assertAlmostEqualDetailed(Kplus, self.status("Kplus"),
"Kplus should have decay")
[docs] def test_preVarsDecayAfterPostSpike(self):
"""
Check that pre-synaptic variables Kplus decay after each post-synaptic
spike.
"""
self.generateSpikes(self.pre_neuron, [2.0])
self.generateSpikes(self.post_neuron, [3.0, 4.0])
self.generateSpikes(self.pre_neuron,
[2.0 + self.decay_duration]) # trigger computation
Kplus = self.decay(self.decay_duration, 1.0)
Kplus += 1.0
nest.Simulate(20.0)
self.assertAlmostEqualDetailed(Kplus, self.status("Kplus"),
"Kplus should have decay")
[docs] def test_weightChangeWhenPrePostSpikes(self):
"""Check that weight changes whenever a pre-post spike pair happen."""
self.generateSpikes(self.pre_neuron, [2.0])
self.generateSpikes(self.post_neuron, [4.0])
self.generateSpikes(self.pre_neuron, [6.0]) # trigger computation
print("")
weight = self.status("weight")
Kplus = self.status("Kplus")
Kminus = 0.
Kplus = self.decay(2.0, Kplus)
# first pre-synaptic spike
weight = self.facilitate(weight, Kminus)
weight = self.depress(weight)
Kplus += 1.0
# Resultant postspike at 3.0ms (because we're using parrot neurons, the
# prespike causes a postspike too
Kminus += 1.0
# Planned postspike at 4.0ms
Kminus = self.decay(1.0, Kminus)
Kminus += 1.0
# next pre-synaptic spike
# first postspike in history
dt = 2.0
Kplus_temp1 = self.decay(2.0, Kplus)
weight = self.facilitate(weight, Kplus_temp1)
# second postspike in history
dt = 3.0
Kplus_temp2 = self.decay(3.0, Kplus)
weight = self.facilitate(weight, Kplus_temp2)
Kminus = self.decay(1.0, Kminus)
weight = self.facilitate(weight, Kminus)
weight = self.depress(weight)
Kplus = self.decay(4.0, Kplus)
# The simulation using Nest
nest.Simulate(20.0)
self.assertAlmostEqualDetailed(weight, self.status("weight"),
"weight should have increased")
[docs] def test_maxWeightStaturatesWeight(self):
"""Check that setting maximum weight property keep weight limited."""
limited_weight = self.status("weight") + 1e-10
conn = nest.GetConnections(target=self.post_neuron,
source=self.pre_neuron)
# disable depression to make it get to max weight
# increase eta to cause enough facilitation
nest.SetStatus(conn, "Wmax", limited_weight)
nest.SetStatus(conn, "eta", 5.)
nest.SetStatus(conn, "alpha", 0.)
self.generateSpikes(self.pre_neuron, [2.0])
self.generateSpikes(self.post_neuron, [3.0])
self.generateSpikes(self.pre_neuron, [4.0]) # trigger computation
self.assertAlmostEqualDetailed(limited_weight,
self.status("weight"),
"weight should have been limited")
[docs]def suite():
return unittest.makeSuite(VogelsSprekelerConnectionTestCase, "test")
[docs]def run():
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite())
if __name__ == "__main__":
run()