Skip to content
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

Default output of symbolic expressions is not usable Julia code #1253

Open
orebas opened this issue Sep 1, 2024 · 8 comments
Open

Default output of symbolic expressions is not usable Julia code #1253

orebas opened this issue Sep 1, 2024 · 8 comments

Comments

@orebas
Copy link

orebas commented Sep 1, 2024

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) and a just be synonyms in symbolic expressions?

julia> using Symbolics

julia> @variables t a(t) b(t)
3-element Vector{Num}:
    t
 a(t)
 b(t)

julia> q = a/b
a(t) / b(t)

julia> q
a(t) / b(t)

julia> r = a(t) / b(t)
ERROR: Sym a(t) is not callable. Use @syms a(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[5]:1
@ChrisRackauckas
Copy link
Member

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?

@orebas
Copy link
Author

orebas commented Sep 1, 2024

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

@ChrisRackauckas
Copy link
Member

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))

@orebas
Copy link
Author

orebas commented Sep 2, 2024

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(..)?

@ChrisRackauckas
Copy link
Member

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.

@orebas
Copy link
Author

orebas commented Sep 5, 2024

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.

@ChrisRackauckas
Copy link
Member

For that use case though, wouldn't you build function?

@orebas
Copy link
Author

orebas commented Sep 8, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants