Prendi in considerazione un problema di programmazione infermieristica di un reparto di un particolare ospedale. Ogni giorno ci sono tre turni di 12 ore a partire da 7h, 13h, 19h. La di pianificazione è di quattro giorni, a partire dal 01/05/2023, per un totale di 12 turni. Ci sono quattro infermieri registrati che possono essere assegnati a questi turni, con l'obiettivo di avere due infermieri nel reparto in un dato momento. La copertura è obbligatorio.
Tutti gli infermieri devono riposare tra un turno e l'altro per almeno 12 ore (720 minuti) e può funzionare per un massimo di 36 ore (2160 minuti) durante l'orizzonte di pianificazione specificato. Questi vincoli hanno rispettivamente una priorità alta e media.
Diversi turni al giorno
Tre turni al giorno sono rappresentati come tre turni indipendenti. Ad esempio: turni per il primo giorno (su quattro giorni) al "reparto" località sono rappresentato come:
{
"shifts": [{
"id": "2023-05-01 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
}
}, {
"id": "2023-05-01 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 1
}
}, {
"id": "2023-05-01 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
}
},
...
]
}
Esempio con 12 turni (quattro giorni con tre turni al giorno)
{
"shifts": [{
"id": "2023-05-01 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
}
}, {
"id": "2023-05-01 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 1
}
}, {
"id": "2023-05-01 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
}
}, {
"id": "2023-05-02 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
}
}, {
"id": "2023-05-02 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 1
}
}, {
"id": "2023-05-02 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
}
}, {
"id": "2023-05-03 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
}
}, {
"id": "2023-05-03 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 1
}
}, {
"id": "2023-05-03 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
}
}, {
"id": "2023-05-04 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
}
}, {
"id": "2023-05-04 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 1
}
}, {
"id": "2023-05-04 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
}
}]
}
Recupera tra i turni
Per rappresentare il resto tra un turno e l'altro per un dipendente, utilizza
Campo minimumRestMinutes
da un
vincolo di pianificazione. Gli orari di inizio e di fine di
vengono utilizzati per determinare quali cambiamenti prendere in considerazione, pertanto
devono allinearsi a un orizzonte di pianificazione sovrapponendosi a tutti i cambiamenti. La
il tempo di riposo è specificato in minuti (720) e la priorità è PRIORITY_HIGH
come
sopra citate. La prima infermiera (chiamata Adamo) è rappresentata come segue:
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}]
}
}
Orario di lavoro massimo
Anche il tempo massimo che può essere impiegato da un dipendente è rappresentato da un
vincolo di pianificazione, utilizzando maximumMinutes
. Il tempo di lavoro massimo in questo esempio è 2160 minuti. L'inizio
le ore di fine del vincolo devono allinearsi all'intero orizzonte di pianificazione. La
la rappresentazione corrispondente del primo infermiere (Marco) può essere aggiornata in:
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}
}
Esempio con tutti e quattro i dipendenti
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Grace",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "James",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Alonso",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}]
}
Copertura per infermieri abilitati
La copertura di due infermieri registrati in un dato momento è rappresentata da un
requisito di copertura. In particolare,
Il campo roleRequirements
è compilato con uno
requisito del ruolo per cui roleId
è impostato su
"Infermiera registrata", targetEmployeeCount
è impostato su 2 e priority
è impostato su
PRIORITY_MANDATORY
. Gli orari di inizio e di fine del requisito di copertura devono
si sovrappongono a ogni turno. Il campo locationId
è impostato su "reparto" in modo che
vengono presi in considerazione solo i cambiamenti che avvengono in questa località.
{
"coverageRequirements": [{
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"locationId": "department",
"roleRequirements": [{
"roleId": "Registered Nurse",
"targetEmployeeCount": 2,
"priority": "PRIORITY_MANDATORY"
}]
}],
"roleIds": ["Registered Nurse"],
"locationIds": ["department"]
}
Esempio di richiesta completa
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Grace",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "James",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Alonso",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}],
"shifts": [{
"id": "2023-05-01 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
}
}, {
"id": "2023-05-01 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 1
}
}, {
"id": "2023-05-01 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
}
}, {
"id": "2023-05-02 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
}
}, {
"id": "2023-05-02 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 1
}
}, {
"id": "2023-05-02 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
}
}, {
"id": "2023-05-03 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
}
}, {
"id": "2023-05-03 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 1
}
}, {
"id": "2023-05-03 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
}
}, {
"id": "2023-05-04 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
}
}, {
"id": "2023-05-04 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 1
}
}, {
"id": "2023-05-04 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
}
}],
"coverageRequirements": [{
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"locationId": "department",
"roleRequirements": [{
"roleId": "Registered Nurse",
"targetEmployeeCount": 2,
"priority": "PRIORITY_MANDATORY"
}]
}],
"roleIds": ["Registered Nurse"],
"locationIds": ["department"]
}
Esempio di risposta
La risposta del risolutore include l'assegnazione degli infermieri ai turni stato della procedura di ottimizzazione. Ad esempio, le variazioni assegnate il primo dipendente viene restituito come:
{
"solutionStatus": "OPTIMAL",
"shiftAssignments": [
{
"employeeId": "Adam",
"shiftId": "2023-05-01 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-02 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-03 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-04 7hr",
"roleId": "Registered Nurse"
},
... ]
}
Esempio di risposta completa
{
"solutionStatus": "OPTIMAL",
"shiftAssignments": [
{
"employeeId": "Adam",
"shiftId": "2023-05-01 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-02 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-03 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-04 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-01 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-02 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-03 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-04 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-01 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-02 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-03 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-04 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-01 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-02 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-03 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-04 7hr",
"roleId": "Registered Nurse"
}
]
}