Shift Creation
Introduction
The Creation Solver can be used to assign shifts based on a given demand. Additional constraints can be placed on the problem like limiting inter-shift-start-times, accounting for limited resources used by certain shifts and/or requiring certain skills. Flexible work is executed as late as possible and user provided preferences and costs can be used by the solver.
Input-Output
The input of the creation solver consists of two parts:
- The possible shifts and their properties
- The demands that must be fulfilled by those shifts
The demands can be provided in two different ways, in fixed or flexible format. These cannot be mixed. Based on which type of demand is provided, the solver will run in fixed or flexible mode, more explanation on this later in the guide.
The output of the solver contains the selected shifts along with the amount of each shift that the solver assigned. The output is the same for fixed and flexible mode.
Input
Shift
Property | Type | Description |
---|---|---|
definition | Array of Pattern | A list of Patterns defining at what times this shift takes place. |
skill | string | specifies the employee type that will execute the shift. Should match with a Demand skill field. |
min | integer | Minimum number of people that have to be assigned to this shift. |
max | integer | Maximum number of people that can be assigned to this shift. |
resourceRequirements | Array of Resource Requirement | The different resources and the number of each resource needed to execute this shift for one person (eg. 1 hammer). |
cost | integer | The cost of assigning a single person to this shift. |
preference | integer | A number that behaves like the cost of a shift. Used to specify a preference between two shifts that have the same cost. |
Pattern
Property | Type | Description |
---|---|---|
from | string (iso DateTime) | Start time of the shift pattern. |
to | string (iso DateTime) | End time of the shift pattern. |
breaks | Array of Break | A list of breaks that take place between the from and to time. |
Break
Property | Type | Description |
---|---|---|
start | string (iso DateTime) | Start time of this break. |
end | string (iso DateTime) | End time of this break. |
Resource Requirement
Used to specify that a shift requires a certain resource during the times when the shift takes place.
For example, a shift with skill 'worker' needs 1 hammer.
Property | Type | Description |
---|---|---|
resourceName | string | The name of the required resource. A resource with this name also needs to be present in the resourceAvaliability list. |
value | integer | The amount of this resource that are needed when assigning 1 person to the shifts that holds this Resource Requirement. |
Resource Availability
Used to specify which resources are available at all times and how many there are available of each resource.
An example would be that there are 5 hammers available.
Property | Type | Description |
---|---|---|
resourceName | string | The name of the available resource. |
max | integer | How many units of the available resource can be used simultaneously. |
Demand
The demands are used to specify when shifts of each skill are needed. When using fixed mode only the demand
field needs to be specified. When using flexible mode only the min
and max
fields of the demands need to be specified. A solver instance can only contain fixed or flexible demands, not both.
Property | Type | Description |
---|---|---|
from | string (iso DateTime) | Start time of the Demand block. |
to | string (iso DateTime) | End time of the Demand block. |
skill | string | The skill that is required to fulfil this demand. |
demand | integer | The number of people needed during this Demand block. (when using fixed mode) |
min | integer | The minimum total number of minutes that need to have been assigned to this skill by the end of this Demand block (when using flexible mode). |
max | integer | The maximum total number of minutes that can be been assigned to this skill by the end of this Demand block (when using flexible mode). |
Example
In the example of Single Day Shift Creation
we will be testing a simple demand curve against 2 patterns from 9am to 5pm and 10am to 2pm.
{
"solver": "CREATE",
"demands": [
{
"from": "2021-10-04T08:15:00",
"to": "2021-10-04T11:30:00",
"skill": "mechanic",
"demand": 3
},
{
"from": "2021-10-04T11:30:00",
"to": "2021-10-04T15:15:00",
"skill": "mechanic",
"demand": 6
}
],
"resourceAvailabilities": [
{
"resourceName": "screwdriver",
"max": 10
}
],
"patterns": [
{
"name": "MON:9-5",
"skill": "mechanic",
"min": 0,
"max": 10,
"cost": 80,
"preference": 10,
"resourceRequirements": [
{
"resourceName": "screwdriver",
"value": 1
}
],
"definition": [
{
"from": "2021-10-04T09:00:00",
"to": "2021-10-04T17:00:00",
"breaks": [
{
"start": "2021-10-04T12:00:00",
"end": "2021-10-04T13:00:00"
}
]
}
]
},
{
"name": "FLEX:10-14",
"skill": "mechanic",
"min": 0,
"max": 10,
"cost": 45,
"preference": 0,
"resourceRequirements": [
{
"resourceName": "screwdriver",
"value": 1
}
],
"definition": [
{
"from": "2021-10-04T10:00:00",
"to": "2021-10-04T14:00:00"
}
]
}
]
}
{
"solver": "CREATE",
"demands": [
{
"from": "2021-10-04T08:15:00",
"to": "2021-10-04T11:30:00",
"skill": "mechanic",
"min": 0,
"max": 180
},
{
"from": "2021-10-04T11:30:00",
"to": "2021-10-04T15:15:00",
"skill": "mechanic",
"min": 120,
"max": 480
}
],
"resourceAvailabilities": [
{
"resourceName": "screwdriver",
"max": 10
}
],
"patterns": [
{
"name": "MON:9-5",
"skill": "mechanic",
"min": 0,
"max": 10,
"cost": 80,
"preference": 10,
"resourceRequirements": [
{
"resourceName": "screwdriver",
"value": 1
}
],
"definition": [
{
"from": "2021-10-04T09:00:00",
"to": "2021-10-04T17:00:00",
"breaks": [
{
"start": "2021-10-04T12:00:00",
"end": "2021-10-04T13:00:00"
}
]
}
]
},
{
"name": "FLEX:10-14",
"skill": "mechanic",
"min": 0,
"max": 10,
"cost": 45,
"preference": 0,
"resourceRequirements": [
{
"resourceName": "screwdriver",
"value": 1
}
],
"definition": [
{
"from": "2021-10-04T10:00:00",
"to": "2021-10-04T14:00:00"
}
]
}
]
}
{
"solver": "CREATE",
"resourceAvailabilities": [
{"resourceName": "screwdriver", "max": 10}
],
"weights": {
"totalDemandWeight": {
"initScore": 0,
"hardScore": 1,
"mediumScore": 0,
"softScore": 0,
"feasible": true,
"solutionInitialized": true
},
"resourceAvailabilityWeight": {
"initScore": 0,
"hardScore": 1,
"mediumScore": 0,
"softScore": 0,
"feasible": true,
"solutionInitialized": true
},
"underDemandWeight": {
"initScore": 0,
"hardScore": 0,
"mediumScore": 10,
"softScore": 0,
"feasible": true,
"solutionInitialized": true
},
"overDemandWeight": {
"initScore": 0,
"hardScore": 0,
"mediumScore": 1,
"softScore": 0,
"feasible": true,
"solutionInitialized": true
},
"underDemandWeightCumulative": {
"initScore": 0,
"hardScore": 0,
"mediumScore": 100,
"softScore": 0,
"feasible": true,
"solutionInitialized": true
},
"timeWastedWeightCumulative": {
"initScore": 0,
"hardScore": 0,
"mediumScore": 50,
"softScore": 0,
"feasible": true,
"solutionInitialized": true
},
"asLateAsPossible": {
"initScore": 0,
"hardScore": 0,
"mediumScore": 1,
"softScore": 0,
"feasible": true,
"solutionInitialized": true
},
"costWeight": {
"initScore": 0,
"hardScore": 0,
"mediumScore": 0,
"softScore": 18,
"feasible": true,
"solutionInitialized": true
},
"preferredShifts": {
"initScore": 0,
"hardScore": 0,
"mediumScore": 0,
"softScore": 1,
"feasible": true,
"solutionInitialized": true
}
},
"patterns": [
{
"name": "MON:9-5",
"skill": "mechanic",
"min": 0,
"max": 10,
"cost": 80,
"preference": 10,
"resourceRequirements": [
{
"resourceName": "screwdriver",
"value": 1
}
],
"definition": [
{
"from": "2021-10-04T09:00:00",
"to": "2021-10-04T17:00:00",
"breaks": [
{
"start": "2021-10-04T12:00:00",
"end": "2021-10-04T13:00:00"
}
]
}
]
},
{
"name": "FLEX:10-14",
"skill": "mechanic",
"min": 0,
"max": 10,
"cost": 45,
"preference": 0,
"resourceRequirements": [
{
"resourceName": "screwdriver",
"value": 1
}
],
"definition": [
{
"from": "2021-10-04T10:00:00",
"to": "2021-10-04T14:00:00"
}
]
}
],
"demands": [
{
"from": "2021-10-04T08:15:00",
"to": "2021-10-04T11:30:00",
"skill": "mechanic",
"min": 0,
"max": 180
},
{
"from": "2021-10-04T11:30:00",
"to": "2021-10-04T15:15:00",
"skill": "mechanic",
"min": 120,
"max": 480
}
]
}
Output
The solver returns a json in which the original instance can be found. The output is given in the solution
field and contains a list of Created Shift
.
Created Shift
Used to represent the output. Each entry corresponds with a pattern that was given as input.
Property | Type | Description |
---|---|---|
pattern | string | The name of the corresponding pattern that was given as input. |
skill | string | The skill of the corresponding pattern. |
value | integer | The amount of people the solver chose to assign to this shift. |
Objective
The solver will try to find the best values to assign to each shift. In order to do this, constraints are used to determine how good a solution is. These constraints represent different numbers used to score the solution. These constraints are prioritised by being either HARD, MEDIUM or SOFT. All improvements in HARD constraints trump any deterioration in MEDIUM or SOFT constraints. All improvements in MEDIUM constraints trump any deterioration in SOFT constraints.
Constraints
In this table is a summary of all constraints and what they mean. The weight and priority of each constraint can be adjusted using the weights
field in a solver request. An example of this can be found on this page in 'Single Day Creation With Weights'. This is an advanced feature, the results of tweaking these weights is often hard to predict.
Name | Level | Description |
---|---|---|
Total Demand | HARD | The total required demand must be met (only relevant in fixed mode). |
Resource Availability | HARD | Only the maximum number of available resources for every resource type can be used. |
Min Time Between Shift Start | HARD | Two shifts with different start times cannot have start times closer to each other than the minimum allowed time specified (optionally) by the user. |
Under demand | MEDIUM | For every demand time block, the supply that is less than the demand must be minimised. |
Over demand | MEDIUM | For every demand time block, the supply that is more than the demand must be minimised. |
As Late As Possible | MEDIUM | Only relevant in flexible mode. When planning shifts, try to plan shifts as late as possible while respecting the Over Demand and Under Demand constraints. |
Costs | SOFT | Cost based minimisation of the shifts. |
Preference | SOFT | Preference based maximisation of the shifts. |
Fixed Mode and Flexible Mode
The solver can run in two modes: Fixed Mode
and Flexible Mode
.
Fixed Mode
In Fixed Mode
the solver has no choice about when work needs to be done. In this mode, the input specifies how many people we need at which point in time for what skill.
When a demand block that starts at 9am and ends at 10am has a demand
value of 3, that means that 3 people are required for that skill between 9am and 10am.
Flexible Mode
In Flexible Mode
the solver has some freedom over when certain work can be done. In this mode, the input specifies when volumes of work can be done and when they have to be completed.
When a demand block that starts at 9am and ends at 10am has a min
value of 60 and a max
value of 120, that means that a minimum of 60 minutes of work needs to have been done by 10am and that the maximum amount of work that can be done by 10am is 120 minutes.
examples of Flexible Mode
Let's say that nobody has worked before 9am, meaning that the total amount of work done by the start of this demand block is 0. We now assign 1 person to a shift that starts at 9am and ends at 10am. This means that during this hour, 60 minutes of work will be done (since 1 person is assigned for 1 hour). That means that the actual volume of work done by the end of this demand block will be 60 minutes. This is okay since it lies between our given min
and max
for the demand block.
Let's say that instead of 1 person, 2 people are assigned during this interval. The total amount of work that will be done by the end of this interval is now 120 minutes. This is also fine since it falls within our given min
and max
for this demand block.
Will the solver choose 1 or 2 people?
In this simple example, the solver will choose to assign only 1 person. We want to schedule work as late as possible so we don't want to do 120 minutes of work when only 60 minutes are needed, even if there are already 120 minutes of work available.
If this demand block was part of a larger instance, then the solver might have preferred to place 2 people here. One reason might be that later in the day, a lot of additional work needs to be completed (which means that the min
field has a high value). In that case we might have chosen to place 2 people here because else we end up being too late with other work down the road.
Updated almost 2 years ago