Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding relative & absolute mip gaps #17

Merged
merged 13 commits into from
Nov 3, 2023
41 changes: 40 additions & 1 deletion src/SolverAPI.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ function response(
res["solve_time_sec"] = Float64(MOI.get(model, MOI.SolveTimeSec()))

result_count = MOI.get(model, MOI.ResultCount())

try
res["relative_gap"] = Float64(MOI.get(model, MOI.RelativeGap()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes a little more sense to do

rel_gap = Float64(MOI.get(model, MOI.RelativeGap()))

and then only set res["relative_gap"] if it's finite.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks. good point

if isinf(res["relative_gap"])
res["relative_gap"] = nothing # Inf cannot be serialized to JSON
end
catch
# ignore if solver does not support relative gap
end

results = [Dict{String,Any}() for _ in 1:result_count]
var_names = [string('\"', v, '\"') for v in json.variables]
var_idxs = MOI.get(model, MOI.ListOfVariableIndices())
Expand Down Expand Up @@ -398,8 +408,37 @@ function set_options!(model::MOI.ModelLike, options::JSON3.Object)#::Nothing
MOI.set(model, MOI.TimeLimitSec(), Float64(get(options, :time_limit_sec, 300.0)))
end

if MOI.supports(model, MOI.RelativeGapTolerance()) &&
haskey(options, :relative_gap_tolerance)
# Set relative gap tolerance
rel_gap_tol = Float64(options[:relative_gap_tolerance])
if rel_gap_tol < 0 || rel_gap_tol > 1
throw(Error(NotAllowed, "Relative gap tolerance must be within [0,1]."))
end

MOI.set(model, MOI.RelativeGapTolerance(), rel_gap_tol)
end

if MOI.supports(model, MOI.AbsoluteGapTolerance()) &&
haskey(options, :absolute_gap_tolerance)
# Set absolute gap tolerance
abs_gap_tol = Float64(options[:absolute_gap_tolerance])
if abs_gap_tol < 0
throw(Error(NotAllowed, "Absolute gap tolerance must be non-negative."))
end

MOI.set(model, MOI.AbsoluteGapTolerance(), abs_gap_tol)
end

for (key, val) in options
if key in [:solver, :print_format, :print_only, :time_limit_sec]
if key in [
:solver,
:print_format,
:print_only,
:time_limit_sec,
:relative_gap_tolerance,
:absolute_gap_tolerance,
]
# Skip - these are handled elsewhere.
continue
elseif key == :silent
Expand Down
6 changes: 6 additions & 0 deletions test/all_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ end
# solve and check output is expected for each input json file
@testset "$j" for j in json_names
output = JSON3.read(run_solve(read_json("inputs", j)))
@info output
#isdefined(Main, :Infiltrator) && Main.infiltrate(@__MODULE__, Base.@locals, @__FILE__, @__LINE__)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and the @info

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh my goodness. thought i 've removed them. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@test output.solver_version isa String
@test output.solve_time_sec isa Float64
expect = JSON3.read(read_json("outputs", j))
Expand Down Expand Up @@ -122,6 +124,10 @@ end
("feas_with_obj", "InvalidFormat"),
# no objective function specified for a minimization problem
("min_no_obj", "InvalidFormat"),
# absolute_gap_tolerance out of range, e.g., -0.1
("abs_gap_out_of_range", "NotAllowed"),
# relative_gap_tolerance must be within [0,1]
("rel_gap_out_of_range", "NotAllowed"),
# unsupported sense such as 'feasibility'
("unsupported_sense", "InvalidFormat"),
# range: wrong number of args
Expand Down
1 change: 1 addition & 0 deletions test/inputs/abs_gap_out_of_range.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"0.1","sense":"min","variables":["x","y"],"constraints":[["and",["==",["+","x",["*",3,"y"]],1],[">=",["+","x","y"],1]],["and",["Int","x"],["Nonneg","x"]],["Int","y"]],"objectives":[["+",["*",2,"x"],"y"]],"options":{"solver":"HIGHS", "absolute_gap_tolerance":-0.1}}
1 change: 1 addition & 0 deletions test/inputs/rel_gap_out_of_range.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"0.1","sense":"min","variables":["x","y"],"constraints":[["and",["==",["+","x",["*",3,"y"]],1],[">=",["+","x","y"],1]],["and",["Int","x"],["Nonneg","x"]],["Int","y"]],"objectives":[["+",["*",2,"x"],"y"]],"options":{"solver":"HIGHS", "relative_gap_tolerance":1.1}}
Loading