Skip to content

Generic Constraints

In the XCSP³-core standard, generic constraints are categorized into two main types: intention and extension constraints.

Intention Constraints

These are constraints that are defined by a logical expression or a function. They are called intentional because they are defined by the property they satisfy. For example, a constraint that specifies that a variable x must be less than a variable y could be defined intentionally as x<y.

Note that the intention constraint is not directly available through the JC-API in Constraints.jl. It is designed as such since defining a constraint through a predicate is the natural way.

We provide a straightforward example through the :dist_different constraint on how to define and add such a constraint in the USUAL_CONSTRAINTS collection.

Higher level modeling languages such as JuMP should provide a Intention interface.

Defining an intention constraint in JC-API

We use the dist_different constraint to illustrate how to define an intention constraint in Constraints.jl. The dist_different constraint ensures that the distances between marks x on a ruler are unique.

|x[1]x[2]||x[3]x[4]|

The constraint is then added to the usual constraints collection.

julia
const description_dist_different = """
Ensures that the distances between marks on the ruler are unique.
"""

# Define the predicate
predicate_dist_different(x) = abs(x[1] - x[2])  abs(x[3] - x[4])

# Add it to usual constraints
@usual concept_dist_different(x) = xcsp_intention(
    list = x,
    predicate = predicate_dist_different
)

Please check the section dedicated to the Golomb Ruler problem to see a use for this constraint. <!– TODO: Golomb Ruler –>

APIs

Note that the intention constraint is not directly available through the JC-API in Constraints.jl. It is designed as such since defining a constraint through a predicate is the natural way.

We provide here a usage example for the :dist_different constraint, previously added to the USUAL_CONSTRAINTS collection.

Higher level modeling language such as JuMP should provide an Intention interface.

julia
using Constraints

concept(:dist_different, x)
concept(:dist_different)(x)
julia
# Defines the DistDifferent constraint
using Constraints

c = x -> xcsp_intention(
    list = x,
    predicate = y -> abs(y[1] - y[2])  abs(y[3] - y[4])
)

c([1, 2, 3, 3]) # true
c([1, 2, 3, 4]) # false
julia
using CBLS, JuMP

model = Model(CBLS.Optimizer)

# Using build-in DistDifferent
@variable(model, 0 <= X[1:4] <= 10, Int)
@constraint(model, X in DistDifferent())

# Alternatively
@variable(model, 0 <= Y[1:4] <= 10, Int)
@constraint(model, Y in Intention(y -> abs(y[1] - y[2])  abs(y[3] - y[4])))

optimize!(model)

@info value.(X)
@info value.(Y)
julia
using CBLS
import MathOptInterface as MOI

optimizer = CBLS.Optimizer()

x = MOI.add_variables(optimizer, 4)
for xi in x
    # Missing RangeDomain currently in CBLS
    MOI.add_constraint(optimizer, xi, CBLS.DiscreteSet(collect[1:10]))
end
MOI.add_constraint(optimizer, x, CBLS.Intention(y -> abs(y[1] - y[2])  abs(y[3] - y[4])))

MOI.optimize!(optimizer)

Extension Constraints

These are constraints that are defined by explicitly listing all the tuples of values that satisfy the constraint. They are called extensional because they are defined by the set of values they allow. For example, a binary constraint that specifies that a variable X must be either 1 or 2 and a variable Y must be either 3 or 4 could be defined extensionally by the set of tuples (1,3),(1,4),(2,3),(2,4).

These two types of constraints provide a flexible way to define complex relationships between variables in constraint programming.

julia
using Constraints

concept(:dist_different, x)
concept(:dist_different)(x)
julia
# Defines the DistDifferent constraint
using Constraints

c = x -> xcsp_intention(
    list = x,
    predicate = y -> abs(y[1] - y[2])  abs(y[3] - y[4])
)

c([1, 2, 3, 3]) # true
c([1, 2, 3, 4]) # false
julia
using CBLS, JuMP

model = Model(CBLS.Optimizer)

# Using build-in DistDifferent
@variable(model, 0 <= X[1:4] <= 10, Int)
@constraint(model, X in DistDifferent())

# Alternatively
@variable(model, 0 <= Y[1:4] <= 10, Int)
@constraint(model, Y in Intention(y -> abs(y[1] - y[2])  abs(y[3] - y[4])))

optimize!(model)

@info value.(X)
@info value.(Y)
julia
using CBLS
import MathOptInterface as MOI

optimizer = CBLS.Optimizer()

x = MOI.add_variables(optimizer, 4)
for xi in x
    # Missing RangeDomain currently in CBLS
    MOI.add_constraint(optimizer, xi, CBLS.DiscreteSet(collect[1:10]))
end
MOI.add_constraint(optimizer, x, CBLS.Intention(y -> abs(y[1] - y[2])  abs(y[3] - y[4])))

MOI.optimize!(optimizer)