Skip to content

Constraints.jl: Streamlining Constraint Definition and Integration in Julia

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)
julia
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])
julia
using CBLS, JuMP

model = Model(CBLS.Optimizer)
@variable(model, 1X[1:5]5, Int)
@variable(model, 1Y[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)
julia
# TODO: How to handle intention in JuMP/MOI
julia
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
julia
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
julia
using CBLS, JuMP

model = Model(CBLS.Optimizer)
@variable(model, 1X[1:4]4, Int)
@variable(model, 1X_at_least[1:4]4, Int)
@variable(model, 1X_at_most[1:4]4, Int)
@variable(model, 1X_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)
julia
# TODO: How to handle intention in JuMP/MOI
julia
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)
julia
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])
julia
using CBLS, JuMP

model = Model(CBLS.Optimizer)
@variable(model, 1X[1:5]5, Int)
@variable(model, 1Y[1:5]5, Int)
@variable(model, 1Z[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)
julia
# TODO: How to handle intention in JuMP/MOI
julia
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])
julia
using Constraints

c = x -> Constraints.xcsp_cardinality(
   	list = x,
		values = [1, 2],
		occurs = [2 3; 1 5]
)

@info c([1, 2, 1, 2])
julia
using CBLS, JuMP

model = Model(CBLS.Optimizer)
@variable(model, 1X[1:4]10, Int)
@variable(model, 1Y[1:4]10, Int)
@variable(model, 1Z[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)
julia
# TODO: How to handle intention in JuMP/MOI

Counting and Summing Constraints

# Constraints.xcsp_sumFunction.
julia
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 in x satisfies a given condition.
julia
concept(:sum, x; op===, pair_vars=ones(x), val)
concept(:sum)(x; op===, pair_vars=ones(x), val)

Examples

julia
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)

source


# Constraints.xcsp_countFunction.
julia
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 in vals in x satisfies the given condition.
julia
concept(:count, x; vals, op, val)
concept(:count)(x; vals, op, val)
  • :at_least: Constraint ensuring that the number of occurrences of the values in vals in x is at least val.
julia
concept(:at_least, x; vals, val)
concept(:at_least)(x; vals, val)
  • :at_most: Constraint ensuring that the number of occurrences of the values in vals in x is at most val.
julia
concept(:at_most, x; vals, val)
concept(:at_most)(x; vals, val)
  • :exactly: Constraint ensuring that the number of occurrences of the values in vals in x is exactly val.
julia
concept(:exactly, x; vals, val)
concept(:exactly)(x; vals, val)

Examples

julia
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)

source


# Constraints.xcsp_nvaluesFunction.
julia
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 is nothing.

Variants

  • :nvalues: The nValues constraint specifies that the number of distinct values in the list of variables x is equal to a given value. 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.
julia
concept(:nvalues, x; op, val)
concept(:nvalues)(x; op, val)

Examples

julia
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)

source


# Constraints.xcsp_cardinalityFunction.
julia
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: The cardinality constraint, also known as the global cardinality constraint (GCC), is a constraint in constraint programming that restricts the number of times a value can appear in a set of variables.
julia
concept(:cardinality, x; bool=false, vals)
concept(:cardinality)(x; bool=false, vals)
  • :cardinality_closed: The closed cardinality constraint, also known as the global cardinality constraint (GCC), is a constraint in constraint programming that restricts the number of times a value can appear in a set of variables. It is closed, meaning that all values in the domain of the variables must be considered.
julia
concept(:cardinality_closed, x; vals)
concept(:cardinality_closed)(x; vals)
  • :cardinality_open: The open cardinality constraint, also known as the global cardinality constraint (GCC), is a constraint in constraint programming that restricts the number of times a value can appear in a set of variables. It is open, meaning that only the values in the list of values must be considered.
julia
concept(:cardinality_open, x; vals)
concept(:cardinality_open)(x; vals)

Examples

julia
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])

source