The simplex method
Solve a linear program: start at a corner of the feasible region and move to a neighbouring corner while the objective improves; in exact fractions.
Linear programming: maximize a linear function c·x under linear constraints A·x ≤ b and x ≥ 0. The feasible
region is a polytope, and if there is an optimum, one is at a corner.
- Time:
exponential worst case, fast in practice - Space:
O(m·n) - CLRS, section 29.3
Maximize 3x1 + x2 + 2x3 under three constraints; the answer is 28 at x = (8, 4, 0).
from fractions import Fractiondef simplex(A, b, c):# Maximize c·x subject to A·x ≤ b and x ≥ 0 (with b ≥ 0, so x = 0 is a starting corner).m, n = len(A), len(c[0])# The tableau: [A | I | b] for the constraints, and [−c | 0 | 0] for the objective at the bottom.T = [[Fraction(v) for v in A[i]] + [Fraction(int(i == k)) for k in range(m)] + [Fraction(b[i][0])] for i in range(m)]T.append([Fraction(-v) for v in c[0]] + [Fraction(0)] * (m + 1))basis = [n + i for i in range(m)]while True:# Bland's rule: the first variable whose objective entry is negative enters.col = next((j for j in range(n + m) if T[m][j] < 0), None)if col is None:breakrows = [i for i in range(m) if T[i][col] > 0]if not rows:return Nonerow = min(rows, key=lambda i: (T[i][-1] / T[i][col], basis[i]))pivot = T[row][col]T[row] = [v / pivot for v in T[row]]for i in range(m + 1):if i != row and T[i][col] != 0:f = T[i][col]T[i] = [v - f * w for v, w in zip(T[i], T[row])]basis[row] = colx = [Fraction(0)] * nfor i, var in enumerate(basis):if var < n:x[var] = T[i][-1]return str(T[m][-1]), [str(v) for v in x]
Start
The table is still empty.
Local variables
Orange = changed in this step
A list
b list
c list
Call stack
- simplex()line 4
Explanation
The idea
Linear programming: maximize a linear function c·x under linear constraints A·x ≤ b and x ≥ 0. The feasible
region is a polytope, and if there is an optimum, one is at a corner.
Simplex
- Start at the corner
x = 0(feasible sinceb ≥ 0). The slack variables start out in the "basis". - If the objective row has a negative entry, raising that variable pays: it enters the basis.
- The ratio test decides how far we can go and which variable leaves the basis.
- Pivoting (like Gaussian elimination) rewrites the tableau for the new corner.
- When no negative entry is left, the corner is optimal.
Bland's rule (always the first negative column) prevents endless cycling.
Cost
Exponential in the worst case, but very fast in practice, and still the most widely used method.
What to watch in the trace
- Look at the
Ttable after each pivot; the last column holds the basic variables' values and the bottom-right corner the objective's value.