1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
#include <math.h>
#include "synapse.h"
Synapse::Synapse() :
src(-1), dst(-1), // seeing this value indicates an unused synapse
weight(0.0),
eligibility(0.0),
delay(0.0),
constant(false),
firstSpike(- INFINITY),
lastSpike(- INFINITY),
evolvedUntil(0.0)
{}
// given an input time and current calculate their output values
void Synapse::computePostsynapticPulse(double &time, double ¤t) {
time += delay;
current = weight;
}
void Synapse::evolve(double time) {
if (time < evolvedUntil)
return;
// get the dopamin history starting from a dopamin event earlier than the synpase's last event
std::list<pair<double, double> >::iterator i = s.da_history.begin();
while (i->first > evolvedUntil)
i++;
// evolve synapse state for each interval given by the dopamin history
while (evolvedUntil < time) {
double da_level = i->second;
if (i->first < evolvedUntil) // the first dopamin event partially lies outside our time window
da_level = g.decay_dopamin(da_level, evolvedUntil - i->first);
double td = - evolvedUntil;
if (i == s.da_history.begin()) {
// this is the last (=newest) element of the history
td += time;
evolvedUntil = time;
}else{
i--;
if (i->first > time) {
// dopamin history goes furher (in time) than we have to simulate
td += time;
evolvedUntil = time;
}else{
td += i->first;
evolvedUntil += td;
}
}
/* below is the exact solution of the equation system
dc/dt = -Cc c - eligibility trace, C - cf. tau
dd/dt = -Dd d - dopamin level, D - cf. tau
dw/dt = cd w - weight
*/
if (!constant) {
double tau = g.dopamin_tau * g.stdp_et_tau / (g.dopamin_tau + g.stdp_et_tau);
double dw = da_level * eligibility * tau * (1 - exp( -td / tau ));
weight += dw;
weight = fmax( msg.Wmin, fmin( msg.Wmax, weight ));
}
eligibility *= exp( -td / g.stdp_et_tau );
}
}
// modify eligibility trace according to a single STDP event given by
// a pre-post time difference (= t_post - t_pre)
void Synapse::stdp(double td) {
if (td >= 0.0) {// WARN: this doesn't work with negative zero
eligibility = g.stdp_lambda_plus * exp( - td / g.stdp_tau_plus );
}else{
eligibility = - g.stdp_lambda_minus * exp( td / g.stdp_tau_minus );
}
}
static void Synapse::updateTopology() {
// clear the sin/sout lists of all neurons
for (int i=0; i<numNeurons; i++) {
n[i].sout.clear();
n[i].sin.clear();
}
// iterate over all synapses wich have a valid source and destination (neuron) and add them to sin/sout lists
int i;
for (i=0; (i<maxSynapses) && (syn[i].src != -1) && (syn[i].dst != -1); i++) {
n[syn[i].src].sout.push_front(syn[i]);
n[syn[i].dst].sin.push_front(syn[i]);
}
// store number of (used) synapses
numSynapses = i;
}
template<class Action>
bool Synapse::reflect<Action>(Action &a) {
return
a(src, "src")
&& a(dst, "dst")
&& a(weight, "weight")
&& a(eligibility, "eligibility")
&& a(delay, "delay")
&& a(constant, "constant")
&& a(firstSpike, "firstSpike")
&& a(lastSpike, "lastSpike")
&& a(evolvedUntil, "evolvedUntil");
}
static id_type Synapse::numElements() {
return numSynapsesDec;
}
static Synapse * Synapse::singleton(id_type id) {
return &(synapses[id]);
}
|