resq/utils/schedule_solver/solver.py

144 lines
5.7 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])
argv_index = day_index + 2
# number of days is fixed at 7 so the number of shifts will be in index 8
num_shifts = sys.argv[argv_index]
hour_shifts = []
for shift_ctr in range(0, int(num_shifts)):
# form list within the list
hour_shift_item = []
shift = sys.argv[argv_index+1]
# append to list
hour_shift_item.append(shift)
# append the list to the list
hour_shifts.append(hour_shift_item)
argv_index+=1
# 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()