Closed dabliss closed 9 years ago
We're definitely open to suggestions of this sort and we decide them based on whether there is a general use case, i.e. whether or not it's likely to be useful to more people. So what sort of use cases do you have in mind? As far as I know (Marcel may correct me), the only important thing that sorting the subexpressions does is to get the dependencies in the right order (but this is essential).
What I noticed is that _sort_subexpressions
gets dependencies in the right order only for subexpressions -- not for differential equations. All differential equations are updated at the same step after subexpressions, and parameters follow differential equations.
I have subexpressions -- e.g.,
I_gaba = -G_gaba * s_gaba * (v - E_gaba) --
that are dependent on differential equations -- in this case,
ds_gaba / dt = -s_gaba / t_gaba.
So I'd like the differential equations to be updated before the subexpressions. (I'm assuming that when a differential equation is updated, the variable to which it applies -- here, s_gaba
-- is also updated.)
Wait, if the dependencies are in the wrong order doesn't that mean it's a bug? If so, it would be really helpful if you could give us a very simple example where the behaviour is wrong.
I wasn't sure whether that order was unintended. A comment in the body of _sort_subexpressions
says,
# i.e. ignore dependencies on parameters and differential equations
So it does what it says it's going to do.
Hmm. OK, I'll wait for a comment from @mstimberg on this, I don't remember at the moment.
I think there is some misconception about the meaning of update order and subexpressions here. In contrast to Brian 1 (where they were called "static equations"), subexpressions do not correspond to a variable, they are just a tool to structure your code. If the name of a subexpressions is used, you should be able to substitute it with the expression and get the same result. Therefore, if you have something like
...
I_gaba = -G_gaba * s_gaba * (v - E_gaba) ... : amp
dv/dt = (g_L*(v - E_L) + I_gaba + ...) / Cm : volt
...
then this is equivalent to
...
dv/dt = (g_L*(v - E_L) + -G_gaba * s_gaba * (v - E_gaba) + ...) / Cm : volt
...
Among several differential equations, there is no such thing as an update order, they are all updated simultaneously, using the state variable values from the previous time step, everything else would be mathematically incorrect.
The update order is only important for the code generation related to subexpressions, if you use one subexpression in abstract code that refers to other subexpressions, those other expressions have to be evaluated first.
Hope that makes things clearer. I don't think there's any situation where the user should have to care about the order of equations, the order you use in the equations string should never matter.
Huh, OK. Thanks a lot for this explanation. I have one lingering question. You say,
Among several differential equations, there is no such thing as an update order, they are all updated simultaneously, using the state variable values from the previous time step, everything else would be mathematically incorrect.
Suppose I have
dv / dt = -G_gaba * s_gaba * (v - E_gaba) / Cm : volt
ds_gaba / dt = -s_gaba / t_gaba.
Is there no way for me to update s_gaba
according to the differential equation for s_gaba
before I update v
according to the differential equation for v
? I guess I'm not seeing why this is in all cases mathematically incorrect (given that, for example, brian2
would allow me to achieve this order if I updated s_gaba
at the 'start' stage and v
at the 'groups' stage).
Is there no way for me to update s_gaba according to the differential equation for s_gaba before I update v according to the differential equation for v?
No, this is a system of coupled differential equations, and v
and s_gaba
are functions of time, you can't "update" them independently of each other if they are part of the same system of equations (which is what putting them in the same Equations
object means). As I said before, during the update step, there's no "order", both variables are updated based on the values of the variables at the beginning of the time step, e.g. with the forward Euler method:
>>> eqs = Equations('''
... dv / dt = -G_gaba * s_gaba * (v - E_gaba) / Cm : volt
... ds_gaba / dt = -s_gaba / t_gaba : 1''')
>>> print euler(eqs)
_s_gaba = -dt*s_gaba/t_gaba + s_gaba
_v = v - G_gaba*dt*s_gaba*(-E_gaba + v)/Cm
s_gaba = _s_gaba
v = _v
I'm not quite sure I understand what you want to achieve, but if this is related to the fact that s_gaba
is discretely updated for synaptic events then you could work around the restrictions of a single system of coupled equations by describing s_gaba
as part of the synaptic model (which will be less efficient because updates will be done once per synapse instead of once per neuron but you can provide an order
keyword argument to change when it is updated during the time step).
Aha, OK, this resolves the issue for me. Thanks for clarifying. It wasn't that I wanted to achieve anything exotic; I just wanted to understand (or, have control over so that I could understand) how the updating was taking place. If it isn't obvious already, I am not all that experienced with neural simulations. I greatly appreciate the help experts like you and Dan give me.
No problem! We're happy that you're using Brian. :)
I'm going to close this issue now if there's no further problems.
Hey,
This is a feature request, not a bug report. I'm wondering how you'd feel about giving users easier control over the order of the equations within an
Equations
object. I'm thinking about giving users the ability to pass an order as a keyword argument (toEquations
and possibly also toNeuronGroup
). Right now I'm sub-classingEquations
and using my own version of_sort_subexpressions
. (Is there a reason the update order should always be what the current_sort_subexpressions
produces -- aside from the special treatment of dependencies?)