Shift schedule: excluding a certain type of shift when and other has been done #4164
-
I found out the answer to my previous question but now I stumbled upon a new one. I have diferent types of shifts. In case a nurse has already taken any of the two STEMI shifts then she can't be assigned to any other shifts. I have 2 lists of shift types. created two list of variables for each set and (hopefully) created the first condition: which does not allow to have more that one STEMO on a single day. My piece of code looks as follows: stemi_shifts = [ShiftType.STEMI_NIGHT, ShiftType.STEMI_MORNING]
other_shifts = [ShiftType.MORNING,
ShiftType.AFTERNOON,
ShiftType.PHONE_FROM_HOME,
ShiftType.PHONE_LOCAL,
ShiftType.PHONE_WEEKEND]
for e in range(num_employees):
for w in range(num_weeks):
for d in range(num_days):
# Shifts for this day
stemis = [shifts[e, s.value, w * 7 + d] for s in stemi_shifts]
other = [shifts[e, s.value, w * 7 + d] for s in other_shifts]
stemis_worked = model.NewIntVar(0, 1, 'max_stemi_per_day')
model.Add(sum(stemis) <= stemis_worked)
other_worked = model.NewIntVar(0, len(other_shifts), 'max_ohter_per_day')
# if other == 0:
# sum(stemi) <= 1
# else:
# sum(stemi) == 0 This is how far I got. Basicaly my problem is that I don't know how can I sum the number of other shifts together to compare it against the sum of STEMIs. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
I've come up with something like this, but can't prove if it is really the solution: for e in range(num_employees):
for d in range(num_days):
b = model.NewBoolVar(f'constr_{e}_{d}')
model.add(sum(shifts[(e, s.value, d)] for s in other_shifts) == 0).OnlyEnforceIf(b)
model.add(sum(shifts[(e, s.value, d)] for s in other_shifts) > 0).OnlyEnforceIf(b.Not())
model.add(sum(shifts[(e, s.value, d)] for s in stemi_shifts) <= 1).OnlyEnforceIf(b) |
Beta Was this translation helpful? Give feedback.
-
Context seems to be missing here. If your underlying decision-variables are of boolean type, consider going for a conflict-graph:
Don't be scared about the size of such a graph (at least in most use-cases). It's basically the native-language of the solver and there are some clique-table/merging-actions designed to reason about this stuff. |
Beta Was this translation helpful? Give feedback.
-
Taking you idea I modified the code as follows: # On any single day only 1 STEMI is allowed!
stemi_shifts = [ShiftType.STEMI_NIGHT, ShiftType.STEMI_MORNING]
other_shifts = [ShiftType.MORNING,
ShiftType.AFTERNOON,
ShiftType.PHONE_FROM_HOME,
ShiftType.PHONE_LOCAL,
ShiftType.PHONE_WEEKEND]
for e in range(num_employees):
for d in range(num_days):
# STEMI hifts for this day
stemis = [shifts[e, s.value, d] for s in stemi_shifts]
stemis_worked = model.NewIntVar(0, 1, 'max_stemi_per_day')
# This ensured that no two STEMIs are done on the same day
model.Add(sum(stemis) <= stemis_worked)
# No other type of shift is allowed when we aredy had a STEMI
for e in range(num_employees):
for d in range(num_days):
# Implement the contraint
b = model.NewBoolVar(f'otherc_{e}_{d}')
# b is True if at least one other type of shift has been done
model.add(sum(shifts[(e, s.value, d)] for s in other_shifts) > 0).OnlyEnforceIf(b)
model.add(sum(shifts[(e, s.value, d)] for s in other_shifts) == 0).OnlyEnforceIf(b.Not())
s = model.NewBoolVar(f'stemic_{e}_{d}')
# s is True if at least one STEMI shift has been done
model.add(sum(shifts[(e, s.value, d)] for s in stemi_shifts) > 0).OnlyEnforceIf(s)
model.add(sum(shifts[(e, s.value, d)] for s in stemi_shifts) == 0).OnlyEnforceIf(s.Not())
model.AddImplication(b, s.Not()) It seems to work but I need an expert eye for a check. |
Beta Was this translation helpful? Give feedback.
Context seems to be missing here.
If your underlying decision-variables are of boolean type, consider going for a conflict-graph:
Don't be scared about the size of such a graph (at least in most use-cases). It's basically the native-language of the solver and there are some clique-table/merging-actions designed to reason about this stuff.