Shift Planning

Shift planning

A how-to guide for specifying the input and output schemas in shift planning.

The shift planning app is available in two modeling languages as a Mixed Integer Problem (MIP). You can also choose to make customizations to the model by instantiating the app first.

nextmv community clone -a shift-planning-ortools
Copy
nextmv community clone -a shift-planning-pyomo
Copy

Once you have the code locally, you can customize the model, run it locally and deploy it to Nextmv Platform.

Input

The format for timestamps should be RFC3339, e.g.: "2023-01-01T00:00:00Z".

The input schema is a JSON payload defining the available workers and the required demand to satisfy for a shift scheduling problem. Nextmv's tools are designed to operate directly on business data (in JSON) to produce decisions that are actionable by software systems. This makes decisions more interpretable and easier to test. It also makes integration with data warehouses and business intelligence platforms significantly easier. An input contains the following components:

Field nameRequiredData typeSI UnitDescriptionExample
shiftsYesarray of shiftNAPossible shifts with additional properties to select from.See shift
demandsYesarray of demandNAA predicted need of workers at certain times.See demand
optionsNoarray of optionNAA set of options to solve the problem.See option

Here you can find a sample .json with the input schema:

{
  "options": {
    "under_supply_cost": 1000,
    "over_supply_cost": 100
  },
  "shifts": [
    {
      "id": "welder",
      "qualification": "welding",
      "min_workers": 1,
      "max_workers": 4,
      "cost": 100,
      "times": [
        {
          "id": "monday-early",
          "start_time": "2023-11-20T06:00:00+02:00",
          "end_time": "2023-11-20T14:00:00+02:00"
        },
        {
          "id": "monday-late",
          "start_time": "2023-11-20T14:00:00+02:00",
          "end_time": "2023-11-20T22:00:00+02:00"
        },
        {
          "id": "monday-night",
          "start_time": "2023-11-20T22:00:00+02:00",
          "end_time": "2023-11-21T06:00:00+02:00",
          "max_workers": 2,
          "cost": 150
        }
      ]
    },
    {
      "id": "normal",
      "min_workers": 0,
      "max_workers": 10,
      "cost": 50,
      "times": [
        {
          "id": "monday-early",
          "start_time": "2023-11-20T06:00:00+02:00",
          "end_time": "2023-11-20T14:00:00+02:00"
        },
        {
          "id": "monday-late",
          "start_time": "2023-11-20T14:00:00+02:00",
          "end_time": "2023-11-20T22:00:00+02:00"
        },
        {
          "id": "monday-night",
          "start_time": "2023-11-20T22:00:00+02:00",
          "end_time": "2023-11-21T06:00:00+02:00",
          "cost": 100
        }
      ]
    }
  ],
  "demands": [
    {
      "start_time": "2023-11-20T06:00:00+02:00",
      "end_time": "2023-11-20T14:00:00+02:00",
      "count": 3,
      "qualification": "welding"
    },
    {
      "start_time": "2023-11-20T14:00:00+02:00",
      "end_time": "2023-11-20T22:00:00+02:00",
      "count": 2,
      "qualification": "welding"
    },
    {
      "start_time": "2023-11-20T11:00:00+02:00",
      "end_time": "2023-11-20T17:00:00+02:00",
      "count": 8
    }
  ]
}
Copy

Shift

A shift is used in the input schema.

Field nameRequiredData typeDescriptionExample
idYesstringID for the shift.{"id": "1"}
qualificationNostringThe qualification needed for the shift.{"qualification": "1"}
min_workersNointThe minimum number of workers for the shift.{"min_workers": 1}
max_workersNointThe maximum number of workers for the shift.{"max_workers": 1}
costNointThe cost for the shift.{"cost": 1}
timesYesarray of timeThe time windows covered by this shift.See time

Time

Time is used in the shift schema.

Field nameRequiredData typeSI UnitDescriptionExample
idYesstringID for the time window.{"id": "1"}
start_timeYestimestampNAThe start time of this time window.{"start_time": "2023-01-01T00:00:00Z"}
end_timeYestimestampNAThe end time of this time window.{"end_time": "2023-01-01T00:00:00Z"}

Demand

Demand is used in the input schema.

Field nameRequiredData typeDescriptionExample
start_timeYestimestampNAThe start time of the predicted demand.
end_timeYestimestampNAThe end time of the predicted demand.
countYesintThe amount of predicted demand.{"count": 1}
qualificationNostringThe qualification needed for the demand.{"qualification": "1"}

Option

Option is used in the input schema.

Field nameRequiredData typeDescriptionExample
over_supply_costNointThe cost for oversupplying a demand.{"over_supply_cost": 1}
under_supply_costNointThe cost for shortfalling a demand.{"under_supply_cost": 1}

Output

The output schema defines the solution to the shift planning problem in JSON format. The output schema contains the following components.

Field nameAlways presentData typeSI UnitDescriptionExample
solutionsYesarray of solutionNASolutions to the shift planning problem.{"solutions": []}
statisticsYesstatisticsNASummary statistics of the solution.{"statistics": {"total_cost": 123}}
{
  "solutions": [
    {
      "planned_shifts": [
        {
          "count": 3,
          "end_time": "2023-11-20T14:00:00+02:00",
          "id": "welder_monday-early",
          "qualification": "welding",
          "shift_id": "welder",
          "start_time": "2023-11-20T06:00:00+02:00",
          "time_id": "monday-early"
        },
        {
          "count": 2,
          "end_time": "2023-11-20T22:00:00+02:00",
          "id": "welder_monday-late",
          "qualification": "welding",
          "shift_id": "welder",
          "start_time": "2023-11-20T14:00:00+02:00",
          "time_id": "monday-late"
        },
        {
          "count": 1,
          "end_time": "2023-11-21T06:00:00+02:00",
          "id": "welder_monday-night",
          "qualification": "welding",
          "shift_id": "welder",
          "start_time": "2023-11-20T22:00:00+02:00",
          "time_id": "monday-night"
        },
        {
          "count": 8,
          "end_time": "2023-11-20T14:00:00+02:00",
          "id": "normal_monday-early",
          "qualification": "",
          "shift_id": "normal",
          "start_time": "2023-11-20T06:00:00+02:00",
          "time_id": "monday-early"
        },
        {
          "count": 8,
          "end_time": "2023-11-20T22:00:00+02:00",
          "id": "normal_monday-late",
          "qualification": "",
          "shift_id": "normal",
          "start_time": "2023-11-20T14:00:00+02:00",
          "time_id": "monday-late"
        }
      ]
    }
  ],
  "statistics": {
    "result": {
      "custom": {
        "constraints": 7,
        "has_solution": true,
        "over_supply": 154,
        "over_supply_cost": 15400,
        "planned_count": 22,
        "planned_shifts": 5,
        "provider": "SCIP",
        "shift_cost": 1450,
        "status": "optimal",
        "under_supply": 0,
        "under_supply_cost": 0,
        "variables": 13
      },
      "duration": 0.123,
      "value": 16850
    },
    "run": {
      "duration": 0.123
    },
    "schema": "v1"
  }
}
Copy

Solution

Field nameAlways presentData typeSI UnitDescriptionExample
planned_shiftsYesarray of planned_shiftNASolution to the shift scheduling problem.{"planned_shifts": []}

Planned shift

Field nameAlways presentData typeSI UnitDescriptionExample
start_timeYestimestampNAStart time of the worker's shift{"start_time": "2023-01-01T00:00:00Z"}
end_timeYestimestampNAEnd time of the worker's shift{"end_time": "2023-01-01T00:00:00Z"}
idYesstringNAThe ID of the planned shift.{"id": "1"}
shift_idYesstringNAThe ID of the used shift.{"shift_id": "1"}
time_idYesstringNAThe ID of used time of the shift.{"time_id": "1"}
qualificationYesstringNAThe needed qualification to work the shift.{"qualification": "1"}
countYesintNACount describes how of this shift/time combination is needed.{"count": "1"}

Statistics

Field nameAlways presentData typeSI UnitDescriptionExample
resultNoresultNAFinal result of the solutions.See result
runYesrunNAInformation about the run.See run
schemaYesstringNASchema of the statistics.{"schema": "v1"}

Here you can find additional definitions used in the statistics schema:

  • result

    Field nameAlways presentData typeSI UnitDescriptionExample
    durationYesfloatsecondsTime duration to get to the final result.{"duration": 0.123}
    valueYesfloatNAValue of the final result.{"value": 0.123}
    customYesanyNACustom solver metrics.See custom
  • run

    Field nameAlways presentData typeSI UnitDescriptionExample
    durationYesfloatsecondsTime duration of the run.{"duration": 0.123}
  • custom

    Field nameAlways presentData typeSI UnitDescriptionExample
    constraintsYesintNANumber of constraints.{"constraints": 123}
    providerYesstringNASolver provider.{"provider": "highs"}
    statusYesstringNASolver status.{"status": "optimal"}
    variablesYesintNANumber of variables.{"variables": 123}

Run options

These are the default options that are available with shift planning.

usage: main.py [-h] [-input INPUT] [-output OUTPUT] [-duration DURATION]
               [-provider PROVIDER]

Solve shift-planning with OR-Tools MIP.

options:
  -h, --help          show this help message and exit
  -input INPUT        Path to input file. Default is stdin.
  -output OUTPUT      Path to output file. Default is stdout.
  -duration DURATION  Max runtime duration (in seconds). Default is 30.
  -provider PROVIDER  Solver provider. Default is SCIP.
Copy

Page last updated

Go to on-page nav menu