Defining Variables and Exploring Domains
ConstraintDomains.jl stands as the standard way to define variables and explore domains within the Julia Constraints ecosystem. This package provides the infrastructure necessary for specifying both discrete and continuous domains. Explorations features are mainly related to the learning about constraints aspect and will be detailed in that chapter.
Variables and their domains can also be defined through MOI
and JuMP
syntaxes in their respective models.
Implementing the AbstractDomain
Interface
At the foundation of ConstraintDomains.jl is the AbstractDomain
type, an abstract supertype for all domain types. Implementations of AbstractDomain
must provide methods for checking membership (rand
), and determining the domain's size or range (length
). These functionalities are essential for defining the behavior and properties of variable domains within constraint models.
ConstraintDomains.AbstractDomain Type
AbstractDomain
An abstract super type for any domain type. A domain type D <: AbstractDomain
must implement the following methods to properly interface AbstractDomain
.
Base.∈(val, ::D)
Base.rand(::D)
Base.length(::D)
that is the number of elements in a discrete domain, and the distance between bounds or similar for a continuous domain
Additionally, if the domain is used in a dynamic context, it can extend
add!(::D, args)
delete!(::D, args)
where args
depends on D
's structure
Discrete Domains
Optimization in discrete spaces has been the core of Constraint Programming since its inception. We provide three kinds of discrete domains.
SetDomain
A SetDomain
is simply a Set
of unordered numerical values.
using ConstraintDomains
d1 = domain([53.69, 89.2, 0.12])
d2 = domain([2//3, 89//123])
d3 = domain(4.3)
d4 = domain(1, 42, 3.14)
using CBLS, JuMP
m = JuMP.Model(CBLS.Optimizer)
@variable(m, x1 in DiscreteSet([53.69, 89.2, 0.12]))
@variable(m, x2 in DiscreteSet([2//3, 89//123]))
@variable(m, x3 in DiscreteSet(4.3))
@variable(m, x4 in DiscreteSet([1, 42, 3.14]))
using CBLS
import MathOptInterface as MOI
optimizer = CBLS.Optimizer()
v1 = MOI.add_variable(optimizer)
MOI.add_constraint(optimizer, v1, CBLS.DiscreteSet([53.69, 89.2, 0.12]))
v2 = MOI.add_variable(optimizer)
MOI.add_constraint(optimizer, v2, CBLS.DiscreteSet([2//3, 89//123]))
v3 = MOI.add_variable(optimizer)
MOI.add_constraint(optimizer, v3, CBLS.DiscreteSet(4.3))
v4 = MOI.add_variable(optimizer)
MOI.add_constraint(optimizer, v4, CBLS.DiscreteSet([1, 42, 3.14]))
RangeDomain
A range domain allows for minimal storage and more efficient operation on discrete sets defined as Range
in Julia. It is not recommended for dynamic domains (it will be replaced with SetDomain
as soon as a non-extremal element is removed).
using ConstraintDomains
d1 = domain(1:5)
d2 = domain(0.4:0.1:1.3)
## To be implemented
# using CBLS, JuMP
# m = JuMP.Model(CBLS.Optimizer)
# @variable(m, 1 ≤ x1 ≤ 5, Int) # Consecutive integers are interpreted as range
# @variable(m, x2 in RangeSet(0.4:0.1:1.3))
## To be implemented
# using CBLS
# import MathOptInterface as MOI
# optimizer = CBLS.Optimizer()
# v1 = MOI.add_variable(optimizer)
# MOI.add_constraint(optimizer, v1, MOI.RangeSet(1:5))
# v2 = MOI.add_variable(optimizer)
# MOI.add_constraint(optimizer, v1, MOI.RangeSet(0.4:0.1:1.3))
Arbitrary Domains
As odd as it may sound, we provide a constructor for sets of elements making up arbitrary, possibly non-numerical, domains.
Until some practical examples are implemented, this structure will mainly be a placeholder with default behavior.
Continuous Domains
Numerous problems cannot be challenged without expressing at least part of their domains as continuous variables. In Julia Constraints we provide such domains as (set of) intervals.
using ConstraintDomains, Intervals
d1 = domain(Interval{Open,Closed}(3.2, true), (42, false))
d2 = domain(3.2..42)
d3 = domain([3.2..42, 63.2..324.1])
## see MOI.Interval
## see MOI.Interval