summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorJan Huwald <jh@sotun.de>2012-05-07 20:01:51 (GMT)
committerJan Huwald <jh@sotun.de>2012-05-07 20:01:51 (GMT)
commit420d2ef464d4a741028e132e662d5626806a41f5 (patch)
tree1aca6eb512e4ed0fb5f3c10c528cb998b6ffd695 /core
Initial commitHEADmaster
Diffstat (limited to 'core')
-rw-r--r--core/all_spikes.cpp49
-rw-r--r--core/array.hpp53
-rw-r--r--core/bit_access.hpp38
-rw-r--r--core/bootstrap.cpp106
-rw-r--r--core/checkpoint.hpp165
-rw-r--r--core/coarse_replay.cpp89
-rw-r--r--core/context.hpp123
-rw-r--r--core/continuous_property.hpp93
-rw-r--r--core/continuous_property_impl.hpp13
-rw-r--r--core/convert_topology.cpp161
-rw-r--r--core/discrete_property.hpp39
-rw-r--r--core/ephermal_checkpoint.hpp83
-rw-r--r--core/event.hpp107
-rw-r--r--core/everything_else.hpp14
-rw-r--r--core/evolve.hpp35
-rw-r--r--core/filter.hpp379
-rw-r--r--core/heap.hpp157
-rw-r--r--core/id_list.hpp47
-rw-r--r--core/index.hpp148
-rw-r--r--core/index_global.hpp48
-rw-r--r--core/index_randomspike.hpp52
-rw-r--r--core/index_spike.hpp14
-rw-r--r--core/index_spike_arrival.hpp32
-rw-r--r--core/index_spike_base.hpp151
-rw-r--r--core/list_synapses.cpp22
-rw-r--r--core/mempool.hpp156
-rw-r--r--core/model.hpp23
-rw-r--r--core/multi_queue.hpp187
-rw-r--r--core/perftools.hpp40
-rw-r--r--core/pla_apply.hpp276
-rw-r--r--core/pla_debug_name.hpp39
-rw-r--r--core/pla_debug_space.hpp172
-rw-r--r--core/pla_evolve.hpp93
-rw-r--r--core/pla_generate.hpp112
-rw-r--r--core/pla_get.hpp92
-rw-r--r--core/pla_getbyname.hpp37
-rw-r--r--core/pla_init_default.hpp65
-rw-r--r--core/pla_initbycopy.hpp70
-rw-r--r--core/pla_set.hpp79
-rw-r--r--core/pla_sync.hpp47
-rw-r--r--core/pointers.hpp213
-rw-r--r--core/priority_queue.hpp146
-rw-r--r--core/property_abbrevations_begin.hpp18
-rw-r--r--core/property_abbrevations_end.hpp9
-rw-r--r--core/property_access.hpp32
-rw-r--r--core/property_composition.hpp35
-rw-r--r--core/property_instance.hpp65
-rw-r--r--core/property_list.hpp94
-rw-r--r--core/quant_types.hpp181
-rw-r--r--core/replay.cpp99
-rw-r--r--core/report_names.cpp15
-rw-r--r--core/report_runtimeid.cpp19
-rw-r--r--core/report_spacereq.cpp15
-rw-r--r--core/rng.hpp83
-rw-r--r--core/scalar.hpp58
-rw-r--r--core/signal_handler.hpp34
-rw-r--r--core/sim_causality.hpp177
-rw-r--r--core/sim_loop.hpp218
-rw-r--r--core/sim_replay.hpp268
-rw-r--r--core/simlimits.hpp18
-rw-r--r--core/simulate.cpp77
-rw-r--r--core/spike_in.cpp64
-rw-r--r--core/spike_out.cpp46
-rw-r--r--core/string_helpers.hpp36
-rw-r--r--core/system_helpers.hpp15
-rw-r--r--core/template_helpers.hpp121
-rw-r--r--core/test_.cpp45
-rw-r--r--core/test_checkpoint.cpp52
-rw-r--r--core/test_filter.cpp77
-rw-r--r--core/test_heap.cpp43
-rw-r--r--core/test_index.cpp41
-rw-r--r--core/test_index_speed.cpp39
-rw-r--r--core/test_mmap.cpp52
-rw-r--r--core/test_mmap2.cpp26
-rw-r--r--core/test_movector.cpp21
-rw-r--r--core/test_multi_queue.cpp164
-rw-r--r--core/test_pla_apply.cpp56
-rw-r--r--core/test_pla_evolve.cpp88
-rw-r--r--core/test_pla_getset.cpp44
-rw-r--r--core/test_prioque.cpp40
-rw-r--r--core/test_prioque_speed.cpp38
-rw-r--r--core/test_propcomp.cpp33
-rw-r--r--core/test_propcomp_cpp-speed.cpp48
-rw-r--r--core/test_rng.cpp76
-rw-r--r--core/test_scalar.cpp23
-rw-r--r--core/test_sim_loop.cpp28
-rw-r--r--core/test_typemap.cpp25
-rw-r--r--core/test_vector.cpp62
-rw-r--r--core/test_vector_speed.cpp28
-rw-r--r--core/time.hpp98
-rw-r--r--core/topology.hpp88
-rw-r--r--core/track_causality.cpp72
-rw-r--r--core/trainer.hpp52
-rw-r--r--core/trainer_impl.hpp162
-rw-r--r--core/type_map.hpp83
-rw-r--r--core/type_set.hpp91
-rw-r--r--core/vector.hpp106
97 files changed, 7763 insertions, 0 deletions
diff --git a/core/all_spikes.cpp b/core/all_spikes.cpp
new file mode 100644
index 0000000..5307e8b
--- /dev/null
+++ b/core/all_spikes.cpp
@@ -0,0 +1,49 @@
+#include <assert.h>
+#include <errno.h>
+#include <iostream>
+#include <stdlib.h>
+
+#include "everything_else.hpp"
+#include "index.hpp"
+#include "index_spike.hpp"
+#include "index_randomspike.hpp"
+
+#include "mempool.hpp"
+
+using namespace std;
+
+int main(int argc, char **argv) {
+ // read cmd line params
+ assert(argc == 3);
+
+ errno = 0;
+ char *tail;
+ Time start(strtod( argv[1], &tail)); assert(*tail == 0);
+ Time stop( strtod( argv[2], &tail)); assert(*tail == 0);
+ assert(errno == 0);
+
+ assertSimDir();
+
+ {
+ // go to first spike with time >= start
+ // Index<RandomSpike> idx;
+ // Ptr<RandomSpike>::ptr_t cur(idx.first(start));
+ Index<Spike> idx;
+ Ptr<Spike>::ptr_t cur(idx.first(start));
+
+ // no spike found?
+ if (cur == idx.nil())
+ return 0;
+
+ // output
+ cout << "# time\tneuron" << endl;
+ while (cur <= idx.last() && idx.time(cur) <= stop) {
+ if (idx.src(cur) < numActualNeurons) // don't plot pseudo neurons
+ // cout << idx.eventTime(cur) << "\t" << idx.src(cur) << endl;
+ cout << idx.time(cur) << "\t" << idx.src(cur) << endl;
+ ++cur;
+ }
+ }
+
+ return 0;
+}
diff --git a/core/array.hpp b/core/array.hpp
new file mode 100644
index 0000000..e882f92
--- /dev/null
+++ b/core/array.hpp
@@ -0,0 +1,53 @@
+#ifndef IuE4Lmq81ZDeAq0u7S79e56kZZQ
+#define IuE4Lmq81ZDeAq0u7S79e56kZZQ
+
+#include <inttypes.h>
+#include <assert.h>
+#include <boost/static_assert.hpp>
+
+#include "bit_access.hpp"
+#include "template_helpers.hpp"
+
+// size - number of elements
+// width - size of each elements (in bit!)
+template<typename T, uint32_t size, size_t width = 8 * sizeof(T)>
+class Array {
+public:
+ typedef uint32_t ptr_t;
+
+ // reader and writer
+ inline T get(ptr_t id);
+ inline void set(ptr_t id, T value);
+
+ // allow accessing raw memory (this also encodes the correct size of the object)
+ uint8_t mem[ size * ((width + 7) / 8) ];
+
+ // garantuee that all sizes = 2^n
+ STATIC_ASSERT_IS_POWER_OF_TWO(width);
+ STATIC_ASSERT_IS_POWER_OF_TWO(size);
+ // garantue that we do not need bit-level access of the underlying container
+ BOOST_STATIC_ASSERT((uint64_t) width * size >= 8);
+};
+
+template<typename T, uint32_t size, size_t width>
+inline T Array<T, size, width>::get(ptr_t id) {
+ assert(id < size);
+ if (width < 8) {
+ uint8_t res = bit_extract(mem, (uint8_t) width, id);
+ return FORCE_CONV(T, res);
+ }else{
+ return *((T*) (((char*) mem) + (width / 8) * id)); // TO CHECK: improve cast?
+ }
+}
+
+template<typename T, uint32_t size, size_t width>
+inline void Array<T, size, width>::set(ptr_t id, T value) {
+ assert(id < size);
+ if (width < 8) {
+ bit_insert(mem, (uint8_t) width, id, value);
+ }else{
+ *((T*) (((char*) mem) + (width / 8) * id)) = value;
+ }
+}
+
+#endif // IuE4Lmq81ZDeAq0u7S79e56kZZQ
diff --git a/core/bit_access.hpp b/core/bit_access.hpp
new file mode 100644
index 0000000..566254e
--- /dev/null
+++ b/core/bit_access.hpp
@@ -0,0 +1,38 @@
+#ifndef vjxaugYoBtZu5XZVahcafy1l5XU
+#define vjxaugYoBtZu5XZVahcafy1l5XU
+
+#include <inttypes.h>
+#include <assert.h>
+
+#include "template_helpers.hpp"
+
+inline uint8_t bit_extract(void *base, uint8_t width, uint64_t id) {
+ assert(width < 8);
+
+ uint8_t off, mask, block, result, *addr;
+
+ addr = ((uint8_t*) base) + (id * width / 8);
+ off = (id % (8 / width)) * width;
+ mask = (~((~0) << width)) << off;
+ block = * addr;
+ result = (block & mask) >> off;
+
+ return result;
+}
+
+template<class T>
+inline void bit_insert(void *base, uint8_t width, uint64_t id, T rawValue) {
+ assert(width < 8);
+
+ uint8_t off, mask, block, result, *addr;
+ uint8_t value(FORCE_CONV(uint8_t, rawValue));
+
+ addr = ((uint8_t*) base) + (id * width / 8);
+ off = (id % (8 / width)) * width;
+ mask = (~((~0) << width)) << off;
+ block = * addr;
+ result = (block & (~mask)) | ((value << off) & mask); // mask also value, in case it is larger than allowed
+ *addr = result;
+}
+
+#endif // vjxaugYoBtZu5XZVahcafy1l5XU
diff --git a/core/bootstrap.cpp b/core/bootstrap.cpp
new file mode 100644
index 0000000..092d0f2
--- /dev/null
+++ b/core/bootstrap.cpp
@@ -0,0 +1,106 @@
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/pair.hpp>
+#include <iostream>
+#include <inttypes.h>
+
+#include "index.hpp"
+#include "index_spike.hpp"
+#include "pla_get.hpp"
+#include "property_composition.hpp"
+#include "pla_init_default.hpp"
+#include "pla_set.hpp"
+#include "sim_loop.hpp"
+
+#include "model.hpp"
+
+using namespace boost;
+
+const Time startTime(0.1);
+
+struct FakeSim {
+ FakeSim()
+ : indices(),
+ queues()
+ {
+ using boost::make_tuple;
+ }
+
+ Ptr<GlobalMsg> addGlobalMsg(RNG::seed_t seed) {
+ const Time gmStartTime(ModelConsts::TrainerInitialDelay);
+ // create an discrete quant instance
+ Ptr<GlobalMsg> res(indices.get<Index<GlobalMsg>>().add
+ (Time(0), gmStartTime, Ptr<Global>()));
+ // and a corresponding event occuring at time 0.1, stored in start
+ // interval (t=0)
+ queues.insert<GlobalMsg>(Time(0), gmStartTime, Event<GlobalMsg>(res));
+ pc.cast(PLA_Set<NextTrainer>(res, TrainerT(seed)));
+ return res;
+ }
+
+ Ptr<Spike> addSpike(Ptr<Neuron> src) {
+ Time eventTime = startTime + TopologicalTimeOffset<Neuron, Spike>()(topo, src);
+ Ptr<Spike> res(indices.get<Index<Spike>>().add(startTime, eventTime, src));
+ queues.insert<Spike>(Time(0), eventTime, Event<Spike>(startTime, src, res));
+ return res;
+ }
+
+ Ptr<RandomSpike> addRandomSpike(Ptr<Neuron> src, RNG::seed_t seed) {
+ Time eventTime = startTime + RNG::expo(seed, 1 / ModelConsts::RandomFreq);
+ Ptr<RandomSpike> res(indices.get<Index<RandomSpike>>().add
+ (startTime, eventTime, src));
+ queues.insert<RandomSpike>(Time(0), eventTime,
+ Event<RandomSpike>(eventTime, src, res));
+ return res;
+ }
+
+ // data structs
+ typedef SimLoop<Lists::all> sim_t;
+ sim_t::indices_t indices;
+ sim_t::queues_t queues;
+ sim_t::pc_t pc;
+ Topology topo;
+};
+
+using namespace std;
+
+int main(int argc, char **argv) {
+ using boost::mpl::pair;
+ using boost::mpl::list;
+ FakeSim data;
+
+ // read cmd line arg
+ if (argc > 2) {
+ cout << "Usage: " << argv[0] << " [random-seed=0]";
+ }
+ char *tail;
+ RNG::seed_t rng(0);
+ if (argc == 2) {
+ rng = RNG::seed_t(strtoll(argv[1], &tail, 10));
+ assert(*tail == 0);
+ }
+
+ // init values (except weight)
+ data.pc.cast(PLA_Init_Default());
+
+ // init random seed (different one for every neuron)
+ for (Ptr<Neuron> i : Ptr<Global>().childs()) {
+ data.pc.cast(PLA_Set<RandomSeed>(Time(0), i, RNG::split(rng)));
+ rng = RNG::next(rng, 40);
+ }
+
+ // TODO: add a global event to start trainer
+ PLA_Get<NextTrainer> get(Ptr<GlobalMsg>(0));
+ data.addGlobalMsg(RNG::split(rng));
+ rng = RNG::next(rng, 40);
+
+ // add a random noise source for every neuron
+ for (Ptr<Neuron> i : Ptr<Global>().childs())
+ if (i() < ModelConsts::NumExcitatory) { // exclude special neurons
+ data.addRandomSpike(i, RNG::split(rng));
+ rng = RNG::next(rng, 40);
+ }
+
+ // TODO: add discrete properties to the created events
+
+ return 0;
+}
diff --git a/core/checkpoint.hpp b/core/checkpoint.hpp
new file mode 100644
index 0000000..44457b9
--- /dev/null
+++ b/core/checkpoint.hpp
@@ -0,0 +1,165 @@
+#ifndef a4jYavu7NKcD1XX5TXFDvm6LUn8
+#define a4jYavu7NKcD1XX5TXFDvm6LUn8
+
+#include <boost/static_assert.hpp>
+
+#include "array.hpp"
+#include "everything_else.hpp"
+#include "simlimits.hpp"
+#include "string_helpers.hpp"
+#include "template_helpers.hpp"
+#include "time.hpp"
+#include "vector.hpp"
+
+template<typename T, uint32_t size>
+class Checkpoint {
+public:
+ typedef uint32_t ptr_t;
+
+ Checkpoint() = delete;
+ Checkpoint(const string name, const T initialValue);
+
+ // read access
+ inline Time getTime (const Time t, const ptr_t i) __attribute__ ((pure)); // DANGER
+ inline T getValue(const Time t, const ptr_t i);
+ inline Time getTime (const Time t); // only with size == 1
+ inline T getValue(const Time t); // only with size == 1
+
+ // write access
+ inline void set(const Time t, const ptr_t i, const T val);
+ inline void set(const Time t, const T val); // only with size == 1
+
+ void sync() const;
+
+ // page turn-over: stores all checkpoints and open a new checkpoint
+ // table for the next interval
+ void addCheckpoints(const Time newTime);
+
+ // time managment
+ static const ptr_t binTime(const Time t) { return t.ceilDiv(interval()); }
+ static constexpr Time interval() { return checkpointInterval; }
+
+ Time timeLimit, // current interval's time limits (infimum, maximum)
+ timeInf;
+ ptr_t currentInterval;
+
+ // file backings; they store for each interval, for each element the ...
+ Vector< Array< T, size > > content; // ... last known content
+ Vector< Array< Time, size > > times; // ... associated time
+};
+
+template<typename T, uint32_t size>
+inline void Checkpoint<T, size>::set(const Time t, const ptr_t i, const T val) {
+ if (unlikely(t > timeLimit)) addCheckpoints(t);
+ times (currentInterval).set(i, t);
+ content(currentInterval).set(i, val);
+}
+
+template<typename T, uint32_t size>
+inline void Checkpoint<T, size>::set(const Time t, const T val) {
+ BOOST_STATIC_ASSERT(size == 1);
+ set(t, 0, val);
+}
+
+template<typename T, uint32_t size>
+void Checkpoint<T, size>::sync() const {
+ content.sync();
+ times.sync();
+}
+
+template<typename T, uint32_t size>
+inline Time Checkpoint<T, size>::getTime(const Time t, const ptr_t i) {
+ if (unlikely(t > timeLimit)) addCheckpoints(t);
+ ptr_t ival = likely(t > timeInf) ? currentInterval : binTime(t);
+ return times(ival).get(i);
+}
+
+template<typename T, uint32_t size>
+inline Time Checkpoint<T, size>::getTime(const Time t) {
+ BOOST_STATIC_ASSERT(size == 1);
+ return getTime(t, 0);
+}
+
+template<typename T, uint32_t size>
+inline T Checkpoint<T, size>::getValue(const Time t, const ptr_t i) {
+ if (unlikely(t > timeLimit)) addCheckpoints(t);
+ ptr_t ival = likely(t > timeInf) ? currentInterval : binTime(t);
+ return content(ival).get(i);
+}
+
+template<typename T, uint32_t size>
+inline T Checkpoint<T, size>::getValue(const Time t) {
+ BOOST_STATIC_ASSERT(size == 1);
+ return getValue(t, 0);
+}
+
+template<typename T, uint32_t size>
+Checkpoint<T, size>::Checkpoint(const string name, const T initialValue) :
+ timeLimit(0),
+ timeInf(Time(0) - interval()),
+ currentInterval(0),
+ content("checkpoint_content_" + name, maxCheckpoints),
+ times( "checkpoint_times_" + name, maxCheckpoints)
+{
+ assert(content.barrierWrite() == times.barrierWrite());
+
+ // check if we are the first to use this checkpoint and have to initialize it
+ if (content.barrierWrite() == 0) {
+ content.barrierWrite() = 1;
+ times. barrierWrite() = 1;
+ content.barrierRead() = 0;
+ times .barrierRead() = 0;
+
+ for (ptr_t i=0; i<size; i++) {
+ content(0).set(i, initialValue);
+ times(0).set(i, 0);
+ }
+ }
+
+ currentInterval = content.barrierWrite() - 1;
+ timeLimit = Time(currentInterval) * interval();
+ timeInf = Time(currentInterval - 1) * interval();
+}
+
+template<typename T, uint32_t size>
+void Checkpoint<T, size>::addCheckpoints(const Time t) {
+ assert(content.barrierWrite() == times.barrierWrite()); // is a pre- and postcondition
+ // check if the write barrier has been updated externally
+ assert(currentInterval == content.barrierWrite() - 1);
+
+ // now create new checkpoint(s)
+ //
+ // usually the loop below is executed exactly once; only in the
+ // rare case of having no event in an interval it may be
+ // executed several times; if this happens more often one should
+ // increase the interval length significantly to avoid wasting
+ // space
+ while (t > timeLimit) {
+ // copy content and associated times to the new checkpoint
+ // TODO: store chekcpoint number in object, use as cache
+ currentInterval = content.barrierWrite(); // next checkpoint's number
+ for (uint32_t i=0; i<size; i++) {
+ // one could simply memcpy() instead of below, but this way it is intuitive (?)
+ content(currentInterval).set(i, content(currentInterval - 1).get(i));
+ times (currentInterval).set(i, times (currentInterval - 1).get(i));
+ }
+
+ // increase barriers and time limit
+ content.barrierWrite()++;
+ times. barrierWrite()++;
+ content.barrierRead() = content.barrierWrite() - 1;
+ times. barrierRead() = times. barrierWrite() - 1;
+ timeLimit = interval() * currentInterval;
+ timeInf = interval() * (currentInterval - 1);
+ }
+
+ assert(content.barrierWrite() == times.barrierWrite());
+
+ // memory advise that we do not need the past
+ if (currentInterval) {
+ content.advise(0, currentInterval, MADV_DONTNEED);
+ times. advise(0, currentInterval, MADV_DONTNEED);
+ }
+}
+
+#endif // a4jYavu7NKcD1XX5TXFDvm6LUn8
diff --git a/core/coarse_replay.cpp b/core/coarse_replay.cpp
new file mode 100644
index 0000000..24412cc
--- /dev/null
+++ b/core/coarse_replay.cpp
@@ -0,0 +1,89 @@
+#include <assert.h>
+#include <errno.h>
+#include <iostream>
+#include <stdlib.h>
+
+#include <boost/type_traits/is_same.hpp>
+
+#include "everything_else.hpp"
+#include "id_list.hpp"
+#include "time.hpp"
+#include "template_helpers.hpp"
+#include "pla_getbyname.hpp"
+#include "property_composition.hpp"
+
+#include "model.hpp"
+
+#include "mempool.hpp"
+
+using namespace std;
+
+template<typename Prop, typename QuantClass = typename Prop::quant::class_t>
+struct CoarseReplay;
+
+// define base case with virtual op() to runtime dispatch call by property name
+template<>
+struct CoarseReplay<BaseCase, Void> {
+ virtual void operator() (Time start, Time stop, IdList<uint64_t> rawIds) {
+ assert(false);
+ }
+};
+
+template<typename Prop>
+struct CoarseReplay<Prop, ContinuousPropertyClass> : CoarseReplay<BaseCase, Void> {
+ virtual void operator() (Time start, Time stop,
+ IdList<uint64_t> rawIds) {
+ IdList<typename Ptr<typename Prop::quant>::ptr_t> ids(rawIds);
+ PropertyInstance<Prop, true> pi;
+ assert(stop <= pi.data.timeLimit);
+ assert(start >= 0);
+
+ // print header
+ cout << "#";
+ for (auto i : ids) cout << "\tval(" << (uint64_t) i << ")";
+ for (auto i : ids) cout << "\ttime(" << (uint64_t) i << ")";
+ cout << endl;
+
+ // print data
+ for (Time t = start; t <= stop; t = t + pi.data.interval()) {
+ cout << t();
+ for (auto i : ids) cout << "\t" << pi.data.getValue(t, i);
+ for (auto i : ids) cout << "\t" << pi.data.getTime (t, i);
+ cout << endl;
+ }
+ }
+};
+
+template<typename Prop>
+struct CoarseReplay<Prop, DiscretePropertyClass> : CoarseReplay<BaseCase, Void> {
+ virtual void operator() (Time start, Time stop, uint64_t raw_addr) {
+ cerr << Prop::name << " is a discrete property" << endl;
+ exit(-1);
+ }
+};
+
+
+int main(int argc, char **argv) {
+ // read cmd line params
+ assert(argc == 5);
+ assertSimDir();
+
+ {
+ PropertyComposition<Lists::all> pc;
+ PLA_GetByName<CoarseReplay> pla(argv[1]);
+ CoarseReplay<BaseCase, Void> *replay(pc.call(pla));
+ assert(replay != NULL);
+
+ errno = 0;
+ char *tail;
+ IdList<uint64_t> ids(argv[2]);
+ Time start( strtod( argv[3], &tail)); assert(*tail == 0);
+ Time stop( strtod( argv[4], &tail)); assert(*tail == 0);
+ assert(errno == 0);
+
+ // output
+ (*replay)(start, stop, ids);
+ }
+
+ return 0;
+}
diff --git a/core/context.hpp b/core/context.hpp
new file mode 100644
index 0000000..dd4ed7e
--- /dev/null
+++ b/core/context.hpp
@@ -0,0 +1,123 @@
+#ifndef sOuC39DJVwHiStoyuZdritpuC5M
+#define sOuC39DJVwHiStoyuZdritpuC5M
+
+#include <assert.h>
+
+#include <boost/type_traits/is_same.hpp>
+#include <boost/mpl/set.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/insert.hpp>
+#include <boost/tuple/tuple.hpp>
+
+#include "pointers.hpp"
+#include "time.hpp"
+#include "type_set.hpp"
+
+/* methods common to all context's
+
+ getptr<Quant>() -> return an instance id
+
+ */
+
+namespace ContextImpl {
+
+ using namespace boost;
+ using namespace boost::mpl;
+
+ // common context (internal)
+ template<typename... Quants>
+ struct CCtx : public TypeSet<Ptr<Quants>...> {
+ CCtx(Ptr<Quants>... ids) : TypeSet<Ptr<Quants>...>(std::move(ids)...) {}
+
+ template<typename Quant>
+ typename Quant::instance_ptr_t getptr() {
+ return this->template get<Ptr<Quant>>();
+ }
+ };
+
+ /// SingleContext: stores a single quant w/o any relation
+ template<typename Quant>
+ struct SingleContext : public CCtx<Quant> {
+ SingleContext(Ptr<Quant> id) : CCtx<Quant>(id) {}
+ };
+
+ /// ContinuousContext: resembles the global <- neuron <- synapse hierarchy
+ template<typename Quant>
+ struct ContinuousContext;
+
+ template<>
+ struct ContinuousContext<Global> : CCtx<Global> {
+ ContinuousContext()
+ : CCtx<Global>(Ptr<Global>()) {}
+ explicit ContinuousContext(Ptr<Global> p)
+ : CCtx<Global>(p) {}
+ };
+
+ template<>
+ struct ContinuousContext<Neuron> : CCtx<Neuron, Global> {
+ explicit ContinuousContext(Ptr<Neuron> p)
+ : CCtx<Neuron, Global>(p, Ptr<Global>()) {}
+ };
+
+ template<>
+ struct ContinuousContext<Synapse>
+ : CCtx<Synapse, Neuron, Global> {
+ explicit ContinuousContext(Ptr<Synapse> p)
+ : CCtx<Synapse, Neuron, Global>(p, p.extractNeuron(), Ptr<Global>()) {}
+ };
+
+ // common context with one discrete ptr (internal)
+ template<typename DQ, typename CQ>
+ struct DCtx {
+ DCtx(Ptr<DQ> did, Ptr<CQ> cid)
+ : id(did), sub(cid) {}
+
+ template<typename Quant>
+ typename Quant::instance_ptr_t getptr() {
+ if (boost::is_same<Quant, DQ>::value) {
+ return FORCE_CONV(typename Quant::instance_ptr_t, id);
+ }else{
+ return sub.getptr<Quant>();
+ }
+ }
+
+ friend std::ostream& operator<< (std::ostream &os, DCtx val) {
+ return os << val.id << ":" << val.sub;
+ }
+
+ Ptr<DQ> id;
+ ContinuousContext<CQ> sub;
+ };
+
+
+ /// DelieverContext: when a (discrete) event is delievered to a
+ /// continuous quantity
+ template<typename DQ, typename CQ>
+ struct DelieverContext : DCtx<DQ, CQ> {
+ DelieverContext(Ptr<DQ> did, Ptr<CQ> cid)
+ : DCtx<DQ, CQ>(did, cid) {}
+ };
+
+ // HACK: allow Neuron to access Synapse on SpikeArrival; this only
+ // works because SA is send with a zero delay, so synapse is already
+ // evolved to current time
+ template<>
+ struct DelieverContext<SpikeArrival, Neuron> : DCtx<SpikeArrival, Synapse> {
+ DelieverContext(boost::tuple<Ptr<SpikeArrival>, Ptr<Synapse>> t, Ptr<Neuron>)
+ : DCtx<SpikeArrival, Synapse>(t.get<0>(), t.get<1>()) {}
+ };
+
+ /// EmitContent: CQ emits event of class DQ
+ template<typename CQ, typename DQ>
+ struct EmitContext : DCtx<DQ, CQ> {
+ EmitContext(Ptr<CQ> cid, Ptr<DQ> did)
+ : DCtx<DQ, CQ>(did, cid) {}
+ };
+}
+
+using ContextImpl::SingleContext;
+using ContextImpl::ContinuousContext;
+using ContextImpl::DelieverContext;
+using ContextImpl::EmitContext;
+
+#endif // sOuC39DJVwHiStoyuZdritpuC5M
diff --git a/core/continuous_property.hpp b/core/continuous_property.hpp
new file mode 100644
index 0000000..bed37cf
--- /dev/null
+++ b/core/continuous_property.hpp
@@ -0,0 +1,93 @@
+#ifndef H3OuNUuw3KK0wmZozXqMmrvzz3M
+#define H3OuNUuw3KK0wmZozXqMmrvzz3M
+
+#include <inttypes.h>
+#include <boost/mpl/bool.hpp>
+
+#include "context.hpp"
+#include "index_global.hpp"
+#include "index_spike.hpp"
+#include "index_spike_arrival.hpp"
+#include "pointers.hpp"
+#include "quant_types.hpp"
+#include "time.hpp"
+
+////////////////////////////////////////////////////////////////////////////////
+// event related actions
+////////////////////////////////////////////////////////////////////////////////
+
+// evolve in time - default case: value remains the same
+template<typename PropComp, typename Prop, typename Quant, typename Context>
+struct ContinuousProperty_Evolve {
+ static inline typename Prop::type eval
+ (PropComp &, Context context, Time t, Time dt);
+};
+
+// apply an incoming event - default case: do not send anything
+template<typename PropComp, typename Prop, typename Quant, typename EventQuant,
+ typename Context, typename IntentMap, typename Transaction>
+struct ContinuousProperty_Apply {
+ static inline void eval(PropComp &, Context, Time, IntentMap &, Transaction &) {}
+};
+
+// apply an incoming event: do we change the prop val at all?
+template<typename Prop, typename SrcQ>
+struct ContinuousProperty_ApplyChangesProp : boost::mpl::bool_<false> {};
+
+// generate an outgoing event - default case: generate nothing
+template<typename Prop, typename Quant, typename EventQuant>
+struct ContinuousProperty_Generate {
+ template<typename PropComp, typename Context, typename MQ, typename MI>
+ static inline void eval(PropComp &, Context, Time, typename Prop::type &,
+ MI &, MQ &) {}
+ static const bool changesValue = false;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// definition helpers
+////////////////////////////////////////////////////////////////////////////////
+
+#define GEN_CP(Quant, nameT, nameS, ValueType, InitialVal) \
+struct nameT { \
+ typedef ValueType type; \
+ typedef Quant quant; \
+ typedef Quant::instance_ptr_t instance_ptr_t; \
+ \
+ static const ValueType initialValue; \
+ static const uint32_t size = sizeof(ValueType); \
+ static const char* const name; \
+}; \
+ \
+const char* const nameT::name = nameS; \
+const ValueType nameT::initialValue{InitialVal};
+
+#define GEN_CPL_EVOLVE(nameT) \
+template<typename PropComp, typename Context> \
+struct ContinuousProperty_Evolve<PropComp, nameT, nameT::quant, Context> { \
+ inline static nameT::type eval(PropComp &pc, Context context, Time t, Time td)
+
+#define GEN_CP_EVOLVE(nameT, ReturnVal) \
+GEN_CPL_EVOLVE(nameT) { \
+ return ReturnVal; \
+ } \
+};
+
+#define GEN_CP_APPLY(Property, EventQuant, ChangeProp) \
+template<> \
+struct ContinuousProperty_ApplyChangesProp<Property, EventQuant> \
+ : boost::mpl::bool_<ChangeProp> {}; \
+ \
+template<typename PropComp, typename Quant, typename Context, typename IntentMap, typename Transaction> \
+struct ContinuousProperty_Apply<PropComp, Property, Quant, EventQuant, Context, IntentMap, Transaction> { \
+ typedef boost::mpl::bool_<ChangeProp> changeProp_t; \
+ static inline void eval(PropComp &pc, Context context, Time t, IntentMap &intent, Transaction &transaction)
+
+#define GEN_CP_GENERATE(CQ, DQ, Prop) \
+template<> \
+struct ContinuousProperty_Generate<Prop, CQ, DQ> { \
+ static const bool changesValue = true; \
+ template<typename PropComp, typename Context, typename MQ, typename MI> \
+ static inline void eval(PropComp &pc, Context context, Time t, \
+ Prop::type &value, MI &indices, MQ &queues)
+
+#endif // H3OuNUuw3KK0wmZozXqMmrvzz3M
diff --git a/core/continuous_property_impl.hpp b/core/continuous_property_impl.hpp
new file mode 100644
index 0000000..13695cf
--- /dev/null
+++ b/core/continuous_property_impl.hpp
@@ -0,0 +1,13 @@
+#ifndef LEt1PyaObN7YkjcGFenqweegIyk
+#define LEt1PyaObN7YkjcGFenqweegIyk
+
+#include "property_access.hpp"
+
+template<typename PropComp, typename Prop, typename Quant, typename Context>
+inline typename Prop::type
+ContinuousProperty_Evolve<PropComp, Prop, Quant, Context>
+::eval(PropComp &pc, Context context, Time t, Time dt) {
+ return Property_Get<Prop>::eval(pc, context, t);
+}
+
+#endif // LEt1PyaObN7YkjcGFenqweegIyk
diff --git a/core/convert_topology.cpp b/core/convert_topology.cpp
new file mode 100644
index 0000000..e348c80
--- /dev/null
+++ b/core/convert_topology.cpp
@@ -0,0 +1,161 @@
+/* format
+ "src dst delay weight\n"
+ multiple src dst combinations are possible (?)
+ */
+#include <string.h>
+#include <iostream>
+#include <map>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/mpl/pair.hpp>
+#include <boost/mpl/list.hpp>
+
+#include "pla_set.hpp"
+#include "pointers.hpp"
+#include "property_composition.hpp"
+#include "simlimits.hpp"
+#include "time.hpp"
+#include "topology.hpp"
+
+#include "model.hpp"
+
+#include "mempool.hpp"
+
+using namespace std;
+
+typedef Ptr<Neuron>::ptr_t np_t;
+typedef Ptr<Synapse>::ptr_t sp_t;
+typedef Ptr<Synapse>::offset_t op_t;
+
+struct Connection {
+ np_t src, dst;
+ Weight::type weight;
+ Time::type delay;
+};
+
+map<np_t, multimap<Time, Connection>*> cons;
+
+PropertyComposition<boost::mpl::list<
+ boost::mpl::pair<Weight, boost::mpl::bool_<true>>,
+ boost::mpl::pair<TargetSumWeight, boost::mpl::bool_<true>>,
+ boost::mpl::pair<SumWeight, boost::mpl::bool_<true>>
+>> pc;
+
+
+void init() {
+ // check that pc time is 0.0
+ assert(pc.properties.data.data.timeLimit == 0.0);
+ for (np_t i=0; i<maxNeurons; i++)
+ cons[i] = new multimap<Time, Connection>();
+}
+
+void read() {
+ cin >> skipws;
+ while (!cin.eof()) {
+ Connection c;
+
+ // read from stream
+ cin >> c.src >> c.dst >> c.delay >> c.weight;
+ assert(!cin.fail());
+ cin >> ws;
+
+ // first sanity check
+ assert(c.src < maxNeurons);
+ assert(c.dst < maxNeurons);
+ assert(c.delay > 0.0);
+ assert(c.weight != 0.0);
+
+ // store (to sort)
+ cons[c.src]->insert(make_pair(c.delay, c));
+ }
+}
+
+void addPseudo() {
+ const Ptr<Neuron>::ptr_t half = maxNeurons/2;
+ assert(numActualNeurons <= half);
+ for (Ptr<Neuron>::ptr_t i=0; i<half; i++) {
+ Connection c;
+ c.src = i + half;
+ c.dst = i;
+ c.delay = Time::epsilon()();
+ c.weight = ModelConsts::TrainerInput;
+ cons[c.src]->insert(make_pair(c.delay, c));
+ }
+}
+
+void setWeight(const sp_t synapse, Weight::type weight) {
+ PLA_Set<Weight> pla{Time{0}, Ptr<Synapse>{synapse}, weight};
+ pc.call(pla);
+}
+
+void writeTopology() {
+ // fill topology tables
+ Array<Time, maxNeurons * maxSynapsesPerNeuron> &delay
+ = *(new Array<Time, maxNeurons * maxSynapsesPerNeuron>());
+ Array<Ptr<Synapse>::ptr_t, maxNeurons * maxSynapsesPerNeuron> &target
+ = *(new Array<Ptr<Synapse>::ptr_t, maxNeurons * maxSynapsesPerNeuron>());
+
+ op_t currentSynapse[maxNeurons];
+ memset(currentSynapse, 0, sizeof(currentSynapse));
+
+ for (np_t i=0; i<maxNeurons; i++) {
+ op_t j=0;
+ multimap<Time, Connection> &l = *(cons[i]);
+ assert(l.size() < maxSynapsesPerNeuron); // last synapse required for nil
+
+ for (multimap<Time, Connection>::iterator k = l.begin(); k != l.end(); k++) {
+ sp_t t = i * maxSynapsesPerNeuron + j;
+ Connection &c = (*k).second;
+ Time::type dt = c.delay;
+ sp_t s = c.dst * maxSynapsesPerNeuron + currentSynapse[c.dst]++;
+
+ delay.set (t, dt);
+ target.set(t, s);
+ setWeight(s, c.weight);
+ j++;
+ }
+
+ // fill unused synapses
+ for (; j<maxSynapsesPerNeuron; j++) {
+ sp_t t = i * maxSynapsesPerNeuron + j;
+ target.set(t, Topology::nil()());
+ delay.set(t, Time(-666)); // HINT: this should raise an decreasing time error
+ }
+ }
+
+ // write topology via special ctor
+ { Topology(delay, target); }
+
+ // init unused synapse weight to inf to provoke errors
+ for (np_t i=0; i<maxNeurons; i++) {
+ while (currentSynapse[i] < maxSynapsesPerNeuron) {
+ setWeight(i * maxSynapsesPerNeuron + currentSynapse[i],
+ std::numeric_limits<Weight::type>::infinity());
+ currentSynapse[i]++;
+ }
+ }
+}
+
+void writeWeightSums() {
+ Topology t;
+ PropertyInstance<Weight, true> weights;
+ for (auto neuron : Ptr<Global>().childs()) {
+ SumWeight::type weightSum = 0;
+ for (auto synapse : neuron.childs()) {
+ Weight::type weight = weights.data.getValue(Time{0}, synapse());
+ if (weight > 0 and weight < std::numeric_limits<Weight::type>::infinity())
+ weightSum += weight;
+ }
+ PLA_Set<TargetSumWeight> s1{Time{0}, neuron, weightSum};
+ PLA_Set<SumWeight> s2{Time{0}, neuron, weightSum};
+ pc.call(s1); pc.call(s2);
+ }
+}
+
+int main() {
+ init();
+ read();
+ addPseudo();
+ writeTopology();
+ writeWeightSums();
+}
diff --git a/core/discrete_property.hpp b/core/discrete_property.hpp
new file mode 100644
index 0000000..741049f
--- /dev/null
+++ b/core/discrete_property.hpp
@@ -0,0 +1,39 @@
+#ifndef iNnFGNqFLlBaWFgGGH0sLM3mh40
+#define iNnFGNqFLlBaWFgGGH0sLM3mh40
+
+#include "pointers.hpp"
+#include "string_helpers.hpp"
+#include "template_helpers.hpp"
+
+/// Macros
+
+#define GEN_DP(Quant, nameT, nameS, ValueType) \
+struct nameT { \
+ typedef ValueType type; \
+ typedef Quant quant; \
+ typedef Quant::instance_ptr_t instance_ptr_t; \
+ static const uint32_t size = sizeof(ValueType); \
+ static const char* const name; \
+}; \
+ \
+const char* const nameT::name = nameS;
+
+#define GEN_DP_DELAY(DQuant, CQuant, Rule) \
+template<> \
+struct DiscreteProperty_ComputeDelay<DQuant, CQuant> { \
+ template<typename PC, typename Context, typename Transaction> \
+ inline static Time eval(PC &pc, Context context, \
+ Transaction transaction, Time t) { \
+ return Rule; \
+ } \
+};
+
+/// default impls
+
+template<typename DQuant, typename CQuant>
+struct DiscreteProperty_ComputeDelay {
+ template<typename PC, typename Context, typename Transaction>
+ inline static Time eval(PC &, Context, Transaction, Time) DO_NOT_CALL
+};
+
+#endif // iNnFGNqFLlBaWFgGGH0sLM3mh40
diff --git a/core/ephermal_checkpoint.hpp b/core/ephermal_checkpoint.hpp
new file mode 100644
index 0000000..1ca59e4
--- /dev/null
+++ b/core/ephermal_checkpoint.hpp
@@ -0,0 +1,83 @@
+// like Checkpoint, but memory-backed instead of file-backed and only
+// storing the last time/value-paiir -> NO ACTUAL CHECKPOINTS
+#ifndef kR1Z42gIzRShmbO3sKvSk0HIEo
+#define kR1Z42gIzRShmbO3sKvSk0HIEo
+
+#include <boost/static_assert.hpp>
+
+#include "array.hpp"
+#include "string_helpers.hpp"
+#include "simlimits.hpp"
+#include "template_helpers.hpp"
+#include "time.hpp"
+
+template<typename T, uint32_t size>
+class EphermalCheckpoint {
+public:
+ typedef uint32_t ptr_t;
+
+ EphermalCheckpoint(string name, const T initialValue);
+
+ // read access
+ inline Time getTime (const Time t, const ptr_t i);
+ inline T getValue(const Time t, const ptr_t i);
+ inline Time getTime (const Time t); // only with size == 1
+ inline T getValue(const Time t); // only with size == 1
+
+ // write access
+ inline void set(const Time t, const ptr_t i, const T val);
+ inline void set(const Time t, const T val); // only with size == 1
+
+ void sync() const {};
+
+ // memory backed data; they store for each element the ...
+ Array<T, size> content; // ... last known content
+ Array<Time, size> times; // ... associated time
+
+private:
+ EphermalCheckpoint();
+};
+
+template<typename T, uint32_t size>
+inline void EphermalCheckpoint<T, size>::set(const Time t, const ptr_t i, const T val) {
+ times.set(i, t);
+ content.set(i, val);
+}
+
+template<typename T, uint32_t size>
+inline void EphermalCheckpoint<T, size>::set(const Time t, const T val) {
+ BOOST_STATIC_ASSERT(size == 1);
+ setValue(t, 0, val);
+}
+
+template<typename T, uint32_t size>
+inline Time EphermalCheckpoint<T, size>::getTime(const Time t, const ptr_t i) {
+ return times.get(i);
+}
+
+template<typename T, uint32_t size>
+inline Time EphermalCheckpoint<T, size>::getTime(const Time t) {
+ BOOST_STATIC_ASSERT(size == 1);
+ return getTime(t, 0);
+}
+
+template<typename T, uint32_t size>
+inline T EphermalCheckpoint<T, size>::getValue(const Time t, const ptr_t i) {
+ return content.get(i);
+}
+
+template<typename T, uint32_t size>
+inline T EphermalCheckpoint<T, size>::getValue(const Time t) {
+ BOOST_STATIC_ASSERT(size == 1);
+ return getValue(t, 0);
+}
+
+template<typename T, uint32_t size>
+EphermalCheckpoint<T, size>::EphermalCheckpoint(string name, const T initialValue) {
+ for (ptr_t i=0; i<size; i++) {
+ content.set(i, initialValue);
+ times.set(i, 0);
+ }
+}
+
+#endif // kR1Z42gIzRShmbO3sKvSk0HIEo
diff --git a/core/event.hpp b/core/event.hpp
new file mode 100644
index 0000000..0044c15
--- /dev/null
+++ b/core/event.hpp
@@ -0,0 +1,107 @@
+#ifndef lolpAJAYZev7fEXugmdiNlqUhWA
+#define lolpAJAYZev7fEXugmdiNlqUhWA
+
+#include <boost/tuple/tuple.hpp>
+
+#include "pointers.hpp"
+#include "index_global.hpp"
+#include "index_spike.hpp"
+#include "template_helpers.hpp"
+#include "topology.hpp"
+
+template<typename UnknownType>
+struct Event {
+ DO_NOT_INSTANCE(UnknownType);
+};
+
+template<>
+struct Event<GlobalMsg> {
+ typedef GlobalMsg quant_t;
+ typedef Ptr<GlobalMsg> msg_ptr_t;
+ typedef Ptr<Global> ptr_t;
+
+ // regular ctors
+ Event(msg_ptr_t inst) : inst(inst) {}
+ Event(Time ignored1, ptr_t ignored2, msg_ptr_t inst) : inst(inst) {}
+
+ // ctor for illegal event sources
+ GEN_ANYCAST_CTOR_3(Event) : inst(0) { DO_NOT_CALL }
+
+ inline ptr_t dst(Topology &ignored) { return ptr_t(); }
+ inline msg_ptr_t instance() { return inst; }
+
+ msg_ptr_t inst;
+};
+
+template<>
+struct Event<RandomSpike> {
+ typedef RandomSpike quant_t;
+ typedef Ptr<RandomSpike> msg_ptr_t;
+ typedef Ptr<Neuron> ptr_t;
+
+ Event(Time, ptr_t neuron, msg_ptr_t inst) : neuron(neuron), inst(inst) {}
+ GEN_ANYCAST_CTOR_3(Event) : neuron(0), inst(0) { DO_NOT_CALL }
+
+ inline ptr_t dst(Topology &) { return neuron; }
+ inline msg_ptr_t instance() { return inst; }
+
+ ptr_t neuron;
+ msg_ptr_t inst;
+};
+
+template<>
+struct Event<Spike> {
+ typedef Spike quant_t;
+ typedef Ptr<Neuron> neuron_ptr_t;
+ typedef Ptr<Spike> spike_ptr_t;
+ typedef uint16_t offset_t;
+
+ // legal ctors
+ Event(Time baseTime, neuron_ptr_t src, spike_ptr_t spike)
+ : baseTime(baseTime),
+ src(src),
+ offset(0),
+ spike(spike)
+ {}
+ Event(Time baseTime, neuron_ptr_t src, spike_ptr_t spike, offset_t offset)
+ : baseTime(baseTime),
+ src(src),
+ offset(offset),
+ spike(spike)
+ {}
+
+ // ctor for illegal event sources
+ GEN_ANYCAST_CTOR_3(Event) : baseTime(0),src(0),offset(0),spike(0) { DO_NOT_CALL }
+ // Event(Time baseTime, neuron_ptr_t src, uint16_t offset)
+ // : baseTime(baseTime), src(src), offset(offset) {}
+
+ inline Ptr<Synapse> dst(Topology &topology) {
+ return topology.synapse(src, offset);
+ }
+ inline spike_ptr_t instance() { return spike; }
+
+ Time baseTime; // time of outgoing spike; add topology.time(src,
+ // offset) to get spike arrival time
+ neuron_ptr_t src;
+ offset_t offset; // HINT: offset in topolgy, _not_ a synapse offset!
+ spike_ptr_t spike;
+};
+
+template<>
+struct Event<SpikeArrival> {
+ typedef SpikeArrival quant_t;
+
+ Event(Ptr<Synapse> dst, Ptr<SpikeArrival> sa)
+ : sdst(dst), sa(sa) {}
+ inline Ptr<Neuron> dst(Topology &ignored) { return dst(); }
+ inline Ptr<Neuron> dst() { return sdst.extractNeuron(); }
+ // HACK for DelieverContext ... what a shame
+ inline boost::tuple<Ptr<SpikeArrival>, Ptr<Synapse>> instance() {
+ return boost::make_tuple(sa, sdst);
+ }
+
+ Ptr<Synapse> sdst;
+ Ptr<SpikeArrival> sa;
+};
+
+#endif // lolpAJAYZev7fEXugmdiNlqUhWA
diff --git a/core/everything_else.hpp b/core/everything_else.hpp
new file mode 100644
index 0000000..8b18cd5
--- /dev/null
+++ b/core/everything_else.hpp
@@ -0,0 +1,14 @@
+#ifndef oaRGw4aWx0YufhAmmpm1h6BILQU
+#define oaRGw4aWx0YufhAmmpm1h6BILQU
+
+#include <assert.h>
+#include <unistd.h>
+
+void assertSimDir() {
+ assert(access("topology_initialized", F_OK) == 0);
+}
+
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+#endif // oaRGw4aWx0YufhAmmpm1h6BILQU
diff --git a/core/evolve.hpp b/core/evolve.hpp
new file mode 100644
index 0000000..628c170
--- /dev/null
+++ b/core/evolve.hpp
@@ -0,0 +1,35 @@
+#ifndef X66AJaG3Qy6m9CIBTEKhiCYWag0
+#define X66AJaG3Qy6m9CIBTEKhiCYWag0
+
+#include "pla_evolve.hpp"
+
+
+
+namespace EvolveImpl {
+
+ template<typename Quant>
+ struct Evolve {
+ template<class PC>
+ void operator() (PC &pc, const Time ct, const Ptr<Quant> id) {
+ typedef typename QuantChild<Quant>::type Child;
+ // first evolve childs
+ for (Ptr<Child> i : id.childs())
+ Evolve<Child>()(pc, ct, i);
+ // then self
+ pc.cast(PLA_Evolve<Quant>{ContinuousContext<Quant>{id}, ct});
+ }
+ };
+
+ template<>
+ struct Evolve<Synapse> {
+ template<class PC>
+ void operator() (PC &pc, const Time ct, const Ptr<Synapse> id) {
+ // no childs -> evolve only self
+ pc.cast(PLA_Evolve<Synapse>{ContinuousContext<Synapse>{id}, ct});
+ }
+ };
+}
+
+using EvolveImpl::Evolve;
+
+#endif // X66AJaG3Qy6m9CIBTEKhiCYWag0
diff --git a/core/filter.hpp b/core/filter.hpp
new file mode 100644
index 0000000..89ebbf6
--- /dev/null
+++ b/core/filter.hpp
@@ -0,0 +1,379 @@
+#ifndef YFUuCq9eKDuTmNenHAFfkJG3V
+#define YFUuCq9eKDuTmNenHAFfkJG3V
+
+/* a Filter is used soley within MultiQueue. It has to have the same
+ interface as a Heap<PriorityQueue>. MultiQueue uses Heap, as well
+ as PriorityQueue features. To simulate this, a filter overloads
+ operator(Time) to return itself and implements all required methods
+ of Heap and PriorityQueue in one class */
+
+#include <queue>
+#include <map>
+#include <set>
+#include <list>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/tuple/tuple.hpp>
+//#include <boost/tuple/tuple_comparison.hpp>
+
+#include "index_global.hpp"
+#include "index_spike.hpp"
+#include "index_randomspike.hpp"
+#include "index_spike_arrival.hpp"
+#include "time.hpp"
+#include "topology.hpp"
+#include "id_list.hpp"
+
+#include "model.hpp" // for QuantDestinationQuant
+
+namespace FilterImpl {
+
+using namespace boost;
+
+// "forward decl" to make iter comparable
+typedef Ptr<Synapse>::offset_t FSA_offset_t;
+typedef std::list<tuple<Time, // 0. delay
+ Ptr<Synapse>, // 1. dst
+ FSA_offset_t // 2. offset in topo table
+ >> FSA_Recv_List;
+typedef std::map<Ptr<Neuron>, FSA_Recv_List> FSA_recv_t;
+
+// an operator only to be used for std::priority_queue, which returns
+// the largest element, not the smallest
+template<typename T>
+struct queue_greater_equal {
+ bool operator() (const T &a, const T &b) {
+ return a.get<0>() > b.get<0>()
+ || (a.get<0>() == b.get<0>()
+ && queue_greater_equal<typename T::tail_type>()(a.get_tail(),
+ b.get_tail()));
+ }
+};
+
+#define MKCMP(T) \
+ template<> \
+ struct queue_greater_equal<T> { \
+ bool operator() (const T&, const T&) { \
+ return true; \
+ } \
+ }
+MKCMP(tuples::null_type);
+MKCMP(FSA_recv_t::mapped_type::iterator);
+typedef boost::tuples::cons<std::_List_iterator<boost::tuples::tuple<Time, Ptr<Synapse>, unsigned char> >, boost::tuples::null_type> ttttt;
+MKCMP(ttttt);
+#undef MKCMP
+
+template<typename Quant> struct Filter;
+
+template<
+ typename Quant,
+ typename QueuePayload,
+ typename Queue = std::priority_queue<QueuePayload,
+ std::vector<QueuePayload>,
+ queue_greater_equal<QueuePayload>>>
+struct CommonFilter {
+ typedef QueuePayload queue_payload_t;
+ typedef Queue queue_t;
+ typedef IdList<Ptr<Neuron>::ptr_t> id_list_t;
+
+ explicit CommonFilter(id_list_t &ids, const Time time)
+ : currentTime(time),
+ ids(ids),
+ queue(),
+ index()
+ {}
+
+ Filter<Quant> & operator() (Time t) {
+ // helper function to emulate Heap<PriorityQueue> behaviour
+ assert(t >= currentTime);
+ currentTime = t;
+ return *static_cast<Filter<Quant>*>(this);
+ }
+
+ Time minVal() const {
+ assert(!isEmpty());
+ return queue.top().get<0>(); // by convention first element of
+ // QueuePayload is Time
+ }
+
+ bool isEmpty() const {
+ return queue.empty();
+ }
+
+ Time currentTime;
+ id_list_t &ids;
+ Queue queue;
+ Index<Quant> index;
+
+ struct Payload {
+ Payload() : src(0), dst(0) {} // fake init
+
+ Ptr<Quant> src;
+ Ptr<typename QuantDestinationQuant<Quant>::type> dst;
+ } payload;
+
+ const Payload & minPayload() const {
+ return payload;
+ }
+
+};
+
+template<>
+struct Filter<GlobalMsg>
+ : CommonFilter<GlobalMsg,
+ tuple<Time, Ptr<GlobalMsg>::ptr_t>>
+{
+ Filter(Time time)
+ : CommonFilter(id_list, time),
+ cur(0), // later
+ last(index.last())
+ {
+ // late init of CommonFilter
+ payload.dst = Ptr<Global>();
+
+ // look for first relevant checkpoint
+ Time tMin(std::min(currentTime, index.maxEventTime.timeLimit));
+ for (; tMin > 0 && index.maxEventTime.getTime(tMin) >= currentTime;
+ tMin -= index.maxEventTime.interval());
+ cur = Ptr<GlobalMsg>(index.first(tMin));
+
+ // init queue
+ if (cur() != index.nil())
+ refillQueue();
+ }
+
+ void removeMin() {
+ assert(currentTime >= minVal()); // assure currentTime is updated
+ queue.pop();
+ refillQueue();
+ if (!isEmpty())
+ payload.src = Ptr<GlobalMsg>(queue.top().get<1>());
+ }
+
+ void refillQueue() {
+ // add all events until the next event to be inserted is created
+ // after the queues min event arrives, but at least until currentTime
+ Time until = queue.empty() ? currentTime : minVal();
+ for (; cur() <= last() && index.time(cur()) <= until; ++cur) {
+ // discard messages for the past
+ if (index.eventTime(cur()) >= currentTime) {
+ queue.push(queue_payload_t(index.eventTime(cur()), cur()));
+ until = minVal();
+ }
+ }
+ // add at most one message iff. required to make progress
+ if (queue.empty() && cur() <= last() && index.time(cur()) > until) {
+ queue.push(queue_payload_t(index.eventTime(cur()), cur()));
+ ++cur;
+ }
+ }
+
+ Ptr<GlobalMsg> cur, last;
+ static id_list_t id_list;
+};
+Filter<GlobalMsg>::id_list_t Filter<GlobalMsg>::id_list((char*) "0");
+
+template<>
+struct Filter<RandomSpike>
+ : CommonFilter<RandomSpike,
+ tuple<Time, Ptr<RandomSpike>::ptr_t>> {
+ Filter(id_list_t &ids, const Time time)
+ : CommonFilter(ids, time)
+ {
+ // find first spike for each given neuron, following spikes are
+ // simple (using index.next)
+ for (auto neuron : ids) {
+ // find first event via first relevent checkpoints
+ Time tMin(std::min(currentTime, index.maxEventTime.timeLimit));
+ for (; tMin > 0 && index.maxEventTime.getTime(tMin, neuron) >= currentTime;
+ tMin -= index.maxEventTime.interval());
+ auto next = Ptr<RandomSpike>(index.first(tMin, Ptr<Neuron>(neuron)))();
+ // skip events before ct
+ while (next != index.nil() && index.time(next) < currentTime)
+ next = index.next(next);
+ // add event (if)
+ if (next != index.nil())
+ queue.push(queue_payload_t(index.eventTime(next), next));
+ }
+ updatePayload();
+ }
+
+ void removeMin() {
+ assert(!isEmpty());
+ queue.pop();
+ auto next = index.next(payload.src());
+ if (next != index.nil())
+ queue.push(queue_payload_t(index.eventTime(next), next));
+ updatePayload();
+ }
+
+ void updatePayload() {
+ if (!isEmpty()) {
+ payload.src = Ptr<RandomSpike>(queue.top().get<1>());
+ payload.dst = Ptr<Neuron>(index.src(payload.src()));
+ }
+ }
+
+};
+
+template<>
+struct Filter<SpikeArrival>
+ : CommonFilter<SpikeArrival,
+ boost::tuple<Time, Ptr<Spike>, FSA_recv_t::mapped_type::iterator>> {
+ typedef FSA_offset_t offset_t;
+
+ Filter(id_list_t &ids, const Time time)
+ : CommonFilter(ids, time) {
+ // extract topology info
+ Topology topo;
+ std::set<Ptr<Neuron>> used;
+ std::map<Ptr<Neuron>, Time> maxDelay;
+ for (auto neuron : Ptr<Neuron>::all()) {
+ for (offset_t off(0); off < maxSynapsesPerNeuron; off++) {
+ Ptr<Synapse> syn(topo.synapse(neuron, off));
+ if (syn == topo.nil()) break;
+ if (ids.count(syn.extractNeuron()())) {
+ Time delay = topo.time(neuron, off);
+ recv[neuron].push_back(make_tuple(delay, syn, off));
+ maxDelay[neuron] = std::max(delay, maxDelay[neuron]);
+ used.insert(neuron);
+ }
+ }
+ }
+
+ // insert pending spikes
+ for (auto neuron : used) {
+ Ptr<Spike> spike(index.first(std::min(currentTime - maxDelay[neuron],
+ index.prevCache.timeLimit),
+ neuron));
+ if (spike() != index.nil()) {
+ Time baseTime = index.time(spike());
+ queue.push(queue_payload_t(baseTime + recv[neuron].front().get<0>(),
+ spike,
+ recv[neuron].begin()));
+ }
+ }
+ updatePayload();
+
+ // remove all arrivals of spikes prior to time
+ while (!isEmpty() && minVal() < time)
+ removeMin();
+ }
+
+ void updatePayload() {
+ if (!isEmpty()) {
+ const queue_payload_t &top(queue.top());
+ const auto &recvElem(*(top.get<2>()));
+ payload.dst = recvElem.get<1>().extractNeuron();
+ payload.src.get<0>() = Ptr<SpikeArrival>(top.get<1>(), recvElem.get<2>());
+ payload.src.get<1>() = recvElem.get<1>();
+ }
+ }
+
+ void removeMin() {
+ assert(!isEmpty());
+ // reinsert next spike from current min (if it exists)
+ const queue_payload_t top = queue.top(); // copy, to allow popping early
+ Ptr<Neuron> neuron(index.src(top.get<1>()()));
+ FSA_Recv_List &recvList = recv[neuron];
+ auto re_iter = top.get<2>();
+
+ // remove old element
+ queue.pop();
+
+ // was this the first element in the rev list?
+ if (re_iter == recvList.begin()) {
+ // insert next spike from same neuron
+ Ptr<Spike> next(index.next(top.get<1>()()));
+ if (next() != index.nil()) {
+ auto re_iter(recvList.begin());
+ queue_payload_t payload(index.time(next()) + re_iter->get<0>(),
+ next,
+ re_iter);
+ queue.push(payload);
+ }
+ }
+
+ // is there a next element in the recv list?
+ if (++re_iter != recvList.end()) {
+ // add SA of remaining list
+ Time baseTime = index.time(top.get<1>()());
+ queue_payload_t payload(baseTime + re_iter->get<0>(),
+ top.get<1>(),
+ re_iter);
+ queue.push(payload);
+ }
+
+ // update payload from new min
+ updatePayload();
+ }
+
+ FSA_recv_t recv;
+ Index<Spike> index;
+
+ struct Payload {
+ Payload() : src(Ptr<SpikeArrival>(0), Ptr<Synapse>(0)), dst(0) {} // fake init
+
+ boost::tuple<Ptr<SpikeArrival>, Ptr<Synapse> > src;
+ Ptr<Neuron> dst;
+ } payload;
+
+ Payload & minPayload() {
+ return payload;
+ }
+};
+
+template<>
+struct Filter<Spike> : Filter<SpikeArrival> {
+ typedef Ptr<Synapse>::offset_t offset_t;
+
+ Filter(id_list_t &res, const Time time)
+ : Filter<SpikeArrival>(res, time) {
+ updatePayload();
+ }
+
+ void removeMin() {
+ Filter<SpikeArrival>::removeMin();
+ updatePayload();
+ }
+
+ void updatePayload() {
+ // we copy from parent unconditionally, assuming valid values
+ // remain in payload even when queue is empty
+ payload.src = Filter<SpikeArrival>::payload.src.get<0>().extractSpike();
+ payload.dst = Filter<SpikeArrival>::payload.src.get<1>();
+ }
+
+ Filter<Spike> & operator() (Time t) {
+ // helper function to emulate Heap<PriorityQueue> behaviour
+ if (t >= currentTime)
+ assert(t >= currentTime);
+ currentTime = t;
+ return *this;
+ }
+
+ typedef CommonFilter<Spike, int>::Payload Payload; // ignore "int"
+ Payload payload;
+
+ Payload & minPayload() {
+ return payload;
+ }
+};
+
+} // namespace FilterImpl
+
+using FilterImpl::Filter;
+
+/// arguments for MultiQueue
+
+template<typename Quant>
+struct FilterPayload : Filter<Quant>::Payload {
+ typedef Quant quant_type;
+};
+
+template<typename Val, typename Payload>
+struct FilterContainer {
+ BOOST_STATIC_ASSERT((boost::is_same<Val, Time>::value));
+ typedef Filter<typename Payload::quant_type> type;
+};
+
+#endif // YFUuCq9eKDuTmNenHAFfkJG3V
diff --git a/core/heap.hpp b/core/heap.hpp
new file mode 100644
index 0000000..40c0a55
--- /dev/null
+++ b/core/heap.hpp
@@ -0,0 +1,157 @@
+#ifndef lxZLmAQ0qUwCFC9Ehehzy92Ldko
+#define lxZLmAQ0qUwCFC9Ehehzy92Ldko
+
+/* warn: heap is sloppy with the write barrier of it's content
+ mmap()ed data store; the stated barrier is always equal or less
+ than the actually used amount of space; it is only correct after
+ sync() calls (which happen implicitely at interval turnover */
+
+#include <inttypes.h>
+#include <boost/tuple/tuple.hpp>
+
+#include "checkpoint.hpp"
+#include "everything_else.hpp"
+#include "scalar.hpp"
+#include "string_helpers.hpp"
+#include "time.hpp"
+#include "vector.hpp"
+
+template<typename Payload>
+struct Heap {
+ // constructor requires a 3-tuple:
+ // 1. name (used for file name creation)
+ // 2. average size of contained object
+ // 3. default payload value (if a new heap is created)
+ Heap(const string name, const uint64_t avgLength);
+ Heap();
+
+ // read & write access
+ inline Payload & operator() (Time t) __attribute__ ((pure));
+ void sync();
+
+ // intern methods
+ void addCheckpoints(Time t);
+
+ // intern data
+ typedef Vector<char>::ptr_t ptr_t;
+ ptr_t interval; // current interval (number)
+ Time timeLimit; // current intervals time limit (inclusive)
+ Time currentTime; // current intervals time (same as times(interval)
+ // but allows compiler to perform better
+ // optimizations)
+
+
+ // file backings
+ Vector<Time> times; // times of the payload
+ Vector<char> content; // the payloads (in temporally ascending order)
+ Vector<ptr_t> index;
+
+private:
+ inline Payload & get(ptr_t id) __attribute__ ((pure));
+ void init();
+};
+
+template<typename Payload>
+Heap<Payload>::Heap(const string name, const uint64_t avgLength) :
+ times( "heap_times_" + name, maxCheckpoints),
+ content("heap_content_" + name, maxCheckpoints * avgLength),
+ index( "heap_index_" + name, maxCheckpoints)
+{
+ init();
+}
+
+template<typename Payload>
+Heap<Payload>::Heap() :
+ times( "heap_times_" + std::string(Payload::payload_t::quant_t::name),
+ maxCheckpoints),
+ content("heap_content_" + std::string(Payload::payload_t::quant_t::name),
+ maxCheckpoints * AverageQueueSize<typename Payload::payload_t::quant_t>::value * Payload::elementSize),
+ index( "heap_index_" + std::string(Payload::payload_t::quant_t::name),
+ maxCheckpoints)
+{
+ init();
+}
+
+template<typename Payload>
+void Heap<Payload>::init() {
+ // do we create the heap (and backing files)?
+ if (index.barrierWrite() == 0) {
+ // yes -> extra initialisation
+ interval = 0;
+ timeLimit = 0;
+ currentTime = 0;
+ times(0) = 0;
+ times.barrierWrite() = 1;
+ // new(&(content(0))) Payload(boost::get<2>(arg)); // init with given arg
+ new(&(content(0))) Payload(); // init with empty ctor
+ content.barrierWrite() = get(0).getSize();
+ index(0) = 0;
+ index.barrierWrite() = 1;
+ }else{
+ // no -> restore previous setup
+ interval = index.barrierWrite() - 1;
+ timeLimit = Time(checkpointInterval) * interval; // hint interval #0 ends with time 0
+ currentTime = times(interval);
+ }
+}
+
+
+template<typename Payload>
+inline Payload& Heap<Payload>::operator() (Time t) {
+ if (t > currentTime) {
+ if (unlikely(t > timeLimit)) addCheckpoints(t);
+ currentTime = t;
+ times(interval) = t;
+ }
+ return get(interval);
+}
+
+template<typename Payload>
+void Heap<Payload>::sync() {
+ // update length of the current heap
+ // WARN: for synchronization these values actually should never
+ // shrink, but the embedded container might violate this
+ content.barrierWrite() = index(interval) + get(interval).getSize();
+
+ // sync all mmap containers
+ content.sync();
+ times.sync();
+ index.sync();
+}
+
+// see checkpoint.hpp for a more commented analogon of this method
+template<typename Payload>
+void Heap<Payload>::addCheckpoints(Time t) {
+ assert(index.barrierWrite() == times.barrierWrite()); // is a pre- and postcondition
+
+ while (t > timeLimit) {
+ content.barrierWrite() = index(interval) + get(interval).getSize(); // update current payload size
+ interval++;
+ index(interval) = content.barrierWrite();
+ times(interval) = times(interval - 1);
+
+ // invoke copy constructor via placement new to copy the payload
+ new(&get(interval)) Payload(get(interval-1));
+
+ index.barrierWrite()++;
+ times.barrierWrite()++;
+ times.barrierRead() = times.barrierWrite() - 1;
+ index.barrierRead() = index.barrierWrite() - 1;
+ content.barrierRead() = content.barrierWrite();
+
+ timeLimit = checkpointInterval * interval;
+ }
+
+ currentTime = t;
+ times(interval) = t;
+
+ assert(index.barrierWrite() == times.barrierWrite());
+
+ content.advise(0, content.barrierRead(), MADV_DONTNEED);
+}
+
+template<typename Payload>
+inline Payload& Heap<Payload>::get (ptr_t id) {
+ return *((Payload*) (&(content(index(id)))));
+}
+#endif // lxZLmAQ0qUwCFC9Ehehzy92Ldko
diff --git a/core/id_list.hpp b/core/id_list.hpp
new file mode 100644
index 0000000..99ff5a2
--- /dev/null
+++ b/core/id_list.hpp
@@ -0,0 +1,47 @@
+#ifndef iUCKfY0lAetXcXu8Ykh6wMB3KhQ
+#define iUCKfY0lAetXcXu8Ykh6wMB3KhQ
+
+#include <set>
+
+#include <boost/xpressive/xpressive_static.hpp>
+#include <boost/xpressive/regex_actions.hpp>
+
+namespace IdListImpl {
+
+using namespace boost::xpressive;
+
+struct push_impl {
+ typedef void result_type;
+ template<typename Set, class Value>
+ void operator()(Set &s, Value const &from, Value const &until) const {
+ for (Value i = from; i <= until; ++i)
+ s.insert(i);
+ }
+};
+function<push_impl>::type const pushRange = {{}};
+
+
+template<typename ID>
+struct IdList : std::set<ID> {
+ explicit IdList(char *s = (char*) "") {
+ cregex number = (s1= +_d)
+ [insert(boost::xpressive::ref(*this), as<ID>(s1))];
+ cregex range = ((s1= +_d) >> as_xpr('-') >> (s2= +_d))
+ [pushRange(boost::xpressive::ref(*this), as<ID>(s1), as<ID>(s2))];
+ cregex list = *((range | number) >> *( as_xpr(',') >> (range | number)));
+ assert(regex_match(s, list));
+ }
+
+ template<typename OtherID>
+ IdList(IdList<OtherID> &src) {
+ for (auto i : src) {
+ assert(i <= std::numeric_limits<ID>::max());
+ this->insert(i);
+ }
+ }
+};
+
+} // IdListImpl
+
+using IdListImpl::IdList;
+#endif // iUCKfY0lAetXcXu8Ykh6wMB3KhQ
diff --git a/core/index.hpp b/core/index.hpp
new file mode 100644
index 0000000..d110586
--- /dev/null
+++ b/core/index.hpp
@@ -0,0 +1,148 @@
+#ifndef hVYFXl0fhRtHkuIHnrxmZOhDCeI
+#define hVYFXl0fhRtHkuIHnrxmZOhDCeI
+
+#include <assert.h>
+
+#include <string>
+
+#include "time.hpp"
+#include "checkpoint.hpp"
+#include "simlimits.hpp"
+#include "template_helpers.hpp"
+#include "vector.hpp"
+
+// TODO: update r/w-barriers in vector
+
+using std::string;
+
+template<typename Quant>
+struct Index;
+
+template<typename Ptr>
+struct CommonIndex {
+ CommonIndex() = delete;
+ CommonIndex(const string name, Ptr max);
+
+ // type and const defs
+ typedef Ptr ptr_t;
+ static constexpr ptr_t nil() {
+ BOOST_STATIC_ASSERT(( (ptr_t) -1 > 0 ));
+ return -1;
+ }
+
+ // read operations
+ // HINT: time refers to creation time, not delievery time; the
+ // later is handled by Filter<>
+ inline ptr_t last(); // returns the latest known event
+ ptr_t last(Time t); // ... before (or at) time t
+ inline ptr_t first(); // ... after (or at) ...
+ ptr_t first(Time t);
+
+ ptr_t binarySearch(Time t);
+
+ virtual void sync() {
+ time.barrierRead() = time.barrierWrite();
+ time.sync();
+ }
+
+ // vector storing timing
+ Vector<Time> time;
+
+ // writing
+ inline ptr_t add(Time t);
+};
+
+template<typename Ptr>
+inline typename CommonIndex<Ptr>::ptr_t CommonIndex<Ptr>::last() {
+ // get ptr from any barrier (all should be the same!)
+ ptr_t id = time.barrierWrite.get();
+ if (id==0)
+ return nil();
+ else
+ return id - 1;
+}
+
+template<typename Ptr>
+inline typename CommonIndex<Ptr>::ptr_t CommonIndex<Ptr>::first() {
+ // get ptr from any barrier (all should be the same!)
+ ptr_t id = time.barrierWrite.get();
+ if (id==0)
+ return nil();
+ else
+ return 0;
+}
+
+template<typename Ptr>
+CommonIndex<Ptr>::CommonIndex(const string name, ptr_t max) :
+ time(name, max)
+{}
+
+template<typename Ptr>
+typename CommonIndex<Ptr>::ptr_t CommonIndex<Ptr>::last(Time t) {
+ ptr_t cur = binarySearch(t);
+ if ((cur == nil()) or (time(cur) > t))
+ return nil();
+
+ // there may be several elements with time = t; go to the last one
+ while ((cur < last()) && (time(cur + 1) == t))
+ cur++;
+
+ return cur;
+}
+
+template<typename Ptr>
+typename CommonIndex<Ptr>::ptr_t CommonIndex<Ptr>::first(Time t) {
+ ptr_t cur = binarySearch(t);
+
+ if (cur == nil())
+ return nil();
+ if ((time(cur) < t) && (cur < last()))
+ cur = cur + 1;
+ if (time(cur) < t)
+ return nil();
+
+
+ // there may be several elements with time = t; go to the first one
+ while ((cur > first()) && (time(cur - 1) == t))
+ cur--;
+ return cur;
+}
+
+template<typename Ptr>
+typename CommonIndex<Ptr>::ptr_t CommonIndex<Ptr>::binarySearch(Time t) {
+ // TODO (optimize): use a constant frequency approximation to
+ // initialize min, max and pivot (w/ proper fallback)
+
+ // get the limits of the heap
+ ptr_t max = last();
+ if (max == nil()) return nil(); // no elements, yet
+ ptr_t min = first();
+
+ // check if t \in [min, max]
+ if (t > time(max)) return max;
+ if (t < time(min)) return min;
+
+ // binary search in the heap
+ // invariant: min <= target <= max
+ while ((time(min) != time(max))) {
+ ptr_t pivot = (min + max + 1) / 2;
+ if (t >= time(pivot)) {
+ min = pivot;
+ }else{
+ max = pivot - 1;
+ }
+ }
+
+ return max; // min would be ok, too
+}
+
+template<typename Ptr>
+inline typename CommonIndex<Ptr>::ptr_t CommonIndex<Ptr>::add(Time aTime) {
+ ptr_t id = last() + 1; // get position to write
+ time.set(id, aTime); // add new record
+ time.barrierWrite.set(id + 1); // increase write barrier
+
+ return id;
+ }
+
+#endif // hVYFXl0fhRtHkuIHnrxmZOhDCeI
diff --git a/core/index_global.hpp b/core/index_global.hpp
new file mode 100644
index 0000000..138c167
--- /dev/null
+++ b/core/index_global.hpp
@@ -0,0 +1,48 @@
+#ifndef Hiq32h5eXlWfeiJLSv6W9vFXUmc
+#define Hiq32h5eXlWfeiJLSv6W9vFXUmc
+
+#include <boost/tuple/tuple.hpp>
+
+#include "simlimits.hpp"
+#include "index.hpp"
+#include "quant_types.hpp"
+
+template <>
+struct Index<GlobalMsg> : CommonIndex<Ptr<GlobalMsg>::ptr_t> {
+ typedef boost::tuple<> con_arg_t;
+ explicit Index(con_arg_t = con_arg_t())
+ : CommonIndex("index_globalmsg_time", maxSpikes),
+ eventTime("index_globalmsg_eventtime", maxSpikes),
+ maxEventTime("index_globalmsg_maxeventtime", Time::beforeAll())
+ {}
+
+ // writing
+ template<typename SrcQuant>
+ inline ptr_t add(Time time, Time eventTime, SrcQuant src);
+
+ virtual void sync() {
+ CommonIndex::sync();
+ eventTime.barrierRead() = eventTime.barrierWrite() = time.barrierWrite();
+ eventTime.sync();
+ maxEventTime.sync();
+ }
+
+ // data
+ Vector<Time> eventTime;
+ Checkpoint<Time, 1> maxEventTime;
+};
+
+template<typename IllegalImpl>
+inline Index<GlobalMsg>::ptr_t Index<GlobalMsg>::add(Time, Time, IllegalImpl) {
+ DO_NOT_CALL;
+}
+
+template<>
+inline Index<GlobalMsg>::ptr_t Index<GlobalMsg>::add(Time t_in, Time t_out, Global::instance_ptr_t) {
+ ptr_t ptr(CommonIndex::add(t_in));
+ eventTime.set(ptr, t_out);
+ maxEventTime.set(t_in, std::max(t_out, maxEventTime.getValue(t_in)));
+ return ptr;
+}
+
+#endif // Hiq32h5eXlWfeiJLSv6W9vFXUmc
diff --git a/core/index_randomspike.hpp b/core/index_randomspike.hpp
new file mode 100644
index 0000000..a40a99b
--- /dev/null
+++ b/core/index_randomspike.hpp
@@ -0,0 +1,52 @@
+#ifndef zpkaBa96qijSBV6tlRldSMrZ3N0
+#define zpkaBa96qijSBV6tlRldSMrZ3N0
+
+#include "index_spike_base.hpp"
+
+template<>
+struct Index<RandomSpike> : CommonSpikeIndex<Ptr<RandomSpike>::ptr_t> {
+ typedef boost::tuple<> con_arg_t;
+ Index() :
+ CommonSpikeIndex("randomspike"),
+ eventTime("index_randomspike_eventtime", maxSpikes),
+ maxEventTime("index_randomspike_maxeventtime", Time::beforeAll())
+ {}
+ Index(const con_arg_t &) :
+ CommonSpikeIndex("randomspike"),
+ eventTime("index_randomspike_eventtime", maxSpikes),
+ maxEventTime("index_randomspike_maxeventtime", Time::beforeAll())
+ {}
+
+ // using Index<SpikeBaseCase>::first;
+
+ // write
+ template<typename SrcQuant>
+ inline ptr_t add(Time time, Time eventTime, SrcQuant src);
+
+ virtual void sync() {
+ CommonSpikeIndex::sync();
+ eventTime.barrierRead() = eventTime.barrierWrite() = time.barrierWrite();
+ eventTime.sync();
+ maxEventTime.sync();
+ }
+
+ // data
+ Vector<Time> eventTime;
+ Checkpoint<Time, maxNeurons> maxEventTime;
+};
+
+template<typename IllegalImpl>
+Index<RandomSpike>::ptr_t Index<RandomSpike>::
+add(Time, Time, IllegalImpl) DO_NOT_CALL
+
+template<>
+Index<RandomSpike>::ptr_t Index<RandomSpike>::
+add(Time t_in, Time t_out, neuron_ptr_t aSrc) {
+ ptr_t ptr(CommonSpikeIndex::add(t_in, t_out, aSrc));
+ eventTime.set(ptr, t_out);
+ maxEventTime.set(t_in, aSrc(),
+ std::max(t_out, maxEventTime.getValue(t_in, aSrc())));
+ return ptr;
+}
+
+#endif // zpkaBa96qijSBV6tlRldSMrZ3N0
diff --git a/core/index_spike.hpp b/core/index_spike.hpp
new file mode 100644
index 0000000..6ec49f1
--- /dev/null
+++ b/core/index_spike.hpp
@@ -0,0 +1,14 @@
+#ifndef oMw7speKIiOKW6S5XaDR2wH4rZM
+#define oMw7speKIiOKW6S5XaDR2wH4rZM
+
+#include "index_spike_base.hpp"
+
+template<>
+struct Index<Spike> : CommonSpikeIndex<Ptr<Spike>::ptr_t> {
+ typedef boost::tuple<> con_arg_t;
+
+ Index() : CommonSpikeIndex("spike") {}
+ explicit Index(const con_arg_t &) : CommonSpikeIndex("spike") {}
+};
+
+#endif // oMw7speKIiOKW6S5XaDR2wH4rZM
diff --git a/core/index_spike_arrival.hpp b/core/index_spike_arrival.hpp
new file mode 100644
index 0000000..c5bff9f
--- /dev/null
+++ b/core/index_spike_arrival.hpp
@@ -0,0 +1,32 @@
+#ifndef B0LYLjBmmWhE4fufCZdMp6k8weE
+#define B0LYLjBmmWhE4fufCZdMp6k8weE
+
+#include <boost/static_assert.hpp>
+#include <boost/tuple/tuple.hpp>
+
+#include "index_spike.hpp"
+#include "simlimits.hpp"
+
+// fake class used to simplify sim_loop; look at Filter<SpikeArrival>
+template<>
+class Index<SpikeArrival> {
+public:
+ typedef Ptr<SpikeArrival>::ptr_t ptr_t;
+ typedef Index<Spike>::neuron_ptr_t neuron_ptr_t;
+ typedef Ptr<Synapse>::offset_t local_synapse_ptr_t;
+ typedef boost::tuple<> con_arg_t;
+
+ static constexpr ptr_t nil() {
+ BOOST_STATIC_ASSERT(( (ptr_t) -1 > 0 ));
+ return -1;
+ }
+
+ // NOP ctor for TypeMap
+ Index(con_arg_t = con_arg_t()) {}
+
+ // check for correct # of synapses
+ BOOST_STATIC_ASSERT(maxSynapsesPerNeuron <= 256);
+ STATIC_ASSERT_IS_POWER_OF_TWO(maxSynapsesPerNeuron);
+};
+
+#endif // B0LYLjBmmWhE4fufCZdMp6k8weE
diff --git a/core/index_spike_base.hpp b/core/index_spike_base.hpp
new file mode 100644
index 0000000..3ec08c3
--- /dev/null
+++ b/core/index_spike_base.hpp
@@ -0,0 +1,151 @@
+#ifndef x9xBGzwmK2Ew29hQ89VsJgDlY3M
+#define x9xBGzwmK2Ew29hQ89VsJgDlY3M
+
+#include <boost/tuple/tuple.hpp>
+
+#include "checkpoint.hpp"
+#include "index.hpp"
+#include "quant_types.hpp"
+
+template<typename Ptr>
+struct CommonSpikeIndex : CommonIndex<Ptr> {
+ // type- and constdefs
+ typedef Neuron::instance_ptr_t neuron_ptr_t;
+
+ // lift stuff from CommonIndex
+ typedef typename CommonIndex<Ptr>::ptr_t ptr_t;
+ using CommonIndex<Ptr>::nil;
+ using CommonIndex<Ptr>::first;
+ using CommonIndex<Ptr>::last;
+ using CommonIndex<Ptr>::time;
+ // using CommonIndex<Ptr>::nil;
+
+ CommonSpikeIndex(string qname);
+
+ // read operations
+ ptr_t last(Time t, neuron_ptr_t n); // ... of neuron n
+ ptr_t first(Time t, neuron_ptr_t n);
+
+ // write operations
+ template<typename SrcQuant>
+ inline ptr_t add(Time time, Time eventTime /* ignored */, SrcQuant src);
+
+ virtual void sync();
+
+ // vectors storing topological information
+ Vector<neuron_ptr_t::ptr_t> src;
+ Vector<ptr_t> prev, next; // address of the previous and next spike
+ // of the same sender neuron
+
+ // checkpoint to store the last known spike of every neuron (to
+ // implement adding a spike in a fast way)
+ Checkpoint<ptr_t, maxNeurons> prevCache;
+};
+
+template<typename Ptr>
+CommonSpikeIndex<Ptr>::CommonSpikeIndex(string qname) :
+ CommonIndex<Ptr>("index_" + qname + "_time", maxSpikes),
+ src("index_" + qname + "_src", maxSpikes),
+ prev("index_" + qname + "_prev", maxSpikes),
+ next("index_" + qname + "_next", maxSpikes),
+ prevCache("index_" + qname + "_checkpoint_prev", this->nil())
+{ }
+
+template<typename Ptr>
+typename CommonSpikeIndex<Ptr>::ptr_t CommonSpikeIndex<Ptr>::last(Time t, neuron_ptr_t n) {
+ // TODO (optimize): improve the alg to use prevCache as seed for
+ // proper min/max values
+
+ // get the last element before (at) time t
+ ptr_t id = last(t);
+ if (id == nil()) return nil(); // no spikes at all
+
+ // get the last known spike of neuron
+ Time lookup = fmin(prevCache.timeLimit(), t());
+ ptr_t lst = prevCache.getValue(lookup, n());
+ if (lst == nil()) return nil(); // n didn't fire at all
+ if (lst < id) return lst; // no l' with time(lst) < time(lst') <= t may exist
+
+ // do a linear search until a spike of n is found
+ while (src(id) != n()) {
+ id--;
+ }
+
+ return id;
+}
+
+template<typename Ptr>
+typename CommonSpikeIndex<Ptr>::ptr_t CommonSpikeIndex<Ptr>::first(Time t, neuron_ptr_t n) {
+ // TODO (optimize): improve the alg to use prevCache as seed for
+ // proper min/max values
+
+ // get the first element after (at) time t
+ ptr_t id = first(t);
+ if (id == nil()) return nil(); // no spikes at all
+
+ // get the first known spike of neuron
+ ptr_t lst;
+ Time lookup = (t + prevCache.interval())();
+ do {
+ lookup = fmin(prevCache.timeLimit(), lookup());
+ lst = prevCache.getValue(lookup, n());
+ lookup += prevCache.interval();
+ } while (lst == nil() && lookup < prevCache.timeLimit());
+ if ((lst < id) || (lst == nil())) return nil(); // no spike of n after t exists
+
+ // do a linear search until a spike of n is found
+ while (src(id) != n()) {
+ id++;
+ }
+
+ return id;
+}
+
+template<typename Ptr> template<typename AddPtr>
+typename CommonSpikeIndex<Ptr>::ptr_t CommonSpikeIndex<Ptr>::add(Time aTime, Time,
+ AddPtr rawSrc) {
+ // cast to neuron ptr (only correct type for call)
+ if (!boost::is_same<AddPtr, neuron_ptr_t>::value) DO_NOT_CALL;
+ neuron_ptr_t &aSrc(FORCE_CONV(neuron_ptr_t, rawSrc));
+
+ // check if all barriers are equal
+ assert(time.barrierWrite() == src.barrierWrite());
+ assert(time.barrierWrite() == prev.barrierWrite());
+ assert(time.barrierWrite() == next.barrierWrite());
+
+ // get position to write
+ ptr_t id = last();
+ if (last() == nil()) {
+ id = 0;
+ }else{
+ id += 1;
+ }
+
+ // add new record
+ time(id) = aTime;
+ src(id) = aSrc();
+ prev(id) = prevCache.getValue(aTime, aSrc());
+ if (prevCache.getValue(aTime, aSrc()) != nil())
+ next(prevCache.getValue(aTime, aSrc())) = id;
+ next(id) = nil();
+ prevCache.set(aTime, aSrc(), id);
+
+ // increase all write barriers
+ time.barrierWrite() = id + 1;
+ src.barrierWrite() = id + 1;
+ prev.barrierWrite() = id + 1;
+ next.barrierWrite() = id + 1;
+
+ return id;
+}
+
+template<typename Ptr>
+void CommonSpikeIndex<Ptr>::sync() {
+ CommonIndex<Ptr>::sync();
+ src.sync();
+ prev.sync();
+ next.sync();
+ prevCache.sync();
+}
+
+#endif // x9xBGzwmK2Ew29hQ89V
diff --git a/core/list_synapses.cpp b/core/list_synapses.cpp
new file mode 100644
index 0000000..6132b56
--- /dev/null
+++ b/core/list_synapses.cpp
@@ -0,0 +1,22 @@
+#include <iostream>
+
+#include "everything_else.hpp"
+#include "id_list.hpp"
+#include "topology.hpp"
+
+int main(int argc, char **argv) {
+ assert(argc == 3);
+ assertSimDir();
+ {
+ Topology t;
+ IdList<Ptr<Neuron>::ptr_t> src(argv[1]), dst(argv[2]);
+
+ for (auto i : src) {
+ int j=0;
+ Ptr<Synapse> s(-1);
+ while ((s = t.synapse(Ptr<Neuron>(i), j++)) != t.nil())
+ if (dst.count(s.extractNeuron()()))
+ std::cout << s() << "\t" << i << " -> " << s.extractNeuron() << "\n";
+ }
+ }
+}
diff --git a/core/mempool.hpp b/core/mempool.hpp
new file mode 100644
index 0000000..a5ac07b
--- /dev/null
+++ b/core/mempool.hpp
@@ -0,0 +1,156 @@
+#ifndef qEzyOXbTTD6KlhKDUsawdWmx6c0
+#define qEzyOXbTTD6KlhKDUsawdWmx6c0
+
+#include <assert.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string>
+
+#include <boost/utility.hpp>
+
+using std::string;
+
+struct MemPool : boost::noncopyable {
+ explicit MemPool(size_t size); // anonymous in-memory-pool
+ MemPool(size_t size, int fd); // mmap()ed memory pool
+ MemPool(size_t size, const string filename); // mmap()ed memory pool
+ MemPool(MemPool &&src); // move ctor
+ MemPool& operator=(MemPool&&);
+ MemPool& operator=(MemPool&) = delete;
+ MemPool& operator=(MemPool) = delete;
+
+ ~MemPool();
+
+ inline void* operator() () const; // return memory region; TODO: pure attr
+ inline size_t getSize() const;
+ void sync() const; // call msync()
+ void advise(size_t start, size_t len, int adv);
+
+protected:
+ void *base;
+ size_t size;
+ bool isMMap;
+
+ void doMMap(int fd, size_t size);
+ int openMMappableFile(const string filename, size_t size);
+
+private:
+ static char* global_offset;
+ MemPool() = delete;
+ MemPool(const MemPool&) = delete;
+};
+
+char* MemPool::global_offset = (char*) (void*) 0x2fffff000000;
+
+inline void* MemPool::operator() () const {
+ return base;
+}
+
+inline size_t MemPool::getSize() const {
+ return size;
+}
+
+MemPool::MemPool(size_t size) : size(size), isMMap(false) {
+ if (size == 0) {
+ base = NULL;
+ }else{
+ base = malloc(size);
+ assert(base != NULL);
+ }
+}
+
+MemPool::MemPool(size_t size, int fd) : size(size),isMMap(true) {
+ if (size == 0) {
+ base = NULL;
+ }else{
+ doMMap(fd, size);
+ }
+}
+
+MemPool::MemPool(size_t size, const string filename) : size(size), isMMap(true) {
+ if (size == 0) {
+ base = NULL;
+ }else{
+ doMMap(openMMappableFile(filename, size), size);
+ }
+}
+
+MemPool::MemPool(MemPool &&src) : base(src.base), size(src.size), isMMap(src.isMMap) {
+ // std::cout << "Mempool " << base << " moved via copy" << std::endl;
+ src.base = NULL;
+ src.size = 0;
+}
+
+MemPool& MemPool::operator= (MemPool &&src) {
+ // std::cout << "Mempool " << base << " moved via assignment" << std::endl;
+ base = src.base;
+ size = src.size;
+ isMMap = src.isMMap;
+ src.base = NULL;
+ src.size = 0;
+ return *this;
+}
+
+MemPool::~MemPool() {
+ // std::cout << "Mempool " << base << " terminated";
+ if (size == 0 or base == NULL) {
+ // std::cout << " from move" << std::endl;
+ return;
+ }else{
+ // std::cout << std::endl;
+ }
+ if (isMMap) {
+ sync();
+ munmap(base, size);
+ }else{
+ free(base);
+ }
+}
+
+void MemPool::sync() const {
+ if (isMMap)
+ msync(base, size, MS_SYNC);
+}
+
+void MemPool::advise(size_t start, size_t len, int adv) {
+ // adjust region to page boundary (defensive)
+ if (start & 4095) {
+ len -= 4096 - (start & 4095);
+ len &= ~4095;
+ start &= 4095;
+ start +=1;
+ }
+ // detect underflow and to large len
+ if (len < size) {
+ assert(madvise((char*) base + start, len, adv) == 0);
+ }
+}
+
+void MemPool::doMMap(int fd, size_t size) {
+ base = (void*) mmap((void*) global_offset, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NONBLOCK, fd, 0);
+ assert(base != MAP_FAILED);
+ assert(base == (void*) global_offset);
+ global_offset += ((size / 4096 + 1) * 4096) + 1024 * 4096;
+}
+
+int MemPool::openMMappableFile(const string filename, size_t size) {
+ int fd = open(filename.c_str(), O_RDWR | O_CREAT | O_LARGEFILE | O_NOATIME, 0644);
+ assert(fd != -1);
+
+ // check if the file size is correct
+ struct stat st;
+ fstat(fd, &st);
+ if ((size_t) st.st_size < size) {
+ // write one byte at the end of the file to make it big enough for the later mmap call (mmap does not increase file size)
+ assert(lseek64(fd, size-1, SEEK_SET) != (off_t) -1);
+ char c(0);
+ assert(write(fd, &c, 1) == 1);
+ }
+
+ return fd;
+}
+
+#endif // qEzyOXbTTD6KlhKDUsawdWmx6c0
diff --git a/core/model.hpp b/core/model.hpp
new file mode 100644
index 0000000..c95bf46
--- /dev/null
+++ b/core/model.hpp
@@ -0,0 +1,23 @@
+#include <math.h>
+
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/pair.hpp>
+
+#include "continuous_property.hpp"
+#include "continuous_property_impl.hpp"
+#include "discrete_property.hpp"
+#include "property_composition.hpp"
+#include "rng.hpp"
+#include "trainer.hpp"
+
+#ifndef RASIMU_MODEL
+#define RASIMU_MODEL
+
+/// the actual model
+#include "properties.hpp"
+
+#include "trainer_impl.hpp"
+
+#endif
+
diff --git a/core/multi_queue.hpp b/core/multi_queue.hpp
new file mode 100644
index 0000000..b77785b
--- /dev/null
+++ b/core/multi_queue.hpp
@@ -0,0 +1,187 @@
+#ifndef JszL9wNT11XcdnV6wZR3NcSJB0
+#define JszL9wNT11XcdnV6wZR3NcSJB0
+
+#include <assert.h>
+
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/pair.hpp>
+#include <boost/mpl/size.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/front.hpp>
+#include <boost/mpl/empty.hpp>
+#include <boost/mpl/push_front.hpp>
+#include <boost/mpl/pop_front.hpp>
+#include <boost/mpl/back.hpp>
+#include <boost/mpl/transform.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/tuple/tuple.hpp>
+
+#include "heap.hpp"
+#include "priority_queue.hpp"
+#include "quant_types.hpp"
+#include "template_helpers.hpp"
+#include "type_set.hpp"
+
+namespace MultiQueueImpl {
+
+ using namespace boost;
+ using namespace boost::mpl;
+ using boost::mpl::empty;
+ using boost::mpl::size;
+
+ const unsigned char numRID =
+ 1 + RuntimeID<back<DiscreteQuantorList>::type>::value;
+
+ template<typename Val, typename Payload>
+ struct DefaultContainer {
+ typedef Heap<PriorityQueue<Val, Payload>> type;
+ };
+
+ // the actual class (the only one lifted)
+ template <typename Val, // keys to be sorted
+ template<typename X> class Payload, // values belongig to above keys
+ typename Members, // list of all data sources
+ template<typename _Val, typename _Payload> class Container
+ = DefaultContainer> // queue impl
+ struct MultiQueue {
+ // type constructions
+ typedef typename size<Members>::type numMembers;
+ typedef typename transform<Members,
+ Container<Val, Payload<_>>
+ >::type MemberList;
+ // typedef typename CalcSetType<Val, Container, Payload, Members>::type MemberList;
+ typedef typename UnpackTypeList<TypeSet, MemberList>::type set_t;
+
+ // get time and type of min element
+ Val min() {
+ return minVal[1];
+ }
+
+ uint8_t minType() {
+ return minRID[1];
+ }
+
+ // insert event
+ template<typename Quant>
+ inline void insert(Val ct, Val val, Payload<Quant> payload) {
+ assert(ct() <= val());
+ BOOST_STATIC_ASSERT(( numRID > RuntimeID<Quant>::value ));
+ get<Quant>()(ct).insert(val, payload);
+
+ uint pos = RIDpos[RuntimeID<Quant>::value];
+ minVal[pos] = get<Quant>()(ct).minVal();
+
+ // correct order; val can only decrease -> bubble down
+ for (uint i=pos-1; maybeSwap(i); i--);
+ }
+
+ // remove min event; ugly part: caller has to supply correct quant
+ // and position
+ template<typename Quant>
+ inline void removeMin(Val ct, uint pos=1) {
+ assert(RuntimeID<Quant>::value == minRID[pos]);
+
+ get<Quant>()(ct).removeMin();
+ minVal[pos] = get<Quant>()(ct).isEmpty()
+ ? Val::never()
+ : get<Quant>()(ct).minVal();
+
+ // correct order; val can only increase -> bubble up
+ for (int i=pos; maybeSwap(i); i++);
+ }
+
+ // like removeMin, but the quant does not need to be the current
+ // global min and no position has to be specified
+ template<typename Quant>
+ inline void removeLocalMin(Val ct) {
+ removeMin<Quant>(ct, RIDpos[RuntimeID<Quant>::value]);
+ }
+
+ // constructor
+ template<typename... Arg>
+ MultiQueue(Arg... arg) : typeSet(std::move(arg)...) {
+ init();
+ }
+
+ MultiQueue() : typeSet() {
+ init();
+ }
+
+ void init() {
+ // set fake entries (to avoid boundary condition during sorting)
+ minVal[0] = Val::beforeAll();
+ minRID[0] = -1;
+ // (and prefill minVal/minRID in case of missing values in loadInitial())
+ for (int i=1; i<=numMembers::value + 1; i++) {
+ minVal[i] = Val::never();
+ minRID[i] = i - 1;
+ }
+
+ // init queue head caches
+ loadInitial<Members>();
+
+ // blind in-place bubble sort
+ for (int i=0; i<numMembers::value; i++)
+ for (int j=1; j<numMembers::value; j++)
+ maybeSwap(j);
+ }
+
+ template<typename RemMembers>
+ void loadInitial(uint pos=1) {
+ typedef typename front<RemMembers>::type head_t;
+ typedef empty<typename pop_front<RemMembers>::type> isLast_t;
+ typedef typename if_<isLast_t,
+ RemMembers,
+ typename pop_front<RemMembers>::type
+ >::type tail_t;
+
+ // read current time from heaps
+ Val ct = get<head_t>().currentTime;
+
+ // init queue head caches
+ minRID[pos] = RuntimeID<head_t>::value;
+ if (get<head_t>()(ct).isEmpty()) {
+ minVal[pos] = Val::never();
+ }else{
+ minVal[pos] = get<head_t>()(ct).minVal();
+ }
+ RIDpos[RuntimeID<head_t>::value] = pos;
+
+ // template recursion
+ if (!is_same<RemMembers, tail_t>::value)
+ loadInitial<tail_t>(pos+1);
+ }
+
+ // access underlying queues directly
+ template <typename Quant>
+ inline typename Container<Val, Payload<Quant>>::type & get() {
+ return typeSet.get<typename Container<Val, Payload<Quant>>::type>();
+ }
+
+ // swap if i and i+1 are in wrong order; return if swapped
+ inline bool maybeSwap(uint i) {
+ // check if order is violated
+ if (minVal[i] < minVal[i+1]) return false;
+ if ((minVal[i] == minVal[i+1]) && (minRID[i] <= minRID[i+1])) return false; // sort by RID if val is equal
+
+ // swap
+ std::swap(minVal[i], minVal[i+1]);
+ std::swap(minRID[i], minRID[i+1]);
+ RIDpos[minRID[i]] = i;
+ RIDpos[minRID[i + 1]] = i + 1;
+ return true;
+ }
+
+ // data
+ set_t typeSet;
+
+ Val minVal[numMembers::value + 2];
+ uint minRID[numMembers::value + 2];
+ uint RIDpos[numRID];
+ };
+}
+
+using MultiQueueImpl::MultiQueue;
+
+#endif // JszL9wNT11XcdnV6wZR3NcSJB0
diff --git a/core/perftools.hpp b/core/perftools.hpp
new file mode 100644
index 0000000..91cf56e
--- /dev/null
+++ b/core/perftools.hpp
@@ -0,0 +1,40 @@
+#ifndef U6JSwQqqOviv7kQT0JaHQQr1VDI
+#define U6JSwQqqOviv7kQT0JaHQQr1VDI
+
+#include <sys/time.h>
+#include <stdio.h>
+
+////// THROUGHPUT
+
+void print_throughput(double time, double num, char * title) {
+ fprintf(stderr, "%s: %lfs\t%lf/s\n", title, time, num / time);
+}
+
+void print_throughput2(double time, double num, long base) {
+ fprintf(stderr, "%ld:\t%lfs\t%lf/s\n", base, time, num / time);
+}
+
+////// TIMER
+
+class Timer {
+public:
+ Timer();
+
+ double diff();
+
+ timeval start;
+};
+
+Timer::Timer() {
+ gettimeofday(&start,NULL);
+}
+
+double Timer::diff() {
+ timeval stop;
+
+ gettimeofday(&stop,NULL);
+
+ return (stop.tv_sec + stop.tv_usec/1000000.0) - (start.tv_sec + start.tv_usec/1000000.0);
+}
+
+#endif // U6JSwQqqOviv7kQT0JaHQQr1VDI
diff --git a/core/pla_apply.hpp b/core/pla_apply.hpp
new file mode 100644
index 0000000..f9ab3f6
--- /dev/null
+++ b/core/pla_apply.hpp
@@ -0,0 +1,276 @@
+#ifndef QwJZ8toZywNt6ETv1SpnUMCaNRM
+#define QwJZ8toZywNt6ETv1SpnUMCaNRM
+
+#include <assert.h>
+
+#include <boost/mpl/and.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/copy.hpp>
+#include <boost/mpl/copy_if.hpp>
+#include <boost/mpl/front.hpp>
+#include <boost/mpl/has_key.hpp>
+#include <boost/mpl/insert.hpp>
+#include <boost/mpl/inserter.hpp>
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/transform.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include "context.hpp"
+#include "continuous_property.hpp"
+#include "pla_set.hpp"
+#include "quant_types.hpp"
+#include "template_helpers.hpp"
+#include "time.hpp"
+#include "type_map.hpp"
+
+#include "model.hpp" // to specialize QuantMayEmit and
+ // QuantHasVarDelay before instanciation
+
+namespace PLA_ApplyImpl {
+
+ using namespace boost::mpl;
+ using boost::is_same;
+
+ /// event intent
+ template<
+ typename EmittingQuant,
+ typename EmittedQuant,
+ typename Enable = typename QuantMayEmit<EmittingQuant, EmittedQuant>::result,
+ typename EnableTime = typename QuantHasVarDelay<EmittedQuant>::result>
+ struct Intent;
+
+ template<typename _Q1, typename _Q2, typename _B>
+ struct Intent<_Q1, _Q2, bool_<false>, _B> {
+ inline void combine(bool) {}
+ inline bool getResult() const { return false; }
+ inline void setDelay(Time t) const { DO_NOT_CALL }
+ inline Time getDelay() const { return Time(0); }
+ };
+
+ // intent without variable delay
+ template<typename SrcCQ, typename DstDQ>
+ struct Intent<SrcCQ, DstDQ, bool_<true>, bool_<false>>
+ : Intent<SrcCQ, DstDQ, bool_<false>, bool_<false>> {
+ inline Intent() :
+ result(QuantEmitDefault<SrcCQ, DstDQ>::value)
+ {}
+
+ inline void combine(bool val) {
+ if (QuantEmitDefault<SrcCQ, DstDQ>::value) {
+ // default == true -> combine via and
+ result = result and val;
+ }else{
+ // default == false -> combine via or
+ result = result or val;
+ }
+ }
+ inline bool getResult() const { return result; }
+
+ bool result;
+ };
+
+ // intent with variable delay
+ template<typename SrcCQ, typename DstDQ>
+ struct Intent<SrcCQ, DstDQ, bool_<true>, bool_<true>>
+ : Intent<SrcCQ, DstDQ, bool_<true>, bool_<false>> {
+ inline Intent() :
+ delay(Time::never())
+ {}
+
+ inline void setDelay(Time t) { delay = t; }
+ inline Time getDelay() const {
+ assert(delay != Time::never()); // assure setDelay has been called
+ return delay;
+ }
+
+ bool result;
+ Time delay;
+ };
+
+ /// event transaction: store changed values (and apply them later);
+ /// it is a PLA itself, but is not exported
+ template<typename SrcDQ,
+ typename DstCQ,
+ typename PC,
+ typename Context>
+ struct Transaction {
+ /// 1st use: storage
+ // filter props to store
+ struct filter_f {
+ template<typename Pair>
+ struct apply {
+ typedef typename Pair::first prop;
+ typedef typename and_<
+ typename is_same<typename prop::quant, DstCQ>::type,
+ typename ContinuousProperty_ApplyChangesProp<prop, SrcDQ>::type
+ >::type type;
+ };
+ };
+
+ // transform property list item into (property, property::type)
+ struct transform_f {
+ template<typename Item>
+ struct apply {
+ typedef typename Item::first prop;
+ typedef pair<prop, typename prop::type> type;
+ };
+ };
+
+ // compute map of props to store (filter and transform)
+ typedef typename transform<
+ typename copy_if<
+ typename PC::properties_t,
+ filter_f
+ >::type,
+ transform_f,
+ inserter<map<>, insert<_1, _2> >
+ >::type map_t;
+
+ // instance vars
+ typename if_<empty<map_t>,
+ TypeMap<Void>,
+ TypeMap<map_t>
+ >::type instance;
+
+ // access
+ template<typename Q>
+ void set(typename at<map_t, Q>::type val) {
+ instance.template get<Q>() = val;
+ }
+
+ /// 2nd use: PLA
+ typedef Void result_t;
+ template<typename ContextProp, bool _aaa> struct local_state_t {
+ typedef ContextProp property_t;
+ };
+
+ Transaction(Context context, Time time) : context(context), time(time) {}
+
+ Context context;
+ Time time;
+ result_t result;
+
+ template<typename ContextData, typename LocalState>
+ inline void pre(PC &pc, ContextData &data, LocalState &state) {
+ typedef typename LocalState::property_t prop_t;
+ typedef typename prop_t::quant quant_t;
+ if (has_key<map_t, prop_t>::type::value) {
+ pc.cast(PLA_Set<prop_t>
+ (time, Ptr<quant_t>(context.template getptr<quant_t>()),
+ instance.template get<prop_t, typename prop_t::type>()));
+ }
+ }
+
+ template<typename _Data, typename LocalState>
+ inline void post(PC &pc, _Data &data, LocalState &state) {
+ }
+
+
+ };
+
+ /// apply action
+ template<
+ typename SrcQuant, // discrete
+ typename DstQuant, // continuous
+ typename PropComp,
+ typename Context = DelieverContext<SrcQuant, DstQuant>
+ >
+ struct PLA_Apply {
+ // map->intent transformation
+ template<typename T>
+ struct intent_from_type {
+ typedef pair<T, Intent<DstQuant, T>> type;
+ };
+
+ // action types & consts
+ typedef Void result_t;
+ template<typename ContextProp, bool _doWriteResults> struct local_state_t {
+ typedef ContextProp property_t;
+ };
+ typedef Transaction<SrcQuant, DstQuant, PropComp, Context> transaction_t;
+ typedef TypeMap<
+ typename transform<
+ DiscreteQuantorList,
+ intent_from_type<_1>,
+ inserter<map<>, insert<_1, _2> >
+ >::type
+ > intentmap_t;
+
+ // action state & constructor
+ Context context;
+ intentmap_t intent;
+ Time time;
+ result_t result;
+ transaction_t transaction;
+
+ inline PLA_Apply(Time time, Context context)
+ : context(context), intent(), time(time), transaction(context, time) {}
+
+ // action methods
+ template<typename PC, typename ContextData, typename LocalState>
+ inline void pre(PC &pc, ContextData &data, LocalState &) {
+ // call apply definition for every destination property
+ if (boost::is_same<typename LocalState::property_t::quant, DstQuant>::value) {
+ ContinuousProperty_Apply<
+ PC, typename LocalState::property_t,
+ DstQuant, SrcQuant, Context,
+ intentmap_t, transaction_t>
+ ::eval(pc, context, time, intent, transaction);
+ }
+ }
+
+ template<typename _PC, typename _Data, typename LocalState>
+ inline void post(_PC &pc, _Data &data, LocalState &state) {
+ }
+
+ // after-use queries
+ inline bool generateAny() {
+ // TODO (beauty, optimize): compile time fold over discrete
+ // quantor list, removing queries of quants we do never emit
+ return generate<GlobalMsg>()
+ or generate<Spike>()
+ or generate<RandomSpike>()
+ or generate<SpikeArrival>();
+ }
+
+ template<typename Q>
+ inline bool generate() {
+ return intent.template get<Q>().getResult();
+ }
+
+ template<typename Q>
+ inline Time getDelay() {
+ return intent.template get<Q>().getDelay();
+ }
+
+ template<typename PC>
+ void computeDelay(PC &pc) {
+ // TODO (beauty, optimize): compile time fold over discrete
+ // quantor list
+#define GEN_CD(Q) \
+ if (QuantHasVarDelay<Q>::result::value \
+ && QuantMayEmit<DstQuant, Q>::result::value) \
+ intent.template get<Q>().setDelay \
+ (DiscreteProperty_ComputeDelay<Q, DstQuant> \
+ ::eval(pc, context, transaction, time));
+
+ GEN_CD(GlobalMsg)
+ GEN_CD(Spike)
+ GEN_CD(RandomSpike)
+ GEN_CD(SpikeArrival)
+#undef GEN_CD
+ }
+
+ template<typename PC>
+ void commit(PC &pc) {
+ pc.call(transaction);
+ }
+
+ private:
+ PLA_Apply();
+ };
+}
+
+using PLA_ApplyImpl::PLA_Apply;
+
+#endif // QwJZ8toZywNt6ETv1SpnUMCaNRM
diff --git a/core/pla_debug_name.hpp b/core/pla_debug_name.hpp
new file mode 100644
index 0000000..1b1f89e
--- /dev/null
+++ b/core/pla_debug_name.hpp
@@ -0,0 +1,39 @@
+#ifndef lULoAciwLXvtwzfgpfl9LrvpNj0
+#define lULoAciwLXvtwzfgpfl9LrvpNj0
+
+#include <string>
+
+#include <boost/type_traits/is_same.hpp>
+
+#include "property_instance.hpp"
+#include "template_helpers.hpp"
+
+// PLA template
+struct PLA_Debug_Name {
+ // action types & consts
+ typedef std::string result_t;
+ template<typename _ContextProp, bool doWriteResults> struct local_state_t {
+ typedef _ContextProp prop;
+ static const bool write = doWriteResults;
+ };
+
+ // action state
+ result_t result;
+
+ PLA_Debug_Name() : result("Property List Content:") { }
+
+ // action methods
+ template<typename _PropList, typename _ContextData, typename LocalState>
+ inline void pre(_PropList &pc, _ContextData &data, LocalState &state) {
+ result = result + "\n"
+ + LocalState::prop::quant::name + "::"
+ + LocalState::prop::name
+ + " (" + LocalState::prop::quant::class_t::name + "): "
+ + (LocalState::write ? "writing" : "reading");
+ }
+
+ template<typename _PropComp, typename _Data, typename _LocalState>
+ inline void post(_PropComp &pc, _Data &data, _LocalState &state) { }
+};
+
+#endif // lULoAciwLXvtwzfgpfl9LrvpNj0
diff --git a/core/pla_debug_space.hpp b/core/pla_debug_space.hpp
new file mode 100644
index 0000000..361f3d5
--- /dev/null
+++ b/core/pla_debug_space.hpp
@@ -0,0 +1,172 @@
+#ifndef iAN34Y9CxgHgVUyhhdYpI8Ynza8
+#define iAN34Y9CxgHgVUyhhdYpI8Ynza8
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <boost/type_traits/is_same.hpp>
+
+#include "checkpoint.hpp"
+#include "index_spike.hpp"
+#include "property_instance.hpp"
+#include "simlimits.hpp"
+#include "template_helpers.hpp"
+
+namespace PLA_Debug_Space_Impl {
+
+template <class Quant>
+struct PLA_Debug_Space_Quant2Num;
+
+// PLA template
+struct PLA_Debug_Space {
+ // action types & consts
+ typedef Void result_t;
+ template<typename _ContextProp, bool doWriteResults> struct local_state_t {
+ typedef _ContextProp prop;
+ static const bool write = doWriteResults;
+ };
+
+ // action state
+ result_t result;
+
+ // tmp type const; to do: change to quant::runtimeID
+ static const int cGlobal = 0;
+ static const int cNeuron = 1;
+ static const int cSynapse = 2;
+ static const int cGlobalMsg = 3;
+ static const int cSpike = 4;
+ static const int cSpikeArrival = 5;
+ static const int propCount = 6;
+
+ // result storage
+ // * set by action methods
+ int num[propCount],
+ numRead[propCount],
+ size[propCount],
+ sizeRead[propCount];
+
+ // * set by generateReport()
+ int totalNum,
+ totalNumRead,
+ totalSize;
+
+ // methods
+ PLA_Debug_Space();
+ std::string generateReport();
+
+ // action methods
+ template<typename _PropList, typename _ContextData, typename LocalState>
+ inline void pre(_PropList &pc, _ContextData &data, LocalState &state) {
+ int id = PLA_Debug_Space_Quant2Num<typename LocalState::prop::quant>::eval();
+ num[id] += 1;
+ size[id] += LocalState::prop::size;
+
+ if (!LocalState::write) {
+ numRead[id] += 1;
+ sizeRead[id] += LocalState::prop::size;
+ }
+ }
+
+ template<typename PropComp, typename Data, typename _LocalState>
+ inline void post(PropComp &pc, Data &data, _LocalState &state) { }
+};
+
+PLA_Debug_Space::PLA_Debug_Space() {
+ for (int i=0; i<propCount; i++) {
+ num[i] = 0;
+ numRead[i] = 0;
+ size[i] = 0;
+ sizeRead[i] = 0;
+ }
+}
+
+using namespace std;
+
+string PLA_Debug_Space::generateReport() {
+ ostringstream &result = *(new ostringstream());
+
+ double chkpt_delta = checkpointInterval;
+
+ result
+ << "Simulation\n"
+ << "==========\n\n"
+ <<"neurons:\t" << maxNeurons << "\n"
+ << "synapses:\t" << maxSynapsesPerNeuron * maxNeurons << "\t(" << (int) maxSynapsesPerNeuron << " per neuron)\n"
+ << "\n"
+ << "max. # spikes:\t\t" << maxSpikes << "\n"
+ << "max. # global messages:\t" << maxGlobalMsg << "\n"
+ << "max. # checkpojts:\t" << maxCheckpoints << "\n"
+ << "checkpoint every\t" << chkpt_delta << " s\n"
+ << "\n"
+ << "max. run-time:\n"
+ << "\t" << min( chkpt_delta * maxCheckpoints, (double) maxSpikes / maxNeurons / 1.0 ) << " s \t@ 1 Hz\n"
+ << "\t" << min( chkpt_delta * maxCheckpoints, (double) maxSpikes / maxNeurons / 10.0 ) << " s \t@ 10 Hz\n"
+ << "\t" << min( chkpt_delta * maxCheckpoints, (double) maxSpikes / maxNeurons / 100.0 ) << " s \t@ 100 Hz\n"
+ << "\n\n";
+
+ totalNum = 0;
+ totalSize = 0;
+ for (int i=0; i<propCount; i++) {
+ totalNum += num[i];
+ totalSize += size[i];
+ }
+
+ result
+ << "Properties\n"
+ << "==========\n\n"
+ << "| Quantor\t| # of \t| size (per\t| size (all \t|\n"
+ << "| \t| props\t| instance)\t| instances)\t|\n"
+ << "+---------------+-------+---------------+---------------+\n"
+
+ << "| Global \t| " << num[cGlobal] << "\t| " << size[cGlobal] << "\t\t| " << size[cGlobal] << "\t\t|\n"
+ << "| Neuron \t| " << num[cNeuron] << "\t| " << size[cNeuron] << "\t\t| " << maxNeurons * size[cNeuron] << "\t\t|\n"
+ << "| Synapse \t| " << num[cSynapse] << "\t| " << size[cSynapse] << "\t\t| " << maxNeurons * maxSynapsesPerNeuron * size[cSynapse] << "\t|\n"
+ << "| GlobalMsg \t| " << num[cGlobalMsg] << "\t| " << size[cGlobalMsg] << "\t\t| - \t|\n"
+ << "| Spike \t| " << num[cSpike] << "\t| " << size[cSpike] << "\t\t| - \t|\n"
+ << "| SpikeArrival \t| " << num[cSpikeArrival] << "\t| " << size[cSpikeArrival] << "\t\t| - \t|\n"
+ << "+---------------+-------+---------------+---------------+\n"
+
+ << "| Total \t| " << totalNum << "\t| " << totalSize << "\t\t| - \t|\n"
+ << "\n\n";
+
+ double pt, ps; // per time / spike space requirement
+ pt = size[cGlobal] + sizeof(Time) * num[cGlobal]
+ + (size[cNeuron] + sizeof(Index<Spike>::ptr_t) + sizeof(Time) * (num[cNeuron] + 1)) * maxNeurons // addend 2 and 4 account for Index<Spike>::prevCache
+ + (size[cSynapse] + sizeof(Time) * num[cSynapse]) * maxNeurons * maxSynapsesPerNeuron;
+ pt /= chkpt_delta;
+
+ ps = maxNeurons * (2*sizeof(Index<Spike>::ptr_t) + sizeof(Index<Spike>::neuron_ptr_t) + size[cNeuron] + maxSynapsesPerNeuron * size[cSpikeArrival]);
+
+ result
+ << "Space Requirements\n"
+ << "==================\n\n"
+ << "These are strict minimum numbers. Global messages, additional managment information (in-app and in-kernel) and many small vars have not been taken into account.\n\n"
+ << "\t: 1 s\t\t| 1 h\t\t| 1 d\t\t|\n"
+ << "--------+---------------+---------------+---------------+\n"
+ << " 1 Hz\t: " << SISuffixify(1 * ( 1 * ps + pt), 1024) << "B\t| " << SISuffixify(3600 * ( 1 * ps + pt), 1024) << "B\t| " << SISuffixify(86400 * ( 1 * ps + pt), 1024) << "B\t|\n"
+ << " 10 Hz\t: " << SISuffixify(1 * ( 10 * ps + pt), 1024) << "B\t| " << SISuffixify(3600 * ( 10 * ps + pt), 1024) << "B\t| " << SISuffixify(86400 * ( 10 * ps + pt), 1024) << "B\t|\n"
+ << " 100 Hz\t: " << SISuffixify(1 * (100 * ps + pt), 1024) << "B\t| " << SISuffixify(3600 * (100 * ps + pt), 1024) << "B\t| " << SISuffixify(86400 * (100 * ps + pt), 1024) << "B\t|\n"
+ << "";
+
+
+ return result.str();
+}
+
+// PLA_Debug_Space_Quant2Num implementation
+// TODO: overhaul
+
+template <> struct PLA_Debug_Space_Quant2Num<Global> { static int eval() { return PLA_Debug_Space::cGlobal; } };
+template <> struct PLA_Debug_Space_Quant2Num<Neuron> { static int eval() { return PLA_Debug_Space::cNeuron; } };
+template <> struct PLA_Debug_Space_Quant2Num<Synapse> { static int eval() { return PLA_Debug_Space::cSynapse; } };
+template <> struct PLA_Debug_Space_Quant2Num<GlobalMsg> { static int eval() { return PLA_Debug_Space::cGlobalMsg; } };
+template <> struct PLA_Debug_Space_Quant2Num<Spike> { static int eval() { return PLA_Debug_Space::cSpike; } };
+template <> struct PLA_Debug_Space_Quant2Num<SpikeArrival> { static int eval() { return PLA_Debug_Space::cSpikeArrival; } };
+
+} // NS
+
+using PLA_Debug_Space_Impl::PLA_Debug_Space;
+
+
+
+#endif // iAN34Y9CxgHgVUyhhdYpI8Ynza8
diff --git a/core/pla_evolve.hpp b/core/pla_evolve.hpp
new file mode 100644
index 0000000..032d9d4
--- /dev/null
+++ b/core/pla_evolve.hpp
@@ -0,0 +1,93 @@
+#ifndef FznMZXtH9pg7npfVO7D248udzM8
+#define FznMZXtH9pg7npfVO7D248udzM8
+
+#include <assert.h>
+
+#include <boost/type_traits/is_same.hpp>
+
+#include "context.hpp"
+#include "continuous_property.hpp"
+#include "template_helpers.hpp"
+#include "pla_set.hpp"
+#include "time.hpp"
+
+// local state
+// general case: no action (and zero storage)
+template<typename Prop, typename Quant1, typename Quant2>
+struct PLA_Evolve_LocalState {
+ template <typename PropComp, typename Context, typename LocalData>
+ inline void evolve(PropComp &pc, Context context, LocalData &data, Time newTime) {
+ DO_NOT_CALL;
+ }
+
+ template <typename PropComp, typename Context>
+ inline void commit(PropComp &pc, Context context, Time time) {
+ DO_NOT_CALL;
+ }
+};
+
+// matching case: get/set the value to local storage
+template<typename Prop, typename Quant>
+struct PLA_Evolve_LocalState<Prop, Quant, Quant> {
+ typename Prop::type val;
+
+ template <typename PropComp, typename Context, typename LocalData>
+ inline void evolve(PropComp &pc, Context context, LocalData &data, Time newTime) {
+ // calc time difference (= time amount we evolve)
+ Time oldTime = data.data.getTime(newTime, context.template getptr<Quant>()());
+ Time dt = newTime - oldTime;
+ assert(dt >= 0);
+
+ // calc new val and store locally
+ val = ContinuousProperty_Evolve<PropComp, Prop, Quant, Context>::
+ eval(pc, context, oldTime, dt);
+ }
+
+ template <typename PropComp, typename Context>
+ inline void commit(PropComp &pc, Context context, Time time) {
+ Ptr<Quant> dst(context.template getptr<Quant>());
+ PLA_Set<Prop> pla_set(time, dst, val);
+ pc.call(pla_set);
+ }
+};
+
+// evolve action
+template<typename Quant, typename Context = ContinuousContext<Quant> >
+struct PLA_Evolve {
+ // action types & consts
+ typedef Void result_t;
+ template<typename ContextProp, bool _doWriteResults>
+ struct local_state_t
+ : PLA_Evolve_LocalState<ContextProp, Quant, typename ContextProp::quant>
+ {
+ typedef ContextProp prop;
+ };
+
+ // action state & constructor
+ typedef typename Quant::instance_ptr_t instance_ptr_t;
+ Context context;
+ Time newTime;
+ result_t result;
+
+ PLA_Evolve(Context context, Time newTime) : context(context), newTime(newTime) {}
+
+ // action methods
+ template<typename PropComp, typename LocalData, typename LocalState>
+ inline void pre(PropComp &pc, LocalData &data, LocalState &state) {
+ // if we have the correct quantity ...
+ if (boost::is_same<Quant, typename LocalState::prop::quant>::value)
+ state.evolve(pc, context, data, newTime); // ... evolve it
+ }
+
+ template<typename _PropComp, typename _LocalData, typename LocalState>
+ inline void post(_PropComp &pc, _LocalData &data, LocalState &state) {
+ // if we have the correct quantity ...
+ if (boost::is_same<Quant, typename LocalState::prop::quant>::value)
+ state.commit(pc, context, newTime); // ... store new value and time
+ }
+
+private:
+ PLA_Evolve();
+};
+
+#endif // FznMZXtH9pg7npfVO7D248udzM8
diff --git a/core/pla_generate.hpp b/core/pla_generate.hpp
new file mode 100644
index 0000000..7ae5169
--- /dev/null
+++ b/core/pla_generate.hpp
@@ -0,0 +1,112 @@
+#ifndef Vaz5kkzRinGGCeloVow8grqZI1c
+#define Vaz5kkzRinGGCeloVow8grqZI1c
+
+// HINT: simple schema, based on the fact the this PLA changes only
+// props it does not depend on (read from)
+
+#include <assert.h>
+
+#include <boost/type_traits/is_same.hpp>
+#include <boost/tuple/tuple.hpp>
+
+#include "context.hpp"
+#include "template_helpers.hpp"
+#include "time.hpp"
+
+namespace PLA_Generate_Impl {
+
+ using namespace boost;
+ using namespace boost::mpl;
+
+ // local state
+ // general case: no action (and zero storage)
+ template<typename Prop, typename CQ, typename DQ, bool quantMatch /* == false */>
+ struct LocalState {
+ template<typename PropComp, typename Context, typename MI, typename MQ>
+ inline void process(PropComp &, Context, Time, MI &, MQ &) {}
+
+ template <typename PropComp, typename Context>
+ inline void commit(PropComp &, Context, Time) {}
+ };
+
+ // matching case: get/set the value to local storage
+ template<typename Prop, typename CQ, typename DQ>
+ struct LocalState<Prop, CQ, DQ, true /* == quantMatch */> {
+ typename Prop::type val;
+
+ template<typename PropComp, typename Context, typename MI, typename MQ>
+ inline void process(PropComp &pc, Context context, Time time,
+ MI &indices, MQ &queues) {
+ // calc new val and store locally
+ // TODO: check generation of discrete properties
+ ContinuousProperty_Generate<Prop, CQ, DQ>::
+ eval(pc, context, time, val, indices, queues);
+ }
+
+ template <typename PropComp, typename Context>
+ inline void commit(PropComp &pc, Context context, Time time) {
+ // HINT: caller has to check if we should commit
+ typedef typename Prop::quant Quant;
+ Ptr<Quant> dst(context.template getptr<Quant>());
+ PLA_Set<Prop> pla_set(time, dst, val); // TODO: omit time if Prop is discrete
+ pc.call(pla_set);
+ }
+ };
+
+ // generate action
+ template<typename CQ, typename DQ, typename MI, typename MQ>
+ struct PLA_Generate {
+ // action types & consts
+ typedef Void result_t;
+ template<typename ContextProp, bool doWriteResults>
+ struct local_state_t : LocalState<ContextProp, CQ, DQ,
+ or_<is_same<CQ, typename ContextProp::quant>,
+ is_same<DQ, typename ContextProp::quant>
+ >::value>
+ {
+ typedef ContextProp prop;
+ static const bool write = doWriteResults;
+ };
+ typedef EmitContext<CQ, DQ> context_t;
+
+ // action state & constructor
+ context_t context;
+ Time time;
+ result_t result;
+
+ MI &indices;
+ MQ &queues;
+
+ PLA_Generate(Time time, context_t context, MI &indices, MQ &queues)
+ : context(context), time(time), indices(indices), queues(queues) {}
+
+ // action methods
+ template<typename PropComp, typename LocalData, typename LocalState>
+ inline void pre(PropComp &pc, LocalData &, LocalState &state) {
+ // if we have the correct quantity (and ought to write to it)
+ typedef typename LocalState::prop Prop;
+ typedef typename Prop::quant Quant;
+ if ( (is_same<CQ, Quant>::value and ContinuousProperty_Generate
+ <Prop, CQ, DQ>::changesValue)
+ or (is_same<DQ, typename LocalState::prop::quant>::value and state.write))
+ state.process(pc, context, time, indices, queues);
+ }
+
+ template<typename PropComp, typename _LocalData, typename LocalState>
+ inline void post(PropComp &pc, _LocalData &data, LocalState &state) {
+ typedef typename LocalState::prop Prop;
+ typedef typename Prop::quant Quant;
+ if ( (is_same<CQ, Quant>::value and ContinuousProperty_Generate
+ <Prop, CQ, DQ>::changesValue)
+ or (is_same<DQ, typename LocalState::prop::quant>::value and state.write))
+ state.commit(pc, context, time); // ... store new value and time
+ }
+
+ private:
+ PLA_Generate();
+ };
+}
+
+using PLA_Generate_Impl::PLA_Generate;
+
+#endif // Vaz5kkzRinGGCeloVow8grqZI1c
diff --git a/core/pla_get.hpp b/core/pla_get.hpp
new file mode 100644
index 0000000..ba7d2a0
--- /dev/null
+++ b/core/pla_get.hpp
@@ -0,0 +1,92 @@
+#ifndef j9bZiR9W7dKz17gTUOtW1xODHdA
+#define j9bZiR9W7dKz17gTUOtW1xODHdA
+
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include "context.hpp"
+#include "continuous_property.hpp"
+#include "property_instance.hpp"
+#include "property_list.hpp"
+#include "quant_types.hpp"
+#include "template_helpers.hpp"
+
+// worker template forward decl
+template<typename Prop, typename CurrentProp, typename Data, typename QuantClass>
+struct PLA_Get_Impl;
+
+// PLA template
+template<typename Prop, typename Context = SingleContext<typename Prop::quant>>
+struct PLA_Get {
+ // action consts
+ typedef typename Prop::type result_t;
+ template<typename ContextProp, bool _doWriteResult> struct local_state_t {
+ typedef ContextProp prop;
+ };
+
+ // action parameters
+ typedef typename Prop::instance_ptr_t instance_t;
+ typedef typename boost::mpl::if_<boost::is_same<ContinuousPropertyClass, typename Prop::quant::class_t>,
+ Time,
+ Void>::type time_t;
+ Context ctx;
+ time_t time;
+ result_t result;
+
+ PLA_Get(time_t time, Context ctx) : ctx(ctx), time(time) {}
+ PLA_Get(Context ctx) : ctx(ctx) {
+ BOOST_STATIC_ASSERT((boost::is_same<time_t, Void>::value));
+ }
+
+ // action methods
+ template<typename _PropComp, typename _ContextData, typename _LocalState>
+ inline void pre(_PropComp &pc, _ContextData &data, _LocalState &state) { }
+
+
+ template<typename PC, typename ContextData, typename LocalState>
+ inline void post(PC &pc, ContextData &data, LocalState &state) {
+ BOOST_MPL_ASSERT(( PL_Contains<PL<typename PC::properties_t>, Prop> ));
+ PLA_Get_Impl<Prop, typename LocalState::prop, ContextData, typename LocalState::prop::quant::class_t>
+ ::eval(pc, data, ctx, time, result);
+ }
+};
+
+// worker template implementation
+// * do nothing at the wrong type
+template<typename Prop, typename WrongProp, typename Data, typename QuantClass>
+struct PLA_Get_Impl {
+ template<typename PC, typename Context = SingleContext<typename Prop::quant>>
+ static inline void eval(PC &, Data &, Context,
+ typename PLA_Get<Prop>::time_t, typename Prop::type &) { }
+};
+
+// * store pointer to the data structure at the correct type
+template<typename Prop, typename Data>
+struct PLA_Get_Impl<Prop, Prop, Data, ContinuousPropertyClass> {
+ template<typename PC, typename Context = SingleContext<typename Prop::quant>>
+ static inline void eval(PC &pc, Data &data, Context ctx,
+ typename PLA_Get<Prop>::time_t time,
+ typename Prop::type &fold_state) {
+ Time oldTime = data.data.getTime(time, ctx.template getptr<typename Prop::quant>()());
+ assert(oldTime <= time); // we can not jump backward
+ if (oldTime < time) {
+ Time dt = time - oldTime;
+ fold_state = ContinuousProperty_Evolve<PC, Prop, typename Prop::quant, Context>
+ ::eval(pc, ctx, oldTime, dt);
+ }else{
+ fold_state = data.data.getValue(time, ctx.template getptr<typename Prop::quant>()());
+ }
+ }
+};
+
+template<typename Prop, typename Data>
+struct PLA_Get_Impl<Prop, Prop, Data, DiscretePropertyClass> {
+ template<typename PC, typename Context = SingleContext<typename Prop::quant>>
+ static inline void eval(PC &, Data &data, Context ctx,
+ typename PLA_Get<Prop>::time_t,
+ typename Prop::type &fold_state) {
+ fold_state = data.data(ctx.template getptr<typename Prop::quant>()());
+ }
+};
+
+#endif // j9bZiR9W7dKz17gTUOtW1xODHdA
diff --git a/core/pla_getbyname.hpp b/core/pla_getbyname.hpp
new file mode 100644
index 0000000..30f2db0
--- /dev/null
+++ b/core/pla_getbyname.hpp
@@ -0,0 +1,37 @@
+#ifndef fwzTcntkbxdRjyBO90weDhBZ4Nc
+#define fwzTcntkbxdRjyBO90weDhBZ4Nc
+
+#include <string.h>
+
+#include "template_helpers.hpp"
+
+// PLA template
+template<template<typename Prop, typename QuantClass> class Payload,
+ typename BaseCase = Payload<BaseCase, Void>>
+struct PLA_GetByName {
+ // action types & consts
+ typedef BaseCase* result_t;
+ template<typename ContextProp, bool doWriteResults> struct local_state_t {
+ typedef ContextProp prop;
+ };
+
+ // action state
+ char *name;
+ result_t result;
+
+ PLA_GetByName(char *name) : name(name), result(NULL) {}
+
+ // action methods
+ template<typename _PropList, typename _ContextData, typename LocalState>
+ inline void pre(_PropList &pc, _ContextData &data, LocalState &state) {
+ typedef typename LocalState::prop Prop;
+ if (strcmp(Prop::name, name) == 0) {
+ result = new Payload<Prop, typename Prop::quant::class_t>();
+ }
+ }
+
+ template<typename _PropComp, typename _Data, typename _LocalState>
+ inline void post(_PropComp &, _Data &, _LocalState &) { }
+};
+
+#endif // fwzTcntkbxdRjyBO90weDhBZ4Nc
diff --git a/core/pla_init_default.hpp b/core/pla_init_default.hpp
new file mode 100644
index 0000000..a0e0808
--- /dev/null
+++ b/core/pla_init_default.hpp
@@ -0,0 +1,65 @@
+#ifndef CbSv0r4ZjDkLZr4WCEmSXjjwPA0
+#define CbSv0r4ZjDkLZr4WCEmSXjjwPA0
+
+#include <assert.h>
+
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include "template_helpers.hpp"
+#include "time.hpp"
+#include "quant_types.hpp"
+
+#include "model.hpp" // for Weight
+
+namespace PLA_Init_Default_Impl {
+
+template<typename Prop, typename QC = typename Prop::quant::class_t /* == discrete */>
+struct Action {
+ template<typename Data> void operator() (Data &data) {}
+};
+
+template<typename Prop>
+struct Action<Prop, ContinuousPropertyClass> {
+ template<typename Data>
+ void operator() (Data &data) {
+ if (boost::is_same<Weight, Prop>::value ||
+ boost::is_same<SumWeight, Prop>::value ||
+ boost::is_same<TargetSumWeight, Prop>::value)
+ return; // do not set weight .. it is done in convert_topology
+ for (uint64_t i{0};
+ i < Prop::quant::instance_ptr_t::numInstances();
+ i++) {
+ data.data.set(0, i, Prop::initialValue);
+ }
+ }
+};
+
+// init default action
+struct PLA_Init_Default {
+ // action types & consts
+ typedef Void result_t;
+ template<typename ContextProp, bool doWriteResults> struct local_state_t {
+ typedef ContextProp prop;
+ static const bool write = doWriteResults;
+ };
+
+ // action state
+ result_t result;
+
+ // action methods
+ template<typename _PropComp, typename ContextData, typename LocalState>
+ inline void pre(_PropComp &pc, ContextData &data, LocalState &state) {
+ Action<typename LocalState::prop>()(data);
+ }
+
+ template<typename _PropComp, typename _Data, typename _LocalState>
+ inline void post(_PropComp &pc, _Data &data, _LocalState &state) { }
+};
+
+} // ns
+
+using PLA_Init_Default_Impl::PLA_Init_Default;
+
+
+#endif // CbSv0r4ZjDkLZr4WCEmSXjjwPA0
diff --git a/core/pla_initbycopy.hpp b/core/pla_initbycopy.hpp
new file mode 100644
index 0000000..7fe6334
--- /dev/null
+++ b/core/pla_initbycopy.hpp
@@ -0,0 +1,70 @@
+#ifndef IsIx5LlrtRM4hjuaHq11FAgirk
+#define IsIx5LlrtRM4hjuaHq11FAgirk
+
+#include <assert.h>
+
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/mpl/if.hpp>
+
+#include "template_helpers.hpp"
+#include "time.hpp"
+#include "quant_types.hpp"
+
+#include "model.hpp" // for Weight
+
+namespace PLA_InitByCopy_Impl {
+
+using namespace boost;
+using namespace boost::mpl;
+
+template<typename Prop, typename QuantClass = typename Prop::quant::class_t>
+struct Action {
+ template<typename Data>
+ void operator() (Data &, Time) {} // NOOP on discrete quants
+};
+
+template<typename Prop>
+struct Action<Prop, ContinuousPropertyClass> {
+ typedef typename Prop::quant Quant;
+
+ template<typename Data>
+ void operator() (Data &data, Time time) {
+ PropertyInstance<Prop, true> src;
+ typedef typename if_<is_same<Quant, Global>,
+ uint8_t,
+ typename Prop::instance_ptr_t::ptr_t
+ >::type ptr_t;
+ assert(time <= src.data.timeLimit); // we do not want to cause addCheckpoint()
+ for (ptr_t i = 0; i < Prop::instance_ptr_t::numInstances(); i++)
+ data.data.set(src.data.getTime(time, i), i, src.data.getValue(time, i));
+ }
+};
+
+struct PLA_InitByCopy {
+ // action types & consts
+ typedef Void result_t;
+ template<typename ContextProp, bool _doWriteResults> struct local_state_t
+ : Action<ContextProp> {};
+
+ // action state
+ result_t result;
+ Time time;
+
+ PLA_InitByCopy(Time time) : time(time) {}
+
+ // action methods
+ template<typename _PC, typename ContextData, typename LocalState>
+ inline void pre(_PC &, ContextData &data, LocalState &action) {
+ action(data, time);
+ }
+
+ template<typename _PC, typename _Data, typename _LocalState>
+ inline void post(_PC &, _Data &, _LocalState &) { }
+};
+
+} // namespace PLA_InitByCopy_Impl
+
+using PLA_InitByCopy_Impl::PLA_InitByCopy;
+
+#endif // IsIx5LlrtRM4hjuaHq11FAgirk
diff --git a/core/pla_set.hpp b/core/pla_set.hpp
new file mode 100644
index 0000000..1c99cc9
--- /dev/null
+++ b/core/pla_set.hpp
@@ -0,0 +1,79 @@
+#ifndef LVOy9pHh2bcXzO1tZ5oxb80UXy8
+#define LVOy9pHh2bcXzO1tZ5oxb80UXy8
+
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include "property_instance.hpp"
+#include "property_list.hpp"
+#include "quant_types.hpp"
+#include "template_helpers.hpp"
+
+// worker template forward decl
+template<typename Prop, typename CurrentProp, typename Data, typename QuantClass, bool isWrite>
+struct PLA_Set_Impl;
+
+// PLA template
+template<typename Prop>
+struct PLA_Set {
+ // action consts
+ typedef Void result_t;
+ template<typename ContextProp, bool _doWriteResult> struct local_state_t {
+ typedef ContextProp prop;
+ static const bool write = _doWriteResult;
+ };
+
+ // action parameters
+ typedef typename Prop::instance_ptr_t instance_t;
+ typedef typename boost::mpl::if_<boost::is_same<ContinuousPropertyClass, typename Prop::quant::class_t>,
+ Time,
+ FakeTime>::type time_t;
+ typedef typename Prop::type value_t;
+ instance_t instance;
+ time_t time;
+ value_t value;
+ result_t result;
+
+ inline PLA_Set(instance_t instance, value_t value)
+ : instance(instance), value(value) {
+ // ctor only allowed for discrete properties
+ BOOST_STATIC_ASSERT((boost::is_same<DiscretePropertyClass,
+ typename Prop::quant::class_t>::value));
+ }
+ inline PLA_Set(time_t time, instance_t instance, value_t value) : instance(instance), time(time), value(value) { }
+
+ // action methods
+ template<typename _PropComp, typename _ContextData, typename _LocalState>
+ inline void pre(_PropComp &pc, _ContextData &data, _LocalState &state) { }
+
+ template<typename PropComp, typename ContextData, typename LocalState>
+ inline void post(PropComp &pl, ContextData &data, LocalState &state) {
+ BOOST_MPL_ASSERT(( PL_Contains<PL<typename PropComp::properties_t>, Prop> ));
+ PLA_Set_Impl<Prop, typename LocalState::prop, ContextData, typename LocalState::prop::quant::class_t, LocalState::write>
+ ::eval(data, instance, time, value);
+ }
+};
+
+// worker template implementation
+// * do nothing at the wrong type
+template<typename Prop, typename WrongProp, typename Data, typename QuantClass, bool isWrite>
+struct PLA_Set_Impl {
+ static inline void eval(Data &data, typename PLA_Set<Prop>::instance_t instance, typename PLA_Set<Prop>::time_t time, typename Prop::type &value) { }
+};
+
+// * store pointer to the data structure at the correct type
+template<typename Prop, typename Data, bool _isWrite>
+struct PLA_Set_Impl<Prop, Prop, Data, ContinuousPropertyClass, _isWrite> {
+ static inline void eval(Data &data, typename PLA_Set<Prop>::instance_t instance, typename PLA_Set<Prop>::time_t time, typename Prop::type &value) {
+ data.data.set(time, instance(), value);
+ }
+};
+
+template<typename Prop, typename Data, bool _isWrite>
+struct PLA_Set_Impl<Prop, Prop, Data, DiscretePropertyClass, _isWrite> {
+ static inline void eval(Data &data, typename PLA_Set<Prop>::instance_t instance, typename PLA_Set<Prop>::time_t time, typename Prop::type &value) {
+ data.data.set(instance(), value);
+ }
+};
+
+#endif // LVOy9pHh2bcXzO1tZ5oxb80UXy8
diff --git a/core/pla_sync.hpp b/core/pla_sync.hpp
new file mode 100644
index 0000000..7114cb4
--- /dev/null
+++ b/core/pla_sync.hpp
@@ -0,0 +1,47 @@
+#ifndef aVCkmoPnFvf2TxOWrvfVb5qPbZM
+#define aVCkmoPnFvf2TxOWrvfVb5qPbZM
+
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include "property_instance.hpp"
+#include "property_list.hpp"
+#include "quant_types.hpp"
+#include "template_helpers.hpp"
+
+// worker template forward decl
+template<typename Data, bool isWrite /* == false */>
+struct PLA_Sync_Impl {
+ static void eval(Data &) {}
+};
+
+template<typename Data>
+struct PLA_Sync_Impl<Data, true> {
+ static void eval(Data &data) {
+ data.data.sync();
+ }
+};
+
+// PLA template
+struct PLA_Sync {
+ // action consts
+ typedef Void result_t;
+ template<typename ContextProp, bool doWriteResult> struct local_state_t {
+ typedef ContextProp prop;
+ static const bool write = doWriteResult;
+ };
+
+ result_t result;
+
+ // action parameters
+ template<typename _PC, typename _ContextData, typename _LocalState>
+ inline void pre(_PC &, _ContextData &, _LocalState &) {}
+
+
+ template<typename _PC, typename ContextData, typename LocalState>
+ inline void post(_PC &, ContextData &data, LocalState &) {
+ PLA_Sync_Impl<ContextData, LocalState::write>::eval(data);
+ }
+};
+
+#endif // aVCkmoPnFvf2TxOWrvfVb5qPbZM
diff --git a/core/pointers.hpp b/core/pointers.hpp
new file mode 100644
index 0000000..cae5f4b
--- /dev/null
+++ b/core/pointers.hpp
@@ -0,0 +1,213 @@
+#ifndef wOYVH4QhyaNIiefhP4sh9Osro2k
+#define wOYVH4QhyaNIiefhP4sh9Osro2k
+
+#include <assert.h>
+
+#include <iostream>
+
+#include <boost/integer.hpp>
+#include <boost/static_assert.hpp>
+
+#include "simlimits.hpp"
+#include "template_helpers.hpp"
+
+// HINT: the template Ptr<> is defined in quant_types; it is an empty,
+// forbidden basecase anyway
+#include "quant_types.hpp"
+
+namespace PtrImpl {
+
+using boost::is_same;
+
+template<typename Quant, typename IterPtr>
+struct Iter {
+ Iter(IterPtr ptr) : ptr(ptr) {}
+ Ptr<Quant> operator* () const { return Ptr<Quant>(ptr); }
+#define REL(op) bool operator op (Iter i) { return ptr op i.ptr; }
+ REL(!=)
+ REL(==)
+#undef REL
+ Iter& operator++ () { ptr++; return *this; }
+ Iter& operator-- () { ptr--; return *this; }
+ IterPtr ptr;
+};
+
+template<typename Quant, typename IterPtr>
+struct Range {
+ typedef Iter<Quant, IterPtr> iter_t;
+ // init range with raw begin/end ptr or the first and last element
+ // to visit (DIFFERENT SEMANTICS!)
+ Range(IterPtr p1, IterPtr p2) : p1(p1), p2(p2) {}
+ Range(Ptr<Quant> p1, Ptr<Quant> p2) : p1(p1.raw), p2(p2.raw + 1) {}
+ iter_t begin() const { return iter_t(p1); }
+ iter_t end() const { return iter_t(p2); }
+ IterPtr p1, p2;
+};
+
+// we discriminate between storage and iter pointer to allow a zero
+// bit storage pointer while maintaining a conforming iteration
+// strategy
+template<typename Quant, uint64_t instanceCount,
+ typename StoragePtr = typename boost::uint_value_t<instanceCount - 1>::least,
+ typename IterPtr = typename boost::uint_value_t<instanceCount >::least>
+struct Common {
+ typedef StoragePtr ptr_t;
+ typedef Range<Quant, IterPtr> range_t;
+
+ Common() = delete;
+ //Common(const StoragePtr raw) : raw(raw) {}
+ explicit Common(const IterPtr ptr) : raw(ptr) {}
+ const StoragePtr operator() () const { return raw; }
+ Ptr<Quant>& operator++ () { raw++; return FORCE_CONV(Ptr<Quant>, *this); }
+#define REL(op) bool operator op (Common const &i) const { return raw op i.raw; }
+ REL(!=)
+ REL(==)
+ REL(<) REL(<=)
+ REL(>) REL(>=)
+#undef REL
+
+ static range_t all() {
+ BOOST_STATIC_ASSERT((is_same<typename Quant::class_t,
+ ContinuousPropertyClass>::value));
+ return range_t(0, instanceCount);
+ }
+
+ // return instanceCount; different semantic for continuous and
+ // discrete quants, so we use two identical function
+ static constexpr IterPtr numInstances() {
+ BOOST_STATIC_ASSERT((is_same<typename Quant::class_t,
+ ContinuousPropertyClass>::value));
+ return instanceCount;
+ }
+
+ static constexpr IterPtr maxInstances() {
+ BOOST_STATIC_ASSERT((is_same<typename Quant::class_t,
+ DiscretePropertyClass>::value));
+ return instanceCount;
+ }
+
+ StoragePtr raw;
+};
+
+// we define the Common<>-instances later used to maintain
+// one-source-of-truth albeit circular dependencies
+typedef Common<Synapse, maxNeurons * maxSynapsesPerNeuron> CommonSynapse;
+typedef Common<Neuron, maxNeurons> CommonNeuron;
+
+} // NS
+
+////////////////////////////////////////////////////////////////////////////////
+// CONTINOUS PROPERTIES
+////////////////////////////////////////////////////////////////////////////////
+
+#define PTR_DEFAULT_CTOR \
+ explicit Ptr(const ptr_t raw) : Common(raw) {}
+
+template<>
+struct Ptr<Global> : PtrImpl::Common<Global, 1> {
+ Ptr() : Common(0) {}
+ explicit Ptr(const uint64_t raw) : Common(0) { assert(raw == 0); }
+// #define REL(op) bool operator op (Ptr &i) { return raw op i.raw; }
+// REL(!=)
+// REL(==)
+// REL(<) REL(<=)
+// REL(>) REL(>=)
+// #undef REL
+
+
+ inline PtrImpl::CommonNeuron::range_t childs() const;
+};
+
+template<>
+struct Ptr<Neuron> : PtrImpl::CommonNeuron {
+ PTR_DEFAULT_CTOR
+
+
+ inline PtrImpl::CommonSynapse::range_t childs() const;
+};
+
+template<>
+struct Ptr<Synapse> : PtrImpl::CommonSynapse {
+ typedef boost::uint_value_t<maxSynapsesPerNeuron>::least offset_t;
+
+ PTR_DEFAULT_CTOR
+ Ptr(const Ptr<Neuron> neuron, const offset_t synapse)
+ : Common(neuron() * maxSynapsesPerNeuron + synapse) {}
+
+ const Ptr<Neuron> extractNeuron() const {
+ return Ptr<Neuron>(raw / maxSynapsesPerNeuron);
+ }
+ const offset_t extractSynapseOffset() const {
+ return (raw % maxSynapsesPerNeuron);
+ }
+};
+
+// we have to declare childs()-functions after childs' Ptr<>
+
+inline PtrImpl::CommonNeuron::range_t Ptr<Global>::childs() const {
+ return PtrImpl::CommonNeuron::range_t{
+ Ptr<Neuron>{0},
+ Ptr<Neuron>{maxNeurons - 1}};
+}
+
+inline PtrImpl::CommonSynapse::range_t Ptr<Neuron>::childs() const {
+ return PtrImpl::CommonSynapse::range_t{
+ Ptr<Synapse>{*this, 0},
+ Ptr<Synapse>{*this, maxSynapsesPerNeuron - 1}};
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DISCRETE PROPERTIES
+////////////////////////////////////////////////////////////////////////////////
+
+template<>
+struct Ptr<GlobalMsg> : PtrImpl::Common<GlobalMsg, maxGlobalMsg> {
+ PTR_DEFAULT_CTOR
+};
+
+template<>
+struct Ptr<Spike> : PtrImpl::Common<Spike, maxSpikes> {
+ PTR_DEFAULT_CTOR
+};
+
+template<>
+struct Ptr<RandomSpike> : PtrImpl::Common<RandomSpike, maxRandomSpikes> {
+ PTR_DEFAULT_CTOR
+};
+
+template<>
+struct Ptr<SpikeArrival> : PtrImpl::Common<SpikeArrival,
+ maxSpikes * maxSynapsesPerNeuron> {
+ typedef boost::uint_value_t<maxSynapsesPerNeuron>::least offset_t;
+
+ PTR_DEFAULT_CTOR
+ // HINT: offset refers to the topology table of the neuron
+ // corresponding to the given spike, _not_ to the synpase offset of
+ // the receiving neuron
+ Ptr(const Ptr<Spike> spike, const offset_t offset)
+ : Common(spike() * maxSynapsesPerNeuron + offset) {}
+ const Ptr<Spike> extractSpike() const {
+ return Ptr<Spike>(raw / maxSynapsesPerNeuron);
+ }
+};
+
+// Stream I/O
+
+namespace std {
+#define GEN(T) \
+ ostream& operator<< (ostream &os, Ptr<T> val) { return os << (uint64_t) val(); }
+
+GEN(Global)
+GEN(Neuron)
+GEN(Synapse)
+GEN(GlobalMsg)
+GEN(Spike)
+GEN(RandomSpike)
+GEN(SpikeArrival)
+
+#undef GEN
+}
+
+
+
+#endif // wOYVH4QhyaNIiefhP4sh9Osro2k
diff --git a/core/priority_queue.hpp b/core/priority_queue.hpp
new file mode 100644
index 0000000..efcdc7e
--- /dev/null
+++ b/core/priority_queue.hpp
@@ -0,0 +1,146 @@
+#ifndef RIoeyayKWeHMNQr5V3eTPolQ4fQ
+#define RIoeyayKWeHMNQr5V3eTPolQ4fQ
+
+#include <assert.h>
+#include <boost/swap.hpp>
+#include <inttypes.h>
+#include <string.h>
+
+template<typename Val, typename Payload>
+struct PriorityQueue {
+ // types
+ typedef Payload payload_t;
+
+ // creation
+ PriorityQueue();
+ PriorityQueue(const PriorityQueue &);
+
+ // access
+ inline Val& minVal();
+ inline Payload& minPayload();
+ inline void insert(const Val val, const Payload payload);
+ inline void removeMin();
+
+ inline bool isEmpty() const;
+ size_t getSize() const; // returns size in bytes, _not_ # of elements
+
+ // intern
+ typedef uint32_t Id;
+ inline void swap(const Id id1, const Id id2);
+ void heapify(const Id id);
+
+ // data
+ Id length;
+ struct Element {
+ Val val;
+ Payload payload;
+ } heap[0];
+ static const size_t elementSize = sizeof(Element);
+
+};
+
+template<typename Val, typename Payload>
+PriorityQueue<Val, Payload>::PriorityQueue() {
+ length = 0;
+}
+
+template<typename Val, typename Payload>
+PriorityQueue<Val, Payload>::PriorityQueue(const PriorityQueue &src) {
+ length = src.length;
+ memcpy(heap, src.heap, length * sizeof(Element));
+}
+
+
+template<typename Val, typename Payload>
+inline Val& PriorityQueue<Val, Payload>::minVal() {
+ assert(!isEmpty());
+ return heap[0].val;
+}
+
+template<typename Val, typename Payload>
+inline Payload& PriorityQueue<Val, Payload>::minPayload() {
+ assert(!isEmpty());
+ return heap[0].payload;
+}
+
+template<typename Val, typename Payload>
+inline void PriorityQueue<Val, Payload>::insert(const Val val, const Payload payload) {
+ heap[length].val = val;
+ heap[length].payload = payload;
+ length++;
+ heapify(length-1);
+}
+
+template<typename Val, typename Payload>
+void PriorityQueue<Val, Payload>::removeMin() {
+ length--;
+ swap(0, length);
+ heapify(0);
+}
+
+template<typename Val, typename Payload>
+inline bool PriorityQueue<Val, Payload>::isEmpty() const {
+ return (length==0);
+}
+
+template<typename Val, typename Payload>
+size_t PriorityQueue<Val, Payload>::getSize() const {
+ return ((char*) &(heap[length])) - (char*) this;
+}
+
+template<typename Val, typename Payload>
+inline void PriorityQueue<Val, Payload>::swap(const Id id1, const Id id2) {
+ boost::swap(heap[id1], heap[id2]);
+}
+
+template<typename Val, typename Payload>
+void PriorityQueue<Val, Payload>::heapify(const Id id) {
+ Id prev(id),
+ next((id-1)/2);
+
+ // upward
+ while (prev != 0 // this is not the root of the tree
+ && heap[prev].val // and our element can still
+ < heap[next].val // bubble further up ...
+ ) {
+ swap(prev, next);
+ prev = next;
+ next = ((next-1)/2);
+ }
+
+ // downward
+ while (true) {
+ next = 2*prev + 1;
+
+ // no child?
+ if (next >= length)
+ return;
+
+ // one child?
+ if (next == length - 1) {
+ if (heap[next].val < heap[prev].val) {
+ swap(prev, next);
+ continue;
+ }
+ return;
+ }
+
+ // two childs!
+ if ((heap[next].val < heap[next+1].val) && (heap[next].val < heap[prev].val)) {
+ swap(next, prev);
+ prev = next;
+ continue;
+ }
+
+ if ((heap[next+1].val <= heap[next].val) && (heap[next+1].val < heap[prev].val)) {
+ swap(next+1, prev);
+ prev = next+1;
+ continue;
+ }
+
+ // we are bigger than both childs
+ return;
+ }
+}
+
+#endif // RIoeyayKWeHMNQr5V3eTPolQ4fQ
diff --git a/core/property_abbrevations_begin.hpp b/core/property_abbrevations_begin.hpp
new file mode 100644
index 0000000..4aaa409
--- /dev/null
+++ b/core/property_abbrevations_begin.hpp
@@ -0,0 +1,18 @@
+#ifndef YCro2esMYpQbHpc3SnRqHRp4QZI
+#define YCro2esMYpQbHpc3SnRqHRp4QZI
+
+// get a continuous property by name
+// * has to have the same quantor type and will be the same instance
+// * can only be used within the evolve function of a continuous property
+#define _CP(Prop) (Property_Get<Prop>::eval(pc, context, t))
+
+// get a discrete property by name
+// * can only be used in the correct (...?) apply function
+#define _DP(Prop) (Property_Get<Prop>::eval(pc, context))
+
+// get a property from a transaction
+#define _TP(Prop) (transaction.instance.template get<Prop, typename Prop::type>())
+
+#else
+#error previous use of property_abbrevation_begin not closed
+#endif // YCro2esMYpQbHpc3SnRqHRp4QZI
diff --git a/core/property_abbrevations_end.hpp b/core/property_abbrevations_end.hpp
new file mode 100644
index 0000000..3df28c3
--- /dev/null
+++ b/core/property_abbrevations_end.hpp
@@ -0,0 +1,9 @@
+#ifdef YCro2esMYpQbHpc3SnRqHRp4QZI
+#undef YCro2esMYpQbHpc3SnRqHRp4QZI
+
+#undef _DP
+#undef _CP
+
+#else
+#error there is no property_abbrevation_begin to close
+#endif
diff --git a/core/property_access.hpp b/core/property_access.hpp
new file mode 100644
index 0000000..19016e9
--- /dev/null
+++ b/core/property_access.hpp
@@ -0,0 +1,32 @@
+#ifndef VIp1Hrkjsl2bQTTqbsZf9mqNsWY
+#define VIp1Hrkjsl2bQTTqbsZf9mqNsWY
+
+#include "pla_get.hpp"
+#include "context.hpp"
+
+template <typename Prop>
+struct Property_Get {
+ template<typename PropComp, typename Context>
+ static inline typename Prop::type eval(PropComp &pc, Context context) __attribute__ ((pure));
+
+ template<typename PropComp, typename Context>
+ static inline typename Prop::type eval(PropComp &pc, Context context, Time t) __attribute__ ((pure));
+};
+
+template <typename Prop>
+template<typename PropComp, typename Context>
+inline typename Prop::type Property_Get<Prop>::eval(PropComp &pc, Context context) {
+ PLA_Get<Prop, Context> action(context);
+ return pc.call(action);
+}
+
+template <typename Prop>
+template<typename PropComp, typename Context>
+inline typename Prop::type Property_Get<Prop>::eval(PropComp &pc, Context context, Time t) {
+ PLA_Get<Prop, Context> action(t, context);
+ return pc.call(action);
+}
+
+
+
+#endif // VIp1Hrkjsl2bQTTqbsZf9mqNsWY
diff --git a/core/property_composition.hpp b/core/property_composition.hpp
new file mode 100644
index 0000000..39b6984
--- /dev/null
+++ b/core/property_composition.hpp
@@ -0,0 +1,35 @@
+#ifndef XDTdAXIBNQWHy4pABnW9tvtXRks
+#define XDTdAXIBNQWHy4pABnW9tvtXRks
+
+#include <boost/mpl/bool.hpp>
+#include <boost/utility.hpp>
+
+#include "pla_get.hpp"
+#include "property_list.hpp"
+
+template <typename PropList>
+struct PropertyComposition : boost::noncopyable {
+ // your endless journey has come to an end. down here lies the
+ // ACTUAL INSTANCE of the entire simulation!
+ typedef PropList properties_t;
+ PL<properties_t> properties;
+
+ /// data access
+ // call: return value of action is of interest
+ template<typename Action>
+ inline typename Action::result_t call(Action &action) {
+ return properties.call(*this, action);
+ }
+
+ // cast: fire and forget
+ template<typename Action>
+ inline void cast(Action &&action) {
+ properties.call(*this, action);
+ }
+
+ void sync() {
+ properties.sync();
+ }
+};
+
+#endif // XDTdAXIBNQWHy4pABnW9tvtXRks
diff --git a/core/property_instance.hpp b/core/property_instance.hpp
new file mode 100644
index 0000000..74a1a98
--- /dev/null
+++ b/core/property_instance.hpp
@@ -0,0 +1,65 @@
+#ifndef m6EAApyWyIDlhjYO7FswFNLRrB0
+#define m6EAApyWyIDlhjYO7FswFNLRrB0
+
+#include <boost/static_assert.hpp>
+
+#include "checkpoint.hpp"
+#include "ephermal_checkpoint.hpp"
+#include "pointers.hpp"
+#include "quant_types.hpp"
+#include "string_helpers.hpp"
+
+namespace PropertyInstanceImpl {
+
+template <
+ typename Prop,
+ bool doWriteResults,
+ typename Quant = typename Prop::quant,
+ typename QuantClass = typename Prop::quant::class_t
+ > struct PropertyInstance_Container;
+
+template <typename Prop>
+struct PropertyInstance_Container<
+ Prop, true, typename Prop::quant, ContinuousPropertyClass> {
+ PropertyInstance_Container() :
+ data(string(Prop::quant::name) + "_" + string(Prop::name), Prop::initialValue)
+ {}
+ typedef Checkpoint<typename Prop::type,
+ Prop::quant::instance_ptr_t::numInstances()> type;
+ type data;
+};
+
+template <typename Prop>
+struct PropertyInstance_Container<
+ Prop, false, typename Prop::quant, ContinuousPropertyClass> {
+ PropertyInstance_Container() :
+ data(string(Prop::quant::name) + "_" + string(Prop::name), Prop::initialValue)
+ {}
+ typedef EphermalCheckpoint<typename Prop::type,
+ Prop::quant::instance_ptr_t::numInstances()> type;
+ type data;
+};
+
+template <typename Prop, bool doWriteResults>
+struct PropertyInstance_Container<
+ Prop, doWriteResults, typename Prop::quant, DiscretePropertyClass> {
+ PropertyInstance_Container() :
+ data(string(Prop::quant::name) + "_" + string(Prop::name),
+ Prop::instance_ptr_t::maxInstances())
+ {}
+ typedef Vector<
+ typename Prop::type,
+ 8 * Prop::size, // size in [bits]
+ boost::mpl::bool_<doWriteResults>
+ > type;
+ type data;
+};
+
+} // namespace PropertyInstanceImpl
+
+template <typename Prop, bool doWriteResults>
+struct PropertyInstance :
+ PropertyInstanceImpl::PropertyInstance_Container<Prop, doWriteResults> {};
+
+
+#endif // m6EAApyWyIDlhjYO7FswFNLRrB0
diff --git a/core/property_list.hpp b/core/property_list.hpp
new file mode 100644
index 0000000..3fd5ee9
--- /dev/null
+++ b/core/property_list.hpp
@@ -0,0 +1,94 @@
+#ifndef RAA4DT8yVWXBMqy1rxYiM12MKFA
+#define RAA4DT8yVWXBMqy1rxYiM12MKFA
+
+#include <boost/mpl/assert.hpp>
+#include <boost/mpl/empty.hpp>
+#include <boost/mpl/front.hpp>
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/logical.hpp>
+#include <boost/mpl/not.hpp>
+#include <boost/mpl/pop_front.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include "property_instance.hpp"
+#include "template_helpers.hpp"
+
+namespace PLImpl {
+
+ using namespace boost::mpl;
+
+ // forward decls
+ template <typename Haystack, typename Needle> struct PL_Contains;
+
+
+ /// PL - Property List
+
+ // template <typename Head, bool doWriteResults, typename Tail>
+ template <typename List>
+ struct PL {
+ // compile time data structure (types)
+ typedef typename front<List>::type head_t;
+ typedef typename pop_front<List>::type tail_t;
+
+ typedef typename head_t::first prop_t;
+ typedef typename head_t::second doWriteResult_t;
+ typedef typename if_<empty<tail_t>,
+ PL<Void>,
+ PL<tail_t>
+ >::type next_t;
+
+ typedef PropertyInstance<prop_t, doWriteResult_t::value > data_t;
+
+ // access methods
+ // template params:
+ // - PropComp: the list of all properties
+ // - Action: the action class to call
+ template<typename PropComp, typename Action>
+ inline typename Action::result_t call(PropComp &pc, Action &action) {
+ typename Action::template local_state_t<prop_t, doWriteResult_t::value> state;
+ action.pre(pc, data, state);
+ tail.call<PropComp, Action>(pc, action);
+ action.post(pc, data, state);
+ return action.result;
+ }
+
+ // data members
+ data_t data;
+ next_t tail;
+
+ // integrity checks:
+ // 1. each property may be used only once
+ BOOST_MPL_ASSERT(( not_< PL_Contains< next_t, prop_t > > ));
+ // TODO (beauty): dependencies (once they are implemented anywhere)
+ };
+
+ // the empty tail
+ template<>
+ struct PL<Void> {
+ typedef Void prop_t;
+ typedef PL<Void> tail_t;
+ typedef Void data_t;
+
+ template<typename PropComp, typename Action>
+ inline typename Action::result_t call(PropComp &pc, Action &action) {
+ return typename Action::result_t();
+ }
+ };
+
+ /// PL Template Helpers
+ template <typename Haystack, typename Needle>
+ struct PL_Contains : boost::mpl::or_<
+ boost::is_same<typename Haystack::prop_t, Needle>,
+ PL_Contains<typename Haystack::next_t, Needle>
+ > { };
+
+ template <typename Needle>
+ struct PL_Contains<PL<Void>, Needle> : boost::mpl::false_ { };
+
+};
+
+using PLImpl::PL;
+using PLImpl::PL_Contains;
+
+#endif // RAA4DT8yVWXBMqy1rxYiM12MKFA
diff --git a/core/quant_types.hpp b/core/quant_types.hpp
new file mode 100644
index 0000000..8278f30
--- /dev/null
+++ b/core/quant_types.hpp
@@ -0,0 +1,181 @@
+#ifndef sKmf7ztuNbBT3ua3iNX4k5rtsg0
+#define sKmf7ztuNbBT3ua3iNX4k5rtsg0
+
+#include <boost/mpl/begin.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/distance.hpp>
+#include <boost/mpl/find.hpp>
+#include <boost/mpl/joint_view.hpp>
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include "template_helpers.hpp"
+#include "simlimits.hpp"
+
+/// definition of Ptr<> template; template specialization
+/// in pointers.hpp (included at the end of this file)
+template<typename UnknownType>
+// struct Ptr {
+// DO_NOT_INSTANCE(UnknownType);
+// };
+struct Ptr;
+
+/// definition of the different quantor classes
+
+struct DiscretePropertyClass {
+ static const char* const name;
+};
+const char* const DiscretePropertyClass::name = "discrete_property";
+
+struct ContinuousPropertyClass {
+ static const char* const name;
+};
+const char* const ContinuousPropertyClass::name = "continuous_property";
+
+template<typename Wrong>
+struct AverageQueueSize {
+ DO_NOT_INSTANCE(Wrong)
+};
+
+/// definition of the different quantor types
+
+#define GEN_QUANT_PROP(nameT, classT, nameS) \
+class nameT { \
+public: \
+ typedef Ptr<nameT> instance_ptr_t; \
+ typedef classT##PropertyClass class_t; \
+ static const char* const name; \
+}; \
+const char* const nameT::name = nameS;
+
+// EQS: estimated average queue size of related event
+#define GEN_DQ_PROP(nameT, classT, nameS, EQS) \
+ GEN_QUANT_PROP(nameT, classT, nameS) \
+ \
+ template<> \
+ struct AverageQueueSize<nameT> { \
+ static const uint64_t value = EQS; \
+ };
+
+// discrete properties
+GEN_DQ_PROP(GlobalMsg, Discrete, "global_msg", 10);
+GEN_DQ_PROP(Spike, Discrete, "spike", maxNeurons);
+GEN_DQ_PROP(RandomSpike, Discrete, "rand_spike", maxNeurons);
+GEN_DQ_PROP(SpikeArrival, Discrete, "spike_arrival", 1);
+
+// continuous properties
+GEN_QUANT_PROP(Global, Continuous, "global");
+GEN_QUANT_PROP(Neuron, Continuous, "neuron");
+GEN_QUANT_PROP(Synapse, Continuous, "synapse");
+
+#undef GEN_QUANT_PROP
+#undef GEN_DQ_PROP
+
+/// quantor type lists
+namespace QuantTypeImpl {
+ using namespace boost::mpl;
+
+ typedef vector<
+ Global, Neuron, Synapse
+ > ContinuousQuantorList;
+
+ // discrete properties are sorted by likelyhood of their occuring
+ // events; also Spike has to have a lower RuntimeID than
+ // SpikeArrival for simulation correctness during replay!
+ typedef vector<
+ Spike, SpikeArrival, RandomSpike, GlobalMsg
+ > DiscreteQuantorList;
+
+ typedef joint_view<
+ DiscreteQuantorList, ContinuousQuantorList
+ > QuantorList;
+
+ /// runtime IDs
+
+ template<typename T>
+ struct RuntimeID {
+ static const uint8_t value = distance<
+ begin<QuantorList>::type,
+ typename find<QuantorList, T>::type
+ >::value;
+ };
+}
+
+using QuantTypeImpl::ContinuousQuantorList;
+using QuantTypeImpl::DiscreteQuantorList;
+using QuantTypeImpl::QuantorList;
+using QuantTypeImpl::RuntimeID;
+
+/// parent-child relations
+
+template<typename Quant> struct QuantChild;
+
+#define GEN_QC(P,C) \
+ template<> struct QuantChild<P> { \
+ typedef C type; \
+ };
+
+GEN_QC(Global, Neuron);
+GEN_QC(Neuron, Synapse);
+GEN_QC(Spike, SpikeArrival); // useless, potentially dangerous
+
+#undef GEN_QC
+
+/// definition of receivers of discrete properties
+/// HINT: in case of multiple receivers the lowest quant in the
+/// context hierarchy is called
+
+template<typename NoMatch>
+struct QuantDestinationQuant {
+ DO_NOT_INSTANCE(NoMatch);
+};
+
+#define GEN_QDQ(Src,Dst) \
+template<> \
+struct QuantDestinationQuant<Src> { \
+ typedef Dst type; \
+};
+
+/// definition of the events a cont. quant can create; defaults to no
+/// events and has to be extended by model description via template
+/// specialization
+
+template<typename ContQ, typename DiscQ>
+struct QuantMayEmit {
+ typedef boost::mpl::false_ result;
+ bool operator() () { return false; }
+};
+
+template<typename ContQ, typename DiscQ>
+struct QuantEmitDefault : boost::mpl::bool_<false> {};
+
+#define GEN_QUANT_EMIT(CQ, DQ, Default) \
+ template<> \
+ struct QuantMayEmit<CQ, DQ> { \
+ typedef boost::mpl::true_ result; \
+ bool operator() () { return true; } \
+ }; \
+ \
+ template<> \
+ struct QuantEmitDefault<CQ, DQ> : boost::mpl::bool_<Default> {};
+
+/// definition if the event linked to a discrete property has a (per
+/// event) variable delay; defaults false
+
+template<typename DiscQ>
+struct QuantHasVarDelay {
+ typedef boost::mpl::false_ result;
+};
+
+#define GEN_QUANT_HASVARDELAY(DQ) \
+ template<> \
+ struct QuantHasVarDelay<DQ> { \
+ typedef boost::mpl::true_ result; \
+};
+
+// we include pointers here, because they rely on the quant classes to
+// be defined
+#include "pointers.hpp"
+
+#endif // sKmf7ztuNbBT3ua3iNX4k5rtsg0
diff --git a/core/replay.cpp b/core/replay.cpp
new file mode 100644
index 0000000..73f0c44
--- /dev/null
+++ b/core/replay.cpp
@@ -0,0 +1,99 @@
+#include <assert.h>
+#include <errno.h>
+#include <iostream>
+#include <stdlib.h>
+
+#include <boost/type_traits/is_same.hpp>
+
+#include "everything_else.hpp"
+#include "pla_getbyname.hpp"
+#include "sim_replay.hpp"
+#include "system_helpers.hpp"
+#include "template_helpers.hpp"
+#include "time.hpp"
+
+#include "model.hpp"
+
+using namespace std;
+
+template<typename Prop, typename QuantClass = typename Prop::quant::class_t>
+struct Replay;
+
+template<>
+struct Replay<BaseCase, Void> {
+ virtual void operator() (TimeSpan span, IdList<uint64_t> &ids) {
+ assert(false);
+ }
+};
+
+template<typename Prop>
+struct Replay<Prop, ContinuousPropertyClass> : Replay<BaseCase, Void> {
+ typedef typename Prop::quant Quant;
+
+ virtual void operator() (TimeSpan span, IdList<uint64_t> &raw_ids) {
+ IdList<typename Quant::instance_ptr_t::ptr_t> ids(raw_ids);
+ for (auto i : ids)
+ assert(i < Ptr<Quant>::numInstances());
+ SimReplay<Lists::all_ro, Quant> simReplay{ids, span.begin()()};
+
+ // header
+ cout << "# " << Quant::name << "\n# time";
+ for (auto i : ids)
+ cout << "\t" << (uint64_t) i;
+ cout << endl;
+
+ // body
+ for (TimeSpan::iterator t=span.begin(); t.hasNext(); ++t) {
+ cout << t()();
+ for (auto i : ids)
+ cout << "\t" << simReplay.template get<Prop>(Ptr<Quant>(i), t());
+ cout << endl;
+ }
+ }
+};
+
+template<typename Prop>
+struct Replay<Prop, DiscretePropertyClass> : Replay<BaseCase, Void> {
+ virtual void operator() (TimeSpan span, IdList<uint64_t> &raw_ids) {
+ cerr << Prop::name << " is a discrete property" << endl;
+ exit(-1);
+ }
+};
+
+int realmain(int argc, char **argv) __attribute__((noinline));
+int realmain(int argc, char **argv) {
+ if (argc != 6) {
+ cout << "Usage: " << argv[0] << " property instance start stop delta" << endl;
+ return -1;
+ }
+
+ garantueeStackSize(64 * 1024 * 1024);
+
+ // read cmd line params
+ Replay<BaseCase, Void> *replay(NULL);
+ {
+ PropertyComposition<Lists::all_ro> pc;
+ PLA_GetByName<Replay> pla(argv[1]);
+ replay = pc.call(pla);
+ assert(replay != NULL);
+ }
+ errno = 0;
+ char *tail;
+ IdList<uint64_t> ids(argv[2]);
+ Time start(strtod(argv[3], &tail)); assert(*tail == 0);
+ Time stop( strtod(argv[4], &tail)); assert(*tail == 0);
+ Time delta(strtod(argv[5], &tail)); assert(*tail == 0);
+ assert(errno == 0);
+ TimeSpan span(start, stop, delta);
+
+ // replay simulation
+ (*replay)(span, ids);
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ garantueeStackSize(64 * 1024 * 1024);
+ assertSimDir();
+ return realmain(argc, argv);
+}
diff --git a/core/report_names.cpp b/core/report_names.cpp
new file mode 100644
index 0000000..0243daf
--- /dev/null
+++ b/core/report_names.cpp
@@ -0,0 +1,15 @@
+#include <iostream>
+
+#include "pla_debug_name.hpp"
+#include "property_composition.hpp"
+
+#include "mempool.hpp"
+
+#include "model.hpp"
+
+int main() {
+ PropertyComposition<Lists::all> allProperties;
+ PLA_Debug_Name action_debug;
+ allProperties.call(action_debug);
+ std::cout << action_debug.result << std::endl;
+}
diff --git a/core/report_runtimeid.cpp b/core/report_runtimeid.cpp
new file mode 100644
index 0000000..0e06afd
--- /dev/null
+++ b/core/report_runtimeid.cpp
@@ -0,0 +1,19 @@
+#include <iostream>
+
+#include <boost/mpl/for_each.hpp>
+
+#include "quant_types.hpp"
+
+using namespace std;
+
+struct printer {
+ template<typename T>
+ void operator() (T x) {
+ cout << T::name << ":\t" << (int) RuntimeID<T>::value << endl;
+ }
+};
+
+int main()
+{
+ boost::mpl::for_each<QuantorList>(printer());
+}
diff --git a/core/report_spacereq.cpp b/core/report_spacereq.cpp
new file mode 100644
index 0000000..f9df0c2
--- /dev/null
+++ b/core/report_spacereq.cpp
@@ -0,0 +1,15 @@
+#include <iostream>
+
+#include "pla_debug_space.hpp"
+#include "property_composition.hpp"
+
+#include "mempool.hpp"
+
+#include "model.hpp"
+
+int main() {
+ Lists::all allProperties;
+ PLA_Debug_Space action_debug;
+ allProperties.call(action_debug);
+ std::cout << action_debug.generateReport() << std::endl;
+}
diff --git a/core/rng.hpp b/core/rng.hpp
new file mode 100644
index 0000000..a8d88f6
--- /dev/null
+++ b/core/rng.hpp
@@ -0,0 +1,83 @@
+#ifndef eyNJdhz0jqVQc4zddlEi67woThg
+#define eyNJdhz0jqVQc4zddlEi67woThg
+
+// TODO: use proper PRNG
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <math.h>
+#include <boost/random.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/random/exponential_distribution.hpp>
+#include <boost/random/variate_generator.hpp>
+#include <boost/static_assert.hpp>
+
+#include "template_helpers.hpp"
+
+#include <boost/random/ranlux.hpp>
+#include <boost/random/additive_combine.hpp>
+
+namespace RNG {
+ typedef boost::ecuyer1988 generator;
+ struct seed_t {
+ generator rng;
+
+ seed_t() : rng(0) {}
+ template<typename T>
+ explicit seed_t(T x) : rng(x + 17 * x + 257 * x) {}
+
+ seed_t & operator= (seed_t x) {
+ rng = x.rng;
+ return *this;
+ }
+ template<typename T>
+ seed_t & operator= (T x) {
+ rng.seed(x);
+ return *this;
+ }
+ };
+
+ seed_t next(seed_t last, int amount=1) {
+ boost::uniform_int<uint64_t> dist;
+ for (int i=0; i<amount; i++)
+ dist(last.rng);
+ return last;
+ }
+
+ seed_t split(seed_t old) {
+ boost::uniform_int<uint64_t> dist(0, -1);
+ uint64_t s = 0;
+ for (int i=0; i<37; i++) {
+ s ^= dist(old.rng);
+ s ^= ~(s << 1);
+ }
+ // std::cout << "new seed: " << s << std::endl;
+ return seed_t(s);
+ }
+
+ uint32_t integer(seed_t s, uint32_t num) {
+ boost::uniform_int<uint32_t> gen(0, num-1);
+ return gen(s.rng);
+ }
+
+ // returns val \in [0,1)
+ double equi(seed_t s) {
+ boost::uniform_01<double> dist;
+ return dist(s.rng);
+ }
+
+ double expo(seed_t s, double mean) {
+ typedef boost::exponential_distribution<double> dist;
+ boost::variate_generator<generator &, dist> gen(s.rng, dist(1.0 / mean));
+ double res = gen();
+ return res;
+ }
+}
+
+namespace std {
+ std::ostream& operator<< (std::ostream &os, RNG::seed_t s) {
+ return os << "rand48(" << s.rng << ")";
+ }
+}
+
+#endif // eyNJdhz0jqVQc4zddlEi67woThg
diff --git a/core/scalar.hpp b/core/scalar.hpp
new file mode 100644
index 0000000..cbab5e6
--- /dev/null
+++ b/core/scalar.hpp
@@ -0,0 +1,58 @@
+#ifndef LOp9uF4R8c3Nq3YZQrpOlN8rCLE
+#define LOp9uF4R8c3Nq3YZQrpOlN8rCLE
+
+#include <inttypes.h>
+#include <boost/static_assert.hpp>
+#include <string>
+
+#include "mempool.hpp"
+
+using std::string;
+
+template<typename T, long long width = 8 * sizeof(T)>
+struct Scalar {
+ explicit Scalar(const string name);
+
+ inline T & operator() () const;
+ inline T get() const;
+ inline void set(const T value) const;
+ void sync() const;
+
+ // associated memory container
+ MemPool mem;
+
+ BOOST_STATIC_ASSERT((width > 0));
+
+private:
+ // Scalar();
+};
+
+// Implementation
+template<typename T, long long width>
+Scalar<T, width>::Scalar(const string name) : mem((width + 7) / 8, name) {
+}
+
+template<typename T, long long width>
+inline T & Scalar<T, width>::operator() () const {
+ return *((T*) mem());
+}
+
+
+template<typename T, long long width>
+inline T Scalar<T, width>::get() const {
+ return (*this)();
+}
+
+template<typename T, long long width>
+inline void Scalar<T, width>::set(const T value) const {
+ // only a single value is in a scalar so we do not require bit-level
+ // access
+ (*this)() = value;
+}
+
+template<typename T, long long width>
+void Scalar<T, width>::sync() const {
+ mem.sync();
+}
+
+#endif // LOp9uF4R8c3Nq3YZQrpOlN8rCLE
diff --git a/core/signal_handler.hpp b/core/signal_handler.hpp
new file mode 100644
index 0000000..87a1353
--- /dev/null
+++ b/core/signal_handler.hpp
@@ -0,0 +1,34 @@
+#ifndef WvCIARcg6KvWbOCcoxmM1lc74OI
+#define WvCIARcg6KvWbOCcoxmM1lc74OI
+
+#include <assert.h>
+#include <signal.h>
+
+volatile bool terminationRequested = false;
+
+void sigIntHandler(int sig) {
+ terminationRequested = true;
+}
+
+void installSigIntHandler() {
+ struct sigaction action;
+ action.sa_handler = sigIntHandler;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ assert(sigaction(SIGINT, &action, NULL) == 0);
+
+}
+
+void sigIntExit() {
+ // restore old SIG INT handler ...
+ struct sigaction action;
+ action.sa_handler = SIG_DFL;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ assert(sigaction(SIGINT, &action, NULL) == 0);
+
+ // ... and use it for suicide
+ kill(getpid(), SIGINT);
+}
+
+#endif // WvCIARcg6KvWbOCcoxmM1lc74OI=
diff --git a/core/sim_causality.hpp b/core/sim_causality.hpp
new file mode 100644
index 0000000..239a070
--- /dev/null
+++ b/core/sim_causality.hpp
@@ -0,0 +1,177 @@
+#ifndef GyWue2EL4TyiAsNv0XegfFL4jk
+#define GyWue2EL4TyiAsNv0XegfFL4jk
+
+#include <map>
+
+#include "sim_replay.hpp"
+
+// discrete property Egal
+struct Egal {
+ typedef uint8_t type;
+ typedef SpikeArrival quant;
+ typedef SpikeArrival::instance_ptr_t instance_ptr_t;
+ static const uint32_t size = 2;
+ static const char* const name;
+};
+const char* const Egal::name = "Egal";
+
+namespace SimCausalityImpl {
+
+using namespace boost::mpl;
+using namespace boost;
+namespace MC = ModelConsts;
+
+template<typename PropList> struct SimCausality;
+
+template<typename ReplayQuant, typename Quant>
+struct MaybeTrackEvent {
+ template<typename Sim>
+ void operator() (Sim &sim) {
+ // we handle every event but only track those affecting neurons
+ auto &sg = static_cast<SimCausality<typename Sim::PropComp::properties_t>&>(sim);
+ if (is_same<Quant, SpikeArrival>::value) {
+ sg.handleSA();
+ }else if (is_same<Quant, RandomSpike>::value) {
+ sg.handleRand();
+ }else{
+ sim.template handleEvent<Quant>();
+ }
+ }
+
+ typedef MaybeTrackEvent<ReplayQuant, Quant> impl;
+};
+
+template<typename PropList>
+struct SimCausality : public SimReplay<PropList, Neuron, MaybeTrackEvent> {
+ typedef SimReplay<PropList, Neuron, MaybeTrackEvent> Super;
+ using Super::queues;
+ using Super::pc;
+ using Super::ct;
+ using Super::handleEvent;
+
+ SimCausality(Time start)
+ : Super(IdList<uint16_t>((char*) "0-999"), start),
+ totalMarks{},
+ trueMarks{},
+ inactiveNeurons(1000),
+ hasFired{}
+ {
+ if (start == Time(0)) {
+ // special case: at t=0 all neurons are have zero membrane
+ // voltage and can be used for analysis before firing the first
+ // time
+ inactiveNeurons = 0;
+ for (int i=0; i<1000; i++)
+ hasFired[i] = true;
+ }
+ }
+
+ bool run(const Time until, uint64_t maxEvents) __attribute__((noinline)) {
+ return Super::run(until, maxEvents);
+ }
+
+ void handleRand() {
+ Ptr<Neuron> neuron(queues.get<RandomSpike>().minPayload().dst);
+ Ptr<SpikeArrival> fakeSA(Index<SpikeArrival>::nil());
+ handleDiff(neuron, fakeSA, MC::RandomSpikeWeight,
+ &SimCausality<PropList>::template handleEvent<RandomSpike>);
+ }
+
+ void handleSA() {
+ auto &event(queues.get<SpikeArrival>().minPayload());
+ Ptr<SpikeArrival> sa (event.src.get<0>());
+ Ptr<Synapse> syn (event.src.get<1>());
+ Ptr<Neuron> neuron(event.dst);
+ PLA_Get<Weight> getWeight (ct, syn);
+ Weight::type weight(pc.call(getWeight));
+ handleDiff(neuron, sa, weight,
+ &SimCausality<PropList>::template handleEvent<SpikeArrival>);
+ }
+
+ void handleDiff(Ptr<Neuron> neuron, Ptr<SpikeArrival> sa, Voltage::type diff,
+ bool (SimCausality<PropList>::*handleEvent)()) {
+ PLA_Get<Voltage> getVoltage (ct, neuron);
+ PLA_Get<IPCoeff1> getIPCoeff1(ct, neuron);
+ Voltage::type preEventVoltage(pc.call(getVoltage));
+ IPCoeff1::type ipCoeff1 (pc.call(getIPCoeff1));
+ bool evokedSpike = (this->*handleEvent)();
+ auto &openExc(this->openExc[neuron()]);
+ auto &openInh(this->openInh[neuron()]);
+
+ if (!hasFired[neuron()]) {
+ if (evokedSpike) {
+ hasFired[neuron()] = true;
+ inactiveNeurons--;
+ if (!inactiveNeurons)
+ lastNeuronActivation = ct;
+ }
+ return;
+ }
+
+ if (evokedSpike) {
+ // check exc. list against voltage diff
+ Time wntGap = ct + wntNorm(diff + preEventVoltage
+ - MC::FireThreshold - ipCoeff1);
+ for (auto i = openExc.lower_bound(wntGap);
+ i != openExc.end();) {
+ mark(i->second, 0);
+ openExc.erase(i++);
+ }
+
+ // mark own spike
+ mark(sa, 0);
+
+ // mark remainig inh/exc spikes as q>0, clear buffers
+ for (auto i : openExc) mark(i.second, 1); openExc.clear();
+ for (auto i : openInh) mark(i.second, 1); openInh.clear();
+ }else{
+ if (diff < 0) {
+ // add to inh. list
+ Time wnt = ct + wntNorm(- diff);
+ openInh.insert(std::make_pair(wnt, sa));
+ }else{
+ // add to exc. list
+ Time wntSelf = ct + wntNorm(diff);
+ openExc.insert(std::make_pair(wntSelf, sa));
+
+ // check inh. list against voltage gap
+ PLA_Get<Voltage> pla_get(ct, neuron);
+ Voltage::type voltage = pc.call(pla_get);
+ Time wntGap = ct + wntNorm(MC::FireThreshold + ipCoeff1 - voltage);
+ for (auto i = openInh.lower_bound(wntGap);
+ i != openInh.end();) {
+ mark(i->second, 0);
+ openInh.erase(i++);
+ }
+ }
+ }
+ }
+
+ void mark(Ptr<SpikeArrival> ptr, bool m) {
+ bool isSA = ptr() != Index<SpikeArrival>::nil();
+ totalMarks[isSA]++;
+ trueMarks[isSA] += !m;
+ if (isSA)
+ egalPC.cast(PLA_Set<Egal>(ptr, 1+m)); // unset values are encoded as zero
+ }
+
+ Time wntNorm(Voltage::type diff) {
+ return MC::Tau_Voltage * log(diff);
+ }
+
+ PropertyComposition<boost::mpl::list<
+ boost::mpl::pair<Egal, boost::mpl::bool_<true>>
+ >> egalPC;
+ uint64_t totalMarks[2],
+ trueMarks[2];
+ uint16_t inactiveNeurons;
+ Time lastNeuronActivation;
+ bool hasFired[maxNeurons];
+ std::multimap<Time, Ptr<SpikeArrival>> openInh[maxNeurons], openExc[maxNeurons];
+};
+
+} // NS
+
+using SimCausalityImpl::SimCausality;
+
+#endif // GyWue2EL4TyiAsNv0XegfFL4jk
diff --git a/core/sim_loop.hpp b/core/sim_loop.hpp
new file mode 100644
index 0000000..0ef748d
--- /dev/null
+++ b/core/sim_loop.hpp
@@ -0,0 +1,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
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
diff --git a/core/simlimits.hpp b/core/simlimits.hpp
new file mode 100644
index 0000000..6680bcd
--- /dev/null
+++ b/core/simlimits.hpp
@@ -0,0 +1,18 @@
+#ifndef q9BbYVk1ebyTzHeB6vbWj8BXsIA
+#define q9BbYVk1ebyTzHeB6vbWj8BXsIA
+
+#include <inttypes.h>
+
+const uint64_t maxNeurons = 2048; // 2^11
+const uint64_t maxSpikes = 1073741824; // 2^30
+const uint64_t maxRandomSpikes = 1073741824; // 2^30
+const uint64_t maxGlobalMsg = 1073741824; // 2^30
+const uint8_t maxSynapsesPerNeuron = 128; // 2^7
+
+const uint64_t maxCheckpoints = 1024; // 2^10
+//const uint64_t maxCheckpoints = 1048576; // 2^20
+const double checkpointInterval = 10.0;
+
+const uint64_t numActualNeurons = 1000; // all above are abused
+
+#endif // q9BbYVk1ebyTzHeB6vbWj8BXsIA
diff --git a/core/simulate.cpp b/core/simulate.cpp
new file mode 100644
index 0000000..7205308
--- /dev/null
+++ b/core/simulate.cpp
@@ -0,0 +1,77 @@
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/pair.hpp>
+#include <iostream>
+
+#include "everything_else.hpp"
+#include "perftools.hpp"
+#include "signal_handler.hpp"
+#include "sim_loop.hpp"
+
+#include "mempool.hpp"
+
+#include "model.hpp"
+
+using namespace std;
+
+int main(int argc, char **argv) {
+ // init sim env
+ const uint64_t eventsPerChunk = 100000;
+ uint64_t totalEventsProcessed(0);
+ installSigIntHandler();
+ assertSimDir();
+
+ // parse command line args
+ assert(argc == 2);
+ Time until(atof(argv[1]));
+
+ {
+ SimLoop<Lists::all> sim;
+
+ Time startTime(sim.currentTime()), oldTime(startTime);
+ cout << "simulating from " << oldTime()
+ << " to " << until() << endl;
+
+ // run for requested time
+ Timer timerAll;
+ while (oldTime < until && !terminationRequested) {
+ uint64_t eventsProcessed = eventsPerChunk - sim.run(until, eventsPerChunk);
+ totalEventsProcessed += eventsProcessed;
+ Time newTime(sim.currentTime()),
+ dt(newTime - oldTime);
+ cout << "\r\033[K"
+ << newTime() << "\t"
+ << eventsProcessed / dt() << " Hz(v)\t"
+ << totalEventsProcessed / timerAll.diff() << " Hz(p)\t"
+ << totalEventsProcessed << " events\t";
+ if (newTime < until)
+ cout << "ETA " << ceil( (until() - newTime())
+ / (newTime() - startTime())
+ * timerAll.diff());
+ cout << flush;
+ oldTime = newTime;
+ }
+
+ if (terminationRequested) {
+ cout << " ... received SIGINT, terminating" << endl;
+ }else{
+ cout << "\r\033[K";
+ }
+
+ // print summary
+ cout << "simulated " << totalEventsProcessed << " events "
+ << "in " << timerAll.diff() << " s "
+ << "(" << totalEventsProcessed / timerAll.diff() << " Hz(p))"
+ << endl;
+
+ // sync to disk
+ cout << "syncing ... " << flush;
+ Timer timerSync;
+ sim.sync();
+ cout << "done (" << timerSync.diff() << "s)" << endl;
+
+ if (terminationRequested)
+ sigIntExit();
+ }
+
+ return 0;
+}
diff --git a/core/spike_in.cpp b/core/spike_in.cpp
new file mode 100644
index 0000000..73a5649
--- /dev/null
+++ b/core/spike_in.cpp
@@ -0,0 +1,64 @@
+#include <assert.h>
+#include <errno.h>
+#include <iostream>
+#include <stdlib.h>
+
+#include "everything_else.hpp"
+#include "filter.hpp"
+#include "index.hpp"
+#include "index_spike.hpp"
+#include "multi_queue.hpp"
+
+using std::cout;
+using std::endl;
+using boost::make_tuple;
+
+int main(int argc, char **argv) {
+ // read cmd line params
+ if (argc != 4) {
+ cout << "Usage: " << argv[0] << " instance start until" << endl;
+ return -1;
+ }
+ errno = 0;
+ char *tail;
+ IdList<Ptr<Neuron>::ptr_t> ids(argv[1]);
+ const Time start(strtod(argv[2], &tail)); assert(*tail == 0);
+ const Time until(strtod(argv[3], &tail)); assert(*tail == 0);
+ assert(errno == 0);
+ for (auto id : ids)
+ assert(id < Ptr<Neuron>::numInstances());
+
+ assertSimDir();
+
+ {
+ MultiQueue<
+ Time, FilterPayload,
+ boost::mpl::list<SpikeArrival, RandomSpike>,
+ FilterContainer> queues(Filter<SpikeArrival>(ids, start),
+ Filter<RandomSpike> (ids, start));
+
+ // output
+ Time ct(start);
+ cout << "# time\tsrc\tdst" << endl;
+ while ((ct = queues.min()) <= until) {
+ cout << ct() << '\t';
+ switch (queues.minType()) {
+ case RuntimeID<SpikeArrival>::value:
+ cout << queues.get<SpikeArrival>().index.src
+ (queues.get<SpikeArrival>().minPayload().src.get<0>().extractSpike()())
+ << '\t' << queues.get<SpikeArrival>().minPayload().dst();
+ queues.removeMin<SpikeArrival>(ct);
+ break;
+ case RuntimeID<RandomSpike>::value:
+ cout << "R\t" << queues.get<RandomSpike>().minPayload().dst();
+ queues.removeMin<RandomSpike>(ct);
+ break;
+ default:
+ assert(false);
+ }
+ cout << endl;
+ }
+}
+
+ return 0;
+}
diff --git a/core/spike_out.cpp b/core/spike_out.cpp
new file mode 100644
index 0000000..2626353
--- /dev/null
+++ b/core/spike_out.cpp
@@ -0,0 +1,46 @@
+#include <assert.h>
+#include <errno.h>
+#include <iostream>
+#include <stdlib.h>
+
+#include "everything_else.hpp"
+#include "index.hpp"
+#include "index_spike.hpp"
+
+#include "mempool.hpp"
+
+using namespace std;
+
+int main(int argc, char **argv) {
+ // read cmd line params
+ assert(argc == 4);
+ errno = 0;
+ char *tail;
+ Ptr<Neuron> addr(strtoul(argv[1], &tail, 10)); assert(*tail == 0);
+ Time start(strtod( argv[2], &tail)); assert(*tail == 0);
+ Time stop(strtod( argv[3], &tail)); assert(*tail == 0);
+ assert(errno == 0);
+ assert(addr() < Ptr<Neuron>::numInstances());
+
+ assertSimDir();
+
+ {
+ // go to first spike with time >= start
+ Index<Spike> idx;
+ Ptr<Spike>::ptr_t cur(idx.first(start, addr));
+
+ // no spike found?
+ if (cur == idx.nil())
+ return 0;
+
+ // output
+ cout << "# time of outgoing spikes from neuron " << addr()
+ << " between " << start() << " and " << stop() << endl;
+ while (cur != idx.nil() && idx.time(cur) <= stop) {
+ cout << idx.time(cur) << endl;
+ cur = idx.next(cur);
+ }
+ }
+
+ return 0;
+}
diff --git a/core/string_helpers.hpp b/core/string_helpers.hpp
new file mode 100644
index 0000000..a35448b
--- /dev/null
+++ b/core/string_helpers.hpp
@@ -0,0 +1,36 @@
+#ifndef M6lbZdsknZWfvEr3i3hoi7EZO8M
+#define M6lbZdsknZWfvEr3i3hoi7EZO8M
+
+#include <math.h>
+#include <sstream>
+#include <string>
+
+template<int> struct SISuffix { };
+
+const char microSISuffixName[6] = { 'm', '~', 'n', 'p', 'f', 'a' };
+const char macroSISuffixName[7] = { 'K', 'M', 'G', 'T', 'P', 'E', 'Y' };
+
+int calcSISuffixId(double val, int base=1000) {
+ if (val >= base) return 1 + calcSISuffixId(val / base);
+ if (val < 1) return -1 + calcSISuffixId(val * base);
+ return 0;
+}
+
+std::string SISuffixify(double val, int base=1000) {
+ int id = calcSISuffixId(val, base);
+ assert(id >= -6);
+ assert(id <= 7);
+
+ std::ostringstream result;
+
+ result << val / pow(base, id) << " ";
+ if (id < 0)
+ result << microSISuffixName[-id - 1];
+ if (id > 0)
+ result << macroSISuffixName[ id - 1];
+
+ return result.str();
+}
+
+
+#endif // M6lbZdsknZWfvEr3i3hoi7EZO8M
diff --git a/core/system_helpers.hpp b/core/system_helpers.hpp
new file mode 100644
index 0000000..75e0d1d
--- /dev/null
+++ b/core/system_helpers.hpp
@@ -0,0 +1,15 @@
+#ifndef AWHaeL8KnNSHrAOreOTeQZXxBG8
+#define AWHaeL8KnNSHrAOreOTeQZXxBG8
+
+#include <sys/resource.h>
+
+void garantueeStackSize(rlim_t size) {
+ struct rlimit rl;
+ assert(getrlimit(RLIMIT_STACK, &rl) == 0);
+ if (rl.rlim_cur < size) {
+ rl.rlim_cur = size;
+ assert(setrlimit(RLIMIT_STACK, &rl) == 0);
+ }
+}
+
+#endif // AWHaeL8KnNSHrAOreOTeQZXxBG8
diff --git a/core/template_helpers.hpp b/core/template_helpers.hpp
new file mode 100644
index 0000000..01a27b5
--- /dev/null
+++ b/core/template_helpers.hpp
@@ -0,0 +1,121 @@
+#ifndef LY1b9novVl8oDseRTw8dH5lzpNo
+#define LY1b9novVl8oDseRTw8dH5lzpNo
+
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_empty.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/is_fundamental.hpp>
+#include <boost/mpl/unpack_args.hpp>
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/mpl/deref.hpp>
+#include <boost/mpl/next.hpp>
+#include <boost/mpl/begin.hpp>
+#include <boost/mpl/end.hpp>
+#include <boost/mpl/front.hpp>
+#include <boost/mpl/pop_front.hpp>
+
+
+#define STATIC_ASSERT_IS_POWER_OF_TWO(x) BOOST_STATIC_ASSERT( !(x & (x-1)) );
+
+template<typename T, long long numerator, long long denominator = 1>
+struct StaticVal {
+ inline static const T value() { return T(numerator) / T(denominator); }
+};
+
+// forcing a type conversion of non-ptr types
+#define FORCE_CONV(Type, Val) (*(reinterpret_cast<Type *>(& Val)))
+
+// generate a constructor which fails when called
+// TODO (beauty): catch error after optimization, before runtime
+// (e.g. by linking to a forbidden symbol)
+#define GEN_ANYCAST_CTOR_3(name) \
+ template<class T1, class T2, class T3> name(T1 t1, T2 t2, T3 t3)
+
+// a void you may return
+struct Void {
+ typedef Void type; // for metaprogramming brainfucks
+ typedef Void con_arg_t;
+};
+
+// just to beautify some code
+struct BaseCase {};
+
+// prevent instanciation of default or unimplemented cases
+#define DO_NOT_INSTANCE(T) BOOST_STATIC_ASSERT((false && boost::is_same<T,T>::value));
+
+// forward decl of a function which will never exist (allows showing
+// errors at link time: later than DO_NOT_INSTANCE but before
+// assert(false)
+void oOoOo_LINK_TIME_ASSERTION_FAILED_oOoOo() __attribute__ ((noreturn));
+#define DO_NOT_CALL {oOoOo_LINK_TIME_ASSERTION_FAILED_oOoOo();}
+
+namespace UnpackTypeListImpl {
+
+using namespace boost::mpl;
+
+template<template<typename... T> class Tgt,
+ typename Iter, typename EndIter,
+ typename... NewList>
+struct Action {
+ typedef typename Action<Tgt,
+ typename next<Iter>::type, EndIter,
+ NewList...,
+ typename deref<Iter>::type
+ >::type type;
+};
+
+template<template<typename... T> class Tgt, typename EndIter, typename... List>
+struct Action<Tgt, EndIter, EndIter, List...> {
+ typedef Tgt<List...> type;
+};
+
+} // NS
+
+// unpack a boost::mpl sequence into a variadic type list
+template<template<typename... T> class Tgt,
+ typename Seq,
+ typename... NewList>
+struct UnpackTypeList {
+ typedef typename UnpackTypeListImpl
+ ::Action<Tgt,
+ typename boost::mpl::begin<Seq>::type,
+ typename boost::mpl::end<Seq>::type,
+ NewList...>::type type;
+};
+
+// create a unique class from a type, given a variadic garbage type
+// list; if the type is an empty struct it is not stored but created
+// upon every request
+// TODO: access functions (right now the stored values are only
+// accessed using outraging pointer casts)
+template<typename T, bool isEmpty, bool isFund, typename... Garbage> struct MakeUniqueImpl;
+
+template<typename T, typename... Garbage>
+struct MakeUnique {
+ typedef MakeUniqueImpl<T, boost::is_empty<T>::value,
+ boost::is_fundamental<T>::value, Garbage...> type;
+};
+
+template<typename T, typename... Garbage>
+struct MakeUniqueImpl<T, true, false, Garbage...> {
+ MakeUniqueImpl(const T &v) {}
+ MakeUniqueImpl(T &&v) {}
+ MakeUniqueImpl() = default;
+};
+
+template<typename T, typename... Garbage>
+struct MakeUniqueImpl<T, false, true, Garbage...> {
+ MakeUniqueImpl(const T &v) : v(v) {}
+ MakeUniqueImpl(T &&v) : v(v) {}
+ MakeUniqueImpl() = default;
+ T v;
+};
+
+template<typename T, typename... Garbage>
+struct MakeUniqueImpl<T, false, false, Garbage...> : protected T {
+ MakeUniqueImpl(T&& a) : T(std::move(a)) {}
+ MakeUniqueImpl() = default;
+};
+
+#endif // LY1b9novVl8oDseRTw8dH5lzpNo
diff --git a/core/test_.cpp b/core/test_.cpp
new file mode 100644
index 0000000..9c14384
--- /dev/null
+++ b/core/test_.cpp
@@ -0,0 +1,45 @@
+#include <set>
+#include <boost/static_assert.hpp>
+#include <boost/mpl/and.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/mpl/at.hpp>
+#include <boost/mpl/empty.hpp>
+#include <boost/mpl/erase_key.hpp>
+#include <boost/mpl/front.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/map.hpp>
+#include <boost/mpl/pair.hpp>
+#include <boost/mpl/transform.hpp>
+#include <boost/mpl/list.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/random.hpp>
+#include <boost/random/exponential_distribution.hpp>
+#include <boost/random/variate_generator.hpp>
+#include <boost/utility.hpp>
+#include <iostream>
+#include <assert.h>
+#include <string>
+
+
+
+// #include "type_set.hpp"
+// #include "simlimits.hpp"
+// #include "time.hpp"
+// #include "pointers.hpp"
+// #include "mempool.hpp"
+// #include "scalar.hpp"
+// #include "multi_queue.hpp"
+// #include "filter.hpp"
+
+
+using namespace boost::mpl;
+using namespace boost;
+using namespace std;
+
+
+int main() {
+ bool b(1);
+ cout << b << endl;
+ return 0;
+}
diff --git a/core/test_checkpoint.cpp b/core/test_checkpoint.cpp
new file mode 100644
index 0000000..2417a32
--- /dev/null
+++ b/core/test_checkpoint.cpp
@@ -0,0 +1,52 @@
+#include <iostream>
+
+#include "checkpoint.hpp"
+#include "ephermal_checkpoint.hpp"
+
+#include "vector.hpp"
+#include "scalar.hpp"
+#include "mempool.hpp"
+
+using namespace std;
+
+int main() {
+ Checkpoint<int, 16> cont("cont", 0), add("moppelkotze", -10);
+ EphermalCheckpoint<int, 16> eph("ignored", -10);
+
+ // check that all initial values are set
+ for (int i=0; i<16; i++) {
+ if (add.getValue(0, i) != -10) {
+ cerr << "initial value of " << i << "wrong (" << add.getValue(0, i) << " != -10)" << endl;
+ return -1;
+ }
+ if (add.getValue(0, i) != -10) {
+ cerr << "(ephermal) initial value of " << i << "wrong (" << add.getValue(0, i) << " != -10)" << endl;
+ return -1;
+ }
+ }
+
+ // check takeover to the next generation
+ add.getValue(1, 0); // readout already triggers (yes, this also happens below)
+ for (int i=0; i<16; i++)
+ if (add.getValue(1, i) != -10) {
+ cerr << "checkout generation takover of " << i << "failed (" << add.getValue(0, i) << " != -10)" << endl;
+ return -1;
+ }
+
+ // set and get value
+ add.set(6, 5, 42);
+
+ // check value continuation over time
+ // WARN: tests also the behaviour that only the most recent value per timeslot is stored
+ for (int i=1; i<1000; i++)
+ if (add.getValue(i, 5) != 42) {
+ cerr << "new value takover failed (time: " << i << ", element 5); value 42 != " << add.getValue(0, i) << endl;
+ return -1;
+ }
+
+
+ add.sync();
+
+ // success
+ return 0;
+}
diff --git a/core/test_filter.cpp b/core/test_filter.cpp
new file mode 100644
index 0000000..3df91fe
--- /dev/null
+++ b/core/test_filter.cpp
@@ -0,0 +1,77 @@
+#include <iostream>
+
+#include "index_global.hpp"
+#include "filter.hpp"
+
+using namespace std;
+
+int main() {
+ const int testSize = 10000;
+
+ // create index
+ {
+ Index<GlobalMsg> idx;
+ for (int i=0; i<testSize; i++)
+ idx.add(Time(i), Time(i + 100.0 * drand48()), Ptr<Global>());
+ }
+ {
+ Index<RandomSpike> idx;
+ for (int i=0; i<testSize; i++)
+ idx.add(Time(i), Time(i + 7.9 * drand48()), Ptr<Neuron>(i % 8));
+ }
+
+ // test index
+ {
+ Time ct(0.0);
+ Filter<GlobalMsg> filter(ct);
+ for (int i=0; i<testSize; i++) {
+ // cout << "OUT#" << i << " " << filter(ct).minPayload().src() << " (" << filter(ct).minVal()() << ")" << endl;
+ assert(!filter(ct).isEmpty());
+ assert(ct <= filter(ct).minVal());
+ assert(filter(ct).minVal() == filter(ct).index.eventTime(filter(ct).minPayload().src()));
+ ct = filter(ct).minVal();
+ filter(ct).removeMin();
+ }
+ assert(filter.isEmpty());
+ }
+
+ {
+ Time ct(0.0);
+ IdList<Ptr<Neuron>::ptr_t> lll((char*) "0,1,2,3,4,5,6,7");
+ Filter<RandomSpike> filter(lll, ct);
+ for (int i=0; i<testSize; i++) {
+ // cout << "OUT#" << i << " " << filter(ct).minPayload().src() << " (" << filter(ct).minVal()() << ")" << endl;
+ assert(!filter(ct).isEmpty());
+ assert(ct <= filter(ct).minVal());
+ assert(filter(ct).minPayload().dst() == filter(ct).minPayload().src() % 8);
+ ct = filter(ct).minVal();
+ filter(ct).removeMin();
+ }
+ assert(filter.isEmpty());
+ }
+
+ {
+ Index<Spike> idx;
+ for (int i=0; i<testSize; i++)
+ idx.add(Time(1+i), Time(1+i), Ptr<Neuron>((i+100) % maxNeurons));
+ }
+ {
+ Time ct(testSize / 2.0);
+ IdList<Ptr<Neuron>::ptr_t> lll((char*) "1,2,3,4,5,6,7,8,9,55");
+ Filter<SpikeArrival> filter(lll, ct);
+
+ int i=0;
+ while (!filter.isEmpty()) {
+ cout << "OUT#" << i << " "
+ << filter(ct).minPayload().src.get<0>().extractSpike()() << ", "
+ << filter(ct).minPayload().src.get<1>()() << " ("
+ << filter(ct).minVal()() << ")" << endl;
+ assert(ct <= filter(ct).minVal());
+ ct = filter(ct).minVal();
+ filter(ct).removeMin();
+ i++;
+ }
+ }
+ return 0;
+}
+
diff --git a/core/test_heap.cpp b/core/test_heap.cpp
new file mode 100644
index 0000000..1ae79c2
--- /dev/null
+++ b/core/test_heap.cpp
@@ -0,0 +1,43 @@
+#include <iostream>
+#include <stdlib.h>
+
+
+template<typename Ignored>
+struct AverageQueueSize {
+ static const uint64_t value = 0; // cause a crash if used
+};
+
+#include "priority_queue.hpp"
+#include "heap.hpp"
+#include "mempool.hpp"
+
+using namespace std;
+
+int main() {
+ int count = 1000;
+ typedef Heap<PriorityQueue<Time, double> > heap_t;
+ heap_t heap("test", count * 2 * sizeof(double));
+
+ // add many random values
+ for (int i=0; i<count; i++) {
+ heap(0).insert(Time(i), i);
+ }
+
+ // retrieve them while continuing the passage of time, perhaps
+ // provoking an error ;-)
+ Time cur = 0;
+ for (int i=0; i<count; i++) {
+ Time n = heap(cur).minVal();
+ if (n < cur) return -1;
+ cur = n;
+ heap(cur).removeMin();
+ }
+
+ // recap them again
+ for (int i=1; i<count; i++) {
+ if (!heap(Time(i)).isEmpty() && (heap(Time(i-1)).minPayload() > heap(Time(i)).minPayload())) return -1;
+ }
+
+ // got until here -> success
+ return 0;
+}
diff --git a/core/test_index.cpp b/core/test_index.cpp
new file mode 100644
index 0000000..7550cdf
--- /dev/null
+++ b/core/test_index.cpp
@@ -0,0 +1,41 @@
+#include <iostream>
+
+#include "index_global.hpp"
+#include "index_spike.hpp"
+
+using namespace std;
+
+int main() {
+ Index<GlobalMsg> g;
+ Index<Spike> s;
+
+ // add/check some global events
+ for (uint i=0; i<1000; i++) {
+ Index<GlobalMsg>::ptr_t r;
+ r = g.add(Time(i), Time(i), Ptr<Global>());
+ if (r != i) {
+ cerr << "discontinuous global event allocation (event: " << i << ", ptr: " << r << ")" << endl;
+ return -1;
+ }
+ }
+
+ // add some spike events
+ for (uint i=0; i<1000; i++) {
+ s.add(i, i, Ptr<Neuron>(i));
+ }
+
+ for (uint i=0; i<1000; i++) {
+ if (s.last(i) != i) {
+ cerr << "last(" << i << ") = " << s.last(i) << " != " << i << endl;
+ return -1;
+ }
+ if (s.last(10000, Ptr<Neuron>(i)) != i) {
+ cerr << "last(inf, " << i << ") = " << s.last(i) << " != " << i << endl;
+ return -1;
+ }
+ }
+
+ // and check if we found the corrent one
+
+ return 0; // success
+}
diff --git a/core/test_index_speed.cpp b/core/test_index_speed.cpp
new file mode 100644
index 0000000..dfcca24
--- /dev/null
+++ b/core/test_index_speed.cpp
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "index.hpp"
+#include "index_global.hpp"
+#include "index_spike.hpp"
+#include "perftools.hpp"
+#include "simlimits.hpp"
+
+int main() {
+ Timer *timer;
+ Index<GlobalMsg> g;
+ Index<Spike> s;
+
+
+ timer = new Timer();
+ const int gcount = 10000000;
+ for (int i=0; i<gcount; i++)
+ g.add(i);
+ print_throughput(timer->diff(), gcount, (char*) "global add\t");
+
+ timer = new Timer();
+ for (int i=0; i<gcount; i++)
+ g.last(i);
+ print_throughput(timer->diff(), gcount,(char*) "global search\t");
+
+ timer = new Timer();
+ const int scount = 10000000;
+ for (int i=0; i<scount; i++)
+ s.add(((double) i / 10 / maxNeurons), Ptr<Neuron>(i%maxNeurons));
+ print_throughput(timer->diff(), scount,(char*) "spike add\t");
+
+ timer = new Timer();
+ for (int i=0; i<scount; i++)
+ s.last(((double) scount / 10 / maxNeurons), Ptr<Neuron>(i%maxNeurons));
+ print_throughput(timer->diff(), scount,(char*) "spike search\t");
+
+ return 0; // user has to control the files
+}
diff --git a/core/test_mmap.cpp b/core/test_mmap.cpp
new file mode 100644
index 0000000..9166521
--- /dev/null
+++ b/core/test_mmap.cpp
@@ -0,0 +1,52 @@
+#include <malloc.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+// how many mmap areas to create
+#define mapMax 100
+// how large should they be
+#define mapSize ((size_t)1024 * 1024 * 1024 * 100)
+
+int fd[mapMax];
+char name[mapMax][100];
+
+void quit(int ret) {
+ for (int i=0; i<mapMax; i++) {
+ // close(fd[i]);
+ unlink(name[i]);
+ }
+ exit(ret);
+}
+
+int main() {
+ memset(name[0], 0, sizeof(name));
+
+ fprintf(stderr, "Allocating\t%f GB\t=\t%d\tx\t%f GB\n", ((double) mapMax * mapSize) / 1024.0 / 1024 / 1024, mapMax, (double) mapSize / 1024.0 / 1024 / 1024 );
+
+ // create tmp files
+ for (int i=0; i<mapMax; i++) {
+ tmpnam(name[i]);
+ fd[i] = open( name[i], O_CREAT | O_EXCL | O_RDWR, S_IRWXU );
+ if (fd[i] == -1) {
+ fprintf(stderr, "opening tmp file #%d failed\n", i);
+ quit(-1);
+ }
+ }
+
+ // mmap them
+ for (int i=0; i<mapMax; i++) {
+ if (MAP_FAILED == mmap((void*) NULL, mapSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NONBLOCK, fd[i], 0)) {
+ fprintf(stderr, "mmap #%d failed (errno: %d, errstr: %s)\n", i, errno, strerror(errno));
+ quit(-1);
+ }
+ }
+
+ quit(0);
+}
diff --git a/core/test_mmap2.cpp b/core/test_mmap2.cpp
new file mode 100644
index 0000000..29312a7
--- /dev/null
+++ b/core/test_mmap2.cpp
@@ -0,0 +1,26 @@
+#include <malloc.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <iostream>
+
+#include "mempool.hpp"
+
+int main() {
+ MemPool ram(4096);
+ MemPool file(4096, "myfunnymmapfile");
+ MemPool file2(4096, "myfunnymmapfile2");
+
+ ram.sync();
+ file.sync();
+
+ char *s = (char*) "Ei der Daus!";
+ memcpy(ram(), s, strlen(s));
+ memcpy(file(), ram(), 4096);
+}
diff --git a/core/test_movector.cpp b/core/test_movector.cpp
new file mode 100644
index 0000000..6ca0b21
--- /dev/null
+++ b/core/test_movector.cpp
@@ -0,0 +1,21 @@
+#include "index_global.hpp"
+#include "index_spike.hpp"
+#include "heap.hpp"
+#include "priority_queue.hpp"
+#include "type_set.hpp"
+
+struct Foo {};
+
+int main() {
+ MemPool m1(1), m2(std::move(m1));
+ Scalar<int> s1("s"), s2(std::move(s1));
+ Vector<Time> v1("v", 1), v2(std::move(v2));
+ Checkpoint<int, 16> c1("c", 0), c2(std::move(c1));
+ Heap<PriorityQueue<int, int>> h1("h", 10), h2(std::move(h1));
+ CommonIndex<int> ci1("ci", 1), ci2(std::move(ci1));
+ CommonSpikeIndex<Ptr<Spike>::ptr_t> cis1("cis"), cis2(std::move(cis1));
+ Index<Spike> is1{}, is2(std::move(is1));
+ Index<GlobalMsg> i1{}, i2(std::move(i1));
+ TypeSet<int, double, Foo> t1{}, t2(std::move(t1));
+ return 0;
+}
diff --git a/core/test_multi_queue.cpp b/core/test_multi_queue.cpp
new file mode 100644
index 0000000..e9ff9b3
--- /dev/null
+++ b/core/test_multi_queue.cpp
@@ -0,0 +1,164 @@
+#include <assert.h>
+#include <iostream>
+#include <stdlib.h>
+
+#include <boost/mpl/vector.hpp>
+
+#include "time.hpp"
+#include "template_helpers.hpp"
+
+// fake RuntimeID & AverageQueueLength wich is otherwise in "quant_types.hpp"
+template<typename T>
+struct RuntimeID {
+ static const uint8_t value = T::runtimeId;
+};
+
+template<typename T>
+struct AverageQueueSize {
+ static const uint64_t value = T::aql;
+};
+
+template<typename T> struct Foo {
+ Foo(int i) : val(i) {}
+ int operator() () { return val; }
+ int val;
+ typedef T quant_t;
+};
+
+struct A {
+ static const unsigned char runtimeId = 0;
+ static const uint64_t aql = 1000;
+ static const char* const name;
+};
+const char* const A::name = "A";
+struct B {
+ static const unsigned char runtimeId = 1;
+ static const uint64_t aql = 2000;
+ static const char* const name;
+};
+const char* const B::name = "B";
+struct C {
+ static const unsigned char runtimeId = 2;
+ static const uint64_t aql = 3000;
+ static const char* const name;
+};
+const char* const C::name = "C";
+
+typedef boost::mpl::vector<A, B, C> DiscreteQuantorList;
+
+// prevent quant_types to be included
+#define sKmf7ztuNbBT3ua3iNX4k5rtsg0
+
+#include "multi_queue.hpp"
+
+#include "mempool.hpp"
+
+using namespace std;
+
+template<typename T>
+void test(int line, int testid, T ex, T got) {
+ if (ex != got) {
+ cout << "line " << line
+ << ", test " << testid
+ << ", expected " << ex
+ << ", got " << got << endl;
+ exit(-1);
+ }
+}
+
+int main() {
+ using boost::make_tuple;
+ typedef MultiQueue<Time, Foo,
+ boost::mpl::list< A, B, C >
+ > mq_t;
+
+ mq_t mq{};
+ Time ct(0);
+
+ // macro helpers
+ //#define PMQ {for(int i=0; i<MultiQueueImpl::numRID;i++)cout<<mq.minVal[i] << " "; cout << endl;}
+#define PMQ
+#define I(v,q) { mq.insert<q>(ct,Time(v),10*v); PMQ }
+#define T(v,q,command) { \
+ test(__LINE__, 1, mq.minType(), RuntimeID<q>::value); \
+ test(__LINE__, 2, mq.min(), Time(v)); \
+ test(__LINE__, 3, mq.get<q>()(ct).minVal(), Time(v)); \
+ test(__LINE__, 4, mq.get<q>()(ct).minPayload()(), 10*v); \
+ mq.command<q>(ct); \
+ PMQ \
+ }
+#define Tg(v,q) T(v,q,removeMin)
+#define Tl(v,q) T(v,q,removeLocalMin)
+
+ // test extractMin
+ PMQ
+ I(9,C);
+ I(7,C);
+ I(3,B);
+ I(3,B);
+ I(3,A);
+ I(2,C);
+ I(2,A);
+ I(2,B);
+ I(1,A);
+
+ Tg(1,A);
+ Tg(2,A);
+ Tg(2,B);
+ Tg(2,C);
+ Tg(3,A);
+ Tg(3,B);
+ Tg(3,B);
+ Tg(7,C);
+ Tg(9,C);
+
+ // test extractLocalMin
+ PMQ
+ I(9,C);
+ I(7,C);
+ I(3,B);
+ I(3,B);
+ I(3,A);
+ I(2,C);
+ I(2,A);
+ I(2,B);
+ I(1,A);
+
+ Tl(1,A);
+ Tl(2,A);
+ Tl(2,B);
+ Tl(2,C);
+ Tl(3,A);
+ Tl(3,B);
+ Tl(3,B);
+ Tl(7,C);
+ Tl(9,C);
+
+ // test extractLocalMin
+ PMQ
+ I(9,C);
+ I(7,C);
+ I(3,B);
+ I(3,B);
+ I(3,A);
+ I(2,C);
+ I(2,A);
+ I(2,B);
+ I(1,A);
+
+ mq.removeLocalMin<B>(ct);
+ Tl(1,A);
+ Tl(2,A);
+ //Tl(2,B);
+ mq.removeLocalMin<A>(ct);
+ Tl(2,C);
+ // Tl(3,A);
+ Tl(3,B);
+ Tl(3,B);
+ Tl(7,C);
+ Tl(9,C);
+
+
+ // got until here -> success
+ return 0;
+}
diff --git a/core/test_pla_apply.cpp b/core/test_pla_apply.cpp
new file mode 100644
index 0000000..7e18c93
--- /dev/null
+++ b/core/test_pla_apply.cpp
@@ -0,0 +1,56 @@
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/pair.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <iostream>
+
+#include "index.hpp"
+#include "index_spike.hpp"
+#include "pla_apply.hpp"
+#include "property_composition.hpp"
+#include "property_access.hpp"
+#include "context.hpp"
+
+#include "model.hpp" // for Voltage, Weight
+
+
+int main() {
+ using boost::mpl::pair;
+ using boost::mpl::list;
+ using boost::mpl::bool_;
+ using boost::make_tuple;
+
+ // define a fake sim env
+ typedef PropertyComposition<Lists::all> pc_t;
+ pc_t pc;
+
+ // set weight to 3.0
+ pc.cast(PLA_Set<Weight>{0.0, Ptr<Synapse>{0}, 3.0});
+
+ // create and call an apply PLA
+ DelieverContext<SpikeArrival, Neuron>
+ ctx(make_tuple(Ptr<SpikeArrival>{0}, Ptr<Synapse>{0}),
+ Ptr<Neuron>(0));
+ PLA_Apply<SpikeArrival, Neuron, pc_t> apply(Time(0), ctx);
+
+ assert(Property_Get<Voltage>::eval(pc, ctx, Time(0)) == 0.0);
+ pc.call(apply);
+ assert(Property_Get<Voltage>::eval(pc, ctx, Time(0)) == 0.0);
+
+
+ // check for desired event generation pattern
+ assert(!apply.generate<SpikeArrival>());
+ assert(!apply.generate<GlobalMsg>());
+ assert(apply.generate<Spike>());
+ assert(apply.generateAny());
+
+ // commit and test for proper change
+ assert(Property_Get<Voltage>::eval(pc, ctx, Time(0)) == 0.0);
+ apply.commit(pc);
+ assert(Property_Get<Voltage>::eval(pc, ctx, Time(0)) == 3.0);
+
+ // additional compile time checks of helper classes
+ BOOST_MPL_ASSERT((ContinuousProperty_ApplyChangesProp<Voltage, SpikeArrival>));
+ BOOST_MPL_ASSERT_NOT((ContinuousProperty_ApplyChangesProp<Weight, SpikeArrival>));
+
+ return 0;
+}
diff --git a/core/test_pla_evolve.cpp b/core/test_pla_evolve.cpp
new file mode 100644
index 0000000..4187c9a
--- /dev/null
+++ b/core/test_pla_evolve.cpp
@@ -0,0 +1,88 @@
+#include <iostream>
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/pair.hpp>
+#include <boost/mpl/bool.hpp>
+
+
+#include "context.hpp"
+#include "continuous_property.hpp"
+#include "pla_evolve.hpp"
+#include "pla_get.hpp"
+#include "pla_init_default.hpp"
+#include "property_composition.hpp"
+
+#include "mempool.hpp"
+
+// create some extra properties
+
+#include "property_abbrevations_begin.hpp"
+
+GEN_CP(Neuron, ConstProp, "const_prop", int, 42);
+GEN_CP_EVOLVE(ConstProp, _CP(ConstProp));
+
+GEN_CP(Neuron, ArithProp, "arith_prop", int, 0);
+GEN_CP_EVOLVE(ArithProp, (_CP(ArithProp) + 1));
+
+GEN_CP(Neuron, GeomProp, "geom_prop", int, 1);
+GEN_CP_EVOLVE(GeomProp, (2*_CP(GeomProp)));
+
+GEN_CP(Neuron, TimeProp, "time_prop", Time, 0.0);
+GEN_CP_EVOLVE(TimeProp, _CP(TimeProp) + td);
+
+GEN_CP(Neuron, Alter1, "alter1", bool, true);
+GEN_CP(Neuron, Alter2, "alter2", bool, false);
+GEN_CP_EVOLVE(Alter1, _CP(Alter2));
+GEN_CP_EVOLVE(Alter2, _CP(Alter1));
+
+#include "property_abbrevations_end.hpp"
+
+using namespace std;
+
+int main() {
+ using boost::mpl::pair;
+ using boost::mpl::list;
+ using boost::mpl::bool_;
+
+ // below is bullshit
+ PropertyComposition<list<
+ pair<ConstProp, bool_<true>>,
+ pair<ArithProp, bool_<true>>,
+ pair<GeomProp, bool_<true>>,
+ pair<TimeProp, bool_<true>>,
+ pair<Alter1, bool_<true>>,
+ pair<Alter2, bool_<true>>
+ >> pc;
+
+ // init with default values
+ //PLA_Init_Default<ArithProp> action_init;
+ // pc.call(action_init);
+
+ // create an instance ptr (we only consider a single instance)
+ Ptr<Neuron> inst{0};
+ ContinuousContext<Neuron> context{inst};
+
+ // evolve and check result using specific gets
+ for (int i=1; i<20; i++) {
+ Time t{double{i}};
+ PLA_Evolve<Neuron> evolve(context, t);
+
+ // evolve
+ pc.call(evolve);
+
+ // check
+ #define CHECK(PN, COND) { \
+ PLA_Get<PN> action{t,inst}; \
+ PN::type res(pc.call(action)); \
+ assert(res == (COND)); \
+ }
+
+ CHECK(ConstProp, 42);
+ CHECK(ArithProp, i);
+ CHECK(GeomProp, (1 << i));
+ CHECK(TimeProp, t);
+
+ PLA_Get<Alter1> ag_a1 (t, inst);
+ PLA_Get<Alter2> ag_a2 (t, inst);
+ assert(pc.call(ag_a1) ^ pc.call(ag_a2));
+ }
+}
diff --git a/core/test_pla_getset.cpp b/core/test_pla_getset.cpp
new file mode 100644
index 0000000..08065f2
--- /dev/null
+++ b/core/test_pla_getset.cpp
@@ -0,0 +1,44 @@
+#include <boost/mpl/pair.hpp>
+#include <iostream>
+
+#include "context.hpp"
+#include "continuous_property.hpp"
+#include "pla_get.hpp"
+#include "pla_set.hpp"
+#include "property_composition.hpp"
+#include "pointers.hpp"
+#include "time.hpp"
+
+#include "mempool.hpp"
+
+// create a test property
+#define RASIMU_MODEL
+#include "model.hpp"
+#include "property_abbrevations_begin.hpp"
+GEN_CP(Neuron, TestProp, "test_prop", int, 42);
+GEN_CP_EVOLVE(TestProp, _CP(TestProp));
+
+using namespace std;
+
+int main() {
+ using boost::mpl::pair;
+ using boost::mpl::list;
+ using boost::mpl::bool_;
+
+ // below is bullshit
+ PropertyComposition<list<boost::mpl::pair<TestProp, bool_<true>>>> pc;
+
+ for (int j=0; j<100; j++) {
+ for (Ptr<Neuron>::ptr_t i=0; i<100; i++) {
+ PLA_Set<TestProp> set{Time{double{j}}, Ptr<Neuron>{i}, 42 * i + j};
+ pc.call(set);
+ }
+ for (int i=0; i<100; i++) {
+ PLA_Get<TestProp> get{Time{double{j}}, Ptr<Neuron>(i)};
+ assert(pc.call(get) == (42 * i + j));
+ }
+ }
+
+ // success
+ return 0;
+}
diff --git a/core/test_prioque.cpp b/core/test_prioque.cpp
new file mode 100644
index 0000000..9457cd8
--- /dev/null
+++ b/core/test_prioque.cpp
@@ -0,0 +1,40 @@
+#include <assert.h>
+#include <iostream>
+#include <stdlib.h>
+
+#include "priority_queue.hpp"
+
+using namespace std;
+
+int main() {
+ // PQ is an open ended data structure -> alloc an arbitrary mem amount
+ PriorityQueue<unsigned int, unsigned int> *pq = new(malloc(1024 * 1024)) PriorityQueue<unsigned int, unsigned int>();
+
+ // macro helpers
+#define I(v) { uint s=pq->length; pq->insert(v,10*v); if (s+1 != pq->length) return -1; }
+#define T(v) { if (pq->minVal() != v || pq->minPayload() != 10*v) return -1; pq->removeMin(); }
+#define DP { for (uint i=0; i<pq->length; i++) { cout << pq->heap[i].val << ", "; } cout << "-" << endl; }
+ // add and remove some values
+ I(3);
+ I(2);
+ I(1);
+ T(1);
+ T(2);
+ T(3);
+
+ // add many random values
+ srand(42);
+ for (int i=0; i<100000; i++) {
+ // cout << ".";
+ pq->insert(rand(), 0);
+ }
+ unsigned int prev = 0;
+ for (int i=0; i<100000; i++) {
+ if (pq->minVal() < prev) return -1;
+ prev = pq->minVal();
+ pq->removeMin();
+ }
+
+ // got until here -> success
+ return 0;
+}
diff --git a/core/test_prioque_speed.cpp b/core/test_prioque_speed.cpp
new file mode 100644
index 0000000..adb6d63
--- /dev/null
+++ b/core/test_prioque_speed.cpp
@@ -0,0 +1,38 @@
+#include <iostream>
+#include <stdlib.h>
+
+#include "perftools.hpp"
+#include "priority_queue.hpp"
+
+using namespace std;
+
+int main() {
+ // PQ is an open ended data structure -> alloc an arbitrary mem amount
+ PriorityQueue<double, int> *pq;
+
+ Timer *timer = new Timer();
+ int trans = 1000000;
+ int maxBase = 1024 * 1024;
+ void *mem = malloc(20 * 1024 * 1024);
+
+ for (int i=0; i<trans; i++) {
+ drand48();
+ }
+ print_throughput(timer->diff(), trans, (char*) "raw PRNG");
+
+ for (int base=1; base<=maxBase; base*=2) {
+ // setup queue
+ pq = new(mem) PriorityQueue<double, int>();
+ for (int i=0; i<base; i++) pq->insert(drand48(),0);
+
+ // test queue
+ timer = new Timer();
+ for (int i=0; i<trans; i++) {
+ pq->insert(i, 0);
+ pq->removeMin();
+ }
+ print_throughput2(timer->diff(), trans, base);
+ }
+
+ return 0;
+}
diff --git a/core/test_propcomp.cpp b/core/test_propcomp.cpp
new file mode 100644
index 0000000..c5522f1
--- /dev/null
+++ b/core/test_propcomp.cpp
@@ -0,0 +1,33 @@
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/pair.hpp>
+#include <boost/mpl/bool.hpp>
+#include <iostream>
+
+#include "continuous_property.hpp"
+#include "pla_debug_name.hpp"
+#include "pla_get.hpp"
+#include "property_composition.hpp"
+
+#include "model.hpp" // for Voltage
+
+#include "mempool.hpp"
+
+// create some extra properties
+GEN_CP(Neuron, CrazyVal, "crazy_val", double, 0.0);
+GEN_CP(Global, CoolVal, "cool_val", double, 0.0);
+GEN_CP(Synapse, ExtraordinaryVal, "extraordinary_val", double, 0.0);
+
+int main() {
+ using boost::mpl::pair;
+ using boost::mpl::list;
+ using boost::mpl::bool_;
+
+ // below is bullshit
+ PropertyComposition<list<
+ pair<Voltage, bool_<false> >,
+ pair<ExtraordinaryVal, bool_<false> >
+ > > test1;
+
+ PLA_Debug_Name action_debug;
+ std::cout << test1.call(action_debug) << std::endl;
+}
diff --git a/core/test_propcomp_cpp-speed.cpp b/core/test_propcomp_cpp-speed.cpp
new file mode 100644
index 0000000..ab9e4ba
--- /dev/null
+++ b/core/test_propcomp_cpp-speed.cpp
@@ -0,0 +1,48 @@
+#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
+#define BOOST_MPL_LIMIT_LIST_SIZE 50
+
+#include <iostream>
+
+#include <boost/mpl/pair.hpp>
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/bool.hpp>
+
+#include "continuous_property.hpp"
+#include "pla_debug_name.hpp"
+#include "property_composition.hpp"
+
+#include "mempool.hpp"
+
+// create some extra properties
+#define A1(t, s) GEN_CP(Global, t, s, int, 0);
+#define A2(t, s) A1(t ## 0, s "0") A1(t ## 1, s "1")
+#define A4(t, s) A2(t ## 0, s "0") A2(t ## 1, s "1")
+#define A8(t, s) A4(t ## 0, s "0") A4(t ## 1, s "1")
+#define A16(t, s) A8(t ## 0, s "0") A8(t ## 1, s "1")
+#define A32(t, s) A16(t ## 0, s "0") A16(t ## 1, s "1")
+#define A64(t, s) A32(t ## 0, s "0") A32(t ## 1, s "1")
+#define A128(t, s) A64(t ## 0, s "0") A64(t ## 1, s "1")
+
+#define B1(t) boost::mpl::pair<t, boost::mpl::bool_<false>>
+#define B2(t) B1(t ## 0), B1(t ## 1)
+#define B4(t) B2(t ## 0), B2(t ## 1)
+#define B8(t) B4(t ## 0), B4(t ## 1)
+#define B16(t) B8(t ## 0), B8(t ## 1)
+#define B32(t) B16(t ## 0), B16(t ## 1)
+#define B64(t) B32(t ## 0), B32(t ## 1)
+#define B128(t) B64(t ## 0), B64(t ## 1)
+
+#define B48(t) B32(t ## 0), B16(t ## 1 ## 1)
+
+A64(Many, "many")
+
+int main() {
+ // below is bullshit
+ PropertyComposition<
+ boost::mpl::list<
+ B48(Many) // work around boost::mpl::list limit of 50 elements
+ >> test1;
+
+ PLA_Debug_Name action_debug;
+ std::cout << *test1.call(action_debug) << std::endl;
+}
diff --git a/core/test_rng.cpp b/core/test_rng.cpp
new file mode 100644
index 0000000..4ee419c
--- /dev/null
+++ b/core/test_rng.cpp
@@ -0,0 +1,76 @@
+#include <assert.h>
+#include <iostream>
+
+#include "rng.hpp"
+
+using namespace RNG;
+//using namespace std;
+
+int main() {
+ seed_t src(0),
+ s( split(src)),
+ s1(split(next(src)));
+
+ std::cout << "RNG size: " << sizeof(generator) << std::endl;
+ // for (int j=0; j<10; j++) {
+ // s = j;
+ // for (int i=0; i<10; i++) {
+ // std::cout << s << ", ";
+ // s = next(s);
+ // }
+ // std::cout << std::endl;
+ // }
+
+ // determinism?
+ assert(next(s).rng == next(s).rng);
+
+ // respect seed
+ assert(next(s).rng != next(s1).rng);
+
+ // respect equipropable distribution
+ {
+ const int times(1000);
+ double mean(0);
+ for (int i=0; i<times; i++) {
+ double res = equi(s);
+ // std::cout << res << std::endl;
+
+ s = next(s);
+ assert(0 <= res);
+ assert(res < 1);
+ mean += res;
+ }
+ mean /= times;
+ assert(0.45 < mean && mean < 0.55);
+ }
+
+ // respect exponential distribution
+ {
+ const int times(1000);
+ double mean(0);
+ for (int i=0; i<times; i++) {
+ double res = expo(s, 66);
+ // std::cout << res << " " << s.rng << std::endl;
+ s = next(s);
+ assert(0 <= res);
+ mean += res;
+ }
+ mean /= times;
+ assert(60 < mean && mean < 75);
+ }
+
+ // print 1000 parallel streams
+ // for (int i=0; i<1000; i++) {
+ // seed_t s = split(src);
+ // src = next(src, 40);
+
+ // double d = 0;
+ // while (d < 100) {
+ // std::cerr << d << "\t" << i << std::endl;
+ // d += expo(s, 1.0);
+ // s = next(s);
+ // }
+ // }
+
+ return 0;
+}
diff --git a/core/test_scalar.cpp b/core/test_scalar.cpp
new file mode 100644
index 0000000..3c57266
--- /dev/null
+++ b/core/test_scalar.cpp
@@ -0,0 +1,23 @@
+#include "stdio.h"
+
+#include "scalar.hpp"
+#include "mempool.hpp"
+
+int main() {
+ Scalar<int> eins("eins"), zwei("zwei");
+ Scalar<uint8_t, 1> bit1("bit");
+
+ eins() = 1;
+ zwei() = 2 * eins();
+ bit1.set(1);
+
+ int result = bit1() * eins() * zwei();
+
+ fprintf(stderr, "bit mul result = %d", result);
+
+ if (result == 2) {
+ return 0;
+ }else{
+ return -1;
+ }
+}
diff --git a/core/test_sim_loop.cpp b/core/test_sim_loop.cpp
new file mode 100644
index 0000000..c17f796
--- /dev/null
+++ b/core/test_sim_loop.cpp
@@ -0,0 +1,28 @@
+#include <boost/mpl/list.hpp>
+#include <boost/mpl/pair.hpp>
+#include <iostream>
+
+#include "sim_loop.hpp"
+
+#include "model.hpp"
+
+using namespace std;
+
+int main() {
+ using boost::mpl::pair;
+ using boost::mpl::list;
+
+ SimLoop<Lists::all> sim;
+
+ // run, exceeding time limit
+ assert(sim.run(0.05, 1000000));
+ cout << "left sim.run at " << sim.queues.min()()
+ << " (" << (int) sim.queues.minType() << ")" << endl;
+
+ // run, execeeding event limit
+ assert(sim.run(1000, 1) == 0);
+ cout << "left sim.run at " << sim.queues.min()()
+ << " (" << (int) sim.queues.minType() << ")" << endl;
+
+ return 0;
+}
diff --git a/core/test_typemap.cpp b/core/test_typemap.cpp
new file mode 100644
index 0000000..12254e5
--- /dev/null
+++ b/core/test_typemap.cpp
@@ -0,0 +1,25 @@
+#include <assert.h>
+
+#include <boost/mpl/map.hpp>
+#include "type_map.hpp"
+
+using namespace boost::mpl;
+
+class Foo {};
+
+int main() {
+ TypeMap<map<
+ pair<int, char>,
+ pair<double, int>,
+ pair<char, Foo>
+ > > mapp;
+
+ mapp.get<int>() = 5;
+ mapp.get<double>() = mapp.get<int>() + 1;
+ mapp.get<char>() = Foo();
+
+ assert(mapp.get<int>() == 5);
+ assert(mapp.get<double>() == 6);
+
+ return 0;
+}
diff --git a/core/test_vector.cpp b/core/test_vector.cpp
new file mode 100644
index 0000000..eb79bd6
--- /dev/null
+++ b/core/test_vector.cpp
@@ -0,0 +1,62 @@
+#include <stdio.h>
+
+#include "vector.hpp"
+
+#include "mempool.hpp"
+
+int main() {
+ Vector<uint8_t, 1> eins("eins", 64);
+ Vector<uint8_t, 2> zwei("zwei", 16);
+ Vector<uint8_t, 4> vier("vier", 8);
+ Vector<uint8_t, 2> del("del", 10);
+ Vector<char, 1> type("type",1);
+
+ Vector<uint8_t, 2> m("test", 32);
+ Vector<uint8_t, 1> c("test", 64);
+ /*
+ for (int i=0; i<m.size; i+=2)
+ m.set(i,1);
+
+ for (int i=0; i<c.size; i++) {
+ fprintf(stderr,"%u", c.get(i));
+ if (i%8==7) fprintf(stderr, " ");
+ }
+ fprintf(stderr,"\n");
+ */
+
+
+ // set a 1 at every position
+ eins.set(0,1);
+ eins.set(9,1);
+ eins.set(18,1);
+ eins.set(27,1);
+ eins.set(36,1);
+ eins.set(45,1);
+ eins.set(54,1);
+ eins.set(63,1);
+
+ // set a 11 at every position
+ zwei.set(0,3);
+ zwei.set(5,3);
+ zwei.set(10,3);
+ zwei.set(15,3);
+
+ // set a 111 at every position
+ vier.set(0,31);
+ vier.set(3,31);
+
+ // fiill with one and delete some
+ for (uint i=0; i<del.size; i++)
+ del.set(i, 3);
+ del.set(2, 1);
+ del.set(5, 2);
+ del.set(7, 0);
+
+ // print the result
+ for (uint i=0; i<eins.size; i++) fprintf(stderr,"%u", eins.get(i)); fprintf(stderr,"\n");
+ for (uint i=0; i<zwei.size; i++) fprintf(stderr,"%u", zwei.get(i)); fprintf(stderr,"\n");
+ for (uint i=0; i<vier.size; i++) fprintf(stderr,"%2u", vier.get(i)); fprintf(stderr,"\n");
+ for (uint i=0; i<del.size; i++) fprintf(stderr,"%u", del.get(i)); fprintf(stderr,"\n");
+
+ return 0; // user has to control the files
+}
diff --git a/core/test_vector_speed.cpp b/core/test_vector_speed.cpp
new file mode 100644
index 0000000..257e8f3
--- /dev/null
+++ b/core/test_vector_speed.cpp
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "scalar.hpp"
+#include "vector.hpp"
+#include "mempool.hpp"
+#include "perftools.hpp"
+
+
+int main() {
+ Timer *timer;
+ Vector<uint8_t, 1> dense("dense", (uint64_t) 1024 * 1024 * 1024 * 800);
+ Vector<uint8_t, 1> sparse("sparse", (uint64_t) 1024 * 1024 * 1024 * 800);
+
+ timer = new Timer();
+ const int dcount = 100000000;
+ for (int i=0; i<dcount; i++)
+ dense.set(i,i%2);
+ print_throughput(timer->diff(), dcount,(char*) "dense");
+
+ timer = new Timer();
+ const int scount = 100000;
+ for (int i=0; i<scount; i++)
+ dense.set(rand(),i%2);
+ print_throughput(timer->diff(), scount,(char*) "sparse");
+
+ return 0; // user has to control the files
+}
diff --git a/core/time.hpp b/core/time.hpp
new file mode 100644
index 0000000..827772b
--- /dev/null
+++ b/core/time.hpp
@@ -0,0 +1,98 @@
+#ifndef yg0goL5EwkwiF99Qqt5ozzKAq9U
+#define yg0goL5EwkwiF99Qqt5ozzKAq9U
+
+#include <assert.h>
+#include <math.h>
+#include <iostream>
+#include <limits>
+
+struct Time {
+ typedef double type;
+ type time;
+
+ Time() {}
+ Time(type time) : time(time) {}
+
+#define Op(op) \
+ Time operator op (const Time & arg) const { return Time(time op arg.time); } \
+ Time& operator op##= (const Time & arg) { time op##= arg.time; return *this; }
+ Op(+);
+ Op(-);
+ Op(*);
+ Op(/);
+ // Op(%);
+#undef Op
+ // WARN: wrong for time/t < epsilon
+ inline unsigned long ceilDiv(const Time & t) const { return ceil(time / t.time); }
+
+
+#define CmpOp(op) inline bool operator op (const Time & arg) const \
+ { return time op arg.time; }
+ CmpOp(==);
+ CmpOp(!=);
+ CmpOp(<=);
+ CmpOp(>=);
+ CmpOp(<);
+ CmpOp(>);
+#undef CmpOp
+
+ void operator= (type t) { time = t; }
+
+ inline type operator() () const { return time; }
+
+ // used as a hack in creating global events; see event_intent.hpp
+ static inline Time never() {
+ return Time(std::numeric_limits<type>::infinity());
+ }
+
+ static inline Time beforeAll() {
+ return Time(- std::numeric_limits<type>::infinity());
+ }
+
+ // a small value, large enough that t + epsilon > t will always hold
+ // during sane simulations
+ static inline Time epsilon() {
+ return Time(0.000001); // leaves approx. 10 digits for time
+ }
+};
+
+namespace std {
+ ostream& operator<< (ostream &os, Time val) {
+ return os << val.time;
+ }
+}
+
+
+struct TimeSpan {
+ TimeSpan(Time start, Time end, Time delta) : start(start), end(end), delta(delta) {
+ assert(start <= end);
+ assert(delta > 0);
+ };
+ Time start, end, delta;
+
+ struct iterator {
+ const TimeSpan &timeSpan;
+ Time current;
+
+ iterator(TimeSpan &parent) : timeSpan(parent), current(timeSpan.start) {}
+
+ bool hasNext() { return current < timeSpan.end; }
+ Time & operator() () { return current; }
+ iterator & operator++() { current = fmin(current.time + timeSpan.delta.time, timeSpan.end.time); return *this; }
+ };
+
+ iterator begin() { return iterator(*this); }
+};
+
+struct FakeTime {
+ FakeTime() {}
+ FakeTime(const Time) {};
+};
+
+namespace std {
+ ostream& operator<< (ostream &os, FakeTime val) {
+ return os << "(FakeTime)";
+ }
+}
+
+#endif // yg0goL5EwkwiF99Qqt5ozzKAq9U
diff --git a/core/topology.hpp b/core/topology.hpp
new file mode 100644
index 0000000..f614739
--- /dev/null
+++ b/core/topology.hpp
@@ -0,0 +1,88 @@
+#ifndef Orz6Wl1nWMpziVYSyArLK0EzFpA
+#define Orz6Wl1nWMpziVYSyArLK0EzFpA
+
+#include "array.hpp"
+#include "pointers.hpp"
+#include "scalar.hpp"
+#include "simlimits.hpp"
+#include "time.hpp"
+
+struct Topology {
+ // ctor for reading topo
+ Topology()
+ : delay("topology_delay"),
+ target("topology_target"),
+ isInitialized("topology_initialized")
+ { assert(isInitialized()); }
+
+ // ctor for writing topo
+ Topology(Array<Time, maxNeurons * maxSynapsesPerNeuron> &aDelay,
+ Array<Ptr<Synapse>::ptr_t, maxNeurons * maxSynapsesPerNeuron> &aTarget)
+ : delay("topology_delay"),
+ target("topology_target"),
+ isInitialized("topology_initialized") {
+ assert(not isInitialized());
+
+ isInitialized() = true;
+ target() = aTarget;
+ delay() = aDelay;
+ }
+
+
+ // tools
+ Ptr<Synapse> synapse(Ptr<Neuron> neuron, uint16_t offset) {
+ return Ptr<Synapse>(target().get(neuron() * maxSynapsesPerNeuron + offset));
+ }
+
+ Time time(Ptr<Neuron> neuron, uint16_t offset) {
+ return delay().get(neuron() * maxSynapsesPerNeuron + offset);
+ }
+
+ // consts
+ inline static Ptr<Synapse> nil() { return Ptr<Synapse>(-1); }
+
+ // storage
+ Scalar<Array<Time, maxNeurons * maxSynapsesPerNeuron>> delay;
+ Scalar<Array<Ptr<Synapse>::ptr_t, maxNeurons * maxSynapsesPerNeuron>> target;
+ Scalar<bool> isInitialized;
+};
+
+/// a helper to generate the offset between the baseTime of an event
+/// and it's arrival time (in priority queue); is zero except for the
+/// case of sending a spike from a neuron
+
+// default case: zero offset
+template<typename ContQuant, typename EventQuant>
+struct TopologicalTimeOffset {
+ inline Time operator() (Topology &topology, typename ContQuant::instance_ptr_t src) {
+ return Time(0.0);
+ }
+};
+
+// neuron emit spike case: lookup offset in topology
+template<>
+struct TopologicalTimeOffset<Neuron, Spike> {
+ inline Time operator() (Topology &topology, Neuron::instance_ptr_t src) {
+ return topology.time(src, 0);
+ }
+};
+
+/// a helper to catch the case of a neuron with empty fanout
+
+// default case: emit event
+template<typename ContQuant, typename EventQuant>
+struct TopologicalEventDiscard {
+ inline bool operator() (Topology &topology, typename ContQuant::instance_ptr_t src) {
+ return false;
+ }
+};
+
+// neuron emit spike case: lookup offset in topology
+template<>
+struct TopologicalEventDiscard<Neuron, Spike> {
+ inline bool operator() (Topology &topology, Neuron::instance_ptr_t src) {
+ return (topology.synapse(src, 0)() == Topology::nil()());
+ }
+};
+
+#endif // Orz6Wl1nWMpziVYSyArLK0EzFpA
diff --git a/core/track_causality.cpp b/core/track_causality.cpp
new file mode 100644
index 0000000..652fa26
--- /dev/null
+++ b/core/track_causality.cpp
@@ -0,0 +1,72 @@
+#include "perftools.hpp"
+#include "sim_causality.hpp"
+#include "system_helpers.hpp"
+
+void realMain(Time start, Time until) {
+ SimCausality<Lists::all_ro> s(start);
+ uint64_t totalEventsProcessed(0), eventsProcessed(-1);
+ const uint64_t eventsPerChunk{10000};
+ Timer timerAll;
+ uint64_t trueMarks[2] = {}, totalMarks[2] = {};
+ std::cout << "miau" << std::endl;
+ while (s.ct < until && until > s.queues.min()) {
+ eventsProcessed = eventsPerChunk - s.run(until, eventsPerChunk);
+ totalEventsProcessed += eventsProcessed;
+ std::cout << "\r\033[K"
+ << s.ct << "\t"
+ << totalEventsProcessed / timerAll.diff() << " Hz(p)\t"
+ << "ETA " << ceil( (until() - s.ct())
+ / (s.ct() - start())
+ * timerAll.diff());
+ std::cout << std::flush;
+
+
+ std::cerr << "MARKSTAT\t" << s.ct << "\t"
+ << s.trueMarks[1] - trueMarks[1] << "\t" << s.totalMarks[1] - totalMarks[1] << "\t"
+ << s.trueMarks[0] - trueMarks[0] << "\t" << s.totalMarks[0] - totalMarks[0] << "\t"
+ << "\n";
+ trueMarks[1] = s.trueMarks[1];
+ trueMarks[0] = s.trueMarks[0];
+ totalMarks[0] = s.totalMarks[0];
+ totalMarks[1] = s.totalMarks[1];
+ }
+ s.run(until, -1);
+
+ if (s.inactiveNeurons) {
+ std::cout << s.inactiveNeurons
+ << " neurons remained inactive during replay time:\n";
+ bool first(0);
+ for (int i=0; i<1000; i++) {
+ if (!s.hasFired[i]) {
+ if (first) {
+ first = false;
+ }else{
+ std::cout << ", ";
+ }
+ std::cout << i;
+ }
+ }
+ std::cout << std::endl;
+ }else{
+ std::cout << "Last neuron went active at " << s.lastNeuronActivation() << "\n";
+ }
+ std::cout << s.trueMarks [1] << " of "
+ << s.totalMarks[1] << " spike arrivals are 0-egal ("
+ << 100 * double(s.trueMarks[1]) / s.totalMarks[1] << " %)\n"
+ << s.trueMarks [0] << " of "
+ << s.totalMarks[0] << " random spikes are 0-egal"
+ << 100 * double(s.trueMarks[0]) / s.totalMarks[0] << " %)\n";
+}
+
+int main(int argc, char **argv) {
+ assert(argc == 3);
+ char *tail;
+ Time start(strtod( argv[1], &tail)); assert(*tail == 0);
+ Time stop( strtod( argv[2], &tail)); assert(*tail == 0);
+
+ assertSimDir();
+ garantueeStackSize(64 * 1024 * 1024);
+ realMain(start, stop);
+
+ return 0;
+}
diff --git a/core/trainer.hpp b/core/trainer.hpp
new file mode 100644
index 0000000..7f0d38c
--- /dev/null
+++ b/core/trainer.hpp
@@ -0,0 +1,52 @@
+#ifndef jB1MwurMlfU1OJE1w1IE29RFf9I
+#define jB1MwurMlfU1OJE1w1IE29RFf9I
+
+#include "event.hpp"
+#include "index.hpp"
+#include "pointers.hpp"
+#include "quant_types.hpp"
+#include "rng.hpp"
+#include "time.hpp"
+
+namespace TrainerImpl {
+
+struct TrainerT;
+
+template <typename PC, typename MI, typename MQ>
+struct Update;
+
+struct TrainerT {
+ explicit TrainerT(RNG::seed_t seed = RNG::seed_t(0));
+
+ template<typename PC, typename MI, typename MQ>
+ TrainerT update(PC &pc, MI &indices, MQ &queues, Time t) const {
+ return Update<PC, MI, MQ>::eval(*this, pc, indices, queues, t);
+ }
+
+ RNG::seed_t rng;
+ Time::type delay;
+ double reward,
+ performance;
+ uint64_t generation,
+ input, output;
+ uint32_t state,
+ resetCounter;
+};
+
+} // NS
+
+using TrainerImpl::TrainerT;
+
+namespace std {
+ ostream& operator<< (ostream &os, TrainerT val) {
+ return os
+ << "Trainer("
+ << val.generation << ", "
+ << val.state << ", "
+ << val.input << ", "
+ << val.output
+ << ")";
+ }
+}
+
+#endif // jB1MwurMlfU1OJE1w1IE29RFf9I
diff --git a/core/trainer_impl.hpp b/core/trainer_impl.hpp
new file mode 100644
index 0000000..d685d66
--- /dev/null
+++ b/core/trainer_impl.hpp
@@ -0,0 +1,162 @@
+#ifndef pAHg29dA1QrONep0XYIUhA0GC08
+#define pAHg29dA1QrONep0XYIUhA0GC08
+
+#include <iostream>
+
+#include "trainer.hpp"
+#include "model.hpp"
+
+#include "index.hpp"
+#include "index_global.hpp"
+#include "index_randomspike.hpp"
+#include "index_spike.hpp"
+#include "index_spike_arrival.hpp"
+
+namespace TrainerImpl {
+
+namespace MC = ModelConsts;
+
+const Time::type delays[6] =
+ { Time::epsilon()(),
+ MC::TrainerInputWindow + MC::TrainerReadoutDelay,
+ MC::TrainerReadoutWindow,
+ Time::epsilon()(),
+ Time::epsilon()(),
+ MC::TrainerInterTrialDelay };
+
+const Time::type randDelays[6] =
+ { 0,
+ MC::TrainerReadoutRandDelay,
+ 0, 0, 0,
+ MC::TrainerInterTrialRandDelay };
+
+TrainerT::TrainerT(RNG::seed_t seed) :
+ rng(seed),
+ delay(delays[0]),
+ reward(0),
+ performance(1.0 / MC::TrainerNumSymbols),
+ generation(0),
+ input(0), output(2),
+ state(0),
+ resetCounter(1) {}
+
+template <typename PC, typename MI, typename MQ>
+struct Update {
+ static TrainerT eval(const TrainerT &old, PC &pc,
+ MI &indices, MQ &queues, Time t) {
+ TrainerT res = old;
+ res.generation++;
+ res.state++;
+ res.reward = 0;
+
+ auto sendSpikes = [&](int mult, double window, int fanIn, double freq) -> void {
+ Time ct = t + Time::epsilon();
+ while (ct < t + window) {
+ // determine dst
+ Ptr<Neuron> dst{uint16_t(RNG::integer(res.rng, fanIn)
+ * mult
+ % MC::NumExcitatory)};
+ Ptr<Neuron> src(dst() + ((Ptr<Neuron>::ptr_t) maxNeurons/2));
+ Ptr<RandomSpike> ptrNE(indices.template get<Index<RandomSpike>>().add(t, ct, src));
+ queues.insert(t, ct, Event<RandomSpike>(ct, src, ptrNE));
+ res.rng = RNG::next(res.rng);
+
+ // determine next spike
+ ct += RNG::expo(res.rng, 1.0 / freq / fanIn);
+ res.rng = RNG::next(res.rng);
+ }
+ };
+
+ switch (res.state) {
+ case 1: // pre: let the network settle
+ case 7: { // pre: give last reward
+ // select and give input
+ res.input = RNG::integer(res.rng, MC::TrainerNumSymbols);
+ res.rng = RNG::next(res.rng);
+ res.state = 1;
+ const int mult_in[10] = // some arbitrarily selected prime number except for
+ {1, 997, 1013, 1021, 1033, 1049, 1061, 1069, 1091, 1097}; // symbol one
+ BOOST_STATIC_ASSERT((MC::TrainerNumSymbols <= 10));
+ std::cerr << "INPUT " << t << std::endl;
+ sendSpikes(mult_in[res.input],
+ MC::TrainerInputWindow, MC::FanIn, MC::TrainerInputFreq);
+ } break;
+
+ case 2:
+ res.resetCounter = 0;
+ break;
+
+ case 4: case 6: // wait
+ break;
+
+ case 3: {
+ // send readout signal
+ std::cerr << "READOUT SIGNAL " << t << std::endl;
+ if (MC::TrainerReadoutFreq > 0)
+ sendSpikes(967, // arbitrary prime
+ MC::TrainerReadoutWindow, MC::FanIn, MC::TrainerReadoutFreq);
+ } break;
+
+
+ case 5: {
+ // evaluate which symbol won, reward (TODO), wait for a longer time
+ const int mult_out[10] = // some arbitrarily selected prime number except for
+ {1, 937, 919, 907, 883, 877, 859, 853, 829, 823}; // symbol one
+ BOOST_STATIC_ASSERT((MC::TrainerNumSymbols <= 10));
+ uint32_t freq[MC::TrainerNumSymbols + 1] = {};
+ uint8_t maxIdx = MC::TrainerNumSymbols,
+ sndIdx = MC::TrainerNumSymbols;
+ uint16_t overlap = uint16_t(MC::FanIn / MC::NumExcitatory * MC::FanOut);
+ std::cerr << "READOUT";
+ for (int o=0; o<MC::TrainerNumSymbols; o++) {
+ for (Ptr<Neuron>::ptr_t i = MC::FanIn - overlap;
+ i < MC::FanIn + MC::FanIn;
+ i++) {
+ Ptr<Neuron> src(uint16_t(mult_out[o] * i % MC::NumExcitatory));
+ PLA_Get<SpikeCounter, ContinuousContext<Neuron> >
+ pla_get(t, ContinuousContext<Neuron>(src));
+ freq[o] += pc.call(pla_get);
+ }
+ if (freq[o] > freq[maxIdx]) {
+ sndIdx = maxIdx;
+ maxIdx = o;
+ }else if (freq[o] > freq[sndIdx]) {
+ sndIdx = o;
+ }
+ std::cerr << " " << freq[o];
+ }
+ bool correct = maxIdx == res.input;
+ res.output = maxIdx;
+ res.reward = (correct ? MC::TrainerReward : (-MC::TrainerPunish))
+ * ((1.0 + MC::TrainerWinAdv) * freq[sndIdx] < freq[maxIdx]);
+ res.performance *= 0.9;
+ res.performance += correct * 0.1;
+ res.resetCounter = 1;
+ std::cerr << "\nWINNER @ " << t << " = " << uint16_t(maxIdx)
+ << " correct = " << uint16_t(res.input)
+ << " reward = " << res.reward
+ << "\n";
+ } break;
+
+ default:
+ assert(false);
+ }
+
+ res.delay = delays[res.state]
+ + randDelays[res.state] * RNG::equi(res.rng);
+ res.rng = RNG::next(res.rng);
+
+ return res;
+ }
+};
+
+/// dummy for sim_replay, must not be called
+template <typename PC>
+struct Update<PC, Void, Void> {
+ static TrainerT eval(const TrainerT&, PC &, Void&, Void&, Time) DO_NOT_CALL;
+};
+
+} // NS
+
+
+#endif // pAHg29dA1QrONep0XYIUhA0GC08
diff --git a/core/type_map.hpp b/core/type_map.hpp
new file mode 100644
index 0000000..e5cedfe
--- /dev/null
+++ b/core/type_map.hpp
@@ -0,0 +1,83 @@
+#ifndef P12JZuE3eei6EPJyqPT0m7uqIrA
+#define P12JZuE3eei6EPJyqPT0m7uqIrA
+
+#include <assert.h>
+
+#include <boost/mpl/assert.hpp>
+#include <boost/mpl/at.hpp>
+#include <boost/mpl/empty.hpp>
+#include <boost/mpl/erase_key.hpp>
+#include <boost/mpl/front.hpp>
+#include <boost/mpl/has_key.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/map.hpp>
+#include <boost/mpl/pair.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include "template_helpers.hpp"
+
+// HINT: in contrast to to typeset wo do not allow the elements to
+// have a (non-default) ctor
+
+namespace TypeMapImpl {
+
+ using namespace boost::mpl;
+ using namespace boost;
+ using boost::mpl::empty;
+
+ template<typename Content>
+ struct TypeMap;
+ template<>
+ struct TypeMap<Void> {
+ // empty constructor and it's param
+ TypeMap() {}
+
+ // get()-dummy never to be called (runtime)
+ template<typename Key, typename Value = Void>
+ inline Value & get() DO_NOT_CALL
+ };
+
+ template<typename Content>
+ struct TypeMap {
+ // type constructions
+ typedef typename front<Content>::type head_t;
+ typedef typename head_t::first key_t;
+ typedef typename head_t::second payload_t;
+
+ typedef typename erase_key<Content, key_t>::type tail_t;
+ typedef typename if_<empty<tail_t>,
+ TypeMap<Void>,
+ TypeMap<tail_t>
+ >::type next_t;
+
+
+ template<typename Key> struct get_t
+ : if_<has_key<Content, Key>,
+ typename at<Content, Key>::type,
+ Void>
+ {};
+
+ // getter
+ template<typename Key, typename Value = typename get_t<Key>::type>
+ inline Value & get() {
+ if (is_same<Key, key_t>::value) {
+ return FORCE_CONV(Value, data);
+ }else{
+ return FORCE_CONV(Value, tail.get<Key>());
+ }
+ }
+
+ // constructor
+ //TypeMap() {}
+
+ // instantiation of data
+ payload_t data;
+ next_t tail;
+ };
+
+}
+
+// lift to global NS
+using TypeMapImpl::TypeMap;
+
+#endif // P12JZuE3eei6EPJyqPT0m7uqIrA
diff --git a/core/type_set.hpp b/core/type_set.hpp
new file mode 100644
index 0000000..206edd0
--- /dev/null
+++ b/core/type_set.hpp
@@ -0,0 +1,91 @@
+#ifndef WSAdISl7wGLmX6tBH6AAVivibiM
+#define WSAdISl7wGLmX6tBH6AAVivibiM
+
+#include <utility>
+
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/or.hpp>
+#include <boost/utility.hpp>
+
+#include "template_helpers.hpp"
+
+namespace TypeSetImpl {
+
+using namespace boost::mpl;
+using boost::is_same;
+
+class Found {};
+
+template <typename... Tail>
+struct TypeSet;
+
+template <typename Head, typename... Tail>
+struct TypeSet<Head, Tail...> : protected MakeUnique<Head, Tail...>::type {
+ typedef typename MakeUnique<Head, Tail...>::type head_t;
+ TypeSet(Head&& head, Tail&&... tail)
+ : head_t(std::move(head)),
+ tail(std::move(tail)...)
+ {}
+ TypeSet() = default;
+
+ template<typename Target>
+ inline Target & get() {
+ typedef is_same<Target, Head> found;
+ typedef typename if_<found, Found, Target>::type nextTarget;
+ if (found::value) {
+ return FORCE_CONV(Target, *this);
+ }else{
+ return FORCE_CONV(Target, tail.get<nextTarget>());
+ }
+ }
+
+ friend std::ostream& operator<< (std::ostream &os, TypeSet val) {
+ return os << val.template get<Head>() << "," << val.tail;
+ }
+
+ TypeSet<Tail...> tail;
+};
+
+template <typename End>
+struct TypeSet<End> : protected MakeUnique<End>::type {
+ typedef typename MakeUnique<End>::type head_t;
+ TypeSet(End&& end) : head_t(std::move(end)) {}
+ TypeSet() = default;
+
+ template<typename Target>
+ inline Target & get() {
+ if (not or_<is_same<Target, Found>, is_same<Target, End>>::value)
+ DO_NOT_CALL;
+ return FORCE_CONV(Target, *this);
+ }
+
+ friend std::ostream& operator<< (std::ostream &os, TypeSet val) {
+ return os << val.template get<End>();
+ }
+};
+
+} // NS
+
+using TypeSetImpl::TypeSet;
+
+// EXAMPLE
+/*
+#include <iostream>
+#include "index_global.hpp"
+using namespace boost::mpl;
+int main() {
+ TypeSetImpl::TypeSet<Index<GlobalMsg>> a(Index<GlobalMsg>{});
+
+ UnpackTypeList<TypeSetImpl::TypeSet, boost::mpl::list<int, double, bool>::type>
+ ::type t(556, 3.1, true), t2;
+ t.get<double>() = t.get<int>() * 1.5;
+
+ std::cout << t.get<int>() << " "
+ << t.get<double>() << " "
+ << t.get<bool>() << " "
+ << std::endl;
+ std::cout << sizeof(TypeSetImpl::TypeSet<Void, Void, Void, Void, Void, Void>) << std::endl;
+ return 0;
+} */
+
+#endif // WSAdISl7wGLmX6tBH6AAVivibiM
diff --git a/core/vector.hpp b/core/vector.hpp
new file mode 100644
index 0000000..b6c7ccb
--- /dev/null
+++ b/core/vector.hpp
@@ -0,0 +1,106 @@
+#ifndef ZnnjWYk20gszrSSZENMjL1hM9gI
+#define ZnnjWYk20gszrSSZENMjL1hM9gI
+
+#include <inttypes.h>
+#include <iostream>
+#include <assert.h>
+#include <boost/static_assert.hpp>
+#include <boost/mpl/if.hpp>
+#include <string>
+
+#include "bit_access.hpp"
+#include "mempool.hpp"
+#include "scalar.hpp"
+#include "string_helpers.hpp"
+#include "template_helpers.hpp"
+
+
+
+namespace VectorImpl {
+
+using std::string;
+using namespace boost::mpl;
+
+template<
+ typename RawPayload,
+ uint32_t width = 8 * sizeof(RawPayload),
+ typename Writable = true_> // true_ or false_
+class Vector {
+public:
+ typedef uint64_t ptr_t;
+ typedef typename if_<Writable,
+ RawPayload,
+ const RawPayload>::type Payload;
+
+ Vector(const string name, const ptr_t size) :
+ mem((size * width + 7) / 8, name),
+ barrierRead("barrier_read_" + name),
+ barrierWrite("barrier_write_" + name),
+ size(size)
+ {}
+ // Vector(Vector&&) = default;
+
+ // direct access
+ Payload & operator() (const ptr_t id) const {
+ BOOST_STATIC_ASSERT((width >= 8));
+ assert(id < size);
+ return *((RawPayload*) (((char*) mem()) + (width / 8) * id));
+ }
+
+ // reader and writer
+ Payload get(const ptr_t id) const {
+ assert(id < size);
+ if (width < 8) {
+ return (uint8_t) bit_extract(mem(), width, id);
+ }else{
+ return *((RawPayload*) (((char*) mem()) + (width / 8) * id));
+ }
+ }
+
+ void set(const ptr_t id, const RawPayload value) const {
+ if (!Writable::value) DO_NOT_CALL;
+ assert(id < size);
+ if (width < 8) {
+ bit_insert(mem(), (uint8_t) width, id, value);
+ }else{
+ *((RawPayload*) (((char*) mem()) + (width / 8) * id)) = value;
+ }
+
+ }
+
+ void sync() const {
+ if (Writable::value) {
+ mem.sync();
+ barrierRead.sync();
+ barrierWrite.sync();
+ }
+ }
+
+ void advise(const ptr_t base, const ptr_t length, int adv) {
+ mem.advise(base * (width / 8), length * (width / 8), adv);
+ }
+
+ // associated memory container
+ MemPool mem;
+
+ // associated r/w-barrier
+ // WARN: these barriers are not checked/updated in Vector but only
+ // by iterators/ranges using them; Vector checks only against
+ // the given size and nothing more
+ Scalar<ptr_t> barrierRead, barrierWrite;
+
+ // maximal number of elements
+ const ptr_t size;
+
+ // garantuee that size = 2^n
+ STATIC_ASSERT_IS_POWER_OF_TWO(width);
+
+private:
+ Vector();
+};
+
+} // namespace VectorImpl
+
+using VectorImpl::Vector;
+
+#endif // ZnnjWYk20gszrSSZENMjL1hM9gI
contact: Jan Huwald // Impressum