Последовательные дни работ - PullRequest
0 голосов
/ 16 апреля 2019

Я пытаюсь сделать планировщик с помощью or-tool. В настоящее время я застрял со следующей проблемой. Я хочу, чтобы сотрудники работали не менее n дней подряд.

Я пробовал это:

for n in all_nurses:
    for d in all_days:
        if sum([shifts[(n, d, 0)], shifts[(n, d, 1)], shifts[(n, (d), 2)]]) == 1: # if employee works this day, then he should works the 2 days after too
            model.Add(sum([shifts[(n, d+1, 0)], shifts[(n, (d+1), 1)], shifts[(n, (d+1), 2)]]) == 1)
            model.Add(sum([shifts[(n, d+2, 0)], shifts[(n, (d+2), 1)], shifts[(n, (d+2), 2)]]) == 1)

Он работает с 3 сотрудниками, но если я добавлю больше сотрудников (10), модель не найдет никаких решений.

У вас есть идея?

РЕДАКТИРОВАТЬ: Я попытался реализовать пример на https://github.com/google/or-tools/blob/39f44709bba203f5ff3bc18fab8098739f189a6d/examples/python/shift_scheduling_sat.py#L61 Но я не смог .. Вот моя попытка:

for n in all_nurses:
    works = [sum(shifts[n, d, s] for s in all_shifts) for d in all_days]
    print (works)
    for length in range(3, 4):
        for start in range(len(works) - length - 1):
            model.AddBoolOr(negated_bounded_span(works, start, length))
    for start in range(len(works) - 5 - 1):
        model.AddBoolOr([works[i].Not() for i in range(start, start + hard_max + 1)])

Я получаю ошибку:

AttributeError: '_SumArray' object has no attribute 'Not'

Я вынужден составлять сумму смен дня, поскольку мне нужны последовательные дни работы, но не в конкретную смену.

Кроме того, если у кого-то есть хорошее объяснение о том, как работает метод здесь: https://github.com/google/or-tools/blob/39f44709bba203f5ff3bc18fab8098739f189a6d/examples/python Потому что я действительно не понимаю, как AddBoolOr гарантирует, что у нас есть последовательность истинных последовательных логических значений

РЕДАКТИРОВАТЬ 2:

Мне удалось реализовать решение на github. Но у меня все еще есть проблема. Я создал зеркало моих дней / смен, как это:

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


#Creation du mirroir
for n in all_nurses:
    for d in all_days:
        model.Add(sum(shifts[(n, d, s)] for s in all_shifts) == mirrors[(n,d)])

Так, что для медсестры 1: 0010 0100 0010 1000 0000 0000 0000 Зеркало будет: 1 1 1 1 0 0 0

Затем я применил метод, чтобы несколько дней подряд работал над моим зеркалом, поскольку он связан с моей основной таблицей.

for n in all_nurses:
    works = [mirrors[n,d] for d in range(num_days)]
    for length in range(1, 3):
        for start in range(len(works) - length - 1):
            model.AddBoolOr(negated_bounded_span(works, start, length))
    for start in range(len(works) - 5 - 1):
        model.AddBoolOr([works[i].Not() for i in range(start, start + 5 + 1)])

Теперь я ожидаю, что результат не будет иметь никакого периода работы, который не будет между 3 и 5. Но, тем не менее, когда я печатаю решение, для одной медсестры я получил следующий результат:

0010 0010 0010 0010 0010 0000 0000 0000 0001 0000

А для зеркала это:

1111100010

Это не должно быть возможно, поскольку период работы составляет от 3 до 5.

У вас есть идея? Спасибо!

1 Ответ

0 голосов
/ 16 апреля 2019

Это реализовано в виде мягкой версии в shift_scheduling_sat.py

См .: https://github.com/google/or-tools/blob/39f44709bba203f5ff3bc18fab8098739f189a6d/examples/python/shift_scheduling_sat.py#L61

in

    # Forbid sequences that are too short.
    for length in range(1, hard_min):
        for start in range(len(works) - length - 1):
            model.AddBoolOr(negated_bounded_span(works, start, length))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...