-
Notifications
You must be signed in to change notification settings - Fork 0
/
multi_hub_app.py
130 lines (96 loc) · 4.61 KB
/
multi_hub_app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import streamlit as st
import pandas as pd
import pyomo.environ as pyo
# Streamlit app title
st.title("Multiple-Allocation Problem with Interconnected Hubs")
# Description of the Model
st.markdown("""
### Description of the Model
The model is a multiple-allocation problem with interconnected hubs.
The objective is to minimize the total cost of allocating goods from multiple origins to multiple destinations.
The cost of allocating goods from origin i to destination j is the sum of the cost of allocating goods from origin i to hub k and from hub m to destination j.
The number of hubs to be used is a parameter that can be modified.
The model is formulated as a mixed-integer linear programming problem.
The model is solved using the CBC solver.
---
""")
# Optional file upload
uploaded_file = st.file_uploader("Upload Cost Matrix Excel file", type=["xlsx"])
if uploaded_file is not None:
cost_df = pd.read_excel(uploaded_file)
else:
# Load the data into a DataFrame
try:
cost_df = pd.read_excel('cost_matrix_multi_hub.xlsx')
except FileNotFoundError:
st.error("Default cost matrix file 'cost_matrix_multi_hub.xlsx' not found. Please upload an Excel file.")
st.stop()
# Load the data into a DataFrame
cost_df.set_index('Origin/Destination', inplace=True)
st.write("Cost Matrix:")
editable_cost_df = st.data_editor(cost_df)
# Transform the DataFrame into a dictionary for combined costs c(i, k, m, j)
cost = {}
nodes = list(editable_cost_df.index)
hubs = list(editable_cost_df.columns)
pairs = [(i, j) for i in nodes for j in nodes if i != j]
hub_pairs = [(k, m) for k in hubs for m in hubs if k != m]
for i in editable_cost_df.index:
for j in editable_cost_df.index:
if i != j:
for k in editable_cost_df.columns:
for m in editable_cost_df.columns:
if k != m:
cost[(i, k, m, j)] = editable_cost_df.loc[i, k] + editable_cost_df.loc[j, m]
# Initialize the model
model = pyo.ConcreteModel()
# Number of hubs to be used (modifiable via Streamlit)
p = st.slider("Number of hubs to be used", min_value=2, max_value=len(hubs), value=5)
if st.button('Calculate'):
# Define sets
model.pairs = pyo.Set(initialize=pairs, dimen=2)
model.hub_pairs = pyo.Set(initialize=hub_pairs, dimen=2)
model.hubs = pyo.Set(initialize=hubs)
# Decision Variables
model.x = pyo.Var(model.pairs, model.hub_pairs, within=pyo.Binary)
model.y = pyo.Var(model.hubs, within=pyo.Binary)
# Objective function: Minimize total cost
def objective_rule(model):
return sum(cost[(i, k, m, j)] * model.x[(i, j), (k, m)]
for (i, j) in model.pairs for (k, m) in model.hub_pairs)
model.obj = pyo.Objective(rule=objective_rule, sense=pyo.minimize)
# Constraints
# Total hubs constraint
def total_hubs_constraint(model):
return sum(model.y[k] for k in model.hubs) == p
model.total_hubs_constraint = pyo.Constraint(rule=total_hubs_constraint)
# Allocation constraint
def allocation_constraint(model, i, j):
return sum(model.x[(i, j), (k, m)] for (k, m) in model.hub_pairs) == 1
model.allocation_constraint = pyo.Constraint(model.pairs, rule=allocation_constraint)
# First flow constraint
def flow_constraint_a(model, i, j, k):
return sum(model.x[(i, j), (k, m)] for m in hubs if k != m) <= model.y[k]
model.flow_constraint_a = pyo.Constraint(pairs, hubs, rule=flow_constraint_a)
# Second flow constraint
def flow_constraint_b(model, i, j, m):
return sum(model.x[(i, j), (k, m)] for k in hubs if m != k) <= model.y[m]
model.flow_constraint_b = pyo.Constraint(pairs, hubs, rule=flow_constraint_b)
# Non-negativity and binary constraints are implicit in the variable definitions
# Solve the model
opt = pyo.SolverFactory('cbc')
results = opt.solve(model)
# Extract the objective function value
objective_value = pyo.value(model.obj)
st.write("\nObjective Function Value:", objective_value)
# Extract results
allocation_plan = pd.DataFrame(
[(i, j, k, m, pyo.value(model.x[(i, j), (k, m)])) for (i, j) in model.pairs for (k, m) in model.hub_pairs if pyo.value(model.x[(i, j), (k, m)]) > 0],
columns=['Origin', 'Destination', 'First Hub', 'Second Hub', 'Allocation']
)
st.write("\nAllocation Plan Table")
st.write(allocation_plan[['Origin', 'Destination', 'First Hub', 'Second Hub']])
st.markdown('''
---
Created by [Lazuardi Al-Muzaki](https://github.com/Lazuardis)
''')