summaryrefslogtreecommitdiff
path: root/core/index_spike_base.hpp
blob: 3ec08c3df60746584a3cb444be24ec63f9cc3708 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#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
contact: Jan Huwald // Impressum