Open orebas opened 2 weeks ago
We'd need to think about this a bit. It is somewhat of an alias, but if someone does a(tau)
should it error? Or would that just be nice syntax to change the time for something like a delay differential equation?
Actually, now that I think about it a bit more, I'm not sure how to ask Julia Symbolics to help me with the following math problem: We have a function f(t), i.e. the variable f depends on t. How do I expand the derivative of f(t^2)?
julia> @variables t f(t)
2-element Vector{Num}:
t
f(t)
julia> D = Differential(t)
Differential(t)
julia> D(t^2)
Differential(t)(t^2)
julia> expand_derivatives(D(t^2))
2t
julia> expand_derivatives(D(f))
Differential(t)(f(t))
julia> expand_derivatives(D(f(t*t)))
ERROR: Sym f(t) is not callable. Use @syms f(t)(var1, var2,...) to create it as a callable.
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:35
[2] (::SymbolicUtils.BasicSymbolic{Real})(args::SymbolicUtils.BasicSymbolic{Real})
@ SymbolicUtils ~/.julia/packages/SymbolicUtils/65hU9/src/types.jl:918
[3] (::Num)(args::Num)
@ Symbolics ~/.julia/packages/Symbolics/ztabB/src/num.jl:19
[4] top-level scope
@ REPL[7]:1
Use a wildcard.
julia> @variables t f(..)
2-element Vector{Any}:
t
f⋆
julia> expand_derivatives(Differential(t)(f(t^2)))
2t*Differential(t^2)(f(t^2))
That's cool. I couldn't find that syntax documented anywhere. What does it mean? (Is it a macro thing?)
What is the reason to ever declare something an f(t) as opposed to f(..)?
We should probably add it to https://docs.sciml.ai/Symbolics/stable/manual/variables/#Symbolics.@variables the docstring.
What does it mean? (Is it a macro thing?)
It's a wildcard. It's a call variable, but with a lazy ask for what the call is.
What is the reason to ever declare something an f(t) as opposed to f(..)?
Simplicity. It's very common to have something that's just x(t)
everywhere (for example, in a differential equation definition). It's much more rare to have expressions like x(t) + x(t^2)
, but the wildcard expression gives you a way to specify it. But if you do that, you do have to put x(t)
everywhere, x
is simply ill-defined because it's a function so it needs what it's a function of everywhere.
For what it's worth, I think that in at least the case I described above, changing the default output so that a
is displayed instead of a(t)
resolves the issue.
To expand a bit: I'm not sold on rejecting a(t) when a is accepted and is interpreted to mean a(t). However, the value of "display" output being pastable and manipulable Julia code is evident, and I think it's the standard for many other base packages (like LinAlg etc.) So whatever input Symbolics chooses to accept, right now a small change in the output would at least fix the above case, and IMHO might improve readability of the output.
For that use case though, wouldn't you build function?
The "use case" here is interacting with Symbolics in the REPL. For example, I was trying to debug some code and the output of the REPL is not something I can just paste back into the REPL, for instance, to simplify it or expand it. I have to copy and paste into an editor and replace "a(t)" with "a". For 5 variables it takes a while. It's easily avoidable.
In both the REPL and when executing scripts, the display of symbolic expressions is not, unfortunately, copy and pastable Julia code. See below for a very simple MWE.
I think it is not currently promised by Symbolics, but reasonable to strive for: -Anything output in the repl as a symbolic expression should be valid Julia syntax, assignable to a new variable.
Separately, I don't really understand the below. Shouldn't
a(t)
anda
just be synonyms in symbolic expressions?