python - 护士调度问题或工具,在某些日子添加不同的轮类时间

标签 python or-tools

我正在修改 here 中的代码我希望能够为某一天添加​​不同长度的轮类。(例如,我希望周五/第 4 天只有 2 个轮类)。我的代码不断以错误代码结束。我相信这是由于我设置的限制存在一些内部问题。

我在 StackOverflow 上看到了几篇关于类似程序的帖子,但找不到能解决我的具体问题的帖子。

from ortools.sat.python import cp_model

class employeePartialSolutionPrinter(cp_model.CpSolverSolutionCallback):
    """Print intermediate solutions."""
    def __init__(self, shifts, num_employee, num_days, num_shifts, sols):
        cp_model.CpSolverSolutionCallback.__init__(self)
        self._shifts = shifts
        self._num_employee = num_employee
        self._num_days = num_days
        self._num_shifts = num_shifts
        self._solutions = set(sols)
        self._solution_count = 0

    def on_solution_callback(self):
        self._solution_count += 1
        if self._solution_count in self._solutions:
            print('Solution %i' % self._solution_count)
            for d in range(self._num_days):
                print('Day %i' % d)
                for n in range(self._num_employee):
                    is_working = False
                    for s in range(self._num_shifts):
                        if self.Value(self._shifts[(n, d, s)]):
                            is_working = True
                            print('  Employee %i works shift %i' % (n, s))
                    if not is_working:
                        print('  Employee {} does not work'.format(n))

    def solution_count(self):
        return self._solution_count
model = cp_model.CpModel()
solver = cp_model.CpSolver()

num_employee = 5
num_shifts = 5
num_days = 5
all_employee = range(num_employee)
all_shifts = range(num_shifts)
all_days = range(num_days)

# Normal Hours
# Monday-Thursday Shift 0-4
# Friday Shift 0-1
friday_deduct = 3

shifts = {}
for n in all_employee:
    for d in all_days:
        if d == 4:
            for s in range(num_shifts-friday_deduct):
                shifts[(n, d, s)] = model.NewBoolVar('shift_n%id%is%i' % (n, d, s))
        else:
            for s in all_shifts:
                shifts[(n,d,s)] = model.NewBoolVar('shift_n%id%is%i' % (n,d,s))


"""
Constraints (Normal Time)
"""
# Each Shift is assigned to a single person per day
# Shift 2 need to be assigned to 3 person
# Shift 1 and 3 need to be assigned to 2 person
for d in all_days:
    if d == 4:
        for s in range(num_shifts-friday_deduct):
            if s == 1:
                model.Add(sum(shifts[(n, d, s)] for n in all_employee) == 2)
            else:
                model.Add(sum(shifts[(n, d, s)] for n in all_employee) == 1)
    else:
        for s in all_shifts:
            if s == 2 :
                model.Add(sum(shifts[(n,d,s)] for n in all_employee) == 3)
            elif s == 3 or s == 1:
                model.Add(sum(shifts[(n, d, s)] for n in all_employee) == 2)
            else:
                model.Add(sum(shifts[(n,d,s)] for n in all_employee) == 1)

#Each nurse works at most 10 shift per week, at least 4 shift per week
for n in range(num_employee):
    week = []
    for d in all_days:
        if d == 4:
            for s in range(num_shifts-friday_deduct):
                week.append(shifts[(n,d,s)])
            # week.append(sum(shifts[(n, d, s)] for s in range(num_shifts-friday_deduct)))
        else:
            for s in all_shifts:
                week.append(shifts[(n,d,s)])
            # week.append(sum(shifts[(n,d,s)] for s in all_shifts))
    model.Add(sum(week) >= 4)
    model.Add(sum(week) <=10)

solver.parameters.linearization_level = 0
a_few_solutions = range(5)
solution_printer = employeePartialSolutionPrinter(shifts, num_employee, 
num_days, num_shifts, a_few_solutions)
solver.SearchForAllSolutions(model, solution_printer)

这是 Pycharm IDE 的打印输出。当我从命令行运行它时,出现“Python 已停止工作”窗口。

Solution 1
Day 0
  Employee 0 does not work
  Employee 1 does not work
  Employee 2 works shift 2
  Employee 3 works shift 1
  Employee 3 works shift 2
  Employee 3 works shift 3
  Employee 3 works shift 4
  Employee 4 works shift 0
  Employee 4 works shift 1
  Employee 4 works shift 2
  Employee 4 works shift 3
Day 1
  Employee 0 works shift 2
  Employee 0 works shift 3
  Employee 0 works shift 4
  Employee 1 works shift 2
  Employee 2 works shift 1
  Employee 2 works shift 2
  Employee 2 works shift 3
  Employee 3 works shift 0
  Employee 3 works shift 1
  Employee 4 does not work
Day 2
  Employee 0 works shift 2
  Employee 0 works shift 3
  Employee 0 works shift 4
  Employee 1 works shift 0
  Employee 1 works shift 1
  Employee 1 works shift 2
  Employee 1 works shift 3
  Employee 2 works shift 1
  Employee 2 works shift 2
  Employee 3 does not work
  Employee 4 does not work
Day 3
  Employee 0 works shift 2
  Employee 0 works shift 3
  Employee 0 works shift 4
  Employee 1 works shift 1
  Employee 1 works shift 2
  Employee 1 works shift 3
  Employee 2 works shift 0
  Employee 2 works shift 1
  Employee 2 works shift 2
  Employee 3 does not work
  Employee 4 does not work
Day 4

Process finished with exit code -1073740791 (0xC0000409)

最佳答案

您的回调有一个关键错误(第 4 天只有 2 个类次):

for s in range(self._num_shifts):
    if self.Value(self._shifts[(n, d, s)]):

一个简单的检查就可以了:

if (n, d, s) in self._shifts and self.Value(
    self._shifts[(n, d, s)]
):

但是你绝对应该看看 Laurent 建议的另一个例子。 https://github.com/google/or-tools/blob/master/examples/python/shift_scheduling_sat.py

关于python - 护士调度问题或工具,在某些日子添加不同的轮类时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57641711/

相关文章:

python - 什么类型的可变对象集合可以让我快速删除 python 中的项目?

python - 使用 Python 请求测量网站加载时间

windows - Google.OrTools.dll 在 Windows 容器中不起作用

python - 向 cp_model、ortools 添加多项选择约束

python - 是否可以仅使用一个整数变量使用 or-tools 来计算 argmax?

python - 使用重复项约束优化

python - django数据库查询日志行号

python - 什么是 'async_generator'?它与 Python 3.6 中的 'coroutine' 有何不同?

python - 将 csv 文件与 pySpark 进行比较

python - OR 工具始终返回非常次优的 TSP 解决方案