sPyNNaker neural_modelling  7.4.2
synapse_dynamics_stdp_mad_impl.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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 #include "post_events.h"
21 
28 };
29 
30 extern uint32_t skipped_synapses;
31 
32 //---------------------------------------
44  const uint32_t time,
45  const uint32_t last_pre_time, const pre_trace_t last_pre_trace,
46  const pre_trace_t new_pre_trace, const uint32_t delay_dendritic,
47  const uint32_t delay_axonal, update_state_t current_state,
49  // Apply axonal delay to time of last presynaptic spike
50  const uint32_t delayed_last_pre_time = last_pre_time + delay_axonal;
51 
52  // Get the post-synaptic window of events to be processed
53  const uint32_t window_begin_time =
54  (delayed_last_pre_time >= delay_dendritic)
55  ? (delayed_last_pre_time - delay_dendritic) : 0;
56  const uint32_t delayed_pre_time = time + delay_axonal;
57  const uint32_t window_end_time =
58  (delayed_pre_time >= delay_dendritic)
59  ? (delayed_pre_time - delay_dendritic) : 0;
61  post_event_history, window_begin_time, window_end_time);
62 
63  log_debug("\tPerforming deferred synapse update at time:%u", time);
64  log_debug("\t\tbegin_time:%u, end_time:%u - prev_time:%u (valid %u), num_events:%u",
65  window_begin_time, window_end_time, post_window.prev_time,
66  post_window.prev_time_valid, post_window.num_events);
67 
68 #if LOG_LEVEL >= LOG_DEBUG
71  window_end_time, delay_dendritic);
72 #endif
73 
74  // Process events in post-synaptic window
75  while (post_window.num_events > 0) {
76  const uint32_t delayed_post_time = *post_window.next_time + delay_dendritic;
77 
78  log_debug("\t\tApplying post-synaptic event at delayed time:%u, pre:%u\n",
79  delayed_post_time, delayed_last_pre_time);
80 
81  // Apply spike to state
82  current_state = timing_apply_post_spike(
83  delayed_post_time, *post_window.next_trace, delayed_last_pre_time,
84  last_pre_trace, post_window.prev_time, post_window.prev_trace,
85  current_state);
86 
87  // Go onto next event
88  post_window = post_events_next(post_window);
89  }
90 
91  // Apply spike to state only if there has been a post spike ever
92  if (post_window.prev_time_valid) {
93  const uint32_t delayed_last_post = post_window.prev_time + delay_dendritic;
94  log_debug("\t\tApplying pre-synaptic event at time:%u last post time:%u\n",
95  delayed_pre_time, delayed_last_post);
96  current_state = timing_apply_pre_spike(
97  delayed_pre_time, new_pre_trace, delayed_last_pre_time, last_pre_trace,
98  delayed_last_post, post_window.prev_trace, current_state);
99  }
100 
101  // Return final synaptic word and weight
102  return synapse_structure_get_final_state(current_state);
103 }
104 
106  address_t address, uint32_t n_neurons, uint32_t n_synapse_types,
107  uint32_t *ring_buffer_to_input_buffer_left_shifts) {
108 
109  if (!synapse_dynamics_stdp_init(&address, &params, n_synapse_types,
110  ring_buffer_to_input_buffer_left_shifts)) {
111  return false;
112  }
113 
115  if (post_event_history == NULL) {
116  return false;
117  }
118 
119  return true;
120 }
121 
122 //---------------------------------------
123 // Synaptic row plastic-region implementation
124 //---------------------------------------
126  synapse_row_plastic_data_t *plastic_region_data,
127  synapse_row_fixed_part_t *fixed_region,
128  uint32_t *ring_buffer_to_input_buffer_left_shifts) {
129  __use(plastic_region_data);
130  __use(fixed_region);
131  __use(ring_buffer_to_input_buffer_left_shifts);
132 
133 #if LOG_LEVEL >= LOG_DEBUG
134  // Extract separate arrays of weights (from plastic region),
135  // Control words (from fixed region) and number of plastic synapses
136  const plastic_synapse_t *plastic_words = plastic_region_data->synapses;
137  const control_t *control_words = synapse_row_plastic_controls(fixed_region);
138  size_t plastic_synapse = synapse_row_num_plastic_controls(fixed_region);
139 
140  log_debug("Plastic region %u synapses\n", plastic_synapse);
141 
142  // Loop through plastic synapses
143  for (uint32_t i = 0; i < plastic_synapse; i++) {
144  // Get next control word (auto incrementing control word)
145  uint32_t control_word = *control_words++;
146  uint32_t synapse_type = synapse_row_sparse_type(
147  control_word, synapse_index_bits, synapse_type_mask);
148 
149  // Get weight
151  *plastic_words++, synapse_type);
153  update_state);
154  weight_t weight = synapse_structure_get_final_weight(final_state);
155 
156  log_debug("%08x [%3d: (w: %5u (=", control_word, i, weight);
158  weight, ring_buffer_to_input_buffer_left_shifts[synapse_type]);
159  log_debug("nA) d: %2u, n = %3u)] - {%08x %08x}\n",
163  }
164 #endif // LOG_LEVEL >= LOG_DEBUG
165 }
166 
167 //---------------------------------------
171 static inline index_t sparse_axonal_delay(uint32_t x) {
172 #if 1
173  // No axonal delay, ever
174  __use(x);
175  return 0;
176 #else
177  return (x >> synapse_delay_index_type_bits) & SYNAPSE_AXONAL_DELAY_MASK;
178 #endif
179 }
180 
181 //---------------------------------------
183  uint32_t time, index_t neuron_index) {
184  log_debug("Adding post-synaptic event to trace at time:%u", time);
185 
186  // Add post-event
187  post_event_history_t *history = &post_event_history[neuron_index];
188  const uint32_t last_post_time = history->times[history->count_minus_one];
189  const post_trace_t last_post_trace =
190  history->traces[history->count_minus_one];
191  post_events_add(time, history,
192  timing_add_post_spike(time, last_post_time, last_post_trace));
193 }
194 
195 //---------------------------------------
196 static inline plastic_synapse_t process_plastic_synapse(
197  uint32_t control_word, uint32_t last_pre_time, pre_trace_t last_pre_trace,
198  pre_trace_t new_pre_trace, weight_t *ring_buffers, uint32_t time,
199  uint32_t colour_delay, plastic_synapse_t synapse) {
200  fixed_stdp_synapse s = synapse_dynamics_stdp_get_fixed(control_word, time,
201  colour_delay);
202 
203  // Create update state from the plastic synaptic word
205  synapse, s.type);
206 
207  // Update the synapse state
208  uint32_t post_delay = s.delay_dendritic;
209  if (!params.backprop_delay) {
210  post_delay = 0;
211  }
213  time - colour_delay, last_pre_time, last_pre_trace, new_pre_trace,
214  post_delay, s.delay_axonal, current_state,
215  &post_event_history[s.index]);
216 
217  // Add weight to ring-buffer entry, but only if not too late
218  if (s.delay_axonal + s.delay_dendritic > colour_delay) {
219  int32_t weight = synapse_structure_get_final_weight(final_state);
220  synapse_dynamics_stdp_update_ring_buffers(ring_buffers, s, weight);
221  } else {
223  }
224 
225  return synapse_structure_get_final_synaptic_word(final_state);
226 }
227 
229  synapse_row_plastic_data_t *plastic_region_address,
230  synapse_row_fixed_part_t *fixed_region,
231  weight_t *ring_buffers, uint32_t time, uint32_t colour_delay,
232  bool *write_back) {
233  // Extract separate arrays of plastic synapses (from plastic region),
234  // Control words (from fixed region) and number of plastic synapses
235  plastic_synapse_t *plastic_words = plastic_region_address->synapses;
236  const control_t *control_words = synapse_row_plastic_controls(fixed_region);
237  size_t n_plastic_synapses = synapse_row_num_plastic_controls(fixed_region);
238 
239  num_plastic_pre_synaptic_events += n_plastic_synapses;
240 
241  // Get last pre-synaptic event from event history
242  const uint32_t last_pre_time = plastic_region_address->history.prev_time;
243  const pre_trace_t last_pre_trace = plastic_region_address->history.prev_trace;
244 
245  // Update pre-synaptic trace
246  log_debug("Adding pre-synaptic event to trace at time:%u", time);
247  plastic_region_address->history.prev_time = time - colour_delay;
248  plastic_region_address->history.prev_trace =
249  timing_add_pre_spike(time - colour_delay, last_pre_time, last_pre_trace);
250 
251  // Loop through plastic synapses
252  for (; n_plastic_synapses > 0; n_plastic_synapses--) {
253  // Get next control word (auto incrementing)
254  uint32_t control_word = *control_words++;
255 
256  plastic_words[0] = process_plastic_synapse(
257  control_word, last_pre_time, last_pre_trace,
258  plastic_region_address->history.prev_trace, ring_buffers, time,
259  colour_delay, plastic_words[0]);
260  plastic_words++;
261  }
262  *write_back = true;
263  return true;
264 }
265 
267  uint32_t id, synaptic_row_t row, weight_t *weight, uint16_t *delay,
268  uint32_t *offset, uint32_t *synapse_type) {
270  const synapse_row_plastic_data_t *plastic_data = (void *)
272  const plastic_synapse_t *plastic_words = plastic_data->synapses;
273  const control_t *control_words = synapse_row_plastic_controls(fixed_region);
274  const size_t n_plastic_synapses = synapse_row_num_plastic_controls(fixed_region);
275 
276  // Loop through plastic synapses
277  for (size_t plastic_synapse = n_plastic_synapses; plastic_synapse > 0;
278  plastic_synapse--) {
279  // Take the weight anyway as this updates the plastic words
280  *weight = synapse_structure_get_weight(*plastic_words++);
281 
282  // Check if index is the one I'm looking for
283  uint32_t control_word = *control_words++;
284  if (synapse_row_sparse_index(control_word, synapse_index_mask) == id) {
285  *offset = n_plastic_synapses - plastic_synapse;
286  *delay = synapse_row_sparse_delay(control_word,
288  *synapse_type = synapse_row_sparse_type(
289  control_word, synapse_index_bits, synapse_type_mask);
290  return true;
291  }
292  }
293 
294  return false;
295 }
296 
297 bool synapse_dynamics_remove_neuron(uint32_t offset, synaptic_row_t row) {
299  synapse_row_plastic_data_t *plastic_data = (void *)
301  plastic_synapse_t *plastic_words = plastic_data->synapses;
302 
303  control_t *control_words = synapse_row_plastic_controls(fixed_region);
304  int32_t plastic_synapse = synapse_row_num_plastic_controls(fixed_region);
305 
306  // Delete weight at offset
307  plastic_words[offset] = plastic_words[plastic_synapse - 1];
308 
309  // Delete control word at offset
310  control_words[offset] = control_words[plastic_synapse - 1];
311  control_words[plastic_synapse - 1] = 0;
312 
313  // Decrement FP
314  fixed_region->num_plastic--;
315  return true;
316 }
317 
319  weight_t weight, uint32_t delay, uint32_t type) {
322  plastic_synapse_t *plastic_words = plastic_data->synapses;
324  control_t new_control = control_conversion(id, delay, type);
325 
326  control_t *control_words = synapse_row_plastic_controls(fixed_region);
327  int32_t plastic_synapse = synapse_row_num_plastic_controls(fixed_region);
328 
329  // Add weight at offset
330  plastic_words[plastic_synapse] = new_weight;
331 
332  // Add control word at offset
333  control_words[plastic_synapse] = new_control;
334 
335  // Increment FP
336  fixed_region->num_plastic++;
337  return true;
338 }
static weight_t * ring_buffers
The ring buffers to be used in the simulation.
Definition: c_main.c:118
static uint32_t time
Simulation time.
uint32_t synapse_delay_mask
The mask to get the synaptic delay from a "synapse".
Definition: local_only.c:71
uint32_t synapse_type_index_bits
The number of bits used by the synapse type and post-neuron index.
Definition: local_only.c:74
uint32_t synapse_index_bits
The number of bits used by just the post-neuron index.
Definition: local_only.c:77
struct synaptic_row * synaptic_row_t
The type of a synaptic row.
static uint32_t n_neurons
The number of neurons on the core.
Definition: neuron.c:45
static uint32_t n_synapse_types
The number of synapse types.
Definition: neuron.c:51
Post-synaptic events.
static post_event_history_t * post_events_init_buffers(uint32_t n_neurons)
Initialise an array of post-synaptic event histories.
Definition: post_events.h:83
static void print_event_history(const post_event_history_t *events)
Print a post-synaptic event history.
Definition: post_events.h:71
static post_event_window_t post_events_next(post_event_window_t window)
Advance a post-synaptic event window to the next event.
Definition: post_events.h:153
static void post_events_add(uint32_t time, post_event_history_t *events, post_trace_t trace)
Add a post-synaptic event to the history.
Definition: post_events.h:172
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.
Definition: post_events.h:111
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.
Definition: post_events.h:200
uint32_t num_events
The number of events.
Definition: post_events.h:59
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
uint32_t prev_time_valid
Whether the previous post-synaptic event is valid (based on time)
Definition: post_events.h:61
Post event window description.
Definition: post_events.h:49
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
plastic_synapse_t synapses[]
The per-synapse information.
pre_event_history_t history
The pre-event history.
The format of the plastic data region of a synaptic row.
STDP core implementation.
uint32_t backprop_delay
The back-propagation delay, in basic simulation timesteps.
static control_t control_conversion(uint32_t id, uint32_t delay, uint32_t type)
packing all of the information into the required plastic control word
static stdp_params params
Configuration parameters.
pre_trace_t prev_trace
The event trace.
static post_event_history_t * post_event_history
The history data of post-events.
static uint32_t num_plastic_pre_synaptic_events
Count of pre-synaptic events relevant to plastic processing.
uint32_t prev_time
The event time.
The type of history data of pre-events.
bool synapse_dynamics_initialise(address_t address, uint32_t n_neurons, uint32_t n_synapse_types, uint32_t *ring_buffer_to_input_buffer_left_shifts)
Initialise the synapse dynamics.
void synapse_dynamics_process_post_synaptic_event(uint32_t time, index_t neuron_index)
Inform the synapses that the neuron fired.
bool synapse_dynamics_find_neuron(uint32_t id, synaptic_row_t row, weight_t *weight, uint16_t *delay, uint32_t *offset, uint32_t *synapse_type)
Search the synaptic row for the the connection with the specified post-synaptic ID.
static final_state_t plasticity_update_synapse(const uint32_t time, const uint32_t last_pre_time, const pre_trace_t last_pre_trace, const pre_trace_t new_pre_trace, const uint32_t delay_dendritic, const uint32_t delay_axonal, update_state_t current_state, const post_event_history_t *post_event_history)
Synapse update loop core.
static index_t sparse_axonal_delay(uint32_t x)
Get the axonal delay.
void synapse_dynamics_print_plastic_synapses(synapse_row_plastic_data_t *plastic_region_data, synapse_row_fixed_part_t *fixed_region, uint32_t *ring_buffer_to_input_buffer_left_shifts)
Print the synapse dynamics.
bool synapse_dynamics_add_neuron(uint32_t id, synaptic_row_t row, weight_t weight, uint32_t delay, uint32_t type)
Add an entry in the synaptic row.
bool synapse_dynamics_remove_neuron(uint32_t offset, synaptic_row_t row)
Remove the entry at the specified offset in the synaptic row.
uint32_t skipped_synapses
Definition: synapses.c:84
bool synapse_dynamics_process_plastic_synapses(synapse_row_plastic_data_t *plastic_region_address, synapse_row_fixed_part_t *fixed_region, weight_t *ring_buffers, uint32_t time, uint32_t colour_delay, bool *write_back)
Process the dynamics of the synapses.
static size_t synapse_row_num_plastic_controls(const synapse_row_fixed_part_t *fixed)
Get the number of plastic controls in the row.
Definition: synapse_row.h:164
static synapse_row_fixed_part_t * synapse_row_fixed_region(synaptic_row_t row)
Get the address of the non-plastic (or fixed) region.
Definition: synapse_row.h:147
static index_t synapse_row_sparse_type(uint32_t x, uint32_t synapse_index_bits, uint32_t synapse_type_mask)
Get the type code.
Definition: synapse_row.h:201
static index_t synapse_row_sparse_index(uint32_t x, uint32_t synapse_index_mask)
Get the index.
Definition: synapse_row.h:190
static control_t * synapse_row_plastic_controls(synapse_row_fixed_part_t *fixed)
Get the array of plastic controls in the row.
Definition: synapse_row.h:172
static index_t synapse_row_sparse_delay(uint32_t x, uint32_t synapse_type_index_bits, uint32_t synapse_delay_mask)
Get the delay from an encoded synapse descriptor.
Definition: synapse_row.h:222
size_t num_plastic
The number of plastic controls in data
Definition: synapse_row.h:120
static synapse_row_plastic_data_t * synapse_row_plastic_region(synaptic_row_t row)
Get the address of the plastic region.
Definition: synapse_row.h:138
uint16_t control_t
Define the type of the control data.
Definition: synapse_row.h:106
The type of the fixed part of the row. The fixed-plastic part follows.
Definition: synapse_row.h:118
static plastic_synapse_t synapse_structure_get_final_synaptic_word(final_state_t final_state)
Get the final plastic synapse data from the final state.
static plastic_synapse_t synapse_structure_create_synapse(weight_t weight)
Create the initial plastic synapse data.
static update_state_t synapse_structure_get_update_state(plastic_synapse_t synaptic_word, index_t synapse_type)
Get the update state from the synapse structure.
static weight_t synapse_structure_get_final_weight(final_state_t final_state)
Get the final weight from the final state.
static final_state_t synapse_structure_get_final_state(update_state_t state)
Get the final state from the update state.
static weight_t synapse_structure_get_weight(plastic_synapse_t synaptic_word)
Get the current synaptic weight from the plastic synapse data.
Plastic synapse contains normal 16-bit weight and an accumulator.
uint32_t synapse_index_mask
Mask to pick out the synapse index.
Definition: synapses.c:69
uint32_t synapse_type_mask
Mask to pick out the synapse type.
Definition: synapses.c:73
static void synapses_print_weight(weight_t weight, uint32_t left_shift)
Print the weight of a synapse.
Definition: synapses.h:68
static post_trace_t timing_add_post_spike(uint32_t time, uint32_t last_time, post_trace_t last_trace)
Add a post spike to the post trace.
static update_state_t timing_apply_pre_spike(uint32_t time, pre_trace_t trace, uint32_t last_pre_time, pre_trace_t last_pre_trace, uint32_t last_post_time, post_trace_t last_post_trace, update_state_t previous_state)
Apply a pre-spike timing rule state update.
static pre_trace_t timing_add_pre_spike(uint32_t time, uint32_t last_time, pre_trace_t last_trace)
Add a pre spike to the pre trace.
static update_state_t timing_apply_post_spike(uint32_t time, post_trace_t trace, uint32_t last_pre_time, pre_trace_t last_pre_trace, uint32_t last_post_time, post_trace_t last_post_trace, update_state_t previous_state)
Apply a post-spike timing rule state update.
The type of post-spike traces.
The type of pre-spike traces.