I have a list of Employee
and a list of Mission
.
Each mission have a start time and a duration.
In the cp model (Google CpSat, from or-tools package), I defined shifts = Dictionary<(int,int),IntVar>
, where shifts[(missionId, employeeId)] == 1
if and only if this mission is realized by this employee.
I need to assign each mission to exactly one employee, and obviously one employee cannot realize two missions at the same time. I already have written those two hard constraints and they are working fine.
Problem:
Now, some missions are "linked" together and should be realized by the same employee. They are stored as follow:
linkedMissions = {{1,2}, {3,4,5}}
Here, mission 1 and 2 must be realized together by the same employee, and it is the same for missions 3, 4 and 5.
To write this last constraint, I gathered for each employee the list of all the shifts that should be linked together, then I made them all equal.
foreach (var employee in listEmployeesIds)
foreach (var missionGroup in linkedMissionsIds)
{
var linkedShifts = shifts
.Where(o => o.Key.Item2 == employee
&& missionGroup.Contains(o.Key.Item1))
.Select(o => o.Value)
.ToList();
for (var i = 0; i < linkedShifts.Count - 1; i++)
model.Add(linkedShifts[i] == linkedShifts[i + 1]);
}
However, the solver tells me the model is infeasible, but with a paper and a pen I can easily find a working planning. I have 35 employees and 25 missions, the missions that are linked together don't overlap, so there shouldn't be any problem.
EDIT:
As an alternative approach, as suggested by @Laurent Perron, I tried to use the same boolean variables for all shifts that must be together:
var constraintBools = new List<IntVar>();
foreach (var missionGroup in linkedMissionsIds) {
var constraintBools = new List<IntVar>();
foreach (var employee in listEmployeesIds)
{
var linkedShifts = shifts
.Where(o => o.Key.Item2 == employee
&& missionGroup.Contains(o.Key.Item1))
.Select(o => o.Value)
.ToList();
var constraint = model.NewBoolVar($"{linkedShifts.GetHashCode()}");
model.AddBoolAnd(linkedShifts).OnlyEnforceIf(constraint);
constraintBools.Add(constraint);
}
model.AddBoolOr(constraintBools);
}
But now, the constraint simply doesn't work: the linked shifts are not realized by the same employee.
What is wrong in my reasoning? Why is my model infeasible?
model.Add(linkedShifts[i] == linkedShifts[i + 1]);
– Beaumarchais