# Circuit constraints in ortools

I am looking to assign tasks to people. Each successive task should be started after the first one is finished and should be started at the same location as the preceding task. While the time constraint works fine, when using circuit constraints for the location constraint, I am not getting the right results. I am looking to allocate all tasks to as few people as possible.

Tasks 1-3-4 are a possible sequence. So is 1-3-5, 2-3-4, etc. It is possible for 3 employees to cover all tasks here. I only get 5 employees as the optimal answer

What am I doing wrong?

from collections import defaultdict
from ortools.sat.python import cp_model

model = cp_model.CpModel()
solver = cp_model.CpSolver()

1: [2, 3, 90, 165], # task_id: start_location, end_location, start_time, end_time
2: [2, 3, 160, 265],
3: [3, 1, 280, 355],
4: [1, 2, 380, 455],
5: [1, 2, 810, 885]
}

employees = range(5)
assigns = {}

for e in employees:
assigns[e, t] = model.NewBoolVar(f'{t}_{e}')
interval = model.NewOptionalIntervalVar(start, duration, end, assigns[e,t], f'task_interval_{t}_{e}')

model.Add(sum(assigns[e,t] for e in employees) == 1)

for e in employees:
arcs = []
#if no tasks assigned to employee then add a self loop for employee
arcs.append([0, 0, any_active.Not()])

first = model.NewBoolVar(f'first_{e}_{t}')
last = model.NewBoolVar(f'last_{e}_{t}')
arcs.append( [0, t+1, first] )
arcs.append( [t+1, 0, last] )

if i == t:
arcs.append([t+1, t+1, assigns[e,t+1].Not()])
continue

#next task starts at same location as current stop

#if the next stop does not start at same locations, then only one of the two tasks are true for this employee

employees_worked = {}
for e in employees:

model.Minimize(sum(employees_worked[e] for e in employees))
status = solver.Solve(model)

assert status in [cp_model.FEASIBLE, cp_model.OPTIMAL]

for e in employees:
if solver.BooleanValue(assigns[e, t]):


Updated code that fixed the problem. I had not sequenced the tasks by time.

for e in employees:
arcs = []
#if no tasks assigned to employee then add a self loop for employee
arcs.append([0, 0, any_active.Not()])

first = model.NewBoolVar(f'first_{e}_{t}')
last = model.NewBoolVar(f'last_{e}_{t}')
arcs.append( [0, t+1, first] )
arcs.append( [t+1, 0, last] )

if i == t:
arcs.append([t+1, t+1, assigns[e,t+1].Not()])
continue