1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
|
#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
|