Skip to content

Commit

Permalink
Fix TerminationStatus when SolutionLimit is 1 (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored Feb 8, 2024
1 parent 2cc387e commit 7161b6f
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 16 deletions.
29 changes: 19 additions & 10 deletions src/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ mutable struct Optimizer{T} <: MOI.AbstractOptimizer
solver = Chuffed()
end
primal_solutions = Dict{MOI.VariableIndex,T}[]
options = Dict{String,Any}("model_filename" => "", "num_solutions" => 1)
options =
Dict{String,Any}("model_filename" => "", "num_solutions" => nothing)
return new(
solver,
Model{T}(),
Expand Down Expand Up @@ -85,7 +86,7 @@ function _run_minizinc(dest::Optimizer)
limit = round(Int, 1_000 * dest.time_limit_sec::Float64)
cmd = `$cmd --time-limit $limit`
end
if dest.options["num_solutions"] > 1
if dest.options["num_solutions"] !== nothing
cmd = `$cmd --num-solutions $(dest.options["num_solutions"])`
end
return run(pipeline(cmd, stdout = _stdout, stderr = _stderr))
Expand Down Expand Up @@ -140,9 +141,9 @@ function MOI.get(model::Optimizer, attr::MOI.RawOptimizerAttribute)
end

function MOI.set(model::Optimizer, attr::MOI.RawOptimizerAttribute, value)
if attr.name == "num_solutions" && !(value isa Int && value >= 1)
msg = "value must be an `Int` that is >= 1"
throw(MOI.SetAttributeNotAllowed(attr, msg))
if attr.name == "num_solutions"
MOI.set(model, MOI.SolutionLimit(), value)
return
end
model.options[attr.name] = value
return
Expand All @@ -154,8 +155,16 @@ function MOI.get(model::Optimizer, ::MOI.SolutionLimit)
return MOI.get(model, MOI.RawOptimizerAttribute("num_solutions"))
end

function MOI.set(model::Optimizer, ::MOI.SolutionLimit, value)
MOI.set(model, MOI.RawOptimizerAttribute("num_solutions"), value)
function MOI.set(
model::Optimizer,
attr::MOI.SolutionLimit,
value::Union{Nothing,Integer},
)
if value isa Integer && value < 1
msg = "value must be an `Int` that is >= 1"
throw(MOI.SetAttributeNotAllowed(attr, msg))
end
model.options["num_solutions"] = value
return
end

Expand Down Expand Up @@ -251,11 +260,11 @@ function MOI.get(model::Optimizer, ::MOI.TerminationStatus)
if model.solver_status == "UNSATISFIABLE"
return MOI.INFEASIBLE
elseif _has_solution(model)
if 1 < model.options["num_solutions"] <= length(model.primal_solutions)
num_solutions = something(model.options["num_solutions"], 0)
if 1 <= num_solutions <= length(model.primal_solutions)
return MOI.SOLUTION_LIMIT
else
return MOI.OPTIMAL
end
return MOI.OPTIMAL
elseif model.solver_status == "UNKNOWN" &&
model.time_limit_sec !== nothing &&
model.solve_time_sec >= model.time_limit_sec
Expand Down
2 changes: 1 addition & 1 deletion test/examples/nqueens_solveall.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ end
function test_nqueens_solve_num_solutions_1()
model, q = _init_nqueens_solve_num_solutions()
MOI.set(model, MOI.SolutionLimit(), 1)
_test_nqueens_solve_num_solutions(model, q, 1)
_test_nqueens_solve_num_solutions(model, q, 1, MOI.SOLUTION_LIMIT)
return
end

Expand Down
14 changes: 9 additions & 5 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1081,17 +1081,21 @@ function test_moi_support_solution_limit()
MOI.supports(solver, MOI.SolutionLimit())
attr = MOI.RawOptimizerAttribute("num_solutions")
MOI.supports(solver, attr)

@test MOI.get(solver, MOI.SolutionLimit()) == 1
@test MOI.get(solver, attr) == 1

@test MOI.get(solver, MOI.SolutionLimit()) === nothing
@test MOI.get(solver, attr) === nothing
MOI.set(solver, MOI.SolutionLimit(), 100)
@test MOI.get(solver, attr) == 100
@test MOI.get(solver, MOI.SolutionLimit()) == 100

MOI.set(solver, attr, 100)
@test MOI.get(solver, attr) == 100
@test MOI.get(solver, MOI.SolutionLimit()) == 100
MOI.set(solver, MOI.SolutionLimit(), nothing)
@test_throws(
MOI.SetAttributeNotAllowed,
MOI.set(solver, MOI.SolutionLimit(), -1),
)
@test MOI.get(solver, MOI.SolutionLimit()) === nothing
@test MOI.get(solver, attr) === nothing
return
end

Expand Down

0 comments on commit 7161b6f

Please sign in to comment.