Skip to content

Synapse creation

Dan Goodman edited this page Jan 15, 2016 · 17 revisions

See also: #600, #65.

Current best option is to have two ways of creating synapses: a simplified syntax for common cases, and a very flexible but slightly more complicated generator syntax. The simplified syntax is basically what we already have:

S.connect(condition='True', p=1, n=1)
S.connect(pre, post)

The first is interpreted as meaning create random synapses with probability p, and then keep them if the condition is satisfied, and then create n of them. The second means create explicit synapses using the arrays pre and post.

The new generator syntax would look like this:

S.connect(j='i+k for k in range(-3, 4)')
S.connect(j='k for k in range(0, N) if condition')
S.connect(j='k for k in random_sample(0, N, p) if condition')
S.connect(j='k for k in fixed_sample(0, N, num_targets)')

or in general:

S.connect(j='expr for var in candidates')
S.connect(j='expr for var in candidates if condition')

where expr can be any integer expression, var can be any variable name, candidates should be one of range, random_sample or fixed_sample and condition can be any boolean expression. range has the default meaning in Python. Random sample would be like setting p=..., and fixed_sample(0, N, k) would return a randomly selected set of k integers between 0 and N-1. Note that the names of range, random_sample and fixed_sample could be changed: those are just a first suggestion (although probably fine I think).

This syntax is easy to convert into different languages (numpy/c++/cython), very flexible, and allows for very efficient synapse construction (since range, random and fixed samples can all be efficiently iterated over). To start with, the candidates would be a fixed list (range, random, fixed), but the nice thing about this syntax is that because it's valid Python it makes it very easy to expand it in the future. It also means that it will be familiar to users, and that they can test out connectivity patterns by just writing it in standard Python code since it is actually a valid Python expression. Parsing it is also extremely easy using the Python ast module (about 20 lines of code).

Other options

syn.connect(j='i+k', foreach='k in [-3, 3]')
syn.connect(j='i+k', foreach='k in [-3, 4[')
syn.connect(j='i+k', foreach='k in {-3, 0, 3}')

This is shorter than the generator syntax, but not as flexible (e.g. no way of specifying a fixed number of targets) and the meaning of the various brackets is maybe not obvious to everyone (for example, some people use [a,b) for a half open interval rather than [a,b[).

S.connect(condition='(i-100)%3==0', target_range=('i-100', 'i+100'), p=0.01)
S.connect(num_random_targets=20)
S.connect(target='i+(-1)**m', m_range=(0, 2))

This and variants were mine and Marcel's suggestions but I think in retrospect it's really less good than the generator syntax.

S.connect('rand()<p and j>=i-100 and j<=i+100')

In this suggestion (also mine, and I'm also disavowing it), we would analyse the boolean expression into parts, check for patterns, and construct an efficient way of iterating over it. The nice thing about this is that it's in some sense no syntax at all, just a condition. The bad part is that this method has many pitfalls (e.g. complicated boolean expressions expressed in a non-canonical way could mean that the expression couldn't be analysed), and actually requires the user to know how it works internally if they don't want nasty surprises.

Clone this wiki locally