New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New syntax for "constant over timestep" variables #720

Closed
mstimberg opened this Issue Jun 20, 2016 · 10 comments

Comments

Projects
None yet
2 participants
@mstimberg
Member

mstimberg commented Jun 20, 2016

In some situations, e.g. when using certain state updaters or to avoid re-evaluations of expressions involving random numbers, it would be useful to have a way of declaring a subexpression that is only evaluated once per timestep. The current workaround is to declare the variable as a parameter and update it with run_regularly -- this is a bit clumsy. I think we could introduce a new flag for subexpressions, something like

x = rand() : 1 (static)

with hopefully a clearer name than "static".

@thesamovar

This comment has been minimized.

Show comment
Hide comment
@thesamovar

thesamovar Jun 20, 2016

Member

The problem I have with this syntax is: when is it evaluated? It doesn't make a difference for rand() but would if there were any state variables in there. Feels like asking for trouble in some way, although I agree that people use x = rand() : 1 and expect it to behave differently than it does. At the very least we should warn when people use a stateful function in a subexpression (which I see you've just opened a new issue for so I'll stop writing here!).

Member

thesamovar commented Jun 20, 2016

The problem I have with this syntax is: when is it evaluated? It doesn't make a difference for rand() but would if there were any state variables in there. Feels like asking for trouble in some way, although I agree that people use x = rand() : 1 and expect it to behave differently than it does. At the very least we should warn when people use a stateful function in a subexpression (which I see you've just opened a new issue for so I'll stop writing here!).

@mstimberg

This comment has been minimized.

Show comment
Hide comment
@mstimberg

mstimberg Jun 20, 2016

Member

One general thought (related to what I just wrote in #721): if we add a syntax, it might be good to have an explicit syntax for both cases, i.e. something like (evaluate-once) vs. (evaluate-everytime).

The problem I have with this syntax is: when is it evaluated?

I see at least three options:

  1. Make it part of the flag, something like (evaluate: start)
  2. The update for these "static subexpressions" happens in its own object, which uses our default scheduling system (e.g. it defaults to when='before_groups' but you can change it by assigning something else to its when attribute).
  3. It is evaluated when it is used the first time during a time step.

I think 3 is a bit intransparent, I'd therefore prefer 1 or 2. I have a slight tendency towards 2 because it would be more consistent with what we do in other places (e.g. for (summed) in synapses), it would be straightforward to implement and it does not add a lot of syntax.

Member

mstimberg commented Jun 20, 2016

One general thought (related to what I just wrote in #721): if we add a syntax, it might be good to have an explicit syntax for both cases, i.e. something like (evaluate-once) vs. (evaluate-everytime).

The problem I have with this syntax is: when is it evaluated?

I see at least three options:

  1. Make it part of the flag, something like (evaluate: start)
  2. The update for these "static subexpressions" happens in its own object, which uses our default scheduling system (e.g. it defaults to when='before_groups' but you can change it by assigning something else to its when attribute).
  3. It is evaluated when it is used the first time during a time step.

I think 3 is a bit intransparent, I'd therefore prefer 1 or 2. I have a slight tendency towards 2 because it would be more consistent with what we do in other places (e.g. for (summed) in synapses), it would be straightforward to implement and it does not add a lot of syntax.

@thesamovar

This comment has been minimized.

Show comment
Hide comment
@thesamovar

thesamovar Jun 20, 2016

Member

OK, agree with having an explicit syntax for both cases. Should we make that only necessary when there are stateful functions or always necessary? I'd say only when there are stateful functions, with a default of the current behaviour of evaluate-everytime when there are no stateful functions. This does allow for some slight problems in that you might write x=v and hope it means the value of v at the beginning of the timestep and actually it wouldn't always mean that, but this seems relatively unlikely and the saving in unnecessary syntax in the majority of cases seems worth it.

Also agree with having before groups be the default if it matches what we're doing elsewhere (and in any case, this does seem fairly logical). Is there any use case for allowing the user to specify something else? I don't really see any. In which case, it's just a question of the syntax.

One option would be something a bit high level, like (step-function) for evaluate once, versus (subexpression) for evaluate every time. I like step-function but not sure about subexpression. Maybe fluctuating? Or could use volatile? (This matches natural language as well as C and Java's usage of that.)

Actually I like (step-function) versus (volatile). What do you think?

Member

thesamovar commented Jun 20, 2016

OK, agree with having an explicit syntax for both cases. Should we make that only necessary when there are stateful functions or always necessary? I'd say only when there are stateful functions, with a default of the current behaviour of evaluate-everytime when there are no stateful functions. This does allow for some slight problems in that you might write x=v and hope it means the value of v at the beginning of the timestep and actually it wouldn't always mean that, but this seems relatively unlikely and the saving in unnecessary syntax in the majority of cases seems worth it.

Also agree with having before groups be the default if it matches what we're doing elsewhere (and in any case, this does seem fairly logical). Is there any use case for allowing the user to specify something else? I don't really see any. In which case, it's just a question of the syntax.

One option would be something a bit high level, like (step-function) for evaluate once, versus (subexpression) for evaluate every time. I like step-function but not sure about subexpression. Maybe fluctuating? Or could use volatile? (This matches natural language as well as C and Java's usage of that.)

Actually I like (step-function) versus (volatile). What do you think?

@mstimberg

This comment has been minimized.

Show comment
Hide comment
@mstimberg

mstimberg Jun 22, 2016

Member

OK, agree with having an explicit syntax for both cases. Should we make that only necessary when there are stateful functions or always necessary?

I think this would be the best solution. I.e., you can always set the two options, but you are forced to do it if the expression involves stateful functions. In models like the one used in the COBAHH example, the subexpressions are really used for structuring the equations and being forced to add an additional flag would be annoying I think.

Also agree with having before groups be the default if it matches what we're doing elsewhere (and in any case, this does seem fairly logical). Is there any use case for allowing the user to specify something else? I don't really see any. In which case, it's just a question of the syntax.

I don't see any immediate use case, but I did not see any for the summed variables either and e.g. the LFP example does need to change the scheduling to work correctly... I think the same approach would be the best: the update happens in a separate object and can therefore be re-scheduled but only with a rather low-level syntax. No need to expose it as an additional keyword argument or anything like that.

Actually I like (step-function) versus (volatile). What do you think?

Hmm, I have to say I am not convinced... I see the reasoning behind step-function, but I don't think it is clear in equations: x = 1/(1 + exp(y/scale)) : 1 (step-function) feels kind of wrong because we are not describing a step function (of what?), something like (step-approximation) would be more meaningful, I guess. On the other hand, for x = rand() I don't think that either makes much sense.

Similar for (volatile): I get it from a technical point of view ("don't read it from a cache"), but I would more think about a variable that can be change from somewhere else. The concept of volatile in C/Java does not apply to expressions.

Ideally, I'd like two have two flags that are somewhat parallel and therefore easily recognizable as alternatives (e.g. just from the names I would not think that (step-function, volatile) is necessarily meaningless), i.e. in the same vein as (clock-driven)/(event-driven). I don't have anything to propose for now, I'll try to come up with something soon!

Member

mstimberg commented Jun 22, 2016

OK, agree with having an explicit syntax for both cases. Should we make that only necessary when there are stateful functions or always necessary?

I think this would be the best solution. I.e., you can always set the two options, but you are forced to do it if the expression involves stateful functions. In models like the one used in the COBAHH example, the subexpressions are really used for structuring the equations and being forced to add an additional flag would be annoying I think.

Also agree with having before groups be the default if it matches what we're doing elsewhere (and in any case, this does seem fairly logical). Is there any use case for allowing the user to specify something else? I don't really see any. In which case, it's just a question of the syntax.

I don't see any immediate use case, but I did not see any for the summed variables either and e.g. the LFP example does need to change the scheduling to work correctly... I think the same approach would be the best: the update happens in a separate object and can therefore be re-scheduled but only with a rather low-level syntax. No need to expose it as an additional keyword argument or anything like that.

Actually I like (step-function) versus (volatile). What do you think?

Hmm, I have to say I am not convinced... I see the reasoning behind step-function, but I don't think it is clear in equations: x = 1/(1 + exp(y/scale)) : 1 (step-function) feels kind of wrong because we are not describing a step function (of what?), something like (step-approximation) would be more meaningful, I guess. On the other hand, for x = rand() I don't think that either makes much sense.

Similar for (volatile): I get it from a technical point of view ("don't read it from a cache"), but I would more think about a variable that can be change from somewhere else. The concept of volatile in C/Java does not apply to expressions.

Ideally, I'd like two have two flags that are somewhat parallel and therefore easily recognizable as alternatives (e.g. just from the names I would not think that (step-function, volatile) is necessarily meaningless), i.e. in the same vein as (clock-driven)/(event-driven). I don't have anything to propose for now, I'll try to come up with something soon!

@mstimberg

This comment has been minimized.

Show comment
Hide comment
@mstimberg

mstimberg Jun 22, 2016

Member

(evaluate-per-timestep)/(evaluate-per-dt) vs. (evaluate-per-use)/(evaluate-per-call)
(per-timestep) vs. (per-use)
(each-timestep) vs. (each-use)
(every-timestep) vs. (every-use)
...

Member

mstimberg commented Jun 22, 2016

(evaluate-per-timestep)/(evaluate-per-dt) vs. (evaluate-per-use)/(evaluate-per-call)
(per-timestep) vs. (per-use)
(each-timestep) vs. (each-use)
(every-timestep) vs. (every-use)
...

@thesamovar

This comment has been minimized.

Show comment
Hide comment
@thesamovar

thesamovar Jun 22, 2016

Member

Very fair points. I will think more on syntax and get back to you. In any case, I think we agree on how it should work now.

Member

thesamovar commented Jun 22, 2016

Very fair points. I will think more on syntax and get back to you. In any case, I think we agree on how it should work now.

@mstimberg

This comment has been minimized.

Show comment
Hide comment
@mstimberg

mstimberg Jun 22, 2016

Member

In any case, I think we agree on how it should work now.

Indeed. Maybe it would be a good idea to start to work on the technical side of this -- the user syntax for the flags is something that we can change easily later (before merging, I mean).

Member

mstimberg commented Jun 22, 2016

In any case, I think we agree on how it should work now.

Indeed. Maybe it would be a good idea to start to work on the technical side of this -- the user syntax for the flags is something that we can change easily later (before merging, I mean).

@thesamovar

This comment has been minimized.

Show comment
Hide comment
@thesamovar

thesamovar Jun 22, 2016

Member

What about something like slow versus fast? I think this isn't quite right because it would be a little weird to say that rand() was slow, but I think maybe something along these lines could work.

Member

thesamovar commented Jun 22, 2016

What about something like slow versus fast? I think this isn't quite right because it would be a little weird to say that rand() was slow, but I think maybe something along these lines could work.

@thesamovar

This comment has been minimized.

Show comment
Hide comment
@thesamovar

thesamovar Jun 22, 2016

Member

Actually now that I think about it, being able to declare that one variable is varying slow or fast with respect to another might be useful for approximations for both numerical and symbolic integration?

Member

thesamovar commented Jun 22, 2016

Actually now that I think about it, being able to declare that one variable is varying slow or fast with respect to another might be useful for approximations for both numerical and symbolic integration?

@mstimberg

This comment has been minimized.

Show comment
Hide comment
@mstimberg

mstimberg Jun 24, 2016

Member

I see what you mean, but I think that slow and fast are too general for what we mean.

Actually now that I think about it, being able to declare that one variable is varying slow or fast with respect to another might be useful for approximations for both numerical and symbolic integration?

I think it is a long way until we will do approximations based on differences in time scale, that's a tricky topic. The only thing that we already use is the distinction between "constant over a time step" (which we call locally constant in our code) and not. I think it is important that the term makes sense for something like rand(), because this is the situation that will trigger a warning. IMO, a qualified from of "constant" (locally constant, constant over dt, constant over timestep, ...) would be the clearest -- unfortunately I cannot think of a good antonym to use here (varying, variable, changing, ...). I had a look at the list here http://www.thesaurus.com/browse/constant , but I think fickle and wobbly are no options ;)

If I had to vote for something of all that has been proposed so far, I'd probably vote for constant over dt and variable over dt.

Member

mstimberg commented Jun 24, 2016

I see what you mean, but I think that slow and fast are too general for what we mean.

Actually now that I think about it, being able to declare that one variable is varying slow or fast with respect to another might be useful for approximations for both numerical and symbolic integration?

I think it is a long way until we will do approximations based on differences in time scale, that's a tricky topic. The only thing that we already use is the distinction between "constant over a time step" (which we call locally constant in our code) and not. I think it is important that the term makes sense for something like rand(), because this is the situation that will trigger a warning. IMO, a qualified from of "constant" (locally constant, constant over dt, constant over timestep, ...) would be the clearest -- unfortunately I cannot think of a good antonym to use here (varying, variable, changing, ...). I had a look at the list here http://www.thesaurus.com/browse/constant , but I think fickle and wobbly are no options ;)

If I had to vote for something of all that has been proposed so far, I'd probably vote for constant over dt and variable over dt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment