Shift Scheduling

Shift scheduling

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

The shift scheduling app is available in one modeling language 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 go-highs-shiftscheduling
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
workersYesarray of workerNAWorkers to assign.See worker
required_workersYesarray of required workerNAA predicted need of workers at certain times.See required worker

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

{
  "workers": [
    {
      "availability": [
        {
          "start": "2023-09-03T04:00:00+02:00",
          "end": "2023-09-03T11:00:00+02:00"
        },
        {
          "start": "2023-09-04T14:00:00+02:00",
          "end": "2023-09-04T22:00:00+02:00"
        }
      ],
      "id": "1"
    },
    {
      "availability": [
        {
          "start": "2023-08-28T15:00:00+02:00",
          "end": "2023-08-29T00:00:00+02:00"
        },
        {
          "start": "2023-08-29T16:00:00+02:00",
          "end": "2023-08-29T17:00:00+02:00"
        }
      ],
      "id": "2"
    },
    {
      "availability": [
        {
          "start": "2023-08-29T02:00:00+02:00",
          "end": "2023-08-29T11:00:00+02:00"
        },
        {
          "start": "2023-08-30T16:00:00+02:00",
          "end": "2023-08-31T03:00:00+02:00"
        },
        {
          "start": "2023-08-31T15:00:00+02:00",
          "end": "2023-08-31T22:00:00+02:00"
        },
        {
          "start": "2023-09-01T07:00:00+02:00",
          "end": "2023-09-01T12:00:00+02:00"
        },
        {
          "start": "2023-09-01T23:00:00+02:00",
          "end": "2023-09-02T05:00:00+02:00"
        },
        {
          "start": "2023-09-02T03:00:00+02:00",
          "end": "2023-09-02T08:00:00+02:00"
        },
        {
          "start": "2023-09-03T07:00:00+02:00",
          "end": "2023-09-03T11:00:00+02:00"
        }
      ],
      "id": "3"
    },
    {
      "availability": [
        {
          "start": "2023-08-28T11:00:00+02:00",
          "end": "2023-08-28T19:00:00+02:00"
        },
        {
          "start": "2023-08-28T20:00:00+02:00",
          "end": "2023-08-29T03:00:00+02:00"
        },
        {
          "start": "2023-08-29T04:00:00+02:00",
          "end": "2023-08-29T06:00:00+02:00"
        },
        {
          "start": "2023-08-29T22:00:00+02:00",
          "end": "2023-08-29T22:00:00+02:00"
        },
        {
          "start": "2023-08-30T12:00:00+02:00",
          "end": "2023-08-30T14:00:00+02:00"
        },
        {
          "start": "2023-09-04T06:00:00+02:00",
          "end": "2023-09-04T07:00:00+02:00"
        }
      ],
      "id": "4"
    }
  ],
  "required_workers": [
    {
      "start": "2023-08-29T09:00:00+02:00",
      "end": "2023-08-29T09:30:00+02:00",
      "count": 2
    },
    {
      "start": "2023-08-29T09:30:00+02:00",
      "end": "2023-08-29T10:00:00+02:00",
      "count": 3
    },
    {
      "start": "2023-08-29T10:00:00+02:00",
      "end": "2023-08-29T10:30:00+02:00",
      "count": 1
    },
    {
      "start": "2023-08-29T10:30:00+02:00",
      "end": "2023-08-29T11:00:00+02:00",
      "count": 2
    },
    {
      "start": "2023-08-29T11:00:00+02:00",
      "end": "2023-08-29T11:30:00+02:00",
      "count": 4
    },
    {
      "start": "2023-08-29T11:30:00+02:00",
      "end": "2023-08-29T12:00:00+02:00",
      "count": 3
    }
  ]
}
Copy

Worker

A worker is used in the input schema.

Field nameRequiredData typeDescriptionExample
availabilityYesarray of availabilityThe availability times of the workerSee availability
idYesstringID for the worker.{"id": "1"}

Availability

Availability is used in the worker schema.

Field nameRequiredData typeSI UnitDescriptionExample
startYestimestampNAThe start of an availability time window for a worker.{"start": "2023-01-01T00:00:00Z"}
endYestimestampNAThe end of an availability time window for a worker.{"end": "2023-01-01T00:00:00Z"}

Required Worker

A worker is used in the input schema.

Field nameRequiredData typeDescriptionExample
startYestimestampThe start of a required worker time window.{"start": "2023-01-01T00:00:00Z"}
endYestimestampThe end of a required worker time window.{"end": "2023-01-01T00:00:00Z"}
countYesintThe number of required workers for that time window.{"count": 1}

Output

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

Field nameAlways presentData typeSI UnitDescriptionExample
solutionsYesarray of solutionNASolutions to the shift scheduling problem.{"solutions": []}
statisticsYesstatisticsNASummary statistics of the solution.{"statistics": {"total_cost": 123}}
versionYesstringNAVersion of the Nextmv SDK used to generate the solution.{"version": {"sdk": "v1.2.3"}}
optionsNoobjectNAArbitrary model and solver options that were used.{"options": {"foo": "bar"}}
{
  "options": {
    "limits": {
      "day": {
        "max_duration": 36000000000000
      },
      "shift": {
        "max_duration": 28800000000000,
        "min_duration": 7200000000000,
        "recovery_time": 28800000000000
      },
      "week": {
        "max_duration": 144000000000000
      }
    },
    "penalty": {
      "over_supply": 1000,
      "under_supply": 500
    },
    "solve": {
      "control": {
        "bool": [],
        "float": [],
        "int": [],
        "string": []
      },
      "duration": 3000000000,
      "mip": {
        "gap": {
          "absolute": 0.000001,
          "relative": 0.0001
        }
      },
      "verbosity": "off"
    }
  },
  "solutions": [
    {
      "assigned_shifts": [
        {
          "end": "2023-08-29T11:00:00+02:00",
          "start": "2023-08-29T03:00:00+02:00",
          "worker_id": "3"
        }
      ],
      "number_assigned_workers": 1
    }
  ],
  "statistics": {
    "result": {
      "custom": {
        "constraints": 2713,
        "provider": "HiGHS",
        "status": "optimal",
        "variables": 913
      },
      "duration": 0.123,
      "value": 5500
    },
    "run": {
      "duration": 0.123
    },
    "schema": "v1"
  },
  "version": {
    "go-highs": "VERSION",
    "go-mip": "VERSION",
    "sdk": "VERSION"
  }
}
Copy

Solution

Field nameAlways presentData typeSI UnitDescriptionExample
assigned_shiftsYesarray of assigned_shiftNASolution to the shift scheduling problem.{"assigned_shifts": []}
number_assigned_workersYesintNAThe number of assigned distinct workers.{"number_assigned_workers": 1}

Assigned shift

Field nameAlways presentData typeSI UnitDescriptionExample
startYestimestampNAStart time of the worker's shift{"start": "2023-01-01T00:00:00Z"}
endYestimestampNAEnd time of the worker's shift{"end": "2023-01-01T00:00:00Z"}
worker_idYesstringNAThe ID of the worker assigned to this shift.{"id": "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 scheduling.

Nextmv Hybrid Optimization Platform
Usage:
  -limits.day.maxduration duration
    	maximum working time per day (env LIMITS_DAY_MAX_DURATION) (default 10h0m0s)
  -limits.shift.maxduration duration
    	maximum working time per shift (env LIMITS_SHIFT_MAX_DURATION) (default 8h0m0s)
  -limits.shift.minduration duration
    	minimum working time per shift (env LIMITS_SHIFT_MIN_DURATION) (default 2h0m0s)
  -limits.shift.recoverytime duration
    	minimum time between shifts (env LIMITS_SHIFT_RECOVERY_TIME) (default 8h0m0s)
  -limits.week.maxduration duration
    	maximum working time per week (env LIMITS_WEEK_MAX_DURATION) (default 40h0m0s)
  -penalty.oversupply float
    	penalty for over-supplying a demand (env PENALTY_OVER_SUPPLY) (default 1000)
  -penalty.undersupply float
    	penalty for under-supplying a demand (env PENALTY_UNDER_SUPPLY) (default 500)
  -runner.input.path string
    	The input file path (env RUNNER_INPUT_PATH)
  -runner.output.path string
    	The output file path (env RUNNER_OUTPUT_PATH)
  -runner.output.solutions string
    	{all, last} (env RUNNER_OUTPUT_SOLUTIONS) (default "last")
  -runner.profile.cpu string
    	The CPU profile file path (env RUNNER_PROFILE_CPU)
  -runner.profile.memory string
    	The memory profile file path (env RUNNER_PROFILE_MEMORY)
  -solve.control.bool string
    	List of solver-specific control options (configurations) with bool values. Example: "name1=value1,name2=value2", where value1 and value2 are bool values. (env SOLVE_CONTROL_BOOL)
  -solve.control.float string
    	List of solver-specific control options (configurations) with float values. Example: "name1=value1,name2=value2", where value1 and value2 are float values. (env SOLVE_CONTROL_FLOAT)
  -solve.control.int string
    	List of solver-specific control options (configurations) with int values. Example: "name1=value1,name2=value2", where value1 and value2 are int values. (env SOLVE_CONTROL_INT)
  -solve.control.string string
    	List of solver-specific control options (configurations) with string values. Example: "name1=value1,name2=value2", where value1 and value2 are string values. (env SOLVE_CONTROL_STRING)
  -solve.duration duration
    	Maximum duration of the solver. (env SOLVE_DURATION) (default 30s)
  -solve.mip.gap.absolute float
    	Absolute gap stopping value. If the problem is an integer problem the solver will stop if the gap between the relaxed problem and the best found integer problem is less than this value. (env SOLVE_MIP_GAP_ABSOLUTE) (default 1e-06)
  -solve.mip.gap.relative float
    	Relative gap stopping value. If the problem is an integer problem the solver will stop if the relative gap between the relaxed problem and the best found integer problem is less than this value. (env SOLVE_MIP_GAP_RELATIVE) (default 0.0001)
  -solve.verbosity value
    	{off, low, medium, high} Verbosity of the solver in the console. (env SOLVE_VERBOSITY)
Copy

Valid time units for -solver.duration are as follows, according to time.ParseDuration from Go's standard library:

  • ns (nanoseconds)
  • us/µs (microseconds)
  • ms (milliseconds)
  • s (seconds)
  • m (minutes)
  • h (hours)

Page last updated

Go to on-page nav menu