Constraints.jl: Streamlining Constraint Definition and Integration in Julia
using Constraints
@info concept(:sum, [1, 2, 3, 4, 5]; op = ==, val=15)
@info concept(:sum, [1, 2, 3, 4, 5]; op = ==, val=2)
@info concept(:sum, [1, 2, 3, 4, 3]; op = ≤, val=15)
@info concept(:sum, [1, 2, 3, 4, 3]; op = ≤, val=3)
using Constraints
c = x -> Constraints.xcsp_sum(
list = x,
condition = (>, 4),
coeffs = [1,2,3,4]
)
@info c([1, 1, 1, 1])
@info c([0, 1, 0, 0])
using CBLS, JuMP
model = Model(CBLS.Optimizer)
@variable(model, 1≤X[1:5]≤5, Int)
@variable(model, 1≤Y[1:5]≤5, Int)
@constraint(model, X in Sum(; op = ==, val = 15))
@constraint(model, Y in Sum(; op = <=, val = 10))
JuMP.optimize!(model)
@info "Sum" value.(X) value.(Y)
# TODO: How to handle intention in JuMP/MOI
using Constraints
concept(:count, [1,1,1,2], vals = [1, 1, 1, 2], op = ==, val = 4) # true
concept(:count, [1,1,1,2], vals = [1, 1, 1, 2], op = ==, val = 5) # false
concept(:count, [2, 1, 4, 3]; vals=[1, 2, 3, 4], op=≥, val=2) # true
concept(:at_least, [1,1,1,2], vals = [1, 1, 1, 2], val = 4) # true
concept(:at_least, [1,1,1,2], vals = [1, 2], val = 4) # true
concept(:at_least, [1,1,1,2], vals = [1, 3], val = 4) # false
concept(:at_most, [1,1,1,2], vals = [1, 1, 1, 2], val = 4) # true
concept(:at_most, [1,1,1,2], vals = [2, 5, 3], val = 2) #true
concept(:at_most, [1,1,1,2], vals = [1, 1, 1, 3], val = 3) # true
concept(:exactly, [1,1,1,2], vals = [1, 3, 4, 2], val = 4) # true
concept(:exactly, [1,1,1,2], vals = [1, 1, 2, 3], val = 4) # true
concept(:exactly, [1,1,1,2], vals = [1, 1, 1, 3], val = 4) # false
using Constraints
c_count = x -> Constraints.xcsp_count(
list = x,
condition = (≥, 4),
values = [1, 2, 3]
)
@info c_count([1, 1, 1, 1, 5]) # true
@info c_count([0, 2, 3, 8]) # false
using CBLS, JuMP
model = Model(CBLS.Optimizer)
@variable(model, 1≤X[1:4]≤4, Int)
@variable(model, 1≤X_at_least[1:4]≤4, Int)
@variable(model, 1≤X_at_most[1:4]≤4, Int)
@variable(model, 1≤X_exactly[1:4]≤4, Int)
@constraint(model, X in Count(vals = [1, 2, 3, 4], op = ≥, val = 2))
@constraint(model, X_at_least in AtLeast(vals = [1, 2, 3, 4], val = 2))
@constraint(model, X_at_most in AtMost(vals = [1, 2], val = 1))
@constraint(model, X_exactly in Exactly(vals = [1, 2], val = 2))
JuMP.optimize!(model)
@info "Count" value.(X) value.(X_at_least) value.(X_at_most) value.(X_exactly)
# TODO: How to handle intention in JuMP/MOI
using Constraints
@info concept(:nvalues, [1, 2, 3, 4, 5]; op = ==, val = 5)
@info concept(:nvalues, [1, 2, 3, 4, 5]; op = ==, val = 2)
@info concept(:nvalues, [1, 2, 3, 4, 3]; op = <=, val = 5)
@info concept(:nvalues, [1, 2, 3, 4, 3]; op = <=, val = 3)
using Constraints
c = x -> Constraints.xcsp_nvalues(
list = x,
condition = (≥, 3),
except = [1,2,3,4]
)
@info c([1, 1, 1, 1])
@info c([9, 3, 6, 8])
using CBLS, JuMP
model = Model(CBLS.Optimizer)
@variable(model, 1≤X[1:5]≤5, Int)
@variable(model, 1≤Y[1:5]≤5, Int)
@variable(model, 1≤Z[1:5]≤5, Int)
@constraint(model, X in NValues(; op = ==, val = 5))
@constraint(model, Y in NValues(; op = ==, val = 2))
@constraint(model, Z in NValues(; op = <=, val = 5, vals = [1, 2]))
JuMP.optimize!(model)
@info "NValues" value.(X) value.(Y) value.(Z)
# TODO: How to handle intention in JuMP/MOI
using Constraints
# [v1, v2, v3], [v1, a1, a2; v2, b1, b2; v3, c1, c2] means v1 occurs between a1 and a2 times in the first array, similar for v2 and v3.
@info concept(:cardinality, [2, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
@info concept(:cardinality, [8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3], bool=false)
@info concept(:cardinality, [8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3], bool=true)
@info concept(:cardinality, [2, 5, 10, 10]; vals=[2 1; 5 1; 10 2])
@info concept(:cardinality_closed, [8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
@info concept(:cardinality_open, [8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
using Constraints
c = x -> Constraints.xcsp_cardinality(
list = x,
values = [1, 2],
occurs = [2 3; 1 5]
)
@info c([1, 2, 1, 2])
using CBLS, JuMP
model = Model(CBLS.Optimizer)
@variable(model, 1≤X[1:4]≤10, Int)
@variable(model, 1≤Y[1:4]≤10, Int)
@variable(model, 1≤Z[1:4]≤10, Int)
@constraint(model, X in Cardinality(; vals = [2 0 1; 5 1 3; 10 2 3]))
@constraint(model, Y in CardinalityOpen(; vals = [2 0 1; 5 1 3; 10 2 3]))
@constraint(model, Z in CardinalityClosed(; vals = [2 0 1; 5 1 3; 10 2 3]))
JuMP.optimize!(model)
@info "Cardinality" value.(X) value.(Y) value.(Z)
# TODO: How to handle intention in JuMP/MOI
Counting and Summing Constraints
Constraints.xcsp_sum Function
xcsp_sum(list, coeffs, condition)
Return true
if the sum of the variables in list
satisfies the given condition, false
otherwise.
Arguments
list::Vector{Int}
: list of values to check.coeffs::Vector{Int}
: list of coefficients to use.condition
: condition to satisfy.
Variants
:sum
: Global constraint ensuring that the sum of the variables inx
satisfies a given numerical condition.
concept(:sum, x; op===, pair_vars=ones(x), val)
concept(:sum)(x; op===, pair_vars=ones(x), val)
Examples
c = concept(:sum)
c([1, 2, 3, 4, 5]; op===, val=15)
c([1, 2, 3, 4, 5]; op===, val=2)
c([1, 2, 3, 4, 3]; op=≤, val=15)
c([1, 2, 3, 4, 3]; op=≤, val=3)
Constraints.xcsp_count Function
xcsp_count(list, values, condition)
Return true
if the number of occurrences of the values in values
in list
satisfies the given condition, false
otherwise.
Arguments
list::Vector{Int}
: list of values to check.values::Vector{Int}
: list of values to check.condition
: condition to satisfy.
Variants
:count
: Constraint ensuring that the number of occurrences of the values invals
inx
satisfies the given condition.
concept(:count, x; vals, op, val)
concept(:count)(x; vals, op, val)
:at_least
: Constraint ensuring that the number of occurrences of the values invals
inx
is at leastval
.
concept(:at_least, x; vals, val)
concept(:at_least)(x; vals, val)
:at_most
: Constraint ensuring that the number of occurrences of the values invals
inx
is at mostval
.
concept(:at_most, x; vals, val)
concept(:at_most)(x; vals, val)
:exactly
: Constraint ensuring that the number of occurrences of the values invals
inx
is exactlyval
.
concept(:exactly, x; vals, val)
concept(:exactly)(x; vals, val)
Examples
c = concept(:count)
c([2, 1, 4, 3]; vals=[1, 2, 3, 4], op=≥, val=2)
c([1, 2, 3, 4]; vals=[1, 2], op==, val=2)
c([2, 1, 4, 3]; vals=[1, 2], op=≤, val=1)
Constraints.xcsp_nvalues Function
xcsp_nvalues(list, condition, except)
Return true
if the number of distinct values in list
satisfies the given condition, false
otherwise.
Arguments
list::Vector{Int}
: list of values to check.condition
: condition to satisfy.except::Union{Nothing, Vector{Int}}
: list of values to exclude. Default isnothing
.
Variants
:nvalues
: Ensures that the number of distinct values inx
satisfies a given numerical condition.
The constraint is defined by the following expression: nValues(x, op, val)
where x
is a list of variables, op
is a comparison operator, and val
is an integer value.
concept(:nvalues, x; op, val)
concept(:nvalues)(x; op, val)
Examples
c = concept(:nvalues)
c([1, 2, 3, 4, 5]; op = ==, val = 5)
c([1, 2, 3, 4, 5]; op = ==, val = 2)
c([1, 2, 3, 4, 3]; op = <=, val = 5)
c([1, 2, 3, 4, 3]; op = <=, val = 3)
Constraints.xcsp_cardinality Function
xcsp_cardinality(list, values, occurs, closed)
Return true
if the number of occurrences of the values in values
in list
satisfies the given condition, false
otherwise.
Arguments
list::Vector{Int}
: list of values to check.values::Vector{Int}
: list of values to check.occurs::Vector{Int}
: list of occurrences to check.closed::Bool
: whether the constraint is closed or not.
Variants
:cardinality
: Global constraint that restricts the number of times specific values in a listvalues
can appear inx
.
concept(:cardinality, x; bool=false, vals)
concept(:cardinality)(x; bool=false, vals)
:cardinality_closed
: Global constraint that restricts the number of times in a listvalues
can appear inx
. It is closed, meaning that the variables inx
cannot have values outside the ones inlist
.
concept(:cardinality_closed, x; vals)
concept(:cardinality_closed)(x; vals)
:cardinality_open
: Global constraint that restricts the number of times in a listvalues
can appear inx
. It is open, meaning that the variables inx
can have values outside the ones inlist
.
concept(:cardinality_open, x; vals)
concept(:cardinality_open)(x; vals)
Examples
c = concept(:cardinality)
c([2, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
c([8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3], bool=false)
c([8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3], bool=true)
c([2, 5, 10, 10]; vals=[2 1; 5 1; 10 2])
c([2, 5, 10, 10]; vals=[2 0 1 42; 5 1 3 7; 10 2 3 -4])
c([2, 5, 5, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
c([2, 5, 10, 8]; vals=[2 1; 5 1; 10 2])
c([5, 5, 5, 10]; vals=[2 0 1 42; 5 1 3 7; 10 2 3 -4])
cc = concept(:cardinality_closed)
cc([8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3])
co = concept(:cardinality_open)
co([8, 5, 10, 10]; vals=[2 0 1; 5 1 3; 10 2 3])