Skip to content
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
5 changes: 5 additions & 0 deletions docs/src/reference/standard_form.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,14 @@ Complements
```@docs
AllDifferent
Among
BinPacking
CountAtLeast
CountDistinct
CountGreaterThan
Circuit
Cumulative
Path
Table
```

## Matrix sets
Expand Down
16 changes: 16 additions & 0 deletions src/Test/test_basic_constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,17 @@ _set(::Type{MOI.CountDistinct}) = MOI.CountDistinct(4)
_set(::Type{MOI.Among}) = MOI.Among(4, Set([3, 4]))
_set(::Type{MOI.CountAtLeast}) = MOI.CountAtLeast(1, [2, 2], Set([3]))
_set(::Type{MOI.CountGreaterThan}) = MOI.CountGreaterThan(5)
_set(::Type{MOI.Circuit}) = MOI.Circuit(3)
_set(::Type{MOI.Cumulative}) = MOI.Cumulative(7)
_set(::Type{MOI.Path}) = MOI.Path([1, 1, 2, 2, 3], [2, 3, 3, 4, 4])

function _set(::Type{T}, ::Type{MOI.BinPacking}) where {T}
return MOI.BinPacking(T(2), T[1, 2])
end

function _set(::Type{T}, ::Type{MOI.Table}) where {T}
return MOI.Table(T[0 1 1; 1 0 1; 1 1 0])
end

function _set(
::Type{MOI.Indicator{MOI.ACTIVATE_ON_ONE,MOI.LessThan{T}}},
Expand Down Expand Up @@ -282,6 +293,11 @@ for s in [
:Among,
:CountAtLeast,
:CountGreaterThan,
:BinPacking,
:Circuit,
:Cumulative,
:Table,
:Path,
]
S = getfield(MOI, s)
functions = if S <: MOI.AbstractScalarSet
Expand Down
237 changes: 237 additions & 0 deletions src/Test/test_cpsat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,240 @@ function setup_test(
)
return
end

"""
test_cpsat_BinPacking(model::MOI.ModelLike, config::Config)

Add a VectorOfVariables-in-BinPacking constraint.
"""
function test_cpsat_BinPacking(
model::MOI.ModelLike,
config::Config{T},
) where {T}
@requires MOI.supports_constraint(
model,
MOI.VectorOfVariables,
MOI.BinPacking{T},
)
@requires MOI.supports_add_constrained_variable(model, MOI.Integer)
@requires _supports(config, MOI.optimize!)
x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:2]
MOI.add_constraint(
model,
MOI.VectorOfVariables(x),
MOI.BinPacking(T(2), T[1, 2]),
)
MOI.optimize!(model)
x_val = round.(Int, MOI.get.(model, MOI.VariablePrimal(), x))
@test 1 * x_val[1] + 2 * x_val[2] <= T(2)
return
end

function setup_test(
::typeof(test_cpsat_BinPacking),
model::MOIU.MockOptimizer,
::Config{T},
) where {T}
MOIU.set_mock_optimize!(
model,
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(
mock,
MOI.OPTIMAL,
(MOI.FEASIBLE_POINT, T[2, 0]),
),
)
return
end

"""
test_cpsat_Cumulative(model::MOI.ModelLike, config::Config)

Add a VectorOfVariables-in-Cumulative constraint.
"""
function test_cpsat_Cumulative(
model::MOI.ModelLike,
config::Config{T},
) where {T}
@requires MOI.supports_constraint(
model,
MOI.VectorOfVariables,
MOI.Cumulative,
)
@requires MOI.supports_add_constrained_variable(model, MOI.Integer)
@requires _supports(config, MOI.optimize!)
s = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]
d = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]
r = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]
b, _ = MOI.add_constrained_variable(model, MOI.Integer())
MOI.add_constraint(
model,
MOI.VectorOfVariables([s; d; r; b]),
MOI.Cumulative(10),
)
MOI.optimize!(model)
s_val = round.(Int, MOI.get.(model, MOI.VariablePrimal(), s))
d_val = round.(Int, MOI.get.(model, MOI.VariablePrimal(), d))
r_val = round.(Int, MOI.get.(model, MOI.VariablePrimal(), r))
b_val = round(Int, MOI.get(model, MOI.VariablePrimal(), b))
times = zeros(1 + maximum(s_val) + maximum(d_val))
for i in 1:3
for j in 0:(d_val[i]-1)
t = s_val[i] + j
times[t+1] += r_val[i]
end
end
@test all(times .<= b_val)
return
end

function setup_test(
::typeof(test_cpsat_Cumulative),
model::MOIU.MockOptimizer,
::Config{T},
) where {T}
MOIU.set_mock_optimize!(
model,
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(
mock,
MOI.OPTIMAL,
(MOI.FEASIBLE_POINT, T[0, 1, 2, 2, 2, 2, 3, 2, 1, 5]),
),
)
return
end

"""
test_cpsat_Table(model::MOI.ModelLike, config::Config)

Add a VectorOfVariables-in-Table constraint.
"""
function test_cpsat_Table(model::MOI.ModelLike, config::Config{T}) where {T}
@requires MOI.supports_constraint(
model,
MOI.VectorOfVariables,
MOI.Table{T},
)
@requires MOI.supports_add_constrained_variable(model, MOI.Integer)
@requires _supports(config, MOI.optimize!)
x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]
table = T[1 1 0; 0 1 1]
MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Table(table))
MOI.optimize!(model)
x_val = round.(Int, MOI.get.(model, MOI.VariablePrimal(), x))
@test x_val == [1, 1, 0] || x_val == [0, 1, 1]
return
end

function setup_test(
::typeof(test_cpsat_Table),
model::MOIU.MockOptimizer,
::Config{T},
) where {T}
MOIU.set_mock_optimize!(
model,
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(
mock,
MOI.OPTIMAL,
(MOI.FEASIBLE_POINT, T[1, 1, 0]),
),
)
return
end

"""
test_cpsat_Circuit(model::MOI.ModelLike, config::Config)

Add a VectorOfVariables-in-Circuit constraint.
"""
function test_cpsat_Circuit(model::MOI.ModelLike, config::Config{T}) where {T}
@requires MOI.supports_constraint(model, MOI.VectorOfVariables, MOI.Circuit)
@requires MOI.supports_add_constrained_variable(model, MOI.Integer)
@requires _supports(config, MOI.optimize!)
x = [MOI.add_constrained_variable(model, MOI.Integer())[1] for _ in 1:3]
MOI.add_constraint(model, MOI.VectorOfVariables(x), MOI.Circuit(3))
MOI.optimize!(model)
x_val = round.(Int, MOI.get.(model, MOI.VariablePrimal(), x))
@test x_val == [3, 1, 2] || x_val == [2, 3, 1]
return
end

function setup_test(
::typeof(test_cpsat_Circuit),
model::MOIU.MockOptimizer,
::Config{T},
) where {T}
MOIU.set_mock_optimize!(
model,
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(
mock,
MOI.OPTIMAL,
(MOI.FEASIBLE_POINT, T[3, 1, 2]),
),
)
return
end

"""
test_cpsat_Path(model::MOI.ModelLike, config::Config)

Add a VectorOfVariables-in-Path constraint.
"""
function test_cpsat_Path(model::MOI.ModelLike, config::Config{T}) where {T}
@requires MOI.supports_constraint(model, MOI.VectorOfVariables, MOI.Path)
@requires MOI.supports_add_constrained_variable(model, MOI.Integer)
@requires _supports(config, MOI.optimize!)
from = [1, 1, 2, 2, 3]
to = [2, 3, 3, 4, 4]
s, _ = MOI.add_constrained_variable(model, MOI.Integer())
t, _ = MOI.add_constrained_variable(model, MOI.Integer())
ns = MOI.add_variables(model, N)
MOI.add_constraint.(model, ns, MOI.ZeroOne())
es = MOI.add_variables(model, E)
MOI.add_constraint.(model, es, MOI.ZeroOne())
MOI.add_constraint(
model,
MOI.VectorOfVariables([s; t; ns; es]),
MOI.Path(from, to),
)
MOI.optimize!(model)
s_val = round(Int, MOI.get(model, MOI.VariablePrimal(), s))
@test 1 <= s_val <= 4
t_val = round(Int, MOI.get(model, MOI.VariablePrimal(), t))
@test 1 <= t_val <= 4
ns_val = round.(Int, MOI.get.(model, MOI.VariablePrimal(), ns))
es_val = round.(Int, MOI.get.(model, MOI.VariablePrimal(), es))
outs = Vector{Int}[[1, 2], [3, 4], [5], Int[]]
ins = Vector{Int}[[], [1], [2], [3, 4]]
has_edges = s_val == t_val ? 0 : 1
# source: must have no incoming and one outgoing (if s != t)
@test sum(es_val[o] for o in ins[s_val]; init = 0) == 0
@test sum(es_val[o] for o in outs[s_val]; init = 0) == has_edges
# dest: must have no outgoing and one incoming (if s != t)
@test sum(es_val[o] for o in ins[t_val]; init = 0) == has_edges
@test sum(es_val[o] for o in outs[t_val]; init = 0) == 0
for i in 1:4
if i != s_val && i != t_val
# other nodes: must have one incoming and one outgoing iff node is
# in subgraph.
@test sum(es_val[o] for o in outs[i]; init = 0) == ns_val[i]
@test sum(es_val[o] for o in ins[i]; init = 0) == ns_val[i]
end
end
return
end

function setup_test(
::typeof(test_cpsat_Path),
model::MOIU.MockOptimizer,
::Config{T},
) where {T}
MOIU.set_mock_optimize!(
model,
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(
mock,
MOI.OPTIMAL,
(MOI.FEASIBLE_POINT, T[1, 4, 1, 1, 0, 1, 1, 0, 0, 1, 0]),
),
)
return
end
5 changes: 5 additions & 0 deletions src/Utilities/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,9 @@ const LessThanIndicatorZero{T} =
MOI.Among,
MOI.CountAtLeast,
MOI.CountGreaterThan,
MOI.Circuit,
MOI.Cumulative,
MOI.Path,
),
(
MOI.PowerCone,
Expand All @@ -800,6 +803,8 @@ const LessThanIndicatorZero{T} =
MOI.SOS2,
LessThanIndicatorOne,
LessThanIndicatorZero,
MOI.Table,
MOI.BinPacking,
),
(),
(MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction),
Expand Down
Loading