In [1]:
import nengo
import nengo.spa as spa
dimensions = 32
model = spa.SPA()
with model:
model.state1 = spa.Buffer(dimensions=dimensions)
model.state2 = spa.Buffer(dimensions=dimensions)
model.output = spa.Buffer(dimensions=dimensions)
model.bg = spa.BasalGanglia(spa.Actions('0.5 --> output=state1*state2'))
model.thal = spa.Thalamus(model.bg)
In [2]:
sim = nengo.Simulator(model)
In [3]:
for ens in model.all_ensembles:
# data defined by the model is directly accessed
n_neurons = ens.n_neurons
dimensions = ens.dimensions
# data generated by the default backend is accessed via sim.model.params
encoder = sim.model.params[ens].encoders
bias = sim.model.params[ens].bias
gain = sim.model.params[ens].gain
In [4]:
decoders = {}
for ens in model.all_ensembles:
decoders[ens] = {}
for connection in model.all_connections:
if isinstance(connection.pre_obj, nengo.Ensemble):
ens = connection.pre_obj
function = connection.function
if function not in decoders[ens]:
decoders[ens][function] = sim.model.params[connection].decoders
Remove internal Nodes from the network. When creating models, we often introduce Nodes that do nothing other than act as conventient shortcuts for referring to collections of ensembles. So we might have a Node that acts like the output from 10 ensembles, allowing us to just connect to that Node rather than making a separate connection from each Ensemble. These Nodes are just a programming convenience, and are generally compiled out by most backends.
In [5]:
objects = model.all_ensembles + model.all_nodes
connections = model.all_connections
import nengo.utils.builder
objects, connections = nengo.utils.builder.remove_passthrough_nodes(objects, connections)
In [6]:
for node in objects:
if isinstance(node, nengo.Node):
size_in = node.size_in # input to the node (output from the model)
size_out = node.size_out # output from the node (input to the model)
output = node.output # the actual output. May be callable() or a constant
In [7]:
for connection in connections:
pre = connection.pre_obj # the Ensemble or Node that is the source for this connection
post = connection.post_obj # the Ensemble or Node that is the target for this connection
synapse = connection.synapse # filter
function = connection.function # the function to compute
if isinstance(pre, nengo.Ensemble):
decoder = decoders[pre][function] # the decoder for that function
transform = nengo.utils.builder.full_transform(connection, allow_scalars=False) # the transform
if isinstance(post, nengo.ensemble.Neurons):
# this is a rare case where we are bypassing the encoder
# In general, this allows for specifying arbitary networks.
# In Spaun, we only ever use this in cases where the weight matrix is all -1
# so we could actually replace it with adding a new dimension to the encoder
# that is also all -1.
bypass_encoders = True
post = post.ensemble