Task Constraints

ProcessScheduler provides a set of ready-to-use temporal task constraints. They allow expressing common rules such as “the task A must start exactly at the instant 4”, “the task B must end at the same time than the task C ends”, “the task C must be scheduled exactly 3 periods after the task D is completed” etc.


Naming convention: if the class name starts with Task* then the constraint applies to one single task, if the class name starts with Tasks* it applies to 2 or more task instances.

Time constraints

  • TaskPrecedence: takes two parameters task_1 and task_2 and constraints task_2 to be scheduled after task_1 is completed. The precedence type can either be 'lax' (default, task_2.start >= task_1.end)), 'strict' (task_2.start >= task_1.end)) or 'tight' (task_2.start >= task_1.end, task_2 starts immediately after task_1 is completed). An optional parameter offset can be additionally set.

task_1 = ps.FixedDurationTask('Task1', duration=3)
task_2 = ps.FixedVariableTask('Task2')
pc = TaskPrecedence(task1, task2, kind='tight', offset=2)

constraints the solver to schedule task_2 start exactly 2 periods after task_1 is completed.

  • TasksStartSynced: takes two parameters task_1 and task_2 such as the schedule must satisfy the constraint \(task_1.start = task_2.start\)

  • TasksEndSynced: takes two parameters task_1 and task_2 such as the schedule must satisfy the constraint \(task_1.end = task_2.end\)

  • TasksDontOverlap: takes two parameters task_1 and task_2 such as the task_1 ends before the task_2 is started or the opposite (task_2 ends before task_1 is started)

  • TaskStartAt: takes two parameters task and value such as the task starts exactly at the instant \(task.start = value\)

  • TaskStartAfterStrict: the constraint \(task.start > value\)

  • TaskStartAfterLax: the constraint \(task.start >= value\)

  • TaskEndAt: takes two parameters task and value such as the task ends exactly at the instant value \(task.end = value\)

  • TaskEndBeforeStrict: the constraint \(task.end < value\)

  • TaskEndBeforeLax: the constraint \(task.end <= value\)

  • TasksContiguous: take a liste of tasks, force the schedule so that tasks are contiguous

  • ScheduleNTasksInTimeIntervals: given a set of \(m\) different tasks, and a list of time intervals, schedule \(N\) tasks among \(m\) in this time interval.

  • ResourceTasksDistance: take a mandatory attribute distance (integer), an optional time_periods (list of couples of integers e.g. [[0, 1], [5, 19]]). All tasks, that use the given resource, scheduled within the time_periods must have a maximal distance of distance (distance being considered as the time between two consecutive tasks).


If the task(s) is (are) optional(s), all these constraints apply only if the task is scheduled. If the solver does not schedule the task, these constraints does not apply.

Optional tasks constraints

Following constraints apply to optional tasks only.

  • OptionalTaskConditionSchedule creates a constraint that adds a condition for the task to be scheduled. The condition is a z3 BoolRef

  • the OptionalTasksDependency takes two optional tasks task_1 and task_2, and ensures that task_1 is schdeuld implies that task_2 is scheduled as well.

  • the ForceScheduleNOptionalTasks forces \(m\) optional tasks among \(n\) to be scheduled, with \(m \leq n\).


All the Task constraints may be defined as optional. This parameter is set to False by default, which means the task constraint is mandatory. If you set the attribute optional to True the the constraint becomes optional, and may/may not apply according to the solver. You can force the schedule to schedule an optional constraint:

pb.add_constraint([task.applied == True])