# Need help for the python scheduling code

I'm working on a Python application using PuLP for optimization, and I'm having trouble ensuring that only one material is produced on a given day.

The constraint prob += pulp.lpSum(production_flag[m][d] for m in materials) <= 1 is intended to ensure that only one material is produced on a given day. However, it doesn't seem to be working as expected. Multiple materials are still being scheduled for production on the same day. How can I modify my constraints or logic to ensure that only one material is produced on any given day?

Below is my current code:

materials = ["600065", "600047", "600063", "600076", "600061"]
current_date = datetime(2024, 6, 13)
current_inventory = {
"600065": {current_date: 247.5},
"600047": {current_date: 0},
"600063": {current_date: 205.2},
"600076": {current_date: 80},
"600061": {current_date: 1.2}
}

quantity_to_be_sold = {
"600065": {datetime(2024, 6, 14): 25,
datetime(2024, 6, 15): 55,
datetime(2024, 6, 18): 25,
datetime(2024, 6, 20): 25,
datetime(2024, 6, 21): 25,
datetime(2024, 6, 27): 25,
datetime(2024, 6, 28): 25,
datetime(2024, 6, 30): 50},
"600047": {datetime(2024, 6, 24): 25},
"600063": {datetime(2024, 6, 14): 52.8,
datetime(2024, 6, 15): 79.2,
datetime(2024, 6, 21): 26.4,
datetime(2024, 6, 22): 79.2,
datetime(2024, 6, 28): 52.8},
"600076": {datetime(2024, 6, 14): 20,
datetime(2024, 6, 15): 20,
datetime(2024, 6, 18): 40,
datetime(2024, 6, 19): 40,
datetime(2024, 6, 24): 20,
datetime(2024, 6, 26): 20,
datetime(2024, 6, 27): 20,
datetime(2024, 6, 28): 20,
datetime(2024, 6, 21): 20},
"600061": {datetime(2024, 6, 21): 26.4}
}

production_capacity = {"600065": 80,"600047": 80, "600063": 36, "600076": 30, "600061": 36}
waiting_period = {"600065": 1,"600047": 1, "600063": 2, "600076": 2, "600061": 2}

#Collect all dates from input data and current inventory
all_dates = sorted(set(date for dates in quantity_to_be_sold.values() for date in dates).union(
date for dates in current_inventory.values() for date in dates))

#Define the problem
prob = pulp.LpProblem("AS_Packaging_Optimization", pulp.LpMaximize)

#Define decision variables
production = pulp.LpVariable.dicts("Production", (materials, all_dates), 0, None, pulp.LpContinuous)
inventory = pulp.LpVariable.dicts("Sales", (materials, all_dates), 0, None, pulp.LpContinuous)
available_for_sale = pulp.LpVariable.dicts("AvailableForSale", (materials, all_dates), 0, None, pulp.LpContinuous)
production_flag = pulp.LpVariable.dicts("ProductionFlag", (materials, all_dates), 0, 1, pulp.LpBinary)

#Objective function: Maximize total sales
prob += pulp.lpSum([quantity_to_be_sold[m].get(d, 0) for m in materials for d in all_dates])

def get_cumulative_production(production_data, current_date, waiting_period, all_dates):
cumulative_production = 0
start_date = current_date - timedelta(days=waiting_period-1)

for date in all_dates:
if start_date <= date <= current_date and date in production_data:
cumulative_production += production_data[date]

return cumulative_production

#Constraints: Inventory
for m in materials:
for i, d in enumerate(all_dates):
# Inventory balance constraints
if i == 0:
prob += inventory[m][d] == current_inventory[m].get(d, 0)
else:
prev_day = all_dates[i - 1]
prob += inventory[m][d] == inventory[m][prev_day] + production[m][d] - quantity_to_be_sold[m].get(d, 0)

# Available for sale considering the waiting period
if i == 0:
prob += available_for_sale[m][d] == inventory[m][d]
else:
production_data = {date: production[m][date] for date in all_dates}
total_production_deduction = get_cumulative_production(production_data, d, waiting_period[m], all_dates)
prob += available_for_sale[m][d] == inventory[m][d] - total_production_deduction

#Constraint: Materials and Production on initial day
for m in materials:
for d in current_inventory[m]:
prob += production[m][d] == 0

#Constraint: Materials and Production on subsequent day
for d in all_dates:
prob += pulp.lpSum(production_flag[m][d] for m in materials) <= 1
for m in materials:
prob += production[m][d] <= production_capacity[m] * production_flag[m][d]
prob += production[m][d] >= 0

#Solve the problem
prob.solve()

# Extract results
def extract_results(material):
results = {
"Date": [],
"Material": [],
"Production": [],
"Sales": [],
"Inventory": [],
"AvailableForSale": []
}

for d in all_dates:
results["Date"].append(d.strftime("%Y-%m-%d"))
results["Material"].append(material)
results["Production"].append(pulp.value(production[material][d]))
results["Sales"].append(quantity_to_be_sold[material].get(d, 0))
results["Inventory"].append(pulp.value(inventory[material][d]))
results["AvailableForSale"].append(pulp.value(available_for_sale[material][d]))

df_results = pd.DataFrame(results)
return df_results

# Extract results for each material
df_results_600065 = extract_results("600065")
df_results_600047 = extract_results("600047")
df_results_600063 = extract_results("600063")
df_results_600076 = extract_results("600076")
df_results_600061 = extract_results("600061")

print("Results for Material 600065:")
print(df_results_600065 if isinstance(df_results_600065, pd.DataFrame) else df_results_600065)
print("Results for Material 600047:")
print(df_results_600047 if isinstance(df_results_600047, pd.DataFrame) else df_results_600047)
print("\nResults for Material 600063:")
print(df_results_600063 if isinstance(df_results_600063, pd.DataFrame) else df_results_600063)
print("\nResults for Material 600076:")
print(df_results_600076 if isinstance(df_results_600076, pd.DataFrame) else df_results_600076)
print("\nResults for Material 600061:")
print(df_results_600061 if isinstance(df_results_600061, pd.DataFrame) else df_results_600061)

• When I run your code on my machine, Pulp says that the problem is infeasible. You should first figure out why this is the case. Commented Jun 17 at 7:38
• Hi, PeterD thank you for your comment. I run it on Jupyter Notebook and the results is feasible (I am not sure it's infeasible, but the result can expose??). Sorry, i am newbie for this thing. Commented Jun 17 at 8:33
• It might show you values for your variables, but this does not mean its feasible. In my case Pulp says that is proved to be infeasible. Commented Jun 17 at 8:47
• Could you tell me where do you run this code? Commented Jun 17 at 8:50
• I add the extract data part after prob.solve. Could you run it to see the result? Thank you very much -/\- Commented Jun 17 at 8:56