brian-team/brian2 — pull request #34 by mstimberg (2013-05-03 16:50:23+00:00)
Title: New run system (changed namespace handling)

This closes #31
### Namespaces

As discussed, there are now three different options for specifying namespaces:

1. Explicit definition for a `NeuronGroup` -- this is fully explicit nothing else will be used for namespace lookup (except for functions and units)
2. Explicit definition of a namespace in the argument of the run call (implies the same namespace for all network objects, but only for objects that did not specify their own namespace)
3. Implicit namespace at the point where the run function is called (again, not used for objects that specify their own namespace).

You cannot override functions or units via either of these methods, they always take precedence.

For all of these, the namespace does not have to be complete at the time of NeuronGroup creation (not relevant for point 2 above).
For example you can do:
```
G = NeuronGroup(1, 'dv/dt = -v / tau : 1', namespace={})
G.namespace['tau'] = 10*ms
run(10*ms)
```
Or
```
G = NeuronGroup(1, 'dv/dt = -v / tau : 1')
tau = 10*ms
run(10*ms)
```

You can change elements in the namespace between runs, the implicit namespace always takes the context at the point of the run call into account.

### Unit checking
Units are checked at creation time, when the namespace is already complete. This is done in a very simple way by just trying it and silently ignoring KeyErrors (resulting from a namespace lookup failure). In the case of an incomplete namespace and unit errors in the model it makes the result unfortunately somewhat unpredictable: Depending on the order of unit checks the check might be raised (if it occurs before any KeyError) or not (if it occurs after a KeyError).

At the point of the run call, all units are checked and namespace resolution failures lead to an error, so unit errors should never slip through, even for changes in the namespace between runs.

BTW: Along the way I introduced unit checking for thresholds and resets! It checks directly the abstract code and even deals with new temporary variables. I first thought that the same check would be useful for the state updater code (it would spot errors in state updater descriptions) but then I realized that the linear state updater already gets rid of some units because it substitutes constants from the namespace, so I disabled the check for the state updater. The equations itself are checked anyway. We could add a check to the `ExplicitStateUpdater` class though that checks the general formulation for errors.

Some more remarks: Because the abstract code for state updates, resets and thresholds is regenerated for each run it is now possible to change the reset or threshold definition between runs.

All the "change between run" features are not much tested in the test suite but it should be quite save as there is no fundamental difference between the first run and subsequent runs in the code.

Finally, I did get rid of the `CodeRunner` vs. `NeuronGroupCodeRunner` distinction and moved the new class to `GroupCodeRunner` as there is nothing `NeuronGroup` specific about it anymore. Apart from `Synapses` it might be useful for `StateMonitor`, for example?

Sooo... anything missing? Otherwise I think it's good to merge (after a scrutinizing review, of course ;) ).