sPyNNaker neural_modelling  7.4.2
synapse_dynamics_stdp_izhikevich_neuromodulation.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 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_with_da.h"
21 #include "stdp_typedefs.h"
22 
23 typedef struct neuromodulation_data_t {
24  uint32_t synapse_type:30;
25  uint32_t is_reward:1;
26  uint32_t is_neuromodulation: 1;
28 
29 typedef struct neuromodulated_synapse_t {
30  weight_t weight;
31  plastic_synapse_t eligibility_synapse;
33 
34 typedef struct nm_update_state_t {
35  accum weight;
36  uint32_t weight_shift;
37  update_state_t eligibility_state;
39 
40 typedef struct nm_final_state_t {
41  weight_t weight;
42  final_state_t final_state;
44 
46  union {
47  struct {
52  };
54  neuromodulation_data_t neuromodulation;
55  };
56 };
57 
58 typedef struct nm_params_t {
59 
62 
64  accum max_weight;
65 
67  accum min_weight;
68 
69 } nm_params_t;
70 
71 static nm_params_t nm_params;
72 
73 static int16_lut *tau_c_lookup;
74 
75 static int16_lut *tau_d_lookup;
76 
77 static uint32_t *nm_weight_shift;
78 
79 extern uint32_t skipped_synapses;
80 
81 #define DECAY_LOOKUP_TAU_C(time) \
82  maths_lut_exponential_decay(time, tau_c_lookup)
83 #define DECAY_LOOKUP_TAU_D(time) \
84  maths_lut_exponential_decay(time, tau_d_lookup)
85 
86 static inline nm_update_state_t get_nm_update_state(
87  neuromodulated_synapse_t synapse, index_t synapse_type) {
88  accum s1615_weight = kbits(synapse.weight << nm_weight_shift[synapse_type]);
89  nm_update_state_t update_state = {
90  .weight=s1615_weight,
91  .weight_shift=nm_weight_shift[synapse_type],
92  .eligibility_state=synapse_structure_get_update_state(
93  synapse.eligibility_synapse, synapse_type)
94  };
95  return update_state;
96 }
97 
98 static inline nm_final_state_t get_nm_final_state(
99  nm_update_state_t update_state) {
100  update_state.weight = kbits(MAX(bitsk(update_state.weight),
101  bitsk(nm_params.min_weight)));
102  update_state.weight = kbits(MIN(bitsk(update_state.weight),
103  bitsk(nm_params.max_weight)));
104  nm_final_state_t final_state = {
105  .weight=(weight_t) (bitsk(update_state.weight) >> update_state.weight_shift),
107  update_state.eligibility_state)
108  };
109  return final_state;
110 }
111 
112 static inline neuromodulated_synapse_t get_nm_final_synaptic_word(
113  nm_final_state_t final_state) {
114  neuromodulated_synapse_t synapse = {
115  .weight=final_state.weight,
116  .eligibility_synapse=synapse_structure_get_final_synaptic_word(
117  final_state.final_state)
118  };
119  return synapse;
120 }
121 
122 static inline post_event_window_t get_post_event_window(
124  const uint32_t delayed_pre_time, const uint32_t delayed_last_pre_time,
125  const uint32_t delay_dendritic) {
126  // Get the post-synaptic window of events to be processed
127  const uint32_t window_begin_time =
128  (delayed_last_pre_time >= delay_dendritic)
129  ? (delayed_last_pre_time - delay_dendritic) : 0;
130  const uint32_t window_end_time =
131  (delayed_pre_time >= delay_dendritic)
132  ? (delayed_pre_time - delay_dendritic) : 0;
134  post_event_history, window_begin_time, window_end_time);
135 
136  log_debug("\t\tbegin_time:%u, end_time:%u - prev_time:%u (valid %u), num_events:%u",
137  window_begin_time, window_end_time, post_window.prev_time,
138  post_window.prev_time_valid, post_window.num_events);
139 
140 #if LOG_LEVEL >= LOG_DEBUG
143  window_end_time, delay_dendritic);
144 #endif
145  return post_window;
146 }
147 
148 static inline accum get_weight_update(int16_t decay_eligibility_trace,
149  int16_t decay_dopamine_trace, int16_t last_dopamine_trace,
150  accum eligibility_weight) {
151  // (exp(-(t_j - t_c) / tau_C).exp(-(t_j - t_c) / tau_D) - 1)
152  int16_t mul_decay = STDP_FIXED_MUL_16X16(
153  decay_eligibility_trace, decay_dopamine_trace)
155  // C_ij.D_c
156  accum mul_trace = mul_accum_fixed(eligibility_weight, last_dopamine_trace);
157  // C_ij.D_c.(exp(-(t_j - t_c) / tau_C).exp(-(t_j - t_c) / tau_D) - 1)
158  accum mul_trace_decay = mul_accum_fixed(mul_trace, mul_decay);
159  // Constant component = 1 / -((1/tau_C) + (1/tau_D))
160  // const_component.C_ij.D_c.
161  // (exp(-(t_j - t_c) / tau_C).exp(-(t_j - t_c) / tau_D) - 1)
162  accum res = mul_trace_decay * nm_params.weight_update_constant_component;
163  return res;
164 }
165 
166 //---------------------------------------
178  const uint32_t time,
179  const uint32_t last_pre_time, const pre_trace_t last_pre_trace,
180  const pre_trace_t new_pre_trace, const uint32_t delay_dendritic,
181  const uint32_t delay_axonal, nm_update_state_t current_state,
183  log_debug("\tPerforming deferred synapse update at time:%u", time);
184  // Apply axonal delay to time of last presynaptic spike
185  const uint32_t delayed_last_pre_time = last_pre_time + delay_axonal;
186  const uint32_t delayed_pre_time = time + delay_axonal;
187 
188  // history <- getHistoryEntries(j, t_old, t)
189  post_event_window_t post_window = get_post_event_window(
190  post_event_history, delayed_pre_time,
191  delayed_last_pre_time, delay_dendritic);
192 
193  // t_c = t_old
194  uint32_t prev_corr_time = delayed_last_pre_time;
195 
196  // D_c = D_prev.exp(-t_c - t_prev / tau_D)
197  int16_t last_dopamine_trace = 0;
198  if (post_window.prev_time_valid) {
199  last_dopamine_trace = STDP_FIXED_MUL_16X16(
200  post_window.prev_trace.dopamine_trace,
201  DECAY_LOOKUP_TAU_D(delayed_last_pre_time - post_window.prev_time));
202  }
203 
204  // Process events in post-synaptic window
205  while (post_window.num_events > 0) {
206  const uint32_t delayed_post_time = *post_window.next_time + delay_dendritic;
207 
208  log_debug("\t\tApplying post-synaptic event at delayed time:%u, pre:%u, prev_corr:%u",
209  delayed_post_time, delayed_last_pre_time, prev_corr_time);
210 
211  // Calculate EXP components of the weight update equation
212  int16_t decay_eligibility_trace = DECAY_LOOKUP_TAU_C(
213  delayed_post_time - prev_corr_time);
214 
215  // No point if dopamine trace is 0 as will just multiply by 0
216  if (last_dopamine_trace != 0) {
217  int16_t decay_dopamine_trace = DECAY_LOOKUP_TAU_D(
218  delayed_post_time - prev_corr_time);
219  accum eligibility_weight = synapse_structure_get_update_weight(
220  current_state.eligibility_state);
221  current_state.weight += get_weight_update(decay_eligibility_trace,
222  decay_dopamine_trace, last_dopamine_trace, eligibility_weight);
223  }
224 
225  // C_ij = C_ij.exp(-(t_j-t_c) / tau_C)
226  synapse_structure_decay_weight(&(current_state.eligibility_state),
227  decay_eligibility_trace);
228 
229  if (!post_events_next_is_dopamine(post_window)) {
230  current_state.eligibility_state = timing_apply_post_spike(
231  delayed_post_time, post_window.next_trace->post_trace,
232  delayed_last_pre_time, last_pre_trace, post_window.prev_time,
233  post_window.prev_trace.post_trace, current_state.eligibility_state);
234  }
235 
236  // Update previous correlation to point to this post-event
237  // D_c = D_j
238  last_dopamine_trace = post_window.next_trace->dopamine_trace;
239  // t_c = t_j
240  prev_corr_time = delayed_post_time;
241 
242  // Go onto next event
243  post_window = post_events_next(post_window);
244  }
245 
246  // Apply spike to state only if there has been a post spike ever
247  if (post_window.prev_time_valid) {
248  const uint32_t delayed_last_post = post_window.prev_time + delay_dendritic;
249  log_debug("\t\tApplying pre-synaptic event at time:%u last post time:%u, prev_corr=%u",
250  delayed_pre_time, delayed_last_post, prev_corr_time);
251  int32_t decay_eligibility_trace = DECAY_LOOKUP_TAU_C(
252  delayed_pre_time - prev_corr_time);
253 
254  if (last_dopamine_trace != 0) {
255  int32_t decay_dopamine_trace = DECAY_LOOKUP_TAU_D(
256  delayed_pre_time - prev_corr_time);
257  accum eligibility_weight = synapse_structure_get_update_weight(
258  current_state.eligibility_state);
259  current_state.weight += get_weight_update(decay_eligibility_trace,
260  decay_dopamine_trace, last_dopamine_trace, eligibility_weight);
261  }
262 
263  // C_ij = C_ij.exp(-(t-t_c) / tau_C)
264  synapse_structure_decay_weight(&(current_state.eligibility_state),
265  decay_eligibility_trace);
266 
267  current_state.eligibility_state = timing_apply_pre_spike(
268  delayed_pre_time, new_pre_trace, delayed_last_pre_time, last_pre_trace,
269  delayed_last_post, post_window.prev_trace.post_trace,
270  current_state.eligibility_state);
271  }
272 
273  return get_nm_final_state(current_state);
274 }
275 
277  address_t address, uint32_t n_neurons, uint32_t n_synapse_types,
278  uint32_t *ring_buffer_to_input_buffer_left_shifts) {
279 
280  if (!synapse_dynamics_stdp_init(&address, &params, n_synapse_types,
281  ring_buffer_to_input_buffer_left_shifts)) {
282  return false;
283  }
284 
286  if (post_event_history == NULL) {
287  return false;
288  }
289 
290  // Load parameters
291  nm_params_t *sdram_params = (nm_params_t *) address;
292  spin1_memcpy(&nm_params, sdram_params, sizeof(nm_params_t));
293 
294  // Read lookup tables
295  address_t lut_address = (void *) &sdram_params[1];
296  tau_c_lookup = maths_copy_int16_lut(&lut_address);
297  tau_d_lookup = maths_copy_int16_lut(&lut_address);
298 
299  // Store weight shifts
300  nm_weight_shift = spin1_malloc(sizeof(uint32_t) * n_synapse_types);
301  if (nm_weight_shift == NULL) {
302  log_error("Could not initialise weight region data");
303  return NULL;
304  }
305  for (uint32_t s = 0; s < n_synapse_types; s++) {
306  nm_weight_shift[s] = ring_buffer_to_input_buffer_left_shifts[s];
307  }
308 
309  return true;
310 }
311 
312 //---------------------------------------
313 // Synaptic row plastic-region implementation
314 //---------------------------------------
316  synapse_row_plastic_data_t *plastic_region_data,
317  synapse_row_fixed_part_t *fixed_region,
318  uint32_t *ring_buffer_to_input_buffer_left_shifts) {
319  __use(plastic_region_data);
320  __use(fixed_region);
321  __use(ring_buffer_to_input_buffer_left_shifts);
322 
323 #if LOG_LEVEL >= LOG_DEBUG
324  // Extract separate arrays of weights (from plastic region),
325  // Control words (from fixed region) and number of plastic synapses
326  const plastic_synapse_t *plastic_words = plastic_region_data->synapses;
327  const control_t *control_words = synapse_row_plastic_controls(fixed_region);
328  size_t plastic_synapse = synapse_row_num_plastic_controls(fixed_region);
329 
330  log_debug("Plastic region %u synapses\n", plastic_synapse);
331 
332  // Loop through plastic synapses
333  for (uint32_t i = 0; i < plastic_synapse; i++) {
334  // Get next control word (auto incrementing control word)
335  uint32_t control_word = *control_words++;
336  uint32_t synapse_type = synapse_row_sparse_type(
337  control_word, synapse_index_bits, synapse_type_mask);
338 
339  // Get weight
341  *plastic_words++, synapse_type);
343  update_state);
344  weight_t weight = synapse_structure_get_final_weight(final_state);
345 
346  log_debug("%08x [%3d: (w: %5u (=", control_word, i, weight);
348  weight, ring_buffer_to_input_buffer_left_shifts[synapse_type]);
349  log_debug("nA) d: %2u, n = %3u)] - {%08x %08x}\n",
353  }
354 #endif // LOG_LEVEL >= LOG_DEBUG
355 }
356 
357 //---------------------------------------
361 static inline index_t sparse_axonal_delay(uint32_t x) {
362 #if 1
363  // No axonal delay, ever
364  __use(x);
365  return 0;
366 #else
367  return (x >> synapse_delay_index_type_bits) & SYNAPSE_AXONAL_DELAY_MASK;
368 #endif
369 }
370 
371 //---------------------------------------
373  uint32_t time, index_t neuron_index) {
374  log_debug("Adding post-synaptic event to trace %u at time:%u", neuron_index, time);
375 
376  // Add post-event
377  post_event_history_t *history = &post_event_history[neuron_index];
378  const uint32_t last_post_time = history->times[history->count_minus_one];
379  const nm_post_trace_t last_post_trace =
380  history->traces[history->count_minus_one];
381  post_trace_t new_post_trace = timing_add_post_spike(
382  time, last_post_time, last_post_trace.post_trace);
383  int32_t new_dopamine_trace = STDP_FIXED_MUL_16X16(
384  last_post_trace.dopamine_trace,
385  DECAY_LOOKUP_TAU_D(time - last_post_time));
386 
387  post_events_add(time, history, new_post_trace, new_dopamine_trace, false);
388 }
389 
390 //---------------------------------------
391 static inline neuromodulated_synapse_t process_plastic_synapse(
392  uint32_t control_word, uint32_t last_pre_time, pre_trace_t last_pre_trace,
393  pre_trace_t new_pre_trace, weight_t *ring_buffers, uint32_t time,
394  uint32_t colour_delay, neuromodulated_synapse_t synapse) {
395  fixed_stdp_synapse s = synapse_dynamics_stdp_get_fixed(control_word, time,
396  colour_delay);
397 
398  // Create update state from the plastic synaptic word
399  nm_update_state_t current_state = get_nm_update_state(synapse, s.type);
400 
401  // Update the synapse state
402  uint32_t post_delay = s.delay_dendritic;
403  if (!params.backprop_delay) {
404  post_delay = 0;
405  }
406  nm_final_state_t final_state =
408  time - colour_delay, last_pre_time, last_pre_trace, new_pre_trace,
409  post_delay, s.delay_axonal, current_state,
410  &post_event_history[s.index]);
411 
412  // Add weight to ring-buffer entry, but only if not too late
413  if (s.delay_dendritic + s.delay_axonal > colour_delay) {
414  synapse_dynamics_stdp_update_ring_buffers(ring_buffers, s,
415  final_state.weight);
416  } else {
418  }
419 
420  return get_nm_final_synaptic_word(final_state);
421 }
422 
423 static inline void process_neuromodulation(
424  synapse_row_plastic_data_t *plastic_region_address,
425  synapse_row_fixed_part_t *fixed_region, uint32_t time) {
426  bool reward = plastic_region_address->neuromodulation.is_reward;
427  uint32_t n_synapses = synapse_row_num_plastic_controls(fixed_region);
428  const uint32_t *words = (uint32_t *) synapse_row_plastic_controls(fixed_region);
429 
430  // Loop through synapses
431  for (; n_synapses > 0; n_synapses--) {
432  // Get next control word (auto incrementing)
433  uint32_t word = *words++;
434  int32_t concentration = (int32_t) synapse_row_sparse_weight(word);
435 
436  if (!reward) {
437  concentration = -concentration;
438  }
439 
440  uint32_t neuron_index = synapse_row_sparse_index(word, 0xFFFF);
441 
442  // Get post event history of this neuron
443  post_event_history_t *history = &post_event_history[neuron_index];
444  const uint32_t last_post_time = history->times[history->count_minus_one];
445  const nm_post_trace_t last_post_trace =
446  history->traces[history->count_minus_one];
447 
448  post_trace_t new_post_trace = timing_decay_post(
449  time, last_post_time, last_post_trace.post_trace);
450  int32_t new_dopamine_trace = STDP_FIXED_MUL_16X16(
451  last_post_trace.dopamine_trace,
452  DECAY_LOOKUP_TAU_D(time - last_post_time));
453  new_dopamine_trace += concentration;
454 
455  // Add a new history trace into the buffer of post synaptic events
456  post_events_add(time, history, new_post_trace, new_dopamine_trace, true);
457  }
458 }
459 
461  synapse_row_plastic_data_t *plastic_region_address,
462  synapse_row_fixed_part_t *fixed_region,
463  weight_t *ring_buffers, uint32_t time, uint32_t colour_delay,
464  bool *write_back) {
465 
466  // If the flag is set, this is neuromodulation
467  if (plastic_region_address->neuromodulation.is_neuromodulation) {
468  process_neuromodulation(plastic_region_address, fixed_region, time);
469  *write_back = false;
470  return true;
471  }
472 
473  // Extract separate arrays of plastic synapses (from plastic region),
474  // Control words (from fixed region) and number of plastic synapses
475  neuromodulated_synapse_t *plastic_words = plastic_region_address->synapses;
476  const control_t *control_words = synapse_row_plastic_controls(fixed_region);
477  size_t n_plastic_synapses = synapse_row_num_plastic_controls(fixed_region);
478 
479  num_plastic_pre_synaptic_events += n_plastic_synapses;
480 
481  // Get last pre-synaptic event from event history
482  const uint32_t last_pre_time = plastic_region_address->history.prev_time;
483  const pre_trace_t last_pre_trace = plastic_region_address->history.prev_trace;
484 
485  // Update pre-synaptic trace
486  log_debug("Adding pre-synaptic event to trace at time:%u", time);
487  plastic_region_address->history.prev_time = time - colour_delay;
488  plastic_region_address->history.prev_trace =
489  timing_add_pre_spike(time - colour_delay, last_pre_time, last_pre_trace);
490 
491  // Loop through plastic synapses
492  for (; n_plastic_synapses > 0; n_plastic_synapses--) {
493  // Get next control word (auto incrementing)
494  uint32_t control_word = *control_words++;
495 
496  plastic_words[0] = process_plastic_synapse(
497  control_word, last_pre_time, last_pre_trace,
498  plastic_region_address->history.prev_trace, ring_buffers, time,
499  colour_delay, plastic_words[0]);
500  plastic_words++;
501  }
502  *write_back = true;
503  return true;
504 }
505 
506 static inline neuromodulated_synapse_t *get_plastic_synapses(synaptic_row_t row) {
507  synapse_row_plastic_data_t *plastic_data = (void *)
509  return plastic_data->synapses;
510 }
511 
513  uint32_t id, synaptic_row_t row, weight_t *weight, uint16_t *delay,
514  uint32_t *offset, uint32_t *synapse_type) {
516  const neuromodulated_synapse_t *plastic_words = get_plastic_synapses(row);
517  const control_t *control_words = synapse_row_plastic_controls(fixed_region);
518  const size_t n_plastic_synapses = synapse_row_num_plastic_controls(fixed_region);
519 
520  // Loop through plastic synapses
521  for (size_t plastic_synapse = n_plastic_synapses; plastic_synapse > 0;
522  plastic_synapse--, plastic_words++) {
523  // Take the weight anyway as this updates the plastic words
524 
525  // Check if index is the one I'm looking for
526  uint32_t control_word = *control_words++;
527  if (synapse_row_sparse_index(control_word, synapse_index_mask) == id) {
529  plastic_words->eligibility_synapse);
530  *offset = n_plastic_synapses - plastic_synapse;
531  *delay = synapse_row_sparse_delay(control_word,
533  *synapse_type = synapse_row_sparse_type(
534  control_word, synapse_index_bits, synapse_type_mask);
535  return true;
536  }
537  }
538 
539  return false;
540 }
541 
542 bool synapse_dynamics_remove_neuron(uint32_t offset, synaptic_row_t row) {
544  neuromodulated_synapse_t *plastic_words = get_plastic_synapses(row);
545  control_t *control_words = synapse_row_plastic_controls(fixed_region);
546  int32_t plastic_synapse = synapse_row_num_plastic_controls(fixed_region);
547 
548  // Delete weight at offset
549  plastic_words[offset] = plastic_words[plastic_synapse - 1];
550 
551  // Delete control word at offset
552  control_words[offset] = control_words[plastic_synapse - 1];
553  control_words[plastic_synapse - 1] = 0;
554 
555  // Decrement FP
556  fixed_region->num_plastic--;
557  return true;
558 }
559 
561  weight_t weight, uint32_t delay, uint32_t type) {
563  neuromodulated_synapse_t *plastic_words = get_plastic_synapses(row);
565  control_t new_control = control_conversion(id, delay, type);
566 
567  control_t *control_words = synapse_row_plastic_controls(fixed_region);
568  int32_t plastic_synapse = synapse_row_num_plastic_controls(fixed_region);
569 
570  // Add weight at offset
571  plastic_words[plastic_synapse] = (neuromodulated_synapse_t) {
572  .eligibility_synapse = new_weight,
573  .weight = weight
574  };
575 
576  // Add control word at offset
577  control_words[plastic_synapse] = new_control;
578 
579  // Increment FP
580  fixed_region->num_plastic++;
581  return true;
582 }
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
static int16_lut * maths_copy_int16_lut(address_t *address)
Copy a Lookup Table from SDRAM to DTCM, updating the address.
Definition: maths.h:57
#define MIN(X, Y)
Minimum. Evaluates arguments twice.
Definition: maths.h:34
#define MAX(X, Y)
Maximum. Evaluates arguments twice.
Definition: maths.h:39
Lookup Table of 16-bit integers.
Definition: maths.h:44
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
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
Post-synaptic events.
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
Basic definitions for STDP.
static accum mul_accum_fixed(accum a, int32_t stdp_fixed)
Multiply an accum by an STDP fixed point and return an accum.
Definition: stdp_typedefs.h:45
#define STDP_FIXED_POINT_ONE
The number 1.0 in the fixed point math used by STDP.
Definition: stdp_typedefs.h:31
#define STDP_FIXED_MUL_16X16(a, b)
Multiply two STDP fixed point numbers.
Definition: stdp_typedefs.h:38
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.
accum max_weight
Maximum of weight after update.
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 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.
accum weight_update_constant_component
Constant part of weight update.
static nm_final_state_t izhikevich_neuromodulation_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, nm_update_state_t current_state, const post_event_history_t *post_event_history)
Synapse update loop core.
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
accum min_weight
Minimum of weight after update (must be >= 0)
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
static weight_t synapse_row_sparse_weight(uint32_t x)
Get the weight from an encoded synapse descriptor.
Definition: synapse_row.h:230
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 accum synapse_structure_get_update_weight(update_state_t state)
Get the current synaptic weight stored in the update state.
static void synapse_structure_decay_weight(update_state_t *state, uint32_t decay)
Decay the synaptic weight value stored by multiplication.
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 post_trace_t timing_decay_post(uint32_t time, uint32_t last_time, post_trace_t last_trace)
Evolve the post trace without adding a spike.
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.