ctn-waterloo/nengo — pull request #329 by drasmuss (2014-04-17 20:52:18+00:00)
Title: Added system to specify default parameters at Network level

Here's a first draft at implementing the default config system we've been talking about. The idea is that you can use this to set one parameter at the Network level (e.g. the `synapse` time constant you want to use) which will then affect everything within that Network. There is also one overall default at the `nengo` level that will get used if nothing is set in the Network.

Here's how it looks when you use it:
```python
with nengo.Network():
a = nengo.Ensemble(nengo.LIF(50), 1) # will use default nengo parameters
a.radius = nengo.default # will assign default radius value
```
If you want to have Network-specific defaults, you need to add a config item to the network, like so:
```python
with nengo.Network() as net:
net.config.add_config(nengo.objects.EnsembleDefaults)
net.config[nengo.Ensemble].radius = 3.0
a = nengo.Ensemble(nengo.LIF(50, 1) # radius will be 3
```
This all works as you'd expect with nested Networks (it uses the config of the lowest level network first, working its way upwards). E.g.,
```python
with nengo.Network() as net:
net.config.add_config(nengo.objects.EnsembleDefaults)
net.config[nengo.Ensemble].radius = 3.0
a = nengo.Ensemble(nengo.LIF(50, 1) # radius will be 3
with nengo.Network():
b = nengo.Ensemble(nengo.LIF(50, 1) # radius will be 3
```

Note that it is using the config of the current _context_ to determine defaults. Just something to keep in mind in a case like this
```python
with nengo.Network() as net:
net.config.add_config(nengo.objects.EnsembleDefaults)
net.config[nengo.Ensemble].radius = 3.0
a = nengo.Ensemble(nengo.LIF(50, 1)
a.radius = nengo.default # will assign 3
a.radius = nengo.default # will assign the overall nengo default (1.0)
```

This is built on top of Terry's previous config work, which was designed to allow backends to add new data to an object. That should all be compatible with the way things are working here (although I haven't tested it). For example, you could do:
```python
class SpinnakerDefaults(nengo.objects.EnsembleDefaults):
on_spinnaker = True
model = nengo.Network()
model.add_config(SpinnakerDefaults)
with model:
model.config[nengo.Ensemble].radius = 3.0
a = nengo.Ensemble(nengo.LIF(50, 1) # radius will be 3
if model.config[nengo.Ensemble].on_spinnaker:
...
```

It passes all the tests and whatnot, so it works functionally. But before any official review/merge I wanted to get people's opinion on the overall design. Things you hate? Features you would like? etc.