# -*- coding: utf-8 -*-
#
# test_facetshw_stdp.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/>.
import nest
import numpy as np
import unittest
[docs]class FacetsTestCase(unittest.TestCase):
"""
This script is testing the accumulation of spike pairs and
the weight update mechanism as implemented in the FACETS hardware.
Author: Thomas Pfeil
Date of first version: 21.01.2013
"""
[docs] def test_facetshw_stdp(self):
modelName = 'stdp_facetshw_synapse_hom'
# homogeneous parameters for all synapses
Wmax = 100.0
# see *.cpp file of synapse model and Pfeil et al. 2012 for LUT
# configuration
lut_0 = [2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, 15]
lut_1 = [0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, 12, 13]
lut_2 = range(16) # identity
config_0 = [0, 0, 1, 0]
config_1 = [0, 1, 0, 0]
reset_pattern = 6 * [1] # reset all
# individual parameters for each synapse
# reached every 36 runs (e^(-10/20) = 21.83510375)
lut_th_causal = 21.835
lut_th_acausal = lut_th_causal
# other parameters
startWeight = 0 # as digital value [0, 1, ..., 15]
tau = 20.0
timeBetweenPairs = 100.0
# frequency_of_pairs = 10Hz => delta_t(+) = 10ms, delta_t(-) = 90ms
delay = 5.0
spikesIn = np.arange(10.0, 60000.0, timeBetweenPairs)
synapseDict = {'tau_plus': tau,
'tau_minus_stdp': tau,
'Wmax': Wmax,
'synapses_per_driver': 50,
'driver_readout_time': 15.0,
'lookuptable_0': lut_0,
'lookuptable_1': lut_1,
'lookuptable_2': lut_2,
'configbit_0': config_0,
'configbit_1': config_1,
'reset_pattern': reset_pattern,
'a_thresh_th': lut_th_causal,
'a_thresh_tl': lut_th_acausal}
# build network
stim = nest.Create('spike_generator')
neuronA = nest.Create('parrot_neuron')
neuronB = nest.Create('parrot_neuron')
nest.SetStatus(stim, [{'spike_times': spikesIn}])
nest.SetDefaults(modelName, synapseDict)
# check if GetDefaults returns same values as have been set
synapseDictGet = nest.GetDefaults(modelName)
for key in synapseDict.keys():
self.assertTrue(
all(np.atleast_1d(synapseDictGet[key] == synapseDict[key])))
nest.Connect(stim, neuronA)
nest.Connect(neuronA, neuronB, syn_spec={
'weight': float(startWeight) / 15.0 * Wmax,
'delay': delay, 'model': modelName})
nest.Simulate(50.0)
weightTrace = []
for run in range(len(spikesIn)):
nest.Simulate(timeBetweenPairs)
connections = nest.GetConnections(neuronA)
for i in range(len(connections)):
if (nest.GetStatus([connections[i]])[0]['synapse_model'] ==
modelName):
weightTrace.append(
[run, nest.GetStatus([connections[i]])[0]['weight'],
nest.GetStatus([connections[i]])[0]['a_causal'],
nest.GetStatus([connections[i]])[0]['a_acausal']])
# analysis
weightTrace = np.array(weightTrace)
# just before theoretical updates
weightTraceMod36pre = weightTrace[35::36]
# just after theoretical updates
weightTraceMod36 = weightTrace[::36]
weightIndex = int(startWeight)
for i in range(len(weightTraceMod36pre)):
# check weight value before update
# (after spike pair with index 35, 71, ...)
self.assertTrue(np.allclose(weightTraceMod36pre[i][1],
1.0 / 15.0 * weightIndex * Wmax,
atol=1e-6))
weightIndex = lut_0[weightIndex]
weightIndex = int(startWeight)
for i in range(len(weightTraceMod36)):
# check weight value after update
# (after spike pair with index 0, 36, 72, ...)
self.assertTrue(np.allclose(weightTraceMod36[i][1],
1.0 / 15.0 * weightIndex * Wmax,
atol=1e-6))
# check charge on causal capacitor
self.assertTrue(np.allclose(weightTraceMod36[i][2],
np.ones_like(weightTraceMod36[i][2]) *
np.exp(-2 * delay / tau), atol=1e-6))
weightIndex = lut_0[weightIndex]
# check charge on anti-causal capacitor after each pair
for i in range(len(weightTrace) - 1):
# TODO: global params
self.assertTrue(np.allclose(weightTrace[i, 3], ((i % 36) + 1) *
np.exp(-(timeBetweenPairs -
2 * delay) / tau),
atol=1e-6))
[docs]def suite():
suite = unittest.makeSuite(FacetsTestCase, 'test')
return suite
[docs]def run():
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite())
if __name__ == "__main__":
run()