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/MOIusing 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) # falseusing 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]) # falseusing 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/MOIusing 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/MOIusing 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/MOICounting 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 inxsatisfies 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 invalsinxsatisfies 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 invalsinxis 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 invalsinxis 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 invalsinxis 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 inxsatisfies 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 listvaluescan 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 listvaluescan appear inx. It is closed, meaning that the variables inxcannot 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 listvaluescan appear inx. It is open, meaning that the variables inxcan 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])