OR-TOOLS CP-SAT作业车间调度:拆分长任务并避免任务穿插
OR-Tools CP-SAT作业车间调度:拆分任务防穿插问题
我在使用OR-TOOLS CP-SAT实现作业车间调度时遇到了问题:拆分后的任务组会被其他工单的任务穿插。
调度背景
机器采用1、2、3班制运行,周末不工作。部分任务时长超过1个甚至2个班次,因此我将这类任务拆分为准备任务+每个工件对应的单独任务(例如某工单15件操作对应16个任务),要求同一操作拆分出的所有任务必须连续调度,不被其他工单任务打断。
现有代码实现
1. 非工作时间间隔定义
# 不同班制对应的非工作时间间隔: # 1班制:下午2点-6点 + 周末;2班制:晚10点-早6点 + 周末;3班制:仅周末 i = 0 for machine in machine_data: for mach_id, mach in enumerate(machine): if mach[1] == 0 and mach[3] == 1: if mach[2] == 1: for cal_id, cal in enumerate(cal_data): for shift_id, shift in enumerate(cal): start = int(shift[0]) size = int(shift[1]) - int(shift[0]) end = int(shift[1]) i = i + 1 name = str(mach[0]) + '_' + str(mach[2]) + '_' + str(i) + '_weekend' machine_to_intervals[mach[0]].append(model.NewIntervalVar(start, size, end, name)) elif mach[2] == 2: for cal_id, cal in enumerate(cal_data): for shift_id, shift in enumerate(cal): start = int(shift[2]) size = int(shift[3]) - int(shift[2]) end = int(shift[3]) i = i + 1 name = str(mach[0]) + '_' + str(mach[2]) + '_' + str(i) + '_weekend' machine_to_intervals[mach[0]].append(model.NewIntervalVar(start, size, end, name)) elif mach[2] == 3: for cal in cal_data: for shift_id, shift in enumerate(cal): if shift[4] > 0: start = int(shift[4]) size = int(shift[5]) - int(shift[4]) end = int(shift[5]) i = i + 1 name = str(mach[0]) + '_' + str(mach[2]) + '_' + str(i) + '_weekend' machine_to_intervals[mach[0]].append(model.NewIntervalVar(start, size, end, name))
2. 尝试实现拆分任务连续调度的约束
我用OnlyEnforceIf约束要求所有不属于当前操作的任务,要么在拆分后首个任务开始前完成,要么在最后一个任务结束后开始,同时以最小化拆分任务首尾间隔为目标:
split_minimize = [] for i in range(len(splitdf)): order = splitdf.iloc[i]['WorkOrder'] activity = splitdf.iloc[i]['Activity'] wc = splitdf.iloc[i]['WC_INT'] order_id = splitdf.iloc[i]['WO_INT'] # 同一拆分操作的首尾任务行号 ord_pl_min = splitdf.iloc[i]['MinROW#'] ord_pl_max = splitdf.iloc[i]['MaxROW#'] spltMin = all_tasks[order_id, ord_pl_max].end - all_tasks[order_id, ord_pl_min].start split_minimize.append(spltMin) for job_id, job in enumerate(jobs_data): for task_id, task in enumerate(job): zName = "z%i_%i_%i" % (i, job_id, task_id) z = model.NewBoolVar(zName) model.Add(all_tasks[job_id, task_id].end < all_tasks[order_id, ord_pl_min].start).OnlyEnforceIf(z) model.Add(all_tasks[job_id, task_id].start > all_tasks[order_id, ord_pl_max].end).OnlyEnforceIf(z.Not())
问题现象
上述方案多数情况下能保证拆分任务连续调度,但偶尔仍会出现其他任务穿插进拆分任务组的情况。我曾尝试用AddCircuit强制任务排序但未成功,想请教如何确保拆分后的任务始终连续,不会被其他任务打断?
内容的提问来源于stack exchange,提问作者Wojtek Gadek
相关产品推荐
相关产品推荐

