my problem is flagged as infeasible, but i cant find any conflict in my constraints,
i formulate an LP model to minimize total costs, which include shipping from China in boxes to the US warehouses, distribution from US warehouses to their respective customer locations in units, and possibly any shortage costs if the demand exceeds available inventory
thanks,
CODE:
<code>import pulp
def create_lp_problem(us_warehouses, china_warehouse, shipping_methods, time_periods, skus, customer_locations,
shipping_cost, admin_cost, distribution_cost, shortage_cost, units_per_box, whight_per_sku, demand,
inventory_in_us, inventory_in_china,
shipment_duration):
import os
# Set the timeout to 10 seconds
#os.environ['PYDEVD_WARN_SLOW_RESOLVE_TIMEOUT'] = '10'
# Large constant for Big-M constraints
M = 200
print('Create the LP problem')
model = pulp.LpProblem("Supply_Chain_Optimization", pulp.LpMinimize)
# Decision Variables
# inventory on the way from China to U.S. Warehouses in boxes
x = {
china_warehouse: {
u: {
s: {
t: {k: pulp.LpVariable(f"Shipment_Quantity_{china_warehouse}_{u}_{s}_{t}_{k}", 0, None, pulp.LpInteger)
for k in skus}
for t in time_periods}
for s in shipping_methods}
for u in us_warehouses}
}
# inventory on the way from U.S. Warehouses to Customer in units
y = {
u: {
l: {
t: {k: pulp.LpVariable(f"Distribution_Quantity_{u}_{l}_{t}_{k}", 0, None, pulp.LpInteger)
for k in skus}
for t in time_periods}
for l in customer_locations[u]}
for u in us_warehouses
}
# binary variables for shipment and admin cost sku level
z_shipment = {
china_warehouse: {
u: {
s: {
t: {k: pulp.LpVariable(f"Shipment_Binary_{china_warehouse}_{u}_{s}_{t}_{k}", 0, 1, pulp.LpBinary)
for k in skus}
for t in time_periods}
for s in shipping_methods}
for u in us_warehouses}
}
# binary variables for admin cost
z_admin = {
china_warehouse: {
u: {
s: {
t: pulp.LpVariable(f"Admin_Binary_{china_warehouse}_{u}_{s}_{t}", 0, 1, pulp.LpBinary)
for t in time_periods}
for s in shipping_methods}
for u in us_warehouses}
}
china_inventory = {
t: {k: pulp.LpVariable(f"China_Inventory_{t}_{k}", 0, None, pulp.LpInteger) for k in skus}
for t in time_periods
}
us_inventory = {
u: {
t: {k: pulp.LpVariable(f"US_Inventory_{u}_{t}_{k}", 0, None, pulp.LpInteger) for k in skus}
for t in time_periods
}
for u in us_warehouses
}
# Objective Function
model += (
pulp.lpSum(
shipping_cost[china_warehouse, u, s] * x[china_warehouse][u][s][t][k] * units_per_box[k] * whight_per_sku[k]
for u in us_warehouses for s in shipping_methods for t in time_periods for k in skus
)
+ pulp.lpSum(
admin_cost[china_warehouse, u, s] * z_admin[china_warehouse][u][s][t]
for u in us_warehouses for s in shipping_methods for t in time_periods
)
+ pulp.lpSum(
distribution_cost[u, l] * y[u][l][t][k] * whight_per_sku[k]
for u in us_warehouses for l in customer_locations[u] for t in time_periods for k in skus
)
+ pulp.lpSum(
shortage_cost * (demand[l, t, k] - pulp.lpSum(y[u][l][t][k] for u in us_warehouses))
for t in time_periods for k in skus for l in customer_locations[list(customer_locations.keys())[0]]
)
), "Total_Cost"
# Constraints
# Inventory Balance at U.S. Warehouses
for t_idx, t in enumerate(time_periods):
for u in us_warehouses:
for k in skus:
if t_idx > 0:
prev_t = time_periods[t_idx - 1]
# Shipments received at time t
shipments_received = pulp.lpSum(
x[china_warehouse][u][s][time_periods[t_idx - int(shipment_duration[(u,s)])]][k]
for s in shipping_methods if t_idx - shipment_duration[(u,s)] >= 0
)
model += (
us_inventory[u][t][k] == us_inventory[u][prev_t][k] + inventory_in_us[u, t, k] +
shipments_received - pulp.lpSum(y[u][l][t][k] for l in customer_locations[u])
), f"Inventory_Balance_{u}_{t}_{k}"
else:
model += (
us_inventory[u][t][k] == inventory_in_us[u, t, k]
), f"Initial_Inventory_{u}_{t}_{k}"
#Inventory Balance at China Warehouse
for t_idx, t in enumerate(time_periods):
for k in skus:
if t_idx == 0:
model += (
china_inventory[t][k] == inventory_in_china[t,k]
), f"China_Initial_Inventory_{k}"
else:
prev_t = time_periods[t_idx - 1]
model += (
china_inventory[t][k] == china_inventory[prev_t][k] +
inventory_in_china[t,k] -
pulp.lpSum(x[china_warehouse][u][s][t][k]* units_per_box[k] for u in us_warehouses for s in shipping_methods)
), f"China_Inventory_Balance_{t}_{k}"
# Binary Linking Constraints
for u in us_warehouses:
for s in shipping_methods:
for t in time_periods:
for k in skus:
model += z_admin[china_warehouse][u][s][t] >= z_shipment[china_warehouse][u][s][t][k],
f"Binary_Link_{u}_{s}_{t}_{k}"
slack = pulp.LpVariable.dicts("Slack", (us_warehouses, shipping_methods, time_periods, skus), 0, None, pulp.LpContinuous)
# Big-M Constraints
for u in us_warehouses:
for s in shipping_methods:
for t in time_periods:
for k in skus:
model += x[china_warehouse][u][s][t][k] <= M * z_shipment[china_warehouse][u][s][t][k]+ slack[u][s][t][k],
f"BigM_{u}_{s}_{t}_{k}"
print('solving the model')
solver = pulp.PULP_CBC_CMD() # Displays solver logs
model.solve(solver)
# set model.constraints to file for debugging
model.writeLP("model.lp")
#model.solve(pulp.PULP_CBC_CMD(msg=1, options=['infeasibility']))
#model.solve(pulp.PULP_CBC_CMD(msg=1)) # Set the timeout to default
os.environ['PYDEVD_WARN_SLOW_RESOLVE_TIMEOUT'] = '0.5'
return model
import pulp
def test_create_lp_problem():
# Define test data
us_warehouses = ["us1", "us2"]
china_warehouse = "china"
shipping_methods = ["method1", "method2"]
time_periods = ["t1", "t2", "t3", "t4"]
skus = ["sku1"]
poligons = ["loc1", "loc2"]
customer_locations = {
"us1": [p for p in poligons],
"us2": [p for p in poligons]
}
shipping_cost = {(china_warehouse, u, s): 10 for u in us_warehouses for s in shipping_methods}
shipping_cost.update(
{('china', 'us1', 'method1'): 100, ('china', 'us1', 'method2'): 2, ('china', 'us2', 'method1'): 100, ('china', 'us2', 'method2'): 2})
admin_cost = {(china_warehouse, u, s): 100 for u in us_warehouses for s in shipping_methods}
# Adjust distribution costs
distribution_cost = {
("us1", "loc1"): 5
}
distribution_cost.update({
("us1", "loc2"): 10
})
distribution_cost.update({
("us2", "loc1"): 10
})
distribution_cost.update({
("us2", "loc2"): 5
})
shortage_cost = 1000
units_per_box = {k: 10 for k in skus}
whight_per_sku = {k: 10 for k in skus}
demand = {(p, t, k): 11 for p in poligons for t in time_periods for k in skus}
inventory_in_us = {(u, t, k): 0 for u in us_warehouses for k in skus for t in time_periods}
inventory_in_us.update({('us1', 't1', 'sku1'): 0, ('us1', 't2', 'sku1'): 0, ('us1', 't3', 'sku1'): 0, ('us2', 't1', 'sku1'): 10, ('us2', 't2', 'sku1'): 0, ('us2', 't3', 'sku1'): 0})
inventory_in_china = {( t, k): 12 for k in skus for t in time_periods}
shipment_duration = {(u, s): 1 for u in us_warehouses for s in shipping_methods}
shipment_duration.update({('us1', 'method1'): 1, ('us1', 'method2'): 2, ('us2', 'method1'): 1, ('us2', 'method2'): 2})
# Call the function with the test data
model = create_lp_problem(
us_warehouses, china_warehouse, shipping_methods, time_periods, skus, customer_locations,
shipping_cost, admin_cost, distribution_cost, shortage_cost, units_per_box, whight_per_sku, demand,
inventory_in_us, inventory_in_china,
shipment_duration
)
# Check if the model is solved successfully
assert pulp.LpStatus[model.status] == 'Optimal', f"Model status: {pulp.LpStatus[model.status]}"
print("Test passed: Model solved successfully")
# Run the test
test_create_lp_problem()```
this is the test model:
* Supply_Chain_Optimization *
Minimize
OBJ: 100 Admin_Binary_china_us1_method1_t1
+ 100 Admin_Binary_china_us1_method1_t2
+ 100 Admin_Binary_china_us1_method1_t3
+ 100 Admin_Binary_china_us1_method2_t1
+ 100 Admin_Binary_china_us1_method2_t2
+ 100 Admin_Binary_china_us1_method2_t3
+ 100 Admin_Binary_china_us2_method1_t1
+ 100 Admin_Binary_china_us2_method1_t2
+ 100 Admin_Binary_china_us2_method1_t3
+ 100 Admin_Binary_china_us2_method2_t1
+ 100 Admin_Binary_china_us2_method2_t2
+ 100 Admin_Binary_china_us2_method2_t3
- 950 Distribution_Quantity_us1_loc1_t1_sku1
- 950 Distribution_Quantity_us1_loc1_t2_sku1
- 950 Distribution_Quantity_us1_loc1_t3_sku1
- 900 Distribution_Quantity_us1_loc2_t1_sku1
- 900 Distribution_Quantity_us1_loc2_t2_sku1
- 900 Distribution_Quantity_us1_loc2_t3_sku1
- 900 Distribution_Quantity_us2_loc1_t1_sku1
- 900 Distribution_Quantity_us2_loc1_t2_sku1
- 900 Distribution_Quantity_us2_loc1_t3_sku1
- 950 Distribution_Quantity_us2_loc2_t1_sku1
- 950 Distribution_Quantity_us2_loc2_t2_sku1
- 950 Distribution_Quantity_us2_loc2_t3_sku1
+ 10000 Shipment_Quantity_china_us1_method1_t1_sku1
+ 10000 Shipment_Quantity_china_us1_method1_t2_sku1
+ 10000 Shipment_Quantity_china_us1_method1_t3_sku1
+ 200 Shipment_Quantity_china_us1_method2_t1_sku1
+ 200 Shipment_Quantity_china_us1_method2_t2_sku1
+ 200 Shipment_Quantity_china_us1_method2_t3_sku1
+ 10000 Shipment_Quantity_china_us2_method1_t1_sku1
+ 10000 Shipment_Quantity_china_us2_method1_t2_sku1
+ 10000 Shipment_Quantity_china_us2_method1_t3_sku1
+ 200 Shipment_Quantity_china_us2_method2_t1_sku1
+ 200 Shipment_Quantity_china_us2_method2_t2_sku1
+ 200 Shipment_Quantity_china_us2_method2_t3_sku1
Subject To
BigM_us1_method1_t1_sku1: - 200 Shipment_Binary_china_us1_method1_t1_sku1
+ Shipment_Quantity_china_us1_method1_t1_sku1 - Slack_us1_method1_t1_sku1
<= 0
BigM_us1_method1_t2_sku1: - 200 Shipment_Binary_china_us1_method1_t2_sku1
+ Shipment_Quantity_china_us1_method1_t2_sku1 - Slack_us1_method1_t2_sku1
<= 0
BigM_us1_method1_t3_sku1: - 200 Shipment_Binary_china_us1_method1_t3_sku1
+ Shipment_Quantity_china_us1_method1_t3_sku1 - Slack_us1_method1_t3_sku1
<= 0
BigM_us1_method2_t1_sku1: - 200 Shipment_Binary_china_us1_method2_t1_sku1
+ Shipment_Quantity_china_us1_method2_t1_sku1 - Slack_us1_method2_t1_sku1
<= 0
BigM_us1_method2_t2_sku1: - 200 Shipment_Binary_china_us1_method2_t2_sku1
+ Shipment_Quantity_china_us1_method2_t2_sku1 - Slack_us1_method2_t2_sku1
<= 0
BigM_us1_method2_t3_sku1: - 200 Shipment_Binary_china_us1_method2_t3_sku1
+ Shipment_Quantity_china_us1_method2_t3_sku1 - Slack_us1_method2_t3_sku1
<= 0
BigM_us2_method1_t1_sku1: - 200 Shipment_Binary_china_us2_method1_t1_sku1
+ Shipment_Quantity_china_us2_method1_t1_sku1 - Slack_us2_method1_t1_sku1
<= 0
BigM_us2_method1_t2_sku1: - 200 Shipment_Binary_china_us2_method1_t2_sku1
+ Shipment_Quantity_china_us2_method1_t2_sku1 - Slack_us2_method1_t2_sku1
<= 0
BigM_us2_method1_t3_sku1: - 200 Shipment_Binary_china_us2_method1_t3_sku1
+ Shipment_Quantity_china_us2_method1_t3_sku1 - Slack_us2_method1_t3_sku1
<= 0
BigM_us2_method2_t1_sku1: - 200 Shipment_Binary_china_us2_method2_t1_sku1
+ Shipment_Quantity_china_us2_method2_t1_sku1 - Slack_us2_method2_t1_sku1
<= 0
BigM_us2_method2_t2_sku1: - 200 Shipment_Binary_china_us2_method2_t2_sku1
+ Shipment_Quantity_china_us2_method2_t2_sku1 - Slack_us2_method2_t2_sku1
<= 0
BigM_us2_method2_t3_sku1: - 200 Shipment_Binary_china_us2_method2_t3_sku1
+ Shipment_Quantity_china_us2_method2_t3_sku1 - Slack_us2_method2_t3_sku1
<= 0
Binary_Link_us1_method1_t1_sku1: Admin_Binary_china_us1_method1_t1
- Shipment_Binary_china_us1_method1_t1_sku1 >= 0
Binary_Link_us1_method1_t2_sku1: Admin_Binary_china_us1_method1_t2
- Shipment_Binary_china_us1_method1_t2_sku1 >= 0
Binary_Link_us1_method1_t3_sku1: Admin_Binary_china_us1_method1_t3
- Shipment_Binary_china_us1_method1_t3_sku1 >= 0
Binary_Link_us1_method2_t1_sku1: Admin_Binary_china_us1_method2_t1
- Shipment_Binary_china_us1_method2_t1_sku1 >= 0
Binary_Link_us1_method2_t2_sku1: Admin_Binary_china_us1_method2_t2
- Shipment_Binary_china_us1_method2_t2_sku1 >= 0
Binary_Link_us1_method2_t3_sku1: Admin_Binary_china_us1_method2_t3
- Shipment_Binary_china_us1_method2_t3_sku1 >= 0
Binary_Link_us2_method1_t1_sku1: Admin_Binary_china_us2_method1_t1
- Shipment_Binary_china_us2_method1_t1_sku1 >= 0
Binary_Link_us2_method1_t2_sku1: Admin_Binary_china_us2_method1_t2
- Shipment_Binary_china_us2_method1_t2_sku1 >= 0
Binary_Link_us2_method1_t3_sku1: Admin_Binary_china_us2_method1_t3
- Shipment_Binary_china_us2_method1_t3_sku1 >= 0
Binary_Link_us2_method2_t1_sku1: Admin_Binary_china_us2_method2_t1
- Shipment_Binary_china_us2_method2_t1_sku1 >= 0
Binary_Link_us2_method2_t2_sku1: Admin_Binary_china_us2_method2_t2
- Shipment_Binary_china_us2_method2_t2_sku1 >= 0
Binary_Link_us2_method2_t3_sku1: Admin_Binary_china_us2_method2_t3
- Shipment_Binary_china_us2_method2_t3_sku1 >= 0
China_Initial_Inventory_sku1: China_Inventory_t1_sku1 = 12
China_Inventory_Balance_t2_sku1: - China_Inventory_t1_sku1
+ China_Inventory_t2_sku1 + 10 Shipment_Quantity_china_us1_method1_t2_sku1
+ 10 Shipment_Quantity_china_us1_method2_t2_sku1
+ 10 Shipment_Quantity_china_us2_method1_t2_sku1
+ 10 Shipment_Quantity_china_us2_method2_t2_sku1 = 12
China_Inventory_Balance_t3_sku1: - China_Inventory_t2_sku1
+ China_Inventory_t3_sku1 + 10 Shipment_Quantity_china_us1_method1_t3_sku1
+ 10 Shipment_Quantity_china_us1_method2_t3_sku1
+ 10 Shipment_Quantity_china_us2_method1_t3_sku1
+ 10 Shipment_Quantity_china_us2_method2_t3_sku1 = 12
Initial_Inventory_us1_t1_sku1: US_Inventory_us1_t1_sku1 = 0
Initial_Inventory_us2_t1_sku1: US_Inventory_us2_t1_sku1 = 10
Inventory_Balance_us1_t2_sku1: Distribution_Quantity_us1_loc1_t2_sku1
+ Distribution_Quantity_us1_loc2_t2_sku1
- Shipment_Quantity_china_us1_method1_t1_sku1 - US_Inventory_us1_t1_sku1
+ US_Inventory_us1_t2_sku1 = 0
Inventory_Balance_us1_t3_sku1: Distribution_Quantity_us1_loc1_t3_sku1
+ Distribution_Quantity_us1_loc2_t3_sku1
- Shipment_Quantity_china_us1_method1_t2_sku1
- Shipment_Quantity_china_us1_method2_t1_sku1 - US_Inventory_us1_t2_sku1
+ US_Inventory_us1_t3_sku1 = 0
Inventory_Balance_us2_t2_sku1: Distribution_Quantity_us2_loc1_t2_sku1
+ Distribution_Quantity_us2_loc2_t2_sku1
- Shipment_Quantity_china_us2_method1_t1_sku1 - US_Inventory_us2_t1_sku1
+ US_Inventory_us2_t2_sku1 = 0
Inventory_Balance_us2_t3_sku1: Distribution_Quantity_us2_loc1_t3_sku1
+ Distribution_Quantity_us2_loc2_t3_sku1
- Shipment_Quantity_china_us2_method1_t2_sku1
- Shipment_Quantity_china_us2_method2_t1_sku1 - US_Inventory_us2_t2_sku1
+ US_Inventory_us2_t3_sku1 = 0
Bounds
0 <= China_Inventory_t1_sku1
0 <= China_Inventory_t2_sku1
0 <= China_Inventory_t3_sku1
0 <= Distribution_Quantity_us1_loc1_t1_sku1
0 <= Distribution_Quantity_us1_loc1_t2_sku1
0 <= Distribution_Quantity_us1_loc1_t3_sku1
0 <= Distribution_Quantity_us1_loc2_t1_sku1
0 <= Distribution_Quantity_us1_loc2_t2_sku1
0 <= Distribution_Quantity_us1_loc2_t3_sku1
0 <= Distribution_Quantity_us2_loc1_t1_sku1
0 <= Distribution_Quantity_us2_loc1_t2_sku1
0 <= Distribution_Quantity_us2_loc1_t3_sku1
0 <= Distribution_Quantity_us2_loc2_t1_sku1
0 <= Distribution_Quantity_us2_loc2_t2_sku1
0 <= Distribution_Quantity_us2_loc2_t3_sku1
0 <= Shipment_Quantity_china_us1_method1_t1_sku1
0 <= Shipment_Quantity_china_us1_method1_t2_sku1
0 <= Shipment_Quantity_china_us1_method1_t3_sku1
0 <= Shipment_Quantity_china_us1_method2_t1_sku1
0 <= Shipment_Quantity_china_us1_method2_t2_sku1
0 <= Shipment_Quantity_china_us1_method2_t3_sku1
0 <= Shipment_Quantity_china_us2_method1_t1_sku1
0 <= Shipment_Quantity_china_us2_method1_t2_sku1
0 <= Shipment_Quantity_china_us2_method1_t3_sku1
0 <= Shipment_Quantity_china_us2_method2_t1_sku1
0 <= Shipment_Quantity_china_us2_method2_t2_sku1
0 <= Shipment_Quantity_china_us2_method2_t3_sku1
0 <= US_Inventory_us1_t1_sku1
0 <= US_Inventory_us1_t2_sku1
0 <= US_Inventory_us1_t3_sku1
0 <= US_Inventory_us2_t1_sku1
0 <= US_Inventory_us2_t2_sku1
0 <= US_Inventory_us2_t3_sku1
Generals
China_Inventory_t1_sku1
China_Inventory_t2_sku1
China_Inventory_t3_sku1
Distribution_Quantity_us1_loc1_t1_sku1
Distribution_Quantity_us1_loc1_t2_sku1
Distribution_Quantity_us1_loc1_t3_sku1
Distribution_Quantity_us1_loc2_t1_sku1
Distribution_Quantity_us1_loc2_t2_sku1
Distribution_Quantity_us1_loc2_t3_sku1
Distribution_Quantity_us2_loc1_t1_sku1
Distribution_Quantity_us2_loc1_t2_sku1
Distribution_Quantity_us2_loc1_t3_sku1
Distribution_Quantity_us2_loc2_t1_sku1
Distribution_Quantity_us2_loc2_t2_sku1
Distribution_Quantity_us2_loc2_t3_sku1
Shipment_Quantity_china_us1_method1_t1_sku1
Shipment_Quantity_china_us1_method1_t2_sku1
Shipment_Quantity_china_us1_method1_t3_sku1
Shipment_Quantity_china_us1_method2_t1_sku1
Shipment_Quantity_china_us1_method2_t2_sku1
Shipment_Quantity_china_us1_method2_t3_sku1
Shipment_Quantity_china_us2_method1_t1_sku1
Shipment_Quantity_china_us2_method1_t2_sku1
Shipment_Quantity_china_us2_method1_t3_sku1
Shipment_Quantity_china_us2_method2_t1_sku1
Shipment_Quantity_china_us2_method2_t2_sku1
Shipment_Quantity_china_us2_method2_t3_sku1
US_Inventory_us1_t1_sku1
US_Inventory_us1_t2_sku1
US_Inventory_us1_t3_sku1
US_Inventory_us2_t1_sku1
US_Inventory_us2_t2_sku1
US_Inventory_us2_t3_sku1
Binaries
Admin_Binary_china_us1_method1_t1
Admin_Binary_china_us1_method1_t2
Admin_Binary_china_us1_method1_t3
Admin_Binary_china_us1_method2_t1
Admin_Binary_china_us1_method2_t2
Admin_Binary_china_us1_method2_t3
Admin_Binary_china_us2_method1_t1
Admin_Binary_china_us2_method1_t2
Admin_Binary_china_us2_method1_t3
Admin_Binary_china_us2_method2_t1
Admin_Binary_china_us2_method2_t2
Admin_Binary_china_us2_method2_t3
Shipment_Binary_china_us1_method1_t1_sku1
Shipment_Binary_china_us1_method1_t2_sku1
Shipment_Binary_china_us1_method1_t3_sku1
Shipment_Binary_china_us1_method2_t1_sku1
Shipment_Binary_china_us1_method2_t2_sku1
Shipment_Binary_china_us1_method2_t3_sku1
Shipment_Binary_china_us2_method1_t1_sku1
Shipment_Binary_china_us2_method1_t2_sku1
Shipment_Binary_china_us2_method1_t3_sku1
Shipment_Binary_china_us2_method2_t1_sku1
Shipment_Binary_china_us2_method2_t2_sku1
Shipment_Binary_china_us2_method2_t3_sku1
End
i constantly get infeasibility evean when i remove or relax some constraints
At line 2 NAME MODEL
At line 3 ROWS
At line 49 COLUMNS
At line 385 RHS
At line 430 BOUNDS
At line 507 ENDATA
Problem MODEL has 44 rows, 92 columns and 135 elements
Coin0008I MODEL read with 0 errors
Option for timeMode changed from cpu to elapsed
Problem is infeasible - 0.00 seconds
Option for printingOptions changed from normal to all
Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00
</code>
<code>import pulp
def create_lp_problem(us_warehouses, china_warehouse, shipping_methods, time_periods, skus, customer_locations,
shipping_cost, admin_cost, distribution_cost, shortage_cost, units_per_box, whight_per_sku, demand,
inventory_in_us, inventory_in_china,
shipment_duration):
import os
# Set the timeout to 10 seconds
#os.environ['PYDEVD_WARN_SLOW_RESOLVE_TIMEOUT'] = '10'
# Large constant for Big-M constraints
M = 200
print('Create the LP problem')
model = pulp.LpProblem("Supply_Chain_Optimization", pulp.LpMinimize)
# Decision Variables
# inventory on the way from China to U.S. Warehouses in boxes
x = {
china_warehouse: {
u: {
s: {
t: {k: pulp.LpVariable(f"Shipment_Quantity_{china_warehouse}_{u}_{s}_{t}_{k}", 0, None, pulp.LpInteger)
for k in skus}
for t in time_periods}
for s in shipping_methods}
for u in us_warehouses}
}
# inventory on the way from U.S. Warehouses to Customer in units
y = {
u: {
l: {
t: {k: pulp.LpVariable(f"Distribution_Quantity_{u}_{l}_{t}_{k}", 0, None, pulp.LpInteger)
for k in skus}
for t in time_periods}
for l in customer_locations[u]}
for u in us_warehouses
}
# binary variables for shipment and admin cost sku level
z_shipment = {
china_warehouse: {
u: {
s: {
t: {k: pulp.LpVariable(f"Shipment_Binary_{china_warehouse}_{u}_{s}_{t}_{k}", 0, 1, pulp.LpBinary)
for k in skus}
for t in time_periods}
for s in shipping_methods}
for u in us_warehouses}
}
# binary variables for admin cost
z_admin = {
china_warehouse: {
u: {
s: {
t: pulp.LpVariable(f"Admin_Binary_{china_warehouse}_{u}_{s}_{t}", 0, 1, pulp.LpBinary)
for t in time_periods}
for s in shipping_methods}
for u in us_warehouses}
}
china_inventory = {
t: {k: pulp.LpVariable(f"China_Inventory_{t}_{k}", 0, None, pulp.LpInteger) for k in skus}
for t in time_periods
}
us_inventory = {
u: {
t: {k: pulp.LpVariable(f"US_Inventory_{u}_{t}_{k}", 0, None, pulp.LpInteger) for k in skus}
for t in time_periods
}
for u in us_warehouses
}
# Objective Function
model += (
pulp.lpSum(
shipping_cost[china_warehouse, u, s] * x[china_warehouse][u][s][t][k] * units_per_box[k] * whight_per_sku[k]
for u in us_warehouses for s in shipping_methods for t in time_periods for k in skus
)
+ pulp.lpSum(
admin_cost[china_warehouse, u, s] * z_admin[china_warehouse][u][s][t]
for u in us_warehouses for s in shipping_methods for t in time_periods
)
+ pulp.lpSum(
distribution_cost[u, l] * y[u][l][t][k] * whight_per_sku[k]
for u in us_warehouses for l in customer_locations[u] for t in time_periods for k in skus
)
+ pulp.lpSum(
shortage_cost * (demand[l, t, k] - pulp.lpSum(y[u][l][t][k] for u in us_warehouses))
for t in time_periods for k in skus for l in customer_locations[list(customer_locations.keys())[0]]
)
), "Total_Cost"
# Constraints
# Inventory Balance at U.S. Warehouses
for t_idx, t in enumerate(time_periods):
for u in us_warehouses:
for k in skus:
if t_idx > 0:
prev_t = time_periods[t_idx - 1]
# Shipments received at time t
shipments_received = pulp.lpSum(
x[china_warehouse][u][s][time_periods[t_idx - int(shipment_duration[(u,s)])]][k]
for s in shipping_methods if t_idx - shipment_duration[(u,s)] >= 0
)
model += (
us_inventory[u][t][k] == us_inventory[u][prev_t][k] + inventory_in_us[u, t, k] +
shipments_received - pulp.lpSum(y[u][l][t][k] for l in customer_locations[u])
), f"Inventory_Balance_{u}_{t}_{k}"
else:
model += (
us_inventory[u][t][k] == inventory_in_us[u, t, k]
), f"Initial_Inventory_{u}_{t}_{k}"
#Inventory Balance at China Warehouse
for t_idx, t in enumerate(time_periods):
for k in skus:
if t_idx == 0:
model += (
china_inventory[t][k] == inventory_in_china[t,k]
), f"China_Initial_Inventory_{k}"
else:
prev_t = time_periods[t_idx - 1]
model += (
china_inventory[t][k] == china_inventory[prev_t][k] +
inventory_in_china[t,k] -
pulp.lpSum(x[china_warehouse][u][s][t][k]* units_per_box[k] for u in us_warehouses for s in shipping_methods)
), f"China_Inventory_Balance_{t}_{k}"
# Binary Linking Constraints
for u in us_warehouses:
for s in shipping_methods:
for t in time_periods:
for k in skus:
model += z_admin[china_warehouse][u][s][t] >= z_shipment[china_warehouse][u][s][t][k],
f"Binary_Link_{u}_{s}_{t}_{k}"
slack = pulp.LpVariable.dicts("Slack", (us_warehouses, shipping_methods, time_periods, skus), 0, None, pulp.LpContinuous)
# Big-M Constraints
for u in us_warehouses:
for s in shipping_methods:
for t in time_periods:
for k in skus:
model += x[china_warehouse][u][s][t][k] <= M * z_shipment[china_warehouse][u][s][t][k]+ slack[u][s][t][k],
f"BigM_{u}_{s}_{t}_{k}"
print('solving the model')
solver = pulp.PULP_CBC_CMD() # Displays solver logs
model.solve(solver)
# set model.constraints to file for debugging
model.writeLP("model.lp")
#model.solve(pulp.PULP_CBC_CMD(msg=1, options=['infeasibility']))
#model.solve(pulp.PULP_CBC_CMD(msg=1)) # Set the timeout to default
os.environ['PYDEVD_WARN_SLOW_RESOLVE_TIMEOUT'] = '0.5'
return model
import pulp
def test_create_lp_problem():
# Define test data
us_warehouses = ["us1", "us2"]
china_warehouse = "china"
shipping_methods = ["method1", "method2"]
time_periods = ["t1", "t2", "t3", "t4"]
skus = ["sku1"]
poligons = ["loc1", "loc2"]
customer_locations = {
"us1": [p for p in poligons],
"us2": [p for p in poligons]
}
shipping_cost = {(china_warehouse, u, s): 10 for u in us_warehouses for s in shipping_methods}
shipping_cost.update(
{('china', 'us1', 'method1'): 100, ('china', 'us1', 'method2'): 2, ('china', 'us2', 'method1'): 100, ('china', 'us2', 'method2'): 2})
admin_cost = {(china_warehouse, u, s): 100 for u in us_warehouses for s in shipping_methods}
# Adjust distribution costs
distribution_cost = {
("us1", "loc1"): 5
}
distribution_cost.update({
("us1", "loc2"): 10
})
distribution_cost.update({
("us2", "loc1"): 10
})
distribution_cost.update({
("us2", "loc2"): 5
})
shortage_cost = 1000
units_per_box = {k: 10 for k in skus}
whight_per_sku = {k: 10 for k in skus}
demand = {(p, t, k): 11 for p in poligons for t in time_periods for k in skus}
inventory_in_us = {(u, t, k): 0 for u in us_warehouses for k in skus for t in time_periods}
inventory_in_us.update({('us1', 't1', 'sku1'): 0, ('us1', 't2', 'sku1'): 0, ('us1', 't3', 'sku1'): 0, ('us2', 't1', 'sku1'): 10, ('us2', 't2', 'sku1'): 0, ('us2', 't3', 'sku1'): 0})
inventory_in_china = {( t, k): 12 for k in skus for t in time_periods}
shipment_duration = {(u, s): 1 for u in us_warehouses for s in shipping_methods}
shipment_duration.update({('us1', 'method1'): 1, ('us1', 'method2'): 2, ('us2', 'method1'): 1, ('us2', 'method2'): 2})
# Call the function with the test data
model = create_lp_problem(
us_warehouses, china_warehouse, shipping_methods, time_periods, skus, customer_locations,
shipping_cost, admin_cost, distribution_cost, shortage_cost, units_per_box, whight_per_sku, demand,
inventory_in_us, inventory_in_china,
shipment_duration
)
# Check if the model is solved successfully
assert pulp.LpStatus[model.status] == 'Optimal', f"Model status: {pulp.LpStatus[model.status]}"
print("Test passed: Model solved successfully")
# Run the test
test_create_lp_problem()```
this is the test model:
* Supply_Chain_Optimization *
Minimize
OBJ: 100 Admin_Binary_china_us1_method1_t1
+ 100 Admin_Binary_china_us1_method1_t2
+ 100 Admin_Binary_china_us1_method1_t3
+ 100 Admin_Binary_china_us1_method2_t1
+ 100 Admin_Binary_china_us1_method2_t2
+ 100 Admin_Binary_china_us1_method2_t3
+ 100 Admin_Binary_china_us2_method1_t1
+ 100 Admin_Binary_china_us2_method1_t2
+ 100 Admin_Binary_china_us2_method1_t3
+ 100 Admin_Binary_china_us2_method2_t1
+ 100 Admin_Binary_china_us2_method2_t2
+ 100 Admin_Binary_china_us2_method2_t3
- 950 Distribution_Quantity_us1_loc1_t1_sku1
- 950 Distribution_Quantity_us1_loc1_t2_sku1
- 950 Distribution_Quantity_us1_loc1_t3_sku1
- 900 Distribution_Quantity_us1_loc2_t1_sku1
- 900 Distribution_Quantity_us1_loc2_t2_sku1
- 900 Distribution_Quantity_us1_loc2_t3_sku1
- 900 Distribution_Quantity_us2_loc1_t1_sku1
- 900 Distribution_Quantity_us2_loc1_t2_sku1
- 900 Distribution_Quantity_us2_loc1_t3_sku1
- 950 Distribution_Quantity_us2_loc2_t1_sku1
- 950 Distribution_Quantity_us2_loc2_t2_sku1
- 950 Distribution_Quantity_us2_loc2_t3_sku1
+ 10000 Shipment_Quantity_china_us1_method1_t1_sku1
+ 10000 Shipment_Quantity_china_us1_method1_t2_sku1
+ 10000 Shipment_Quantity_china_us1_method1_t3_sku1
+ 200 Shipment_Quantity_china_us1_method2_t1_sku1
+ 200 Shipment_Quantity_china_us1_method2_t2_sku1
+ 200 Shipment_Quantity_china_us1_method2_t3_sku1
+ 10000 Shipment_Quantity_china_us2_method1_t1_sku1
+ 10000 Shipment_Quantity_china_us2_method1_t2_sku1
+ 10000 Shipment_Quantity_china_us2_method1_t3_sku1
+ 200 Shipment_Quantity_china_us2_method2_t1_sku1
+ 200 Shipment_Quantity_china_us2_method2_t2_sku1
+ 200 Shipment_Quantity_china_us2_method2_t3_sku1
Subject To
BigM_us1_method1_t1_sku1: - 200 Shipment_Binary_china_us1_method1_t1_sku1
+ Shipment_Quantity_china_us1_method1_t1_sku1 - Slack_us1_method1_t1_sku1
<= 0
BigM_us1_method1_t2_sku1: - 200 Shipment_Binary_china_us1_method1_t2_sku1
+ Shipment_Quantity_china_us1_method1_t2_sku1 - Slack_us1_method1_t2_sku1
<= 0
BigM_us1_method1_t3_sku1: - 200 Shipment_Binary_china_us1_method1_t3_sku1
+ Shipment_Quantity_china_us1_method1_t3_sku1 - Slack_us1_method1_t3_sku1
<= 0
BigM_us1_method2_t1_sku1: - 200 Shipment_Binary_china_us1_method2_t1_sku1
+ Shipment_Quantity_china_us1_method2_t1_sku1 - Slack_us1_method2_t1_sku1
<= 0
BigM_us1_method2_t2_sku1: - 200 Shipment_Binary_china_us1_method2_t2_sku1
+ Shipment_Quantity_china_us1_method2_t2_sku1 - Slack_us1_method2_t2_sku1
<= 0
BigM_us1_method2_t3_sku1: - 200 Shipment_Binary_china_us1_method2_t3_sku1
+ Shipment_Quantity_china_us1_method2_t3_sku1 - Slack_us1_method2_t3_sku1
<= 0
BigM_us2_method1_t1_sku1: - 200 Shipment_Binary_china_us2_method1_t1_sku1
+ Shipment_Quantity_china_us2_method1_t1_sku1 - Slack_us2_method1_t1_sku1
<= 0
BigM_us2_method1_t2_sku1: - 200 Shipment_Binary_china_us2_method1_t2_sku1
+ Shipment_Quantity_china_us2_method1_t2_sku1 - Slack_us2_method1_t2_sku1
<= 0
BigM_us2_method1_t3_sku1: - 200 Shipment_Binary_china_us2_method1_t3_sku1
+ Shipment_Quantity_china_us2_method1_t3_sku1 - Slack_us2_method1_t3_sku1
<= 0
BigM_us2_method2_t1_sku1: - 200 Shipment_Binary_china_us2_method2_t1_sku1
+ Shipment_Quantity_china_us2_method2_t1_sku1 - Slack_us2_method2_t1_sku1
<= 0
BigM_us2_method2_t2_sku1: - 200 Shipment_Binary_china_us2_method2_t2_sku1
+ Shipment_Quantity_china_us2_method2_t2_sku1 - Slack_us2_method2_t2_sku1
<= 0
BigM_us2_method2_t3_sku1: - 200 Shipment_Binary_china_us2_method2_t3_sku1
+ Shipment_Quantity_china_us2_method2_t3_sku1 - Slack_us2_method2_t3_sku1
<= 0
Binary_Link_us1_method1_t1_sku1: Admin_Binary_china_us1_method1_t1
- Shipment_Binary_china_us1_method1_t1_sku1 >= 0
Binary_Link_us1_method1_t2_sku1: Admin_Binary_china_us1_method1_t2
- Shipment_Binary_china_us1_method1_t2_sku1 >= 0
Binary_Link_us1_method1_t3_sku1: Admin_Binary_china_us1_method1_t3
- Shipment_Binary_china_us1_method1_t3_sku1 >= 0
Binary_Link_us1_method2_t1_sku1: Admin_Binary_china_us1_method2_t1
- Shipment_Binary_china_us1_method2_t1_sku1 >= 0
Binary_Link_us1_method2_t2_sku1: Admin_Binary_china_us1_method2_t2
- Shipment_Binary_china_us1_method2_t2_sku1 >= 0
Binary_Link_us1_method2_t3_sku1: Admin_Binary_china_us1_method2_t3
- Shipment_Binary_china_us1_method2_t3_sku1 >= 0
Binary_Link_us2_method1_t1_sku1: Admin_Binary_china_us2_method1_t1
- Shipment_Binary_china_us2_method1_t1_sku1 >= 0
Binary_Link_us2_method1_t2_sku1: Admin_Binary_china_us2_method1_t2
- Shipment_Binary_china_us2_method1_t2_sku1 >= 0
Binary_Link_us2_method1_t3_sku1: Admin_Binary_china_us2_method1_t3
- Shipment_Binary_china_us2_method1_t3_sku1 >= 0
Binary_Link_us2_method2_t1_sku1: Admin_Binary_china_us2_method2_t1
- Shipment_Binary_china_us2_method2_t1_sku1 >= 0
Binary_Link_us2_method2_t2_sku1: Admin_Binary_china_us2_method2_t2
- Shipment_Binary_china_us2_method2_t2_sku1 >= 0
Binary_Link_us2_method2_t3_sku1: Admin_Binary_china_us2_method2_t3
- Shipment_Binary_china_us2_method2_t3_sku1 >= 0
China_Initial_Inventory_sku1: China_Inventory_t1_sku1 = 12
China_Inventory_Balance_t2_sku1: - China_Inventory_t1_sku1
+ China_Inventory_t2_sku1 + 10 Shipment_Quantity_china_us1_method1_t2_sku1
+ 10 Shipment_Quantity_china_us1_method2_t2_sku1
+ 10 Shipment_Quantity_china_us2_method1_t2_sku1
+ 10 Shipment_Quantity_china_us2_method2_t2_sku1 = 12
China_Inventory_Balance_t3_sku1: - China_Inventory_t2_sku1
+ China_Inventory_t3_sku1 + 10 Shipment_Quantity_china_us1_method1_t3_sku1
+ 10 Shipment_Quantity_china_us1_method2_t3_sku1
+ 10 Shipment_Quantity_china_us2_method1_t3_sku1
+ 10 Shipment_Quantity_china_us2_method2_t3_sku1 = 12
Initial_Inventory_us1_t1_sku1: US_Inventory_us1_t1_sku1 = 0
Initial_Inventory_us2_t1_sku1: US_Inventory_us2_t1_sku1 = 10
Inventory_Balance_us1_t2_sku1: Distribution_Quantity_us1_loc1_t2_sku1
+ Distribution_Quantity_us1_loc2_t2_sku1
- Shipment_Quantity_china_us1_method1_t1_sku1 - US_Inventory_us1_t1_sku1
+ US_Inventory_us1_t2_sku1 = 0
Inventory_Balance_us1_t3_sku1: Distribution_Quantity_us1_loc1_t3_sku1
+ Distribution_Quantity_us1_loc2_t3_sku1
- Shipment_Quantity_china_us1_method1_t2_sku1
- Shipment_Quantity_china_us1_method2_t1_sku1 - US_Inventory_us1_t2_sku1
+ US_Inventory_us1_t3_sku1 = 0
Inventory_Balance_us2_t2_sku1: Distribution_Quantity_us2_loc1_t2_sku1
+ Distribution_Quantity_us2_loc2_t2_sku1
- Shipment_Quantity_china_us2_method1_t1_sku1 - US_Inventory_us2_t1_sku1
+ US_Inventory_us2_t2_sku1 = 0
Inventory_Balance_us2_t3_sku1: Distribution_Quantity_us2_loc1_t3_sku1
+ Distribution_Quantity_us2_loc2_t3_sku1
- Shipment_Quantity_china_us2_method1_t2_sku1
- Shipment_Quantity_china_us2_method2_t1_sku1 - US_Inventory_us2_t2_sku1
+ US_Inventory_us2_t3_sku1 = 0
Bounds
0 <= China_Inventory_t1_sku1
0 <= China_Inventory_t2_sku1
0 <= China_Inventory_t3_sku1
0 <= Distribution_Quantity_us1_loc1_t1_sku1
0 <= Distribution_Quantity_us1_loc1_t2_sku1
0 <= Distribution_Quantity_us1_loc1_t3_sku1
0 <= Distribution_Quantity_us1_loc2_t1_sku1
0 <= Distribution_Quantity_us1_loc2_t2_sku1
0 <= Distribution_Quantity_us1_loc2_t3_sku1
0 <= Distribution_Quantity_us2_loc1_t1_sku1
0 <= Distribution_Quantity_us2_loc1_t2_sku1
0 <= Distribution_Quantity_us2_loc1_t3_sku1
0 <= Distribution_Quantity_us2_loc2_t1_sku1
0 <= Distribution_Quantity_us2_loc2_t2_sku1
0 <= Distribution_Quantity_us2_loc2_t3_sku1
0 <= Shipment_Quantity_china_us1_method1_t1_sku1
0 <= Shipment_Quantity_china_us1_method1_t2_sku1
0 <= Shipment_Quantity_china_us1_method1_t3_sku1
0 <= Shipment_Quantity_china_us1_method2_t1_sku1
0 <= Shipment_Quantity_china_us1_method2_t2_sku1
0 <= Shipment_Quantity_china_us1_method2_t3_sku1
0 <= Shipment_Quantity_china_us2_method1_t1_sku1
0 <= Shipment_Quantity_china_us2_method1_t2_sku1
0 <= Shipment_Quantity_china_us2_method1_t3_sku1
0 <= Shipment_Quantity_china_us2_method2_t1_sku1
0 <= Shipment_Quantity_china_us2_method2_t2_sku1
0 <= Shipment_Quantity_china_us2_method2_t3_sku1
0 <= US_Inventory_us1_t1_sku1
0 <= US_Inventory_us1_t2_sku1
0 <= US_Inventory_us1_t3_sku1
0 <= US_Inventory_us2_t1_sku1
0 <= US_Inventory_us2_t2_sku1
0 <= US_Inventory_us2_t3_sku1
Generals
China_Inventory_t1_sku1
China_Inventory_t2_sku1
China_Inventory_t3_sku1
Distribution_Quantity_us1_loc1_t1_sku1
Distribution_Quantity_us1_loc1_t2_sku1
Distribution_Quantity_us1_loc1_t3_sku1
Distribution_Quantity_us1_loc2_t1_sku1
Distribution_Quantity_us1_loc2_t2_sku1
Distribution_Quantity_us1_loc2_t3_sku1
Distribution_Quantity_us2_loc1_t1_sku1
Distribution_Quantity_us2_loc1_t2_sku1
Distribution_Quantity_us2_loc1_t3_sku1
Distribution_Quantity_us2_loc2_t1_sku1
Distribution_Quantity_us2_loc2_t2_sku1
Distribution_Quantity_us2_loc2_t3_sku1
Shipment_Quantity_china_us1_method1_t1_sku1
Shipment_Quantity_china_us1_method1_t2_sku1
Shipment_Quantity_china_us1_method1_t3_sku1
Shipment_Quantity_china_us1_method2_t1_sku1
Shipment_Quantity_china_us1_method2_t2_sku1
Shipment_Quantity_china_us1_method2_t3_sku1
Shipment_Quantity_china_us2_method1_t1_sku1
Shipment_Quantity_china_us2_method1_t2_sku1
Shipment_Quantity_china_us2_method1_t3_sku1
Shipment_Quantity_china_us2_method2_t1_sku1
Shipment_Quantity_china_us2_method2_t2_sku1
Shipment_Quantity_china_us2_method2_t3_sku1
US_Inventory_us1_t1_sku1
US_Inventory_us1_t2_sku1
US_Inventory_us1_t3_sku1
US_Inventory_us2_t1_sku1
US_Inventory_us2_t2_sku1
US_Inventory_us2_t3_sku1
Binaries
Admin_Binary_china_us1_method1_t1
Admin_Binary_china_us1_method1_t2
Admin_Binary_china_us1_method1_t3
Admin_Binary_china_us1_method2_t1
Admin_Binary_china_us1_method2_t2
Admin_Binary_china_us1_method2_t3
Admin_Binary_china_us2_method1_t1
Admin_Binary_china_us2_method1_t2
Admin_Binary_china_us2_method1_t3
Admin_Binary_china_us2_method2_t1
Admin_Binary_china_us2_method2_t2
Admin_Binary_china_us2_method2_t3
Shipment_Binary_china_us1_method1_t1_sku1
Shipment_Binary_china_us1_method1_t2_sku1
Shipment_Binary_china_us1_method1_t3_sku1
Shipment_Binary_china_us1_method2_t1_sku1
Shipment_Binary_china_us1_method2_t2_sku1
Shipment_Binary_china_us1_method2_t3_sku1
Shipment_Binary_china_us2_method1_t1_sku1
Shipment_Binary_china_us2_method1_t2_sku1
Shipment_Binary_china_us2_method1_t3_sku1
Shipment_Binary_china_us2_method2_t1_sku1
Shipment_Binary_china_us2_method2_t2_sku1
Shipment_Binary_china_us2_method2_t3_sku1
End
i constantly get infeasibility evean when i remove or relax some constraints
At line 2 NAME MODEL
At line 3 ROWS
At line 49 COLUMNS
At line 385 RHS
At line 430 BOUNDS
At line 507 ENDATA
Problem MODEL has 44 rows, 92 columns and 135 elements
Coin0008I MODEL read with 0 errors
Option for timeMode changed from cpu to elapsed
Problem is infeasible - 0.00 seconds
Option for printingOptions changed from normal to all
Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00
</code>
import pulp
def create_lp_problem(us_warehouses, china_warehouse, shipping_methods, time_periods, skus, customer_locations,
shipping_cost, admin_cost, distribution_cost, shortage_cost, units_per_box, whight_per_sku, demand,
inventory_in_us, inventory_in_china,
shipment_duration):
import os
# Set the timeout to 10 seconds
#os.environ['PYDEVD_WARN_SLOW_RESOLVE_TIMEOUT'] = '10'
# Large constant for Big-M constraints
M = 200
print('Create the LP problem')
model = pulp.LpProblem("Supply_Chain_Optimization", pulp.LpMinimize)
# Decision Variables
# inventory on the way from China to U.S. Warehouses in boxes
x = {
china_warehouse: {
u: {
s: {
t: {k: pulp.LpVariable(f"Shipment_Quantity_{china_warehouse}_{u}_{s}_{t}_{k}", 0, None, pulp.LpInteger)
for k in skus}
for t in time_periods}
for s in shipping_methods}
for u in us_warehouses}
}
# inventory on the way from U.S. Warehouses to Customer in units
y = {
u: {
l: {
t: {k: pulp.LpVariable(f"Distribution_Quantity_{u}_{l}_{t}_{k}", 0, None, pulp.LpInteger)
for k in skus}
for t in time_periods}
for l in customer_locations[u]}
for u in us_warehouses
}
# binary variables for shipment and admin cost sku level
z_shipment = {
china_warehouse: {
u: {
s: {
t: {k: pulp.LpVariable(f"Shipment_Binary_{china_warehouse}_{u}_{s}_{t}_{k}", 0, 1, pulp.LpBinary)
for k in skus}
for t in time_periods}
for s in shipping_methods}
for u in us_warehouses}
}
# binary variables for admin cost
z_admin = {
china_warehouse: {
u: {
s: {
t: pulp.LpVariable(f"Admin_Binary_{china_warehouse}_{u}_{s}_{t}", 0, 1, pulp.LpBinary)
for t in time_periods}
for s in shipping_methods}
for u in us_warehouses}
}
china_inventory = {
t: {k: pulp.LpVariable(f"China_Inventory_{t}_{k}", 0, None, pulp.LpInteger) for k in skus}
for t in time_periods
}
us_inventory = {
u: {
t: {k: pulp.LpVariable(f"US_Inventory_{u}_{t}_{k}", 0, None, pulp.LpInteger) for k in skus}
for t in time_periods
}
for u in us_warehouses
}
# Objective Function
model += (
pulp.lpSum(
shipping_cost[china_warehouse, u, s] * x[china_warehouse][u][s][t][k] * units_per_box[k] * whight_per_sku[k]
for u in us_warehouses for s in shipping_methods for t in time_periods for k in skus
)
+ pulp.lpSum(
admin_cost[china_warehouse, u, s] * z_admin[china_warehouse][u][s][t]
for u in us_warehouses for s in shipping_methods for t in time_periods
)
+ pulp.lpSum(
distribution_cost[u, l] * y[u][l][t][k] * whight_per_sku[k]
for u in us_warehouses for l in customer_locations[u] for t in time_periods for k in skus
)
+ pulp.lpSum(
shortage_cost * (demand[l, t, k] - pulp.lpSum(y[u][l][t][k] for u in us_warehouses))
for t in time_periods for k in skus for l in customer_locations[list(customer_locations.keys())[0]]
)
), "Total_Cost"
# Constraints
# Inventory Balance at U.S. Warehouses
for t_idx, t in enumerate(time_periods):
for u in us_warehouses:
for k in skus:
if t_idx > 0:
prev_t = time_periods[t_idx - 1]
# Shipments received at time t
shipments_received = pulp.lpSum(
x[china_warehouse][u][s][time_periods[t_idx - int(shipment_duration[(u,s)])]][k]
for s in shipping_methods if t_idx - shipment_duration[(u,s)] >= 0
)
model += (
us_inventory[u][t][k] == us_inventory[u][prev_t][k] + inventory_in_us[u, t, k] +
shipments_received - pulp.lpSum(y[u][l][t][k] for l in customer_locations[u])
), f"Inventory_Balance_{u}_{t}_{k}"
else:
model += (
us_inventory[u][t][k] == inventory_in_us[u, t, k]
), f"Initial_Inventory_{u}_{t}_{k}"
#Inventory Balance at China Warehouse
for t_idx, t in enumerate(time_periods):
for k in skus:
if t_idx == 0:
model += (
china_inventory[t][k] == inventory_in_china[t,k]
), f"China_Initial_Inventory_{k}"
else:
prev_t = time_periods[t_idx - 1]
model += (
china_inventory[t][k] == china_inventory[prev_t][k] +
inventory_in_china[t,k] -
pulp.lpSum(x[china_warehouse][u][s][t][k]* units_per_box[k] for u in us_warehouses for s in shipping_methods)
), f"China_Inventory_Balance_{t}_{k}"
# Binary Linking Constraints
for u in us_warehouses:
for s in shipping_methods:
for t in time_periods:
for k in skus:
model += z_admin[china_warehouse][u][s][t] >= z_shipment[china_warehouse][u][s][t][k],
f"Binary_Link_{u}_{s}_{t}_{k}"
slack = pulp.LpVariable.dicts("Slack", (us_warehouses, shipping_methods, time_periods, skus), 0, None, pulp.LpContinuous)
# Big-M Constraints
for u in us_warehouses:
for s in shipping_methods:
for t in time_periods:
for k in skus:
model += x[china_warehouse][u][s][t][k] <= M * z_shipment[china_warehouse][u][s][t][k]+ slack[u][s][t][k],
f"BigM_{u}_{s}_{t}_{k}"
print('solving the model')
solver = pulp.PULP_CBC_CMD() # Displays solver logs
model.solve(solver)
# set model.constraints to file for debugging
model.writeLP("model.lp")
#model.solve(pulp.PULP_CBC_CMD(msg=1, options=['infeasibility']))
#model.solve(pulp.PULP_CBC_CMD(msg=1)) # Set the timeout to default
os.environ['PYDEVD_WARN_SLOW_RESOLVE_TIMEOUT'] = '0.5'
return model
import pulp
def test_create_lp_problem():
# Define test data
us_warehouses = ["us1", "us2"]
china_warehouse = "china"
shipping_methods = ["method1", "method2"]
time_periods = ["t1", "t2", "t3", "t4"]
skus = ["sku1"]
poligons = ["loc1", "loc2"]
customer_locations = {
"us1": [p for p in poligons],
"us2": [p for p in poligons]
}
shipping_cost = {(china_warehouse, u, s): 10 for u in us_warehouses for s in shipping_methods}
shipping_cost.update(
{('china', 'us1', 'method1'): 100, ('china', 'us1', 'method2'): 2, ('china', 'us2', 'method1'): 100, ('china', 'us2', 'method2'): 2})
admin_cost = {(china_warehouse, u, s): 100 for u in us_warehouses for s in shipping_methods}
# Adjust distribution costs
distribution_cost = {
("us1", "loc1"): 5
}
distribution_cost.update({
("us1", "loc2"): 10
})
distribution_cost.update({
("us2", "loc1"): 10
})
distribution_cost.update({
("us2", "loc2"): 5
})
shortage_cost = 1000
units_per_box = {k: 10 for k in skus}
whight_per_sku = {k: 10 for k in skus}
demand = {(p, t, k): 11 for p in poligons for t in time_periods for k in skus}
inventory_in_us = {(u, t, k): 0 for u in us_warehouses for k in skus for t in time_periods}
inventory_in_us.update({('us1', 't1', 'sku1'): 0, ('us1', 't2', 'sku1'): 0, ('us1', 't3', 'sku1'): 0, ('us2', 't1', 'sku1'): 10, ('us2', 't2', 'sku1'): 0, ('us2', 't3', 'sku1'): 0})
inventory_in_china = {( t, k): 12 for k in skus for t in time_periods}
shipment_duration = {(u, s): 1 for u in us_warehouses for s in shipping_methods}
shipment_duration.update({('us1', 'method1'): 1, ('us1', 'method2'): 2, ('us2', 'method1'): 1, ('us2', 'method2'): 2})
# Call the function with the test data
model = create_lp_problem(
us_warehouses, china_warehouse, shipping_methods, time_periods, skus, customer_locations,
shipping_cost, admin_cost, distribution_cost, shortage_cost, units_per_box, whight_per_sku, demand,
inventory_in_us, inventory_in_china,
shipment_duration
)
# Check if the model is solved successfully
assert pulp.LpStatus[model.status] == 'Optimal', f"Model status: {pulp.LpStatus[model.status]}"
print("Test passed: Model solved successfully")
# Run the test
test_create_lp_problem()```
this is the test model:
* Supply_Chain_Optimization *
Minimize
OBJ: 100 Admin_Binary_china_us1_method1_t1
+ 100 Admin_Binary_china_us1_method1_t2
+ 100 Admin_Binary_china_us1_method1_t3
+ 100 Admin_Binary_china_us1_method2_t1
+ 100 Admin_Binary_china_us1_method2_t2
+ 100 Admin_Binary_china_us1_method2_t3
+ 100 Admin_Binary_china_us2_method1_t1
+ 100 Admin_Binary_china_us2_method1_t2
+ 100 Admin_Binary_china_us2_method1_t3
+ 100 Admin_Binary_china_us2_method2_t1
+ 100 Admin_Binary_china_us2_method2_t2
+ 100 Admin_Binary_china_us2_method2_t3
- 950 Distribution_Quantity_us1_loc1_t1_sku1
- 950 Distribution_Quantity_us1_loc1_t2_sku1
- 950 Distribution_Quantity_us1_loc1_t3_sku1
- 900 Distribution_Quantity_us1_loc2_t1_sku1
- 900 Distribution_Quantity_us1_loc2_t2_sku1
- 900 Distribution_Quantity_us1_loc2_t3_sku1
- 900 Distribution_Quantity_us2_loc1_t1_sku1
- 900 Distribution_Quantity_us2_loc1_t2_sku1
- 900 Distribution_Quantity_us2_loc1_t3_sku1
- 950 Distribution_Quantity_us2_loc2_t1_sku1
- 950 Distribution_Quantity_us2_loc2_t2_sku1
- 950 Distribution_Quantity_us2_loc2_t3_sku1
+ 10000 Shipment_Quantity_china_us1_method1_t1_sku1
+ 10000 Shipment_Quantity_china_us1_method1_t2_sku1
+ 10000 Shipment_Quantity_china_us1_method1_t3_sku1
+ 200 Shipment_Quantity_china_us1_method2_t1_sku1
+ 200 Shipment_Quantity_china_us1_method2_t2_sku1
+ 200 Shipment_Quantity_china_us1_method2_t3_sku1
+ 10000 Shipment_Quantity_china_us2_method1_t1_sku1
+ 10000 Shipment_Quantity_china_us2_method1_t2_sku1
+ 10000 Shipment_Quantity_china_us2_method1_t3_sku1
+ 200 Shipment_Quantity_china_us2_method2_t1_sku1
+ 200 Shipment_Quantity_china_us2_method2_t2_sku1
+ 200 Shipment_Quantity_china_us2_method2_t3_sku1
Subject To
BigM_us1_method1_t1_sku1: - 200 Shipment_Binary_china_us1_method1_t1_sku1
+ Shipment_Quantity_china_us1_method1_t1_sku1 - Slack_us1_method1_t1_sku1
<= 0
BigM_us1_method1_t2_sku1: - 200 Shipment_Binary_china_us1_method1_t2_sku1
+ Shipment_Quantity_china_us1_method1_t2_sku1 - Slack_us1_method1_t2_sku1
<= 0
BigM_us1_method1_t3_sku1: - 200 Shipment_Binary_china_us1_method1_t3_sku1
+ Shipment_Quantity_china_us1_method1_t3_sku1 - Slack_us1_method1_t3_sku1
<= 0
BigM_us1_method2_t1_sku1: - 200 Shipment_Binary_china_us1_method2_t1_sku1
+ Shipment_Quantity_china_us1_method2_t1_sku1 - Slack_us1_method2_t1_sku1
<= 0
BigM_us1_method2_t2_sku1: - 200 Shipment_Binary_china_us1_method2_t2_sku1
+ Shipment_Quantity_china_us1_method2_t2_sku1 - Slack_us1_method2_t2_sku1
<= 0
BigM_us1_method2_t3_sku1: - 200 Shipment_Binary_china_us1_method2_t3_sku1
+ Shipment_Quantity_china_us1_method2_t3_sku1 - Slack_us1_method2_t3_sku1
<= 0
BigM_us2_method1_t1_sku1: - 200 Shipment_Binary_china_us2_method1_t1_sku1
+ Shipment_Quantity_china_us2_method1_t1_sku1 - Slack_us2_method1_t1_sku1
<= 0
BigM_us2_method1_t2_sku1: - 200 Shipment_Binary_china_us2_method1_t2_sku1
+ Shipment_Quantity_china_us2_method1_t2_sku1 - Slack_us2_method1_t2_sku1
<= 0
BigM_us2_method1_t3_sku1: - 200 Shipment_Binary_china_us2_method1_t3_sku1
+ Shipment_Quantity_china_us2_method1_t3_sku1 - Slack_us2_method1_t3_sku1
<= 0
BigM_us2_method2_t1_sku1: - 200 Shipment_Binary_china_us2_method2_t1_sku1
+ Shipment_Quantity_china_us2_method2_t1_sku1 - Slack_us2_method2_t1_sku1
<= 0
BigM_us2_method2_t2_sku1: - 200 Shipment_Binary_china_us2_method2_t2_sku1
+ Shipment_Quantity_china_us2_method2_t2_sku1 - Slack_us2_method2_t2_sku1
<= 0
BigM_us2_method2_t3_sku1: - 200 Shipment_Binary_china_us2_method2_t3_sku1
+ Shipment_Quantity_china_us2_method2_t3_sku1 - Slack_us2_method2_t3_sku1
<= 0
Binary_Link_us1_method1_t1_sku1: Admin_Binary_china_us1_method1_t1
- Shipment_Binary_china_us1_method1_t1_sku1 >= 0
Binary_Link_us1_method1_t2_sku1: Admin_Binary_china_us1_method1_t2
- Shipment_Binary_china_us1_method1_t2_sku1 >= 0
Binary_Link_us1_method1_t3_sku1: Admin_Binary_china_us1_method1_t3
- Shipment_Binary_china_us1_method1_t3_sku1 >= 0
Binary_Link_us1_method2_t1_sku1: Admin_Binary_china_us1_method2_t1
- Shipment_Binary_china_us1_method2_t1_sku1 >= 0
Binary_Link_us1_method2_t2_sku1: Admin_Binary_china_us1_method2_t2
- Shipment_Binary_china_us1_method2_t2_sku1 >= 0
Binary_Link_us1_method2_t3_sku1: Admin_Binary_china_us1_method2_t3
- Shipment_Binary_china_us1_method2_t3_sku1 >= 0
Binary_Link_us2_method1_t1_sku1: Admin_Binary_china_us2_method1_t1
- Shipment_Binary_china_us2_method1_t1_sku1 >= 0
Binary_Link_us2_method1_t2_sku1: Admin_Binary_china_us2_method1_t2
- Shipment_Binary_china_us2_method1_t2_sku1 >= 0
Binary_Link_us2_method1_t3_sku1: Admin_Binary_china_us2_method1_t3
- Shipment_Binary_china_us2_method1_t3_sku1 >= 0
Binary_Link_us2_method2_t1_sku1: Admin_Binary_china_us2_method2_t1
- Shipment_Binary_china_us2_method2_t1_sku1 >= 0
Binary_Link_us2_method2_t2_sku1: Admin_Binary_china_us2_method2_t2
- Shipment_Binary_china_us2_method2_t2_sku1 >= 0
Binary_Link_us2_method2_t3_sku1: Admin_Binary_china_us2_method2_t3
- Shipment_Binary_china_us2_method2_t3_sku1 >= 0
China_Initial_Inventory_sku1: China_Inventory_t1_sku1 = 12
China_Inventory_Balance_t2_sku1: - China_Inventory_t1_sku1
+ China_Inventory_t2_sku1 + 10 Shipment_Quantity_china_us1_method1_t2_sku1
+ 10 Shipment_Quantity_china_us1_method2_t2_sku1
+ 10 Shipment_Quantity_china_us2_method1_t2_sku1
+ 10 Shipment_Quantity_china_us2_method2_t2_sku1 = 12
China_Inventory_Balance_t3_sku1: - China_Inventory_t2_sku1
+ China_Inventory_t3_sku1 + 10 Shipment_Quantity_china_us1_method1_t3_sku1
+ 10 Shipment_Quantity_china_us1_method2_t3_sku1
+ 10 Shipment_Quantity_china_us2_method1_t3_sku1
+ 10 Shipment_Quantity_china_us2_method2_t3_sku1 = 12
Initial_Inventory_us1_t1_sku1: US_Inventory_us1_t1_sku1 = 0
Initial_Inventory_us2_t1_sku1: US_Inventory_us2_t1_sku1 = 10
Inventory_Balance_us1_t2_sku1: Distribution_Quantity_us1_loc1_t2_sku1
+ Distribution_Quantity_us1_loc2_t2_sku1
- Shipment_Quantity_china_us1_method1_t1_sku1 - US_Inventory_us1_t1_sku1
+ US_Inventory_us1_t2_sku1 = 0
Inventory_Balance_us1_t3_sku1: Distribution_Quantity_us1_loc1_t3_sku1
+ Distribution_Quantity_us1_loc2_t3_sku1
- Shipment_Quantity_china_us1_method1_t2_sku1
- Shipment_Quantity_china_us1_method2_t1_sku1 - US_Inventory_us1_t2_sku1
+ US_Inventory_us1_t3_sku1 = 0
Inventory_Balance_us2_t2_sku1: Distribution_Quantity_us2_loc1_t2_sku1
+ Distribution_Quantity_us2_loc2_t2_sku1
- Shipment_Quantity_china_us2_method1_t1_sku1 - US_Inventory_us2_t1_sku1
+ US_Inventory_us2_t2_sku1 = 0
Inventory_Balance_us2_t3_sku1: Distribution_Quantity_us2_loc1_t3_sku1
+ Distribution_Quantity_us2_loc2_t3_sku1
- Shipment_Quantity_china_us2_method1_t2_sku1
- Shipment_Quantity_china_us2_method2_t1_sku1 - US_Inventory_us2_t2_sku1
+ US_Inventory_us2_t3_sku1 = 0
Bounds
0 <= China_Inventory_t1_sku1
0 <= China_Inventory_t2_sku1
0 <= China_Inventory_t3_sku1
0 <= Distribution_Quantity_us1_loc1_t1_sku1
0 <= Distribution_Quantity_us1_loc1_t2_sku1
0 <= Distribution_Quantity_us1_loc1_t3_sku1
0 <= Distribution_Quantity_us1_loc2_t1_sku1
0 <= Distribution_Quantity_us1_loc2_t2_sku1
0 <= Distribution_Quantity_us1_loc2_t3_sku1
0 <= Distribution_Quantity_us2_loc1_t1_sku1
0 <= Distribution_Quantity_us2_loc1_t2_sku1
0 <= Distribution_Quantity_us2_loc1_t3_sku1
0 <= Distribution_Quantity_us2_loc2_t1_sku1
0 <= Distribution_Quantity_us2_loc2_t2_sku1
0 <= Distribution_Quantity_us2_loc2_t3_sku1
0 <= Shipment_Quantity_china_us1_method1_t1_sku1
0 <= Shipment_Quantity_china_us1_method1_t2_sku1
0 <= Shipment_Quantity_china_us1_method1_t3_sku1
0 <= Shipment_Quantity_china_us1_method2_t1_sku1
0 <= Shipment_Quantity_china_us1_method2_t2_sku1
0 <= Shipment_Quantity_china_us1_method2_t3_sku1
0 <= Shipment_Quantity_china_us2_method1_t1_sku1
0 <= Shipment_Quantity_china_us2_method1_t2_sku1
0 <= Shipment_Quantity_china_us2_method1_t3_sku1
0 <= Shipment_Quantity_china_us2_method2_t1_sku1
0 <= Shipment_Quantity_china_us2_method2_t2_sku1
0 <= Shipment_Quantity_china_us2_method2_t3_sku1
0 <= US_Inventory_us1_t1_sku1
0 <= US_Inventory_us1_t2_sku1
0 <= US_Inventory_us1_t3_sku1
0 <= US_Inventory_us2_t1_sku1
0 <= US_Inventory_us2_t2_sku1
0 <= US_Inventory_us2_t3_sku1
Generals
China_Inventory_t1_sku1
China_Inventory_t2_sku1
China_Inventory_t3_sku1
Distribution_Quantity_us1_loc1_t1_sku1
Distribution_Quantity_us1_loc1_t2_sku1
Distribution_Quantity_us1_loc1_t3_sku1
Distribution_Quantity_us1_loc2_t1_sku1
Distribution_Quantity_us1_loc2_t2_sku1
Distribution_Quantity_us1_loc2_t3_sku1
Distribution_Quantity_us2_loc1_t1_sku1
Distribution_Quantity_us2_loc1_t2_sku1
Distribution_Quantity_us2_loc1_t3_sku1
Distribution_Quantity_us2_loc2_t1_sku1
Distribution_Quantity_us2_loc2_t2_sku1
Distribution_Quantity_us2_loc2_t3_sku1
Shipment_Quantity_china_us1_method1_t1_sku1
Shipment_Quantity_china_us1_method1_t2_sku1
Shipment_Quantity_china_us1_method1_t3_sku1
Shipment_Quantity_china_us1_method2_t1_sku1
Shipment_Quantity_china_us1_method2_t2_sku1
Shipment_Quantity_china_us1_method2_t3_sku1
Shipment_Quantity_china_us2_method1_t1_sku1
Shipment_Quantity_china_us2_method1_t2_sku1
Shipment_Quantity_china_us2_method1_t3_sku1
Shipment_Quantity_china_us2_method2_t1_sku1
Shipment_Quantity_china_us2_method2_t2_sku1
Shipment_Quantity_china_us2_method2_t3_sku1
US_Inventory_us1_t1_sku1
US_Inventory_us1_t2_sku1
US_Inventory_us1_t3_sku1
US_Inventory_us2_t1_sku1
US_Inventory_us2_t2_sku1
US_Inventory_us2_t3_sku1
Binaries
Admin_Binary_china_us1_method1_t1
Admin_Binary_china_us1_method1_t2
Admin_Binary_china_us1_method1_t3
Admin_Binary_china_us1_method2_t1
Admin_Binary_china_us1_method2_t2
Admin_Binary_china_us1_method2_t3
Admin_Binary_china_us2_method1_t1
Admin_Binary_china_us2_method1_t2
Admin_Binary_china_us2_method1_t3
Admin_Binary_china_us2_method2_t1
Admin_Binary_china_us2_method2_t2
Admin_Binary_china_us2_method2_t3
Shipment_Binary_china_us1_method1_t1_sku1
Shipment_Binary_china_us1_method1_t2_sku1
Shipment_Binary_china_us1_method1_t3_sku1
Shipment_Binary_china_us1_method2_t1_sku1
Shipment_Binary_china_us1_method2_t2_sku1
Shipment_Binary_china_us1_method2_t3_sku1
Shipment_Binary_china_us2_method1_t1_sku1
Shipment_Binary_china_us2_method1_t2_sku1
Shipment_Binary_china_us2_method1_t3_sku1
Shipment_Binary_china_us2_method2_t1_sku1
Shipment_Binary_china_us2_method2_t2_sku1
Shipment_Binary_china_us2_method2_t3_sku1
End
i constantly get infeasibility evean when i remove or relax some constraints
At line 2 NAME MODEL
At line 3 ROWS
At line 49 COLUMNS
At line 385 RHS
At line 430 BOUNDS
At line 507 ENDATA
Problem MODEL has 44 rows, 92 columns and 135 elements
Coin0008I MODEL read with 0 errors
Option for timeMode changed from cpu to elapsed
Problem is infeasible - 0.00 seconds
Option for printingOptions changed from normal to all
Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00
New contributor
user3477726 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.