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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
|
#ifndef Lh5wJREkwqXIDpptCEqbkLO3ed4
#define Lh5wJREkwqXIDpptCEqbkLO3ed4
#include <boost/tuple/tuple.hpp>
#include <boost/mpl/joint_view.hpp>
#include "context.hpp"
#include "event.hpp"
#include "evolve.hpp"
#include "index.hpp"
#include "index_global.hpp"
#include "index_randomspike.hpp"
#include "index_spike.hpp"
#include "index_spike_arrival.hpp"
#include "multi_queue.hpp"
#include "pla_apply.hpp"
#include "pla_evolve.hpp"
#include "pla_generate.hpp"
#include "pla_sync.hpp"
#include "time.hpp"
#include "topology.hpp"
#include "type_set.hpp"
namespace SimLoopImpl {
using namespace boost;
using namespace boost::mpl;
template<typename PropList>
struct SimLoop {
typedef PropertyComposition<PropList> pc_t;
SimLoop()
: indices(),
queues()
{}
bool run(const Time until, uint64_t maxEvents) __attribute__((noinline)) {
Time old(queues.min());
while (queues.min() <= until && maxEvents) {
assert(old <= queues.min());
old = queues.min();
switch (queues.minType()) {
#define HT(T) case RuntimeID<T>::value: handleEvent<T>(); break;
HT(SpikeArrival);
HT(Spike);
HT(RandomSpike);
HT(GlobalMsg);
#undef HT
default: assert(false);
}
maxEvents--;
}
return maxEvents;
}
template<typename Quant>
inline void handleEvent() {
typedef typename QuantDestinationQuant<Quant>::type DstQuant;
Time ct(queues.min());
Event<Quant> &event = queues.get<Quant>()(ct).minPayload();
Ptr<DstQuant> dst(event.dst(topology));
// deliever the event and check if to create new events
DelieverContext<Quant, DstQuant> delieverContext(event.instance(), dst);
PLA_Apply<Quant, DstQuant, pc_t> apply(ct, delieverContext);
pc.call(apply);
// if we create any events
if (apply.generateAny()) {
// evolve all entities which depend on our pre-event values
Evolve<DstQuant>()(pc, ct, dst);
// compute delay values (they require access to the pre- and
// post-event values and can thus only be computed here)
apply.computeDelay(pc);
}
// commit data calculated during apply
// this is necessary because childs are only eventually evolved,
// but require the pre-event values of the instance we are
// committing to now
apply.commit(pc);
// generate events and compute discrete properties
#define MGE(DQ) \
if (apply.template generate<DQ>()) \
generateEvent<DstQuant, DQ, Quant> (ct, dst, apply);
MGE(GlobalMsg);
MGE(Spike);
MGE(RandomSpike);
#undef MGE
if (apply.template generate<SpikeArrival>())
generateSAEvent(ct, event, apply);
if (boost::is_same<Quant, Spike>::value) {
// reinsert spike to get to the next neuron; also handles
// removing current min element from the queue (because of a
// race condition)
reinsertSpike(ct, FORCE_CONV(Event<Spike>, event));
}else{
queues.removeLocalMin<Quant>(ct);
}
}
template<typename ContQuant, typename EventQuant, typename SrcEvQuant>
inline void generateEvent(Time ct,
typename ContQuant::instance_ptr_t src,
PLA_Apply<SrcEvQuant, ContQuant, pc_t> &apply) {
// generate new discrete quant instance
Time eventTime = ct + apply.template getDelay<EventQuant>();
Ptr<EventQuant> ptrNE(indices.get<Index<EventQuant>>().add(ct, eventTime, src));
EmitContext<ContQuant, EventQuant> emitContext(src, ptrNE);
PLA_Generate<ContQuant, EventQuant, indices_t, queues_t>
pla_gen(ct, emitContext, indices, queues);
pc.call(pla_gen);
// generate new event
if (likely((not TopologicalEventDiscard<ContQuant, EventQuant>()(topology, src))))
queues.insert
(ct,
eventTime + TopologicalTimeOffset<ContQuant, EventQuant>()(topology, src),
Event<EventQuant>(eventTime, src, ptrNE));
}
template<typename EventT, typename ContQuant, typename SrcEvQuant>
inline void generateSAEvent(Time ct,
EventT &rawEvent,
PLA_Apply<SrcEvQuant, ContQuant, pc_t> &apply) {
// garantuee that we are called by spike event and cast alike
assert((boost::is_same<EventT, Event<Spike>>::value));
assert((boost::is_same<ContQuant, Synapse>::value));
Event<Spike> &event(FORCE_CONV(Event<Spike>, rawEvent));
Ptr<Synapse> src(event.dst(topology));
// calculate the SA-ptr
Ptr<SpikeArrival> ptrNE(event.instance(), event.offset);
// generate all SA properties (except voltage difference)
EmitContext<Synapse, SpikeArrival> emitContext(src, ptrNE);
PLA_Generate<Synapse, SpikeArrival, indices_t, queues_t>
pla_gen(ct, emitContext, indices, queues);
pc.call(pla_gen);
// generate event and add to queues
queues.insert(ct, ct, Event<SpikeArrival>(src, ptrNE));
}
inline void reinsertSpike(Time ct, Event<Spike> &event) {
// TODO (optimize): reuse the current event
Event<Spike>::offset_t offset(event.offset + 1);
if (unlikely((topology.synapse(event.src, offset)() == Topology::nil()()))) {
queues.removeLocalMin<Spike>(ct);
}else{
// create new event (depends on old)
Event<Spike> newEvent
(event.baseTime,
event.src,
event.spike,
offset);
// delete old event; this must happen before insertion of the
// new event to avoid race in case of equal times
queues.removeLocalMin<Spike>(ct);
// insert new event
queues.insert
(ct,
newEvent.baseTime + topology.time(newEvent.src, offset),
newEvent);
}
}
void sync() {
// TODO: sync all or remove method
pc.cast(PLA_Sync{});
indices.get<Index<GlobalMsg>>().sync();
queues.get<GlobalMsg>().sync();
}
Time currentTime() {
return queues.min();
}
/// persistant data storage (holds every mmap'ed data structure)
// properties
pc_t pc;
Topology topology;
// indices
template<typename T> struct index_from_type {
typedef Index<T> type;
};
typedef typename boost::mpl::transform<
DiscreteQuantorList,
index_from_type<boost::mpl::_>
>::type indices_list_t;
typedef typename UnpackTypeList<TypeSet, indices_list_t>::type indices_t;
indices_t indices;
// event queues
typedef MultiQueue<
Time, Event, DiscreteQuantorList
> queues_t;
queues_t queues;
// TODO (beauty): add checks for proper r/w status in pc_t (all
// writable)
};
} // Namespace SimLoopImpl
using SimLoopImpl::SimLoop;
#endif // Lh5wJREkwqXIDpptCEqbkLO3ed4
|