sPyNNaker neural_modelling  7.4.2
topographic_map_impl.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 
25 
26 #include <random.h>
27 #include <spin1_api.h>
28 #include <debug.h>
29 #include <stdfix-full-iso.h>
30 #include <circular_buffer.h>
31 #include <recording.h>
32 
33 #include <neuron/synapse_row.h>
34 
35 #include <neuron/synapses.h>
36 
37 #include <common/maths-util.h>
38 #include <simulation.h>
39 
40 // Interface for rules
43 #include "formation/formation.h"
44 
46 enum {
48  ELIM_FLAG = 0,
50  FORM_FLAG = 1
51 };
53 #define ID_SHIFT 1
55 #define PRE_ID_SHIFT 9
56 
57 //-----------------------------------------------------------------------------
58 // Structures and global data |
59 //-----------------------------------------------------------------------------
60 
63 
66 
69 
71 static formation_params_t **formation_params;
72 
74 static elimination_params_t **elimination_params;
75 
79 static circular_buffer current_state_queue;
80 
85 static circular_buffer free_states;
86 
89 
92  uint32_t time;
93  uint32_t value;
95 
98 
100 static uint32_t last_rewiring_time = 0;
101 
103  uint32_t n_elements =
104  rewiring_data.s_max * rewiring_data.machine_no_atoms;
105 
106  for (uint32_t i=0; i < n_elements; i++) {
107  log_debug("index %d, pop index %d, sub pop index %d, neuron_index %d",
108  i, post_to_pre_table[i].pop_index,
109  post_to_pre_table[i].sub_pop_index,
110  post_to_pre_table[i].neuron_index);
111  }
112 }
113 
114 //-----------------------------------------------------------------------------
115 // Access helpers for circular buffers
116 //-----------------------------------------------------------------------------
117 static inline void _queue_state(current_state_t *state) {
118  if (__builtin_expect(
119  !circular_buffer_add(current_state_queue, (uint32_t) state), 0)) {
120  log_error("Could not add state (0x%08x) to queued states", state);
121  rt_error(RTE_SWERR);
122  }
123 }
124 
125 static inline current_state_t *_get_state(void) {
126  current_state_t *state;
127  if (__builtin_expect(
128  !circular_buffer_get_next(current_state_queue, (uint32_t *) &state),
129  0)) {
130  log_error("Could not read a state!");
131  rt_error(RTE_SWERR);
132  }
133  return state;
134 }
135 
136 static inline void _free_state(current_state_t *state) {
137  if (__builtin_expect(
138  !circular_buffer_add(free_states, (uint32_t) state), 0)) {
139  log_error("Could not add state (0x%08x) to free states", state);
140  rt_error(RTE_SWERR);
141  }
142 }
143 
144 static inline current_state_t *_alloc_state(void) {
145  current_state_t *state;
146  if (__builtin_expect(
147  !circular_buffer_get_next(free_states, (uint32_t *) &state), 0)) {
148  log_error("Ran out of states!");
149  rt_error(RTE_SWERR);
150  }
151  return state;
152 }
153 
154 //-----------------------------------------------------------------------------
155 // Initialisation |
156 //-----------------------------------------------------------------------------
157 
159  address_t sdram_sp_address, uint32_t *recording_regions_used) {
160  uint8_t *data = sp_structs_read_in_common(
161  sdram_sp_address, &rewiring_data, &pre_info, &post_to_pre_table);
162 
163  // Allocate current states
164  uint32_t n_states = 1;
165  if (rewiring_data.fast) {
166  n_states = rewiring_data.p_rew;
167  }
168  log_debug("Rewiring period %u, fast=%u, n_states=%u",
169  rewiring_data.p_rew, rewiring_data.fast, n_states);
170  // Add one to number of states as buffer wastes an entry
171  current_state_queue = circular_buffer_initialize(n_states + 1);
172  if (current_state_queue == NULL) {
173  log_error("Could not allocate current state queue");
174  rt_error(RTE_SWERR);
175  }
176  // Add one to number of states as buffer wastes an entry
177  free_states = circular_buffer_initialize(n_states + 1);
178  if (free_states == NULL) {
179  log_error("Could not allocate free state queue");
180  }
181  current_state_t *states = spin1_malloc(n_states * sizeof(current_state_t));
182  if (states == NULL) {
183  log_error("Could not allocate states");
184  rt_error(RTE_SWERR);
185  }
186  for (uint32_t i = 0; i < n_states; i++) {
187  _free_state(&states[i]);
188  }
189 
190  partner_init(&data);
191 
192  formation_params = spin1_malloc(
193  rewiring_data.no_pre_pops * sizeof(struct formation_params *));
194  if (formation_params == NULL) {
195  log_error("Could not initialise formation parameters");
196  rt_error(RTE_SWERR);
197  }
198  for (uint32_t i = 0; i < rewiring_data.no_pre_pops; i++) {
200  }
201 
202  elimination_params = spin1_malloc(
203  rewiring_data.no_pre_pops * sizeof(struct elimination_params *));
204  if (elimination_params == NULL) {
205  log_error("Could not initialise elimination parameters");
206  rt_error(RTE_SWERR);
207  }
208  for (uint32_t i = 0; i < rewiring_data.no_pre_pops; i++) {
210  }
211 
212  rewiring_recording_index = *recording_regions_used;
213  *recording_regions_used = rewiring_recording_index + 1;
214 
215  log_debug("The rewiring_recording_index is %u", rewiring_recording_index);
216 
217  return true;
218 }
219 
221  uint32_t time, spike_t *spike, pop_table_lookup_result_t *result) {
222 
223  // Randomly choose a postsynaptic (application neuron)
224  uint32_t post_id = rand_int(rewiring_data.app_no_atoms,
225  rewiring_data.shared_seed);
226 
227  // Check if neuron is in the current machine vertex
228  if (post_id < rewiring_data.low_atom ||
229  post_id > rewiring_data.high_atom) {
230  return false;
231  }
232  post_id -= rewiring_data.low_atom;
233 
234  // Select an arbitrary synaptic element for the neurons
235  uint32_t row_offset = post_id * rewiring_data.s_max;
236  uint32_t column_offset = rand_int(rewiring_data.s_max,
237  rewiring_data.local_seed);
238  uint32_t total_offset = row_offset + column_offset;
239  post_to_pre_entry entry = post_to_pre_table[total_offset];
240  uint32_t pre_app_pop = 0, pre_sub_pop = 0, m_pop_index = 0, neuron_id = 0;
241  if (entry.neuron_index == 0xFFFF) {
242  if (!potential_presynaptic_partner(time, &pre_app_pop, &pre_sub_pop,
243  &neuron_id, spike, &m_pop_index)) {
244  return false;
245  }
246  } else {
247  pre_app_pop = entry.pop_index;
248  pre_sub_pop = entry.sub_pop_index;
249  neuron_id = entry.neuron_index;
250  }
251  pre_info_t *prepop_info = pre_info.prepop_info[pre_app_pop];
252  key_atom_info_t *key_atom_info = &prepop_info->key_atom_info[pre_sub_pop];
253  if (entry.neuron_index != 0xFFFF) {
254  *spike = key_atom_info->key | (neuron_id << key_atom_info->n_colour_bits);
255  m_pop_index = key_atom_info->m_pop_index;
256  }
257 
258  if (!population_table_get_first_address(*spike, result)) {
259  log_error("FAIL@key %d", *spike);
260  rt_error(RTE_SWERR);
261  }
262  uint32_t index = 0;
263  while (index < m_pop_index) {
264  if (!population_table_get_next_address(spike, result)) {
265  log_error("FAIL@key %d, index %d (failed at %d)",
266  *spike, m_pop_index, index);
267  rt_error(RTE_SWERR);
268  }
269  index++;
270  }
271 
272  // Saving current state
273  current_state_t *current_state = _alloc_state();
274  current_state->pre_syn_id = neuron_id;
275  current_state->post_syn_id = post_id;
276  current_state->element_exists = entry.neuron_index != 0xFFFF;
277  current_state->post_to_pre_table_entry = &post_to_pre_table[total_offset];
278  current_state->pre_population_info = prepop_info;
279  current_state->key_atom_info = key_atom_info;
280  current_state->post_to_pre.neuron_index = neuron_id;
281  current_state->post_to_pre.pop_index = pre_app_pop;
282  current_state->post_to_pre.sub_pop_index = pre_sub_pop;
283  current_state->local_seed = &rewiring_data.local_seed;
284  current_state->post_low_atom = rewiring_data.low_atom;
285  current_state->with_replacement = rewiring_data.with_replacement;
286  _queue_state(current_state);
287  return true;
288 }
289 
290 static bool do_formation(uint32_t time, synaptic_row_t restrict row,
291  current_state_t *restrict current_state) {
292  if (synaptogenesis_formation_rule(current_state,
293  formation_params[current_state->post_to_pre.pop_index], time, row)) {
294  // Create recorded value
295  // (bottom bit: add/remove, next 8: local id, remainder: pre global id)
296  uint32_t pre_id = current_state->key_atom_info->lo_atom
297  + current_state->pre_syn_id;
298  uint32_t id = current_state->post_syn_id;
299  uint32_t record_value = FORM_FLAG | (id << ID_SHIFT) |
300  (pre_id << PRE_ID_SHIFT);
302  structural_recording_values.value = record_value;
305 
306  return true;
307  }
308  return false;
309 }
310 
317 static inline bool row_restructure(
318  uint32_t time, synaptic_row_t restrict row,
319  current_state_t *restrict current_state) {
320  // the selected pre- and postsynaptic IDs are in current_state
321 
322  if (current_state->element_exists) {
323  // find the offset of the neuron in the current row
325  current_state->post_syn_id, row,
326  &current_state->weight, &current_state->delay,
327  &current_state->offset, &current_state->synapse_type)) {
328  log_debug("Post neuron %u not in row", current_state->post_syn_id);
329  return false;
330  }
331 
332  if (synaptogenesis_elimination_rule(current_state,
333  elimination_params[current_state->post_to_pre.pop_index],
334  time, row)) {
335  // Create recorded value
336  // (bottom bit: add/remove, next 8: local id, remainder: pre global id)
337  uint32_t pre_id = current_state->key_atom_info->lo_atom + current_state->pre_syn_id;
338  uint32_t id = current_state->post_syn_id;
339  uint32_t record_value = ELIM_FLAG | (id << ID_SHIFT) | (pre_id << PRE_ID_SHIFT);
341  structural_recording_values.value = record_value;
344 
345  return true;
346  } else {
347  return false;
348  }
349 
350  } else {
351  // Can't form if the row is full
352  uint32_t no_elems = synapse_dynamics_n_connections_in_row(
354  if (no_elems >= rewiring_data.s_max) {
355  return false;
356  } else {
357  if (current_state->with_replacement) {
358  // A synapse can be added anywhere on the current row, so just do it
359  return do_formation(time, row, current_state);
360  } else {
361  // A synapse cannot be added if one exists between the current pair of neurons
363  current_state->post_syn_id, row,
364  &(current_state->weight), &(current_state->delay),
365  &(current_state->offset), &(current_state->synapse_type))) {
366  return do_formation(time, row, current_state);
367  } else {
368  log_debug("Post neuron %u already in row", current_state->post_syn_id);
369  return false;
370  }
371  }
372  }
373  }
374 }
375 
377  current_state_t *current_state = _get_state();
378  bool return_value = row_restructure(time, row, current_state);
379  _free_state(current_state);
380  return return_value;
381 }
382 
385 }
386 
387 uint32_t synaptogenesis_n_updates(void) {
388  if (rewiring_data.fast) {
389  return rewiring_data.p_rew;
390  }
391 
393  if (last_rewiring_time >= rewiring_data.p_rew) {
394  last_rewiring_time = 0;
395  return 1;
396  }
397 
398  return 0;
399 }
static uint32_t time
Simulation time.
API for synapse elimination.
elimination_params_t * synaptogenesis_elimination_init(uint8_t **data)
Read and return an elimination parameter data structure from the data stream.
static bool synaptogenesis_elimination_rule(current_state_t *current_state, const elimination_params_t *params, uint32_t time, synaptic_row_t row)
Elimination rule for synaptogenesis.
Configuration of synapse elimination rule.
API for synapse formation.
static bool synaptogenesis_formation_rule(current_state_t *current_state, const formation_params_t *params, uint32_t time, synaptic_row_t row)
Formation rule for synaptogenesis; picks what neuron in the current population will have a synapse ad...
formation_params_t * synaptogenesis_formation_init(uint8_t **data)
Read and return an formation parameter data structure from the data stream.
Configuration of synapse formation rule.
void partner_init(uint8_t **data)
Initialise the partner selection rule.
static void partner_spike_received(uint32_t time, spike_t spike)
Notifies the rule that a spike has been received.
static bool potential_presynaptic_partner(uint32_t time, uint32_t *restrict population_id, uint32_t *restrict sub_population_id, uint32_t *restrict neuron_id, spike_t *restrict spike, uint32_t *restrict m_pop_index)
Choose the potential (remote) synaptic partner.
maths-util.h - first created 7/10/2013 version 0.1
struct synaptic_row * synaptic_row_t
The type of a synaptic row.
uint32_t spike_t
The type of a spike.
Partner selection rule common API.
Master pop(ulation) table API.
bool population_table_get_next_address(spike_t *spike, pop_table_lookup_result_t *result)
Get the next row data for a previously given spike. If no spike has been given, return False.
bool population_table_get_first_address(spike_t spike, pop_table_lookup_result_t *result)
Get the first row data for the given input spike.
A structure to hold a response to a population table lookup.
uint32_t element_exists
does the connection already exist
Definition: sp_structs.h:103
uint32_t post_low_atom
Low atom copied from rewiring data.
Definition: sp_structs.h:96
mars_kiss64_seed_t * local_seed
Seed referenced from rewiring data.
Definition: sp_structs.h:94
static uint32_t rand_int(uint32_t max, mars_kiss64_seed_t seed)
Definition: sp_structs.h:123
static uint8_t * sp_structs_read_in_common(address_t sdram_sp_address, rewiring_data_t *rewiring_data, pre_pop_info_table_t *pre_info, post_to_pre_entry **post_to_pre_table)
Common code for structural plasticity initialisation.
Definition: sp_structs.h:246
struct representing the current state of rewiring
Definition: sp_structs.h:92
information per atom
Definition: sp_structs.h:48
Entry of map from post-connection to pre-connection neural indices.
Definition: sp_structs.h:41
individual pre-synaptic sub-population information
Definition: sp_structs.h:58
table of individual pre-synaptic information
Definition: sp_structs.h:70
parameters of the synaptic rewiring model
Definition: sp_structs.h:76
uint32_t synapse_dynamics_n_connections_in_row(synapse_row_fixed_part_t *fixed)
Get the number of connections in the given row.
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.
implementation for handling the processing of synapse rows.
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
Operations on synapses.
This file contains the main interface for structural plasticity.
bool synaptogenesis_dynamics_rewire(uint32_t time, spike_t *spike, pop_table_lookup_result_t *result)
Trigger the process of synaptic rewiring.
#define ID_SHIFT
How much to shift post-IDs by.
rewiring_data_t rewiring_data
the instantiation of the rewiring data
pre_pop_info_table_t pre_info
pre-population information table
uint32_t rewiring_recording_index
The recording region for the structural events.
void synaptogenesis_spike_received(uint32_t time, spike_t spike)
Indicates that a spike has been received.
static circular_buffer current_state_queue
Current states in use.
structural_recording_values_t structural_recording_values
Working buffer for the recording of structural changes.
uint32_t synaptogenesis_n_updates(void)
Number of updates to do of synaptogenesis this time step.
static formation_params_t ** formation_params
The formation parameters per pre-population.
static bool row_restructure(uint32_t time, synaptic_row_t restrict row, current_state_t *restrict current_state)
Performs the actual restructuring of a row.
static uint32_t last_rewiring_time
Timer callbacks since last rewiring.
void print_post_to_pre_entry(void)
Print a certain data object.
static elimination_params_t ** elimination_params
The elimination parameters per pre-population.
static post_to_pre_entry * post_to_pre_table
inverse of synaptic matrix
@ FORM_FLAG
Formation flag.
@ ELIM_FLAG
Elimination flag.
static circular_buffer free_states
Free current states.
#define PRE_ID_SHIFT
How much to shift pre-IDs by.
bool synaptogenesis_row_restructure(uint32_t time, synaptic_row_t row)
Perform the actual restructuring of a row.
bool synaptogenesis_dynamics_initialise(address_t sdram_sp_address, uint32_t *recording_regions_used)
Initialisation of synaptic rewiring (synaptogenesis) parameters (random seed, spread of receptive fie...
Struct for structural recording data.