JuliaSymbolics / SymbolicUtils.jl

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

Generated functions no longer re-tracable with Symbolics #544

Open baggepinnen opened 10 months ago

baggepinnen commented 10 months ago

A recent change (maybe PR #536 @YingboMa ?) causes functions produced by build_function to fail when called with symbolic variables:

julia> @variables x
1-element Vector{Num}:
 x

julia> f = build_function([sin(x)], [x], expression=Val{false});

julia> f[1]([1])
1-element Vector{Float64}:
 0.8414709848078965

julia> f[1]([x])
ERROR: StackOverflowError:
Stacktrace:
 [1] sin(x::Num) (repeats 79984 times)
   @ NaNMath ~/.julia/packages/NaNMath/ceWIc/src/NaNMath.jl:11

This is a problem when generated functions are used to build, e.g., cost functions for optimization problems, after which symbolic tracing is used to find sparsity patterns or generate jacobian functions etc.

shashi commented 10 months ago
        ($f)(x::Real) = ($f)(float(x))

They have this, and assume float will always return a float which it should, but @YingboMa added this:

https://github.com/JuliaSymbolics/Symbolics.jl/commit/c890de9bb#diff-b8c0c7fd71b608d8ede7feac325fbfa572e06bd50bc32f0b835f3dbe61bb7fa5R32

which will make it go into an infinite loop.

Makes me think #536 is not really working...

shashi commented 10 months ago

@baggepinnen just curious why is the sparsity detection implemented like this? Is it beneficial to do this over just calling jacobian_sparsity before you generate the code? (I need legit examples where we trace generated code symbolically again.)

baggepinnen commented 10 months ago

I my use case, I have dynamics functions generated by MTK, those are then used to compute a Lagrangian for an optimal control problem, the Hessian of which I need for the optimization. It's this Hessian, and other similar functions, I am "re tracing". I could keep everything symbolic without generating the intermediate dynamics function, but then I'd need separate logic to handle MTK models and manually written models, so I opted for always going through a function.

shashi commented 10 months ago

Awesome! Thanks that's a great example of code reuse.