sPyNNaker neural_modelling  development
post_events_with_da.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 The University of Manchester
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
19 #ifndef _POST_EVENTS_H_
20 #define _POST_EVENTS_H_
21 
22 // Standard includes
23 #include <stdbool.h>
24 #include <stdint.h>
25 
26 // Include debug header for log_info etc
27 #include <debug.h>
28 
29 //---------------------------------------
30 // Macros
31 //---------------------------------------
33 #define MAX_POST_SYNAPTIC_EVENTS 16
34 
35 typedef struct nm_post_trace_t {
36  int16_t dopamine_trace;
37  post_trace_t post_trace;
39 
40 //---------------------------------------
41 // Structures
42 //---------------------------------------
44 typedef struct {
46  uint32_t count_minus_one;
48  uint32_t times[MAX_POST_SYNAPTIC_EVENTS];
54 
56 typedef struct {
60  uint32_t prev_time;
64  const uint32_t *next_time;
66  uint32_t num_events;
68  uint32_t prev_time_valid;
72 
73 //---------------------------------------
74 // Inline functions
75 //---------------------------------------
76 
77 #if LOG_LEVEL >= LOG_DEBUG
80 static inline void print_event_history(const post_event_history_t *events) {
81  log_debug(" ## printing entire post event history ##");
82  for (uint32_t i = 0; i <= events->count_minus_one; i++) {
83  log_debug("post event: %u, time: %u, trace: %u",
84  i, events->times[i], events->traces[i]);
85  }
86 }
87 #endif
88 
93  uint32_t n_neurons) {
95  spin1_malloc(n_neurons * sizeof(post_event_history_t));
96  // Check allocations succeeded
97  if (post_event_history == NULL) {
98  log_error("Unable to allocate global STDP structures - Out of DTCM: Try "
99  "reducing the number of neurons per core to fix this problem ");
100  return NULL;
101  }
102 
103  // Loop through neurons
104  for (uint32_t n = 0; n < n_neurons; n++) {
105  // Add initial placeholder entry to buffer
106  post_event_history[n].times[0] = 0;
107  post_event_history[n].traces[0].dopamine_trace = 0;
108  post_event_history[n].traces[0].post_trace =
112  }
113 
114  return post_event_history;
115 }
116 
117 //---------------------------------------
124  const post_event_history_t *events, uint32_t begin_time,
125  uint32_t end_time) {
126  // Start at end event - beyond end of post-event history
127  const uint32_t count = events->count_minus_one + 1;
128  const uint32_t *end_event_time = events->times + count;
129  const uint32_t *event_time = end_event_time;
130  const nm_post_trace_t *event_trace = events->traces + count;
131 
132  post_event_window_t window;
133  do {
134  // If this event is still in the future, set it as the end
135  if (*event_time > end_time) {
136  end_event_time = event_time;
137  }
138 
139  // Cache pointer to this event as potential next event and go back one
140  // event.
141  // **NOTE** next_time can be invalid
142  window.next_time = event_time--;
143  window.next_trace = event_trace--;
144 
145  // Keep looping while event occurred after start of window and we
146  // haven't hit beginning of array...
147  } while (*event_time > begin_time && event_time != events->times);
148 
149  // Deference event to use as previous
150  window.prev_time = *event_time;
151  window.prev_trace = *event_trace;
152  window.prev_time_valid = event_time != events->times;
153 
154  // Calculate number of events
155  window.num_events = (end_event_time - window.next_time);
156 
157  // Find a vector of dopamine trace markers, with the LSB
158  // entry in the vector corresponding to the oldest trace in the window
159  window.dopamine_trace_markers =
160  events->dopamine_trace_markers >> (count - window.num_events);
161 
162  // Return window
163  return window;
164 }
165 
166 //---------------------------------------
171  post_event_window_t window) {
172  // Update previous time and increment next time
173  window.prev_time = *window.next_time++;
174  window.prev_trace = *window.next_trace++;
175 
176  // Time will now be valid for sure!
177  window.prev_time_valid = 1;
178 
179  // Decrement remaining events
180  window.num_events--;
181 
182  // Shift the dopamine trace markers to place the next trace marker at LSB
183  window.dopamine_trace_markers >>= 1;
184  return window;
185 }
186 
187 //---------------------------------------
188 
189 // Check the LSB of dopamine trace marker vector to figure out whether the
190 // oldest trace in the given history trace window is dopamine trace
191 static inline bool post_events_next_is_dopamine(
192  post_event_window_t window) {
193  return (window.dopamine_trace_markers & 0x1) != 0x0;
194 }
195 
196 //---------------------------------------
201 static inline void post_events_add(
202  uint32_t time, post_event_history_t *events, post_trace_t post_trace,
203  int16_t dopamine_trace, bool dopamine) {
204  if (events->count_minus_one < MAX_POST_SYNAPTIC_EVENTS - 1) {
205  // If there's still space, store time at current end
206  // and increment count minus 1
207  const uint32_t new_index = ++events->count_minus_one;
208  events->times[new_index] = time;
209  events->traces[new_index].post_trace = post_trace;
210  events->traces[new_index].dopamine_trace = dopamine_trace;
211  if (dopamine) {
212  events->dopamine_trace_markers |= (1 << new_index);
213  } else {
214  events->dopamine_trace_markers &= ~(1 << new_index);
215  }
216  } else {
217  // Otherwise Shuffle down elements
218  // **NOTE** 1st element is always an entry at time 0
219  for (uint32_t e = 2; e < MAX_POST_SYNAPTIC_EVENTS; e++) {
220  events->times[e - 1] = events->times[e];
221  events->traces[e - 1] = events->traces[e];
222  }
223  events->dopamine_trace_markers >>= 1;
224 
225  // Stick new time at end
226  events->times[MAX_POST_SYNAPTIC_EVENTS - 1] = time;
227  events->traces[MAX_POST_SYNAPTIC_EVENTS - 1].post_trace = post_trace;
228  events->traces[MAX_POST_SYNAPTIC_EVENTS - 1].dopamine_trace = dopamine_trace;
229  if (dopamine) {
230  events->dopamine_trace_markers |=
231  (1 << (MAX_POST_SYNAPTIC_EVENTS - 1));
232  } else {
233  events->dopamine_trace_markers &=
234  ~(1 << (MAX_POST_SYNAPTIC_EVENTS - 1));
235  }
236  }
237 }
238 
239 #if LOG_LEVEL >= LOG_DEBUG
245 static inline void print_delayed_window_events(
247  uint32_t begin_time, uint32_t end_time, uint32_t delay_dendritic) {
248  log_info(" ## printing post window ##");
250  post_event_history, begin_time, end_time);
251 
252  while (post_window.num_events > 0) {
253  const uint32_t delayed_post_time =
254  *post_window.next_time + delay_dendritic;
255  log_info("post spike: %u, time: %u, trace: %u, dop_trace: %u",
256  post_window.num_events, delayed_post_time,
257  post_window.next_trace->post_trace,
258  post_window.next_trace->dopamine_trace);
259 
260  post_window = post_events_next(post_window);
261  }
262 }
263 #endif
264 
265 #endif // _POST_EVENTS_H_
static uint32_t time
Simulation time.
static uint32_t n_neurons
The number of neurons on the core.
Definition: neuron.c:45
nm_post_trace_t prev_trace
The previous post-synaptic event trace.
#define MAX_POST_SYNAPTIC_EVENTS
Maximum number of post-synaptic events supported.
uint32_t num_events
The number of events.
Definition: post_events.h:59
static post_event_history_t * post_events_init_buffers(uint32_t n_neurons)
Initialise an array of post-synaptic event histories.
static void print_event_history(const post_event_history_t *events)
Print a post-synaptic event history.
static post_event_window_t post_events_next(post_event_window_t window)
Advance a post-synaptic event window to the next event.
static void post_events_add(uint32_t time, post_event_history_t *events, post_trace_t post_trace, int16_t dopamine_trace, bool dopamine)
Add a post-synaptic event to the history.
post_trace_t prev_trace
The previous post-synaptic event trace.
Definition: post_events.h:51
const uint32_t * next_time
The next post-synaptic event time.
Definition: post_events.h:57
uint32_t prev_time
The previous post-synaptic event time.
Definition: post_events.h:53
const post_trace_t * next_trace
The next post-synaptic event trace.
Definition: post_events.h:55
static post_event_window_t post_events_get_window_delayed(const post_event_history_t *events, uint32_t begin_time, uint32_t end_time)
Get the post-synaptic event window.
uint32_t dopamine_trace_markers
Bit field to indicate whether a trace is dopamine or not.
uint32_t prev_time_valid
Whether the previous post-synaptic event is valid (based on time)
Definition: post_events.h:61
const nm_post_trace_t * next_trace
The next post-synaptic event trace.
static void print_delayed_window_events(const post_event_history_t *post_event_history, uint32_t begin_time, uint32_t end_time, uint32_t delay_dendritic)
Print the post-synaptic event history.
Post event window description.
Definition: post_events.h:49
uint32_t dopamine_trace_markers
Bit field to indicate whether a trace is dopamine or not.
uint32_t count_minus_one
Number of events stored (minus one)
Definition: post_events.h:41
uint32_t times[MAX_POST_SYNAPTIC_EVENTS]
Event times.
Definition: post_events.h:43
post_trace_t traces[MAX_POST_SYNAPTIC_EVENTS]
Event traces.
Definition: post_events.h:45
Trace history of post-synaptic events.
Definition: post_events.h:39
static post_event_history_t * post_event_history
The history data of post-events.
static post_trace_t timing_get_initial_post_trace(void)
Get an initial post-synaptic timing trace.
The type of post-spike traces.