LP model using pulp (time series optimization) Problem is infeasible

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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<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.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật