EKT-scheduler/ekg.py

141 lines
4.1 KiB
Python
Raw Normal View History

2024-11-14 07:24:02 +00:00
import pandas as pd #handling dataframes
import numpy as np #numpy for array management
import matplotlib.pyplot as plt #plotting
import plotly.express as px #generate beautiful interactive plots
from datetime import timedelta, date #for later datetimes processing
from itertools import product
import datetime
import openpyxl
#pyomo.environ provides the framework for build the model
import pyomo.environ as pyo
#SolverFactory allows to call the solver to solve
from pyomo.opt import SolverFactory
#store the solver in a variable to call it later, we need to tell google colab
#the specific path on which the solver was installed
opt_glpk = pyo.SolverFactory('glpk', executable='/usr/bin/glpsol')
activities = {0:'Start',
1: 'A',
2: 'B',
3: 'C',
4: 'D',
5: 'E',
6: 'F',
7: 'G',
8: 'H',
9: 'I',
10: 'J',
11:'End'}
p = [0, 5, 2, 5, 6, 5, 2, 3, 2, 4, 3, 0] # activity durations
u = [[0, 0, 0], # list of resource consumptions
[1, 0, 0],
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
[0, 1, 0],
[0, 1, 0],
[0, 0, 1],
[0, 0, 1],
[0, 0, 1],
[0, 0, 1],
[0, 0, 0]]
E = [[0, 1], # list of precedence constraints
[0, 2],
[1, 3],
[2, 4],
[3, 5],
[3, 6],
[3, 7],
[5, 8],
[6, 9],
[8, 10],
[9, 10],
[4, 11],
[7, 11],
[10, 11]]
c = [1,1,1] # max resource capacity
n = len(p) - 2
ph = sum(p)
(R, J, T) = (range(len(c)), range(len(p)), range(ph))
model = pyo.ConcreteModel() # create empty model (like empty canvas)
model.J = pyo.RangeSet(0,len(p)-1) # set for the activities
model.T = pyo.RangeSet(0,ph) # set for the days in the planning horizon
model.Xs = pyo.Var(model.J,model.T,within = pyo.Binary) # variables
Xs = model.Xs
# Objective Function Eq. (1)
# Next we proceed to create our objective function. Following the exact formula described by equation (1).
# sum of the dates for the final activity (the dummy end)
Z = sum([t*Xs[(n+1,t)] for t in model.T])
# we want to minimize this objective function
model.obj = pyo.Objective(expr = Z,sense=pyo.minimize)
# Constraint (2): Only one start time
model.one_xs = pyo.ConstraintList() #create a list of constraints
for j in model.J:
#add constraints to the list created above
model.one_xs.add(expr = sum(Xs[(j,t)] for t in model.T)==1)
# Constraint (3): Precedence constraints
model.pc = pyo.ConstraintList() # precedence constraints
for (j,s) in E:
model.pc.add(expr = sum(t*Xs[(s,t)] - t*Xs[(j,t)] for t in model.T) >= p[j])
# Constraint (4): Resource capacity constraints
model.rl = pyo.ConstraintList() #resource level constraints
print(R)
print(T)
for (r, t) in product(R, T):
model.rl.add(expr = sum(u[j][r]*Xs[(j,t2)] for j in model.J for t2 in range(max(0, t - p[j] + 1), t + 1)) <= c[r])
# solve
opt_glpk.options['tmlim'] = 60
opt_glpk.options["mipgap"] = 0
results = opt_glpk.solve(model,tee=True) # ask the solver to solve the model
results.write()
SCHEDULE = {}
for (j, t) in product(J, T):
if pyo.value(Xs[(j, t)]) >= 0.99: #only get the x values == 1
a = activities[j]
SCHEDULE[a] = {'s':t,'f':t+p[j]}
print(f'Activity {j}, begins at t={t} and finishes at {t+p[j]}')
out = pd.DataFrame(SCHEDULE).T
SCHEDULE = out.T.to_dict()
#start_date = datetime.date(2023, 1, 11)
start_date = datetime.date.today()
SCHEDULE_DF = pd.DataFrame(SCHEDULE).T
SCHEDULE_DF['Start_Date'] = [str(start_date + datetime.timedelta(days=s)) for s in SCHEDULE_DF['s']]
SCHEDULE_DF['Finish_Date'] =[str(start_date + datetime.timedelta(days=f)) for f in SCHEDULE_DF['f']]
SCHEDULE_DF.to_csv('output_schedule.csv') #export csv file
SCHEDULE_DF.to_excel('output_schedule.xlsx') #export excel file
fig = px.timeline(SCHEDULE_DF,
x_start="Start_Date",
x_end="Finish_Date",
y=SCHEDULE_DF.index,title='Project Gantt Chart')
fig.update_yaxes(autorange="reversed") # otherwise tasks are listed from the bottom up
fig.write_html("Gantt_chart.html")
fig.show()