我对这个话题相当陌生,但我已经开始使用这个例子来实现一个轮班调度程序:https ://developers.google.com/optimization/scheduling/employee_scheduling
现在我想添加以下约束:在五班之后,需要强制中断 3 个连续班次,然后才能再次安排一个人
我们已经实现了如下图,逻辑是如果在过去的 6 个班次中有连续 3 个班次的员工不在某个岗位(无论角色)我想强制执行当前的敬业度不能配备人员。需要注意的是,休息 2 次不算作休息,但就像员工工作过一样。
例如,如果过去的班次看起来像这样010011 ,则该员工需要休息一下(0 不工作,1 工作)。
我设置模型如下:
from ortools.sat.python import cp_model
engagements = {}
model = cp_model.CpModel()
# set up boolean term for each time, emploeyee, station and role
shifts = [1,2,3,4,5,6,7, 8, 9, 10]
employee = ['employee1', 'employee2', 'employee3', 'employee4', 'employee5', 'employee6', 'employee7', 'employee8']
stations = ['station1', 'station2', 'station3', 'station4']
roles = ['senior', 'junior', 'manager']
for y in shifts:
for n in employee:
for d in stations:
for s in roles:
engagements[(y, n, d, s)] = model.NewBoolVar('engagement_y%in{0}d{1}s{2}'.format(n, d, s) % (y))
接下来我实施了约束,即在五班之后,当前工作站和员工至少需要休息 3 班
for n in employee:
for d in stations:
for y in shifts:
# first 5 shifts are fine either way
# past shifts need to be checked
if y > min(shifts)+5:
past_shift_6_4 = model.NewIntVar(0, 1, 'bpast_shift_6_4_y%in{0}d{1}'.format(n, d) % (y))
past_shift_5_3 = model.NewIntVar(0, 1, 'cpast_shift_5_3_y%in{0}d{1}'.format(n, d) % (y))
past_shift_4_2 = model.NewIntVar(0, 1, 'dpast_shift_4_2_y%in{0}d{1}'.format(n, d) % (y))
past_shift_3_1 = model.NewIntVar(0, 1, 'epast_shift_3_1_y%in{0}d{1}'.format(n, d) % (y))
b_6_4 = model.NewBoolVar('b_6_4_y%in{0}d{1}'.format(n, d) % (y))
b_5_3 = model.NewBoolVar('b_5_3_y%in{0}d{1}'.format(n, d) % (y))
b_4_2 = model.NewBoolVar('b_4_2_y%in{0}d{1}'.format(n, d) % (y))
b_3_1 = model.NewBoolVar('b_3_1_y%in{0}d{1}'.format(n, d) % (y))
# set all parameters
if y > min(shifts)+6:
for yp in range(y-4, y-7, -1):
for s in roles:
past_shift_6_4 += engagements[(yp, n, d, s)]
for yp in range(y-3, y-6, -1):
for s in roles:
past_shift_5_3 += engagements[(yp, n, d, s)]
for yp in range(y-2, y-5, -1):
for s in roles:
past_shift_4_2 += engagements[(yp, n, d, s)]
for yp in range(y-1, y-4, -1):
for s in roles:
past_shift_3_1 += engagements[(yp, n, d, s)]
model.Add(past_shift_6_4 == 0).OnlyEnforceIf(b_6_4.Not())
model.Add(past_shift_5_3 == 0).OnlyEnforceIf(b_5_3.Not())
model.Add(past_shift_4_2 == 0).OnlyEnforceIf(b_4_2.Not())
model.Add(past_shift_3_1 == 0).OnlyEnforceIf(b_3_1.Not())
# be true because cooldown not included
model.Add(past_shift_6_4 > 0).OnlyEnforceIf(b_6_4)
model.Add(past_shift_5_3 > 0).OnlyEnforceIf(b_5_3)
model.Add(past_shift_4_2 > 0).OnlyEnforceIf(b_4_2)
model.Add(past_shift_3_1 > 0).OnlyEnforceIf(b_3_1)
final = model.NewBoolVar('final')
model.AddBoolOr([b_6_4.Not(), b_5_3.Not(),b_4_2.Not(),b_3_1.Not(), final])
model.AddImplication(final, b_6_4)
model.AddImplication(final, b_5_3)
model.AddImplication(final, b_4_2)
model.AddImplication(final, b_3_1)
model.Add(engagements[(y, n, d, s)]==0).OnlyEnforceIf(final)
乘法与此类似:https ://github.com/google/or-tools/blob/stable/ortools/sat/doc/boolean_logic.md#python-code-3
如果所有布尔值(b_7_5,b_6_4,b_5_3,b_4_2,b_3_1)为真(意味着冷却没有在任何时间窗口发生),我预计最终会强制执行约束,这显然目前没有发生。
任何建议将不胜感激!