Lagrangian#
Consider a convex optimisation problem with inequality constraints:
The Lagrangian combines the objective and the constraints with Lagrange multipliers :
where , (elementwise). The multipliers penalise constraint violations: if , the term adds a positive penalty.
The primal problem can be rewritten as:
If violates any constraint (), the inner max drives by letting . If is feasible (all ), the max over sets each or keeps it at the boundary, recovering . So equals when is feasible and otherwise.
Dual Function#
The Lagrange dual function is obtained by swapping min and max:
For each fixed , is the minimum of an unconstrained (but -parametrised) problem. The domain of is .
The dual problem is to maximise the dual function:
Worked example — 1D quadratic with constraint:
subject to (rewritten as ).
Lagrangian: , .
Dual function: . Set . Substitute: .
Dual problem: . Set derivative to zero: . Dual value: . Primal optimum: , . Duality gap: .
For s.t. , the dual peaks at with — exactly the primal optimum. Weak duality says the dual can never exceed the primal; strong duality makes the two meet and the gap collapse to zero.
Weak and Strong Duality#
Weak duality: For any feasible and any ,
The dual function always lower-bounds the primal objective. Maximising gives the best possible lower bound. The duality gap is always nonnegative.
Strong duality: Under certain conditions, — the duality gap is zero. For convex problems, Slater's condition is sufficient: if there exists a strictly feasible point (all ), then strong duality holds.
In practice, most convex ML problems satisfy Slater's condition trivially. Strong duality means we can solve either the primal or the dual and get the same answer — whichever is easier.
Complementary Slackness#
At the primal-dual optimum with strong duality:
This is complementary slackness. For each constraint:
- If (constraint is inactive/slack), then (the multiplier for that constraint is zero)
- If (the multiplier is active), then (the constraint is tight/binding)
Complementary slackness tells us which constraints matter at the optimum. In the 1D example above: (active), so can be nonzero; indeed .
SVM Dual as Worked Example#
The soft-margin SVMSupport Vector Machine is a canonical ML application of duality. The primal problem:
The Lagrangian introduces multipliers (for the margin constraints) and (for ):
Setting , , gives:
Substituting back, the SVM dual is:
This is a quadratic program in variables with box constraints. The number of variables is now (number of examples) instead of (feature dimension) — a win when .
Kernel trick preview: The dual depends on the data only through inner products . Replacing with a kernel allows SVMs to learn nonlinear decision boundaries without ever computing features in the kernel space explicitly.
Knowledge Check#
If $h_i(x^*) < 0$ (the constraint is inactive) at the optimum, complementary slackness forces:
Weak duality states that the dual objective is always ___ the primal objective for feasible points.
Browser lab: the SVM dual by projected gradient#
Solve a tiny 2D linearly separable SVM via projected gradient on the dual variables . Plot the decision boundary and highlight support vectors.
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(42)
n = 30
X_pos = rng.normal(loc=[2, 2], scale=1.0, size=(n//2, 2))
X_neg = rng.normal(loc=[-2, -2], scale=1.0, size=(n//2, 2))
X = np.vstack([X_pos, X_neg])
y = np.hstack([np.ones(n//2), -np.ones(n//2)])
n = len(y)
C = 1.0
K = X @ X.T
def dual_obj(alpha):
return np.sum(alpha) - 0.5 * np.sum(np.outer(alpha * y, alpha * y) * K)
def dual_grad(alpha):
return 1.0 - (K @ (alpha * y)) * y
alpha = np.zeros(n)
eta = 0.01
for _ in range(2000):
g = dual_grad(alpha)
alpha = alpha + eta * g
alpha = np.clip(alpha, 0, C) * (np.abs(alpha) > 1e-5)
sv_idx = alpha > 1e-3
w_dual = X.T @ (alpha * y)
print(f"Support vectors: {sv_idx.sum()} / {n}")
print(f"Dual objective: {dual_obj(alpha):.4f}")
print(f"w = {np.round(w_dual, 3)}")
print("Notice: projected gradient on the dual recovers a separating boundary, and the points it sits on are the support vectors.")
plt.figure(figsize=(6, 5))
plt.scatter(X_pos[:, 0], X_pos[:, 1], c="tab:blue", alpha=0.6, label="y=+1")
plt.scatter(X_neg[:, 0], X_neg[:, 1], c="tab:red", alpha=0.6, label="y=−1")
plt.scatter(X[sv_idx, 0], X[sv_idx, 1], facecolors="none", edgecolors="black", s=80, linewidths=1.5, label="support vectors")
xx = np.linspace(-5, 5, 100)
yy = -w_dual[0] / w_dual[1] * xx
plt.plot(xx, yy, "k--", label="decision boundary")
plt.xlim(-5, 5); plt.ylim(-5, 5)
plt.xlabel("x1"); plt.ylabel("x2")
plt.title("SVM Dual: Decision Boundary and Support Vectors")
plt.legend(); plt.gca().set_aspect("equal"); plt.show()
Further Reading#
- Stephen Boyd & Lieven Vandenberghe, Convex Optimization (Cambridge University Press, 2004). Chapter 5 is the standard treatment of the Lagrangian, weak/strong duality, and complementary slackness.
- Corinna Cortes & Vladimir Vapnik, "Support-Vector Networks" (Machine Learning, 1995). The soft-margin SVM and the dual problem derived here.
- Bernhard Schölkopf & Alexander Smola, Learning with Kernels (MIT Press, 2001). Chapters 6–7 derive the SVM dual and the kernel trick.