Lagrangian duality
Form the dual problem, prove weak duality, and state when strong duality holds.
Every constrained minimization has a shadow problem, its dual, built from the Lagrangian. The dual is always a concave maximization (even when the original is not convex), it always lower-bounds the original, and for convex problems the two have the same optimal value. This is the theory behind SVM solvers and the certificates that prove a solution optimal.
The primal and the Lagrangian
The primal problem, now with inequality constraints, is
The Lagrangian attaches a multiplier to each constraint, with for inequalities and free for equalities:
The dual function
The Lagrange dual function minimizes the Lagrangian over for fixed multipliers:
It is a pointwise minimum of functions that are affine in , and a pointwise minimum of affine functions is concave. So is concave regardless of whether or the constraints are convex, which is why the dual is always a well-behaved maximization.
Weak duality
Theorem. For any and any , [1].
Proof. Let be any feasible point for the primal, so and . With , the term and , hence
Minimizing the left side over all only decreases it, so for every feasible , and in particular .
The dual problem and the duality gap
The best (largest) lower bound is the dual problem:
Weak duality says always. The difference is the duality gap. Any dual-feasible produces a certified lower bound on the primal optimum, a way to bound how suboptimal a candidate solution is.
Strong duality
Strong duality holds when (zero gap). It is not automatic, but for convex primal problems it holds under a mild condition.
Slater's condition: if the primal is convex and there exists a strictly feasible point (some with for all inequality constraints), then strong duality holds. Most convex problems met in practice (linear programs, convex QPs, SVMs) satisfy Slater, so their dual solves the primal exactly[2]. When strong duality holds, the primal and dual solutions are linked by the KKT conditions of the next lesson.
Check it on arrays
import numpy as np
# Convex QP: min 0.5 x^T x s.t. a^T x >= 1 (i.e. g(x) = 1 - a^T x <= 0)
a = np.array([1.0, 2.0])
# Dual function: D(lam) = min_x 0.5 x^T x + lam (1 - a^T x), lam >= 0.
# Inner min at x = lam a, giving D(lam) = lam - 0.5 lam^2 ||a||^2.
# Maximize over lam >= 0: lam* = 1/||a||^2, d* = 1/(2||a||^2).
norm2 = a @ a
lam_star = 1.0 / norm2
d_star = lam_star - 0.5 * lam_star**2 * norm2
print("dual optimum d* =", round(d_star, 6))
# Primal optimum: closest point to origin on the half-space a^T x >= 1
# is x* = a / ||a||^2, with f = 0.5 / ||a||^2.
x_star = a / norm2
p_star = 0.5 * x_star @ x_star
print("primal optimum p* =", round(p_star, 6))
print("duality gap:", round(p_star - d_star, 8), " (zero -> strong duality)")
# Weak duality: any lam >= 0 gives a valid lower bound
for lam in [0.05, 0.1, 0.2, 0.5]:
D = lam - 0.5 * lam**2 * norm2
print(f"lam={lam}: D(lam)={D:.5f} <= p*={p_star:.5f}: {D <= p_star + 1e-12}")The dual and primal optima coincide (zero gap, strong duality via Slater), and every nonnegative multiplier yields a lower bound below the primal optimum.
Exercises
Exercise 1. For the problem subject to (so ) with , derive the dual function in closed form and find .
Solution
Step 1. Write the Lagrangian for :
Step 2. Minimize over . Setting gives the inner minimizer .
Step 3. Substitute back, using :
Step 4. Maximize the concave over . The derivative gives , which is nonnegative. With , and
Exercise 2. Prove weak duality in the form: for the primal optimum and any dual-feasible with , the value is a lower bound on at every primal-feasible point.
Solution
Step 1. Let be primal-feasible, so and . Because and , each product , and the equality terms vanish: .
Step 2. Therefore
Step 3. The dual function minimizes the Lagrangian over all , so it is no larger than this particular value:
This holds for every primal-feasible , so .
Exercise 3 (code). For a linear program subject to , the dual is subject to . Take , , . Solve the primal directly (the constraint forces since ), construct the dual point , and verify weak duality holds with zero gap.
Solution
import numpy as np
c = np.array([1.0, 1.0])
A = np.eye(2)
b = np.array([2.0, 3.0])
# Primal: minimize c^T x s.t. x >= b. With c > 0, push x down to the bound.
x_star = b.copy()
p_star = c @ x_star
# Dual: max b^T y s.t. A^T y = c, y >= 0. Here A^T = I so y = c, and c >= 0.
y = np.linalg.solve(A.T, c)
assert np.all(y >= 0) # dual feasibility
d_star = b @ y
assert np.isclose(p_star, d_star) # zero duality gap
print("p* =", p_star, " d* =", d_star, " gap =", p_star - d_star)The primal optimum and the dual optimum coincide, so the duality gap is zero, as strong duality predicts for a feasible LP.
The next lesson collects the optimality conditions linking primal and dual: the KKT conditions.