Skip to content

Commit

Permalink
Fix support for MOI.is_valid (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored Mar 7, 2024
1 parent e0e6f8c commit bbbd6d4
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 48 deletions.
87 changes: 76 additions & 11 deletions src/moi/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,45 @@ function MOI.add_constraint(
f::MOI.VariableIndex,
set::S,
) where {S<:Bounds{Float64}}
check_variable_indices(model, f)
variable_info = find_variable_info(model, f)
set_bounds(variable_info, set)
return MOI.ConstraintIndex{MOI.VariableIndex,S}(f.value)
end

function MOI.is_valid(
model::Optimizer,
ci::MOI.ConstraintIndex{MOI.VariableIndex,MOI.LessThan{Float64}},
)
if !MOI.is_valid(model, MOI.VariableIndex(ci.value))
return false
end
info = model.inner.variable_info[ci.value]
return info.upper_bound !== nothing && info.lower_bound != info.upper_bound
end

function MOI.is_valid(
model::Optimizer,
ci::MOI.ConstraintIndex{MOI.VariableIndex,MOI.GreaterThan{Float64}},
)
if !MOI.is_valid(model, MOI.VariableIndex(ci.value))
return false
end
info = model.inner.variable_info[ci.value]
return info.lower_bound !== nothing && info.lower_bound != info.upper_bound
end

function MOI.is_valid(
model::Optimizer,
ci::MOI.ConstraintIndex{MOI.VariableIndex,MOI.EqualTo{Float64}},
)
if !MOI.is_valid(model, MOI.VariableIndex(ci.value))
return false
end
info = model.inner.variable_info[ci.value]
return info.lower_bound !== nothing && info.lower_bound == info.upper_bound
end

function MOI.supports_constraint(
::Optimizer,
::Type{
Expand All @@ -60,6 +94,19 @@ function MOI.supports_constraint(
return true
end

function MOI.is_valid(
model::Optimizer,
ci::MOI.ConstraintIndex{F,<:Bounds{Float64}},
) where {
F<:Union{
MOI.ScalarAffineFunction{Float64},
MOI.ScalarQuadraticFunction{Float64},
MOI.ScalarNonlinearFunction,
},
}
return 1 <= ci.value <= length(model.inner.constraint_info)
end

function MOI.add_constraint(
model::Optimizer,
f::F,
Expand Down Expand Up @@ -107,6 +154,23 @@ function MOI.supports_constraint(
return true
end

function MOI.is_valid(
model::Optimizer,
ci::MOI.ConstraintIndex{MOI.VariableIndex,MOI.ZeroOne},
)
return MOI.is_valid(model, MOI.VariableIndex(ci.value)) &&
model.inner.variable_info[ci.value].category == :Bin
end

function MOI.add_constraint(
model::Optimizer,
f::MOI.VariableIndex,
::MOI.ZeroOne,
)
find_variable_info(model, f).category = :Bin
return MOI.ConstraintIndex{MOI.VariableIndex,MOI.ZeroOne}(f.value)
end

function MOI.supports_constraint(
::Optimizer,
::Type{MOI.VariableIndex},
Expand All @@ -115,20 +179,21 @@ function MOI.supports_constraint(
return true
end

function MOI.is_valid(
model::Optimizer,
ci::MOI.ConstraintIndex{MOI.VariableIndex,MOI.Integer},
)
return MOI.is_valid(model, MOI.VariableIndex(ci.value)) &&
model.inner.variable_info[ci.value].category == :Int
end

function MOI.add_constraint(
model::Optimizer,
f::MOI.VariableIndex,
set::S,
) where {S<:Union{MOI.ZeroOne,MOI.Integer}}
variable_info = find_variable_info(model, f)
if set isa MOI.ZeroOne
variable_info.category = :Bin
elseif set isa MOI.Integer
variable_info.category = :Int
else
error("Unsupported variable type $set.")
end
return MOI.ConstraintIndex{MOI.VariableIndex,S}(f.value)
::MOI.Integer,
)
find_variable_info(model, f).category = :Int
return MOI.ConstraintIndex{MOI.VariableIndex,MOI.Integer}(f.value)
end

# MOI.supports(::Optimizer, ::MOI.NLPBlock) = true
Expand Down
39 changes: 2 additions & 37 deletions src/moi/variables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,8 @@ function MOI.add_variable(model::Optimizer)
return MOI.VariableIndex(length(model.inner.variable_info))
end

function MOI.add_variables(model::Optimizer, nvars::Integer)
return [MOI.add_variable(model) for i in 1:nvars]
end

function MOI.add_constraint(
model::Optimizer,
vi::MOI.VariableIndex,
lt::MOI.LessThan{Float64},
)
check_variable_indices(model, vi)
set_upper_bound(model.inner.variable_info[vi.value], lt.upper)
return MOI.ConstraintIndex{MOI.VariableIndex,MOI.LessThan{Float64}}(
vi.value,
)
end

function MOI.add_constraint(
model::Optimizer,
vi::MOI.VariableIndex,
gt::MOI.GreaterThan{Float64},
)
check_variable_indices(model, vi)
set_lower_bound(model.inner.variable_info[vi.value], gt.lower)
return MOI.ConstraintIndex{MOI.VariableIndex,MOI.GreaterThan{Float64}}(
vi.value,
)
end

function MOI.add_constraint(
model::Optimizer,
vi::MOI.VariableIndex,
eq::MOI.EqualTo{Float64},
)
check_variable_indices(model, vi)
set_lower_bound(model.inner.variable_info[vi.value], eq.value)
set_upper_bound(model.inner.variable_info[vi.value], eq.value)
return MOI.ConstraintIndex{MOI.VariableIndex,MOI.EqualTo{Float64}}(vi.value)
function MOI.is_valid(model::Optimizer, x::MOI.VariableIndex)
return 1 <= x.value <= length(model.inner.variable_info)
end

# see comment in: write_bar_file
Expand Down
52 changes: 52 additions & 0 deletions test/moi_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,58 @@ function test_ListOfSupportedNonlinearOperators()
return
end

function test_is_valid()
model = BARON.Optimizer()
x = MOI.add_variables(model, 6)
@test all(MOI.is_valid.(model, x))
@test !MOI.is_valid(model, MOI.VariableIndex(-1))
sets = (
MOI.GreaterThan(0.0),
MOI.LessThan(0.0),
MOI.EqualTo(0.0),
MOI.Integer(),
MOI.ZeroOne(),
)
cis = Any[]
for (i, set) in enumerate(sets)
push!(cis, MOI.add_constraint(model, x[i], set))
end
for ci in cis
@test MOI.is_valid(model, ci)
@test !MOI.is_valid(model, typeof(ci)(-1))
@test !MOI.is_valid(model, typeof(ci)(x[6].value))
end
c_eq = MOI.add_constraint(model, 1.0 * x[1] + x[2], MOI.EqualTo(0.0))
@test MOI.is_valid(model, c_eq)
@test !MOI.is_valid(model, typeof(c_eq)(-1))
return
end

function test_bridge_indicator_to_milp()
model = MOI.instantiate(
BARON.Optimizer;
with_bridge_type = Float64,
with_cache_type = Float64,
)
MOI.set(model, MOI.Silent(), true)
x = MOI.add_variables(model, 2)
MOI.add_constraint.(model, x, MOI.GreaterThan(0.0))
MOI.add_constraint.(model, x, MOI.LessThan(2.0))
z = MOI.add_variable(model)
MOI.add_constraint(model, z, MOI.ZeroOne())
MOI.add_constraint(
model,
MOI.Utilities.operate(vcat, Float64, z, 1.0 * x[1] + 1.0 * x[2]),
MOI.Indicator{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(1.0)),
)
MOI.optimize!(model)
@test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMAL
x_val = MOI.get.(model, MOI.VariablePrimal(), x)
z_val = MOI.get(model, MOI.VariablePrimal(), z)
@test z_val < 0.5 || (sum(x_val) <= 1.0 + 1e-5)
return
end

end # module

MOITests.runtests()

0 comments on commit bbbd6d4

Please sign in to comment.