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

[MOI] Allow accessing multiple results #392

Merged
merged 2 commits into from
Feb 6, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Gurobi"
uuid = "2e9cd046-0924-5485-92f1-d5272153d98b"
repo = "https://github.com/jump-dev/Gurobi.jl"
version = "0.9.7"
version = "0.9.8"

[deps]
CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82"
Expand Down
45 changes: 36 additions & 9 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2533,17 +2533,34 @@ function _has_primal_ray(model::Optimizer)
return ret == 0
end

function MOI.get(model::Optimizer, attr::MOI.VariablePrimal, x::MOI.VariableIndex)
_throw_if_optimize_in_progress(model, attr)
MOI.check_result_index_bounds(model, attr)
key = model.has_unbounded_ray ? "UnbdRay" : "X"
function _get_dbl_attr_variable(
model::Optimizer, key::String, x::MOI.VariableIndex
)
col = Cint(column(model, x) - 1)
valueP = Ref{Cdouble}()
ret = GRBgetdblattrelement(model, key, col, valueP)
_check_ret(model, ret)
return valueP[]
end

function MOI.get(
model::Optimizer, attr::MOI.VariablePrimal, x::MOI.VariableIndex
)
_throw_if_optimize_in_progress(model, attr)
if model.has_unbounded_ray
return _get_dbl_attr_variable(model, "UnbdRay", x)
odow marked this conversation as resolved.
Show resolved Hide resolved
end
result_count = MOI.get(model, MOI.ResultCount())
odow marked this conversation as resolved.
Show resolved Hide resolved
if !(1 <= attr.N <= result_count)
throw(MOI.ResultIndexBoundsError(attr, result_count))
elseif attr.N == 1
return _get_dbl_attr_variable(model, "X", x)
else
MOI.set(model, MOI.RawParameter("SolutionNumber"), attr.N - 1)
odow marked this conversation as resolved.
Show resolved Hide resolved
return _get_dbl_attr_variable(model, "Xn", x)
end
end

function MOI.get(
model::Optimizer, attr::MOI.ConstraintPrimal,
c::MOI.ConstraintIndex{MOI.SingleVariable, <:Any}
Expand Down Expand Up @@ -2760,11 +2777,21 @@ end

function MOI.get(model::Optimizer, attr::MOI.ObjectiveValue)
_throw_if_optimize_in_progress(model, attr)
MOI.check_result_index_bounds(model, attr)
valueP = Ref{Cdouble}()
ret = GRBgetdblattr(model, "ObjVal", valueP)
_check_ret(model, ret)
return valueP[]
result_count = MOI.get(model, MOI.ResultCount())
odow marked this conversation as resolved.
Show resolved Hide resolved
if !(1 <= attr.result_index <= result_count)
throw(MOI.ResultIndexBoundsError(attr, result_count))
elseif attr.result_index == 1
valueP = Ref{Cdouble}()
ret = GRBgetdblattr(model, "ObjVal", valueP)
_check_ret(model, ret)
return valueP[]
else
MOI.set(model, MOI.RawParameter("SolutionNumber"), attr.result_index - 1)
valueP = Ref{Cdouble}()
ret = GRBgetdblattr(model, "PoolObjVal", valueP)
_check_ret(model, ret)
return valueP[]
end
end

function MOI.get(model::Optimizer, attr::MOI.ObjectiveBound)
Expand Down
54 changes: 53 additions & 1 deletion test/MOI/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ end
function test_Add_and_delete_sos_constraints()
model = Gurobi.Optimizer(GRB_ENV)
MOI.set(model, MOI.Silent(), true)
# SOS2 to model piecewise linear function
# SOS2 to model piecewise linear function
xp1 = [1.0, 2.0, 3.0]
yp1 = [3.0, 2.0, 3.0]
λ = MOI.add_variables(model, length(xp1))
Expand Down Expand Up @@ -1532,6 +1532,58 @@ function test_add_constrained_variables()
@test MOI.get(model, MOI.ConstraintSet(), ci) == set
end

function _is_binary(x; atol = 1e-6)
return isapprox(x, 0; atol = atol) || isapprox(x, 1; atol = atol)
end

function test_multiple_solutions()
model = Gurobi.Optimizer(GRB_ENV)
MOI.set(model, MOI.RawParameter("OutputFlag"), 0)
MOI.set(model, MOI.RawParameter("Cuts"), 0)
MOI.set(model, MOI.RawParameter("Presolve"), 0)
MOI.set(model, MOI.RawParameter("PreCrush"), 0)
MOI.set(model, MOI.RawParameter("Heuristics"), 0)
N = 30
x = MOI.add_variables(model, N)
MOI.add_constraints(model, MOI.SingleVariable.(x), MOI.ZeroOne())
MOI.set.(model, MOI.VariablePrimalStart(), x, 0.0)
Random.seed!(1)
item_weights, item_values = rand(N), rand(N)
MOI.add_constraint(
model,
MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(item_weights, x), 0.0),
MOI.LessThan(10.0)
)
MOI.set(
model,
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(item_values, x), 0.0)
)
MOI.set(model, MOI.ObjectiveSense(), MOI.MAX_SENSE)
MOI.optimize!(model)
RC = MOI.get(model, MOI.ResultCount())
@test RC > 1
for n in [0, RC + 1]
@test_throws(
MOI.ResultIndexBoundsError,
MOI.get(model, MOI.VariablePrimal(n), x),
)
@test_throws(
MOI.ResultIndexBoundsError,
MOI.get(model, MOI.ObjectiveValue(n)),
)
end
for n = 1:RC
xn = MOI.get(model, MOI.VariablePrimal(n), x)
@test all(_is_binary, xn)
@test isapprox(
MOI.get(model, MOI.ObjectiveValue(n)),
item_values' * xn,
atol=1e-6,
)
end
end

end

runtests(TestMOIWrapper)