|
|
@ -0,0 +1,131 @@ |
|
|
|
# Import necessary libraries |
|
|
|
%pip install gurobipy |
|
|
|
import pandas as pd |
|
|
|
from gurobipy import * |
|
|
|
|
|
|
|
# Define model |
|
|
|
model = Model("CloudServiceTransportation") |
|
|
|
|
|
|
|
# Number of providers (AWS, Azure, Google) |
|
|
|
m = 3 # AWS, Azure, Google |
|
|
|
# Number of services (C1, C2, AI/ML) |
|
|
|
n = 3 # C1, C2, AI/ML |
|
|
|
|
|
|
|
# Cost coefficients for AWS, Azure, and Google for each service (no storage cost) |
|
|
|
costs_AWS = {'C1': 0.1664, 'C2': 0.08, 'AI/ML': 3.06} |
|
|
|
costs_Azure = {'C1': 0.2021, 'C2': 0.10, 'AI/ML': 0.90} |
|
|
|
costs_Google = {'C1': 0.1900, 'C2': 0.10, 'AI/ML': 1.80} |
|
|
|
|
|
|
|
# Supply limits for each provider (AWS, Azure, Google) - fixed units |
|
|
|
supply_AWS = {'C1': 100, 'C2': 300, 'AI/ML': 50} |
|
|
|
supply_Azure = {'C1': 120, 'C2': 180, 'AI/ML': 80} |
|
|
|
supply_Google = {'C1': 130, 'C2': 200, 'AI/ML': 70} |
|
|
|
|
|
|
|
# Demand for each service (C1, C2, AI/ML) |
|
|
|
demand = {'C1': 100, 'C2': 100, 'AI/ML': 50} |
|
|
|
|
|
|
|
# Inter-provider egress costs |
|
|
|
inter_provider_egress = { |
|
|
|
('AWS', 'Azure'): 20, |
|
|
|
('AWS', 'Google'): 30, |
|
|
|
('Azure', 'Google'): 15, |
|
|
|
('Azure', 'AWS'): 25, |
|
|
|
('Google', 'AWS'): 35, |
|
|
|
('Google', 'Azure'): 10 |
|
|
|
} |
|
|
|
|
|
|
|
# Budget constraint |
|
|
|
budget = 20000 # Total budget |
|
|
|
|
|
|
|
# Decision variables for quantities to transport |
|
|
|
x = {} # Amount of service allocated |
|
|
|
y = {} # Binary variable indicating provider selection |
|
|
|
w = {} # Egress costs between providers |
|
|
|
|
|
|
|
# Create decision variables |
|
|
|
for i, provider_from in enumerate(['AWS', 'Azure', 'Google']): |
|
|
|
for j, service in enumerate(['C1', 'C2', 'AI/ML']): |
|
|
|
x[i, j] = model.addVar(vtype=GRB.CONTINUOUS, lb=0, name=f"{provider_from}_{service}") |
|
|
|
y[i, j] = model.addVar(vtype=GRB.BINARY, name=f"provider_{provider_from}_service_{service}") |
|
|
|
for k, provider_to in enumerate(['AWS', 'Azure', 'Google']): |
|
|
|
if provider_from != provider_to: |
|
|
|
w[i, j, k] = model.addVar(vtype=GRB.CONTINUOUS, lb=0, name=f"egress_{provider_from}_{service}_{provider_to}") |
|
|
|
|
|
|
|
# Update model |
|
|
|
model.update() |
|
|
|
|
|
|
|
# Objective function: Minimize total cost (including egress costs) |
|
|
|
total_cost = ( |
|
|
|
sum(costs_AWS[service] * x[0, j] for j, service in enumerate(['C1', 'C2', 'AI/ML'])) + |
|
|
|
sum(costs_Azure[service] * x[1, j] for j, service in enumerate(['C1', 'C2', 'AI/ML'])) + |
|
|
|
sum(costs_Google[service] * x[2, j] for j, service in enumerate(['C1', 'C2', 'AI/ML'])) + |
|
|
|
sum(inter_provider_egress[('AWS', 'Azure')] * w[0, j, 1] for j in range(n)) + |
|
|
|
sum(inter_provider_egress[('AWS', 'Google')] * w[0, j, 2] for j in range(n)) + |
|
|
|
sum(inter_provider_egress[('Azure', 'Google')] * w[1, j, 2] for j in range(n)) + |
|
|
|
sum(inter_provider_egress[('Azure', 'AWS')] * w[1, j, 0] for j in range(n)) + |
|
|
|
sum(inter_provider_egress[('Google', 'AWS')] * w[2, j, 0] for j in range(n)) + |
|
|
|
sum(inter_provider_egress[('Google', 'Azure')] * w[2, j, 1] for j in range(n)) |
|
|
|
) |
|
|
|
model.setObjective(total_cost, GRB.MINIMIZE) |
|
|
|
|
|
|
|
# Supply constraints |
|
|
|
for i, provider in enumerate(['AWS', 'Azure', 'Google']): |
|
|
|
for j, service in enumerate(['C1', 'C2', 'AI/ML']): |
|
|
|
supply_limit = {'AWS': supply_AWS, 'Azure': supply_Azure, 'Google': supply_Google}[provider][service] |
|
|
|
model.addConstr(x[i, j] <= supply_limit * y[i, j], name=f"supply_{provider}_{service}") |
|
|
|
|
|
|
|
# Demand constraints |
|
|
|
for j, service in enumerate(['C1', 'C2', 'AI/ML']): |
|
|
|
model.addConstr(sum(x[i, j] for i in range(m)) == demand[service], name=f"demand_{service}") |
|
|
|
|
|
|
|
# Budget constraint |
|
|
|
model.addConstr(total_cost <= budget, name="BudgetConstraint") |
|
|
|
|
|
|
|
# Only one provider per service |
|
|
|
for j, service in enumerate(['C1', 'C2', 'AI/ML']): |
|
|
|
model.addConstr(sum(y[i, j] for i in range(m)) == 1, name=f"one_provider_per_service_{service}") |
|
|
|
|
|
|
|
# Egress constraints: Egress cost applies only when transferring between providers |
|
|
|
for i in range(m): |
|
|
|
for j in range(n): |
|
|
|
for k in range(m): |
|
|
|
if i != k: |
|
|
|
model.addConstr(w[i, j, k] <= x[i, j], name=f"egress_constraint_{i}_{j}_{k}") |
|
|
|
|
|
|
|
# Optimize model |
|
|
|
model.optimize() |
|
|
|
|
|
|
|
# Display results in a table format if optimal solution is found |
|
|
|
if model.status == GRB.OPTIMAL: |
|
|
|
# Create a list to hold the results |
|
|
|
results = [] |
|
|
|
|
|
|
|
# Calculate egress costs dynamically for each provider |
|
|
|
egress_costs = {'AWS': 0, 'Azure': 0, 'Google': 0} |
|
|
|
for i, provider_from in enumerate(['AWS', 'Azure', 'Google']): |
|
|
|
for j in range(n): |
|
|
|
for k, provider_to in enumerate(['AWS', 'Azure', 'Google']): |
|
|
|
if provider_from != provider_to: |
|
|
|
egress_costs[provider_from] += w[i, j, k].x * inter_provider_egress[(provider_from, provider_to)] |
|
|
|
|
|
|
|
# Gather results for each provider |
|
|
|
for i, provider in enumerate(['AWS', 'Azure', 'Google']): |
|
|
|
row = [provider] |
|
|
|
# Add allocated quantities of each service |
|
|
|
for j, service in enumerate(['C1', 'C2', 'AI/ML']): |
|
|
|
allocated_quantity = x[i, j].x |
|
|
|
row.append(allocated_quantity) |
|
|
|
# Append the calculated egress cost |
|
|
|
row.append(egress_costs[provider]) |
|
|
|
results.append(row) |
|
|
|
|
|
|
|
# Convert to DataFrame for display |
|
|
|
columns = ['Provider', 'C1 (units)', 'C2 (units)', 'AI/ML (units)', 'Egress Cost ($)'] |
|
|
|
df = pd.DataFrame(results, columns=columns) |
|
|
|
|
|
|
|
# Display the DataFrame and the total optimal cost |
|
|
|
print(f"Optimal Cost: {model.objVal}") |
|
|
|
print(df) |
|
|
|
else: |
|
|
|
print("No optimal solution found") |
|
|
|
|