sPyNNaker neural_modelling  7.4.2
connection_generator_fixed_total.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 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 
22 #include <log.h>
23 #include <synapse_expander/rng.h>
25 
28  // Whether to connect to self or not
29  uint32_t allow_self_connections;
30  // Whether to repeat connections or not
31  uint32_t with_replacement;
32  // The number of synapses to generate in total over all cores
33  uint32_t n_synapses_total;
34 };
35 
41 struct fixed_total {
43 
44  // This is how many connections there are to make per core
45  uint16_t *n_connections_per_core;
46 };
47 
48 /*static inline uint32_t _pick(rng_t *rng, uint32_t K, uint32_t not_K) {
49  return (uint32_t) (ulrbits(rng_generator(rng)) * (K + not_K));
50 }*/
51 
60 /*static uint32_t binomial(uint32_t n, uint32_t N, uint32_t K, rng_t *rng) {
61  uint32_t count = 0;
62  uint32_t not_K = N - K;
63  for (uint32_t i = 0; i < n; i++) {
64  if (_pick(rng, K, not_K) < K) {
65  count++;
66  }
67  }
68  return count;
69 }*/
70 
79 /*static uint32_t hypergeom(uint32_t n, uint32_t N, uint32_t K, rng_t *rng) {
80  uint32_t count = 0;
81  uint32_t K_remaining = K;
82  uint32_t not_K_remaining = N - K;
83  for (uint32_t i = 0; i < n; i++) {
84  if (_pick(rng, K_remaining, not_K_remaining) < K_remaining) {
85  count++;
86  K_remaining--;
87  } else {
88  not_K_remaining--;
89  }
90  }
91  return count;
92 } */
93 
101  // Allocate memory for the parameters
102  struct fixed_total *obj = spin1_malloc(sizeof(struct fixed_total));
103 
104  // Copy the parameters in
105  struct fixed_total_params *params_sdram = *region;
106  obj->params = *params_sdram;
107  *region = &params_sdram[1];
108 
109  log_debug("Fixed Total Number Connector, allow self connections = %u, "
110  "with replacement = %u, n_synapses_total = %u",
111  obj->params.allow_self_connections,
112  obj->params.with_replacement, obj->params.n_synapses_total);
113 
114  // Go through every core and use the population-level RNG to generate
115  // the number of synapses on every core with a binomial.
116  /*obj->n_connections_per_core = spin1_malloc(obj->params.n_cores * sizeof(uint16_t));
117  uint32_t n_to_go = obj->params.n_synapses_total;
118  uint32_t synapses_to_go = obj->params.max_synapses_total;
119  for (uint32_t i = 0; i < obj->params.n_cores; i++) {
120  if (i + 1 == obj->params.n_cores) {
121  // Last core gets the treat
122  obj->n_connections_per_core[i] = n_to_go;
123  } else {
124  // Do a binomial for this core
125  uint32_t n_conns = binomial(n_to_go, synapses_to_go,
126  obj->params.max_synapses_per_core, population_rng);
127  obj->n_connections_per_core[i] = n_conns;
128  n_to_go -= n_conns;
129  synapses_to_go -= obj->params.max_synapses_per_core;
130  }
131  } */
132 
133  return obj;
134 }
135 
140 static void connection_generator_fixed_total_free(void *generator) {
141  sark_free(generator);
142 }
143 
144 static uint32_t random_in_range(rng_t *rng, uint32_t range) {
145  unsigned long fract u01 = ulrbits(rng_generator(rng));
146  return muliulr(range, u01);
147 }
148 
149 static void fixed_total_next(uint32_t *pre, uint32_t *post, uint32_t pre_lo, uint32_t pre_hi) {
150  *pre += 1;
151  if (*pre > pre_hi) {
152  *pre = pre_lo;
153  *post += 1;
154  }
155 }
156 
157 
178  void *generator, uint32_t pre_lo, uint32_t pre_hi,
179  uint32_t post_lo, uint32_t post_hi, UNUSED uint32_t post_index,
180  uint32_t post_slice_start, uint32_t post_slice_count,
181  unsigned long accum weight_scale, accum timestep_per_delay,
182  param_generator_t weight_generator, param_generator_t delay_generator,
183  matrix_generator_t matrix_generator) {
184  struct fixed_total *obj = generator;
185 
186  uint32_t n_pre = pre_hi - pre_lo + 1;
187  uint32_t n_post = post_hi - post_lo + 1;
188  uint32_t post_slice_end = post_slice_start + post_slice_count;
189  uint32_t n_conns = obj->params.n_synapses_total;
190 
191  // Generate the connections for all cores then filter for this one
192  if (obj->params.with_replacement) {
193  for (uint32_t i = 0; i < n_conns; i++) {
194  uint32_t post = random_in_range(population_rng, n_post) + post_lo;
195  if (post >= post_slice_start && post < post_slice_end) {
196  uint32_t local_post = post - post_slice_start;
197  accum weight = param_generator_generate(weight_generator);
198  uint16_t delay = rescale_delay(
199  param_generator_generate(delay_generator), timestep_per_delay);
200 
201  uint32_t pre;
202  bool written = false;
203  uint32_t n_retries = 0;
204  do {
205  pre = random_in_range(core_rng, n_pre) + pre_lo;
206  if (obj->params.allow_self_connections || pre != post) {
208  pre, local_post, weight, delay, weight_scale);
209  n_retries++;
210  }
211  } while (!written && n_retries < 10);
212  if (!written) {
213  log_error("Couldn't find a row to write to!");
214  return false;
215  }
216  }
217  }
218  } else {
219  uint32_t pre = pre_lo;
220  uint32_t post = post_lo;
221  uint32_t i = 0;
222  struct {
223  uint32_t pre;
224  uint32_t post;
225  } conns[n_conns];
226  for (i = 0; i < n_conns; i++) {
227  conns[i].pre = pre;
228  conns[i].post = post;
229  fixed_total_next(&pre, &post, pre_lo, pre_hi);
230  if (!obj->params.allow_self_connections && (pre == post)) {
231  fixed_total_next(&pre, &post, pre_lo, pre_hi);
232  }
233  }
234  while (pre <= pre_hi && post <= post_hi) {
235  uint32_t r = random_in_range(population_rng, i + 1);
236  if (r < n_conns) {
237  conns[r].pre = pre;
238  conns[r].post = post;
239  }
240  fixed_total_next(&pre, &post, pre_lo, pre_hi);
241  if (!obj->params.allow_self_connections && (pre == post)) {
242  fixed_total_next(&pre, &post, pre_lo, pre_hi);
243  }
244  i++;
245  }
246  for (uint32_t i = 0; i < n_conns; i++) {
247  uint32_t local_post = conns[i].post;
248  if (local_post >= post_slice_start && local_post < post_slice_end) {
249  local_post -= post_slice_start;
250  uint32_t local_pre = conns[i].pre;
251  accum weight = param_generator_generate(weight_generator);
252  uint16_t delay = rescale_delay(
253  param_generator_generate(delay_generator), timestep_per_delay);
254  if (!matrix_generator_write_synapse(matrix_generator, local_pre, local_post,
255  weight, delay, weight_scale)) {
256  // Not a lot we can do here...
257  log_error("Couldn't write matrix!");
258  return false;
259  }
260  }
261  }
262  }
263  return true;
264 }
static void connection_generator_fixed_total_free(void *generator)
Free the fixed-total connection generator.
static bool connection_generator_fixed_total_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 fixed-total connection generator.
static void * connection_generator_fixed_total_initialise(void **region)
Draw from a binomial distribution i.e. with replacement.
The data to be passed around.
The parameters that can be copied from SDRAM.
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.
rng_t * core_rng
An RNG that is local to the current core.
rng_t * population_rng
An RNG that starts in the same place on every core of the Population.
accum param_generator_generate(param_generator_t generator)
Generate value with a parameter generator.
uint32_t rng_generator(rng_t *rng)
Generate a uniformly-distributed random number.
Definition: rng.c:26
Random number generator interface.
The Random number generator parameters.
Definition: rng.h:30
region
spike source array region IDs in human readable form
static uint32_t rng(void)
Random number generation for the Poisson sources. This is a local version for speed of operation.
static stdp_params params
Configuration parameters.