2

Dear fellow python users,

I am building a multi period multi product planning model using Pulp. What the model should do is rather simple: plan production against minimal holding and production costs while meeting demand.

I have the following data:

periods = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
products = ['A', 'B', 'C']

And I create the following variables:

prod_vars = pulp.LpVariable.dicts('production', [(i,j) for i in products for j in periods],0) 
inv_vars = pulp.LpVariable.dicts('inventory', [(i,j) for i in products for j in periods],0)

There are 2 constraints, 1 to always meet demand and 1 to stay below production capacity. Please note that there is a dataframe (input_data) that retrieves the value of the given demand for that period.

for i in products:
    for j in periods[1:]: 
        model.addConstraint(pulp.LpConstraint(
                    e=inv_vars[(i,j-1)] + prod_vars[(i,j)] - inv_vars[(i,j)],
                sense=pulp.LpConstraintEQ,
                name='inv_balance_'  + str(i)+ str(j),
                rhs=input_data[i][j-1]))

for j in periods:
model.addConstraint(pulp.LpConstraint(
    e=(pulp.lpSum(prod_vars[(i,j)] for i in products)),
    sense=pulp.LpConstraintLE,
    name='total_production_capacity'+str(j),
    rhs=(input_data['production_capacity'][j-1])

Then I add cost function and set the objective:

total_production_cost = production_cost*pulp.lpSum(prod_vars)
total_holding_cost =holding_cost * pulp.lpSum(inv_vars)

objective = total_holding_cost + total_production_cost + activation_cost model.setObjective(objective)

This model works all fine and gives me an output like this. prod_vars: (A,1) =5, (B,1)=10, (C,1)=15 and so on for all periods. However: I want to penalize the system for producing multiple products. I.e., adding fixed costs when choosing to produce a second or third product. It would then be more benefical to produce more of product A and hold inventory for some months then to produce A every month. I tried so by adding another variable:

use_vars = pulp.LpVariable.dicts('uselocation', [(i,j) for i in products for j in periods] , 0,1,pulp.LpBinary)

And add fixed costs for using the variable:

activation_cost = pulp.lpSum(activation_cost*use_vars[(i,j)] for i in products for j in periods)

I think that I would need to multiply al my prod_vars by my use_vars in the two constraints. However, if I would do this in my first inventory constraint, Pulp gives the error that my constraint is not linear anymore.

Does someone know how I can make this happen?? Thanks in advance :)

2 Answers 2

2

I want to penalize the system for producing multiple products. I.e., adding fixed costs when choosing to produce a second or third product.

It is best to step away from code and look at it mathematically.

Let x(i,t)>=0 be the production of item i in period t 

As we need to count, we need binary variables. So, introduce:

y(i,t) = 1 if item i is produced in period t
         0 otherwise

Then we can add

x(i,t) <= M*y(i,t)   (M large enough constant: i.e. capacity)

This implements y(i,t)=0 => x(i,t)=0. We don't have to worry about the other way around x(i,t)=0 => y(i,t)=0 as that is taken care of by the objective (minimize cost).

To add a special cost for producing 2 or 3 products, we need one more binary variable:

count(k,t) = 1 if the number of products produced is k (k=0,1,2,3)
           = 0 otherwise

This can be calculated as:

 y(A,t)+y(B,t)+y(C,t) = 1*count(1,t)+2*count(2,t)+3*count(3,t)   
 count(1,t)+count(2,t)+count(3,t) <= 1

Now you can add say: 100*count(2,t)+200*count(3,t) to your cost calculation. (Note: just for completeness: I assumed the cost for 3 products is at least as large as the cost for 2 products).

Sign up to request clarification or add additional context in comments.

1 Comment

How would you implement y(i,t) = 1 if item i is produced in period t 0 otherwise considering that x(i,t) is an Integer variable and not a binary variable? what linear constraint would you impose?
0

To achieve what you intend you can add additional constraints connecting prod_vars and use_vars like (pseudo-code):

prod_vars[(i, j)] >= use_vars[(i, j)] forall i, j
prod_vars[(i, j)] <= M * use_vars[(i, j)] forall i, j

where M can be set to max(input_data['production_capacity']).

Doing this you don't need modify the original constraints.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.