Skip to content

Commit 0393088

Browse files
authored
[FileFormats.MPS] Fix to stop writing OBJSENSE by default (#1807)
1 parent 6b50fa0 commit 0393088

File tree

2 files changed

+85
-17
lines changed

2 files changed

+85
-17
lines changed

src/FileFormats/MPS/MPS.jl

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ end
4141

4242
struct Options
4343
warn::Bool
44+
objsense::Bool
4445
end
4546

46-
get_options(m::Model) = get(m.ext, :MPS_OPTIONS, Options(false))
47+
get_options(m::Model) = get(m.ext, :MPS_OPTIONS, Options(false, true))
4748

4849
"""
4950
Model(; kwargs...)
@@ -53,10 +54,11 @@ Create an empty instance of FileFormats.MPS.Model.
5354
Keyword arguments are:
5455
5556
- `warn::Bool=false`: print a warning when variables or constraints are renamed.
57+
- `print_objsense::Bool=false`: print the OBJSENSE section when writing
5658
"""
57-
function Model(; warn::Bool = false)
59+
function Model(; warn::Bool = false, print_objsense::Bool = false)
5860
model = Model{Float64}()
59-
model.ext[:MPS_OPTIONS] = Options(warn)
61+
model.ext[:MPS_OPTIONS] = Options(warn, print_objsense)
6062
return model
6163
end
6264

@@ -171,13 +173,18 @@ function Base.write(io::IO, model::Model)
171173
names[x] = n
172174
end
173175
write_model_name(io, model)
174-
if MOI.get(model, MOI.ObjectiveSense()) == MOI.MAX_SENSE
175-
println(io, "OBJSENSE MAX")
176+
flip_obj = false
177+
if options.objsense
178+
if MOI.get(model, MOI.ObjectiveSense()) == MOI.MAX_SENSE
179+
println(io, "OBJSENSE MAX")
180+
else
181+
println(io, "OBJSENSE MIN")
182+
end
176183
else
177-
println(io, "OBJSENSE MIN")
184+
flip_obj = MOI.get(model, MOI.ObjectiveSense()) == MOI.MAX_SENSE
178185
end
179186
write_rows(io, model)
180-
obj_const = write_columns(io, model, ordered_names, names)
187+
obj_const = write_columns(io, model, flip_obj, ordered_names, names)
181188
write_rhs(io, model, obj_const)
182189
write_ranges(io, model)
183190
write_bounds(io, model, ordered_names, names)
@@ -256,10 +263,12 @@ function _extract_terms(
256263
coefficients::Dict{String,Vector{Tuple{String,Float64}}},
257264
row_name::String,
258265
func::MOI.ScalarAffineFunction,
266+
flip_sign::Bool = false,
259267
)
260268
for term in func.terms
261269
variable_name = v_names[term.variable]
262-
push!(coefficients[variable_name], (row_name, term.coefficient))
270+
coef = flip_sign ? -term.coefficient : term.coefficient
271+
push!(coefficients[variable_name], (row_name, coef))
263272
end
264273
return
265274
end
@@ -281,7 +290,7 @@ function _collect_coefficients(
281290
return
282291
end
283292

284-
function write_columns(io::IO, model::Model, ordered_names, names)
293+
function write_columns(io::IO, model::Model, flip_obj, ordered_names, names)
285294
coefficients = Dict{String,Vector{Tuple{String,Float64}}}(
286295
n => Tuple{String,Float64}[] for n in ordered_names
287296
)
@@ -294,7 +303,7 @@ function write_columns(io::IO, model::Model, ordered_names, names)
294303
model,
295304
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
296305
)
297-
_extract_terms(names, coefficients, "OBJ", obj_func)
306+
_extract_terms(names, coefficients, "OBJ", obj_func, flip_obj)
298307
integer_variables = list_of_integer_variables(model, names)
299308
println(io, "COLUMNS")
300309
int_open = false

test/FileFormats/MPS/MPS.jl

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ const MOIU = MOI.Utilities
88
const MPS = MOI.FileFormats.MPS
99
const MPS_TEST_FILE = "test.mps"
1010

11-
function _test_model_equality(model_string, variables, constraints)
12-
model = MPS.Model()
11+
function _test_model_equality(model_string, variables, constraints; kwargs...)
12+
model = MPS.Model(; kwargs...)
1313
MOIU.loadfromstring!(model, model_string)
1414
MOI.write_to_file(model, MPS_TEST_FILE)
1515
model_2 = MPS.Model()
@@ -114,7 +114,18 @@ function test_maximization()
114114
MOI.set(model, MOI.VariableName(), x, "x")
115115
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
116116
MOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), x)
117-
@test sprint(MPS.write_columns, model, ["x"], Dict(x => "x")) ==
117+
@test sprint(MPS.write_columns, model, true, ["x"], Dict(x => "x")) ==
118+
"COLUMNS\n x OBJ -1\n"
119+
end
120+
121+
function test_maximization_objsense_false()
122+
model = MPS.Model(; print_objsense = true)
123+
x = MOI.add_variable(model)
124+
MOI.set(model, MOI.VariableName(), x, "x")
125+
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
126+
MOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), x)
127+
sprint(MPS.write, model)
128+
@test sprint(MPS.write_columns, model, false, ["x"], Dict(x => "x")) ==
118129
"COLUMNS\n x OBJ 1\n"
119130
end
120131

@@ -290,15 +301,27 @@ c1: 1.1 * x in Interval(1.0, 2.0)
290301
end
291302

292303
function test_objsense_max()
293-
return _test_model_equality(
304+
_test_model_equality(
294305
"""
295306
variables: x
296307
maxobjective: 1.2x
297308
c1: 1.0 * x >= 0.0
298309
""",
299310
["x"],
300311
["c1"],
312+
print_objsense = true,
313+
)
314+
_test_model_equality(
315+
"""
316+
variables: x
317+
minobjective: 1.2x
318+
c1: 1.0 * x >= 0.0
319+
""",
320+
["x"],
321+
["c1"],
322+
print_objsense = true,
301323
)
324+
return
302325
end
303326

304327
function test_MARKER_INT()
@@ -400,7 +423,6 @@ a_really_long_name <= 2.0
400423
MOI.write_to_file(model, MPS_TEST_FILE)
401424
@test read(MPS_TEST_FILE, String) ==
402425
"NAME \n" *
403-
"OBJSENSE MIN\n" *
404426
"ROWS\n" *
405427
" N OBJ\n" *
406428
"COLUMNS\n" *
@@ -446,7 +468,6 @@ function test_names_with_spaces()
446468
MOI.set(model, MOI.ConstraintName(), c, "c c")
447469
@test sprint(write, model) ==
448470
"NAME \n" *
449-
"OBJSENSE MIN\n" *
450471
"ROWS\n" *
451472
" N OBJ\n" *
452473
" E c_c\n" *
@@ -460,6 +481,45 @@ function test_names_with_spaces()
460481
"ENDATA\n"
461482
end
462483

484+
function test_objsense_default()
485+
model = MPS.Model()
486+
x = MOI.add_variable(model)
487+
MOI.set(model, MOI.VariableName(), x, "x")
488+
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
489+
MOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), x)
490+
@test sprint(write, model) ==
491+
"NAME \n" *
492+
"ROWS\n" *
493+
" N OBJ\n" *
494+
"COLUMNS\n" *
495+
" x OBJ -1\n" *
496+
"RHS\n" *
497+
"RANGES\n" *
498+
"BOUNDS\n" *
499+
" FR bounds x\n" *
500+
"ENDATA\n"
501+
end
502+
503+
function test_objsense_true()
504+
model = MPS.Model(; print_objsense = true)
505+
x = MOI.add_variable(model)
506+
MOI.set(model, MOI.VariableName(), x, "x")
507+
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
508+
MOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), x)
509+
@test sprint(write, model) ==
510+
"NAME \n" *
511+
"OBJSENSE MAX\n" *
512+
"ROWS\n" *
513+
" N OBJ\n" *
514+
"COLUMNS\n" *
515+
" x OBJ 1\n" *
516+
"RHS\n" *
517+
"RANGES\n" *
518+
"BOUNDS\n" *
519+
" FR bounds x\n" *
520+
"ENDATA\n"
521+
end
522+
463523
function test_sos_constraints()
464524
model = MPS.Model()
465525
x = MOI.add_variables(model, 3)
@@ -476,7 +536,6 @@ function test_sos_constraints()
476536
)
477537
@test sprint(write, model) ==
478538
"NAME \n" *
479-
"OBJSENSE MIN\n" *
480539
"ROWS\n" *
481540
" N OBJ\n" *
482541
"COLUMNS\n" *

0 commit comments

Comments
 (0)