ModelingToolkit + IntervalConstraintProgramming: how to build expressions and contractors without "world age" problems or ambiguities

Hi,

I’m facing a problem of “world age” that my Julia experience doesn’t allow me to comprehend very well. Here is a MWE that uses the ModelingToolkit and IntervalConstraintProgramming packages:

using ModelingToolkit
using IntervalArithmetic
using IntervalConstraintProgramming

# dynamic reformulation of the expression by adding a slack
function add_slack(constraint_expression)
    new_variable = @variables s
    return (constraint_expression - s, new_variable[1])
end

# contract the box wrt the constraint
function contract(box, constraint_expression, variables)
    contractor = Contractor(variables, constraint_expression)
    box = contractor(0..0, box)
    return box
end


function constraint(x)
    return x[1]*x[2]
end

# create the original variables
variables = @variables x[1:2]
# flatten to an array
variables = vcat(variables...)

# add the slack
constraint_expression = constraint(x)
(constraint_expression, new_variable) = add_slack(constraint_expression)
# create the array [x1, x2, s]
append!(variables, new_variable)

# create a box and contract it wrt constraint
box = IntervalBox(0..1, 0..1, 0..1)
box = contract(box, constraint_expression, variables)

I define a problem, reformulate it somehow (here I add a slack variable, but I could add arbitrarily many variables), generate a contractor and call it.
I get this error:

ERROR: LoadError: MethodError: no method matching (::IntervalConstraintProgramming.var"#31#32")(::IntervalBox{3,Float64})
The applicable method may be too new: running in world age 27984, while current world is 27986.

Somehow my logic is not Julia-compliant :slight_smile: I must say that the scope of the ModelingToolkit variables eludes me.
Can you help me out? If possible, I’d like to keep the same structure (problem definition + reformulation + creation of contractor independently).
Thanks,

Charlie

Whatever is evaling in there, make it not use eval and instead use Runtime generated functions.

As Chris suggests, the problem is that Contractor is using eval to evaluate an expression, but then you are immediately calling contractor within the same function.

To avoid the world-age problem you need to return to the “top level” before using a function created by eval. Maybe we should indeed be using RuntimeGeneratedFunctions instead of eval.

1 Like

You should :wink:

1 Like

Thanks for your answers! I tried something like this:

using ModelingToolkit
using IntervalArithmetic
using IntervalConstraintProgramming

function add_slack(constraint_expression)
    new_variable = @variables s
    return (constraint_expression - s, new_variable[1])
end

function create_contractor(variables, constraint_expression)
    return Contractor(variables, constraint_expression)
end

function constraint(x)
    return x[1]*x[2]
end

function main()
    # create the original variables
    variables = @variables x[1:2]
    # flatten to an array
    variables = vcat(variables...)

    # add the slack
    constraint_expression = constraint(x)
    (constraint_expression, new_variable) = add_slack(constraint_expression)
    # create the array [x1, x2, s]
    append!(variables, new_variable)

    # create a box and contract it wrt constraint
    box = IntervalBox(0..1, 0..1, 0..1)
    contractor = create_contractor(variables, constraint_expression)
    box = contractor(0..0, box)
    println(box)
    return box
end

main()

with the same result. What happens is absolutely not intuitive for me. The Contractor is now created and called in 2 different functions :thinking:

That’s still the same world age. You want to call contractor via Base.invokelatest(contractor, 0..0, box), but note that this will infer to Any and have some overhead.

Or just don’t put it in a main function.

But @dpsanders knows what’s up and this’ll presumably get fixed in the package soon.

2 Likes

You’re still inside the main() function. You don’t get back to top level (global scope).

Got it this time :slight_smile: Thanks a lot!

1 Like