Невозможное решение, безусловно выполнимое - CPLEX - PullRequest
0 голосов
/ 29 мая 2019

По сути, у меня есть два сотрудника, каждый из которых может быть распределен по одному из двух шаблонов списка, который, в свою очередь, назначает набор смен для каждого сотрудника.

Назначает сотруднику шаблон списка -> этот сотрудникмогут работать только смены, указанные в этом списке, и должны работать все из них.

Для этого у меня есть ограничение, которое в основном гласит, что сумма всех смен, которые выполняет каждый сотрудник, должна равняться входному значению shiftsPerRP,Поэтому, если для, например, сотрудника Аллана выбран шаблон списка, например 0, то Аллан должен работать ровно в 45 смен.

Однако это ограничение продолжает сбой и приводит к невозможному решению.Я не могу понять, что мне здесь не хватает.Любая помощь приветствуется.

Соответствующий DAT:

days={
    1, 2, 3, 4, 5, 6, 7
}

People = {
    Allan,
    Joe,
};

rosterPatterns = {
    0,1
};


shiftsPerRP = {
    <0,45>
    <1,5>
};

Skills= {
    A, 
    B, 
    C
};

Соответствующий код:

dvar boolean Assign[days][Hours][People][Skills];   // Indicates a shift assignment

range Hours = 0..23; 

forall(h in Hours, d in days, p in People, rp in rosterPatterns, shiftsInRP in shiftsPerRP : shiftsInRP.ID == rp)
      sum(s in Skills)
            Assign[d][h][p][s] == shiftsInRP.shifts;

1 Ответ

2 голосов
/ 29 мая 2019

Чтобы проанализировать это, пометьте ваши ограничения (см. Добавленный 'c1'):

forall(h in Hours,
       d in days,
       p in People,
       rp in rosterPatterns,
       shiftsInRP in shiftsPerRP
       : shiftsInRP.ID == rp)
c1:
      sum(s in Skills)
            Assign[d][h][p][s] == shiftsInRP.shifts;

С этим OPL следует вычислить минимальный конфликт, который показывает, какие ограничения недопустимы.Делая это (в командной строке), я обнаружил, что самое первое сгенерированное ограничение недопустимо.Ограничение имеет только три переменные с левой стороны, но с правой стороны - 5. Это никогда не может быть удовлетворено.

Учитывая, что в вашем наборе только три элемента Skills, леваяСторона стороны ограничения всегда будет иметь 3 переменные.Таким образом, он может принимать значения в {0, 1, 2, 3}.Если для любого кортежа shifts имеет значение больше 3, то это ограничение, очевидно, не может быть выполнено.

РЕДАКТИРОВАТЬ : похоже, вы перепутали то, что должно войти в forall и что должно идти в sum.Чтобы сформулировать это правильно, я думаю, что вам понадобится вспомогательная переменная

dvar boolean RosterAssigned[People][rosterPatterns];

, которая равна 1, если человек назначен в список, и 0 в противном случае.При этом вы можете сформулировать ограничение как

forall(p in People)
  sum(h in Hours, s in Skills, d in days)
     Assign[d][h][p][s]
     == sum(rp in rosterPatterns, shiftsInRP in shiftsPerRP : shitsInRP.ID == rp) (RosterAssigned[p][rp] * shiftsInRP.shifts);

В левой части указано количество смен, которые человек p фактически работает.В правой части указано количество сдвигов, требуемых по шаблону реестра.Конечно, вы также должны добавить ограничения, которые гарантируют, что каждому сотруднику будет присвоен ровно один список.

...