| name | pulp-3-3-0 |
| description | Complete toolkit for PuLP 3.3.0, a Python linear and mixed-integer programming modeler generating MPS/LP/JSON files and calling solvers like CBC, GLPK, CPLEX, Gurobi, HiGHS, and SCIP. Use when formulating optimization problems in Python, solving LP/MIP models, configuring solver backends, or performing model export/import. |
PuLP 3.3.0
Overview
PuLP is a linear and mixed-integer programming modeler written in Python. It enables developers to formulate optimization problems as mathematical models, then call external solvers (CBC, GLPK, CPLEX, Gurobi, MOSEK, HiGHS, COPT, SCIP, XPRESS, CHOCO, MIPCL, and others) to find optimal solutions. PuLP generates intermediate MPS or LP files and handles solver communication transparently.
Version 3.3.0 includes a Rust extension (pulp._rustcore) that implements the core model, variables, constraints, and affine expressions for improved performance. CBC is no longer bundled — install it separately via pulp[cbc] or place cbc/cbc.exe on your PATH.
PuLP requires Python 3.9 or newer. It supports Windows, macOS (x86_64, arm64), and Linux (x86_64, arm64).
When to Use
- Formulating linear programming (LP) or mixed-integer programming (MIP) models in Python
- Solving blending, transportation, assignment, scheduling, cutting stock, set partitioning, and production planning problems
- Building models with large numbers of indexed variables using dictionary/matrix patterns
- Exporting models to LP, MPS, or JSON format for external solver use
- Performing column generation, two-stage stochastic programming, or constraint-based feasibility problems (e.g., Sudoku)
- Configuring and switching between multiple solver backends (CBC, GLPK, CPLEX, Gurobi, HiGHS, etc.)
Core Concepts
LpProblem — The central model container. Created with a name and sense (LpMinimize or LpMaximize). Holds variables, the objective function, and constraints.
LpVariable — Decision variables. Three categories: LpContinuous (default), LpInteger, and LpBinary. Each has a name, optional lower/upper bounds, and a category.
Objective Function — A linear expression added to the problem with +=. Defines what to minimize or maximize.
Constraints — Linear expressions ending in <=, >=, or ==. Added to the problem with += along with an optional name string.
lpSum() — Efficiently sums a list of linear expressions or variables. Preferred over Python's built-in sum() for PuLP expressions.
LpVariable.dicts() / LpVariable.matrix() — Factory methods that create indexed dictionaries or matrices of variables, essential for problems with many decision variables.
Solver — External optimization engine (CBC, GLPK, CPLEX, Gurobi, etc.). PuLP communicates via command-line (_CMD) or Python API interfaces. prob.solve() uses the default available solver.
Installation / Setup
Install from PyPI (recommended with CBC):
python -m pip install "pulp[cbc]"
uv pip install "pulp[cbc]"
The [cbc] extra installs the cbcbox package, which bundles a CBC binary that PuLP resolves automatically. Without it, you must provide your own cbc on PATH or use another solver.
Building from source requires Rust (latest stable) and uses maturin for the Rust extension:
uv venv
uv pip install --group dev -e ".[cbc]"
python -m pip install -e ".[cbc]"
Usage Examples
Basic LP — Minimization
from pulp import *
prob = LpProblem("test1", LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob.writeLP("test1.lp")
prob.solve()
print("Status:", LpStatus[prob.status])
for v in prob.variables():
print(v.name, "=", v.varValue)
print("objective =", value(prob.objective))
Blending Problem — Whiskas Cat Food
Minimize ingredient cost while meeting nutritional requirements:
from pulp import *
Ingredients = ["CHICKEN", "BEEF", "MUTTON", "RICE", "WHEAT", "GEL"]
costs = {"CHICKEN": 0.013, "BEEF": 0.008, "MUTTON": 0.010,
"RICE": 0.002, "WHEAT": 0.005, "GEL": 0.001}
proteinPercent = {"CHICKEN": 0.100, "BEEF": 0.200, "MUTTON": 0.150,
"RICE": 0.000, "WHEAT": 0.040, "GEL": 0.000}
fatPercent = {"CHICKEN": 0.080, "BEEF": 0.100, "MUTTON": 0.110,
"RICE": 0.010, "WHEAT": 0.010, "GEL": 0.000}
ingredient_vars = LpVariable.dicts("Ingr", Ingredients, 0)
prob = LpProblem("Whiskas", LpMinimize)
prob += lpSum([costs[i] * ingredient_vars[i] for i in Ingredients])
prob += lpSum([ingredient_vars[i] for i Ingredients]) ==
prob += lpSum([proteinPercent[i] * ingredient_vars[i] i Ingredients]) >=
prob += lpSum([fatPercent[i] * ingredient_vars[i] i Ingredients]) >=
prob.solve()
(, LpStatus[prob.status])
v prob.variables():
(v.name, , v.varValue)
Transportation Problem — Beer Distribution
Ship crates from warehouses to bars at minimum cost:
from pulp import *
Warehouses = ["A", "B"]
supply = {"A": 1000, "B": 4000}
Bars = ["1", "2", "3", "4", "5"]
demand = {"1": 500, "2": 900, "3": 1800, "4": 200, "5": 700}
costs = [
[2, 4, 5, 2, 1],
[3, 1, 3, 2, 3],
]
costs_dict = makeDict([Warehouses, Bars], costs, 0)
prob = LpProblem("Beer Distribution", LpMinimize)
Routes = [(w, b) for w in Warehouses for b in Bars]
vars = LpVariable.dicts("Route", (Warehouses, Bars), 0, None, LpInteger)
prob += lpSum([vars[w][b] * costs_dict[w][b] for (w, b) in Routes])
for w in Warehouses:
prob += lpSum([[w][b] b Bars]) <= supply[w]
b Bars:
prob += lpSum([[w][b] w Warehouses]) >= demand[b]
prob.solve()
(, LpStatus[prob.status])
Sudoku as a Feasibility Problem
No objective function needed — just find values satisfying all constraints:
from pulp import *
VALS = ROWS = COLS = range(1, 10)
Boxes = [
[(3*i+k+1, 3*j+l+1) for k in range(3) for l in range(3)]
for i in range(3) for j in range(3)
]
prob = LpProblem("Sudoku")
choices = LpVariable.dicts("Choice", (VALS, ROWS, COLS), cat="Binary")
for r in ROWS:
for c in COLS:
prob += lpSum([choices[v][r][c] for v in VALS]) == 1
for v in VALS:
for r in ROWS:
prob += lpSum([choices[v][r][c] for c in COLS]) == 1
for c in COLS:
prob += lpSum([choices[v][r][c] for r in ROWS]) == 1
for b in Boxes:
prob += lpSum([choices[v][r][c] for (r, c) b]) ==
input_data = [(,,), (,,), (,,), (,,), (,,),
(,,), (,,), (,,)]
v, r, c input_data:
prob += choices[v][r][c] ==
prob.solve()
(, LpStatus[prob.status])
Advanced Topics
Variables and Expressions: LpVariable categories, bounds, LpVariable.dicts(), LpVariable.matrix(), LpAffineExpression, lpSum(), lpDot() → Variables and Expressions
Constraints: LpConstraint, constraint senses, named constraints, dual values (shadow prices), reduced costs → Constraints
Solvers: COIN_CMD (CBC), GLPK_CMD, CPLEX_CMD, GUROBI, HiGHS, MOSEK, SCIP, COPT, XPRESS, CHOCO, solver configuration, environment variables, listSolvers(), getSolver() → Solvers
Model Export and Import: writeLP(), writeMPS(), toJson()/fromJson(), to_dict()/from_dict(), JSON vs MPS trade-offs → Model Export and Import
Utility Functions: makeDict, splitDict, allcombinations, allpermutations, value(), roundSolution() → Utility Functions
Case Studies: Blending, transportation, set partitioning (wedding seating), cutting stock with column generation, two-stage stochastic programming, Sudoku, production planning, generation scheduling → Case Studies