JuliaSymbolics / Symbolics.jl

Symbolic programming for the next generation of numerical software
https://docs.sciml.ai/Symbolics/stable/
Other
1.36k stars 151 forks source link

Registering Functions with mixed array/non-array types #1188

Closed markilg closed 1 month ago

markilg commented 3 months ago

Trying to register functions to avoid tracing into wrapper code and having issues with mixed array/non-array types. For example:

function lookup(a::Float64,x::AbstractVector{Float64}) return -1; end
@register_symbolic lookup(a, x)::Float64

@variables a
lookup(1.0,[a,a])
ERROR: MethodError: no method matching lookup(::Float64, ::Vector{Num}) ...

but... the following dispatches correctly

@variables x[1:2]
lookup(1.0, x)

Any suggestions? The second argument to the lookup function must not be a Symbolic array type as it is composed of a variety of variables.

ChrisRackauckas commented 3 months ago

We got a few of these issues recently. Right now I've been helping people add the necessary dispatches, though I want to hear from @shashi on his take on how this corresponds to the designs of the macros.

markilg commented 2 months ago

What would be your recommendation for handling registration for this case? When I preform manual registration symbolics dispatches properly but MTK fails during structural simplify.

Example for Array only with Real return value:

lookup(x::AbstractVector{Float64}) = 1.0;
lookup(x::AbstractVector{Num}) = SymbolicUtils.term(lookup,Symbolics.unwrap(x))
(::(typeof)(SymbolicUtils.promote_symtype))(::(typeof)(lookup), args...) = Float64

structural simplify will give error about not having a lookup(x::AbstractVector{Any}) method.

If I create the method (Without Error Checking!):

lookup(x::AbstractVector{Any}) = lookup(convert(Array{Num,1}, x));

simplification works but fails on solve attempting to convert type SymbolicUtils.BasicSymbolic{Float64} to an object of type Float64

Seems like a rabbit hole I don't want to progress down.

ChrisRackauckas commented 1 month ago

@shashi @AayushSabharwal this was handled?

AayushSabharwal commented 1 month ago

Yes, this works if registered with the correct type annotations:

julia> @register_symbolic lookup(a, x::AbstractVector)::Float64

julia> lookup(1.0,[a,a])
lookup(1.0, SymbolicUtils.BasicSymbolic{Real}[a, a])

julia> Symbolics.toexpr(lookup(1.0,[a,a]))
:((lookup)(1.0, begin
          #= /Users/aayush/.julia/packages/SymbolicUtils/rcLYm/src/code.jl:480 =#
          (SymbolicUtils.Code.create_array)(Vector{SymbolicUtils.BasicSymbolic{Real}}, nothing, Val{1}(), Val{(2,)}(), a, a)
      end))

julia> fn = build_function(Symbolics.toexpr(lookup(1.0,[a,a])), a, expression = Val{false})
RuntimeGeneratedFunction(#=in Symbolics=#, #=using Symbolics=#, :((a,)->begin
          #= /Users/aayush/.julia/packages/SymbolicUtils/rcLYm/src/code.jl:385 =#
          #= /Users/aayush/.julia/packages/SymbolicUtils/rcLYm/src/code.jl:386 =#
          #= /Users/aayush/.julia/packages/SymbolicUtils/rcLYm/src/code.jl:387 =#
          (lookup)(1.0, begin
                  #= /Users/aayush/.julia/packages/SymbolicUtils/rcLYm/src/code.jl:480 =#
                  (SymbolicUtils.Code.create_array)(Vector{SymbolicUtils.BasicSymbolic{Real}}, nothing, Val{1}(), Val{(2,)}(), a, a)
              end)
      end))

julia> fn(1.0)
-1