#ifndef BjxF7IwCJEpR8eQGIzMk04pwFg #define BjxF7IwCJEpR8eQGIzMk04pwFg #include #include #include #include #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 struct CalcDPtr { typedef Ptr type; }; template <> struct CalcDPtr { typedef boost::tuple, Ptr> type; }; /// factory defining which discrete quants we have to consider template struct MultiQueueFactory; template<> struct MultiQueueFactory { typedef list dependencies; typedef MultiQueue type; typedef IdList::ptr_t> id_list_t; static type instance(id_list_t &, const Time time) { return type(time); } }; template<> struct MultiQueueFactory { typedef list dependencies; typedef MultiQueue type; typedef IdList::ptr_t> id_list_t; static type instance(id_list_t ids, const Time time) { return type(Filter (time), Filter (ids, time), Filter (ids, time), Filter(ids, time)); } }; template<> struct MultiQueueFactory : MultiQueueFactory { typedef IdList::ptr_t> id_list_t; static type instance(id_list_t ids_synapse, Time time) { MultiQueueFactory::id_list_t ids_neuron; for (auto syn : ids_synapse) ids_neuron.insert(Ptr(syn).extractNeuron()()); return MultiQueueFactory::instance(ids_neuron, time); } }; /// template brainfuck to prevent instancing unnecessary handleEvents<>() template struct MaybeHandleEvent { template struct HandleEvent { template void operator() (Sim &sim) { sim.template handleEvent(); } }; struct IgnoreEvent { template void operator() (Sim &sim) {} }; typedef typename contains< typename MultiQueueFactory::dependencies, Quant>::type isRelevant; typedef typename if_, IgnoreEvent >::type impl; }; /// extract neurons from arbitrary id list template struct ExtractNeuronIDs; template<> struct ExtractNeuronIDs { IdList::ptr_t> operator() (IdList::ptr_t> &) { return IdList::ptr_t>(); } }; template<> struct ExtractNeuronIDs { IdList::ptr_t> operator() (IdList::ptr_t> &src) { return src; } }; template<> struct ExtractNeuronIDs { IdList::ptr_t> operator() (IdList::ptr_t> &src) { IdList::ptr_t> res; for (auto id : src) res.insert(Ptr(id).extractNeuron()()); return res; } }; /// the precious replay template class EventHandler = MaybeHandleEvent> struct SimReplay { typedef PropertyComposition PropComp; typedef Checkpoint Cp; typedef IdList::ptr_t> id_list_t; typedef IdList::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()(ids)), queues(std::move(MultiQueueFactory::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::type get(Ptr 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 Ctx; PLA_Get 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::value: typename EventHandler::impl()(*this); break; HT(SpikeArrival); HT(Spike); HT(RandomSpike); HT(GlobalMsg); #undef HT default: assert(false); } --maxEvents; } return maxEvents; } template inline bool handleEvent() { typedef typename QuantDestinationQuant::type DstQuant; typename CalcDPtr::type src(queues.get().minPayload().src); Ptr dst(queues.get().minPayload().dst); // deliever the event and check if to create new events DelieverContext delieverContext{src, dst}; PLA_Apply apply(ct, delieverContext); pc.call(apply); // create events if (apply.generateAny()) { // determine how much we have to simulate: if (is_same::value) { // - global replay don't needs any childs pc.cast(PLA_Evolve{ContinuousContext{Ptr{}}, ct}); }else{ if (is_same::value) { // - neuron/synapse replay needs global and selected neurons for (auto id : neurons) Evolve()(pc, ct, Ptr{id}); pc.cast(PLA_Evolve{ContinuousContext{Ptr{}}, ct}); }else{ // - neuron/synapse evolve happens as usual Evolve()(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()) \ handleEventGeneration(ct, dst, apply); HGE(GlobalMsg); HGE(Spike); HGE(RandomSpike); HGE(SpikeArrival); #undef HGE queues.template removeMin(ct); return apply.template generate(); } template inline void handleEventGeneration(Time ct, Ptr src, PLA_Apply &) { Void nix; pc.cast(PLA_Generate (ct, EmitContext(src, Ptr(-1)), nix, nix)); } Time currentTime() { return ct; } /// ephermal state Time ct; id_list_t ids; neuron_list_t neurons; typename MultiQueueFactory::type queues; PropComp pc; /// persistant data storage (holds every mmap'ed data structure) //Topology topology; }; } // Namespace ReplayImpl using SimReplayImpl::SimReplay; #endif // BjxF7IwCJEpR8eQGIzMk04pwFg