alpar@1: /* File: shiftcover.mod */ alpar@1: alpar@1: /* WORKFORCE SHIFT COVERAGE assignment problem */ alpar@1: alpar@1: /* Written by Larry D'Agostino alpar@1: alpar@1: Maximize Productivity with Industrial Engineer and Operations Research Tools alpar@1: http://industrialengineertools.blogspot.com alpar@1: alpar@1: alpar@1: /* The WORKFORCE SHIFT COVERAGE is an assigment problem that determines alpar@1: the schedule of crew given available time and shifts. alpar@1: alpar@1: The objective is to cover the available time given hourly demand with the minimum alpar@1: number of crew members. alpar@1: alpar@1: This is a set covering problem that is very common among finding crew alpar@1: and shift allocations. Notice in the data section the workforce shift allocation alpar@1: per day of the week.*/ alpar@1: alpar@1: alpar@1: /* ----- Model PARAMTERS and SETS -----*/ alpar@1: alpar@1: param numhrs; alpar@1: /* number of hours of operations in a given day */ alpar@1: alpar@1: param dys; alpar@1: /* number of days in a week */ alpar@1: alpar@1: set S; alpar@1: /* set of crew shifts */ alpar@1: alpar@1: set H := 1..numhrs; alpar@1: /* set of hours of a day*/ alpar@1: alpar@1: set D; alpar@1: /* set of days of a week*/ alpar@1: alpar@1: param dmnd{h in H, d in D}; alpar@1: /* demand for crew members given h hour and d day */ alpar@1: alpar@1: param shifts{d in D, h in H, s in S}; alpar@1: /* shifts to assign to crew members given d day, h hour, and s shift schedule alpar@1: alpar@1: /*----- Model VARIABLES -----*/ alpar@1: alpar@1: var crew{s in S}, integer, >=0; alpar@1: /* number of crew assigned to shift S */ alpar@1: alpar@1: alpar@1: /*----- Model CONSTRAINTS -----*/ alpar@1: alpar@1: s.t. Coverage{h in H, d in D}: sum{s in S} crew[s]*shifts[d,h,s] >= dmnd[h,d]; alpar@1: /* number of crew to cover with a shift given hourly demand and day */ alpar@1: alpar@1: alpar@1: /*----- Model OBJECTIVE -----*/ alpar@1: alpar@1: minimize obj: sum{s in S} crew[s]; alpar@1: /* minimize number of crew to cover demand*/ alpar@1: alpar@1: solve; alpar@1: display crew; alpar@1: alpar@1: printf "\n"; alpar@1: printf "Total Crew: %3d\n\n", sum{s in S} crew[s]; alpar@1: alpar@1: alpar@1: alpar@1: printf "\n\n"; alpar@1: printf "Weekly Crew Schedule\n\n"; alpar@1: printf "Hour "; alpar@1: printf{d in D} " %s ", d; alpar@1: printf "\n"; alpar@1: for {h in H} { alpar@1: printf " %2s ",h; alpar@1: printf{d in D} " %3d ", sum{s in S} crew[s]*shifts[d,h,s]; alpar@1: printf "\n"; alpar@1: } alpar@1: printf"\n"; alpar@1: alpar@1: alpar@1: alpar@1: data; alpar@1: alpar@1: param numhrs := 16; alpar@1: alpar@1: set D := SUN, MON, TUE, WED, THU, FRI, SAT; alpar@1: alpar@1: set S := Sh1, Sh2, Sh3, Sh4, Sh5, Sh6, Sh7, Sh8, Sh9; alpar@1: alpar@1: param dmnd : SUN MON TUE WED THU FRI SAT := alpar@1: 1 0 3 3 4 3 2 0 alpar@1: 2 0 14 14 16 14 12 12 alpar@1: 3 0 24 24 27 24 20 15 alpar@1: 4 0 28 28 32 28 23 15 alpar@1: 5 0 33 33 37 33 24 16 alpar@1: 6 0 34 34 38 34 24 15 alpar@1: 7 0 35 35 39 35 25 11 alpar@1: 8 0 35 35 40 35 27 0 alpar@1: 9 0 34 34 39 34 25 0 alpar@1: 10 0 31 31 35 31 24 0 alpar@1: 11 2 24 24 27 24 25 0 alpar@1: 12 3 19 19 21 19 21 0 alpar@1: 13 2 24 24 27 24 13 0 alpar@1: 14 2 16 16 18 16 0 0 alpar@1: 15 0 7 7 7 7 0 0 alpar@1: 16 0 5 5 5 5 0 0; alpar@1: alpar@1: alpar@1: param shifts := alpar@1: ['SUN',*,*]: alpar@1: Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 := alpar@1: 1 0 0 0 0 0 0 0 0 0 alpar@1: 2 0 0 0 0 0 0 0 0 0 alpar@1: 3 0 0 0 0 0 0 0 0 0 alpar@1: 4 0 0 0 0 0 0 0 0 0 alpar@1: 5 0 0 0 0 0 0 0 0 0 alpar@1: 6 0 0 0 0 0 0 0 0 0 alpar@1: 7 0 0 0 0 0 0 0 0 0 alpar@1: 8 0 0 0 0 0 0 0 0 0 alpar@1: 9 0 0 0 0 0 0 0 0 0 alpar@1: 10 0 0 0 0 0 0 0 0 0 alpar@1: 11 0 0 0 0 0 0 0 0 1 alpar@1: 12 0 0 0 0 0 0 0 0 1 alpar@1: 13 0 0 0 0 0 0 0 0 1 alpar@1: 14 0 0 0 0 0 0 0 0 1 alpar@1: 15 0 0 0 0 0 0 0 0 0 alpar@1: 16 0 0 0 0 0 0 0 0 0 alpar@1: alpar@1: alpar@1: ['MON',*,*]: alpar@1: Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 := alpar@1: 1 1 0 0 0 0 0 0 0 0 alpar@1: 2 1 1 0 0 0 0 0 0 0 alpar@1: 3 1 1 1 0 0 0 0 0 0 alpar@1: 4 1 1 1 1 0 0 0 0 0 alpar@1: 5 0 1 1 1 1 0 0 0 0 alpar@1: 6 1 0 1 1 1 1 0 0 1 alpar@1: 7 1 1 0 1 1 1 1 0 1 alpar@1: 8 1 1 1 0 1 1 1 1 1 alpar@1: 9 1 1 1 1 0 1 1 1 1 alpar@1: 10 0 1 1 1 1 0 1 1 1 alpar@1: 11 0 0 1 1 1 1 0 1 0 alpar@1: 12 0 0 0 1 1 1 1 0 1 alpar@1: 13 0 0 0 0 1 1 1 1 1 alpar@1: 14 0 0 0 0 0 1 1 1 1 alpar@1: 15 0 0 0 0 0 0 1 1 1 alpar@1: 16 0 0 0 0 0 0 0 1 1 alpar@1: alpar@1: ['TUE',*,*]: alpar@1: Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 := alpar@1: 1 1 0 0 0 0 0 0 0 0 alpar@1: 2 1 1 0 0 0 0 0 0 0 alpar@1: 3 1 1 1 0 0 0 0 0 0 alpar@1: 4 1 1 1 1 0 0 0 0 0 alpar@1: 5 0 1 1 1 1 0 0 0 0 alpar@1: 6 1 0 1 1 1 1 0 0 1 alpar@1: 7 1 1 0 1 1 1 1 0 1 alpar@1: 8 1 1 1 0 1 1 1 1 1 alpar@1: 9 1 1 1 1 0 1 1 1 1 alpar@1: 10 0 1 1 1 1 0 1 1 1 alpar@1: 11 0 0 1 1 1 1 0 1 0 alpar@1: 12 0 0 0 1 1 1 1 0 1 alpar@1: 13 0 0 0 0 1 1 1 1 1 alpar@1: 14 0 0 0 0 0 1 1 1 1 alpar@1: 15 0 0 0 0 0 0 1 1 1 alpar@1: 16 0 0 0 0 0 0 0 1 1 alpar@1: alpar@1: ['WED',*,*]: alpar@1: Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 := alpar@1: 1 1 0 0 0 0 0 0 0 0 alpar@1: 2 1 1 0 0 0 0 0 0 0 alpar@1: 3 1 1 1 0 0 0 0 0 0 alpar@1: 4 1 1 1 1 0 0 0 0 0 alpar@1: 5 0 1 1 1 1 0 0 0 0 alpar@1: 6 1 0 1 1 1 1 0 0 1 alpar@1: 7 1 1 0 1 1 1 1 0 1 alpar@1: 8 1 1 1 0 1 1 1 1 1 alpar@1: 9 1 1 1 1 0 1 1 1 1 alpar@1: 10 0 1 1 1 1 0 1 1 1 alpar@1: 11 0 0 1 1 1 1 0 1 0 alpar@1: 12 0 0 0 1 1 1 1 0 1 alpar@1: 13 0 0 0 0 1 1 1 1 1 alpar@1: 14 0 0 0 0 0 1 1 1 1 alpar@1: 15 0 0 0 0 0 0 1 1 1 alpar@1: 16 0 0 0 0 0 0 0 1 1 alpar@1: alpar@1: ['THU',*,*]: alpar@1: Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 := alpar@1: 1 1 0 0 0 0 0 0 0 0 alpar@1: 2 1 1 0 0 0 0 0 0 0 alpar@1: 3 1 1 1 0 0 0 0 0 0 alpar@1: 4 1 1 1 1 0 0 0 0 0 alpar@1: 5 0 1 1 1 1 0 0 0 0 alpar@1: 6 1 0 1 1 1 1 0 0 0 alpar@1: 7 1 1 0 1 1 1 1 0 0 alpar@1: 8 1 1 1 0 1 1 1 1 0 alpar@1: 9 1 1 1 1 0 1 1 1 0 alpar@1: 10 0 1 1 1 1 0 1 1 0 alpar@1: 11 0 0 1 1 1 1 0 1 0 alpar@1: 12 0 0 0 1 1 1 1 0 0 alpar@1: 13 0 0 0 0 1 1 1 1 0 alpar@1: 14 0 0 0 0 0 1 1 1 0 alpar@1: 15 0 0 0 0 0 0 1 1 0 alpar@1: 16 0 0 0 0 0 0 0 1 0 alpar@1: alpar@1: ['FRI',*,*]: alpar@1: Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 := alpar@1: 1 1 0 0 0 0 0 0 0 0 alpar@1: 2 1 1 0 0 0 0 0 0 0 alpar@1: 3 1 1 1 0 0 0 0 0 0 alpar@1: 4 1 1 1 1 0 0 0 0 0 alpar@1: 5 0 1 1 1 1 0 0 0 0 alpar@1: 6 1 0 1 1 1 1 0 0 0 alpar@1: 7 1 1 0 1 1 1 1 0 0 alpar@1: 8 1 1 1 0 1 1 1 1 0 alpar@1: 9 1 1 1 1 0 1 1 1 0 alpar@1: 10 0 1 1 1 1 0 1 1 0 alpar@1: 11 0 0 1 1 1 1 0 1 0 alpar@1: 12 0 0 0 1 1 1 1 0 0 alpar@1: 13 0 0 0 0 1 1 1 1 0 alpar@1: 14 0 0 0 0 0 1 1 1 0 alpar@1: 15 0 0 0 0 0 0 1 1 0 alpar@1: 16 0 0 0 0 0 0 0 1 0 alpar@1: alpar@1: ['SAT',*,*]: alpar@1: Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 := alpar@1: 1 0 0 0 0 0 0 0 0 0 alpar@1: 2 0 0 0 0 0 0 0 0 1 alpar@1: 3 0 0 0 0 0 0 0 0 1 alpar@1: 4 0 0 0 0 0 0 0 0 1 alpar@1: 5 0 0 0 0 0 0 0 0 1 alpar@1: 6 0 0 0 0 0 0 0 0 1 alpar@1: 7 0 0 0 0 0 0 0 0 1 alpar@1: 8 0 0 0 0 0 0 0 0 0 alpar@1: 9 0 0 0 0 0 0 0 0 0 alpar@1: 10 0 0 0 0 0 0 0 0 0 alpar@1: 11 0 0 0 0 0 0 0 0 0 alpar@1: 12 0 0 0 0 0 0 0 0 0 alpar@1: 13 0 0 0 0 0 0 0 0 0 alpar@1: 14 0 0 0 0 0 0 0 0 0 alpar@1: 15 0 0 0 0 0 0 0 0 0 alpar@1: 16 0 0 0 0 0 0 0 0 0;