sPyNNaker neural_modelling 7.3.1
Loading...
Searching...
No Matches
connection_generator_all_but_me.h
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
24#include <stdbool.h>
26
29 // How many values there are in each WTA group
30 uint32_t n_values;
31
32 // Whether there are weight values specified or not
33 uint32_t has_weights;
34
35 // The weight values if specified.
36 // If so, there must be (n_values * n_values - 1) weights
37 accum weights[];
38};
39
41struct all_but_me {
42 // How many neurons there are in each WTA group
43 uint32_t n_neurons_per_group;
44
45 // The weight values if specified.
46 // If so, there must be (n_values * n_values - 1) weights
47 accum *weights;
48};
49
50
58 // Get the SDRAM params
59 struct all_but_me_conf *params_sdram = *region;
60
61 // Allocate the data structure for parameters
62 struct all_but_me *params = spin1_malloc(sizeof(struct all_but_me));
63
64 // Copy the parameters
65 params->n_neurons_per_group = params_sdram->n_values;
66 if (params_sdram->has_weights) {
67 uint32_t n_per_group = params->n_neurons_per_group;
68 uint32_t weight_size = n_per_group * (n_per_group - 1) * sizeof(accum);
69 params->weights = spin1_malloc(weight_size);
70 if (params->weights == NULL) {
71 // If we can't copy, just reference the SDRAM
72 params->weights = &params_sdram->weights[0];
73 } else {
74 spin1_memcpy(&params->weights[0], &params_sdram->weights[0], weight_size);
75 }
76 *region = &params_sdram->weights[n_per_group * (n_per_group - 1)];
77 } else {
78 params->weights = NULL;
79 *region = &params_sdram->weights[0];
80 }
81
82 log_info("allButMe connector, n_values = %u, has_weights = %u", params->n_neurons_per_group,
83 params_sdram->has_weights);
84
85 return params;
86}
87
92static void connection_generator_all_but_me_free(void *generator) {
93 sark_free(generator);
94}
95
96static inline bool make_all_but_me_conn(accum weight,
97 param_generator_t delay_generator, matrix_generator_t matrix_generator,
98 uint32_t pre, uint32_t post, unsigned long accum weight_scale,
99 accum timestep_per_delay) {
100 uint16_t delay = rescale_delay(
101 param_generator_generate(delay_generator), timestep_per_delay);
103 weight, delay, weight_scale)) {
104 log_error("Matrix not sized correctly!");
105 return false;
106 }
107 return true;
108}
109
110static inline void div_mod(uint32_t dividend, uint32_t divisor, uint32_t *div,
111 uint32_t *mod) {
112 uint32_t remainder = dividend;
113 uint32_t count = 0;
114 while (remainder >= divisor) {
115 remainder -= divisor;
116 count++;
117 }
118 *div = count;
119 *mod = remainder;
120}
121
125static inline accum get_weight(struct all_but_me *obj,
126 param_generator_t weight_generator, uint32_t pre_value,
127 uint32_t post_value) {
128 // Get the post position rather than the post value. Because each "row" in
129 // the table has the diagonal removed, we need to adjust where we get the
130 // value from depending on the relative pre and post values (which must not
131 // be the same - this isn't checked here though).
132 uint32_t post_pos = post_value;
133 if (post_value >= pre_value) {
134 post_pos -= 1;
135 }
136 if (obj->weights != NULL) {
137 uint32_t weight_index = (pre_value * (obj->n_neurons_per_group - 1)) + post_pos;
138 return obj->weights[weight_index];
139 } else {
140 return param_generator_generate(weight_generator);
141 }
142}
143
157 void *generator, uint32_t pre_lo, uint32_t pre_hi,
158 uint32_t post_lo, uint32_t post_hi, UNUSED uint32_t post_index,
159 uint32_t post_slice_start, uint32_t post_slice_count,
160 unsigned long accum weight_scale, accum timestep_per_delay,
161 param_generator_t weight_generator, param_generator_t delay_generator,
162 matrix_generator_t matrix_generator) {
163 struct all_but_me *obj = generator;
164
165 // Get the actual ranges to generate within
166 uint32_t post_start = max(post_slice_start, post_lo);
167 uint32_t post_end = min(post_slice_start + post_slice_count - 1, post_hi);
168
169 // Work out where we are in the generation
170 // We need to connect each pre-neuron to each post-neuron in each group
171 // (but not to itself). We are currently generating a subset of the post
172 // neurons, so we need to work out which group we are in within that subset,
173 // and which is the first post-neuron in the group that we are generating
174 // for now.
175 uint32_t post_group;
176 uint32_t post_value;
177 div_mod(post_start, obj->n_neurons_per_group, &post_group, &post_value);
178
179 // Work out where the pre-neurons start and end for the group that we are
180 // in at the start of the post-neurons. The group might not have enough
181 // neurons in it, so we check just in case.
182 uint32_t pre_start = pre_lo + post_group * obj->n_neurons_per_group;
183 uint32_t pre_end = min(pre_start + obj->n_neurons_per_group, pre_hi + 1);
184 uint32_t n_values = pre_end - pre_start;
185
186 // Go through the post neurons in this slice
187 for (uint32_t post = post_start; post <= post_end; post++) {
188 uint32_t local_post = post - post_slice_start;
189
190 // Go through each of the "values" in this group that can target this
191 // post neuron (each of which is a pre-neuron)
192 for (uint32_t pre_value = 0; pre_value < n_values; pre_value++) {
193 if (pre_value != post_value) {
194 uint32_t pre = pre_start + pre_value;
195 accum weight = get_weight(obj, weight_generator, pre_value, post_value);
196 if (!make_all_but_me_conn(weight, delay_generator,
197 matrix_generator, pre, local_post, weight_scale,
198 timestep_per_delay)) {
199 return false;
200 }
201 }
202 }
203
204 // Work out next loop iteration. If we have reached the end of a group
205 // of values, we need to move onto the next group.
206 post_value += 1;
207 if (post_value == obj->n_neurons_per_group) {
208 post_value = 0;
209 pre_start += obj->n_neurons_per_group;
210 pre_end = min(pre_start + obj->n_neurons_per_group, pre_hi + 1);
211 if (pre_start >= pre_hi) {
212 break;
213 }
214 n_values = pre_end - pre_start;
215 }
216 }
217
218 return true;
219}
static void connection_generator_all_but_me_free(void *generator)
Free the All But Me connection generator.
static void * connection_generator_all_but_me_initialise(void **region)
Initialise the all but me connection generator.
static accum get_weight(struct all_but_me *obj, param_generator_t weight_generator, uint32_t pre_value, uint32_t post_value)
static bool connection_generator_all_but_me_generate(void *generator, uint32_t pre_lo, uint32_t pre_hi, uint32_t post_lo, uint32_t post_hi, uint32_t post_index, uint32_t post_slice_start, uint32_t post_slice_count, unsigned long accum weight_scale, accum timestep_per_delay, param_generator_t weight_generator, param_generator_t delay_generator, matrix_generator_t matrix_generator)
Generate connections with the all but me connection generator.
The parameters to be passed around for this connector.
The parameters to be passed around for this connector.
void log_error(const char *message,...)
void log_info(const char *message,...)
General types associated with generators.
static uint16_t rescale_delay(accum delay, accum timestep_per_delay)
Rescales a delay to account for timesteps and type-converts it.
bool matrix_generator_write_synapse(matrix_generator_t generator, uint32_t pre_index, uint16_t post_index, accum weight, uint16_t delay, unsigned long accum weight_scale)
Write a synapse with a matrix generator.
The data for a matrix generator.
accum param_generator_generate(param_generator_t generator)
Generate value with a parameter generator.
void sark_free(void *ptr)
region
spike source array region IDs in human readable form
#define NULL
void spin1_memcpy(void *dst, void const *src, uint len)
#define min(a, b)
static stdp_params params
Configuration parameters.