Maximizing Profit Using Linear Programming in Python | by Luciano Vilas Boas | Towards Data Science

The Simplex Method was designed to help solve LP problems and it is basically what we will see here. With advances in the technological field, this method started to be used, not only in the Military, but in a vast myriad of industries. Today, I will present you an example of how we can take advantage of this algorithm. I’ll cover the following:
1- Basic Concepts of Linear Programming
2- How to Formulate a LP Problem
3- How to Solve a LP using Python
4- A Graphical Way to Look at LP Problem
Linear Programming and linear inequalities go side by side. That is, many real-life problems are subject to some restrictions, e.g. number of raw material to produce a chair. In order words, there are some limitations that prevent us to manufacture an item without compromising the production of others.
For example, let’s say you need wood to make chairs and tables, so the amount of wood that you have available imposes a limit on the number of chairs and tables you can produce.
In essence, this is the very problem LP attempts to solve: how to systematically allocate the resources in order to get the most out of the restriction (constraints) that we have, while considering, for example, the potential maximization of the profit you get from their sales. On that note, we can use LP to Maximize a profit, or Minimize a cost, like said previously. Funny thing is that we can convert a maximization problem into minimization, and vice-versa. But this won’t be the focus here.
In LP, when I say “solve” that does not mean we will find a solution (like 2 + 2 = 4) all the time. We can formulate a LP problem, do some Math, and come to the conclusion that the particular LP problem does not have an Optimal Solution, which is the main goal of solving a LP: trying to land a unique optimal solution. This can occur because some problems may have too many different optimal solutions or even no optimal solution at all.
Some of the reasons we may encounter a LP without an optimal solution may be out of our control. In many cases, the problems are simply way too complex to be solved (finding a unique optimal solution). A question we may want to ask ourselves when working on a LP problem may be: Is the problem feasible or infeasible? Some problems can even have many feasible solutions, and ended up being unbounded. To sum up, we can classify a LP problem into three classes: optimal solution, infeasible, and unbounded.
Here, you are going to see an example of a LP problem that give us an Optimal Solution. But before we start working on our problem, I want to show you an example of how a traditional LP problem looks like:
The first line says “maximize” and that is where our objective function is located. That could also say “minimize”, and that would indicate our problem was a minimization problem.
The second and third lines are our constraints. This is basically what prevent us from, let’s say, maximizing our profit to the infinite. Like I mentioned already, this is the part where we can spot the linear inequalities (≤, =, ≥). I also have to disclose that there are different ways to solve a LP problem, like for instance, BigM, Dual, Two Phased method etc.
Unfortunately, it’s counterproductive trying to cover all the nuts and bolts of LP here, I hope you got some basic foundation to move on to our example. If not, I’m dropping some references at the end of this post so you can refer to.
True Optimization it the revolutionary contribution of modern research to decision processes — George Dantzig
Let’s say we work on a Data Science team for a manufacturing firm. The problem we are going to tackle here is named “The Activity-Analysis Problem” (Gass 1970). The Data Science team’s goal is to maximize the profit of the manufacturing company by defining how many different products to produce, taking into consideration, the limitation of resources available. By improving the operations of the firm and its resources allocation, we can potentially maximize the profit, which is the focus of our discussion here.
The company produces four furniture items: chairs, tables, desks, and bookcases. The principal component is mahogany, but they also use glue, leather, glass, and man-hours. For example, when we see a chair, what really takes to make a single one is 5 board-feet of mahogany, 10 man-hours of labor, 3 ounces of glue, and 4 square feet of leather. To produce a table we need 20 board-feet, 15 man-hours, 8 ounces of glue. A desk is made by 15 board-feet, 25 man-hours, 15 ounces of glue, and 20 square feet of leather. Lastly, the bookcase is produce using 22 board-feet, 20 man-hours, 10 ounces of glue, and 20 square feet of glass.
Here is an illustration of what we need to make a single chair:
The bottom neck is that all these material have the following total quantities available, per week:
- 20,000 board-feet of mahogany
- 4,000 man-hours
- 2,000 ounces of glue
- 3,000 square feet of leather
- 500 square feet of glass
As you can see, the restricted amount of materials prevent us to produce all products with unlimited quantities at the same time. That is to say, our job is to decide how to better allocate these resources together in order to make the most profit. This is an exercise of how to develop a data-driven decision making process.
But in order to set up this problem, we need to know the profit that each product brings to the firm. Hint: this is what we want to Maximize.
Here they are:
- $45 per Chair
- $ 80 per Table
- $110 per Desk
- $55 per Bookcase
Wait! One may decide to produce only desks, because this item alone has the highest profit ($110). But, why should we not embrace this approach? I will leave that answer for you figure out.
Since we want to manufacture all these four items, and offer a good mix of products to our customers, while splitting the risk at the same time, what we really want to know is how many units of each item we have to produce in order to get the most profit. That is where LP modeling can help us square this problem out.
For this Maximization LP problem, we are going to represent the items by the first letter of its name. Likewise, c for chair, t for table, d for desk, and b for bookcase.
Just like we did in the previous example of what would take to produce a single chair, we will follow a similar schema for all the other items. Below we can see the amount of resources needed to make every single one of them. Note that the total amount for making these products must be less or equal to the total resources available.
Take your time to read this schema. I just put together the data for making every single one of our four products, plus the constraints, which are the resources available (last column).
Now, in order to formulate our LP in a more conventional way, all we have to do is bring the profit to be made by the items (the Objective Function). Here is how it looks like the final formulation of this LP problem:
We did it. Congratulations! Tap yourself on the back because, usually, formulating a LP problem is the hardest part of this processing. Remember “garbage in, garbage out”, so if a LP is not formulated properly, it will not bring much value.
Now that we have formulated the problem, we will use Python, and more specifically, the library called PuLP to solve this LP. Without further due, let’s do that.
Linear Programming is a generalization of Linear Algebra. It is capable of handling a variety of problems, ranging from finding schedules for airlines or movies in a theater to distributing oil from refineries to markets. The reason for this great versatility is the ease at which constraints can be incorporated into the model-Steven J. Miller
Instructions on how to install PuLP on Anaconda can be found here.
Because this is simple example, and we are not working with many variables, constraints etc, we will not be using and importing any file (like csv) into Python, we are rather just entering these few variables. We could also create a Python program to request the user to do that in a more high level and organized way, but I’ll leave that up to you.
I will break this section in two parts: in Part 1 we are going to set up this previous problem in Python using PuLP, and in Part 2 we are going to solve it.
After you have installed PuLP you’ll we need to import PuLP library as following below:
# import the library PuLP as p import pulp as p
Next we will set up the Maximization problem and initiate the variables:
# Set Up a LP Maximization Problem:Lp_prob = p.LpProblem('Activity-Analysis_1', p.LpMaximize) # Here we named the Problem "Acitity-Analysis_1".  # Set Up Problem Variables: c = p.LpVariable("c", lowBound = 0) # "c" for chairt = p.LpVariable("t", lowBound = 0) # "t" for tabled = p.LpVariable("d", lowBound = 0) # "d" for deskb = p.LpVariable("b", lowBound = 0) # "b" for bookcase
Now, that’s the part we will create the Objective Function (what we are trying to Maximize), and the Constraints.
# Create Objective Function:Lp_prob += 45 * c + 80 * t + 110 * d + 55 * b      # Create Constraints: Lp_prob += 5 * c + 20 * t + 15 * d + 22 * b <= 20000Lp_prob += 10 * c + 15 * t + 25 * d + 20 * b <= 4000Lp_prob += 3 * c + 8 * t + 15 * d + 10 * b <= 2000Lp_prob += 4 * c + 20 * d <= 3000Lp_prob += 20 * b <= 500
Finally, we will display this problem in order to make sure things look good.
# Show the problem:print(Lp_prob) # note that it's shown in alphabetical order
After running this previous code, this is how your LP problem should look like:
As you can see the displayed problem looks like the one I wrote before, except the fact that PuLP organize the variables alphabetically, which has no impact in the solution whatsoever. So far, all we did was enter the variables we talked earlier and modeling the LP problem in Python. For the sake of simplicity and easier the understanding, we won’t be solving it now, but in Phase 2.
Here we are going to create a new and simplified problem, which derivates from the one we just saw. The reason for that is just to make easier to convey the solution and it also helps to get additional intuition on solving these type of problems.
Alright, in this new problem, we are still working with the same variables, but now we brought it down to only two variables (chair, and table), and we changed some numbers. Here is how our new Maximization problem looks like:
As matter of fact, we kept most of the numbers without change, but now, the total of mahogany is 400, and the total of man-hours is 450. The second constraint was also changed from “15t” to “20t”. Now we will solve this problem in Python as following:
### Simplifying the Problem and Solving it #### Generate a New LP Maximization Problem:Lp_prob2 = p.LpProblem('Activity-Analysis_2', p.LpMaximize)  # Generate Problem Variables (>= 0): c = p.LpVariable("c", lowBound = 0)t = p.LpVariable("t", lowBound = 0)# Create Objective Function:Lp_prob2 += 45 * c + 80 * t #+ 110 * d + 55 * b      # Set Up the Constraints: Lp_prob2 += 5 * c + 20 * t <= 400Lp_prob2 += 10 * c + 15 * t <= 450# Show the problem:print(Lp_prob2) # note that it's shown in alphabetical order
Again, let’s check how this new problem is displayed in Python:
It looks just fine, so now we can proceed to solve it. Below is the code you need to do so. Note that will we print the “status” of the solution, which just tells us if the solution is Optimal (or not). In this example, we got an Optimal Solution.
# Solve the Problem:status = Lp_prob2.solve()print(p.LpStatus[status])   # Display Solution Status
Keep in mind that not all LP problems have an Optimal solution. Now, to really see the actual numbers we need to print the result as following.
# Printing the final solution print(p.value(c), p.value(t), p.value(Lp_prob2.objective))# Result: 24.0 14.0 2200.0
So we got “24”, “14”, and “2200”. One may be wondering what those numbers are, right? It turns out that 24 and 14 are the optimal number of chairs and tables, respectively, that we need to produce in order to get the Optimal profit of $2,200. Hint: Linear Programming is all about Optimization.
If you want to, you can create a loop to display this result. Here is an example:
# Printing Number of Chairs and Tables:for var in (c,t):    print('Optimal number of {} to produce is: {:1.0f}'          .format(var.name, var.value()))# Output:# Optimal number of c to produce is: 24# Optimal number of t to produce is: 14
In order words, the optimum combination to produce for these two items, and making the most profit, considering the restrictions we have on the number of mahogany and man-hour available is: c=24 chairs, t=14 tables, and to find the optimal profit, we have to bring the objective function in this equation. This will look like: $45 x 24 + $80 x 14 = $2,200.
We just used the Simplex algorithm to solve this problem. Now we can make a decision based on data, and supported by the results we got. Not based on gut feeling, right?!
One more thing I need to point it out is that the Simplex can be quite challenging and tricky to solve. Although, it looked like a piece of cake here, if you attempt to solve it by hand, you can have a hard time if you don’t know what and how to actually do it. Thank God that nowadays we have the capabilities to do that using a solution like Python/PuLP.
Before resting my case, I want to show you how this problem can be plotted into a chart. There are many ways to solve a Linear Programming problem, and the graphical method is one of them.
So, I went to the white board and drew the Simplex Graph to take our discussion one step further. Here is the plot (which can be done using Matplotlib on Python):
It looks nice, right?! Let me explain to you how we got there.
First, we start looking at the first inequality (5c + 20t ≤ 400) of our LP problem, in this case, represented by the orange color. What we need is to find two points, one for c axis and other on the t axis (remember c for chair, and t for table). The simplest way to come up with that is to assume that if c = 0, we must get t = 20, and mark that “dot” on the t axis; and if t = 0, then we get c = 80, which we plot on the c axis.
Second, we plot the last constrain (10c + 15t ≤ 450), represented by the green line. Following the same approach as before, we got the points on the axes as following: 45,0 and 0,30.
In this plot, what we see is the superimposition of these two inequalities. By overlapping them, we can figure out the required solution space, which is the highlighted area in yellow. Any points in this region will satisfy the constraints of this problem, and this combination represents the different set ups of tables and chairs that we can produce considering the resources we have available (mahogany and man-hours). When both lines cross each other, we get the Optimal value of 24,14 (in red). This means that c=24, and t=14 satisfies both constraints precisely. We also found this same result using PuLP, but you can work with some algebra if you want to confirm that as well.
Finally, we look at the Objective Function (45c + 80t = 0). This is represented by the gray line. Now, let’s think for a second. If the firm does not make any chairs and tables what would be its profit? Zero, right?! That would mean that c =0, and t=0. This is our starting point with the Simplex method, and we can move that gray line from zero up to the point that intersects c and t (24, 14), but not out of the boundary of that yellow area. By doing so, we eventually get to the Optimum formulation, which we have seen before: $45 x 24 + $80 x 14 = $2,200.
By now you may have gotten the intuition that you could experiment with different values, and ended up testing multiple optimum solutions based on changes in the objective function, for instance. I hope this was useful for you.
This example was extracted and adapted from the book “An Illustrated Guide to Linear Programming” by Saul I. Gass. You can find the codes on my GitHub here.
Get started, but don’t try to eat the elephant in one meal. Start small with a pilot project and build your first dashboard. From there you can learn, improve, and expand into other areas-Rupert Bonham-Carter
In this article you were introduced to some basic concepts of LP, you saw how to formulate a LP problem, and how to solve it. Optimization of resources will always be part of the agenda in many companies around the world. There will be always problems to Maximize and/or Minimize, depending on the scope of the project.
Data Scientists need to have, at least, a very basic idea of how LP can be useful and the resources that we have available today to help us out. I hope this post has inspired you to perform your own experiments. Good Luck.
Thank you!
[1] Lial, Greenwell, and Ritchey, 2012: Finite Mathematics. Boston, Massachusets: Pearson.
[2] Chvatal, Vasek, 1983: Linear Programming. USA: Freeman.
[3] Gass, Saul I., 1970: An Illustrated Guide to Linear Programming. Canada: Dover.