-
Notifications
You must be signed in to change notification settings - Fork 2
Unavailable Items
While computing a workshift scheme, you have to take into account employee unavailabilities. An employee cannot work at all when she is unavailable.
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.
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)
...;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).
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.
NaturalShift is a .NET library released under the terms of AGPL-3.0 license. esposito.marce@gmail.com
The author will not be held responsible for any damage or losses or for any implications whatsoever resulting from using this this source code or the program compiled out of this source code. Use it at your own risk.
Rest after an overnight shift: slot lengths
Employees must rest: MaxConsecutiveWorkingDays
Less items needed for certain days: slot closures
Items can be on vacation: unavailable items
Items do better or worse certain slots: items aptitudes
Shift Y is better after shift X: consecutive slots aptitude
People love and ate each other: cross item aptitudes
Not all shifts are equally important: slot values
Not all shifts are equally heavy: slot weights
How to cover shift X and Y simultaneously: compatible slots