resq/utils/schedule_solver/solver.py
2021-09-01 09:04:31 +00:00

175 lines
7.6 KiB
Python

from __future__ import print_function
from ortools.linear_solver import pywraplp
import sys
def main():
# days
days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
# hours
hours = [
'00',
'01',
'02',
'03',
'04',
'05',
'06',
'07',
'08',
'09',
'10',
'11',
'12',
'13',
'14',
'15',
'16',
'17',
'18',
'19',
'20',
'21',
'22',
'23']
# initialize required hours - req_hours[days][hours]
req_hours = [[0 for x in range(len(hours))] for y in range(len(days))]
# get arguments
# there will be 8 arguments, monday to sunday schedule and the shift selected
# sample argument:
# 0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0 0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0 0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0 0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0 0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0 0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0 0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0 24_7
for day_index in range(0, len(days)):
hours_string = sys.argv[day_index + 1]
hours_data = hours_string.split('-')
for hour_index in range(0, len(hours)):
req_hours[day_index][hour_index] = int(hours_data[hour_index])
# index of shift selected is 8
shift = sys.argv[8]
hour_shifts = []
if shift == "24_7":
hour_shifts = [
['00 - 09', 0, 1, 2, 3, 4, 5, 6, 7, 8],
['01 - 10', 1, 2, 3, 4, 5, 6, 7, 8, 9],
['02 - 11', 2, 3, 4, 5, 6, 7, 8, 9, 10],
['03 - 12', 3, 4, 5, 6, 7, 8, 9, 10, 11],
['04 - 13', 4, 5, 6, 7, 8, 9, 10, 11, 12],
['05 - 14', 5, 6, 7, 8, 9, 10, 11, 12, 13],
['06 - 15', 6, 7, 8, 9, 10, 11, 12, 13, 14],
['07 - 16', 7, 8, 9, 10, 11, 12, 13, 14, 15],
['08 - 17', 8, 9, 10, 11, 12, 13, 14, 15, 16],
['09 - 18', 9, 10, 11, 12, 13, 14, 15, 16, 17],
['10 - 19', 10, 11, 12, 13, 14, 15, 16, 17, 18],
['11 - 20', 11, 12, 13, 14, 15, 16, 17, 18, 19],
['12 - 21', 12, 13, 14, 15, 16, 17, 18, 19, 20],
['13 - 22', 13, 14, 15, 16, 17, 18, 19, 20, 21],
['14 - 23', 14, 15, 16, 17, 18, 19, 20, 21, 22],
['15 - 00', 15, 16, 17, 18, 19, 20, 21, 22, 23],
['16 - 01', 16, 17, 18, 19, 20, 21, 22, 23, 0],
['17 - 02', 17, 18, 19, 20, 21, 22, 23, 0, 1],
['18 - 03', 18, 19, 20, 21, 22, 23, 0, 1, 2],
['19 - 04', 19, 20, 21, 22, 23, 0, 1, 2, 3],
['20 - 05', 20, 21, 22, 23, 0, 1, 2, 3, 4],
['21 - 06', 21, 22, 23, 0, 1, 2, 3, 4, 5],
['22 - 07', 22, 23, 0, 1, 2, 3, 4, 5, 6],
['23 - 08', 23, 0, 1, 2, 3, 4, 5, 6, 7]]
if shift == "8AM_5PM":
hour_shifts = [
['07 - 16', 7, 8, 9, 10, 11, 12, 13, 14, 15],
['08 - 17', 8, 9, 10, 11, 12, 13, 14, 15, 16]]
if shift == "7AM_10PM":
hour_shifts = [
['07 - 16', 7, 8, 9, 10, 11, 12, 13, 14, 15],
['08 - 17', 8, 9, 10, 11, 12, 13, 14, 15, 16],
['09 - 18', 9, 10, 11, 12, 13, 14, 15, 16, 17],
['10 - 19', 10, 11, 12, 13, 14, 15, 16, 17, 18],
['11 - 20', 11, 12, 13, 14, 15, 16, 17, 18, 19],
['12 - 21', 12, 13, 14, 15, 16, 17, 18, 19, 20],
['13 - 22', 13, 14, 15, 16, 17, 18, 19, 20, 21]]
if shift == "6AM_7PM":
hour_shifts = [
['06 - 15', 6, 7, 8, 9, 10, 11, 12, 13, 14],
['07 - 16', 7, 8, 9, 10, 11, 12, 13, 14, 15],
['08 - 17', 8, 9, 10, 11, 12, 13, 14, 15, 16],
['09 - 18', 9, 10, 11, 12, 13, 14, 15, 16, 17],
['10 - 19', 10, 11, 12, 13, 14, 15, 16, 17, 18]]
# all possible days riders come in
day_shifts = [
['Mon - Sat', 0, 1, 2, 3, 4, 5], # Mon - Sat
['Tue - Sun', 1, 2, 3, 4, 5, 6], # Tue - Sun
['Wed - Mon', 2, 3, 4, 5, 6, 0], # Wed - Mon
['Thu - Tue', 3, 4, 5, 6, 0, 1], # Thu - Tue
['Fri - Wed', 4, 5, 6, 0, 1, 2], # Fri - Wed
['Sat - Thu', 5, 6, 0, 1, 2, 3], # Sat - Thu
['Sun - Fri', 6, 0, 1, 2, 3, 4]] # Sun - Fri
# build shift lookup index
# instantiate glop solver
solver = pywraplp.Solver('SolveSchedule', pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)
# solver variables
solv_shifts = [[0 for x in range(len(hour_shifts))] for y in range(len(day_shifts))]
# objective
objective = solver.Objective()
# variables for shifts
for day_index in range(0, len(day_shifts)):
for hour_index in range(0, len(hour_shifts)):
solv_shifts[day_index][hour_index] = solver.IntVar(0, solver.infinity(), day_shifts[day_index][0] + ' ' + hour_shifts[hour_index][0])
# objective is to minimize number of shifts
objective.SetCoefficient(solv_shifts[day_index][hour_index], 1)
objective.SetMinimization()
# set constraints
constraints = [[0 for x in range(len(hours))] for y in range(len(days))]
# go through all days
for day_index in range(0, len(days)):
# go through all hours
for hour_index in range(0, len(hours)):
# hour personnel should be equal or less than shift personnel that covers those hours
# set the required manpower for that day + hour combo
# print('setting constraint for', day_index, '-', hour_index, '=', req_hours[day_index][hour_index])
constraints[day_index][hour_index] = solver.Constraint(req_hours[day_index][hour_index], solver.infinity())
# go through all day shifts
for shift_day in range(0, len(day_shifts)):
# go through days inside day shift
for shift_day_index in range(1, len(day_shifts[shift_day])):
# is day shift part of that day?
if day_index == day_shifts[shift_day][shift_day_index]:
# go through all hour shifts
for shift_hour in range(0, len(hour_shifts)):
# go through all hours inside hour shift
for shift_hour_index in range(1, len(hour_shifts[shift_hour])):
# is hour shift part of the hour
if hour_index == hour_shifts[shift_hour][shift_hour_index]:
# print(day_index, ' - ', hour_index, ' vs ', day_shifts[shift_day][shift_day_index], ' - ', hour_shifts[shift_hour][shift_hour_index])
# add it to constraint
constraints[day_index][hour_index].SetCoefficient(solv_shifts[shift_day][shift_hour], 1)
# solve it!
status = solver.Solve()
#print('Number of variables =', solver.NumVariables())
#print('Number of constraints =', solver.NumConstraints())
if status == solver.OPTIMAL:
#print('Optimal solution found!')
for day_index in range(0, len(day_shifts)):
for hour_index in range(0, len(hour_shifts)):
result = solv_shifts[day_index][hour_index].solution_value()
if result > 0:
print(day_index, hour_index, int(solv_shifts[day_index][hour_index].solution_value()), sep='-')
#print(day_shifts[day_index][0], ' ', hour_shifts[hour_index][0], ' = ', int(solv_shifts[day_index][hour_index].solution_value()), sep='')
else:
if status == solver.FEASIBLE:
print('Feasible solution found!')
else:
print('Could not solve problem.')
if __name__ == '__main__':
main()