MathOptInterface.jl icon indicating copy to clipboard operation
MathOptInterface.jl copied to clipboard

[FileFormats.LP] support indicator constraints

Open hdavid16 opened this issue 2 years ago • 9 comments

The following works:

julia> model=Model();
julia> @variable(model,x);
julia> @variable(model,y,Bin);
julia> @constraint(model, y => {x == 0});
julia> write_to_file(model,"test.lp")

However if the indicator constraint is changed to @constraint(model, !y => {x == 0}), writing the LP file fails:

ERROR: Unable to use IndicatorToMILPBridge because element 2 in the function has a non-finite domain: 0.0 + 1.0 MOI.VariableIndex(2)

hdavid16 avatar Dec 04 '23 19:12 hdavid16

What is the original output of test.lp?

Our LP file format does not support indicator constraints, so it'll be getting reformulated somehow.

odow avatar Dec 04 '23 23:12 odow

shell> cat test.lp
minimize
obj: 
subject to
c1: 1 x + 1 x3 = 0
Bounds
x free
x3 free
Binary
y
SOS
c1_1: S1:: x3:0.4 y:0.6
End

odow avatar Dec 04 '23 23:12 odow

So this reformulates your indicator constraint as an SOS1 constraint. when you do the negation, it tries to instead reformulate as a big-M MIP, which it can't do because x is free.

We could improve the error message, but this seems like it is working as expected.

odow avatar Dec 04 '23 23:12 odow

It looks like CPLEX and Gurobi support indicators

https://www.ibm.com/docs/en/icos/22.1.0?topic=representation-mip-features-in-lp-file-format#d360454e288

[constraintname:] binaryvariable = value -> linear constraint

https://www.gurobi.com/documentation/11.0/refman/lp_format.html

c0: b1 = 1 -> 2.5 x + 2.3 y + 5.3 z <= 8.1

But I'm not in a rush to add support for this. Why is it useful?

odow avatar Dec 04 '23 23:12 odow

Using a SOS reformulation is fine. When the negation is used, it can be reformulated as:

minimize
obj: 
subject to
c1: 1 y + 1 x3 = 1
Bounds
x free
Binary
y
x3
SOS
c1_1: S1:: x3:0.4 x:0.6
End

It is useful when examining a model file since the .LP format is more understandable than an MOF file (wether that is supporting the indicator constraint directly or using a reformulation)

hdavid16 avatar Dec 05 '23 03:12 hdavid16

I get that we can reformulate the indicator constraint a different way. But the current bridge supports only ACTIVATE_ON_ONE: https://github.com/jump-dev/MathOptInterface.jl/blob/77d6b6fffc7cbc59dfa1696f1905a88162e34dc6/src/Bridges/Constraint/bridges/indicator_sos.jl#L7-L24 But this is unrelated to the file format issue.

It is useful when examining a model file since the .LP format is more understandable

But in this case the model you are examining is not the same as the model you wrote down.

It seems like you're really asking for tools to make MOF files more understandable.

But if you're looking for a readable output, then you could just print(model) instead?

odow avatar Dec 05 '23 04:12 odow

So to give some context, I have some .lp files for some models (made by someone else) that I am trying to implement myself (develop the general model so that it can be solved on different input datasets). When I develop my version of the model, I use JuMP to compare my model with the one in the .lp file and find the differences between the two. However, these models get big and thus print(model) is not helpful for inspection. However, saving my version of the model to an .lp file helps me dig into the differences because I can search for text in the file as I drill into some of the differences between my version of the model and the one in the external .lp file.

hdavid16 avatar Dec 05 '23 06:12 hdavid16

You can print to file:

open("model.txt") do io
    print(io, model)
end

But oh, reverse engineering a model from the LP file does not sound like fun.

odow avatar Dec 05 '23 17:12 odow

Yes, writing to a text file is a good idea. Thanks. Haha...yeah...

hdavid16 avatar Dec 05 '23 19:12 hdavid16