worlddynamics / Vensim2MTK.jl

A Julia package to import Vensim .xmile files as ModelingToolkit.jl models.
MIT License
2 stars 1 forks source link

Boolean operations #13

Closed meyde closed 1 year ago

meyde commented 1 year ago

ModelingToolkit does not support boolean operations, whereas Vensim does. this leads to some problem.

example of a failed code: @variables var_a @variables var_b @variables var_c

var_c ~ IfElse.ifelse(var_a > 0 && var_b <0,1,0)

this fails with "TypeError: non-boolean (Num) used in boolean expression"

one fix i tried is registering an "And" function:

And(a,b)= a && b @register symbolic And(a,b)

[...]

var_c ~ IfElse.ifelse(And(var_a>0,var_b<0),1,0)

this fails with MethodError: no method matching ifelse(::SymbolicUtils.BasicSymbolic{Real}, ::Float64, ::Float64)

meyde commented 1 year ago

bruteforce fix: just split the IfElse.ifelse into 2: IfElse.ifelse(var_a>0,IfElse.ifelse(var_b>0,1,0),0)

i still need to automatically do it for when i encounter a ":AND:" or an ":OR:", but that should not be too problematic.

natema commented 1 year ago

This issue doesn't ring a bell. I suggest that you proceed with the transfer of the repo in the WorldDynamics organization so that I'll ping the others to have a look.

natema commented 1 year ago

@aurorarossi @piluc @paulobruno does this ring any bell? Perhaps we encountered something similar before.

aurorarossi commented 1 year ago

Yes, I have encountered this problem, but I can't remember how I fixed it. I will look into it.

natema commented 1 year ago

I didn't reopen it since Mael did fix it in the way he explains, but we can compare with the solution we found back then.

aurorarossi commented 1 year ago

Ok, I found where it happens when implementing Earth4All.jl. It was in the function pulse, see the closed issue https://github.com/worlddynamics/Earth4All.jl/issues/5. Emanule's version works by using register, but in the end we used Pierluigi's version.

natema commented 1 year ago

Ok, so in principle one can replace IfElse.ifelse(var_a > 0 && var_b <0,1,0) with

f(x,y) = x > 0 && y < 0 ? 1 : 0
@register_symbolic f(x,y)

@meyde, in the OP, you mention something similar, but there you write @register symbolic And(a,b) without underscore. Maybe there was a typo?

meyde commented 1 year ago

this was a typo in the comment, the problem here was not the register symbolic syntax, but that i did not encapsulate the fucntion large enough; i just did the "&&", so in the ifelse function there was a mistake.

and while this works for the pulse function, i don't think it is really more efficient to automatise this for every "&&" and "||".

right now what i'm doing is after the parsing, i do a BFS looking for if_then_else functions (as it's only here we can have ":AND:" and ":OR:" instruction, and change the children nodes of the if_then_else accordingly, creating nested if_then_elses