[FileFormats.LP] support indicator constraints
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)
What is the original output of test.lp?
Our LP file format does not support indicator constraints, so it'll be getting reformulated somehow.
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
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.
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?
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)
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?
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.
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.
Yes, writing to a text file is a good idea. Thanks. Haha...yeah...