Closed ChrisRackauckas closed 5 years ago
Variable
s as functions rather than "leaf nodes". This is a change I would definitely be for, and I should be able to get this done fairly quickly.Variable
s as functions, we should be able to call them as usual in the expression tree with no unexpected consequences.Note that it's possible to get the second example working based on the existing model with a bit of outside manipulation of the function. (e.g. for each call to σ′
, make a new variable - σ′t1
, σ′t2
, etc. - and pass it in as a separate parameter) This isn't elegant, though, and doesn't work in the context of unknown variables.
If we move forward and treat variables as functions, I propose the following macro meaning:
@parameters t()
@variables x(t) y(t) z(t)
@parameters σ ρ(t) β()
t = Variable(:t; known=true)()
x = Variable(:x)(t)
y = Variable(:y)(t)
z = Variable(:z)(t)
σ = Variable(:σ; known=true)
ρ = Variable(:ρ; known=true)(t)
β = Variable(:β; known=true)()
Providing a symbol name in a non-call form leaves the symbol as a function object to be called. Providing the arguments within the macro call aliases the variable to the specified call, however, which includes 0-ary calls (for independent variables and constant values).
Assuming this looks reasonable, I can swap out the internals of a few helper functions and have this functionality ready.
I think that's a reasonable way forward. Though I don't know what you mean by:
Providing a symbol name in a non-call form leaves the symbol as a function object to be called.
Does this mean in this case it's kept as β
and not β()
?
No, I mean the opposite, actually - it's an important distinction to make.
There, I mean if you simply give a symbol name (in this example, σ
), it is left as a function which can be called in the expression (e.g. σ(t)
, σ(t-1)
, etc.). However, if you provide the macro with an expression in call format (like ρ(t)
or β()
), we alias the name to this specific call (ρ
refers to ρ(t)
and β
refers to the constant β()
).
Notice in the macro expansion I provided that all Variable
s are called and turned into Expression
s, other than σ
, which is left as a Variable <: Function
.
I suppose an alternative scheme could be to use _
to denote functions, treating symbols as implicit 0-ary functions:
@parameters t
@variables x(t) y(t) z(t)
@parameters σ(_) ρ(t) β
This might reduce confusion with macro usage, actually.
There, I mean if you simply give a symbol name (in this example, σ), it is left as a function which can be called in the expression (e.g. σ(t), σ(t-1), etc.). However, if you provide the macro with an expression in call format (like ρ(t) or β()), we alias the name to this specific call (ρ refers to ρ(t) and β refers to the constant β()).
That sounds promising.
I suppose an alternative scheme could be to use _ to denote functions, treating symbols as implicit 0-ary functions:
That looks more confusing to me. I like the σ()
For initial time-varying parameter support, @HarrisonGrodin got the following test problem working:
This generates an expression that expands to
σ′(t)
. This works, and in many cases is what the user will want, but what we need in order to support delay differential equations, and also make some cases easier to parse into MT format, is something like:So there's two questions to ask here: