DAG API
The DAG (Directed Acyclic Graph) API provides the core constraint and objective modeling functionality.
DAG Construction
JuLS.DAG
— Typestruct DAG <: MoveEvaluator
Core data structure representing an optimization problem as a Directed Acyclic Graph (DAG). An invariant represents an intermediate relationship between variables. We represent these relationships as a Directed Acyclic Graph (DAG). This representation allows for cheap evaluations of local moves.
Fields
_invariants::Vector{Invariant}
: Problem invariants (nodes of the DAG)_names::Vector{Union{Nothing,String}}
: Optional names for invariants_using_cp::BitVector
: Flags for constraint programming usage per invariant_adjacency_matrix::AdjacencyMatrix
: Graph structure representation_var_to_first_invariants::Vector{Int}
: Maps variables to their first dependent invariants_early_stop_threshold::Float64
: Threshold for early termination of move evaluation_helper::AbstractDAGHelper
: Problem-specific helper object_is_init::Bool
: Initialization status flag
Invariants
Invariants are the building blocks of the DAG that represent constraints and computations.
Arithmetic Invariants
JuLS.ScalarProductInvariant
— TypeScalarProductInvariant <: Invariant
Invariant to represent the scalar product y = (w | x)
JuLS.SumInvariant
— TypeSumInvariant <: StatelessInvariant
Invariant that enforces y = ∑ x_i
Comparison Invariants
JuLS.ComparatorInvariant
— TypeComparatorInvariant <: SummableDeltaInvariant
Invariant that compares a sum of values against a capacity threshold, typically used in constrained optimization problems. y = max(0, ∑ x - C)
Fields
current_value::Float64
: Current accumulated sumoriginal_capacity::Float64
: Threshold value for comparison
Boolean Invariants
JuLS.AndInvariant
— TypeAndInvariant <: Invariant
Represents an invariant for the logical AND constraint. y = x1 ∩ x2 ∩ ... ∩ x_n
Fields
nb_false::Int
: Number of variables currently false.
JuLS.OrInvariant
— TypeOrInvariant <: Invariant
Represents an invariant for the logical OR constraint. y = x1 ∪ x2 ∪ ... ∪ x_n
Fields
nb_trues::Int
: Number of variables currently true.
Specialized Invariants
JuLS.AllDifferentInvariant
— Typestruct AllDifferentInvariant <: Invariant
An invariant that enforces all variables to have different values.
Description
Represents the constraint x₁ ≠ x₂ ≠ ... ≠ xₙ where each variable xᵢ takes values in the domain D = {1,...,n}.
Violation Measure
The violation is calculated as: y = ∑ max(0, c(i) - 1) where c(i) is the count of variables taking value i.
Fields
current_value_counter::Vector{Int}
: Counts occurrences of each value in the current assignment
Constructor
AllDifferentInvariant(n_variables::Int)
Creates an AllDifferentInvariant for n_variables variables, initializing the counter to zeros.
JuLS.AmongInvariant
— TypeAmongInvariant <: StatelessInvariant
This invariant represents the constraint Among(X, S, n) which enforces y = |{x ∈ X : x.value ∈ S}|
JuLS.ElementInvariant
— Typestruct ElementInvariant{T} <: StatelessInvariant where {T<:DecisionValue}
Given a message with an IntDecisionValue i, the ElementInvariant returns elements[i] which is a message with a DecisionValue of type T. y = elements[x]
DAG Operations
Adding Invariants
# Add an invariant to the DAG
invariant_id = add_invariant!(dag, ScalarProductInvariant(weights); variable_parent_indexes = [1, 2, 3])
Message Passing
The DAG uses message passing for efficient computation:
Message Types
FullMessage
: Complete state informationDelta
: Incremental changes only
Example Usage
using JuLS
# Create a DAG for a simple problem
dag = DAG(3) # 3 decision variables
# Add scalar product invariant
weights = [2.0, 3.0, 1.0]
sum_id = add_invariant!(dag, ScalarProductInvariant(weights); variable_parent_indexes = [1, 2, 3])
# Add comparator for constraint
capacity = 10.0
constraint_id = add_invariant!(dag, ComparatorInvariant(capacity); variable_parent_indexes = [1, 2, 3])
# Connect sum to constraint
connect!(dag, sum_id, constraint_id)
# Set objective
objective_weights = [5.0, 4.0, 3.0]
obj_id = add_invariant!(dag, ScalarProductInvariant(objective_weights); variable_parent_indexes= [1, 2, 3])
add_invariant!(dag, ObjectiveInvariant(); invariant_parent_indexes= [obj_id])
Performance Considerations
Memory Usage
- DAGs store computation history for efficiency
- Consider clearing history for long runs
- Monitor memory usage for large problems
Computation Efficiency
- Use appropriate invariant types
- Minimize unnecessary connections
- Batch updates when possible