Skip to content

Commit

Permalink
[FileFormats.MPS] fix MAX_SENSE with quadratic objective
Browse files Browse the repository at this point in the history
  • Loading branch information
odow committed Aug 29, 2024
1 parent cb1ad41 commit 5fdfd4a
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 12 deletions.
20 changes: 10 additions & 10 deletions src/FileFormats/MPS/MPS.jl
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ function Base.write(io::IO, model::Model)
write_rhs(io, model, obj_const)
write_ranges(io, model)
write_bounds(io, model, var_to_column)
write_quadobj(io, model, var_to_column)
write_quadobj(io, model, flip_obj, var_to_column)
if options.quadratic_format != kQuadraticFormatCPLEX
# Gurobi needs qcons _after_ quadobj and _before_ SOS.
write_quadcons(io, model, var_to_column)
Expand Down Expand Up @@ -805,7 +805,7 @@ end
# QUADRATIC OBJECTIVE
# ==============================================================================

function write_quadobj(io::IO, model::Model, var_to_column)
function write_quadobj(io::IO, model::Model, flip_obj::Bool, var_to_column)
f = _get_objective(model)
if isempty(f.quadratic_terms)
return
Expand All @@ -822,6 +822,7 @@ function write_quadobj(io::IO, model::Model, var_to_column)
_write_q_matrix(
io,
model,
flip_obj,
f,
var_to_column;
duplicate_off_diagonal = options.quadratic_format ==
Expand All @@ -833,6 +834,7 @@ end
function _write_q_matrix(
io::IO,
model::Model,
flip_obj::Bool,
f,
var_to_column;
duplicate_off_diagonal::Bool,
Expand Down Expand Up @@ -861,15 +863,13 @@ function _write_q_matrix(
)
x_name = _var_name(model, x, var_to_column[x], options.generic_names)
y_name = _var_name(model, y, var_to_column[y], options.generic_names)
println(
io,
Card(f2 = x_name, f3 = y_name, f4 = _to_string(terms[(x, y)])),
)
coef = terms[(x, y)]
if flip_obj
coef *= -1

Check warning on line 868 in src/FileFormats/MPS/MPS.jl

View check run for this annotation

Codecov / codecov/patch

src/FileFormats/MPS/MPS.jl#L866-L868

Added lines #L866 - L868 were not covered by tests
end
println(io, Card(f2 = x_name, f3 = y_name, f4 = _to_string(coef)))

Check warning on line 870 in src/FileFormats/MPS/MPS.jl

View check run for this annotation

Codecov / codecov/patch

src/FileFormats/MPS/MPS.jl#L870

Added line #L870 was not covered by tests
if x != y && duplicate_off_diagonal
println(
io,
Card(f2 = y_name, f3 = x_name, f4 = _to_string(terms[(x, y)])),
)
println(io, Card(f2 = y_name, f3 = x_name, f4 = _to_string(coef)))

Check warning on line 872 in src/FileFormats/MPS/MPS.jl

View check run for this annotation

Codecov / codecov/patch

src/FileFormats/MPS/MPS.jl#L872

Added line #L872 was not covered by tests
end
end
return
Expand Down
24 changes: 22 additions & 2 deletions test/FileFormats/MPS/MPS.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ module TestMPS
using Test

import MathOptInterface as MOI
import MathOptInterface.FileFormats: MPS
import DataStructures: OrderedDict

const MPS = MOI.FileFormats.MPS

function runtests()
for name in names(@__MODULE__; all = true)
if startswith("$(name)", "test_")
Expand Down Expand Up @@ -1249,6 +1248,27 @@ function test_binary_with_infeasible_bounds()
return
end

function test_issue_2538()
model = MPS.Model()
x = MOI.add_variables(model, 2)
f = 1.0 * x[1] + 2.0 * x[2] + 3.0 * x[1] * x[2] + 4.0 * x[2] * x[2]
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
MOI.set(model, MOI.ObjectiveFunction{typeof(f)}(), f)
io = IOBuffer()
write(io, model)
model_2 = MPS.Model()
seekstart(io)
read!(io, model_2)
MOI.get(model_2, MOI.ObjectiveSense()) == MOI.MIN_SENSE
y = MOI.get(model_2, MOI.ListOfVariableIndices())
g = MOI.get(model_2, MOI.ObjectiveFunction{typeof(f)}())
@test isapprox(
g,
-1.0 * y[1] - 2.0 * y[2] - 3.0 * y[1] * y[2] - 4.0 * y[2] * y[2],
)
return
end

end # TestMPS

TestMPS.runtests()

0 comments on commit 5fdfd4a

Please sign in to comment.