sPyNNaker neural_modelling 7.3.1
Loading...
Searching...
No Matches
synapse_dynamics_external_weight_change.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 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
20#include <neuron/synapses.h>
22#include <stddef.h>
23
24typedef struct limits {
25 weight_t min;
26 weight_t max;
27} limits;
28
29typedef struct change_params {
30 uint32_t n_limits;
31 limits weight_limits[];
33
34typedef struct updatable_synapse_t {
35 weight_t weight;
37
39 uint32_t pre_spike: 31;
40 uint32_t is_update: 1;
41
42 // This is only present if is_update is false
44};
45
46typedef struct fixed_stdp_synapse {
47 uint32_t delay;
48 uint32_t type;
49 uint32_t index;
50 uint32_t ring_buffer_index;
52
55
58
60static uint32_t plastic_saturation_count = 0;
61
64
66 address_t address, uint32_t n_neurons,
67 uint32_t n_synapse_types,
68 UNUSED uint32_t *ring_buffer_to_input_buffer_left_shifts) {
69
70 change_params *sdram_params = (change_params *) address;
71 uint32_t size = sizeof(change_params) + (n_synapse_types * sizeof(limits));
72 params = spin1_malloc(size);
73 if (params == NULL) {
74 log_error("Unable to allocate memory for params");
75 return false;
76 }
77 spin1_memcpy(params, sdram_params, size);
78 for (uint32_t i = 0; i < n_synapse_types; i++) {
79 log_info("Synapse type %u: min = %d, max = %d", i,
80 params->weight_limits[i].min, params->weight_limits[i].max);
81 }
82
84 if (post_event_history == NULL) {
85 log_error("Failed to allocate post_event_history");
86 return false;
87 }
88
89 return true;
90}
91
92//---------------------------------------
94 UNUSED uint32_t time, UNUSED index_t neuron_index) {
95 // Do Nothing - not needed here!
96}
97
98static inline fixed_stdp_synapse synapse_dynamics_stdp_get_fixed(
99 uint32_t control_word, uint32_t time, uint32_t colour_delay) {
100 // Extract control-word components
101 // **NOTE** cunningly, control word is just the same as lower
102 // 16-bits of 32-bit fixed synapse so same functions can be used
103 uint32_t delay = synapse_row_sparse_delay(control_word,
105 uint32_t type_index = synapse_row_sparse_type_index(control_word,
107 uint32_t type = synapse_row_sparse_type(control_word, synapse_index_bits,
109 uint32_t index = synapse_row_sparse_index(control_word, synapse_index_mask);
110 return (fixed_stdp_synapse) {
111 .delay = delay,
112 .type = type,
113 .index = index,
115 (delay + time) - colour_delay, type_index,
117 };
118}
119
120static inline void synapse_dynamics_stdp_update_ring_buffers(
121 weight_t *ring_buffers, fixed_stdp_synapse s, int32_t weight) {
122 uint32_t accumulation = ring_buffers[s.ring_buffer_index] + weight;
123
124 uint32_t sat_test = accumulation & 0xFFFF0000;
125 if (sat_test) {
126 accumulation = 0xFFFF;
128 }
129
130 ring_buffers[s.ring_buffer_index] = accumulation;
131}
132
133//---------------------------------------
134static inline updatable_synapse_t process_plastic_synapse(
135 uint32_t pre_spike, uint32_t control_word, weight_t *ring_buffers,
136 uint32_t time, uint32_t colour_delay, updatable_synapse_t synapse,
137 uint32_t *changed) {
138 fixed_stdp_synapse s = synapse_dynamics_stdp_get_fixed(control_word, time,
139 colour_delay);
140
141
142 // Work out if the weight needs to be updated
143 post_event_history_t *history = &post_event_history[s.index];
144 weight_t min_weight = params->weight_limits[s.type].min;
145 weight_t max_weight = params->weight_limits[s.type].max;
146 log_debug(" Looking at change weight history 0x%08x of %u items to post"
147 " neuron index %u", history, history->count, s.index);
148 for (uint32_t i = 0; i < history->count; i++) {
149 update_post_trace_t *trace = &history->traces[i];
150 log_debug(
151 " Checking history item %u, weight change %d for"
152 " pre-neuron %u, synapse_type = %u",
153 i, trace->weight_change, trace->pre_spike, trace->synapse_type);
154 if (trace->pre_spike == pre_spike && s.type == trace->synapse_type) {
155 int32_t new_weight = synapse.weight + trace->weight_change;
156 if (new_weight < min_weight) {
157 synapse.weight = min_weight;
158 } else if (new_weight > max_weight) {
159 synapse.weight = max_weight;
160 } else {
161 synapse.weight = (weight_t) new_weight;
162 }
163 log_debug(" Weight now %d", synapse.weight);
164 *changed = 1;
165
166 // Remove the done item from history and then go back to make sure
167 // we do the next one!
168 if (post_events_remove(history, i)) {
169 i--;
170 }
171 }
172 }
173
174 // Add weight to ring-buffer entry, but only if not too late
175 if (s.delay > colour_delay) {
176 synapse_dynamics_stdp_update_ring_buffers(ring_buffers, s,
177 synapse.weight);
178 } else {
180 }
181
182 return synapse;
183}
184
185static inline int16_t change_sign(weight_t weight) {
186 union {
187 weight_t weight;
188 int16_t value;
189 } converter;
190 converter.weight = weight;
191 return converter.value;
192}
193
194static inline void process_weight_update(
195 synapse_row_plastic_data_t *plastic_region_address,
196 synapse_row_fixed_part_t *fixed_region) {
197 uint32_t n_synapses = synapse_row_num_plastic_controls(fixed_region);
198 const uint32_t *words = (uint32_t *) synapse_row_plastic_controls(fixed_region);
199 uint32_t pre_spike = plastic_region_address->pre_spike;
200
201 log_debug("Weight change update for pre-neuron %u", pre_spike);
202
203 // Loop through synapses
204 for (; n_synapses > 0; n_synapses--) {
205 // Get next control word (auto incrementing)
206 uint32_t word = *words++;
207 int32_t weight_change = change_sign(synapse_row_sparse_weight(word));
208 uint32_t synapse_type = synapse_row_sparse_type(word,
210 uint32_t neuron_index = synapse_row_sparse_index(word,
212
213 log_debug(" Adding weight change %d to post-neuron %u",
214 weight_change, neuron_index);
215
216 // Get post event history of this neuron
217 post_event_history_t *history = &post_event_history[neuron_index];
218
219 // Add a new history trace into the buffer of post synaptic events
220 post_events_add(history, weight_change, pre_spike, synapse_type);
221 }
222}
223
225 synapse_row_plastic_data_t *plastic_region_address,
226 synapse_row_fixed_part_t *fixed_region,
227 weight_t *ring_buffers, uint32_t time, uint32_t colour_delay,
228 bool *write_back) {
229
230 // If the flag is set, this is neuromodulation
231 if (plastic_region_address->is_update) {
232 process_weight_update(plastic_region_address, fixed_region);
233 *write_back = false;
234 return true;
235 }
236
237 // Extract separate arrays of plastic synapses (from plastic region),
238 // Control words (from fixed region) and number of plastic synapses
239 updatable_synapse_t *plastic_words = plastic_region_address->synapses;
240 const control_t *control_words = synapse_row_plastic_controls(fixed_region);
241 size_t n_plastic_synapses = synapse_row_num_plastic_controls(fixed_region);
242
243 num_plastic_pre_synaptic_events += n_plastic_synapses;
244 uint32_t pre_spike = plastic_region_address->pre_spike;
245
246 log_debug("Checking for weight changes for pre-neuron %u", pre_spike);
247
248 // Loop through plastic synapses
249 for (; n_plastic_synapses > 0; n_plastic_synapses--) {
250 // Get next control word (auto incrementing)
251 uint32_t control_word = *control_words++;
252 uint32_t changed = 0;
253 plastic_words[0] = process_plastic_synapse(pre_spike, control_word,
254 ring_buffers, time, colour_delay, plastic_words[0], &changed);
255 plastic_words++;
256 if (changed) {
257 *write_back = true;
258 }
259 }
260 return true;
261}
262
263input_t synapse_dynamics_get_intrinsic_bias(
264 UNUSED uint32_t time, UNUSED index_t neuron_index) {
265 return ZERO;
266}
267
271
uint32_t index_t
static weight_t * ring_buffers
The ring buffers to be used in the simulation.
Definition c_main.c:118
uint32_t time
The current timer tick value.
Definition c_main.c:94
uint32_t * address_t
void log_error(const char *message,...)
void log_debug(const char *message,...)
void log_info(const char *message,...)
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
#define ZERO
A REAL 0.0.
Definition maths-util.h:123
REAL input_t
The type of an input.
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 post_events_add(uint32_t time, post_event_history_t *events, post_trace_t trace)
Add a post-synaptic event to the history.
uint16_t synapse_type
The synapse type.
uint32_t count
Number of events stored.
int16_t weight_change
The amount to change the weight by (positive or negative)
uint32_t pre_spike
The pre-spike to look out for in doing the update.
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
#define NULL
void spin1_memcpy(void *dst, void const *src, uint len)
API for synapse dynamics.
uint32_t synapse_dynamics_get_plastic_pre_synaptic_events(void)
Get the counters for plastic pre synaptic events based on (if the model was compiled with SYNAPSE_BEN...
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.
uint32_t synapse_dynamics_get_plastic_saturation_count(void)
Get the number of ring buffer saturation events due to adding plastic weights.
static uint32_t plastic_saturation_count
Count of times that the plastic math became saturated.
plastic_synapse_t synapses[]
The per-synapse information.
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.
static change_params * params
Parameters.
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.
The format of the plastic data region of a synaptic row.
uint32_t skipped_synapses
Definition synapses.c:84
static size_t synapse_row_num_plastic_controls(const synapse_row_fixed_part_t *fixed)
Get the number of plastic controls in the row.
static control_t * synapse_row_plastic_controls(synapse_row_fixed_part_t *fixed)
Get the array of plastic controls in the row.
static index_t synapse_row_sparse_type(uint32_t x, uint32_t synapse_index_bits, uint32_t synapse_type_mask)
Get the type code.
static index_t synapse_row_get_ring_buffer_index_combined(uint32_t simulation_timestep, uint32_t combined_synapse_neuron_index, uint32_t synapse_type_index_bits, uint32_t synapse_delay_mask)
Get the index of the ring buffer for a given timestep and combined synapse type and neuron index (as ...
static index_t synapse_row_sparse_index(uint32_t x, uint32_t synapse_index_mask)
Get the index.
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.
static index_t synapse_row_sparse_type_index(uint32_t x, uint32_t synapse_type_index_mask)
Get the type and index.
uint16_t control_t
Define the type of the control data.
static weight_t synapse_row_sparse_weight(uint32_t x)
Get the weight from an encoded synapse descriptor.
The type of the fixed part of the row. The fixed-plastic part follows.
uint32_t synapse_index_mask
Mask to pick out the synapse index.
Definition synapses.c:69
uint32_t synapse_type_index_mask
Mask to pick out the synapse type and index.
Definition synapses.c:65
uint32_t synapse_type_mask
Mask to pick out the synapse type.
Definition synapses.c:73
Operations on synapses.