diff options
Diffstat (limited to 'core/sim_replay.hpp')
-rw-r--r-- | core/sim_replay.hpp | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/core/sim_replay.hpp b/core/sim_replay.hpp new file mode 100644 index 0000000..c34e216 --- /dev/null +++ b/core/sim_replay.hpp @@ -0,0 +1,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 |