OR-TOOLS 作业车间调度 - 拆分较长的任务并在轮班之间将它们保持在一起

问题描述 投票:0回答:1

使用 OR-TOOLS CP-SAT 我发现了一个任务之间侵入其他任务的问题。在我的模型中,有机器按 1、2、3 班倒工作,周末不工作。

#intervals for non-working time depending on shift model:
#1 shifts 2 PM - 6 & weekends, 2 shifts 10 PM - 6 AM & weekends, 3 shifts weekends
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:
                    #print('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))

有些任务的时间超过 1 甚至 2 个班次,所以我决定将它们划分为准备时间,并将每 1 件作为单独的任务,例如工单中的一项操作有 15 件 = 16 个任务。然后我希望该操作中的每项任务都将被依次安排,而不会受到其他工单中的其他任务的干扰。

为了实现此目的,我使用

OnlyEnforceIf
,在该活动中的第一个任务开始之前或该活动中的最后一个任务结束之后,对不属于此操作(活动)的所有任务进行排队。我还定义了目标
model.Minimize(splitMin)
以最小化拆分活动中第一个任务和最后一个任务之间的距离。

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']
        #first and last row with the same split activity
        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())

在大多数情况下,它工作正常,并且求解器可以对任务进行排队,而无需在其间输入其他任务。但也有这样的情况:

Schedule for one machine working in 2 shifts model

我认为

OnlyEnforceIf
是一个“软”约束。我尝试使用
AddCircuit
,因为我认为它可以强制正确的队列,但我失败了。您能告诉我,我应该怎样做才能将这些任务放在一起?

python or-tools constraint-programming cp-sat
1个回答
0
投票

我推荐另一种方法,即根据开始计算间隔的长度,并且实际上不创建中断。

请参阅 https://github.com/google/or-tools/blob/stable/ortools/sat/docs/scheduling.md#intervals-spanning-over-breaks-in-the-calendar

© www.soinside.com 2019 - 2024. All rights reserved.