[英]Google ortools CP-SAT maximize takes too long
I am trying to solve a scheduling problem.我正在尝试解决调度问题。 As input I have the number of workers and the number of shifts.作为输入,我有工人的数量和轮班的数量。
After that I place all the constraints, including:之后,我放置了所有约束,包括:
I then try to maximize a given sequence of shifts.然后我尝试最大化给定的班次序列。
For example, I can receive the sequence: 123BBBB.例如,我可以收到序列:123BBBB。 This means that I must maximize the appearance of this sequence for each worker in their calendar.这意味着我必须在他们的日历中为每个工人最大化这个序列的外观。
I calculate the schedule for the whole year (so let's say 365 days) for each worker.我计算每个工人全年的时间表(比如说 365 天)。 I tried to make bools for each possible sequence: so for the days in range(1, length(sequence)), in range(2, length(sequence))), etc.我试图为每个可能的序列制作布尔值:所以对于范围(1,长度(序列)),范围(2,长度(序列)))等的天数。
And then I add as a constraint that the sum of shifts from today to len(sequence)
is len(sequence)
.然后我添加一个约束,即从今天到len(sequence)
的移位总和是len(sequence)
。 So I have the shifts represented as bools too ( shifts[(w, d, s)]
) meaning for shifts[(0, 3, 0)]
that worker 1 in day 3 works shift 1.因此,我也将班次表示为布尔值( shifts[(w, d, s)]
),这意味着第 3 天的工人 1 工作班次 1 的shifts[(0, 3, 0)]
。
The constraint for the given sequence is OnlyEnforcedIf the bool created for that sequence is true.给定序列的约束是 OnlyEnforcedIf 为该序列创建的 bool 为真。 And then I try to maximize the sum of the bools created for each sequence.然后我尝试最大化为每个序列创建的布尔值的总和。
The problem: I tried running this and after 8 hours of running I gave up.问题:我尝试运行它,运行 8 小时后我放弃了。 It found me about 62 sequences, but then took too long to stop or find another one.它为我找到了大约 62 个序列,但是花了很长时间才停下来或找到另一个。 My question is: how to do this more efficiently?我的问题是:如何更有效地做到这一点?
The code:编码:
shift_requests = []
requiredShift = "111222333BBBBBB"
appearences_for_1 = 0
appearences_for_2 = 0
appearences_for_3 = 0
appearences_for_L = 0
for i in requiredShift:
if i == '1':
appearences_for_1 += 1
for i in requiredShift:
if i == '2':
appearences_for_2 += 1
for i in requiredShift:
if i == '3':
appearences_for_3 += 1
for i in requiredShift:
if i == 'B':
appearences_for_B += 1
print(appearences_for_1, appearences_for_2, appearences_for_3, appearences_for_B)
for w in range(worker):
shift_requests.append([])
poz = 0
dayz = 1
while dayz + len(requiredShift) <= 365:
shift_requests[w].append(model.NewBoolVar(f'{w}_{dayz}_{dayz + len(requiredShift)}'))
first_range = dayz + appearences_for_1
second_range = first_range + appearences_for_2
third_range = second_range + appearences_for_3
fourth_range = third_range + appearences_for_B
#shift = 5 ( 0 is shift 1, 1 is shift 2, 2 is shift 3, 3 is break, 4 is holiday)
model.Add(sum(shifts[(w, d, shift - 2 - 3)] for d in range(dayz, first_range))+
sum(shifts[(w, d, shift - 2 - 2)] for d in range(first_range, second_range))+
sum(shifts[(w, d, shift - 2 - 1)] for d in range(second_range, third_range))+
sum(shifts[(w, d, shift - 2)] for d in range(third_range, fourth_range)) == len(requiredShift))\
.OnlyEnforceIf(shift_requests[w][poz])
dayz += 1
poz += 1
model.Maximize(sum(shift_requests[w][poz] for w in range(worker) for poz in range(len(shift_requests[w]))))
For each start date d
, you can have one Boolean variable s_d
.对于每个开始日期d
,您可以拥有一个 Boolean 变量s_d
。
Imagine the pattern is '123BBB', you can have想象一下模式是'123BBB',你可以有
s_d
implies that the sequence starts at this date: s_d
表示序列从该日期开始:
model.Add(x[d] == 1).OnlyEnforceIf(s_d)
model.Add(x[d + 1] == 2).OnlyEnforceIf(s_d)
model.Add(x[d + 2] == 3).OnlyEnforceIf(s_d)
model.Add(x[d + 3] == 0).OnlyEnforceIf(s_d) # 0 == Break
model.Add(x[d + 4] == 0).OnlyEnforceIf(s_d) # 0 == Break
model.Add(x[d + 5] == 0).OnlyEnforceIf(s_d) # 0 == Break
Then maximize the number of positive s_d
.然后最大化正s_d
的数量。
worker = 5
days = 365
required_sequence_bools = []
required_sequence = "111222333BBBBBB"
for w in range(worker):
required_sequence_bools.append([])
for d in range(1, days - len(required_sequence)):
required_sequence_bools[w].append(model.NewBoolVar(f"{w}_{d}"))
for w in range(worker):
for d in range(0, days - len(required_sequence) - 1):
day = d + 1
for letter in required_sequence:
if letter == '1':
model.Add(shifts[(w, day, 0)] == 1).OnlyEnforceIf(required_sequence_bools[w][d])
elif letter == '2':
model.Add(shifts[(w, day, 1)] == 1).OnlyEnforceIf(required_sequence_bools[w][d])
elif letter == '3':
model.Add(shifts[(w, day, 2)] == 1).OnlyEnforceIf(required_sequence_bools[w][d])
elif letter == 'B':
model.Add(shifts[(w, day, 3)] == 1).OnlyEnforceIf(required_sequence_bools[w][d])
day += 1
model.Maximize(sum(required_sequence_bools[w][d] for w in range(worker) for d in range(0, days - len(required_sequence) - 1)))
This is what I understood from what you said and I think I didn't understand correctly because it's kind of what I did previously.这是我从你所说的内容中理解的,我认为我没有正确理解,因为这是我之前所做的。 I have 5 workers and try to start in each day with the sequence for each worker.我有 5 名工人,并尝试每天从每个工人的顺序开始。 Most likely I didn't understand what you tried to say since this will most likely take more than one day to solve on 8 cores.很可能我不明白你想说什么,因为这很可能需要一天以上的时间才能解决 8 个内核。 Also sorry for posting this as an answear but I didn't know how to post code in the comment section.也很抱歉将其发布为 answear,但我不知道如何在评论部分发布代码。 PS: by worker I mean a person that works shifts in my algorithm not a processor core. PS:我所说的工人是指一个在我的算法中工作的人,而不是处理器核心。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.