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

Fix failed MOI tests #434

Merged
merged 7 commits into from
Nov 13, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
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
65 changes: 39 additions & 26 deletions src/MOI_wrapper/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,9 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
# An enum to remember what objective is currently stored in the model.
objective_type::_ObjectiveType

# A flag to keep track of MOI.FEASIBILITY_SENSE, since Gurobi only stores
# MIN_SENSE or MAX_SENSE. This allows us to differentiate between MIN_SENSE
# and FEASIBILITY_SENSE.
is_feasibility::Bool
# track whether objective function is set and the state of objective sense
is_objective_set::Bool
objective_sense::Union{Nothing,MOI.OptimizationSense}

# A mapping from the MOI.VariableIndex to the Gurobi column. _VariableInfo
# also stores some additional fields like what bounds have been added, the
Expand Down Expand Up @@ -401,7 +400,8 @@ function MOI.empty!(model::Optimizer)
end
model.needs_update = false
model.objective_type = _SCALAR_AFFINE
model.is_feasibility = true
model.is_objective_set = false
model.objective_sense = nothing
empty!(model.variable_info)
model.next_column = 1
empty!(model.columns_deleted_since_last_update)
Expand All @@ -428,7 +428,8 @@ end
function MOI.is_empty(model::Optimizer)
model.needs_update && return false
model.objective_type != _SCALAR_AFFINE && return false
model.is_feasibility == false && return false
model.is_objective_set == true && return false
model.objective_sense !== nothing && return false
!isempty(model.variable_info) && return false
!isone(model.next_column) && return false
!isempty(model.columns_deleted_since_last_update) && return false
Expand Down Expand Up @@ -661,7 +662,13 @@ function MOI.get(model::Optimizer, ::MOI.ListOfVariableAttributesSet)
end

function MOI.get(model::Optimizer, ::MOI.ListOfModelAttributesSet)
attributes = Any[MOI.ObjectiveSense()]
if MOI.is_empty(model)
return Any[]
end
attributes = Any[]
if model.objective_sense !== nothing
push!(attributes, MOI.ObjectiveSense())
end
typ = MOI.get(model, MOI.ObjectiveFunctionType())
if typ !== nothing
odow marked this conversation as resolved.
Show resolved Hide resolved
push!(attributes, MOI.ObjectiveFunction{typ}())
Expand All @@ -672,8 +679,20 @@ function MOI.get(model::Optimizer, ::MOI.ListOfModelAttributesSet)
return attributes
end

function MOI.get(model::Optimizer, ::MOI.ListOfConstraintAttributesSet)
return MOI.AbstractConstraintAttribute[MOI.ConstraintName()]
function MOI.get(
model::Optimizer,
::MOI.ListOfConstraintAttributesSet{F,S},
) where {S,F}
ret = MOI.AbstractConstraintAttribute[]
constraint_indices = MOI.get(model, MOI.ListOfConstraintIndices{F,S}())
found_name = any(
!isempty(MOI.get(model, MOI.ConstraintName(), index)) for
index in constraint_indices
)
if found_name
push!(ret, MOI.ConstraintName())
end
return ret
end

function _indices_and_coefficients(
Expand Down Expand Up @@ -1010,34 +1029,25 @@ function MOI.set(
if sense == MOI.MIN_SENSE
ret = GRBsetintattr(model, "ModelSense", 1)
_check_ret(model, ret)
model.is_feasibility = false
elseif sense == MOI.MAX_SENSE
ret = GRBsetintattr(model, "ModelSense", -1)
_check_ret(model, ret)
model.is_feasibility = false
else
@assert sense == MOI.FEASIBILITY_SENSE
_zero_objective(model)
ret = GRBsetintattr(model, "ModelSense", 1)
_check_ret(model, ret)
model.is_feasibility = true
end
model.objective_sense = sense
_require_update(model)
return
end

function MOI.get(model::Optimizer, ::MOI.ObjectiveSense)
_update_if_necessary(model)
sense = Ref{Cint}()
ret = GRBgetintattr(model, "ModelSense", sense)
_check_ret(model, ret)
if model.is_feasibility
return MOI.FEASIBILITY_SENSE
elseif sense[] == -1
return MOI.MAX_SENSE
if model.objective_sense !== nothing
return model.objective_sense
else
@assert sense[] == 1
return MOI.MIN_SENSE
return MOI.FEASIBILITY_SENSE
end
end

Expand All @@ -1052,6 +1062,7 @@ function MOI.set(
convert(MOI.ScalarAffineFunction{Float64}, f),
)
model.objective_type = _SINGLE_VARIABLE
model.is_objective_set = true
return
end

Expand Down Expand Up @@ -1087,7 +1098,9 @@ function MOI.set(
ret = GRBsetdblattr(model, "ObjCon", f.constant)
_check_ret(model, ret)
_require_update(model)
return model.objective_type = _SCALAR_AFFINE
model.objective_type = _SCALAR_AFFINE
model.is_objective_set = true
return
end

function MOI.get(
Expand Down Expand Up @@ -1140,6 +1153,7 @@ function MOI.set(
_check_ret(model, ret)
_require_update(model)
model.objective_type = _SCALAR_QUADRATIC
model.is_objective_set = true
return
end

Expand Down Expand Up @@ -3409,9 +3423,7 @@ function MOI.get(model::Optimizer, ::MOI.ListOfConstraintTypesPresent)
end

function MOI.get(model::Optimizer, ::MOI.ObjectiveFunctionType)
if model.is_feasibility
return nothing
elseif model.objective_type == _SINGLE_VARIABLE
if model.objective_type == _SINGLE_VARIABLE
return MOI.VariableIndex
elseif model.objective_type == _SCALAR_AFFINE
return MOI.ScalarAffineFunction{Float64}
Expand Down Expand Up @@ -3450,6 +3462,7 @@ function MOI.modify(
chg.new_coefficient,
)
_check_ret(model, ret)
model.is_objective_set = true
_require_update(model)
return
end
Expand Down
5 changes: 2 additions & 3 deletions test/MOI/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,9 @@ function test_runtests()
MOI.Test.Config(atol = 1e-3, rtol = 1e-3),
exclude = String[
# TODO(odow): investigate errors
"test_objective_set_via_modify",
"test_model_ListOfConstraintAttributesSet",
# Gurobi Error 10015: Cannot compute IIS on a feasible model
# https://www.gurobi.com/documentation/9.5/refman/error_codes.html
"test_solve_conflict_feasible",
"test_objective_get_ObjectiveFunction_ScalarAffineFunction",
# SecondOrderCone does not return dual solutions. Tested below.
"_SecondOrderCone_",
"test_constraint_PrimalStart_DualStart_SecondOrderCone",
Expand Down