I'm trying to solve for the minimal weekly manufacturing staffing levels based on our weekly inventory deliveries.
import numpy as np
import pulp as p
inventory_delivery = np.array([200, 500, 0, 900, 0]) # deliveries over 5 weeks
productivity = 1 # using 1 to keep it simple for now. This varies week by week.
prob = p.LpProblem('Decision', p.LpMinimize)
a = list()
for x in inventory_delivery:
a.append(p.LpVariable(f'a{len(a)}', 0, None))
# objective
output = sum(a * productivity for a in a) # number of workers * weekly productivity
prob += output
# constraints
prob += output == sum(inventory_delivery) # Need total output by the end to equal total deliveries
#### How do I add a constraint that says my weekly output cannot exceed the inventory I have on hand in a given week?
#### (i.e., Cumulative Inventory - Cumulative Output >= 0 every week)
status = prob.solve()
print(p.LpStatus[status])
print("Objective value:", p.value(prob.objective))
print ('\nThe values of the variables : \n')
for v in prob.variables():
print(v.name, "=", v.varValue)
Right now it solves by front-loading staffing in a0, when I want it spread across all 5 weeks based on my inventory.
Current Output:
Optimal
Objective value: 1600.0
The values of the variables :
a0 = 1600.0
a1 = 0.0
a2 = 0.0
a3 = 0.0
a4 = 0.0
EDIT:
Forgot to mention that the staffing in a
can only stay the same or increase week-over-week; can never decrease. So I'm trying to solve for the lowest total staffing over the course of those 5 weeks.
Reading between the lines a bit, I think the below is about what you are looking for. A couple of key concepts that will help you:
staff_level
to integer, which will slow the model a bit, but nothing noticeable in this small of a model.numpy
when able here. It just makes things more complicated and adds no acceleration in these types of models.import pulp as p
# DATA
deliveries = (200, 500, 0, 0, 900, 0) # deliveries over 5 weeks
productivity = 1 # using 1 to keep it simple for now. This varies week by week.
weeks = list(range(len(deliveries)))
# LP Problem setup
prob = p.LpProblem('Decision', p.LpMinimize)
# VARS
# your life will be easier if you index the variables with lists/sets, like "weeks"...
staff_level = p.LpVariable.dicts('staff', weeks, lowBound=0, cat='Continuous')
inventory = p.LpVariable.dicts('inventory', weeks, lowBound=0, cat='Continuous')
production = p.LpVariable.dicts('production', weeks, lowBound=0, cat='Continuous')
peak_staff_level = p.LpVariable('peak_staff')
# OBJECTIVE
# minimize the "peak" staff level and include a tiny penalty for staff totals to prevent
# unnecessary hires
prob += peak_staff_level + .01 * sum(staff_level[week] for week in weeks)
# constraints
prob += sum(production[week] for week in weeks) == sum(deliveries) # Need total production by the end to equal total deliveries
# an example of a week-based constraint for staff
for week in weeks[1:]: # start with the 2nd week...
prob += staff_level[week] >= staff_level[week - 1]
# an example to keep track of inventory
# first week is special case:
prob += inventory[0] == deliveries[0]
# remainder of weeks are rolling sum...
for week in weeks[1:]:
prob += inventory[week] == inventory[week - 1] - production[week - 1] + deliveries[week]
# now we need to limit the production to inventory on hand, for each week
# and limit to staff productivity... We can combine this in one loop, or break it up.
# either way is fine
for week in weeks:
prob += production[week] <= inventory[week]
prob += production[week] <= staff_level[week] * productivity
# we cannot use max() in an LP, so we must use a constraint to tie the max level to each week's staff level
for week in weeks:
prob += peak_staff_level >= staff_level[week]
#### How do I add a constraint that says my weekly production cannot exceed the inventory I have on hand in a given week?
#### (i.e., Cumulative Inventory - Cumulative Output >= 0 every week)
# inspect the model construction:
print(prob)
status = prob.solve()
print(p.LpStatus[status])
print("Objective value:", p.value(prob.objective))
print ('\nThe values of the variables : \n')
for v in prob.variables():
print(v.name, "=", v.varValue)
inventory_0 = 200.0
inventory_1 = 525.0
inventory_2 = 350.0
inventory_3 = 175.0
inventory_4 = 900.0
inventory_5 = 450.0
peak_staff = 450.0
production_0 = 175.0
production_1 = 175.0
production_2 = 175.0
production_3 = 175.0
production_4 = 450.0
production_5 = 450.0
staff_0 = 175.0
staff_1 = 175.0
staff_2 = 175.0
staff_3 = 175.0
staff_4 = 450.0
staff_5 = 450.0