Skip to content

Commit 1cf8497

Browse files
authored
[FileFormats.LP] fix reading models with default bounds (#2121)
1 parent 065e1b0 commit 1cf8497

File tree

2 files changed

+79
-11
lines changed

2 files changed

+79
-11
lines changed

src/FileFormats/LP/LP.jl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -778,9 +778,6 @@ function _parse_section(
778778
if _is_less_than(tokens[2])
779779
# name <= bound
780780
ub = rhs
781-
# LP files have default lower bounds of 0, unless the upper
782-
# bound is less than 0.
783-
lb = ub > 0.0 ? 0.0 : -Inf
784781
elseif _is_greater_than(tokens[2])
785782
# name >= bound
786783
lb = rhs
@@ -800,9 +797,6 @@ function _parse_section(
800797
elseif _is_greater_than(tokens[2])
801798
# bound >= name
802799
ub = lhs
803-
# LP files have default lower bounds of 0, unless the upper
804-
# bound is less than 0.
805-
lb = ub > 0.0 ? 0.0 : -Inf
806800
elseif _is_equal_to(tokens[2])
807801
lb = ub = lhs
808802
else

test/FileFormats/LP/LP.jl

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,8 @@ function test_read_model1_tricky()
469469
@test occursin("Var4 >= 5.5", file)
470470
@test occursin("V3 >= -3", file)
471471
@test occursin("V5 = 1", file)
472-
@test occursin("0 <= V2 <= 3", file)
472+
@test occursin("V2 <= 3", file)
473+
@test occursin("V2 >= 0", file)
473474
@test occursin("0 <= V7 <= 1", file)
474475
@test occursin("0 <= V8 <= 1", file)
475476
@test occursin("V6 free", file)
@@ -717,15 +718,15 @@ end
717718
function test_wrong_way_bounds()
718719
for (case, result) in [
719720
"x >= 2" => "x >= 2",
720-
"x <= 2" => "0 <= x <= 2",
721+
"x <= 2" => "x <= 2\nx >= 0",
721722
"x == 2" => "x = 2",
722723
"x > 2" => "x >= 2",
723-
"x < 2" => "0 <= x <= 2",
724+
"x < 2" => "x <= 2\nx >= 0",
724725
"x = 2" => "x = 2",
725-
"2 >= x" => "0 <= x <= 2",
726+
"2 >= x" => "x <= 2\nx >= 0",
726727
"2 <= x" => "x >= 2",
727728
"2 == x" => "x = 2",
728-
"2 > x" => "0 <= x <= 2",
729+
"2 > x" => "x <= 2\nx >= 0",
729730
"2 < x" => "x >= 2",
730731
"2 = x" => "x = 2",
731732
]
@@ -758,6 +759,79 @@ function test_variable_coefficient_variable()
758759
return
759760
end
760761

762+
function _test_round_trip(bound, needle)
763+
model = MOI.FileFormats.LP.Model()
764+
io = IOBuffer()
765+
write(io, "Minimize\nobj: x\nBounds\n$bound\nEnd")
766+
seekstart(io)
767+
read!(io, model)
768+
seekstart(io)
769+
write(io, model)
770+
seekstart(io)
771+
file = read(io, String)
772+
@test occursin(needle, file)
773+
return
774+
end
775+
776+
function test_reading_bounds()
777+
# Test lower bound
778+
_test_round_trip("x >= 1", "Bounds\nx >= 1\nEnd")
779+
_test_round_trip("x >= 0", "Bounds\nx >= 0\nEnd")
780+
_test_round_trip("x >= -1", "Bounds\nx >= -1\nEnd")
781+
_test_round_trip("x > 1", "Bounds\nx >= 1\nEnd")
782+
_test_round_trip("x > 0", "Bounds\nx >= 0\nEnd")
783+
_test_round_trip("x > -1", "Bounds\nx >= -1\nEnd")
784+
# Test reversed lower bound
785+
_test_round_trip("1 <= x", "Bounds\nx >= 1\nEnd")
786+
_test_round_trip("0 <= x", "Bounds\nx >= 0\nEnd")
787+
_test_round_trip("-1 <= x", "Bounds\nx >= -1\nEnd")
788+
_test_round_trip("1 < x", "Bounds\nx >= 1\nEnd")
789+
_test_round_trip("0 < x", "Bounds\nx >= 0\nEnd")
790+
_test_round_trip("-1 < x", "Bounds\nx >= -1\nEnd")
791+
# Test upper bound
792+
_test_round_trip("x <= 1", "Bounds\nx <= 1\nx >= 0\nEnd")
793+
_test_round_trip("x <= 0", "Bounds\nx <= 0\nx >= 0\nEnd")
794+
_test_round_trip("x <= -1", "Bounds\nx <= -1\nEnd")
795+
_test_round_trip("x < 1", "Bounds\nx <= 1\nx >= 0\nEnd")
796+
_test_round_trip("x < 0", "Bounds\nx <= 0\nx >= 0\nEnd")
797+
_test_round_trip("x < -1", "Bounds\nx <= -1\nEnd")
798+
# Test reversed upper bound
799+
_test_round_trip("1 >= x", "Bounds\nx <= 1\nx >= 0\nEnd")
800+
_test_round_trip("0 >= x", "Bounds\nx <= 0\nx >= 0\nEnd")
801+
_test_round_trip("-1 >= x", "Bounds\nx <= -1\nEnd")
802+
_test_round_trip("1 > x", "Bounds\nx <= 1\nx >= 0\nEnd")
803+
_test_round_trip("0 > x", "Bounds\nx <= 0\nx >= 0\nEnd")
804+
_test_round_trip("-1 > x", "Bounds\nx <= -1\nEnd")
805+
# Test equality
806+
_test_round_trip("x == 1", "Bounds\nx = 1\nEnd")
807+
_test_round_trip("x == 0", "Bounds\nx = 0\nEnd")
808+
_test_round_trip("x == -1", "Bounds\nx = -1\nEnd")
809+
_test_round_trip("1 = x", "Bounds\nx = 1\nEnd")
810+
_test_round_trip("0 = x", "Bounds\nx = 0\nEnd")
811+
_test_round_trip("-1 = x", "Bounds\nx = -1\nEnd")
812+
# Test interval
813+
_test_round_trip("0 <= x <= 1", "Bounds\n0 <= x <= 1\nEnd")
814+
_test_round_trip("-1 <= x <= 1", "Bounds\n-1 <= x <= 1\nEnd")
815+
_test_round_trip("-2 <= x <= -1", "Bounds\n-2 <= x <= -1\nEnd")
816+
# Test reversed interval
817+
_test_round_trip("1 >= x >= 0", "Bounds\n0 <= x <= 1\nEnd")
818+
_test_round_trip("1 >= x >= -1", "Bounds\n-1 <= x <= 1\nEnd")
819+
_test_round_trip("-1 >= x >= -2", "Bounds\n-2 <= x <= -1\nEnd")
820+
# Test double-sided equality
821+
_test_round_trip("1 <= x <= 1", "Bounds\nx = 1\nEnd")
822+
_test_round_trip("0 <= x <= 0", "Bounds\nx = 0\nEnd")
823+
_test_round_trip("-2 <= x <= -2", "Bounds\nx = -2\nEnd")
824+
# Test upper then lower
825+
_test_round_trip("x <= 1\nx >= 0", "Bounds\nx <= 1\nx >= 0\nEnd")
826+
_test_round_trip("x <= 2\nx >= 1", "Bounds\nx <= 2\nx >= 1\nEnd")
827+
_test_round_trip("x <= 2\nx >= -1", "Bounds\nx <= 2\nx >= -1\nEnd")
828+
# Test lower then upper
829+
_test_round_trip("x >= 0\nx <= 1", "Bounds\nx <= 1\nx >= 0\nEnd")
830+
_test_round_trip("x >= 1\nx <= 2", "Bounds\nx <= 2\nx >= 1\nEnd")
831+
_test_round_trip("x >= -1\nx <= 2", "Bounds\nx <= 2\nx >= -1\nEnd")
832+
return
833+
end
834+
761835
function runtests()
762836
for name in names(@__MODULE__, all = true)
763837
if startswith("$(name)", "test_")

0 commit comments

Comments
 (0)