Skip to content

Commit 207b153

Browse files
authored
[FileFormats.LP] fix reading off-diagonals of quadratic functions (#2182)
1 parent a189a89 commit 207b153

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

src/FileFormats/LP/LP.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -596,11 +596,12 @@ function _parse_function(
596596
push!(f.terms, term::MOI.ScalarAffineTerm{Float64})
597597
elseif term isa MOI.ScalarQuadraticTerm{Float64}
598598
push!(cache.quad_terms, term::MOI.ScalarQuadraticTerm{Float64})
599-
if tokens[offset-1] == "]"
599+
if tokens[offset-1] in ("]", "]/2")
600+
scale = tokens[offset-1] == "]/2" ? 0.5 : 1
600601
for (i, term) in enumerate(cache.quad_terms)
601602
x, y = term.variable_1, term.variable_2
602-
scale = (x == y ? 2 : 1) * term.coefficient
603-
cache.quad_terms[i] = MOI.ScalarQuadraticTerm(scale, x, y)
603+
coef = scale * (x == y ? 2 : 1) * term.coefficient
604+
cache.quad_terms[i] = MOI.ScalarQuadraticTerm(coef, x, y)
604605
end
605606
end
606607
else

test/FileFormats/LP/LP.jl

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ function test_read_model1_tricky()
459459
seekstart(io)
460460
file = read(io, String)
461461
@test occursin("maximize", file)
462-
@test occursin("obj: -1 Var4 + 1 V5 + [ 1 Var4 ^ 2 - 2.4 V5 * V1 ]/2", file)
462+
@test occursin("obj: -1 Var4 + 1 V5 + [ 1 Var4 ^ 2 - 1.2 V5 * V1 ]/2", file)
463463
@test occursin("CON3: 1 V3 <= 2.5", file)
464464
@test occursin("CON4: 1 V5 + 1 V6 + 1 V7 <= 1", file)
465465
@test occursin("CON1: 1 V1 >= 0", file)
@@ -632,8 +632,8 @@ function test_read_tricky_quadratic()
632632
@test occursin("minimize", file)
633633
@test occursin("obj: [ 2 x ^ 2 + 2 x * y ]/2", file)
634634
@test occursin("c1: [ 1 x ^ 2 - 1 x * y ] <= 0", file)
635-
@test occursin("c2: [ 0.5 x ^ 2 - 1 x * y ] <= 0", file)
636-
@test occursin("c3: [ 0.5 x ^ 2 - 1 x * y ] <= 0", file)
635+
@test occursin("c2: [ 0.5 x ^ 2 - 0.5 x * y ] <= 0", file)
636+
@test occursin("c3: [ 0.5 x ^ 2 - 0.5 x * y ] <= 0", file)
637637
@test occursin("x free", file)
638638
@test occursin("y free", file)
639639
return
@@ -832,6 +832,61 @@ function test_reading_bounds()
832832
return
833833
end
834834

835+
function _test_read_quadratic(input::String, output::String = input)
836+
io = IOBuffer()
837+
input_text = """
838+
minimize
839+
obj: $input
840+
subject to
841+
Bounds
842+
x >= 0
843+
y >= 0
844+
End
845+
"""
846+
write(io, input_text)
847+
model = MOI.FileFormats.LP.Model()
848+
seekstart(io)
849+
read!(io, model)
850+
out = IOBuffer()
851+
write(out, model)
852+
seekstart(out)
853+
output_text = """
854+
minimize
855+
obj: $output
856+
subject to
857+
Bounds
858+
x >= 0
859+
y >= 0
860+
End
861+
"""
862+
@test read(out, String) == output_text
863+
return
864+
end
865+
866+
function test_read_quadratic()
867+
_test_read_quadratic("1 x + 1 y + [ 1 x * y + 1 y ^ 2 ]/2")
868+
_test_read_quadratic("1 x + 1 y + [ 2 x * y + 1 y ^ 2 ]/2")
869+
_test_read_quadratic("1 x + 1 y + [ 1 x * y + 2 y ^ 2 ]/2")
870+
_test_read_quadratic("1 x + 1 y + [ 2 x * y + 2 y ^ 2 ]/2")
871+
_test_read_quadratic(
872+
"1 x + 1 y + [ 1 x * y + 1 y ^ 2 ]",
873+
"1 x + 1 y + [ 2 x * y + 2 y ^ 2 ]/2",
874+
)
875+
_test_read_quadratic(
876+
"1 x + 1 y + [ 2 x * y + 1 y ^ 2 ]",
877+
"1 x + 1 y + [ 4 x * y + 2 y ^ 2 ]/2",
878+
)
879+
_test_read_quadratic(
880+
"1 x + 1 y + [ 1 x * y + 2 y ^ 2 ]",
881+
"1 x + 1 y + [ 2 x * y + 4 y ^ 2 ]/2",
882+
)
883+
_test_read_quadratic(
884+
"1 x + 1 y + [ 2 x * y + 2 y ^ 2 ]",
885+
"1 x + 1 y + [ 4 x * y + 4 y ^ 2 ]/2",
886+
)
887+
return
888+
end
889+
835890
function runtests()
836891
for name in names(@__MODULE__, all = true)
837892
if startswith("$(name)", "test_")

0 commit comments

Comments
 (0)