Skip to content

Unavailable Items

supix edited this page Apr 30, 2017 · 17 revisions

While computing a workshift scheme, you have to take into account employee unavailabilities. An employee cannot work at all when she is unavailable.

Employee unavailable in a day range

If the first employee is unavailable in days from 0 to 4 (i.e. the first 5 days of the scheme) you can set the problem as follows.

var problem = ProblemBuilder.Configure()
  ...
  .Making.Item(0)
    .UnavailableForAllSlots()
    .InDays().From(0).To(4)
  .Build();

A solution is the following.

Fitness: 0,943880319595337
Evaluated solutions: 118800
  -,  -,  -,  -,  -,  6,  4, 11,  -,  3,  8,  5, 10,  -,  9,  8,  6, 10,  -,  4,  9, 11,  -,  5,  8, 13,  -,  5,  1,  1
  9,  5,  0, 10,  -,  8, 13,  -, 12,  -,  4,  8,  5, 10,  -,  3,  8, 11,  -,  6,  7,  2, 13,  -,  2,  3,  0, 13,  -,  9
  -,  2,  5,  9, 13,  -,  8,  7,  9, 11,  -,  2,  1,  6,  5, 13,  -,  -,  7,  1, 10,  -,  3, 11,  -,  7, 12,  -,  0,  7
  4,  9,  8, 12,  -, 11,  -,  1,  2,  7, 11,  -,  9,  5, 11,  -,  2,  9,  8, 10,  -,  1,  4, 13,  -,  1,  5, 11,  -,  8
  7,  8, 12,  -, 11,  -,  5,  5,  6, 10,  -,  4,  0, 12,  -,  2, 12,  -,  9, 12,  -,  5,  8, 12,  -,  0,  9,  2,  6,  2
  1,  6, 11,  -,  7,  9,  9,  8,  0,  -,  -,  7,  6,  7, 12,  -,  7, 12,  -, 13,  -, 10,  -,  4, 10,  -,  8,  6,  2,  4
  -,  7,  4,  6,  4,  4,  -,  -, 11,  -,  2, 12,  -,  2,  0, 12,  -,  0, 11,  -,  2, 13,  -,  9, 12,  -,  3,  7,  7, 10
 13,  -,  9,  7,  9,  3,  3,  -,  -,  1,  5,  6, 11,  -,  6,  6,  4,  8, 12,  -,  -,  0,  7,  0, 13,  -, 11,  -,  8,  3
  8,  3, 13,  -,  0,  7,  7, 13,  -,  9,  6, 13,  -,  4,  1,  7,  9,  2,  -,  -,  3,  8,  5,  3,  4,  -,  -,  1, 10,  -
  -, 12,  -,  0,  2,  2,  2, 10,  -,  -,  3,  9,  8,  9, 10,  -,  -,  7,  0,  2,  4, 12,  -,  -,  0,  4,  1, 10,  -,  6
  0, 13,  -, 11,  -,  0,  0, 12,  -,  2,  0,  0, 12,  -,  3,  1,  5, 13,  -,  9, 13,  -,  0,  2,  1, 12,  -,  8,  9,  5
  3, 10,  -,  1, 12,  -,  1,  0,  4,  8,  9,  -,  -,  0,  8,  9, 11,  -,  6,  8,  5,  4, 10,  -,  -,  2,  2,  -, 13,  -
 12,  -,  1,  3,  1,  1,  6,  -,  -,  0,  1,  3, 13,  -,  4,  5, 13,  -,  3,  7, 12,  -,  6,  8,  5, 10,  -,  3, 12,  -
 10,  -,  2,  8,  5, 13,  -,  4,  8,  6, 12,  -,  3,  8, 13,  -, 10,  -,  4,  0,  6,  7,  2,  -,  -,  9,  6,  0,  4, 11
  6,  4, 10,  -,  6, 12,  -,  3,  1,  4, 10,  -,  4,  1,  2,  0,  3,  -,  -,  3, 11,  -, 11,  -,  7,  8, 13,  -,  5, 13
 11,  -,  6, 13,  -,  5, 10,  -, 10,  -,  7, 11,  -,  3,  7, 10,  -,  3, 13,  -,  0,  9, 12,  -,  3,  6,  4,  4, 11,  -
  5, 11,  -,  4,  8, 10,  -,  9,  3, 12,  -,  1,  2, 13,  -, 11,  -,  6,  2,  5,  8,  6,  -,  -,  6, 11,  -,  9,  3, 12
  2,  1,  7,  2, 10,  -,  -,  2,  5,  5, 13,  -,  7, 11,  -,  4,  1,  4,  5, 11,  -,  -,  9,  7, 11,  -,  7, 12,  -,  0

As you can see, in the first five days the first employee does not work: her shifts are empty.

Employee unavailable for a shift range

Sometimes an employee cannot do only certain shifts, e.g. a shift she is unable for or the overnight shift. Considering that the overnight shifts are those whose index ranges from 10 to 13, the problem can be configured as follows.

var problem = ProblemBuilder.Configure()
  .WithDays(30)
  .WithSlots(14)
  .WithItems(18)
  .WithMaxConsecutiveWorkingDaysEqualTo(5)
  .RestAfterMaxWorkingDaysReached(2)
  .AssigningLength(2).ToSlots().From(10).To(13)
  .Making.Item(0)
    .UnavailableForSlots().From(10).To(13)
    .Always()
  .Build();

The corresponding solution is the following.

Fitness: 0,950853645801544
Evaluated solutions: 127700
  8,  0,  7,  5,  9,  -,  -,  9,  5,  5,  5,  2,  -,  -,  9,  3,  8,  3,  5,  -,  -,  6,  8,  7,  1,  2,  -,  -,  6,  6
  -, 12,  -,  8,  0,  4, 13,  -,  7,  1,  7, 12,  -,  4, 13,  -, 12,  -,  4, 13,  -,  2,  1,  1,  0,  -,  9,  2,  0,  5
  1,  6,  3,  7,  2,  -,  -,  7,  8, 13,  -,  5,  2,  0,  2,  4,  -,  -,  7, 12,  -,  9, 12,  -,  3,  9,  8, 11,  -,  0
  3, 10,  -,  4,  3,  2, 11,  -,  6, 10,  -, 13,  -,  6,  0,  7,  5,  9,  -,  -,  5,  0, 10,  -,  5,  3,  2,  1, 12,  -
  9,  2, 10,  -, 13,  -,  5, 11,  -,  3,  3, 10,  -,  5,  1,  6, 11,  -,  9,  7,  7,  3,  3,  -,  -,  4,  5, 13,  -,  8
  -,  8, 13,  -,  5, 13,  -,  6, 12,  -,  6,  4, 12,  -,  6,  0, 10,  -,  2,  5, 11,  -,  7,  9, 13,  -,  3,  9,  3, 10
  5, 13,  -,  0,  4, 10,  -,  8, 11,  -, 11,  -,  9,  1,  5, 11,  -,  6,  3,  8, 12,  -,  4,  4, 12,  -,  7,  6,  1,  7
 11,  -,  8,  6, 10,  -,  9,  3,  0, 12,  -, 11,  -,  7,  4, 10,  -, 10,  -,  4,  0,  5, 11,  -,  6,  1, 12,  -,  2, 13
 13,  -, 11,  -,  8,  8,  7,  0,  2,  -,  -,  0,  7,  3, 12,  -,  0,  5, 10,  -,  9,  7,  0, 11,  -,  6,  1, 12,  -,  2
  4,  3, 12,  -, 11,  -,  0, 12,  -,  2,  1,  7, 13,  -,  3,  9,  1, 13,  -,  2, 10,  -,  9,  2,  9, 10,  -, 10,  -,  4
  6,  5,  0, 10,  -,  7,  4,  1, 13,  -,  9,  3,  5, 13,  -,  2,  6, 12,  -, 10,  -, 11,  -,  8,  8, 13,  -,  3,  9, 12
  -,  9,  1,  3, 12,  -, 10,  -,  3,  7, 12,  -,  8, 12,  -,  8,  2,  4, 12,  -,  6, 10,  -,  6,  2,  7, 13,  -,  4,  1
  0,  4,  6, 13,  -,  9,  2, 10,  -,  6,  0,  1,  4,  8,  -,  -,  7,  8,  0,  1,  4,  -,  -, 10,  -, 11,  -,  5,  7, 11
  -,  7,  5, 12,  -,  0,  3, 13,  -,  4, 13,  -,  6,  9,  8, 12,  -, 11,  -,  6, 13,  -,  2,  5,  4, 12,  -,  0,  8,  3
  7,  1,  9, 11,  -,  1,  1,  5, 10,  -,  2,  6,  0, 11,  -, 13,  -,  1,  1,  0,  1,  4,  -,  -,  7,  5,  4,  8, 11,  -
 12,  -,  4,  2,  1,  6, 12,  -,  -,  0,  4,  8,  3, 10,  -,  -,  9,  7, 11,  -,  8, 12,  -,  0, 11,  -,  0,  7, 13,  -
 10,  -,  2,  9,  6, 11,  -,  2,  9,  8,  8,  9,  -,  -,  7,  5,  4,  0,  6,  -,  -,  1,  5, 13,  -,  0,  6,  4, 10,  -
  2, 11,  -,  1,  7, 12,  -,  4,  4, 11,  -,  -,  1,  2, 10,  -,  3,  2, 13,  -,  2, 13,  -, 12,  -,  8, 10,  -,  5,  9

As you can see, the first employee never covers a slot numbered from 10 to 13.

You can mix item unavailabilities configuration rules in many different ways. For example in a very complex case you can even write something as:

var problem = ProblemBuilder.Configure()
  ...
  .Making.Items().From(5).To(7)
    .UnavailableForSlots().From(0).To(4)
    .InDays().From(10).To(15)
  ...;

Composing item unavailabilities rules

Item unavailabilities configuration rules can be composed through method chaining. For example, if the first employee never can do night shifts and second employee must do nights from 5-th to 9-th day, you can configure the problem as follows.

var problem = ProblemBuilder.Configure()
  ...
  .Making.Item(0)
    .UnavailableForSlots().From(10).To(13)
    .Always()
  .Making.Item(1)
    .UnavailableForSlots().From(0).To(9)
    .InDays().From(5).To(9)
  ...;

The given solution is the following.

Fitness: 0,948448240756989
Evaluated solutions: 122900
  7,  4,  2,  5,  8,  -,  -,  9,  3,  1,  6,  2,  -,  -,  5,  1,  7,  6,  8,  -,  -,  1,  0,  9,  2,  0,  -,  -,  7,  4
  -,  3,  9,  4, 10,  -, 12,  -, 10,  -,  5,  7,  8, 13,  -,  4,  9, 12,  -,  3,  2, 11,  -, 13,  -,  6,  7, 11,  -, 11
  0,  9, 12,  -,  2, 12,  -,  1,  7,  4,  2,  1,  -,  -,  9,  8, 13,  -,  4,  5,  8,  0, 13,  -,  -, 11,  -, 10,  -,  1
  8, 13,  -,  6,  5,  6, 10,  -, 12,  -,  0, 13,  -,  7,  1, 11,  -, 10,  -,  4,  7, 12,  -,  7,  3,  3, 12,  -,  8,  8
 13,  -,  1, 10,  -,  2,  0,  5,  8, 10,  -,  -, 11,  -,  7,  3,  4,  0,  5,  -,  -,  7,  3,  2, 13,  -,  6,  6,  4,  3
  4,  2,  3,  1, 13,  -,  -,  2,  9,  5, 13,  -,  4,  1, 11,  -,  5, 11,  -,  8,  6, 13,  -,  5,  0,  8, 11,  -, 13,  -
  6,  5,  6, 11,  -,  8,  3, 12,  -,  0,  8,  5, 10,  -,  0, 12,  -,  4,  2,  7, 10,  -,  7,  1, 11,  -,  9,  3, 12,  -
  -, 12,  -,  3,  4,  3, 11,  -,  6,  9,  3, 11,  -, 12,  -,  7, 10,  -,  6,  0, 11,  -,  6, 12,  -,  2,  0,  8,  2, 13
  -,  1,  8,  0, 11,  -,  7, 10,  -,  2,  4, 12,  -,  4,  6,  9, 12,  -,  1, 11,  -,  2,  8,  8,  9, 10,  -,  -,  3,  9
  2,  7, 10,  -,  1, 13,  -,  4, 11,  -,  1,  8, 12,  -, 10,  -,  2,  8, 13,  -,  5,  3,  9,  4,  6,  -,  -,  9,  0,  0
  5, 10,  -,  7,  9, 11,  -,  0,  0, 13,  -,  4,  9, 10,  -,  5,  6, 13,  -,  6,  3,  8, 12,  -,  8, 13,  -,  4, 10,  -
 10,  -,  0,  2,  3,  0,  9,  -,  -,  7, 12,  -,  5,  6,  4,  0,  3,  -,  -, 10,  -,  6, 10,  -,  4,  9,  5,  5, 11,  -
  -,  0, 11,  -,  7,  4, 13,  -,  5,  8, 10,  -,  2,  3, 13,  -,  0,  1,  3,  1,  9,  -,  -,  6, 12,  -,  2, 12,  -,  7
  3,  8, 13,  -, 12,  -,  5, 13,  -,  6,  7,  6,  1,  9,  -,  -, 11,  -,  0,  9,  0,  4,  2,  -,  -,  1,  3,  0,  5, 12
  9, 11,  -, 13,  -,  5,  2,  3,  4, 11,  -,  -,  0,  5,  2, 13,  -,  7, 10,  -,  1,  5, 11,  -,  7,  7,  8, 13,  -,  6
 11,  -,  5,  8,  6,  7,  1,  -,  -,  3,  9,  0, 13,  -,  3,  6,  1,  5,  7,  -,  -,  9,  5, 11,  -,  4,  1,  2,  9, 10
 12,  -,  4,  9,  0, 10,  -,  6,  2, 12,  -,  9,  7,  0,  8, 10,  -,  -, 11,  -,  4, 10,  -,  3,  1,  5, 13,  -,  1,  2
  1,  6,  7, 12,  -,  9,  4,  7, 13,  -, 11,  -,  3, 11,  -,  2,  8,  9, 12,  -, 13,  -,  1,  0,  5, 12,  -,  7,  6,  5

The first employee covers just slots from 0 to 9; the second employee covers just slots from 10 to 13 (or otherwise she rests) in days from 6-th to 10-th (whose zero-based index ranges from 5 to 9).

Item unavailability affects preceeding days

Let's consider one more case. Items from 0 to 4 are unavailable for overnight shifts in days from 3 to 6.

var problem = ProblemBuilder.Configure()
  .WithDays(30)
  .WithSlots(14)
  .WithItems(18)
  .WithMaxConsecutiveWorkingDaysEqualTo(5)
  .RestAfterMaxWorkingDaysReached(2)
  .AssigningLength(2).ToSlots().From(10).To(13)
  .Making.Items.From(0).To(4)
    .UnavailableForSlots().From(10).To(13)
    .InDays().From(3).To(6)
  .Build();

Here is a solution.

Fitness: 0,948942303657532
Evaluated solutions: 122400
 13,  -,  1,  7,  -,  6,  2,  5, 10,  -,  4,  6,  9,  3,  2,  -,  -,  5,  1, 12,  -,  4, 12,  -,  8,  1, 10,  -,  5,  1
  -,  3,  5,  0,  7,  5,  -,  -,  3,  6,  5,  3,  8,  -,  -,  4,  3,  3,  8,  0,  -,  -,  0,  2,  6, 12,  -,  2,  4,  9
  7,  4,  8,  3,  0,  -,  -,  6,  0,  9,  2,  1,  -,  -,  5, 10,  -,  2, 10,  -,  1, 11,  -,  5,  4,  3,  4, 11,  -,  -
 10,  -,  6,  4,  8,  1,  1,  -,  -,  4,  3,  9, 12,  -,  0,  9,  5,  1,  9,  -,  -,  7,  9, 13,  -,  7,  2,  3, 10,  -
  3, 11,  -,  9,  5,  0,  4, 12,  -,  -,  8,  8, 10,  -,  8,  7,  4,  9, 12,  -,  -,  2,  7,  9, 10,  -, 11,  -,  6,  2
  5,  2,  0,  8, 11,  -,  -,  1,  5,  2,  -,  4,  2,  5, 10,  -,  0,  4,  7, 10,  -, 12,  -,  8,  7,  9, 12,  -, 11,  -
  0,  9, 10,  -,  4,  3,  0, 11,  -, 10,  -, 12,  -,  7, 11,  -,  9,  7, 13,  -,  4,  0,  6, 12,  -,  2,  1,  6,  8,  6
 11,  -,  7, 11,  -, 12,  -,  7, 13,  -, 13,  -,  0,  4,  9, 12,  -,  6,  3,  2, 10,  -,  8,  3,  0, 13,  -,  9,  2,  4
  1,  5, 13,  -,  2,  4, 12,  -,  9,  0,  7, 10,  -,  8, 13,  -,  7, 12,  -,  8,  0,  3, 13,  -,  9,  0,  5, 13,  -, 10
  8,  7,  9,  1,  3,  -,  -,  9,  2, 13,  -,  7,  3,  6, 12,  -, 10,  -,  2,  6, 11,  -,  4,  4,  5,  5,  6,  -,  -, 11
  -,  1,  2, 12,  -, 10,  -,  4,  6, 12,  -,  5, 11,  -,  7, 11,  -,  8,  0, 11,  -,  8, 10,  -,  2, 10,  -,  0,  1, 13
  9, 12,  -,  6,  1,  7, 11,  -,  4,  3,  6, 13,  -, 12,  -,  2, 13,  -,  6,  3,  2,  6, 11,  -,  -,  8,  3, 10,  -,  3
  6, 10,  -, 10,  -,  2,  7,  2, 11,  -, 12,  -,  4, 10,  -,  0,  6,  0,  5, 13,  -,  -,  1,  6, 13,  -, 13,  -,  9,  8
  -,  8, 12,  -, 10,  -,  3,  8, 12,  -,  9,  0,  6, 11,  -,  3, 12,  -,  4,  4,  7,  1,  2,  -,  -,  6,  0,  1,  7,  5
  4, 13,  -,  2, 12,  -, 10,  -,  7,  8,  1, 11,  -,  9,  1, 13,  -, 11,  -,  5,  3, 10,  -,  0, 12,  -,  9,  7,  3,  0
  2,  6,  4, 13,  -, 11,  -,  0,  8,  5, 11,  -,  7,  2,  3,  8, 11,  -,  -,  1,  5,  9,  5, 10,  -,  -,  7, 12,  -, 12
 12,  -,  3,  5,  9, 13,  -,  3,  1,  1,  0,  2,  -,  -,  6,  1,  8, 10,  -,  7,  9, 13,  -,  7,  3, 11,  -,  4, 13,  -
  -,  0, 11,  -,  6,  8,  6, 10,  -,  7, 10,  -, 13,  -,  4,  6,  2, 13,  -,  9,  8,  5,  3, 11,  -,  -,  8,  8,  0,  7

As you can see, in days from 3 to 6 (columns from the 4-th to the 7-th) the first five employees do not cover the overnight shift (indexes from 10 to 13).

But there is more.

Such employees do not cover the overnight slot even in day with index 2 (i.e. the day just before unavailabilities start). Infact otherwise such a night would overrun the day of unavailability. In other words, item unavailability rules take into account slot lenghts to avoid interferences with preceeding long shifts.