JuMP fails to throw an ERROR on an expr-model mismatch

Sometimes I build incorrect expressions obliviously, but JuMP won’t throw an ERROR. Is this good?

import JuMP, Gurobi
model1 = JuMP.Model(Gurobi.Optimizer);
JuMP.@variable(model1, x1 >= 1);
JuMP.@objective(model1, Min, x1);
JuMP.optimize!(model1);

model2 = JuMP.Model(Gurobi.Optimizer);
JuMP.@variable(model2, x2);
JuMP.@objective(model2, Min, x2);

# I miswrote `model2` as `model1` here
expr_miswrote = JuMP.@expression(model1, JuMP.value(x1)x2)
# But I fail to receive a proper ERROR
# And it can work normally later on!
JuMP.@constraint(model2, expr_miswrote >= 2)
JuMP.optimize!(model2)
JuMP.assert_is_solved_and_feasible(model2; allow_local = false)
@assert JuMP.objective_value(model2) == 2

Two unusual things to note:

  1. JuMP.value(x1)x2 belongs to model2 indeed, but it can be associated to model1.
  2. At least by inspecting the code, expr_miswrote belongs to model1, but it can be inserted into a model2’s constraint.

This is expected behavior, even if it might look confusing.

Your expr_miswrote contains variables from model2. But you can “add” it as an expression to model1 because it never actually gets added to the objective or constraints of model1.

We allow it because you can actually add expressions of any type to a model.

julia> using JuMP

julia> model = Model();

julia> @expression(model, my_expr[i in 1:2], Dict(:foo => i))
2-element Vector{Dict{Symbol, Int64}}:
 Dict(:foo => 1)
 Dict(:foo => 2)

julia> model[:my_expr]
2-element Vector{Dict{Symbol, Int64}}:
 Dict(:foo => 1)
 Dict(:foo => 2)

You can use expr_miswrote in a constraint of model2 because that is perfectly legal: it contains only variables from model2.

This makes some sense as my_expr becomes one of the belongings of model.

But the arg model1 in this anonymous usage becomes pointless.
To build an anonymous expression, it suffices to write
expr = JuMP.@build_expression(JuMP.value(x1)x2)
resembling
con = JuMP.@build_constraint(expr <= 2), no?

To build an anonymous expression, it suffices to write

I assume you meant this as a potential feature request. Currently @build_expression doesn’t exist.

I don’t plan to make any changes to JuMP related to this issue. Yes, you can create expression in the “wrong” model, but changing this is a breaking change we won’t be doing. We also won’t be adding any new macros just to support anonymous expressions that are not affiliated with a model.

No, I just express my thoughts.

Maybe this can be improved in JuMP 2.0 or some version that permit breaking changes.

We have no plans to work on or release JuMP 2.0