GeNN  4.9.0
GPU enhanced Neuronal Networks (GeNN)
initSparseConnectivitySnippet.h
Go to the documentation of this file.
1 #pragma once
2 
3 // Standard C++ includes
4 #include <functional>
5 #include <vector>
6 
7 // Standard C includes
8 #include <cassert>
9 #include <cmath>
10 
11 // GeNN includes
12 #include "binomial.h"
13 #include "snippet.h"
14 
15 //----------------------------------------------------------------------------
16 // Macros
17 //----------------------------------------------------------------------------
18 #define SET_ROW_BUILD_CODE(CODE) virtual std::string getRowBuildCode() const override{ return CODE; }
19 #define SET_ROW_BUILD_STATE_VARS(...) virtual ParamValVec getRowBuildStateVars() const override{ return __VA_ARGS__; }
20 
21 #define SET_COL_BUILD_CODE(CODE) virtual std::string getColBuildCode() const override{ return CODE; }
22 #define SET_COL_BUILD_STATE_VARS(...) virtual ParamValVec getColBuildStateVars() const override{ return __VA_ARGS__; }
23 
24 #define SET_HOST_INIT_CODE(CODE) virtual std::string getHostInitCode() const override{ return CODE; }
25 
26 #define SET_CALC_MAX_ROW_LENGTH_FUNC(FUNC) virtual CalcMaxLengthFunc getCalcMaxRowLengthFunc() const override{ return FUNC; }
27 #define SET_CALC_MAX_COL_LENGTH_FUNC(FUNC) virtual CalcMaxLengthFunc getCalcMaxColLengthFunc() const override{ return FUNC; }
28 #define SET_CALC_KERNEL_SIZE_FUNC(...) virtual CalcKernelSizeFunc getCalcKernelSizeFunc() const override{ return __VA_ARGS__; }
29 
30 #define SET_MAX_ROW_LENGTH(MAX_ROW_LENGTH) virtual CalcMaxLengthFunc getCalcMaxRowLengthFunc() const override{ return [](unsigned int, unsigned int, const std::vector<double> &){ return MAX_ROW_LENGTH; }; }
31 #define SET_MAX_COL_LENGTH(MAX_COL_LENGTH) virtual CalcMaxLengthFunc getCalcMaxColLengthFunc() const override{ return [](unsigned int, unsigned int, const std::vector<double> &){ return MAX_COL_LENGTH; }; }
32 
33 //----------------------------------------------------------------------------
34 // InitSparseConnectivitySnippet::Base
35 //----------------------------------------------------------------------------
38 {
40 {
41 public:
42  //----------------------------------------------------------------------------
43  // Typedefines
44  //----------------------------------------------------------------------------
45  typedef std::function<unsigned int(unsigned int, unsigned int, const std::vector<double> &)> CalcMaxLengthFunc;
46  typedef std::function<std::vector<unsigned int>(const std::vector<double> &)> CalcKernelSizeFunc;
47 
48  //----------------------------------------------------------------------------
49  // Declared virtuals
50  //----------------------------------------------------------------------------
51  virtual std::string getRowBuildCode() const{ return ""; }
52  virtual ParamValVec getRowBuildStateVars() const{ return {}; }
53 
54  virtual std::string getColBuildCode() const { return ""; }
55  virtual ParamValVec getColBuildStateVars() const { return {}; }
56 
57  virtual std::string getHostInitCode() const{ return ""; }
58 
61 
64 
67 
68  //------------------------------------------------------------------------
69  // Public methods
70  //------------------------------------------------------------------------
72  boost::uuids::detail::sha1::digest_type getHashDigest() const;
73 
75  void validate() const;
76 };
77 
78 //----------------------------------------------------------------------------
79 // Init
80 //----------------------------------------------------------------------------
81 class Init : public Snippet::Init<InitSparseConnectivitySnippet::Base>
82 {
83 public:
84  Init(const Base *snippet, const std::vector<double> &params)
85  : Snippet::Init<Base>(snippet, params)
86  {
87  }
88 };
89 
90 //----------------------------------------------------------------------------
91 // InitSparseConnectivitySnippet::Uninitialised
92 //----------------------------------------------------------------------------
94 class Uninitialised : public Base
95 {
96 public:
98 };
99 
100 //----------------------------------------------------------------------------
101 // InitSparseConnectivitySnippet::OneToOne
102 //----------------------------------------------------------------------------
104 class OneToOne : public Base
105 {
106 public:
108 
110  "$(addSynapse, $(id_pre));\n"
111  "$(endRow);\n");
112 
115 };
116 
117 //----------------------------------------------------------------------------
118 // InitSparseConnectivitySnippet::FixedProbabilityBase
119 //----------------------------------------------------------------------------
123 {
124 public:
125  virtual std::string getRowBuildCode() const override = 0;
126 
127  SET_ROW_BUILD_STATE_VARS({{"prevJ", "int", -1}});
128 
129  SET_PARAM_NAMES({"prob"});
130  SET_DERIVED_PARAMS({{"probLogRecip", [](const std::vector<double> &pars, double){ return 1.0 / log(1.0 - pars[0]); }}});
131 
133  [](unsigned int numPre, unsigned int numPost, const std::vector<double> &pars)
134  {
135  // Calculate suitable quantile for 0.9999 change when drawing numPre times
136  const double quantile = pow(0.9999, 1.0 / (double)numPre);
137 
138  return binomialInverseCDF(quantile, numPost, pars[0]);
139  });
141  [](unsigned int numPre, unsigned int numPost, const std::vector<double> &pars)
142  {
143  // Calculate suitable quantile for 0.9999 change when drawing numPos times
144  const double quantile = pow(0.9999, 1.0 / (double)numPost);
145 
146  return binomialInverseCDF(quantile, numPre, pars[0]);
147  });
148 };
149 
150 //----------------------------------------------------------------------------
151 // InitSparseConnectivitySnippet::FixedProbability
152 //----------------------------------------------------------------------------
155 
165 {
166 public:
168 
170  "const scalar u = $(gennrand_uniform);\n"
171  "prevJ += (1 + (int)(log(u) * $(probLogRecip)));\n"
172  "if(prevJ < $(num_post)) {\n"
173  " $(addSynapse, prevJ + $(id_post_begin));\n"
174  "}\n"
175  "else {\n"
176  " $(endRow);\n"
177  "}\n");
178 };
179 
180 //----------------------------------------------------------------------------
181 // InitSparseConnectivitySnippet::FixedProbabilityNoAutapse
182 //----------------------------------------------------------------------------
187 
197 {
198 public:
200 
202  "int nextJ;\n"
203  "do {\n"
204  " const scalar u = $(gennrand_uniform);\n"
205  " nextJ = prevJ + (1 + (int)(log(u) * $(probLogRecip)));\n"
206  "} while(nextJ == $(id_pre));\n"
207  "prevJ = nextJ;\n"
208  "if(prevJ < $(num_post)) {\n"
209  " $(addSynapse, prevJ + $(id_post_begin));\n"
210  "}\n"
211  "else {\n"
212  " $(endRow);\n"
213  "}\n");
214 };
215 
216 //----------------------------------------------------------------------------
217 // InitSparseConnectivitySnippet::FixedNumberPostWithReplacement
218 //----------------------------------------------------------------------------
220 
225 {
226 public:
228 
230  "if(c == 0) {\n"
231  " $(endRow);\n"
232  "}\n"
233  "const scalar u = $(gennrand_uniform);\n"
234  "x += (1.0 - x) * (1.0 - pow(u, 1.0 / (scalar)c));\n"
235  "unsigned int postIdx = (unsigned int)(x * $(num_post));\n"
236  "postIdx = (postIdx < $(num_post)) ? postIdx : ($(num_post) - 1);\n"
237  "$(addSynapse, postIdx + $(id_post_begin));\n"
238  "c--;\n");
239  SET_ROW_BUILD_STATE_VARS({{"x", "scalar", 0.0},{"c", "unsigned int", "$(rowLength)"}});
240 
241  SET_PARAM_NAMES({"rowLength"});
242 
244  [](unsigned int, unsigned int, const std::vector<double> &pars)
245  {
246  return (unsigned int)pars[0];
247  });
248 
250  [](unsigned int numPre, unsigned int numPost, const std::vector<double> &pars)
251  {
252  // Calculate suitable quantile for 0.9999 change when drawing numPost times
253  const double quantile = pow(0.9999, 1.0 / (double)numPost);
254 
255  // In each row the number of connections that end up in a column are distributed
256  // binomially with n=numConnections and p=1.0 / numPost. As there are numPre rows the total number
257  // of connections that end up in each column are distributed binomially with n=numConnections * numPre and p=1.0 / numPost
258  return binomialInverseCDF(quantile, (unsigned int)pars[0] * numPre, 1.0 / (double)numPost);
259  });
260 };
261 
262 //----------------------------------------------------------------------------
263 // InitSparseConnectivitySnippet::FixedNumberTotalWithReplacement
264 //----------------------------------------------------------------------------
269 
274 {
275 public:
277 
279  "if(c == 0) {\n"
280  " $(endRow);\n"
281  "}\n"
282  "const scalar u = $(gennrand_uniform);\n"
283  "x += (1.0 - x) * (1.0 - pow(u, 1.0 / (scalar)c));\n"
284  "unsigned int postIdx = (unsigned int)(x * $(num_post));\n"
285  "postIdx = (postIdx < $(num_post)) ? postIdx : ($(num_post) - 1);\n"
286  "$(addSynapse, postIdx + $(id_post_begin));\n"
287  "c--;\n");
288  SET_ROW_BUILD_STATE_VARS({{"x", "scalar", 0.0},{"c", "unsigned int", "$(preCalcRowLength)[($(id_pre) * $(num_threads)) + $(id_thread)]"}});
289 
290  SET_PARAM_NAMES({"total"});
291  SET_EXTRA_GLOBAL_PARAMS({{"preCalcRowLength", "uint16_t*"}})
292 
294  "// Allocate pre-calculated row length array\n"
295  "$(allocatepreCalcRowLength, $(num_pre) * $(num_threads));\n"
296  "// Calculate row lengths\n"
297  "const size_t numPostPerThread = ($(num_post) + $(num_threads) - 1) / $(num_threads);\n"
298  "const size_t leftOverNeurons = $(num_post) % numPostPerThread;\n"
299  "size_t remainingConnections = $(total);\n"
300  "size_t matrixSize = (size_t)$(num_pre) * (size_t)$(num_post);\n"
301  "uint16_t *subRowLengths = $(preCalcRowLength);\n"
302  "// Loop through rows\n"
303  "for(size_t i = 0; i < $(num_pre); i++) {\n"
304  " const bool lastPre = (i == ($(num_pre) - 1));\n"
305  " // Loop through subrows\n"
306  " for(size_t j = 0; j < $(num_threads); j++) {\n"
307  " const bool lastSubRow = (j == ($(num_threads) - 1));\n"
308  " // If this isn't the last sub-row of the matrix\n"
309  " if(!lastPre || ! lastSubRow) {\n"
310  " // Get length of this subrow\n"
311  " const unsigned int numSubRowNeurons = (leftOverNeurons != 0 && lastSubRow) ? leftOverNeurons : numPostPerThread;\n"
312  " // Calculate probability\n"
313  " const double probability = (double)numSubRowNeurons / (double)matrixSize;\n"
314  " // Create distribution to sample row length\n"
315  " std::binomial_distribution<size_t> rowLengthDist(remainingConnections, probability);\n"
316  " // Sample row length;\n"
317  " const size_t subRowLength = rowLengthDist($(rng));\n"
318  " // Update counters\n"
319  " remainingConnections -= subRowLength;\n"
320  " matrixSize -= numSubRowNeurons;\n"
321  " // Add row length to array\n"
322  " assert(subRowLength < std::numeric_limits<uint16_t>::max());\n"
323  " *subRowLengths++ = (uint16_t)subRowLength;\n"
324  " }\n"
325  " }\n"
326  "}\n"
327  "// Insert remaining connections into last sub-row\n"
328  "*subRowLengths = (uint16_t)remainingConnections;\n"
329  "// Push populated row length array\n"
330  "$(pushpreCalcRowLength, $(num_pre) * $(num_threads));\n");
331 
333  [](unsigned int numPre, unsigned int numPost, const std::vector<double> &pars)
334  {
335  // Calculate suitable quantile for 0.9999 change when drawing numPre times
336  const double quantile = pow(0.9999, 1.0 / (double)numPre);
337 
338  // There are numConnections connections amongst the numPre*numPost possible connections.
339  // Each of the numConnections connections has an independent p=float(numPost)/(numPre*numPost)
340  // probability of being selected and the number of synapses in the sub-row is binomially distributed
341  return binomialInverseCDF(quantile, (unsigned int)pars[0], (double)numPost / ((double)numPre * (double)numPost));
342  });
343 
345  [](unsigned int numPre, unsigned int numPost, const std::vector<double> &pars)
346  {
347  // Calculate suitable quantile for 0.9999 change when drawing numPost times
348  const double quantile = pow(0.9999, 1.0 / (double)numPost);
349 
350  // There are numConnections connections amongst the numPre*numPost possible connections.
351  // Each of the numConnections connections has an independent p=float(numPre)/(numPre*numPost)
352  // probability of being selected and the number of synapses in the sub-row is binomially distributed
353  return binomialInverseCDF(quantile, (unsigned int)pars[0], (double)numPre / ((double)numPre * (double)numPost));
354  });
355 };
356 
357 //----------------------------------------------------------------------------
358 // InitSparseConnectivitySnippet::FixedNumberPreWithReplacement
359 //----------------------------------------------------------------------------
361 
363 {
364 public:
366 
368  "if(c == 0) {\n"
369  " $(endCol);\n"
370  "}\n"
371  "const unsigned int idPre = (unsigned int)ceil($(gennrand_uniform) * $(num_pre)) - 1;\n"
372  "$(addSynapse, idPre + $(id_pre_begin));\n"
373  "c--;\n");
374  SET_COL_BUILD_STATE_VARS({{"c", "unsigned int", "$(colLength)"}});
375 
376  SET_PARAM_NAMES({"colLength"});
377 
379  [](unsigned int numPre, unsigned int numPost, const std::vector<double> &pars)
380  {
381  // Calculate suitable quantile for 0.9999 chance when drawing numPre times
382  const double quantile = pow(0.9999, 1.0 / (double)numPre);
383 
384  // In each column the number of connections that end up in a row are distributed
385  // binomially with n=numConnections and p=1.0 / numPre. As there are numPost columns the total number
386  // of connections that end up in each row are distributed binomially with n=numConnections * numPost and p=1.0 / numPre
387  return binomialInverseCDF(quantile, (unsigned int)pars[0] * numPost, 1.0 / (double)numPre);
388  });
389 
391  [](unsigned int, unsigned int, const std::vector<double> &pars)
392  {
393  return (unsigned int)pars[0];
394  });
395 };
396 
397 //----------------------------------------------------------------------------
398 // InitSparseConnectivitySnippet::Conv2D
399 //----------------------------------------------------------------------------
403 
404 class Conv2D : public Base
405 {
406 public:
407  DECLARE_SNIPPET(Conv2D, 12);
408 
409  SET_PARAM_NAMES({"conv_kh", "conv_kw",
410  "conv_sh", "conv_sw",
411  "conv_padh", "conv_padw",
412  "conv_ih", "conv_iw", "conv_ic",
413  "conv_oh", "conv_ow", "conv_oc"});
414 
415  SET_ROW_BUILD_STATE_VARS({{"inRow", "int", "($(id_pre) / (int)$(conv_ic)) / (int)$(conv_iw)"},
416  {"inCol", "int", "($(id_pre) / (int)$(conv_ic)) % (int)$(conv_iw)"},
417  {"inChan", "int", "$(id_pre) % (int)$(conv_ic)"},
418  {"outRow", "int", "min((int)$(conv_oh), max(0, 1 + (int)floor((inRow + $(conv_padh) - $(conv_kh)) / $(conv_sh))))"},
419  {"maxOutRow", "int", "min((int)$(conv_oh), max(0, 1 + ((inRow + (int)$(conv_padh)) / (int)$(conv_sh))))"},
420  {"minOutCol", "int", "min((int)$(conv_ow), max(0, 1 + (int)floor((inCol + $(conv_padw) - $(conv_kw)) / $(conv_sw))))"},
421  {"maxOutCol", "int", "min((int)$(conv_ow), max(0, 1 + ((inCol + (int)$(conv_padw)) / (int)$(conv_sw))))"}});
422 
424  "if($(outRow) == $(maxOutRow)) {\n"
425  " $(endRow);\n"
426  "}\n"
427  "const int strideRow = ($(outRow) * (int)$(conv_sh)) - (int)$(conv_padh);\n"
428  "const int kernRow = $(inRow) - strideRow;\n"
429  "for(int outCol = $(minOutCol); outCol < $(maxOutCol); outCol++) {\n"
430  " const int strideCol = (outCol * (int)$(conv_sw)) - (int)$(conv_padw);\n"
431  " const int kernCol = $(inCol) - strideCol;\n"
432  " for(unsigned int outChan = 0; outChan < (unsigned int)$(conv_oc); outChan++) {\n"
433  " const int idPost = (($(outRow) * (int)$(conv_ow) * (int)$(conv_oc)) +\n"
434  " (outCol * (int)$(conv_oc)) +\n"
435  " outChan);\n"
436  " $(addSynapse, idPost, kernRow, kernCol, $(inChan), outChan);\n"
437  " }\n"
438  "}\n"
439  "$(outRow)++;\n");
440 
442  [](unsigned int, unsigned int, const std::vector<double> &pars)
443  {
444  const double conv_kh = pars[0];
445  const double conv_kw = pars[1];
446  const double conv_sh = pars[2];
447  const double conv_sw = pars[3];
448  const unsigned int conv_oc = (unsigned int)pars[11];
449  return (unsigned int)std::ceil(conv_kh / conv_sh) * (unsigned int)std::ceil(conv_kw / conv_sw) * conv_oc;
450  });
451 
453  [](const std::vector<double> &pars)->std::vector<unsigned int>
454  {
455  return {(unsigned int)pars[0], (unsigned int)pars[1],
456  (unsigned int)pars[8], (unsigned int)pars[11]};
457  });
458 };
459 } // namespace InitSparseConnectivitySnippet
virtual ParamValVec getColBuildStateVars() const
Definition: initSparseConnectivitySnippet.h:55
#define SET_MAX_ROW_LENGTH(MAX_ROW_LENGTH)
Definition: initSparseConnectivitySnippet.h:30
virtual CalcMaxLengthFunc getCalcMaxColLengthFunc() const
Get function to calculate the maximum column length of this connector based on the parameters and the...
Definition: initSparseConnectivitySnippet.h:63
#define SET_COL_BUILD_CODE(CODE)
Definition: initSparseConnectivitySnippet.h:21
Definition: initSparseConnectivitySnippet.h:81
#define GENN_EXPORT
Definition: gennExport.h:13
Definition: snippet.h:250
virtual std::string getColBuildCode() const
Definition: initSparseConnectivitySnippet.h:54
#define SET_COL_BUILD_STATE_VARS(...)
Definition: initSparseConnectivitySnippet.h:22
virtual CalcMaxLengthFunc getCalcMaxRowLengthFunc() const
Get function to calculate the maximum row length of this connector based on the parameters and the si...
Definition: initSparseConnectivitySnippet.h:60
#define SET_ROW_BUILD_STATE_VARS(...)
Definition: initSparseConnectivitySnippet.h:19
#define DECLARE_SNIPPET(TYPE, NUM_PARAMS)
Definition: snippet.h:19
#define SET_CALC_MAX_COL_LENGTH_FUNC(FUNC)
Definition: initSparseConnectivitySnippet.h:27
Definition: initSparseConnectivitySnippet.h:273
GENN_EXPORT unsigned int binomialInverseCDF(double cdf, unsigned int n, double p)
Definition: binomial.cc:38
virtual ParamValVec getRowBuildStateVars() const
Definition: initSparseConnectivitySnippet.h:52
Definition: initSparseConnectivitySnippet.h:39
Initialises connectivity with a fixed number of random synapses per row.
Definition: initSparseConnectivitySnippet.h:224
#define SET_HOST_INIT_CODE(CODE)
Definition: initSparseConnectivitySnippet.h:24
Base class for all sparse connectivity initialisation snippets.
Definition: initSparseConnectivitySnippet.h:37
#define SET_DERIVED_PARAMS(...)
Definition: snippet.h:37
#define SET_CALC_KERNEL_SIZE_FUNC(...)
Definition: initSparseConnectivitySnippet.h:28
Initialises connectivity to a &#39;one-to-one&#39; diagonal matrix.
Definition: initSparseConnectivitySnippet.h:104
#define SET_MAX_COL_LENGTH(MAX_COL_LENGTH)
Definition: initSparseConnectivitySnippet.h:31
virtual std::string getRowBuildCode() const
Definition: initSparseConnectivitySnippet.h:51
virtual CalcKernelSizeFunc getCalcKernelSizeFunc() const
Get function to calculate kernel size required for this conenctor based on its parameters.
Definition: initSparseConnectivitySnippet.h:66
std::function< unsigned int(unsigned int, unsigned int, const std::vector< double > &)> CalcMaxLengthFunc
Definition: initSparseConnectivitySnippet.h:45
#define SET_ROW_BUILD_CODE(CODE)
Definition: initSparseConnectivitySnippet.h:18
Used to mark connectivity as uninitialised - no initialisation code will be run.
Definition: initSparseConnectivitySnippet.h:94
Definition: initSparseConnectivitySnippet.h:164
Base class for all code snippets.
Definition: snippet.h:120
#define SET_PARAM_NAMES(...)
Definition: snippet.h:36
virtual std::string getHostInitCode() const
Definition: initSparseConnectivitySnippet.h:57
std::function< std::vector< unsigned int >const std::vector< double > &)> CalcKernelSizeFunc
Definition: initSparseConnectivitySnippet.h:46
Initialises connectivity with a fixed number of random synapses per column.
Definition: initSparseConnectivitySnippet.h:362
Definition: initSparseConnectivitySnippet.h:404
Init(const Base *snippet, const std::vector< double > &params)
Definition: initSparseConnectivitySnippet.h:84
Definition: snippet.h:45
#define SET_CALC_MAX_ROW_LENGTH_FUNC(FUNC)
Definition: initSparseConnectivitySnippet.h:26
Definition: initSparseConnectivitySnippet.h:122
#define SET_EXTRA_GLOBAL_PARAMS(...)
Definition: snippet.h:38
Definition: initSparseConnectivitySnippet.h:196
std::vector< ParamVal > ParamValVec
Definition: snippet.h:180