微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么ortools 严格设置约束?

如何解决为什么ortools 严格设置约束?

我经历了 google ortools scheduling tutorial 并创建了稍微不同的约束。

假设我们有一个 df,表示以下内容

  1. 每位护士只能在预先分配的班次上工作。根据表格,护士 0 必须在 0 或 1 班工作,护士 2 必须只在 2 班工作,依此类推。
  2. 此外,我添加了以下约束:“如果nurse_0 需要shift_0,那么她必须需要shif_1”。它由“is_child”列显示 - shift_1 是 child_shift for shift_0 fornurse_0。
 df_dict = {
            "slot_number":[1,1,2,3],"asset_name":['0','1','0','2'],"is_child":["No","No","Yes",'No','No']
           }

  df = pd.DataFrame.from_dict(df_dict)

创建变量和模型:

num_nurses = 3
num_shifts = 3
all_nurses = range(num_nurses)
all_shifts = range(num_shifts)

model = cp_model.CpModel()

shifts = {}
for n in all_nurses:
    for s in all_shifts:
        shifts[(n,s)] = model.NewBoolVar('shift_n%is%i' % (n,s)) 

一名护士只能轮班:

for s in all_shifts:
    model.Add(sum(shifts[(n,s)] for n in all_nurses) == 1)

我的约束

# whether the slot (key) have any children in other slots
children = {0: [1],1: [],2: []} 
#  what nurses are considered the children (values) in which slot (key)
nurse_child_sched = {0:[],1:[0],2:[]} 
# In this case if nurse 0 take slot 0,then she must take slot 1 too.
for s in all_shifts:
    for n in all_nurses:
        if (children[s]):
            for child in children[s]:
                if n in nurse_child_sched[child]:
                    model.Add((shifts[(n,s)] + shifts[(n,child)])==2)
                    print(f"{s}-parent_slot and {child}-child_slot were connected for nurse {n}")

用于创建时间表和显示解决方案的代码

class NursesPartialSolutionPrinter(cp_model.cpsolverSolutionCallback):
"""Print intermediate solutions."""

def __init__(self,shifts,num_nurses,num_shifts,sols):
    cp_model.cpsolverSolutionCallback.__init__(self)
    self._shifts = shifts
    self._num_nurses = num_nurses
    self._num_shifts = num_shifts
    self._solutions = set(sols)
    self._solution_count = 0

def on_solution_callback(self):
    if self._solution_count in self._solutions:
        print('Solution %i' % self._solution_count)

        for n in range(self._num_nurses):
            is_working = False
            for s in range(self._num_shifts):
                if self.Value(self._shifts[(n,s)]):
                    is_working = True
                    print('  Nurse %i works shift %i' % (n,s))
            if not is_working:
                print('  Nurse {} does not work'.format(n))
        print()
    self._solution_count += 1

def solution_count(self):
    return self._solution_count

solver = cp_model.cpsolver()
solver.parameters.linearization_level = 0
a_few_solutions = range(5)
solution_printer = NursesPartialSolutionPrinter(shifts,a_few_solutions)

solver.SearchForAllSolutions(model,solution_printer)

最后,我得到以下结果:

Solution 0
  Nurse 0 works shift 0
  Nurse 0 works shift 1
  Nurse 1 works shift 2
  Nurse 2 does not work

Solution 1
  Nurse 0 works shift 0
  Nurse 0 works shift 1
  Nurse 1 does not work
  Nurse 2 works shift 2

Solution 2
  Nurse 0 works shift 0
  Nurse 0 works shift 1
  Nurse 0 works shift 2
  Nurse 1 does not work
  Nurse 2 does not work

不过,按照我的逻辑,至少也必须有下面的解决方案。我意识到,我的约束表明模型将nurse_0 放在shift_0 上,但我只需要放置两个插槽之间的关系,以防nurse_0 放在第一班,否则没有约束。提前致谢。

Solution x
  Nurse 1 works shift 0
  Nurse 0 works shift 1
  Nurse 0 works shift 2
  Nurse 1 does not work
  Nurse 2 does not work

解决方法

附注:

一名护士只能轮班:

  for s in all_shifts:
    model.Add(sum(shifts[(n,s)] for n in all_nurses) == 1)

这里你写了“每个班次只分配给一名护士”

如果你想表达“一个护士只能轮班”,你应该写:

for n in all_nurses:
    model.Add(sum(shifts[(n,s)] for s in all_shifts) == 1)

注意:但在这种情况下,由于护士只工作一个班次,因此不可能进行儿童班次,所以我猜您的代码没问题,而不是注释...

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。