I am working on Production planning optimization where I have three stages of planning
- Production plan
- Packaging plan
- Dispatch plan
for each stage I have its capacity and lead time it takes for each stage.
I have my demand on each state level
I am developing my code in glpk optimizer with PYOMO library to solve linear problem the model shows that i have found optimal solution but for some reason it is not generating any non zero value
here is my sample dictionary data
{‘Demand’: state Depot Product varient pack size W1 W2 W3 W4 W5 W6 W7 W8 W9 W10
0 mah D1 P1 V1 20 L 1000 1300 100 200 2300 3300 2300 3200 3300 2300
1 mah D1 P1 V2 20 L 1000 1300 100 200 2300 3300 2300 3200 3300 2300
2 mah D1 P1 V1 10 L 1000 1300 100 200 2300 3300 2300 3200 3300 2300
3 Goa D2 P2 V3 20 L 1000 1300 100 200 2300 3300 2300 3200 3300 2300
4 Goa D3 P2 V3 20 L 1000 1300 100 200 2300 3300 2300 3200 3300 2300, ‘Financial’: state Depot Product varient pack size Factory Gross Margin
0 mah D1 P1 V1 20 L Factory_1 100
1 mah D1 P1 V2 20 L Factory_1 120
2 mah D1 P1 V1 10 L Factory_2 140
3 Goa D2 P2 V3 20 L Factory_2 122
4 Goa D3 P2 V3 20 L Factory_2 111
5 mah D1 P1 V1 20 L Factory_3 -120
6 mah D1 P1 V2 20 L Factory_3 111
7 mah D1 P1 V1 10 L Factory_3 212
8 Goa D2 P2 V3 20 L Factory_4 0
9 Goa D3 P2 V3 20 L Factory_4 22, ‘Disruption_week’: Week_number Disprution_flag
0 1 1
1 2 0
2 3 0
3 4 0
4 5 0
5 6 1
6 7 0
7 8 1
8 9 0
9 10 0
10 11 0
11 12 0
12 13 0
13 14 0
14 15 0, ‘Market_inventory’: State Depot Product Variant Name Harmonized Pack Mkt Opening stock at W1
0 mah D1 P1 V1 20 L 10
1 mah D1 P1 V2 20 L 20
2 mah D1 P1 V1 10 L 13
3 Goa D2 P2 V3 20 L 22
4 Goa D3 P2 V3 20 L 40, ‘Dispatch_LT’: Factory State Dispatch_LT
0 Factory_1 mah 2
1 Factory_2 mah 1
2 Factory_3 mah 4
3 Factory_4 mah 3
4 Factory_1 Goa 2
5 Factory_2 Goa 4
6 Factory_3 Goa 2
7 Factory_4 Goa 0, ‘Packaging_LT’: Factory Pack size Packaging_LT
0 Factory_1 10 L 10
1 Factory_2 10 L 3
2 Factory_3 10 L 4
3 Factory_4 10 L 5
4 Factory_1 20 L 2
5 Factory_2 20 L 3
6 Factory_3 20 L 4
7 Factory_4 20 L 5, ‘Production_LT’: Source Product Production_LT
0 Factory_1 P1 2
1 Factory_2 P1 1
2 Factory_3 P1 3
3 Factory_4 P1 4
4 Factory_1 P2 4
5 Factory_2 P2 1
6 Factory_3 P2 0
7 Factory_4 P2 0, ‘Dispatch_capacity’: Factory pack size Dispatch Capacity
0 Factory_1 10 L 700
1 Factory_2 10 L 700
2 Factory_3 10 L 700
3 Factory_4 10 L 700
4 Factory_1 20 L 700
5 Factory_2 20 L 700
6 Factory_3 20 L 700
7 Factory_4 20 L 700, ‘Packaging_capacity’: Source Pack Type Capacity
0 Factory_1 10 L 1000
1 Factory_2 10 L 1000
2 Factory_3 10 L 1000
3 Factory_4 10 L 1000
4 Factory_1 20 L 1000
5 Factory_2 20 L 1000
6 Factory_3 20 L 1000
7 Factory_4 20 L 1000, ‘Production_capacity’: Factory Capacity
0 Factory_1 1000
1 Factory_2 1000
2 Factory_3 1000
3 Factory_4 1000}
here are the business constraints i wrote for this
def model_optimizer(data,config):
print(data)
n_days=range(1,config['n_days_optimise']+1)
# Initialize the model
model=pyo.ConcreteModel()
# Sets
model.factories=pyo.Set(initialize=config["factories"])
model.products=pyo.Set(initialize=config["products"])
model.pack_size=pyo.Set(initialize=config["pack_sizes"])
model.states=pyo.Set(initialize=config["states"])
model.depots=pyo.Set(initialize=config["depots"])
model.varients=pyo.Set(initialize=config["varient"])
model.days=pyo.RangeSet(config["n_days_optimise"])
# parameter extraction
demand,financial,mkt_inv,dispatch_lt,packaging_lt,production_lt,dispatch_cap,packaging_capacity,production_capacity=get_all_params(data,config)
#decision variables
model.production=pyo.Var(model.factories,model.products,model.days,within=pyo.NonNegativeReals)
model.packaging = pyo.Var(model.factories, model.varients,model.pack_size,model.days, within=pyo.NonNegativeReals)
model.dispatch = pyo.Var(model.factories, model.varients,model.pack_size, model.depots, model.states, model.days, within=pyo.NonNegativeReals)
model.sales = pyo.Var(model.varients, model.states, model.depots, model.pack_size, model.days, within=pyo.NonNegativeReals)
model.market_inventory = pyo.Var(model.varients, model.states, model.depots, model.pack_size, model.days, within=pyo.NonNegativeReals)
# gross_margin = {(row['state'], row['Depot'], row['Product'], row['varient'], row['pack size'], row['Factory']): row['Gross Margin'] for index, row in financial.iterrows()}
gross_margin=financial
# Objective function
def objective_rule(model):
return sum(
model.dispatch[f, v, ps, depot, state, d] * gross_margin.get((state, depot, p, v, ps, f), 0)
for f in model.factories
for p in model.products
for v in model.varients
for ps in model.pack_size
for depot in model.depots
for state in model.states
for d in model.days
)
model.objective = pyo.Objective(rule=objective_rule, sense=pyo.maximize)
#constraints
# Demand constraint (sales must not exceed demand)
def sales_demand_constraint_rule(model, v, s, depot, ps, d):
return model.sales[v, s, depot, ps, d] <= demand.get((depot, s, v, ps, d), 0)
model.sales_demand_constraint = pyo.Constraint(model.varients, model.states, model.depots, model.pack_size, model.days, rule=sales_demand_constraint_rule)
# capacity Constraints
# Production capacity constraint
def production_capacity_rule(model, f, d):
return sum(model.production[f, p, d] for p in model.products) <= production_capacity.get((f, d), 0)
model.production_capacity_constraint = pyo.Constraint(model.factories, model.days, rule=production_capacity_rule)
# Packaging capacity constraint
def packaging_capacity_rule(model, f, d):
return sum(model.packaging[f, v, ps, d] for v in model.varients for ps in model.pack_size) <= packaging_capacity.get((f, d), 0)
model.packaging_capacity_constraint = pyo.Constraint(model.factories, model.days, rule=packaging_capacity_rule)
# Dispatch capacity constraint
def dispatch_capacity_rule(model, f, ps, d):
return sum(model.dispatch[f, v, ps, depot, state, d] for v in model.varients for depot in model.depots for state in model.states) <= dispatch_cap.get((f, ps), 0)
model.dispatch_capacity_constraint = pyo.Constraint(model.factories, model.pack_size, model.days, rule=dispatch_capacity_rule)
# lead time constraints
def lead_time_production_rule(model, f, p, d):
lead_time = production_lt.get((f, p), 0)
if lead_time > 0 and d > lead_time:
# Constraint to ensure the production respects the lead time
return model.production[f, p, d] <= sum(model.production[f, p, d - i] for i in range(1, lead_time + 1))
elif lead_time == 0:
# If lead time is zero, production can occur without delay
return model.production[f, p, d] <= production_capacity.get((f, d), 0)
else:
return pyo.Constraint.Skip
model.lead_time_production_constraint = pyo.Constraint(model.factories, model.products, model.days, rule=lead_time_production_rule)
def lead_time_packaging_rule(model, f, v, ps, d):
lead_time = packaging_lt.get((f, ps), 0)
if d > lead_time:
return model.packaging[f, v, ps, d] <= model.packaging[f, v, ps, d - lead_time]
else:
return pyo.Constraint.Skip
model.lead_time_packaging_constraint = pyo.Constraint(model.factories, model.varients, model.pack_size, model.days, rule=lead_time_packaging_rule)
def lead_time_dispatch_rule(model, f, v, ps, depot, state, d):
lead_time = dispatch_lt.get((f, state), 0)
if d > lead_time:
return model.dispatch[f, v, ps, depot, state, d] <= model.dispatch[f, v, ps, depot, state, d - lead_time]
else:
return pyo.Constraint.Skip
model.lead_time_dispatch_constraint = pyo.Constraint(model.factories, model.varients, model.pack_size, model.depots, model.states, model.days, rule=lead_time_dispatch_rule)
def demand_fulfillment_constraint_rule(model, p, ps, depot, state, d):
# Calculate the total demand for the product in the specified state, depot, and pack size
total_demand = sum(demand.get((depot, state, p, v, ps), 0) for v in model.varients)
# Ensure that the sum of production, packaging, and dispatch equals or exceeds the demand
return (
sum(model.production[f, p, d] for f in model.factories) +
sum(model.packaging[f, v, ps, d] for f in model.factories for v in model.varients) +
sum(model.dispatch[f, v, ps, depot, state, d] for f in model.factories for v in model.varients)
) >= total_demand
# Add demand fulfillment constraints to the model
model.demand_fulfillment_constraint = pyo.Constraint(model.products, model.pack_size, model.depots, model.states, model.days, rule=demand_fulfillment_constraint_rule)
# Solve the model
solver = pyo.SolverFactory('glpk')
result= solver.solve(model,tee=True)
if (result.solver.status == pyo.SolverStatus.ok) and (result.solver.termination_condition == pyo.TerminationCondition.optimal):
print('Solution is optimal')
elif result.solver.termination_condition == pyo.TerminationCondition.infeasible:
print('Solution is infeasible')
else:
print('Solver Status: ', result.solver.status)
I have tried changing my optimizer objective function to
def objective_rule(model):
return (
sum(model.production[f, p, d] for f in model.factories for p in model.products for d in model.days) +
sum(model.packaging[f, v, ps, d] for f in model.factories for v in model.varients for ps in model.pack_size for d in model.days) +
sum(model.dispatch[f, v, ps, depot, state, d] for f in model.factories for v in model.varients for ps in model.pack_size for depot in model.depots for state in model.states for d in model.days)
)
model.objective = pyo.Objective(rule=objective_rule, sense=pyo.maximize)
I have also played with the Input value. checked the data is getting parsed but for some reason, the decision variable is not able to generate any non-zero value. Any feedback or approach change would be appreciated.