Doctor Planning

The Doctor Planning example was submitted by us to the dmcommunity.org as a challenge. The full version, together with other submitted solutions, can be found on this page. Its specification is as follows:

Doctor Planning

In a hospital, there has to be a doctor present at all times. In order to make sure this is the case, a planning is made for the next 7 days, starting on a monday. Each day consists of three shifts: an early shift, a late shift and a night shift.

Every shift needs to be assigned to a doctor. In total there are 5 doctors: every doctor has a list of available days, and some have special requirements. In general, the following rules apply:

  1. A doctor can only work one shift per day.
  2. A doctor should always be available for his shift (see table below)
  3. If a doctor has the night shift, they either get the next day off, or the night shift again.
  4. A doctor either works both days of the weekend, or none of the days.

A planning should be made in which every requirement is fulfilled.

Name Available
Fleming Friday, Saturday, Sunday
Freud Every day early or late, never night
Heimlich Every day but neven the night shift on weekends
Eustachi Every day, every shift
Golgi Every day, every shift but at max 2 night shifts

To create a cDMN model for this challenge, we start by building our glossary. From reading the description, we can see that we will need the following types:

  • Doctor
  • Day
  • Time (early, late or night)
  • Nb_shifts, to represent a number of shifts.

Thus, we create a glossary table as such:

Type
Name Type Values
Doctor String Fleming, Freud, Heimlich, Eustachi, Golgi
Day String Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
Time String Early, Late, Night
Nb Shift Int [0..21]

Next, we will need a way to assign doctors to days and shifts. Since for every pair of day and shift (e.g. “Monday” and “Early”) we need exactly 1 doctor, we use a function to do so. We also introduce functions to count the number of shifts per doctor and day, and the number of night shifts per doctor. Finally, we create one last function to represent the next day for every day.

Function
Name Type
doctor assigned to Day and Time Doctor
nb shifts of Doctor and Day Nb_Shift
nb nights of Doctor Nb_Shift
day after Day Day

The last information to include in our model is the availabilities of every doctor. For this, we implement the relation Doctor is available on Day and Time.

Relation
Name
Doctor is available on Day and Time

Now that our glossary is done, we can move on to implementing the rules. We start by first implementing every rule one by one.

Rule 1

A doctor can only work one shift per day.

This rule can be modeled as a simple constraint table. We evaluate every doctor, on every day, and state that they work at max 1 shift that day.

Rule 1
E* Doctor Day nb shifts of Doctor and Day
1 - - ≤ 1

Rule 2

A doctor should always be available for his shift.

Once again, a single constraint table suffices. We state that for every doctor, day, and time, IF the doctor is assigned to that day and time, THEN he has to be available. In other words, a doctor can only be assigned to a day and time if he is available.

Rule 2
E* Doctor Day Time doctor assigned to Day and Time Doctor is available on Day and Time
1 - - - Doctor Yes

Rule 3

If a doctor has the night shift, they either get the next day off, or the night shift again.

This rule is by far the most difficult one to implement. We go over every doctor who works the night shift, and then state that they cannot be assigned to the early or late shift on the next day.

Rule 3
E* Doctor Day called d1 doctor assigned to d1 and Night Day called d2 Time doctor assigned to d2 and Time
1 - - Doctor Day after d1 not(Night) not(Doctor)

Rule 4

A doctor either works both days of the weekend, or none of the days.

In order to implement this rule, we create a constraint table that says that every doctor who has a shift on Saturday has to work on Sunday, and vice versa.

Rule 4
E* Doctor Day called d1 nb shifts of Doctor and d1 Day called d2 nb shifts of Doctor and d2
1 - Saturday 1 Sunday 1
2 - Sunday 1 Saturday 1

Special preference

Golgi only works a maximum of 2 night shifts every week.

This preference nicely shows of the simplicity of constraints in cDMN. We implement it as follows:

Max Nb of Nights
E* Doctor nb nights of Doctor
1 Golgi ≤ 2

Now that every rule has been implemented, we need to create tables for the other concepts which we defined. We start by creating the decision table which defines the next day for every day. Then we create the tables which count the number of shifts per day, and the number of night shifts per week.

Define next day
U Day daf after Day
1 Monday Tuesday
2 Tuesday Wednesday
3 Wednesday Thursday
4 Thursday Friday
5 Friday Saturday
6 Saturday Sunday
7 Sunday Monday

Count shifts per day
C+ Doctor Day Time doctor assigned to Day and Time nb shifts of Doctor and Day
1 - - - Doctor 1

Count number of night shifts per doctor
C+ Doctor Day doctor assigned to Day and Night nb nights of Doctor
1 - - Doctor 1

Now all that rests is implementing the availablities in a data table. This table is quite long, so only the first few lines are shown.

Data Table: Availabilities
Doctor Day Time Doctor is available on Day and Time
1 Fleming Friday Early Yes
2 Fleming Friday Late Yes
3 Fleming Friday Night Yes
... ... ... ... ...

We can now run our model using the cDMN solver. For example, this is one of the solutions found by the solver:

Model 1
==========
doctor_assigned_to_Day_and_Time := {(Monday,Early)->Freud, (Monday,Late)->Golgi, (Monday,Night)->Heimlich, (Tuesday,Early)->Eustachi, (Tuesday,Late)->Freud, (Tuesday,Night)->Golgi, (Wednesday,Early)->Freud, (Wednesday,Late)->Eustachi, (Wednesday,Night)->Heimlich, (Thursday,Early)->Golgi, (Thursday,Late)->Freud, (Thursday,Night)->Heimlich, (Friday,Early)->Fleming, (Friday,Late)->Eustachi, (Friday,Night)->Heimlich, (Saturday,Early)->Golgi, (Saturday,Late)->Eustachi, (Saturday,Night)->Fleming, (Sunday,Early)->Golgi, (Sunday,Late)->Eustachi, (Sunday,Night)->Fleming}.
nb_shifts_of_Doctor_and_Day := {(Fleming,Monday)->0, (Fleming,Tuesday)->0, (Fleming,Wednesday)->0, (Fleming,Thursday)->0, (Fleming,Friday)->1, (Fleming,Saturday)->1, (Fleming,Sunday)->1, (Freud,Monday)->1, (Freud,Tuesday)->1, (Freud,Wednesday)->1, (Freud,Thursday)->1, (Freud,Friday)->0, (Freud,Saturday)->0, (Freud,Sunday)->0, (Heimlich,Monday)->1, (Heimlich,Tuesday)->0, (Heimlich,Wednesday)->1, (Heimlich,Thursday)->1, (Heimlich,Friday)->1, (Heimlich,Saturday)->0, (Heimlich,Sunday)->0, (Eustachi,Monday)->0, (Eustachi,Tuesday)->1, (Eustachi,Wednesday)->1, (Eustachi,Thursday)->0, (Eustachi,Friday)->1, (Eustachi,Saturday)->1, (Eustachi,Sunday)->1, (Golgi,Monday)->1, (Golgi,Tuesday)->1, (Golgi,Wednesday)->0, (Golgi,Thursday)->1, (Golgi,Friday)->0, (Golgi,Saturday)->1, (Golgi,Sunday)->1}.
nb_nights_of_Doctor := {Fleming->2, Freud->0, Heimlich->4, Eustachi->0, Golgi->1}.
day_after_Day := {Monday->Tuesday, Tuesday->Wednesday, Wednesday->Thursday, Thursday->Friday, Friday->Saturday, Saturday->Sunday, Sunday->Monday}.
Doctor_is_available_on_Day_and_Time := {(Fleming,Friday,Early), (Fleming,Friday,Late), (Fleming,Friday,Night), (Fleming,Saturday,Early), (Fleming,Saturday,Late), (Fleming,Saturday,Night), (Fleming,Sunday,Early), (Fleming,Sunday,Late), (Fleming,Sunday,Night), (Freud,Monday,Early), (Freud,Monday,Late), (Freud,Tuesday,Early), (Freud,Tuesday,Late), (Freud,Wednesday,Early), (Freud,Wednesday,Late), (Freud,Thursday,Early), (Freud,Thursday,Late), (Freud,Friday,Early), (Freud,Friday,Late), (Freud,Saturday,Early), (Freud,Saturday,Late), (Freud,Sunday,Early), (Freud,Sunday,Late), (Heimlich,Monday,Early), (Heimlich,Monday,Late), (Heimlich,Monday,Night), (Heimlich,Tuesday,Early), (Heimlich,Tuesday,Late), (Heimlich,Tuesday,Night), (Heimlich,Wednesday,Early), (Heimlich,Wednesday,Late), (Heimlich,Wednesday,Night), (Heimlich,Thursday,Early), (Heimlich,Thursday,Late), (Heimlich,Thursday,Night), (Heimlich,Friday,Early), (Heimlich,Friday,Late), (Heimlich,Friday,Night), (Heimlich,Saturday,Early), (Heimlich,Saturday,Late), (Heimlich,Sunday,Early), (Heimlich,Sunday,Late), (Eustachi,Monday,Early), (Eustachi,Monday,Late), (Eustachi,Monday,Night), (Eustachi,Tuesday,Early), (Eustachi,Tuesday,Late), (Eustachi,Tuesday,Night), (Eustachi,Wednesday,Early), (Eustachi,Wednesday,Late), (Eustachi,Wednesday,Night), (Eustachi,Thursday,Early), (Eustachi,Thursday,Late), (Eustachi,Thursday,Night), (Eustachi,Friday,Early), (Eustachi,Friday,Late), (Eustachi,Friday,Night), (Eustachi,Saturday,Early), (Eustachi,Saturday,Late), (Eustachi,Saturday,Night), (Eustachi,Sunday,Early), (Eustachi,Sunday,Late), (Eustachi,Sunday,Night), (Golgi,Monday,Early), (Golgi,Monday,Late), (Golgi,Monday,Night), (Golgi,Tuesday,Early), (Golgi,Tuesday,Late), (Golgi,Tuesday,Night), (Golgi,Wednesday,Early), (Golgi,Wednesday,Late), (Golgi,Wednesday,Night), (Golgi,Thursday,Early), (Golgi,Thursday,Late), (Golgi,Thursday,Night), (Golgi,Friday,Early), (Golgi,Friday,Late), (Golgi,Friday,Night), (Golgi,Saturday,Early), (Golgi,Saturday,Late), (Golgi,Saturday,Night), (Golgi,Sunday,Early), (Golgi,Sunday,Late), (Golgi,Sunday,Night)}.

Elapsed Time:
2.045

The Assigned_Doctor function maps every day and shift on a doctor, conform to all the requirements!