summaryrefslogtreecommitdiff
path: root/core/sim_replay.hpp
blob: c34e2162a928ddcf830f3552169bd6fbedd1c9d0 (plain)
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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#ifndef BjxF7IwCJEpR8eQGIzMk04pwFg
#define BjxF7IwCJEpR8eQGIzMk04pwFg

#include <algorithm>
#include <boost/tuple/tuple.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/contains.hpp>

#include "context.hpp"
#include "event.hpp"
#include "evolve.hpp"
#include "index.hpp"
#include "index_global.hpp"
#include "index_spike.hpp"
#include "index_spike_arrival.hpp"
#include "filter.hpp"
#include "multi_queue.hpp"
#include "pla_apply.hpp"
#include "pla_evolve.hpp"
#include "pla_generate.hpp"
#include "pla_initbycopy.hpp"
#include "pla_sync.hpp"
#include "time.hpp"
#include "topology.hpp"
#include "type_set.hpp"

#include "model.hpp"

namespace SimReplayImpl {

using namespace boost;
using namespace boost::mpl;

// TODO: remove (is redundant code)
template <typename Quant> struct CalcDPtr { 
  typedef Ptr<Quant> type; 
};
template <> struct CalcDPtr<SpikeArrival> {
  typedef boost::tuple<Ptr<SpikeArrival>, Ptr<Synapse>> type;
};

/// factory defining which discrete quants we have to consider

template<typename ReplayQuant>
struct MultiQueueFactory;

template<>
struct MultiQueueFactory<Global> {
  typedef list<GlobalMsg> dependencies;
  typedef MultiQueue<Time, FilterPayload, dependencies, FilterContainer> type;
  typedef IdList<Ptr<Global>::ptr_t> id_list_t;
  static type instance(id_list_t &, const Time time) {
    return type(time);
  }
};

template<>
struct MultiQueueFactory<Neuron> {
  typedef list<GlobalMsg, Spike, RandomSpike, SpikeArrival> dependencies;
  typedef MultiQueue<Time, FilterPayload, dependencies, FilterContainer> type;
  typedef IdList<Ptr<Neuron>::ptr_t> id_list_t;
  static type instance(id_list_t ids, const Time time) {
    return type(Filter<GlobalMsg>   (time),
		Filter<Spike>       (ids, time),
		Filter<RandomSpike> (ids, time),
		Filter<SpikeArrival>(ids, time));
  }
};

template<>
struct MultiQueueFactory<Synapse> : MultiQueueFactory<Neuron> {
  typedef IdList<Ptr<Synapse>::ptr_t> id_list_t;
  static type instance(id_list_t ids_synapse, Time time) {
    MultiQueueFactory<Neuron>::id_list_t ids_neuron;
    for (auto syn : ids_synapse)
      ids_neuron.insert(Ptr<Synapse>(syn).extractNeuron()());
    return MultiQueueFactory<Neuron>::instance(ids_neuron, time);
  }
};

/// template brainfuck to prevent instancing unnecessary handleEvents<>()

template<typename ReplayQuant, typename Quant>
struct MaybeHandleEvent {
  template<typename Q> struct HandleEvent {
    template<typename Sim> void operator() (Sim &sim) {
      sim.template handleEvent<Q>();
    }
  };

  struct IgnoreEvent {
    template<typename Sim> void operator() (Sim &sim) {}
  };

  typedef typename contains<
    typename MultiQueueFactory<ReplayQuant>::dependencies,
    Quant>::type isRelevant;
  typedef typename if_<isRelevant,
		       HandleEvent<Quant>,
		       IgnoreEvent
		       >::type impl;
};


/// extract neurons from arbitrary id list
template<typename Quant> struct ExtractNeuronIDs;

template<>
struct ExtractNeuronIDs<Global> {
  IdList<Ptr<Neuron>::ptr_t> operator() (IdList<Ptr<Global>::ptr_t> &) {
    return IdList<Ptr<Neuron>::ptr_t>();
  }
};

template<>
struct ExtractNeuronIDs<Neuron> {
  IdList<Ptr<Neuron>::ptr_t> operator() (IdList<Ptr<Neuron>::ptr_t> &src) {
    return src;
  }
};

template<>
struct ExtractNeuronIDs<Synapse> {
  IdList<Ptr<Neuron>::ptr_t> operator() (IdList<Ptr<Synapse>::ptr_t> &src) {
    IdList<Ptr<Neuron>::ptr_t> res;
    for (auto id : src)
      res.insert(Ptr<Synapse>(id).extractNeuron()());
    return res;
  }
};

/// the precious replay

template<typename PropList, typename ReplayQuant,
	 template<class, class> class EventHandler = MaybeHandleEvent>
struct SimReplay {
  typedef PropertyComposition<PropList> PropComp;
  typedef Checkpoint<Void, 1> Cp;
  typedef IdList<typename Ptr<ReplayQuant>::ptr_t> id_list_t;
  typedef IdList<typename Ptr<Neuron>::ptr_t> neuron_list_t;

  SimReplay(id_list_t ids, Time start)
    // we need the previous checkpoint interval
    : ct(Cp::interval() * (std::max((const uint32_t) 1, Cp::binTime(start)) - 1)),
      ids(ids),
      neurons(ExtractNeuronIDs<ReplayQuant>()(ids)),
      queues(std::move(MultiQueueFactory<ReplayQuant>::instance(ids, ct)))
  {
    // init values of our quant
    pc.cast(PLA_InitByCopy{ct});

    // forward precisely to the request time
    run(start, -1);
  }

  template<typename Prop>
  typename Prop::type get(Ptr<ReplayQuant> id, Time t) {
    // TODO (maybe): allow to read all calculated values, not just
    // those of the ReplayQuant (e.g. the synapses properties of a
    // simulated neuron)
    assert(t >= ct);
    assert(ids.count(id()));
    run(t, -1);
    typedef ContinuousContext<ReplayQuant> Ctx;
    PLA_Get<Prop, Ctx> pla_get(t, Ctx(id));
    return pc.call(pla_get);
  }

  bool run(const Time until, uint64_t maxEvents) {
    assert(until != Time::never());
    while (queues.min() <= until && maxEvents) {
      ct = queues.min();
      switch (queues.minType()) {
#define HT(T) case RuntimeID<T>::value: typename EventHandler<ReplayQuant, T>::impl()(*this); break;
	HT(SpikeArrival);
	HT(Spike);
	HT(RandomSpike);
	HT(GlobalMsg);
#undef HT
      default: assert(false);
      }
      --maxEvents;
    }
    return maxEvents;
  }
    
  template<typename Quant>
  inline bool handleEvent() {
    typedef typename QuantDestinationQuant<Quant>::type DstQuant;
    typename CalcDPtr<Quant>::type src(queues.get<Quant>().minPayload().src);
    Ptr<DstQuant>                  dst(queues.get<Quant>().minPayload().dst);

    // deliever the event and check if to create new events
    DelieverContext<Quant, DstQuant> delieverContext{src, dst};
    PLA_Apply<Quant, DstQuant, PropComp> apply(ct, delieverContext);
    pc.call(apply);
    
    // create events
    if (apply.generateAny()) {
      // determine how much we have to simulate:
      if (is_same<ReplayQuant, Global>::value) {
	// - global replay don't needs any childs
	pc.cast(PLA_Evolve<Global>{ContinuousContext<Global>{Ptr<Global>{}}, ct});
      }else{
	if (is_same<DstQuant, Global>::value) {
	  // - neuron/synapse replay needs global and selected neurons
	  for (auto id : neurons)
	    Evolve<Neuron>()(pc, ct, Ptr<Neuron>{id});
	  pc.cast(PLA_Evolve<Global>{ContinuousContext<Global>{Ptr<Global>{}}, ct});
	}else{
	  // - neuron/synapse evolve happens as usual
	  Evolve<DstQuant>()(pc, ct, dst);
	}
      }
    }
    // 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);

    // call the continuous property related post-event triggers to
    // update state
#define HGE(Q) \
    if (apply.template generate<Q>()) \
      handleEventGeneration<DstQuant, Q, Quant>(ct, dst, apply);

    HGE(GlobalMsg);
    HGE(Spike);
    HGE(RandomSpike);
    HGE(SpikeArrival);
#undef HGE

    queues.template removeMin<Quant>(ct);

    return apply.template generate<Spike>();
  }

  template<typename ContQuant, typename EventQuant, typename SrcEvQuant>
  inline void handleEventGeneration(Time ct, Ptr<ContQuant> src, 
				    PLA_Apply<SrcEvQuant, ContQuant, PropComp> &)
  {
    Void nix;
    pc.cast(PLA_Generate<ContQuant, EventQuant, Void, Void>
	    (ct, EmitContext<ContQuant, EventQuant>(src, Ptr<EventQuant>(-1)),
	     nix, nix));
  }

  Time currentTime() {
    return ct;
  }

  /// ephermal state
  Time ct;
  id_list_t ids;
  neuron_list_t neurons;
  typename MultiQueueFactory<ReplayQuant>::type queues;
  PropComp pc;  

  /// persistant data storage (holds every mmap'ed data structure)
  //Topology topology;
};

} // Namespace ReplayImpl

using SimReplayImpl::SimReplay;

#endif // BjxF7IwCJEpR8eQGIzMk04pwFg
contact: Jan Huwald // Impressum