Search code examples
pythonconstraintspulpoptimal

How to create a program for constraints based on decision variables when using Python's pulp


Introduction

I would like to create a "switch using a decision variable (if syntax)" using Python's pulp. Here, "switch using decision variables (if syntax)" means, for example, "when x (x is an integer greater than or equal to 0) and y (y is a binary variable of 0, 1) are decision variables, if x is an integer greater than or equal to 1, y outputs 1, and if x is 0, y outputs 0. The following is a simple example. The formula is shown in Problem Formulation 3 (image) attached below.

The following is a simple example of how we tried to create a "switch with decision variables (if syntax)" and the results we achieved.

The examples were created by referring to the examples in "Introduction to Operations Research" (Tokai University Press) .

An ice cream shop is planning to produce two kinds of ice cream: espresso ice cream and raspberry ice cream. However, he cannot produce as much as he wants because he is limited to producing 8000 cc of milk and working for 360 minutes. With this amount of milk and time required for each ice cream, what is the plan to increase production to maximize profits? Today, however, the quantity of raspberries (the ingredients) for one serving of raspberry ice cream will expire. Therefore, you need to produce at least one raspberry ice cream so that it does not go to waste.

Product name Quantity of milk needed Working time Profit
Espresso ice cream 100cc 7 minutes 50 yen
Raspberry ice cream 150cc 5 minutes 10 yen

The above problem setup can be formulated as follows

Problem Formulation1

As a Python program, it can be expressed as follows

import pulp

problem = pulp.LpProblem('ice', pulp.LpMaximize)

# Define the decision variables
x_e = pulp.LpVariable('x_e', lowBound=0, cat=pulp.LpInteger) 
x_r = pulp.LpVariable('x_r', lowBound=0, cat=pulp.LpInteger) 

# Set the objective function
problem += 50*x_e +10*x_r

# Set constraints
problem += 100*x_e + 150* x_r <= 8000
problem += 7*x_e + 5*x_r <= 360

## Newly added constraint
problem += x_r >= 1

# # optimize
problem.solve()

# # print the result
print("Espresso",x_e.value(), "pieces")
print("raspberry",x_r.value(), "pieces")
print("profit",pulp.value(problem.objective), "yen")

The result of running the above program is as follows. We were able to maximize our profit while not discarding the raspberries that were about to expire (the amount of one raspberry ice cream).

Espresso 50.0 pieces
raspberry 2.0 pieces
profit 2520.0 yen

Challenge: After introducing a constraint that functions as a "switch with decision variables (if syntax)" of my own creation (Ice Cream Production Problem)

In the previous chapter, we added the following constraints to the original basic problem

Problem Formulation2

#Newly added constraints
problem += x_r >= 1

In order to align with the theme of this question, we will rewrite this constraint as a "switch with decision variables (if syntax)" constraint like the following

Problem Formulation3

import pulp

problem = pulp.LpProblem('ice', pulp.LpMaximize)

# Define a decision variable
x_e = pulp.LpVariable('x_e', lowBound=0, cat=pulp.LpInteger) 
x_r = pulp.LpVariable('x_r', lowBound=0, cat=pulp.LpInteger)

### Newly added decision variable
y_r = pulp.LpVariable('y_r', lowBound=0, cat=pulp.LpBinary)

# Set the objective function
problem += 50*x_e +10*x_r

# Set constraints
problem += 100*x_e + 150* x_r <= 8000
problem += 7*x_e + 5*x_r <= 360

### Newly added constraint
if x_r.value() >= 1:
  y_r=1
  problem += y_r == 1

# # Optimize
problem.solve()

# Print the result
print("Espresso",x_e.value(), "pieces")
print("raspberry",x_r.value(), "pieces")
print("profit",pulp.value(problem.objective), "yen")

The result is as follows, and I got an error.

   if x_r.value() >= 1:
TypeError: '>=' not supported between instances of 'NoneType' and 'int'

I tried to work on it in the above, but I could not create a switch (if syntax) using decision variables.

Is it impossible to create and solve such a constraint (= switch (if syntax) using decision variables) in pulp? (I'm sorry for my lack of study, but is it a non-linear problem and cannot be expressed in pulp?) (I'm sorry for my lack of study, but maybe it's a non-linear problem and can't be expressed in pulp?) Or is it just a badly written program on my part?

If you could please tell me the cause and solution, I would appreciate it. (If possible, I would like to use pulp, which I am familiar with, but if it is possible to write the program without pulp, I would like to challenge it, so please let me know.)


Solution

  • You cannot add a constraint based on x_r.value() because this won't be available until the problem has been solved.

    A better approach would be to connect x_r and y_r through two additional constraints:

    problem += M*y_r >= x_r
    problem += y_r <= x_r
    

    Here M is a big enough number, with your data setting M = min(8000/150, 360/5) would suffice.