JuliaSymbolics / SymbolicUtils.jl

Symbolic expressions, rewriting and simplification
https://docs.sciml.ai/SymbolicUtils/stable/
Other
536 stars 107 forks source link

`@register` does not work for arrays variables or arrays of variables #402

Open baggepinnen opened 2 years ago

baggepinnen commented 2 years ago

I cannot get @register to work with arrays of variables.

julia> foo(x) = 2x
foo (generic function with 1 method)

julia> @register foo(x)

julia> methods(foo)
# 3 methods for generic function "foo":
[1] foo(x::SymbolicUtils.Symbolic) in Main at /home/fredrikb/.julia/packages/Symbolics/LTmGT/src/register.jl:52
[2] foo(x::Num) in Main at /home/fredrikb/.julia/packages/Symbolics/LTmGT/src/register.jl:52
[3] foo(x) in Main at REPL[19]:1

julia> @register foo(x::Vector{Num})

julia> methods(foo)
# 3 methods for generic function "foo":
[1] foo(x::SymbolicUtils.Symbolic) in Main at /home/fredrikb/.julia/packages/Symbolics/LTmGT/src/register.jl:52
[2] foo
(x::Num) in Main at /home/fredrikb/.julia/packages/Symbolics/LTmGT/src/register.jl:52
[3] foo(x) in Main at REPL[19]:1

I have found one workaround, which is to define a wrapper function that accepts a symbolic dummy variable, like so

julia> bar(x, dummy) = foo(x)
bar (generic function with 1 method)

julia> @register bar(x::Vector{Num}, dummy)

julia> methods(bar)
# 3 methods for generic function "bar":
[1] bar(x::Vector{Num}, dummy::SymbolicUtils.Symbolic) in Main at /home/fredrikb/.julia/packages/Symbolics/LTmGT/src/register.jl:52
[2] bar(x::Vector{Num}, dummy::Num) in Main at /home/fredrikb/.julia/packages/Symbolics/LTmGT/src/register.jl:52
[3] bar(x, dummy) in Main at REPL[25]:1

but this is of course not optimal :)

Changing Vector{Num} to

julia> @variables x[1:2]
1-element Vector{Symbolics.Arr{Num, 1}}:
 x[1:2]

doesn't change anything

baggepinnen commented 2 years ago

ref https://github.com/JuliaSymbolics/Symbolics.jl/issues/292

baggepinnen commented 2 years ago

@YingboMa would this issue be a suitable first step towards better array-variable register support? An example usecase could be a dynamics function on the form

function f(u, p, t)
   # heavy computation
    return du
end

where du is an array. To register this, I imagine that you'd like to say something about the type and size of the output, e.g.,

@register f(u::Vector, p, t::Real)::Vector

but with additional size information.

The intended effect of calling f on arrays with symbols or symbolic arrays would be to get a "symbolic function call" like

FunctionCall{typeof(f)}((u, p, t), arg_types, return_type)

that can later be extended with derivative/sparsity information etc.

YingboMa commented 2 years ago

FYI, there's https://github.com/JuliaSymbolics/Symbolics.jl/pull/457. But it seems to be slightly buggy.

julia> @register_symbolic oof(x::AbstractVector)

julia> @variables x[1:100]
1-element Vector{Symbolics.Arr{Num, 1}}:
 x[1:100]

julia> oof(x)
ERROR: MethodError: no method matching oof(::Symbolics.Arr{Num, 1})
Closest candidates are:
  oof(::SymbolicUtils.Symbolic{<:AbstractVector}) at ~/src/julia/Symbolics/src/register.jl:51
Stacktrace:
 [1] top-level scope
   @ REPL[313]:1

julia> oof(Symbolics.unwrap(x))
oof(x)

@shashi could you take a look?

shashi commented 2 years ago

https://github.com/JuliaSymbolics/Symbolics.jl/pull/557 fixes it.