Skip to main content

Constraint Reference

Every constraint type available in the Jia language.

Comparison constraints

The most general constraint form. Compare two expressions with a relational operator:

comparison_stmt = expr cmp_op expr
cmp_op = '<=' | '>=' | '<' | '>' | '==' | '!='

Used for precedence relationships, makespan bounds, deadlines, and any custom temporal or arithmetic relationship.

end_of(task_a) <= start_of(task_b) // task_a must finish before task_b starts
start_of(task_b) >= end_of(task_a) + 2 // at least 2-unit gap
end_of(task_c) <= makespan // task_c ends within the makespan
x + y >= 10 // LP linear constraint

LP models use comparison constraints for all linear inequalities and equalities:

@model lp
model lp_constraints

variables {
Real: x, y, z
}

domains {
x in 0..inf
y in 0..inf
z in 0..inf
}

constraints {
x + y + z >= 15
2 * x + y <= 30
x + 2 * z == 20
}

minimize x + y + z

no_overlap

Ensures that no two intervals in the group execute at the same time. This is the core machine-scheduling constraint — each machine processes at most one task at a time.

no_overlap_stmt = 'no_overlap' '(' IDENT (',' IDENT)* ')'

Pass a Set[Interval] name to apply the constraint to all members of the set:

no_overlap(machine1)
no_overlap(machine2)

Or list individual interval names directly:

no_overlap(task_a, task_b, task_c)

Complete example — two-machine job shop:

model no_overlap_example

variables {
Interval: j1_op1, j1_op2
Interval: j2_op1, j2_op2
Integer: makespan
Set[Interval]: machine1, machine2
}

domains {
duration(j1_op1) = 3
duration(j1_op2) = 2
duration(j2_op1) = 4
duration(j2_op2) = 1
machine1 = {j1_op1, j2_op2}
machine2 = {j1_op2, j2_op1}
makespan in 0..50
}

constraints {
end_of(j1_op1) <= start_of(j1_op2)
end_of(j2_op1) <= start_of(j2_op2)
no_overlap(machine1)
no_overlap(machine2)
end_of(j1_op2) <= makespan
end_of(j2_op2) <= makespan
}

minimize makespan

cumulative

Ensures the total demand on a resource never exceeds its capacity at any instant. Each interval in the resource set consumes its declared demand while active.

cumulative_stmt = 'cumulative' '(' IDENT ',' expr ')'
  • First argument: the Set[Interval] representing the resource.
  • Second argument: the resource capacity (an expression, so it can reference a variable).
cumulative(workers, 4) // at most 4 workers active at once
cumulative(memory, max_mem) // capacity from an Integer variable

Demands must be declared in the domains block:

demand(task_a, workers) = 2
demand(task_b, workers) = 3

Complete example — two-resource project:

model cumulative_example

variables {
Interval: compile, link, test
Integer: makespan
Set[Interval]: cpu, memory
}

domains {
duration(compile) = 4
duration(link) = 2
duration(test) = 3

cpu = {compile, link, test}
memory = {compile, test}

demand(compile, cpu) = 3
demand(link, cpu) = 1
demand(test, cpu) = 2
demand(compile, memory) = 2
demand(test, memory) = 3

makespan in 0..20
}

constraints {
end_of(compile) <= start_of(link)
cumulative(cpu, 4)
cumulative(memory, 4)
end_of(link) <= makespan
end_of(test) <= makespan
}

minimize makespan

span

The parent interval spans all present children: its start equals the earliest child start, and its end equals the latest child end.

span_stmt = 'span' '(' IDENT ',' IDENT ')'
  • First argument: the parent Interval.
  • Second argument: a Set[Interval] of child intervals.
span(project, phases)

Complete example — project composed of phases:

model span_example

variables {
Interval: project, phase1, phase2, phase3
Set[Interval]: phases
}

domains {
duration(phase1) = 3
duration(phase2) = 5
duration(phase3) = 2
phases = {phase1, phase2, phase3}
}

constraints {
end_of(phase1) <= start_of(phase2)
span(project, phases)
}

minimize end_of(project)

The project interval automatically covers the full extent of all three phases.

alternative

Exactly one interval from the set is present (scheduled), and the parent interval mirrors that interval's time window. All other members of the set are absent.

alternative_stmt = 'alternative' '(' IDENT ',' IDENT ')'
  • First argument: the parent Interval.
  • Second argument: a Set[Interval] of candidate intervals.

The candidate intervals must be declared optional in the domains block.

optional(candidate_a, candidate_b)
alternative(operation, candidates)

Complete example — operation that can run on either of two machines:

model alternative_example

variables {
Interval: op1, op1_machine_a, op1_machine_b
Interval: op2
Integer: makespan
Set[Interval]: op1_candidates
Set[Interval]: machine_a, machine_b
}

domains {
duration(op1_machine_a) = 3
duration(op1_machine_b) = 5
duration(op2) = 2
optional(op1_machine_a, op1_machine_b)
op1_candidates = {op1_machine_a, op1_machine_b}
machine_a = {op1_machine_a}
machine_b = {op1_machine_b, op2}
makespan in 0..20
}

constraints {
alternative(op1, op1_candidates)
no_overlap(machine_a)
no_overlap(machine_b)
end_of(op1) <= makespan
end_of(op2) <= makespan
}

minimize makespan

The solver chooses which machine processes op1 and schedules it accordingly.