138 lines
3.8 KiB
Python
138 lines
3.8 KiB
Python
import pyomo
|
|
import pandas as pd
|
|
from pulp import *
|
|
|
|
class Scheduler:
|
|
def __init__(self,
|
|
task_path='data/tasks.csv',
|
|
block_path='data/blocks.csv',
|
|
patient_path='data/patients.csv'):
|
|
"""
|
|
Read case and session data into Pandas DataFrames
|
|
Args:
|
|
case_file_path (str): path to case data in CSV format
|
|
session_file_path (str): path to theatre session data in CSV format
|
|
"""
|
|
try:
|
|
self.df_tasks = pd.read_csv(task_path)
|
|
except FileNotFoundError:
|
|
print("Task data not found.")
|
|
try:
|
|
self.df_blocks = pd.read_csv(block_path)
|
|
except FileNotFoundError:
|
|
print("Session data not found")
|
|
try:
|
|
self.df_patients = pd.read_csv(patient_path)
|
|
except FileNotFoundError:
|
|
print("Patient data not found")
|
|
|
|
self.create_lists()
|
|
self.extend_data()
|
|
|
|
def extend_data(self):
|
|
|
|
# Date to integer all dates
|
|
# tasks date
|
|
newcol = [self.date2int(date) for date in self.df_tasks['date'].tolist()]
|
|
self.df_tasks.insert(7, "dateint", newcol)
|
|
|
|
# block date
|
|
newcol2 = [self.date2int(date) for date in self.df_blocks['day'].tolist()]
|
|
self.df_blocks.insert(3, "dateint", newcol2)
|
|
return
|
|
|
|
def create_lists(self):
|
|
self.s = self.df_tasks['priority'].tolist()
|
|
self.d = self.df_tasks['duration'].tolist()
|
|
self.dates = self.df_tasks['date'].tolist()
|
|
self.b = self.df_blocks['available'].tolist()
|
|
self.block_dates= self.df_blocks['day'].tolist()
|
|
|
|
self.patient_ids = self.df_patients['patient'].tolist()
|
|
self.task_patient= self.df_tasks['patient'].tolist()
|
|
# convert dates of tasks and blocks to (week,day)
|
|
self.convert_dates()
|
|
return
|
|
|
|
def convert_dates(self):
|
|
self.week_day = [self.date2week_day(date) for date in self.dates]
|
|
self.block_week_day = [self.date2week_day(date) for date in self.block_dates]
|
|
|
|
def date2int(self, date, dzero="25/11/2024"):
|
|
return self.date2week_day(date)[0]*7 + self.date2week_day(date)[1]
|
|
|
|
def date2week_day(self, date, dzero="25/11/2024"):
|
|
d0 = pd.to_datetime(dzero, dayfirst=True)
|
|
delta = (pd.to_datetime(date, dayfirst=True) - d0).days
|
|
day = delta%7
|
|
week = int((delta - day)/7)
|
|
return week,day
|
|
|
|
def int2date(week, day):
|
|
d0 = pd.to_datetime("25/11/2024", dayfirst=True)
|
|
delta = datetime.timedelta(days = 7*week + day)
|
|
date = d0 + delta
|
|
return date
|
|
|
|
|
|
sc = Scheduler()
|
|
print(sc.df_tasks)
|
|
print(sc.df_blocks)
|
|
print(sc.df_patients)
|
|
|
|
# Declare variables for optimization
|
|
s = sc.s
|
|
print(f's = {s}')
|
|
|
|
d = sc.d
|
|
print(f'd = {d}')
|
|
|
|
b = sc.b
|
|
print(f'b = {b}')
|
|
|
|
B = len(b)
|
|
n = len(s)
|
|
A = sum(b)
|
|
|
|
# Import PuLP
|
|
|
|
# Define the problem
|
|
prob = LpProblem("Schedule_Tasks", LpMaximize)
|
|
|
|
# Define y
|
|
y = LpVariable.dicts('Block', [(i, t) for i in range(n) for t in range(B)], cat = 'Binary')
|
|
|
|
# Definite objective function
|
|
prob += lpSum(s[i]*b[t]*y[(i,t)] for i in range(n) for t in range(B))
|
|
|
|
# CONSTRAINTS
|
|
# Constraint #1
|
|
prob += lpSum(y[(i,t)] for i in range(n) for t in range(B)) <= A
|
|
|
|
# Constraint #2
|
|
for i in range(n):
|
|
prob += lpSum(y[(i,t)] for t in range(B)) <= d[i]
|
|
|
|
# Constraint #3
|
|
for t in range(B):
|
|
prob += lpSum(y[(i,t)] for i in range(n)) <= 1
|
|
|
|
prob.solve()
|
|
|
|
# Visualize solution
|
|
tasks_blocks = pd.DataFrame(columns=['Task', 'Block'])
|
|
|
|
for i in range(n):
|
|
for t in range(B):
|
|
if y[(i,t)].varValue == 1:
|
|
tasks_blocks = pd.concat([tasks_blocks,
|
|
pd.DataFrame({'Task': [i], 'Block': [t], 'Patient': sc.task_patient[i] })],
|
|
ignore_index=True)
|
|
|
|
print(tasks_blocks)
|
|
|
|
print(sc.df_tasks)
|
|
print(sc.df_patients)
|
|
print(sc.df_blocks)
|
|
print(type(sc.df_blocks))
|