Linear Programming (LP) is a fundamental optimization technique that
helps decision-makers allocate limited resources optimally. In this
module, we’ll explore how to formulate linear programming models,
identify their components, and solve them using both Excel Solver and
Python with Gurobi.
After completing this module, you will be able to:
Identify the three key components of a linear programming model
Formulate linear programming models from problem descriptions
Determine whether a function is linear or nonlinear
Solve linear programming problems using graphical methods
Implement and solve LP models using Excel Solver
Implement and solve LP models using Python with Gurobi
Interpret the results of your optimization models
2
Introduction to Linear Programming
Linear Programming (LP) is a powerful optimization technique used to
find the best outcome in mathematical models with linear relationships.
LP has wide applications in business and supply chain management,
including:
Production planning and scheduling
Resource allocation
Transportation and distribution problems
Financial portfolio optimization
Network flow problems
2.1
What Makes a Problem Suitable for Linear Programming?
A problem can be solved using linear programming if:
The objective (what you’re trying to maximize or minimize) can be
expressed as a linear function
All constraints can be expressed as linear inequalities or
equations
All variables can take non-negative values (in standard form)
2.2
Components of a Linear Programming Model
Every LP model consists of three essential components:
Decision Variables: What you’re trying to decide
(usually denoted as , , etc.)
Objective Function: The goal you’re trying to
maximize or minimize (, , etc.)
Constraints: Limitations on resources or
requirements that must be satisfied
2.3
Linear vs. Nonlinear Functions
A linear function has the form:
Where:
are
variables
are
constants
In a linear function:
Variables appear only to the first power (no squares, cubes,
etc.)
Variables don’t multiply or divide each other
There are no transcendental functions (log, sin, etc.) of
variables
Examples of linear functions:
(constant function)
(can be rewritten as
)
Examples of nonlinear functions:
(variables raised to
powers other than 1)
(variables
dividing each other)
(variables
multiplying each other)
3 The
Wyndor Glass Co. Problem
Let’s examine a classic LP problem that we’ll use throughout this
module. The Wyndor Glass Company produces high-quality glass products in
three plants and is considering launching two new products:
Aluminum-framed glass doors (Product 1)
Wood-framed windows (Product 2)
Each plant has a limited number of production hours available per
week:
Plant 1: 4 hours available for Product 1 only
Plant 2: 12 hours available for Product 2 only
Plant 3: 18 hours available for both products
The company earns:
$3,000 profit per batch of Product 1
$5,000 profit per batch of Product 2
The problem: How many batches of each product should Wyndor produce
weekly to maximize profit?
3.1
Formulating the Wyndor Glass LP Model
Decision Variables:
= Number of batches of
Product 1 (aluminum-framed doors)
= Number of batches of
Product 2 (wood-framed windows)
Objective Function:
Maximize
(profit in thousands of dollars)
Constraints:
Plant 1:
(hours available in Plant 1)
Plant 2:
(hours available in Plant 2)
Plant 3:
(hours available in Plant 3)
Non-negativity:
(can’t produce negative amounts)
This complete mathematical model represents our optimization
problem.
4 Solving
LP Models Graphically
For LP problems with two decision variables, we can solve them
graphically by:
Plotting each constraint on a graph
Identifying the feasible region (the area that satisfies all
constraints)
Finding the optimal solution at one of the corner points of the
feasible region
4.1
Steps to Solve the Wyndor Glass Problem Graphically:
Plot the constraints:
Plant 1: (vertical
line at )
Plant 2: (horizontal
line at )
Plant 3:
(line connecting points and
)
Non-negativity: and
(the positive
quadrant)
Identify the feasible region:
The region bounded by these lines forms a polygon. Any point inside
this polygon represents a feasible solution.
Find the optimal solution:
The optimal solution will be at one of the corner points of the
feasible region
For a maximization problem, we want the corner point that gives the
highest value of the objective function
Let’s calculate the objective function value at each corner
point:
Corner Point
(0,0)
0
0
0
(4,0)
4
0
12
(0,6)
0
6
30
(2,6)
2
6
36
The optimal solution is ,
, which gives a maximum
profit of $36,000.
4.2
Using Level Curves to Find the Optimal Solution
Another approach is to use level curves of the
objective function:
Draw the level curve for some value of
Increase until the level
curve is about to leave the feasible region
The last point of contact is the optimal solution
This graphical method helps visualize how the optimal solution is
found, though it becomes impractical for problems with more than two
variables.
4.3
Visualization of the Wyndor Glass Problem
Let’s visualize the solution to better understand the constraints and
optimal point:
Code
import matplotlib.pyplot as pltimport numpy as np# Create a new figure with a specific size for better visibilityplt.figure(figsize=(7, 6))# Define the range for x and y axesx_range = np.linspace(0, 6, 100)y_range = np.linspace(0, 9, 100)# Create a meshgrid for contour plottingX, Y = np.meshgrid(x_range, y_range)Z =3* X +5* Y # Objective function: 3x₁ + 5x₂# Plot the constraints# Constraint 1: x₁ ≤ 4 (Plant 1)plt.axvline(x=4, color='red', linestyle='-', linewidth=2, label='Plant 1: x₁ ≤ 4')# Constraint 2: x₂ ≤ 6 (Plant 2)plt.axhline(y=6, color='green', linestyle='-', linewidth=2, label='Plant 2: x₂ ≤ 6')# Constraint 3: 3x₁ + 2x₂ ≤ 18 (Plant 3)# Convert to y = mx + b form: y ≤ (18 - 3x₁)/2 = 9 - 1.5x₁constraint3_y =lambda x: (18-3* x) /2plt.plot(x_range, [constraint3_y(x) for x in x_range], 'blue', linestyle='-', linewidth=2, label='Plant 3: 3x₁ + 2x₂ ≤ 18')# Non-negativity constraintsplt.axhline(y=0, color='black', linestyle='-', linewidth=1.5)plt.axvline(x=0, color='black', linestyle='-', linewidth=1.5)# Define the vertices of the feasible regionfeasible_region_x = [0, 0, 2, 4, 4]feasible_region_y = [0, 6, 6, 3, 0]# Shade the feasible regionplt.fill(feasible_region_x, feasible_region_y, color='gray', alpha=0.2, label='Feasible Region')# Create contours for the objective functioncontour_levels = np.arange(0, 45, 6) # Levels at 0, 6, 12, 18, 24, 30, 36, 42contour = plt.contour(X, Y, Z, levels=contour_levels, colors='purple', alpha=0.6)plt.clabel(contour, inline=True, fontsize=10, fmt='Z = %1.0f')# Mark the corner points of the feasible region and evaluate the objective function at eachcorner_points = [(0, 0), (0, 6), (2, 6), (4, 3), (4, 0)]corner_values = [3*x +5*y for x, y in corner_points]for i, point inenumerate(corner_points): x, y = point value = corner_values[i] plt.plot(x, y, 'ko', markersize=8) # Black dots for corner points# Add labels for each corner point with its coordinates and objective valueif point != (2, 6): # Skip the optimal point as we'll label it differently plt.annotate(f'({x}, {y}): Z = {value}', xy=point, xytext=(x+0.2, y+0.2), fontsize=10, arrowprops=dict(arrowstyle='->'))# Highlight the optimal solutionplt.plot(2, 6, 'ro', markersize=12) # Red dot for optimal solutionplt.annotate(f'Optimal Solution (2, 6): Z = 36', xy=(2, 6), xytext=(2.5, 7), fontsize=12, fontweight='bold', color='red', arrowprops=dict(facecolor='red', shrink=0.05))# Add axis labels and a titleplt.xlabel('x₁ (Product 1: Doors)', fontsize=12)plt.ylabel('x₂ (Product 2: Windows)', fontsize=12)plt.title('Wyndor Glass Company Linear Programming Problem', fontsize=14, fontweight='bold')# Set the axis limits with some marginplt.xlim(-0.5, 6)plt.ylim(-0.5, 9)# Add a grid for better readabilityplt.grid(True, linestyle='--', alpha=0.6)# Add a legendplt.legend(loc='upper right', fontsize=10)# Add a text box explaining the problemtextbox_text = ("Wyndor Glass Company Problem:\n""Maximize Z = 3x₁ + 5x₂\n""Subject to:\n"" x₁ ≤ 4 (Plant 1)\n"" x₂ ≤ 6 (Plant 2)\n"" 3x₁ + 2x₂ ≤ 18 (Plant 3)\n"" x₁, x₂ ≥ 0")plt.figtext(0.15, 0.02, textbox_text, fontsize=10, bbox=dict(facecolor='white', alpha=0.7, boxstyle='round,pad=0.5'))# Make the layout tightplt.tight_layout()plt.show()
5 Special
Cases in Linear Programming
Linear programming problems can sometimes have special cases:
5.1
Infeasible Solution
If the constraints are contradictory, there’s no feasible region, and
the problem has no solution.
Example: If we added a constraint to the Wyndor problem, it would conflict with our
other constraints, making the problem infeasible.
5.2
Multiple Optimal Solutions
If the objective function is parallel to one of the constraint
boundaries, there could be infinitely many optimal solutions along that
boundary.
Example: If the Wyndor objective function were (instead of ), there might be multiple
optimal solutions.
5.3
Unbounded Solution
If the feasible region extends infinitely in the direction of
improvement for the objective function, the problem is unbounded.
Example: If we removed the Plant 3 constraint from the Wyndor
problem, the profit could increase without limit by producing more of
Product 2.
6 Solving
LP with Excel Solver
While graphical methods are educational, real-world problems
typically have many variables and constraints. We need computational
tools like Excel Solver.
6.1
Setting Up the Wyndor Glass Problem in Excel
Create a spreadsheet with cells for:
Decision variables ( and
)
Objective function calculation
Left-hand side of each constraint
Right-hand side of each constraint
Set up the Excel Solver:
Go to Data tab → Solver
Set Objective: Cell containing the objective function value
By Changing Variable Cells: Cells containing and
Subject to the Constraints: Add each constraint
Select “Simplex LP” as the solving method
Click Solve and review the solution
Excel Solver will find:
,
Maximum profit = $36,000
6.2
Sensitivity Analysis in Excel Solver
Excel Solver also provides sensitivity analysis, showing how changes
in parameters affect the optimal solution:
After solving, click on “Sensitivity Report”
This shows:
Shadow prices (dual values) for constraints
Allowable increases/decreases for coefficients
For example, we can answer questions like:
What if the profit of Product 2 decreases to $3,000?
What if Plant 3 capacity increases by 2 hours?
7 Solving
LP with Python and Gurobi
For more complex problems or when integrating optimization into
larger systems, Python with the Gurobi solver provides a powerful
alternative.
7.1
Setting Up the Wyndor Glass Problem in Python
Here’s how to formulate and solve the Wyndor Glass problem using
Gurobi in Python:
Gurobi Optimizer version 12.0.1 build v12.0.1rc0 (win64 - Windows 11.0 (26100.2))
CPU model: 13th Gen Intel(R) Core(TM) i9-13900H, instruction set [SSE2|AVX|AVX2]
Thread count: 14 physical cores, 20 logical processors, using up to 20 threads
Optimize a model with 3 rows, 2 columns and 4 nonzeros
Model fingerprint: 0xc030cf3a
Coefficient statistics:
Matrix range [1e+00, 3e+00]
Objective range [3e+00, 5e+00]
Bounds range [0e+00, 0e+00]
RHS range [4e+00, 2e+01]
Presolve removed 2 rows and 0 columns
Presolve time: 0.00s
Presolved: 1 rows, 2 columns, 2 nonzeros
Iteration Objective Primal Inf. Dual Inf. Time
0 4.5000000e+01 1.500000e+00 0.000000e+00 0s
1 3.6000000e+01 0.000000e+00 0.000000e+00 0s
Solved in 1 iterations and 0.01 seconds (0.00 work units)
Optimal objective 3.600000000e+01
Optimal solution found:
X1 = 2.00, X2 = 6.00
Optimal profit = $36000.00
This code:
Creates a Gurobi model
Adds decision variables with lower bounds of 0
Sets the objective function to maximize profit
Adds the three plant constraints
Solves the model and prints the results
The solution will match what we found graphically and with Excel
Solver: , , with a profit of $36,000.
7.2
Sensitivity Analysis with Gurobi
We can also perform sensitivity analysis with Gurobi:
# Get shadow prices (dual values)for constr in model.getConstrs():print(f"{constr.ConstrName}: Shadow Price = {constr.Pi}")# Get reduced costsfor var in model.getVars():print(f"{var.VarName}: Reduced Cost = {var.RC}")
Gurobi Optimizer version 12.0.1 build v12.0.1rc0 (win64 - Windows 11.0 (26100.2))
CPU model: 13th Gen Intel(R) Core(TM) i9-13900H, instruction set [SSE2|AVX|AVX2]
Thread count: 14 physical cores, 20 logical processors, using up to 20 threads
Optimize a model with 3 rows, 2 columns and 4 nonzeros
Model fingerprint: 0xbc523b33
Coefficient statistics:
Matrix range [1e+00, 2e+01]
Objective range [8e+01, 1e+02]
Bounds range [0e+00, 0e+00]
RHS range [1e+01, 5e+02]
Presolve removed 3 rows and 2 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Iteration Objective Primal Inf. Dual Inf. Time
0 3.2000000e+03 0.000000e+00 0.000000e+00 0s
Solved in 0 iterations and 0.01 seconds (0.00 work units)
Optimal objective 3.200000000e+03
Optimal solution found:
X1 = 20.00, X2 = 10.00
Optimal profit = $3200.00
8.4
Visualization of the Apex Television Problem
Let’s visualize the solution to better understand the constraints and
optimal point:
Linear Programming is a powerful optimization technique with wide
applications in supply chain management and operations. These skills
provide a foundation for more advanced optimization models that we’ll
explore in future modules, including network flow models, facility
location problems, and integer programming.
10
Exercises
10.1
Production Planning
A manufacturing plant produces two types of products: standard and
deluxe. Each standard product requires 4 hours of machining time and 2
hours of assembly time. Each deluxe product requires 6 hours of
machining time and 3 hours of assembly time. The plant has 240 hours of
machining time and 120 hours of assembly time available per week. The
profit is $7 per standard product and $10 per deluxe product.
Formulate this as an LP model and solve it using both Excel Solver
and Python with Gurobi to determine the optimal production levels.