-
-
Notifications
You must be signed in to change notification settings - Fork 217
handling of if-else-end conditionals in an MTK model (not requiring IfElse.jl) #1070
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
Comments
macro to_ifelse(ex)
esc(to_ifelse(ex))
end
function to_ifelse(ex)
if ex isa Expr && ex.head in (:if, :elseif)
:($(IfElse.ifelse)($(map(to_ifelse, vcat(ex.args, nothing)[1:3])...)))
elseif ex isa Expr
Expr(ex.head, map(to_ifelse, ex.args)...)
else
ex
end
end more robust |
Was this fixed? |
No, but it's more of a symbolics issue. We'd need an alternative tracer since a dispatch-based tracer cannot handle if, at least in its current form. If |
Here is a macro that can convert nested if statements to ffirst(x) = first(first(x))
opmap = Dict(
:(+=) => :(+),
:(-=) => :(-),
:(*=) => :(*),
:(/=) => :(/),
:(%=) => :(%),
:(&=) => :(&),
:(|=) => :(|),
)
ifelsexpr(cond, lhs, rhs) = :($lhs = $ifelse($cond, $rhs, $(Expr(:isdefined, lhs)) ? $lhs : NaN))
function assignments(cond, expr, res, mod)
if expr isa LineNumberNode
push!(res, expr)
elseif !(expr isa Expr)
push!(res, :($ifelse($cond, $expr, NaN)))
elseif expr.head == :if || expr.head == :elseif
tcond = :($(expr.args[1]) & $cond)
assignments(tcond, expr.args[2], res, mod)
if length(expr.args) == 3
fcond = :($(expr.args[1]) & !($cond))
assignments(fcond, expr.args[3], res, mod)
end
elseif expr.head == :call && expr.args[1] == ifelse
tcond = :($(expr.args[2]) & $cond)
assignments(tcond, expr.args[3], res, mod)
if length(expr.args) == 4
fcond = :($(expr.args[2]) & !($cond))
assignments(fcond, expr.args[4], res, mod)
end
elseif expr.head == :block
for e in expr.args
assignments(cond, e, res, mod)
end
elseif expr.head == :(=)
lhs, rhs = expr.args
push!(res, ifelsexpr(cond, lhs, rhs))
elseif expr.head in keys(opmap)
lhs, rhs = expr.args
push!(res, ifelsexpr(cond, lhs, Expr(:call, opmap[expr.head], lhs , rhs)))
else
@warn("Only if and assignement supported: $expr")
push!(res, :(if$cond; $expr; end))
end
return res
end
function ssa_(expr, mod)
expr = macroexpand(mod, expr)
@assert expr.head == :if || expr.head == :elseif
res = Expr(:block)
cond = expr.args[1]
assignments(cond, expr.args[2], res.args, mod)
if length(expr.args) == 3
assignments(:(!($cond)), expr.args[3], res.args, mod)
end
res
end
macro ssa(expr)
esc(ssa_(expr, __module__))
end |
Yeah it's interesting but it doesn't solve this because the tracing still requires that the code is hitting dispatchable ifelse functions. Users would have to use this macro for our code to work. We would need to for example setup the abstract interpreter to do this transform before dispatching, or write a more complex tracer which @MasonProtter looked into before. Otherwise it indeed requires user intervention. That said, this macro is a nice thing to help users do that manual intervention so if they find this issue, they should do it |
DAECompiler is an alternative approach that indeed uses custom interpreters to run Julia IR rather than tracing symbolics. The above macro was from an experiment to use JuliaSimCompiler. |
This would be a great feature. The documentation says |
maybe related to #38, not sure.
There are a collection of these type branches in my model (including nested). In MATLAB, the solver is able to handle this, but MTK currently cannot and
modelingtoolkitize
will fail.I started working on a macro but I didn't know how to handle the original case all that well. It handles the very most basic case but nothing more.
The text was updated successfully, but these errors were encountered: