From convex sets to robots, in three weeks · v1.1 (2026-10-26)
A three-week course
Convex optimization, without the fog.
21 lessons of about an hour each. Week 1 shows what makes an optimization problem easy. Week 2 opens up the algorithms inside every solver. Week 3 goes past convexity and into robots and self-driving cars. Plain language, real numbers, interactive widgets, and sources you can check.
Lessons
21 days
Widgets
26 interactive
Library
17 algorithms · 15 papers
How to use this course
One day per sitting. Read the lesson from top to bottom. Each day builds on the one before.
Play with every widget. Each one is a small optimization running in your browser, not a picture.
Take the quiz, then mark the day done. Progress is saved on this device only.
Use the other tabs.Algorithms has one card per method. Papers explains the robotics papers from Week 3. Glossary lets you look up any term.
Open the sources. The small chips after sentences (like this one CO4A) link to the original.
What you need to know first
Some high-school algebra, what a derivative is, and the basics of vectors and matrices: adding them, the dot product, and multiplying a matrix by a vector. You do not need to read proofs. The few you will meet are optional and sit in grey "Going deeper" boxes. Keep this notation table open while you read:
Symbol
Read it as
Example
x ∈ ℝn
x is a list of n real numbers (a vector)
x = (2, −1) is in ℝ2
xTy
dot product: multiply entry by entry, then add
(1,2)T(3,4) = 3 + 8 = 11
‖x‖2, ‖x‖1
length of x; sum of absolute values
‖(3,4)‖2 = 5, ‖(3,−4)‖1 = 7
∇f(x)
gradient: the vector of slopes, which points uphill
f = x12 + 3x2 → ∇f = (2x1, 3)
∇2f(x)
Hessian: the matrix of second derivatives (curvature)
f = x12 + 3x22 → diag(2, 6)
A ⪰ 0
A is positive semidefinite: xTAx ≥ 0 for every x
diag(2, 6) ⪰ 0
min f(x) s.t. …
"make f as small as possible, subject to (s.t.) these rules"
After today you can say what an optimization problem is, tell a convex problem from a nonconvex one, and explain why 'every local minimum is global' makes convex problems easy to solve.
About 60 min · No prerequisites · CO4A chapter 1
Today's big idea
An optimization problem asks for the best choice that obeys some rules. In general, a search can stall in a dip that is not the deepest one. Convex problems have no such false dips: a point that no small step can improve is the best point anywhere, so computers can solve them reliably.
1. Knobs, a score, and rules
Every optimization problem has the same three parts. Think of planning a drive home. You choose the turns, you want the trip to be short, and you must obey the one-way streets.
The things you choose are the optimization variables. We stack them into one vector x = (x1, …, xn) in ℝn. The score you want small is the objective function f(x), also called the cost. The rules are the constraints.
A point that obeys every rule is called feasible. The set of all feasible points is the feasible set. Written out, every problem in this course has the same shape. "s.t." is short for "subject to". CO4A 1-1CMU 10-725 2016
minimize f(x) s.t. gi(x) ≤ 0, i = 1, …, m hj(x) = 0, j = 1, …, r
Each gi is an inequality constraint ("at most"). Each hj is an equality constraint ("exactly"). Any rule can be moved into this form. For example, x ≤ 1 becomes g(x) = x − 1 ≤ 0.
The best score you can reach is the optimal value, written p*. A feasible point that reaches it is an optimal solution, or minimizer, written x*. Keep the two apart: p* is a number, and x* is a point.
Here is a problem with one knob. Minimize (x − 2)2 subject to x ≤ 1. Without the rule, the best choice would be x = 2, with a score of 0. The rule forbids it, so the best allowed point sits on the edge: x* = 1, with p* = (1 − 2)2 = 1.
The three parts in one picture. The knob is x, the score is the blue curve, and the rule x ≤ 1 keeps you in the green strip. The lowest point of the curve, x = 2, is not allowed, so the answer is the lowest allowed point, x* = 1.
Some rules are not written down at all. They hide inside the formula. Take the problem: minimize f(x) = x − log x. The logarithm only exists for x > 0, so x > 0 is a hidden rule, called an implicit constraint. Setting the slope f′(x) = 1 − 1/x to zero gives x* = 1 and p* = 1 − log 1 = 1. CO4A 1-1
A problem with no written-down constraints is an unconstrained problem. The example above counts as unconstrained, even though it hides the rule x > 0.
In practice you describe the three parts to a modelling tool and let a solver do the rest. Here is the one-knob problem in CVXPY, a free Python library. Day 4 explains how it checks that a problem is convex before it solves it.
import cvxpy as cp
x = cp.Variable() # the knob
objective = cp.Minimize(cp.square(x - 2)) # the score
constraints = [x <= 1] # the rule
problem = cp.Problem(objective, constraints)
problem.solve()
print(x.value, problem.value) # about 1.0 and 1.0
2. Optimization is everywhere
Once you look for knobs, a score and rules, you find optimization problems everywhere. The table lists some from daily life, driving, robotics and machine learning. The last column previews today's main question: is the problem convex? Sections 3 and 4 explain how to tell.
Fitting a line. Suppose you measure three points: (0, 1), (1, 3) and (2, 4). You want the line y = ax + b that passes closest to them. The score adds up the squared vertical misses:
f(a, b) = (b − 1)² + (a + b − 3)² + (2a + b − 4)²
This score is a bowl over the two knobs a and b. Its lowest point is a = 1.5 and b ≈ 1.17, where the total squared miss is 0.167. Every "least squares" fit in statistics and machine learning is a bigger version of this bowl. Day 6 shows gradient descent finding its bottom.
Planning a car's speed. A self-driving car re-plans its speed many times a second. The knobs are its speeds over the next few seconds. The score adds up how hard it brakes and accelerates, so the ride stays smooth. The rules keep it under the speed limit and a safe distance behind the car ahead.
Distance travelled is a sum of speed × time, so "stay 10 m behind the car ahead" is a linear rule in the speeds. With linear rules and a squared score, the problem is convex. It is called a quadratic program, and Day 17 builds one step by step. Boyd and Vandenberghe's course slides say that convex solvers generated as code now run in milliseconds, and cite the landing of SpaceX's Falcon 9 rocket. Boyd EE364a slides
A robot arm, which is not convex. Picture an arm with two links, each 1 m long, trying to touch the point (1, 1). Two poses reach it exactly. "Elbow down" puts the shoulder at 0° and bends the elbow 90°. "Elbow up" puts the shoulder at 90° and bends the elbow −90°.
Now blend the two answers. The halfway pose has the shoulder at 45° and a straight elbow (0°). It puts the hand at (1.41, 1.41), which misses the target by 0.59 m. Two perfect answers, and the point halfway between them is bad. Section 4 shows that this cannot happen in a convex problem.
Machine learning. Training a model means choosing its weights to make the average error on the data small. For linear regression and logistic regression this problem is convex. Boyd & Vandenberghe 2004 For a deep neural network it is not, which is one reason training one needs careful starting points and tuning. Day 16 and Day 20 come back to this.
3. Convex sets and convex functions, one picture each
Two shapes carry the whole subject. Today you only need a rough picture of each. Day 2 and Day 3 treat them properly.
A set with no dents. Pick any two points inside a shape and draw the straight path between them. If the path never leaves the shape, whichever two points you pick, the shape is a convex set. A disk passes. A crescent moon fails, because the path between its two tips cuts across the empty bite.
To write "every point on the path", blend the two points x and y with a weight θ between 0 and 1. θ = 1 gives x, θ = 0 gives y, and θ = 0.5 gives the midpoint. Such a weighted average is called a convex combination. A set C is convex when CO4A 1-2
x, y ∈ C and θ ∈ [0, 1] ⇒ θx + (1 − θ)y ∈ C
A number check. The halfspace of points (p, q) with p + 2q ≤ 4 contains x = (0, 0) and y = (4, 0). With θ = 0.25 the blend is 0.25·(0, 0) + 0.75·(4, 0) = (3, 0). Since 3 + 2·0 = 3 ≤ 4, the blend is inside too.
A function shaped like a bowl. Stretch a string between any two points on the graph of a function. If the string never dips below the graph, the function is a convex function. On a bumpy curve, some strings pass under a hump.
f(θx + (1 − θ)y) ≤ θf(x) + (1 − θ)f(y)
The left side is the height of the graph at the blended point. The right side is the height of the string there. Take f(x) = x2, x = −1, y = 3 and θ = 0.5. The blended point is 1, where the graph has height f(1) = 1. The string has height (1 + 9)/2 = 5 there. Since 1 ≤ 5, the string is above the graph, by 4.
The string test. Left: on the bowl x², the string from x = −1 to x = 3 runs above the curve, here by 4 at x = 1. Right: on the bumpy curve, the string between the two dips (x = −1.473 and x = 1.347) runs under the hump. At x = 0.126 the curve is at 0.063 but the string is at −3.84, so g is not convex. The widget in section 5 rolls a ball on this same curve.
The two ideas are linked. Paint everything on or above the graph of f. That painted region is the epigraph of f. A function is convex exactly when its epigraph is a convex set. CO4A 1-2Boyd & Vandenberghe 2004
Check it on f(x) = |x|. The points (−1, 1) and (1, 1) lie on its graph. Their midpoint (0, 1) has height 1, which is above |0| = 0, so it lies inside the painted region, as convexity requires.
4. What makes a problem convex
Now put the pieces together. A convex optimization problem needs three things. The objective f is a convex function. Each inequality function gi is convex. Each equality function hj is affine, meaning flat: hj(x) = ajTx + bj, a linear part plus a constant. CO4A 1-2CMU 10-725 2016
Why these rules? A convex gi is a bowl, and the region where it is at most 0 is the part of the bowl under the water line: a convex blob. A flat hj makes the region where it equals 0 a flat line or plane. Overlapping convex pieces gives a convex feasible set (Day 2 shows why). A bowl-shaped score over a convex feasible set is the whole recipe.
Example A, convex. Minimize x2 subject to 1 − x ≤ 0, which means x ≥ 1. The objective is a bowl and the rule is flat. The feasible set is the ray [1, ∞), with no gaps. The answer is x* = 1 with p* = 1.
Example B, not convex. Minimize x2 subject to x2 − 1 = 0. The equality is curved, not flat. Its feasible set is just two points, −1 and 1. The path between them runs through 0, which is not allowed.
Example C, not convex. Minimize x2 subject to x2 ≥ 1, written as 1 − x2 ≤ 0. Here g(x) = 1 − x2 is an upside-down bowl. Its feasible set, everything outside (−1, 1), has a gap in the middle.
The feasible sets of examples A, B and C, drawn in green. A is one unbroken ray. In B and C the midpoint of two feasible points (the red ring at 0) is not feasible, so the segment test fails and the problem is not convex.
Two more facts. Maximizing a concave function, an upside-down bowl, is also a convex problem, because it is the same as minimizing its negative. And modelling tools check the rules before solving. CVXPY raises an error if you ask it to solve example B, because "x² == 1" is not an affine equality. CVXPY docs
The robot arm from section 2 fails for the same kind of reason. In a convex problem, the set of best points is itself convex, so the blend of two best answers is also a best answer. The arm's two perfect poses blend into a pose that misses by 0.59 m, so its problem cannot be convex.
5. The payoff: every local minimum is global
Imagine a hiker in thick fog who wants the lowest point of a valley. She can only feel the ground under her boots. She steps downhill until every direction goes up, and then she stops.
Where she stops is a local minimum: no nearby point is lower. What she wants is a global minimum: no point anywhere is lower. In mountains these can differ, and she may stop in a small hollow high on a slope.
On a convex bowl they cannot differ. There is only one valley, so "nothing nearby is lower" already means "nothing anywhere is lower". This is the most useful fact in the course: CMU 10-725 2016Boyd & Vandenberghe 2004
if f(x) ≤ f(y) for every feasible y with ‖y − x‖2 ≤ ρ, then f(x) ≤ f(y) for every feasible y
Here x is a feasible point, ρ > 0 is the radius of "nearby", and ‖y − x‖2 is the ordinary straight-line distance. The reason fits in one line. If a better point y existed far away, a short step from x toward y would already be better, because the string to y lies above the bowl. The box at the end of this section works it through with numbers.
For a smooth function with no constraints, the test gets even simpler. If f is convex and differentiable, then ∇f(x) = 0 holds exactly at the global minimizers. CMU 10-725 2016 For f(x) = (x − 1)2, setting f′(x) = 2(x − 1) to zero gives x = 1, and that is the bottom of the bowl.
The simplest computer version of the hiker is gradient descent. It repeats one move: step against the slope, scaled by a step size η (the Greek letter eta). See the gradient descent card for more.
xk+1 = xk − η f′(xk)
Run it on f(x) = (x − 1)2 with η = 0.1, starting at x0 = 2. The slope there is 2, so x1 = 2 − 0.1·2 = 1.8. Each step shrinks the distance to the bottom by a factor of 0.8. After 21 steps the ball is within 0.01 of x = 1.
Try it: tap either curve to start both balls there and watch them roll, or set x0 with the slider and press Roll. Both balls use the same rule from the same start. Then move x0 left of 0.13 and roll again. Finally, push the bowl's step size above 1.
Notice: from the default start x0 = 2.00, the bowl's ball settles at x = 1.000 after 66 steps. The bumpy ball settles after 48 steps at x = 1.347, where g = −2.619. That is only a local minimum. The global minimum, g = −5.444 at x = −1.473, lies beyond the hilltop at x ≈ 0.126, and the ball never sees it.
Analogy
Drop a marble anywhere in a salad bowl and it ends at the same bottom. Drop it into an egg carton and it ends in whichever cup is nearest, deep or shallow. Convex problems are salad bowls. Many real problems are egg cartons, and a marble cannot tell which cup is deepest.
Going deeper (optional): why local means global, with numbers
Take f(x) = (x − 1)2 and suppose someone claims x = 3 is a local minimum, with "nearby" meaning within ρ = 0.5. A better point exists: y = 1, with f(1) = 0 < f(3) = 4.
Step a little from x toward y, by θ = ρ / (2‖y − x‖2) = 0.5/4 = 0.125. That gives z = 3 + 0.125·(1 − 3) = 2.75, which is 0.25 from x, so it counts as nearby. The string inequality says f(z) ≤ 0.125·f(1) + 0.875·f(3) = 3.5, which is less than f(3) = 4. (Indeed f(2.75) = 3.0625.) A nearby point beats x, so the claim was false.
The same steps work for any convex problem. The feasible set is convex, so z is feasible, and the string inequality makes z better than x. The full proof is in Boyd & Vandenberghe §4.2.2. Boyd & Vandenberghe 2004
6. Why convex problems are the "easy" ones
Most algorithms are like the hiker. They only look at the ground near the current point. On a nonconvex problem that local view can mislead them, as the bumpy ball showed.
Boyd and Vandenberghe put it bluntly. For general nonlinear problems there is no effective general method, and even some problems with about ten variables are very hard. Boyd & Vandenberghe 2004
The usual fallback is local optimization: start somewhere, go downhill, and hope. It needs a good starting guess and some tuning. It also cannot tell you how far you are from the true best. The book calls it "more art than technology". Global search does find the true best, but its worst-case cost grows exponentially with the number of variables.
Convex problems escape this trap. Usually there is no formula for the answer. But interior-point methods solve them reliably, almost always in 10 to 100 iterations. In the book's words, once you have formulated a problem as convex, solving it is "(almost) technology". Boyd & Vandenberghe 2004Day 12 opens up these methods.
So the hard part moves from solving to formulating. Your job is to recognise, or rewrite, a problem as convex. That skill is what Week 1 trains.
This also corrects an old rule of thumb, "linear is easy, nonlinear is hard". The better dividing line is convex versus nonconvex. A curved bowl is just as easy as a flat plane, and only the bumps make problems hard. Boyd EE364a slidesCMU 10-725 2016
Convex does not mean any method will do, though. Tibshirani's first lecture cleans up a noisy image by solving one convex problem with three methods. A specialised ADMM needed 20 iterations, proximal gradient needed 1,000, and coordinate descent needed 10,000 cycles. CMU 10-725 2016CO4A 1-3
The lesson is not "ADMM is best". ADMM won here because its steps matched the problem's structure. On another problem a different method wins. Choosing the method is the theme of Week 2.
Karmarkar's interior-point method solves linear programs in polynomial time.
1994
Nesterov and Nemirovski extend such methods to general convex problems.
1990 onward
Use spreads to control, signal processing and circuit design; since the 2000s, machine learning, statistics and finance.
7. The road ahead
The course has three weeks. Week 1 teaches you to recognise convex problems: convex sets (Day 2), convex functions (Day 3), convex problems (Day 4), and the standard families from linear programs up to semidefinite programs (Day 5). Week 2 opens up the solvers. You will meet gradient descent, subgradients, proximal methods, duality, the KKT conditions, Newton's method, interior-point methods, ADMM, Frank–Wolfe and coordinate descent (Days 6–14). Week 3 leaves the safe bowl. It covers yes-or-no decisions, general nonlinear problems, and robots and cars: model predictive control, trajectory optimization, collision avoidance, safety filters, and solvers in practice (Days 15–21).
Explain it to a 10-year-old
You are in a dark room and want to put a ball at the lowest spot on the floor. You can't see, but you can feel which way the floor tilts. If the floor is shaped like one big bowl, just keep walking downhill and you will reach the bottom for sure. If the floor has lots of little dips, you might stop in a small one and never know a deeper one is across the room.
Common misunderstandings
"Convex means exactly one minimizer." No. Convexity says every local minimizer is global, not that there is only one. f(x) = max(0, |x| − 1) is convex, and every x in [−1, 1] is a minimizer. Uniqueness needs strict convexity (Day 3).
"A convex problem has a formula for its answer." Usually not. What it has is algorithms that reliably find the answer. Boyd & Vandenberghe 2004
"Smooth equality constraints are fine." No. Equalities must be affine. The smooth rule x2 = 1 already breaks convexity, leaving only the two points −1 and 1.
"Convex means any step size works." No. On f(x) = (x − 1)2, gradient descent with η = 1.05 from x0 = −2.2 reaches x = −7.30 after 10 steps, moving away from the answer. Convexity removes false valleys; it does not fix a bad step size.
"Zero slope means I found the answer." Only for convex problems. On the bumpy curve the slope is also zero at the local minimum x ≈ 1.347 and at the hilltop x ≈ 0.126.
Check yourself
Q1. Which of these is a convex optimization problem?
(x − 2)² is a bowl and x ≤ 1 is flat, so it is convex (answer x* = 1). x² = 1 is a curved equality. −x² is an upside-down bowl, and minimizing it is not convex. x² ≥ 1 leaves a gap in the feasible set.
Q2. In a convex problem, each equality constraint h(x) = 0 must have h…
An equality must be flat. "Convex" sounds right but is not enough: h(x) = x² − 1 is convex, yet h(x) = 0 leaves only the two points −1 and 1.
Q3. Why does "every local minimum is global" matter in practice?
Local methods only see nearby points, and convexity guarantees that what they find is the true best. It does not promise a unique minimizer (max(0, |x| − 1) has many), a formula, or safety from big steps.
Q4. Gradient descent on g(x) = x⁴ − 4x² + x, started at x0 = 1 with η = 0.02, ends near…
x0 = 1 is right of the hilltop at 0.126, so the ball rolls into the right-hand dip and stops at 1.347. The deeper dip at −1.473 (g ≈ −5.44) is never reached. Set x0 = 1 in the widget to watch it.
Q5. A two-link arm reaches a target exactly in two poses, but the pose halfway between them misses by 0.59 m. What does this show?
In a convex problem the set of minimizers is convex, so the blend of two minimizers is also a minimizer. Here it misses by 0.59 m. The arm is long enough, since both poses reach the target exactly.
Q6. According to Boyd and Vandenberghe, what is usually the hard part of convex optimization?
Once a problem is written in convex form, solving it is "(almost) technology". Starting points and local-versus-global worries are what make nonconvex problems hard.
Recap: things to remember
An optimization problem has variables (knobs), an objective (score) and constraints (rules). x* is the best point, and p* is the best score.
A problem is convex when the objective and each "≤" function are convex and each "=" function is affine.
In a convex problem every local minimum is global. With no constraints and a smooth f, ∇f(x) = 0 is enough.
Nonconvex problems can trap local methods. On the bumpy curve, starts right of x ≈ 0.126 stop at g ≈ −2.62, not at −5.44.
The real dividing line is convex versus nonconvex, not linear versus nonlinear. Formulating is the hard part, and the choice of algorithm still matters.
After today you can recognise convex sets (lines, halfspaces, balls, polyhedra, cones, the PSD cone), build new ones with convexity-preserving operations, and explain what separating and supporting hyperplanes guarantee.
About 60 min · Needs Day 1 · CO4A chapter 2
Today's big idea
A set is convex when the straight segment between any two of its points stays inside it. A few basic shapes pass this test: lines, halfspaces, balls, polyhedra and cones. Safe moves such as intersection build every other convex set you will need. And two convex sets that do not overlap can always be split by a flat wall.
1. Blending two points: lines, segments and rays
Picture a slider between two points x and y. At one end you sit on x, at the other on y. Let the slider run past both ends and you trace the whole line through them.
The slider position is a number θ. The point it gives is a blend of x and y. CO4A 2-1-1
z = θx + (1 − θ)y = y + θ(x − y)
Read the second form as a recipe: start at y and move θ of the way toward x. θ = 0 gives y, θ = 1 gives x, and θ = 0.5 gives the midpoint.
The range of θ decides the shape. If θ can be any real number, you get the line through x and y. If 0 ≤ θ ≤ 1, you get the line segment between them. If θ ≥ 0, you get a ray: it starts at y, passes through x, and goes on forever.
One formula, z = θx + (1 − θ)y, and three ranges of θ. The dashed line in the middle and right panels is the full line, shown for reference.
A number check with x = (1, 0) and y = (0, 1). θ = 0.5 gives 0.5·(1, 0) + 0.5·(0, 1) = (0.5, 0.5), the midpoint, on the segment. θ = 3 gives 3·(1, 0) − 2·(0, 1) = (3, −2). That point is on the line, far past x, but not on the segment.
2. Affine sets and convex sets
Some sets are flat and endless, like a point, a line or a plane. An affine set contains the whole line through any two of its points: the blend θx + (1 − θ)y stays inside for every real θ. The solutions of linear equations, {x : Ax = b}, are the typical example. CO4A 2-1-2
Blends of more than two points work the same way. A sum θ1x1 + … + θkxk whose weights add up to 1 is an affine combination. The weights may be negative. An affine set contains every affine combination of its points.
Take C = {x ∈ ℝ2 : x1 + x2 = 1}, a line. It contains (1, 0) and (0, 1), and also their blend (3, −2) from above, since 3 − 2 = 1. Slide C by (1, 0) toward the origin and you get the line x1 + x2 = 0 through the origin. Every affine set is a subspace slid away from the origin like this.
A convex set asks for less. Only the segment has to stay inside, not the whole line. This is the test from Day 1: no dents and no holes. CO4A 2-1-3Boyd & Vandenberghe 2004
x, y ∈ C and θ ∈ [0, 1] ⇒ θx + (1 − θ)y ∈ C
A weighted average θ1x1 + … + θkxk with every θi ≥ 0 and weights adding up to 1 is a convex combination. A convex set contains every convex combination of its points, not only blends of two at a time.
Stretch a rubber band around a set of points and let it snap tight. The region inside the band is the convex hull, the smallest convex set that contains them. It is also the set of all their convex combinations.
For example, the convex hull of (0, 0), (2, 0), (0, 2) and (1, 1) is the triangle with corners (0, 0), (2, 0) and (0, 2). The fourth point adds nothing. It is 0.5·(2, 0) + 0.5·(0, 2), so it already lies on an edge.
Every affine set is convex, because the segment is part of the line. The reverse fails: a disk is convex, but the line through two of its points runs out of the disk. The edge matters too. A square that keeps its top corners but not the middle of its top edge is not convex.
Try it: pick a shape, then drag P and Q (or tap to move the nearer one). The segment is solid green where it stays inside and dashed red where it leaves. "Find a bad pair" lets the computer search 2,000 random pairs for a leak.
Notice: in the default crescent both handles are inside, P = (−0.20, 0.90) and Q = (−0.20, −0.90). Yet the points θP + (1 − θ)Q leave the set for θ from 0.285 to 0.715, where the segment crosses the bite. One leaking segment proves the crescent is not convex. On the disk, square or cut disk, no pair you drag ever leaks.
Analogy
A convex set is like a room where everyone can see everyone else. Put a pillar in the middle, or make the room L-shaped, and some pairs of people lose sight of each other. The segment test simply asks whether every pair of points can "see" each other without the line of sight leaving the room.
3. Cones: rays from the origin
Think of a flashlight beam with the bulb at the origin. If a point is lit, so is every point farther out along the same ray. A set C is a cone if x ∈ C and θ ≥ 0 always give θx ∈ C. CO4A 2-1-4
A convex cone also contains all nonnegative sums: x, y ∈ C and θ1, θ2 ≥ 0 give θ1x + θ2y ∈ C. In the plane it looks like a pie slice with its tip at the origin, running on forever.
The quarter-plane ℝ2+, where both coordinates are ≥ 0, is a convex cone. From (1, 2) and (3, 0), the sum 2·(1, 2) + 1·(3, 0) = (5, 4) is still in it.
A cone does not have to be convex. The two coordinate axes together form a cone, since stretching a point on an axis keeps it there. But (1, 0) + (0, 1) = (1, 1) is on neither axis, so this cone is not convex. CMU 10-725 2016
4. A gallery of basic convex sets
A few shapes appear in almost every problem. Learn to spot them the way you spot a circle. The figure shows them, and the paragraphs below give formulas and number checks. CO4A 2-2-1CMU 10-725 2016
The gallery. Top row: a hyperplane with its normal vector a, a halfspace (the shaded side, where aTx ≤ b), a ball with centre c and radius r, and an ellipsoid with its two semi-axes. Bottom row: a polyhedron, the norm balls for p = 1 (orange diamond), p = 2 (blue disk) and p = ∞ (purple square), the second-order or "ice-cream" cone, and the cone of positive semidefinite matrices, drawn as a tilted cone.
Hyperplanes and halfspaces. A hyperplane {x : aTx = b}, with a ≠ 0, is a flat wall. The vector a, called the normal, sticks straight out of the wall. A halfspace {x : aTx ≤ b} is one side of the wall, wall included. It is convex but not affine. Take a = (1, 2) and b = 4. The point (2, 1) gives 2 + 2 = 4, so it is on the wall. (0, 0) gives 0 ≤ 4, inside. (4, 4) gives 12 > 4, outside.
Balls. The Euclidean ball with centre c and radius r is every point within distance r of c: {x : ‖x − c‖2 ≤ r}. With c = (1, 1) and r = 2, the point (2, 2) is √2 ≈ 1.414 away from the centre, so it is inside.
Ellipsoids. Stretch a ball along some directions and you get an ellipsoid: {x : (x − c)TP−1(x − c) ≤ 1}. Here P is a symmetric positive definite matrix (all eigenvalues > 0). The semi-axis lengths are the square roots of P's eigenvalues. With P = diag(4, 1) and c = 0, the set is x12/4 + x22 ≤ 1, with semi-axes 2 and 1. A ball is the special case P = r2I. Boyd & Vandenberghe 2004
Norm balls. You can measure length in other ways than the straight-line distance. The p-norm is
‖x‖p = (|x1|p + … + |xn|p)1/p
The absolute values matter: without them, negative entries would break the formula. The norm ball ‖x‖p ≤ 1 is a diamond for p = 1, a disk for p = 2, and a square for p = ∞, where the norm is the largest |xi|. All of these are convex.
The formula only gives a true norm, and a convex ball, when p ≥ 1. Try p = ½, where the "ball" is √|x1| + √|x2| ≤ 1. The points (1, 0) and (0, 1) are in it. Their midpoint (0.5, 0.5) scores √0.5 + √0.5 ≈ 1.414 > 1, so it is outside. The shape is a four-pointed star, and you can drag across its dent in the widget.
Polyhedra. A polyhedron is what remains after cutting space with finitely many flat walls: {x : Ax ⪯ b, Cx = d}. The sign ⪯ means "≤ in every entry". Each row of A ⪯ b is one halfspace, and each row of Cx = d is one hyperplane. A bounded polyhedron is a polytope.
For example, x1 ≥ 0, x2 ≥ 0 and x1 + x2 ≤ 1 cut out a triangle. In matrix form, the rows of A are (−1, 0), (0, −1) and (1, 1), and b = (0, 0, 1).
Simplices. A simplex is the convex hull of affinely independent points (no point is an affine combination of the others): a segment, a triangle, a tetrahedron. The probability simplex holds the vectors with entries ≥ 0 that add up to 1, such as (0.2, 0.3, 0.5): every possible list of probabilities or mixing weights.
5. Three cones you will meet again
The ice-cream cone. The second-order cone is {(x, t) : ‖x‖2 ≤ t}, where x ∈ ℝn and t is a number. Each horizontal slice at height t is a disk of radius t, so the slices grow as you go up. CO4A 2-2-2
Check three points. (3, 4, 5) is on the surface, since ‖(3, 4)‖2 = 5. (3, 4, 6) is inside, and (3, 4, 4) is outside.
This cone describes friction. A box on a floor will not slide while the sideways force stays within μ times the pushing-down force, where μ is the friction coefficient. With μ = 0.5 and 10 N pressing down, any sideways force up to 5 N, in any direction, is safe. Legged robots and grasping hands keep their contact forces inside such cones. Day 5 builds second-order cone programs from them.
The PSD cone. A symmetric matrix X is positive semidefinite (PSD), written X ⪰ 0, when all its eigenvalues are ≥ 0. Equivalently, vTXv ≥ 0 for every vector v. The PSD matrices of size n form the PSD cone Sn+.
It is a convex cone for a one-line reason. If vTXv ≥ 0 and vTYv ≥ 0, then vT(θ1X + θ2Y)v ≥ 0 for any θ1, θ2 ≥ 0.
For 2×2 matrices there is a quick test:
[a b; b c] ⪰ 0 ⇔ a ≥ 0, c ≥ 0, ac ≥ b²
[2 1; 1 1] passes, since 2·1 = 2 ≥ 1. Its eigenvalues are 0.382 and 2.618. [2 1.5; 1.5 1] fails, since 2·1 = 2 < 2.25. One of its eigenvalues is −0.081.
Every covariance matrix is PSD, including the uncertainty a car's localisation keeps about its own position. Problems over PSD matrices are semidefinite programs, also on Day 5.
6. Building new convex sets: the safe moves
Checking the segment test by hand gets tiring for complicated sets. Instead, build them from the basic shapes with moves that keep convexity. Boyd's slides list three ways to prove a set convex: the definition, convex functions (Day 3), or safe moves from simple sets. Boyd EE364a slidesCO4A 2-3
Move 1: intersection. If a segment stays inside each of two sets, it stays inside their overlap. So the intersection of convex sets is convex, even of infinitely many. The unit disk intersected with the halfspace x2 ≤ 0.5 is a "cut disk", one of the widget's shapes. In fact every closed convex set is the intersection of all the halfspaces that contain it. Boyd & Vandenberghe 2004
Move 2: affine maps. An affine map f(x) = Ax + b scales, rotates, shears, shifts or projects. It sends segments to segments. So the image of a convex set is convex, and so is the preimage {x : f(x) ∈ D} of a convex set D.
For example, A = diag(2, 1) stretches the unit disk into the ellipse x12/4 + x22 ≤ 1, with semi-axes 2 and 1. A preimage example: the set {x : x1A1 + … + xkAk ⪯ B}, called a linear matrix inequality, is convex. It is the set of x for which the affine map x ↦ B − ΣxiAi lands in the PSD cone. CMU 10-725 2016
Move 3: the perspective map. A pin-hole camera divides by depth. The perspective function P(z, t) = z/t, defined for t > 0, does the same. Images and preimages of convex sets under it are convex. For example, P(2, 4, 2) = (2/2, 4/2) = (1, 2). A convex object in front of a camera therefore shows up as a convex blob in the picture.
Following an affine map by the perspective gives a linear-fractional function f(x) = (Ax + b)/(cTx + d), defined where cTx + d > 0. It also keeps convex sets convex.
Not a safe move: union. Two disks side by side are each convex, but together they are not. In the widget's "two disks" shape, the midpoint of the two centres lies outside both.
A driving example. A planner for a self-driving car has to describe the free space it may drive into. The simplest pieces are halfspaces, one per straight edge: the two road edges, the lane line, and a line some metres behind the car ahead. Intersect a few of them and you get a convex piece of free space.
Free space as convex pieces. x is metres along the road and y is metres to the left of your lane's centre. Region A (green) keeps 10 m behind the car ahead, whose rear is at x = 30. Region B (blue) is the left lane. Each is an intersection of halfspaces, so each is convex. Their union is L-shaped: the straight path from p = (15, 0) to q = (45, 3.5) leaves both regions between x = 20 and x = 30 (the solid red part).
Here region A is the road with x ≤ 20, which keeps 10 m behind the car ahead. Region B is the road with y ≥ 1.75, the left lane. Each is a polyhedron, so each is convex.
The free space as a whole is "A or B", a union, and it is not convex. The point p = (15, 0) is in A and q = (45, 3.5) is in B. At x = 25 their segment has y ≈ 1.17: still in the right lane, but past the 20 m line. It is in neither region.
Planners handle this by picking a convex piece, or a chain of them, and optimizing inside it. Picking is a yes-or-no decision (Day 15). Day 19 builds whole planners this way, following the IRIS paper and graphs of convex sets.
7. Separating and supporting hyperplanes
Picture two fields that do not overlap. If both are convex, you can always build a straight fence between them. If one has a dent that wraps around the other, a straight fence may be impossible.
That is the separating hyperplane theorem. If C and D are nonempty convex sets with no common point, then there are a ≠ 0 and b such that Boyd & Vandenberghe 2004CO4A 2-5
aTx ≤ b for all x ∈ C, and aTx ≥ b for all x ∈ D
For example, take the disks of radius 1 centred at (−2, 0) and (2, 0). The wall x1 = 0, meaning a = (1, 0) and b = 0, separates them. Every point of the left disk has x1 ≤ −1, and every point of the right disk has x1 ≥ 1.
Now lay a ruler against a convex pebble. At any point on its edge, the ruler can touch the pebble with the whole pebble on one side. That is a supporting hyperplane. If C is convex and x0 is on its boundary, there is an a ≠ 0 with aTx ≤ aTx0 for every x ∈ C.
For example, take the unit disk and x0 = (1, 0). The vertical line x1 = 1, with a = (1, 0), supports it: every point of the disk has x1 ≤ 1.
Left: a separating line between two disjoint convex sets, with its normal a pointing from C toward D. Right: a supporting line touching the disk at the boundary point x0 = (1, 0), with the whole disk on one side.
Read the separating theorem in one direction only. The sets C = D = {0} on the number line share a point, yet the "wall" x = 0 satisfies both inequalities. And a wall with a gap on both sides is not guaranteed. Two disjoint closed convex sets can creep arbitrarily close to each other, leaving no room for a gap. Boyd & Vandenberghe 2004
These two theorems are the geometry behind duality (Day 9) and behind linear classifiers, which look for a wall between two classes of data points. CO4A 2-5
Robot planners use the same fact. A car's footprint and an obstacle, both convex polygons, are apart exactly when some straight line separates them with a gap. Day 19 and the OBCA paper turn this into constraints a solver can handle.
Going deeper (optional): cones as a way to compare vectors
Numbers can always be compared, but vectors cannot. A cone K gives a partial ordering: say x ⪯K y when y − x ∈ K. With K = ℝ+, the nonnegative numbers, this is the usual ≤. K must be a proper cone: convex, closed, with a nonempty interior, and containing no whole line. CO4A 2-4
With K = ℝ2+, (1, 2) ⪯ (2, 3), because (1, 1) ∈ K. But (1, 3) and (2, 2) cannot be compared, since neither (1, −1) nor (−1, 1) is in K.
Take S = {(1, 3), (2, 2), (3, 1), (3, 3)}. No point is below all the others, so S has no minimum. But (1, 3), (2, 2) and (3, 1) are minimal: nothing in S is below them. (3, 3) is not, since (2, 2) is below it. Minimal points are the Pareto-optimal trade-offs.
Weights find them: minimizing λTz over S with λ = (2, 1) picks (1, 3). Such weights live in the dual cone K* = {λ : λTx ≥ 0 for all x ∈ K}. CO4A 2-6-1Boyd & Vandenberghe 2004
Explain it to a 10-year-old
Draw a shape. Put two dots anywhere inside it and join them with a ruler. If the line never leaves the shape, whichever two dots you pick, the shape is "convex". A pizza slice passes. A star or a doughnut fails, because some lines poke outside or cross the hole.
Common misunderstandings
"Convex means round." No. Squares, triangles and halfspaces are convex. The test is about segments, not smoothness.
"A union of convex sets is convex." No. Intersection is safe, union is not. Two separate disks fail, and so does the two-lane free space in section 6.
"Any p-norm ball is convex." Only for p ≥ 1. For p = ½, the midpoint of (1, 0) and (0, 1) scores ≈ 1.414 > 1 and sits outside.
"If a separating hyperplane exists, the sets are disjoint." No. C = D = {0} share a point, and x = 0 still "separates" them. Also, disjoint convex sets cannot always be separated with a gap.
"Every cone is convex, and a cone can't be affine." Both are false. The two coordinate axes form a cone that is not convex. And any subspace, such as a line through the origin or ℝn itself, is both a cone and an affine set. (CO4A 2-1-4 states the second claim; it is a slip.)
Check yourself
Q1. Which set is NOT convex?
The ring has a hole: (0.75, 0) and (−0.75, 0) are in it, but their midpoint (0, 0) is not. An intersection of convex sets is always convex, even though a union need not be.
Q2. The ray that starts at y and passes through x is θx + (1 − θ)y with…
θ = 0 is y, θ = 1 is x, and larger θ goes past x forever. Any real θ gives the whole line, and 0 ≤ θ ≤ 1 gives only the segment.
Q3. The p-norm ball {x : ‖x‖p ≤ 1} is convex when…
For p ≥ 1 the formula is a norm and its ball is convex: diamond, disk, square, and everything in between. For p = ½ the midpoint of (1, 0) and (0, 1) scores 1.414 and leaves the "ball".
Q4. Is the matrix [2 1.5; 1.5 1] positive semidefinite?
The 2×2 test needs a ≥ 0, c ≥ 0 and ac ≥ b². The third condition fails. Positive diagonal entries and symmetry are necessary, but not enough.
Q5. Which operation can turn convex sets into a set that is not convex?
Two separate disks are each convex, but their union is not. Intersection, affine maps and the perspective map always keep convex sets convex.
Q6. What does the separating hyperplane theorem guarantee?
Both sets must be convex; a crescent can wrap around a point so that no straight wall works. The wall need not leave a gap, and the reverse direction fails: C = D = {0} share a point but are "separated" by x = 0.
Recap: things to remember
z = θx + (1 − θ)y gives the line (any θ), the segment (0 ≤ θ ≤ 1) and the ray (θ ≥ 0). A set is convex when it contains the segment between any two of its points.
Know the basic convex sets on sight: hyperplanes, halfspaces, balls, ellipsoids, norm balls with p ≥ 1, polyhedra, simplices, the second-order cone and the PSD cone.
Intersection, affine images and preimages, and perspective maps keep sets convex. Union does not.
Two disjoint convex sets can be split by a hyperplane, and every boundary point of a convex set has a supporting hyperplane.
Free space for a car or robot is often a union of convex pieces, each an intersection of halfspaces. Planners optimize inside one piece at a time.
After today you can test whether a function is convex (chord, tangent-line and second-derivative tests), build convex functions from simple pieces with convexity-preserving rules, and recognise strongly convex, quasiconvex and log-convex functions.
About 60 min · Needs Day 2 · CO4A chapter 3
Today's big idea
A convex function is shaped like a bowl: a straight string stretched between any two points of its graph never dips below the graph. Three tests check this (the chord, the tangent line and the curvature), and a short list of safe rules builds big convex costs out of small ones without testing anything. The payoff is the one from Day 1: on a bowl, a flat spot is the lowest point anywhere.
1. The chord test: what "convex" means for a function
Draw the graph of a function. Pick two points on it and stretch a string between them. If the string never passes below the graph, wherever you pick the points, the function is convex. A bowl-shaped valley passes. A road over a hill fails, because some string would cut through the hill.
The string is called a chord. To write it down, call the two inputs x and y. Every point between them is θx + (1 − θ)y for some weight θ ∈ [0, 1]: θ = 1 gives x, θ = 0 gives y, and θ = ½ gives the midpoint. The chord's height above that point is the same blend of the two heights, θf(x) + (1 − θ)f(y).
A function f is a convex function if its domain dom f (the inputs where it is defined) is a convex set and the curve never rises above the chord: CO4A 3-1-1Boyd & Vandenberghe 2004 §3.1.1
f(θx + (1 − θ)y) ≤ θf(x) + (1 − θ)f(y)
This must hold for all x and y in dom f and every θ ∈ [0, 1]. A worked pair: f(x) = x², x = −1, y = 3 and θ = ½. The midpoint is 1, where the curve is at f(1) = 1. The chord there is at (1 + 9)/2 = 5. The gap, chord minus curve, is 4, so this pair passes.
One passing pair proves nothing, because the rule covers every pair. One failing pair, though, settles the question. Take f(x) = x⁴ − 2x² with x = −1 and y = 1. Both ends sit at height −1, so the chord is flat at −1, but the curve at the midpoint is f(0) = 0. The curve is 1 above the chord, so this f is not convex.
Turn the picture upside down for the mirror idea. A function is a concave function if −f is convex: the chord never passes above the graph, like a dome. A straight line f(x) = aTx + b (where aTx = a₁x₁ + … + aₙxₙ) turns the inequality into an equality, so affine functions are both convex and concave. CO4A 3-1-1
With θ = ½ the chord test reads "f of the average ≤ the average of f". Extended to many points and to expected values, this is Jensen's inequality, f(E[X]) ≤ E[f(X)]. If X is 0 or 2 with equal odds and f(x) = x², then f(E[X]) = f(1) = 1, while E[f(X)] = (0 + 4)/2 = 2. CO4A 3-1-3Boyd & Vandenberghe 2004 §3.1.8
Day 2 gives a second picture of the same idea. Shade everything on or above the graph. That region is the epigraph, epi f = {(x, t) : f(x) ≤ t}, where t stands for a height. A function is convex exactly when its epigraph is a convex set. The chord test is Day 2's segment test applied to two points on the graph: a chord that dips below the graph leaves the shaded region. CO4A 3-1-3Boyd & Vandenberghe 2004 §3.1.7
The chord test. Left: for x², the green chord from −1 to 3 stays above the graph; at x = 1 the curve is at 1 and the chord at 5. Right: for x⁴ − 2x², the red chord from −1 to 1 runs under the hump at 0. The blue shading is the epigraph. On the left it is a convex set; on the right the red chord joins two of its points but passes outside it.
Try it: pick a function and drag the two points (or use the sliders). The θ slider moves the pair of dots that compare chord and curve. Press Hunt for a bad chord to scan 41 × 41 pairs of points with 11 weights each. The coloured strip under the plot shows the sign of f″, which section 3 explains.
Notice that the default, x² with a = −1 and b = 3, shows a gap of 4.000 at x = 1 (chord 5.000 − curve 1.000) and a lowest gap of 0.000, so the chord is green. Switch to x³: its default chord from 0 to 2 is green as well, but Hunt finds a chord from −2 to 1.1 that dips 3.98 below the graph.
Explain it to a 10-year-old
Think of a slide shaped like a smile. Hold a straight stick so that it touches the slide at two spots. Wherever you choose the spots, the stick is above the slide or touching it. Now think of a slide shaped like a W, with a bump in the middle. Put the stick's ends on both sides of the bump, and the bump pokes up through the stick. A marble on the smile always rolls to the one lowest point. On the W it can get stuck on the wrong side of the bump.
2. The tangent test: one slope gives a floor everywhere
Lay a ruler against a bowl so that it touches at one spot. The ruler touches the bowl there and nowhere cuts into it. For a convex function the tangent line is that ruler: it touches the graph at one point and stays on or below the graph everywhere else.
In symbols, write ∇f(x) for the gradient, the vector of slopes ∂f/∂x₁, …, ∂f/∂xₙ, which points uphill. The tangent at x predicts f(y) ≈ f(x) + ∇f(x)T(y − x). The first-order condition says that a differentiable f on a convex domain is convex exactly when this prediction never overshoots: CO4A 3-1-3Boyd & Vandenberghe 2004 §3.1.3
f(y) ≥ f(x) + ∇f(x)T(y − x) for all x, y
A number check. For f(x) = x² at x = 1 the slope is 2, so the tangent line is 1 + 2(y − 1) = 2y − 1. At y = 3 the tangent says 5 and the true value is 9, so the floor holds. Now take sin x at x = 0. Its tangent is the line through the origin with slope 1. At y = 1 the line says 1, but sin 1 ≈ 0.841 is lower. The tangent has poked above the graph, so sin is not convex.
Here is why this matters. Suppose the gradient is zero at some point x*. The floor then reads f(y) ≥ f(x*) for every y, so nothing anywhere beats x*. For a convex function, a flat spot is a global minimum, not just a local one. That is Day 1's "local equals global", seen through tangents. Boyd and Vandenberghe call the first-order condition "perhaps the most important property of convex functions". Boyd & Vandenberghe 2004 §3.1.3
For a planner this is a guarantee you can act on. If a car's cost is convex in its plan and there are no constraints, a zero gradient means the best plan, not just a nearby dip. With constraints, the zero-gradient test becomes the KKT conditions of Day 10. A kink, like |x| at 0, has no single tangent, but it still has many lines that act as floors; Day 7 calls their slopes subgradients.
The tangent test. Left: every tangent of x² is a floor. The purple tangent at x = 1 gives 5 at x = 3, under the true 9. The orange tangent at x = 0 is flat, so nothing lies lower: x = 0 is the global minimum. Right: the tangent of sin x at 0 runs above the graph for 0 < x < π (red shading), so sin is not convex.
Going deeper (optional): why the tangent test works
Take one variable. Convexity on the short chord from x to x + t(y − x) gives f(x + t(y − x)) ≤ (1 − t)f(x) + t·f(y) for t ∈ (0, 1]. Subtract f(x) from both sides and divide by t:
[f(x + t(y − x)) − f(x)] / t ≤ f(y) − f(x)
As t shrinks to 0, the left side becomes f′(x)(y − x), and that is the tangent inequality. For n variables, run the same argument along the line through x and y. The converse (tangent floors everywhere imply convexity) is also short; Boyd and Vandenberghe give both directions. Boyd & Vandenberghe 2004 §3.1.3
3. The curvature test: second derivatives and the Hessian
Drive along the graph from left to right. On a convex function the steering wheel only ever turns left (the road bends upward) or stays straight. It never turns right. Bending upward means the slope keeps growing.
The rate at which the slope grows is the second derivative f″. So a function of one variable, twice differentiable on an open interval, is convex exactly when f″(x) ≥ 0 everywhere. Boyd & Vandenberghe 2004 §3.1.4 For −log x on x > 0, f′ = −1/x and f″ = 1/x² > 0, so −log x is convex. For x⁴ − 2x², f″ = 12x² − 4, which is negative for |x| < 0.577. There the graph bends down, and that is exactly where the chord in the first figure failed.
With several variables, curvature becomes a matrix. The Hessian ∇2f(x) is the table of all second derivatives; its entry (i, j) is ∂²f/∂xᵢ∂xⱼ. "Bends up in every direction" means the Hessian is positive semidefinite, written ∇2f(x) ⪰ 0: all its eigenvalues are ≥ 0, or equivalently vT∇2f(x)v ≥ 0 for every direction v. The second-order condition, for f twice differentiable on a convex open domain, is the n-variable version of f″ ≥ 0: CO4A 3-1-3Boyd & Vandenberghe 2004 §3.1.4
f convex ⇔ ∇2f(x) ⪰ 0 for every x in dom f
Two quadratics that look alike show the difference. Write a matrix row by row, with ";" between rows. f(x) = x₁² + x₁x₂ + x₂² has the constant Hessian [2 1; 1 2], with eigenvalues 1 and 3. Both are positive, so f is a bowl. g(x) = x₁² + 4x₁x₂ + x₂² also has only positive coefficients, but its Hessian [2 4; 4 2] has eigenvalues −2 and 6. One negative eigenvalue makes g a saddle: up in one direction, down in another.
You can see the saddle without eigenvalues. Walk through the origin along the direction v = (1, −1), so that x = (t, −t). Then g = t² − 4t² + t² = −2t², a parabola that opens downward. A convex function must be convex along every line, so g is not convex. This trick, restricting to a line, turns any n-variable question into a one-variable one. B&V slides 3.7CMU 10-725 2016
Try it: start from the saddle, then pick the bowl, or slide q₁₂ toward 0 and watch the verdict turn convex once |q₁₂| ≤ 1. With q₁₁ = q₂₂ = 1 the Hessian eigenvalues are 2 − 2q₁₂ and 2 + 2q₁₂.
Notice that the default saddle, x₁² + 4x₁x₂ + x₂², has Hessian eigenvalues −2 and 6. Its contours are hyperbolas, and the slices read f = 6t² along (1, 1) but f = −2t² along (1, −1), the same −2t² as in the text.
How curved is curved enough? Convexity allows straight stretches: the chord of |x| from 1 to 3 lies on the graph, gap 0. A function is strictly convex if the chord lies strictly above the graph between any two different points (for 0 < θ < 1). Then it cannot have two lowest points, because the midpoint between them would be lower still. A quick test: if ∇2f(x) has all eigenvalues > 0 everywhere, f is strictly convex. The converse fails: x⁴ is strictly convex, yet f″(0) = 0. CO4A 3-1-1Boyd & Vandenberghe 2004 §3.1.4
A function is strongly convex with parameter m > 0 if it is at least as curved as the bowl (m/2)‖x‖₂², where ‖x‖₂ = √(x₁² + … + xₙ²) is ordinary length. Formally, f(x) − (m/2)‖x‖₂² must still be convex. CO4A 3-1-1 The Hessian of that difference is ∇2f(x) − mI, where I is the identity matrix. So for twice-differentiable f, strong convexity means ∇2f(x) ⪰ mI: every eigenvalue of the Hessian is at least m, at every x.
Some numbers. x² is strongly convex with m = 2: x² − x² = 0 is still convex, while m = 3 would leave −½x². The bowl x₁² + x₁x₂ + x₂² has smallest Hessian eigenvalue 1, so m = 1. x⁴ is strictly but not strongly convex, because its curvature 12x² falls to 0 at x = 0. So strongly convex ⇒ strictly convex ⇒ convex, and neither arrow reverses. CMU 10-725 2016 Why care? Strong convexity puts a curved floor under f instead of a flat one, f(y) ≥ f(x) + ∇f(x)T(y − x) + (m/2)‖y − x‖₂². Day 6 uses this floor to show that gradient descent then shrinks its error bound by a constant factor at every step.
Analogy
Picture a skateboard bowl. The chord test: a plank laid between any two points of the surface never goes underground. The tangent test: a plank resting on the surface at one spot never pokes into it anywhere else. The curvature test: as you roll across, the surface under your wheels only ever curves up. A bowl with a flat floor is convex but not strictly convex. A bowl that curves up everywhere by at least some fixed amount is strongly convex.
4. A catalogue of convex functions
Most convexity proofs end with "and this piece is a function we already know". So it pays to recognise a dozen on sight, the way you read road signs without reading the words. The table lists the standard ones, each with a one-line reason. CO4A 3-1-2Boyd & Vandenberghe 2004 §3.1.5CMU 10-725 2016
Function
Formula
Convex on
Why, or a number
Exponential
eax, any a
all of ℝ
f″ = a²eax ≥ 0
Powers
xa
x > 0, when a ≥ 1 or a ≤ 0
f″ = a(a − 1)xa−2 ≥ 0; for 0 ≤ a ≤ 1 it is concave (√x)
Negative log
−log x
x > 0
f″ = 1/x² > 0
Negative entropy
x log x
x > 0
f″ = 1/x > 0
Absolute powers
|x|p, p ≥ 1
all of ℝ
p = 1 is |x|: convex, not strictly
Affine
aTx + b
ℝn
flat, so convex and concave
Quadratic
½xTPx + qTx + r
ℝn, if P ⪰ 0
its Hessian is P
Least squares
‖Ax − b‖₂²
ℝn, any A
Hessian 2ATA ⪰ 0
Norms
‖x‖p = (Σ|xᵢ|p)1/p, p ≥ 1; ‖x‖∞ = maxᵢ|xᵢ|
ℝn
triangle inequality; x = (3, −4) gives 7, 5, 4 for p = 1, 2, ∞
Maximum
max{x₁, …, xₙ}
ℝn
a maximum of linear functions
Log-sum-exp
log(ex₁ + … + exₙ)
ℝn
Hessian ⪰ 0; x = (1, 2, 3) gives 3.408
Indicator
IC(x): 0 on C, +∞ off C
ℝn, if C is convex
turns "x ∈ C" into a cost
A norm ‖x‖ measures the length of a vector. Three are common: ‖x‖₁ = |x₁| + … + |xₙ| (city-block length), ‖x‖₂ (straight-line length) and ‖x‖∞ = maxᵢ|xᵢ| (the largest entry). For x = (3, −4) they give 7, 5 and 4. Every norm is convex for a one-line reason: scaling (‖θx‖ = θ‖x‖ for θ ≥ 0) and the triangle inequality (‖u + v‖ ≤ ‖u‖ + ‖v‖) together give ‖θx + (1 − θ)y‖ ≤ θ‖x‖ + (1 − θ)‖y‖, which is the chord test. In a planner, the distance ‖p − pgoal‖₂ from a car's position p to its goal is therefore convex in p.
A quadratic f(x) = ½xTPx + qTx + r, with P a symmetric matrix, has the same Hessian P at every point. So it is convex exactly when P ⪰ 0. Least squares, ‖Ax − b‖₂², is the case P = 2ATA. It is always convex, because vTATAv = ‖Av‖₂² ≥ 0 for every v.
Log-sum-exp, lse(x) = log(ex₁ + … + exₙ), is a smooth version of the maximum: max xᵢ ≤ lse(x) ≤ max xᵢ + log n. At x = (1, 2, 3) it is 3.408, between 3 and 3 + log 3 ≈ 4.099. Its Hessian is diag(z) − zzT, where zᵢ = exᵢ/Σⱼexⱼ are the softmax weights and diag(z) is the diagonal matrix holding them. At x = (0, 0) that is [0.25 −0.25; −0.25 0.25], with eigenvalues 0 and 0.5, so it is positive semidefinite. Boyd & Vandenberghe 2004 §3.1.5CMU 10-725 2016
Finally, the indicator function of a set C, IC(x) = 0 for x in C and +∞ outside, turns a constraint "x ∈ C" into a cost. It is convex exactly when C is a convex set, which ties today back to Day 2. CO4A 3-1-2
5. Building convex functions from safe pieces
Checking a Hessian by hand gets painful fast. Engineers instead build costs like Lego, from catalogue pieces joined by moves known to keep convexity. Five moves cover almost everything. CO4A 3-2Boyd & Vandenberghe 2004 §3.2
Nonnegative weighted sums. If f₁, …, fₘ are convex and every weight αᵢ ≥ 0, then α₁f₁ + … + αₘfₘ is convex: add up their chord inequalities. Example: 3x² + 2|x| + ex. A negative weight can break it: x² − 2x⁴ has f″ = 2 − 24x², which is negative for |x| > 0.29.
Affine composition. If f is convex, so is f(Ax + b) for any matrix A and vector b, because a straight line in x maps to a straight line in Ax + b. Example: ‖Ax − b‖ is convex for every norm.
Pointwise maximum. The pointwise maximum f(x) = max{f₁(x), …, fₘ(x)} of convex functions is convex, and so is a supremum over infinitely many. Picture the upper edge of several bowls: still one bowl. Example: f(x) = max(2x + 1, −x + 4) has a kink at x = 1 with f(1) = 3, and the chord from x = 0 (f = 4) to x = 2 (f = 5) passes above it at 4.5. The same rule makes a worst-case cost convex: the largest of several convex costs, one for each guess about what the car ahead will do.
Partial minimization. If f(x, y) is convex in x and y jointly and C is a convex set, then g(x) = infy ∈ C f(x, y) is convex, as long as g stays above −∞. This is partial minimization. Example: the distance to a convex set, dist(x, C) = miny ∈ C ‖x − y‖. For C = [0, 1] it equals max(0, −x, x − 1), so dist(3, [0, 1]) = 2. How far a car's position lies outside a convex lane corridor is therefore a convex penalty. Boyd & Vandenberghe 2004 §3.2.5
Composition. For f(x) = h(g(x)), convex pieces are not enough; the direction in which the outer function h slopes matters too. The composition rule comes from the chain rule f″ = h″(g)·g′² + h′(g)·g″: when both terms are ≥ 0, f is convex. The table lists the four cases. CMU 10-725 2016Boyd & Vandenberghe 2004 §3.2.4
Outer h
Inner g
h(g(x)) is
Example
convex, nondecreasing
convex
convex
eg(x), such as ex²
convex, nonincreasing
concave
convex
1/g(x) for g concave and > 0, such as 1/(1 − x²) on (−1, 1)
concave, nondecreasing
concave
concave
log g(x) for g concave and > 0
concave, nonincreasing
convex
concave
√(1 − x²), the top half of a circle
A failure shows why the slope direction matters. h(u) = e−u is convex but decreasing, and g(x) = x² is convex. Their composition, the bell curve e−x², is not convex: at x = 0 it is 1, above the chord from −1 to 1, which sits at e−1 ≈ 0.368.
One move looks safe and is not: a plain minimum. min(x², (x − 2)²) is 0 at x = 0 and x = 2 but 1 at x = 1, above the chord at 0. Two bowls side by side make two valleys. Partial minimization is different: one jointly convex function, minimized over a convex set. CO4A 3-2 opens its minimization part by calling the minimum of convex functions convex; that sentence is wrong, though the formula after it is right. CO4A 3-2
Max is safe, min is not. Both panels start from the bowls x² and (x − 2)², drawn dashed. Their maximum (left) is one valley, lowest at x = 1. Their minimum (right) has two valleys, and at x = 1 it sits at 1, above the chord at 0 that joins them.
Here is the toolkit on a real cost. A car's speed planner chooses accelerations a₁, …, aN, one every Δt seconds. A comfort cost penalizes acceleration and jerk, the change in acceleration per second, (ak+1 − ak)/Δt:
J(a) = Σ ak² + w Σ ((ak+1 − ak)/Δt)²
Each term is a square, which is convex, of an affine function of a (move 2), and the weights 1 and w are nonnegative (move 1). So J is convex for every w ≥ 0 and Δt > 0, with no Hessian in sight. Numbers, with N = 3, Δt = 1 and w = 1: plan A = (0, 2, 0) costs 4 + 8 = 12, plan B = (2, 0, 2) costs 8 + 8 = 16, and their average (1, 1, 1) costs 3 + 0 = 3, far below the average cost of 14. Blending two plans never costs more than blending their costs. That is the chord test again, and it is why a model predictive controller (Day 17) can find the single best plan reliably.
Going deeper (optional): two more rules and a catch
Perspective. If f is convex, its perspective g(x, t) = t·f(x/t), for t > 0, is convex as well. For example, f(x) = xTx gives g(x, t) = xTx/t, convex in x and t together. The logic runs from f to g; the examples in CO4A 3-2 state it the other way round. Boyd & Vandenberghe 2004 §3.2.6
Conjugate. The conjugate function f*(y) = supx (yTx − f(x)) is a supremum of functions that are affine in y, so by move 3 it is convex even when f is not. It is a standard tool in duality theory. Boyd & Vandenberghe 2004 §3.3.1
The catch in composition. The monotonicity of h must hold on all of ℝ once h is given the value +∞ outside its domain. h(u) = u² with domain u ≥ 0 increases on its domain, but its extension does not: it drops from +∞ to 0 at u = 0. With g(x) = x² − 1, h(g(x)) is defined only for |x| ≥ 1, which is not even a convex set. Boyd & Vandenberghe 2004 §3.2.4
6. Two looser cousins: quasiconvex and log-convex functions
Some useful functions are not bowls but still have only one valley. Count the 10-tonne trucks needed to move x tonnes: 0 for nothing, 1 for up to 10 tonnes, 2 for up to 20. The graph is a staircase, ⌈x/10⌉. It fails the chord test, since 5 tonnes needs 1 truck, above the chord's 0.5 between 0 and 10 tonnes. Yet it never goes down, so it never makes a second valley.
The idea that captures this is the sublevel set {x : f(x) ≤ α}, all the inputs that score at most α. A function is quasiconvex if every sublevel set is convex. In one variable that means the graph goes down and then up, or only one way, with no second dip. There is a chord-style test too, with the higher endpoint in place of the chord: CO4A 3-4-1CO4A 3-4-2
f(θx + (1 − θ)y) ≤ max{f(x), f(y)}
Every convex function is quasiconvex, because its sublevel sets are convex. CO4A 3-1-3 The reverse fails. f(x) = √|x| has the sublevel sets [−α², α²], all intervals, so it is quasiconvex. It is not convex: between 0 and 4 the chord at x = 2 is at 1, while f(2) ≈ 1.414. But 1.414 ≤ max{f(0), f(4)} = 2, so the weaker test passes. Boyd & Vandenberghe 2004 §3.4.1
Quasiconvex means every sublevel set is one piece. Left: the inputs where √|x| ≤ 1.5 form the single interval [−2.25, 2.25], and the same holds at every level, so √|x| is quasiconvex though not convex. Right: the inputs where x⁴ − 2x² ≤ −0.5 form two separate intervals, so this function is not even quasiconvex.
Weaker means fewer guarantees. A zero slope no longer marks a minimum: x³ only rises, so it is quasiconvex, and its slope at 0 is 0, but 0 is not a minimizer. For differentiable f, the correct first-order test is: if f(y) ≤ f(x), then ∇f(x)T(y − x) ≤ 0. Every point at least as good as x lies on the downhill side of the gradient. CO4A 3-4-3 garbles this statement, so follow Boyd and Vandenberghe here. Boyd & Vandenberghe 2004 §3.4.3
Two more warnings. A local minimum need not be global: at x = 5 tonnes nothing nearby needs fewer trucks, yet x = 0 needs none. Boyd & Vandenberghe 2004 §4.2.2 And sums can break quasiconvexity: x³ and −x each run one way, but x³ − x has the sublevel set {x : x³ − x ≤ 0} = (−∞, −1] ∪ [0, 1], two pieces.
The second cousin works on a log scale. A positive function f is log-concave if log f is concave, and log-convex if log f is convex. The bell curve e−x²/2 is the standard log-concave example: it is not concave everywhere (its tails bend up), but its log, −x²/2, is a dome. The Gaussian cumulative distribution function and det X on positive definite matrices are log-concave too. On the other side, 1/x on x > 0 is log-convex, since its log, −log x, is convex. CO4A 3-5Boyd & Vandenberghe 2004 §3.5.1
Four facts are worth keeping. A log-convex f is convex, since f = elog f is a convex, nondecreasing function of the convex log f. Products of log-concave functions are log-concave, since their logs add. Sums of log-convex functions stay log-convex: log(f + g) is log-sum-exp applied to (log f, log g), which is convex and nondecreasing in each argument. (CO4A 3-5 argues this step with "the log of a convex function is convex", which is false.) Sums of log-concave functions need not stay log-concave: two bells at ±2, e−(x−2)²/2 + e−(x+2)²/2, have (log f)″(0) ≈ +3 > 0. Boyd & Vandenberghe 2004 §3.5.2
7. How to check convexity in practice
Faced with a new cost, work down this list and stop at the first step that answers. It is the recipe from the Boyd and Vandenberghe slides, cheapest step first. B&V slides 3.18
Recognise it. Is it in the catalogue of section 4? Then it is convex.
Build it. Can you write it as catalogue pieces joined by the five moves of section 5? Then it is convex, and you never needed a derivative.
Differentiate it. For a function of one or two variables, compute f″ or the Hessian and check its sign or eigenvalues at every point of a convex domain.
Slice it. Otherwise restrict to lines: g(t) = f(x + tv) must be convex in t for every point x and direction v.
Attack it. If you suspect it is not convex, hunt for one bad chord, as the widget does, or one direction with a negative Hessian eigenvalue. One failure settles it. No number of passing samples proves convexity.
Steps 1 and 2 are automated in CVXPY, a Python modelling library, under the name disciplined convex programming (DCP). Every built-in function (an "atom", such as square, norm or log_sum_exp) carries its known curvature and monotonicity, and CVXPY applies the composition rule at every node of your expression (as of Oct 2026). CVXPY docs If the rules certify an expression, it is convex. If they cannot, CVXPY reports UNKNOWN, which may only mean the expression was written in an unlucky way: DCP is sufficient, not necessary. B&V slides 3.33
import cvxpy as cp
x = cp.Variable()
a = cp.Variable(3) # a 3-step acceleration plan
comfort = cp.sum_squares(a) + 4 * cp.sum_squares(cp.diff(a)) # w/Δt² = 4
print(comfort.curvature) # CONVEX
print(cp.log_sum_exp(a).curvature) # CONVEX
print(cp.sqrt(1 + cp.square(x)).curvature) # UNKNOWN, though convex
print(cp.norm(cp.hstack([1, x]), 2).curvature) # CONVEX: same function
print(cp.minimum(cp.square(x), cp.square(x - 2)).curvature) # UNKNOWN: truly not convex
The √(1 + x²) line is the textbook case. The function equals ‖(1, x)‖₂, a norm of an affine expression, which CVXPY certifies at once when it is written that way. Day 4 takes the next step and builds whole optimization problems from convex pieces.
Common misunderstandings
"One passing chord proves convexity." The rule covers all pairs. x³ passes from 0 to 2 (gap +3 at the midpoint) and fails from −2 to 0 (gap −3).
"The minimum of convex functions is convex." min(x², (x − 2)²) is 1 at x = 1, above the chord at 0. A maximum is safe; a minimum keeps convexity only as partial minimization of one jointly convex function.
"Strictly convex means f″ > 0." x⁴ is strictly convex with f″(0) = 0. Only the other direction holds: f″ > 0 on an interval implies strictly convex there.
"f″ > 0 wherever f is defined is enough." The domain must be convex too. 1/x² on x ≠ 0 has f″ = 6/x⁴ > 0, yet it is not convex: its domain has a hole at 0.
"Convex sublevel sets mean a convex function." That is quasiconvexity, which is weaker. √|x| has interval sublevel sets and fails the chord test.
"A convex function of a convex function is convex." Only if the outer one is nondecreasing. e−x² is a convex, decreasing function of the convex x², and it is not convex.
Check yourself
Q1. Which of these is convex on all of ℝ?
ex has f″ = ex > 0 everywhere. The others all bend down somewhere: x³ for x < 0, sin x on (0, π), and the bell e−x² for |x| < 0.707.
Q2. The first-order condition says that the tangent line of a convex function is…
The tangent is a global floor: f(y) ≥ f(x) + ∇f(x)T(y − x) for every y, not just nearby ones. With ∇f(x) = 0 this says f(y) ≥ f(x) for all y.
Q3. f(x) = x⁴ has f″(0) = 0. So f is…
f″ ≥ 0 everywhere gives convexity, and the chord lies strictly above x⁴ between any two different points. f″ > 0 is enough for strict convexity but not required; x⁴ is the standard example.
Q4. g(x) = x₁² + 4x₁x₂ + x₂² is…
The Hessian eigenvalues are 2 ± 4, so −2 and 6. Along (1, −1), g(t, −t) = −2t², a downward parabola. Positive coefficients and symmetry say nothing about the signs of the eigenvalues.
Q5. f₁ and f₂ are convex. Which of these can fail to be convex?
min(x², (x − 2)²) has two valleys and sits at 1, above the chord at 0 between them. Nonnegative sums, maxima and affine composition always keep convexity.
Q6. f(x) = √|x| is…
Every sublevel set {x : √|x| ≤ α} = [−α², α²] is an interval, so it is quasiconvex. Its chord from 0 to 4 is at 1 at x = 2, below f(2) ≈ 1.414, so it is not convex. It is not concave on ℝ either: the chord from −1 to 1 sits at 1, above f(0) = 0.
Recap: things to remember
Convex means the chord between any two graph points lies on or above the graph; equivalently, the epigraph is a convex set. One bad chord disproves convexity.
For differentiable f, the tangent is a global floor, f(y) ≥ f(x) + ∇f(x)T(y − x), so ∇f(x) = 0 means x is a global minimizer.
For twice-differentiable f on a convex domain, convex ⇔ ∇2f(x) ⪰ 0 everywhere. Strongly convex (∇2f ⪰ mI, m > 0) ⇒ strictly convex ⇒ convex.
Know the catalogue (norms, quadratics with P ⪰ 0, least squares, −log x, ex, max, log-sum-exp) and the safe moves (nonnegative sums, affine composition, maximum, partial minimization, composition with the right monotonicity). A plain minimum is not safe.
Quasiconvex functions have convex sublevel sets and weaker guarantees; log-concave and log-convex functions are tested through log f. CVXPY's DCP rules automate the build-it check.
Convex Optimization, Stephen Boyd and Lieven Vandenberghe, Cambridge University Press, 2004; free PDF, chapter 3 (§3.1–3.5) and §4.2.2 (accessed 2026-10-26).
Convex Optimization lecture slides, Stephen Boyd and Lieven Vandenberghe, chapter 3 (slides 3.7, 3.18, 3.28–3.33) (accessed 2026-10-26).
Convexity I: Sets and Functions, Ryan Tibshirani, CMU 10-725 Convex Optimization, Fall 2016, slides 16–27 (accessed 2026-10-26).
After today you can write a problem in standard form, explain why every local minimum of a convex problem is global, use the first-order optimality condition, and reshape problems with slack variables, epigraphs and other equivalent transformations.
About 60 min · Needs Day 3 · CO4A chapter 4
Today's big idea
A convex problem is a convex cost minimized over a convex set of allowed points. Such a problem has no false bottoms: if no small step improves a point, no big step does either. Much of the practical skill is rewriting a problem until its convexity is plain to see.
1. Writing a problem down: standard form
Every optimization problem says the same thing. Pick some numbers to make one number as small as possible, while obeying some rules. A delivery robot picks a route to make the travel time small without leaving the sidewalk.
Standard form is the agreed way to write this down, so that theorems and solvers can read it. CO4A 4-1
minimize f(x) subject to gi(x) ≤ 0, i = 1, …, m hj(x) = 0, j = 1, …, r
Here x ∈ ℝn is the optimization variable, the numbers you get to choose. f is the objective (CO4A also calls it the criterion), the number you want small. Each gi(x) ≤ 0 is an inequality constraint and each hj(x) = 0 is an equality constraint. All the rules are written as "something ≤ 0" or "something = 0", so a rule like x ≤ 3 becomes x − 3 ≤ 0.
A point that obeys every rule is a feasible point, and all of them together form the feasible set. The smallest objective value over the feasible set is the optimal value f*. A feasible point x* with f(x*) = f* is an optimal point, also called a solution or minimizer.
Two more names help. A feasible x with f(x) ≤ f* + ε is ε-suboptimal; solvers return such points, because they stop at a tolerance. An inequality with gi(x) = 0 is active at x: you are touching that fence. CO4A 4-1
The problem is a convex problem when f is convex, every gi is convex, and every hj is affine, so that all the equalities together read Ax = b. Why must equalities be affine? The rule h(x) = 0 is the same as two rules, h(x) ≤ 0 and −h(x) ≤ 0. Both are convex only when h is both convex and concave, which means affine. Tibshirani 2016 To maximize a concave function, minimize its negative instead.
The three parts of a convex problem in standard form. If any part breaks its rule, the theorems below no longer apply as written.
Worked example: maximize 3x + 2y subject to x + y ≤ 4, x ≤ 3, x ≥ 0 and y ≥ 0. In standard form it reads: minimize −3x − 2y subject to x + y − 4 ≤ 0, x − 3 ≤ 0, −x ≤ 0 and −y ≤ 0. Linear functions are both convex and affine, so this is a convex problem. The feasible set is a four-sided region with corners (0, 0), (3, 0), (3, 1) and (0, 4), where 3x + 2y is 0, 9, 11 and 8. The best point is (3, 1), with maximum 11, so f* = −11 in the minimize form. There the rules x + y ≤ 4 and x ≤ 3 are active, and x ≥ 0, y ≥ 0 are not. (Day 5 explains why a corner always wins here.)
A driving example in one dimension: a lane-keeping planner chooses a lateral offset d, in metres from the lane centre. It would like d = 0.8 to give a cyclist room, but the lane edge allows at most d = 0.5. In standard form: minimize (d − 0.8)2 subject to d − 0.5 ≤ 0. The answer is d* = 0.5 with the rule active, and f* = 0.09. Keep this example in mind for section 3.
2. Why local means global
Imagine walking downhill in thick fog. You can only feel the slope under your feet, so you stop when every step goes up. In a single round valley you are now at the bottom. In the Alps you might be standing in a small hollow halfway up a mountain.
A feasible x is a local optimum if no feasible point within some distance R > 0 is better: f(x) ≤ f(y) for all feasible y with ‖y − x‖2 ≤ R. It is a global optimum if no feasible point anywhere is better. For a convex problem, every local optimum is a global optimum. Tibshirani 2016Boyd & Vandenberghe 2004
The one-line reason: suppose some feasible y were better than a local optimum x. The straight segment from x to y stays feasible, because the feasible set is convex. Along it, f stays below the chord, because f is convex. So points on the segment just next to x are also better than x, and x was not a local optimum after all.
Worked example. The function f(x) = x4 − 3x2 + x is not convex. Its slope is zero at three points: x ≈ −1.301 (f ≈ −3.514, the global minimum), x ≈ 0.170 (a local maximum) and x ≈ 1.131 (f ≈ −1.070, a local minimum that is not global). Gradient descent from x = 2 with step 0.01 slides into the hollow at 1.131 and stops there. The convex function x2 + x has exactly one point of zero slope, x = −0.5, and that point is the global minimum.
Orange dots are the first gradient-descent steps from x = 2 (step 0.01). On the left they settle at the local minimum x ≈ 1.131, never seeing the deeper valley at x ≈ −1.301. On the right there is only one valley to find.
Two more facts. First, the set of all optimal points is convex: if x and y are both optimal, every point between them is too. For example, f(x) = max(|x| − 1, 0) is flat on [−1, 1], and that whole interval is optimal. Second, if f is strictly convex (no flat stretches), there is at most one optimal point. CO4A 4-2
Going deeper (optional): the local-equals-global proof
Let x be locally optimal with radius R, and suppose a feasible y has f(y) < f(x). Then ‖y − x‖2 > R. Take z = (1 − θ)x + θy with θ = R / (2‖y − x‖2), a point on the segment at distance R/2 from x. Since the feasible set is convex, z is feasible. Since f is convex, f(z) ≤ (1 − θ)f(x) + θf(y) < f(x). That contradicts local optimality. The full version is in Boyd & Vandenberghe §4.2.2. Boyd & Vandenberghe 2004
3. The first-order optimality condition
Back to the lane-keeping planner. At d* = 0.5 the slope of the cost is f′(0.5) = 2(0.5 − 0.8) = −0.6, not zero. The cost would keep falling if d could grow, but the lane edge stops it. Every allowed move goes to some y ≤ 0.5, and the predicted change f′(d*)(y − d*) = −0.6(y − 0.5) is never negative. So every allowed move goes uphill, and d* is optimal.
The general rule is the first-order optimality condition. Take a convex problem with a differentiable f and feasible set C. Then x is optimal exactly when x ∈ C and CO4A 4-3
∇f(x)T(y − x) ≥ 0 for every y ∈ C
Read ∇f(x)T(y − x) as "the first-order change in f when you start moving from x toward y". The condition says no feasible direction goes downhill. Picture it: −∇f(x) is the steepest-downhill arrow, and at the optimum it points out of C. The line through x at right angles to ∇f(x) is a supporting hyperplane of C: it touches C at x, and all of C lies on its uphill side. Boyd & Vandenberghe 2004
With no constraints at all (C = ℝn), y − x can point anywhere, including along −∇f(x). Then the condition becomes the familiar ∇f(x) = 0. Example: f(x) = ½xTQx + bTx with Q = diag(2, 4) and b = (−2, −8). Setting ∇f(x) = Qx + b to zero gives x* = (1, 2). Tibshirani 2016
Now a two-dimensional example with constraints. Minimize f(x) = (x1 − 3)2 + (x2 − 2)2 over the triangle x1 ≥ 0, x2 ≥ 0, x1 + x2 ≤ 2. The level sets of f are circles around the target (3, 2), which lies outside the triangle. The best point is the triangle's closest point to the target, x* = (1.5, 0.5), with f* = 1.52 + 1.52 = 4.5.
Check the condition. The gradient is ∇f(x*) = (2(1.5 − 3), 2(0.5 − 2)) = (−3, −3). For any y in the triangle:
∇f(x*)T(y − x*) = −3(y1 + y2 − 2) ≥ 0
It is non-negative because y1 + y2 ≤ 2. At the corner y = (0, 0) it equals 6, and anywhere on the edge x1 + x2 = 2 it equals 0. Compare a point that is not optimal, x = (1, 1), where f = 5 and ∇f = (−4, −2). Toward y = (2, 0) the product is −4·1 − 2·(−1) = −2 < 0. That direction goes downhill: the point (1.2, 0.8) has f = 4.68 < 5.
Try it: drag the orange target and watch x* and the arrow −∇f(x*). The pink half-plane holds the points y with ∇f(x)T(y − x) < 0, which lie downhill to first order. Then pick "a candidate point x" and drag x around; the widget shows the corner that goes most downhill.
Notice that with the target at (3, 2), the best point is x* = (1.5, 0.5), with f* = 4.5 and ∇f(x*) = (−3, −3), which is not zero. The arrow −∇f = (3, 3) points straight out through the edge x1 + x2 = 2. The smallest value of ∇f(x*)T(y − x*) over the triangle is 0, so the pink downhill side does not enter the triangle.
Analogy
A ball rolls downhill until a fence stops it. The slope still pulls it toward the fence, and the fence pushes back just as hard. The first-order condition says the ball has nowhere left to roll.
If the only constraints are equalities Ax = b, the condition becomes ∇f(x) + ATu = 0 for some vector u. This is the Lagrange condition from calculus, and its numbers u return as dual variables on Day 9 and in the KKT conditions on Day 10. Tibshirani 2016
Here is the triangle problem in CVXPY, a Python modelling tool you will see all course:
import cvxpy as cp
x = cp.Variable(2)
f = cp.sum_squares(x - [3, 2]) # bowl centred on the target (3, 2)
rules = [x >= 0, cp.sum(x) <= 2] # the triangle
prob = cp.Problem(cp.Minimize(f), rules)
prob.solve()
print(x.value, prob.value) # about [1.5 0.5] and 4.5
print(rules[1].dual_value) # about 3: how hard the edge pushes back
That last number, 3, is the fence's push. At x*, ∇f + 3·(1, 1) = (−3, −3) + (3, 3) = 0, so the slope and the push cancel.
4. Equivalent problems and slack variables
Equivalent problems are two problems where solving one quickly gives you a solution of the other. They can look very different, with different sizes or different smoothness. Boyd & Vandenberghe 2004 The rest of today is a toolbox of such rewrites, each used to make convexity visible or to fit what a solver accepts.
The simplest rewrite applies an increasing function to the objective. Minimizing ‖Ax − b‖2 and minimizing ‖Ax − b‖22 give the same x, because squaring a non-negative number keeps its order. Only the squared version is differentiable everywhere, which is why least squares uses it. CO4A 4-5
A slack variable turns an inequality into an equality by naming the leftover room. Think of an airline's 23 kg suitcase limit: the slack is how many kilograms you still have spare. In symbols: CO4A 4-7
gi(x) ≤ 0 ⇔ gi(x) + si = 0, si ≥ 0
Worked example: x + y ≤ 4 becomes x + y + s = 4 with s ≥ 0. At (3, 1), s = 0, so the rule is active. At (1, 1), s = 2: there are 2 units of room. In driving terms, a following-distance rule "gap ≥ 20 m" becomes 20 − gap + s = 0, and the slack s is the number of spare metres to the car ahead. Slacks are how linear programs reach their standard form on Day 5.
One warning. The new equality gi(x) + si = 0 is affine only if gi is affine. Add a slack to a curved rule such as x2 ≤ 1 and you get x2 + s = 1, a curved equality, and the problem stops being convex in standard form. CO4A 4-7
5. Epigraph form: move the objective into the rules
Think of the graph of f as a tent roof. Its epigraph is everything on or above the roof, as on Day 3. Finding the lowest point of the roof is the same as finding the lowest height t at which a point (x, t) still fits in the epigraph.
minimize t over (x, t) subject to f(x) − t ≤ 0, gi(x) ≤ 0, Ax = b
The objective is now linear, and all the curvature has moved into the constraints. If f is convex, f(x) − t ≤ 0 is a convex rule, so the new problem is still convex.
Worked example: minimize max(2x + 1, 4 − x). The objective has a kink where the two lines cross, so it is not differentiable there. In epigraph form it becomes: minimize t subject to 2x + 1 ≤ t and 4 − x ≤ t. That is a linear program. The two lines meet where 2x + 1 = 4 − x, so x = 1 and t = 3. In planning, the same trick turns "make the worst of several errors small" into a linear program.
The shaded epigraph holds every (x, t) with t ≥ both lines. Its lowest point, (1, 3), solves both the kinked problem and the linear program on the right.
6. Substitutions: change of variables and removing equalities
Some problems are convex in disguise. A change of variables x = φ(z), with φ one-to-one and covering the feasible set, gives an equivalent problem in z that may be visibly convex. CO4A 4-5
The classic case is the geometric program (GP). A monomial is γx1a1⋯xnan with γ > 0 and positive x. A posynomial is a sum of monomials, each with its own γ and exponents. A GP minimizes a posynomial subject to posynomials ≤ 1 and monomials = 1. With zi = log xi, each monomial becomes eaTz + log γ, the exponential of an affine function. The log of a posynomial becomes a log-sum-exp, which is convex. Tibshirani 2016
Worked example: minimize x + y subject to xy = 1, with x, y > 0. As written it is not a convex problem, because xy = 1 is a curved equality. Put u = log x and v = log y. The problem becomes: minimize eu + ev subject to u + v = 0. Now the objective is convex and the rule is affine. Setting v = −u leaves eu + e−u, smallest at u = 0. So x = y = 1, with value 2.
A second substitution removes equality constraints. Find one point x0 with Ax0 = b and a matrix M whose columns span the null space of A. Then every solution of Ax = b is x = Mz + x0, and you can minimize over a free z instead. CO4A 4-6
Worked example: minimize x12 + x22 subject to x1 + x2 = 2. Take x0 = (2, 0) and M = (1, −1)T, so (x1, x2) = (2 + z, −z). Minimize (2 + z)2 + z2: the derivative 2(2 + z) + 2z is zero at z = −1. So x* = (1, 1) and f* = 2. In large problems this trick is often a poor idea in practice, because M can be costly to compute. Tibshirani 2016 CO4A adds that the new problem can lose sparsity.
7. Optimize in stages, or loosen the rules
Partial optimization means minimizing over some variables first, then over the rest. If f(x, y) is jointly convex and C is convex, then g(x) = min over y ∈ C of f(x, y) is convex in x. So the outer problem is still convex. CO4A 4-4
Worked example: minimize (x − 2)2 + (y − x)2 with y ∈ [0, 1]. For a fixed x, the best y is the point of [0, 1] closest to x. For x ≥ 1 that is y = 1, leaving (x − 2)2 + (x − 1)2, smallest at x = 1.5. For x ≤ 1 the cost is at least 1, which is worse. So the solution is (x, y) = (1.5, 1), with value 0.5.
CO4A's main example is the support vector machine. Its slack variables can be minimized out by hand, which leaves the hinge function a+ = max{0, a} in the objective. A training point whose margin is 0.6, short of the target 1, is charged 1 − 0.6 = 0.4. CO4A 4-4
A relaxation loosens the rules: you solve over a bigger set C̃ ⊇ C. With more choices you can only do as well or better, so the relaxed optimal value is a lower bound on the true one. CO4A 4-8 Example: minimize (x − 0.3)2 with x ∈ {0, 1}, which is not a convex set. The answer is x = 0 with value 0.09. Relax to x ∈ [0, 1] and you get x = 0.3 with value 0, a lower bound but not the same answer. Branch and bound on Day 15 (branch-and-bound card) is built on exactly such bounds. CO4A also relaxes a convex but non-affine equality h(x) = 0 to h(x) ≤ 0.
Rewrite
What you do
Stays convex when
Today's example
Monotone transform
apply an increasing h to f
h(f) is convex, e.g. squaring a norm
‖Ax − b‖2 → ‖Ax − b‖22
Slack variable
g(x) ≤ 0 → g(x) + s = 0, s ≥ 0
g is affine
x + y + s = 4
Epigraph form
min t s.t. f(x) ≤ t
f is convex
max(2x + 1, 4 − x) → LP
Change of variables
x = φ(z), φ one-to-one
the new f and rules are convex
GP with z = log x
Remove equalities
x = Mz + x0
always (affine map)
(2 + z, −z) → (1, 1)
Partial optimization
min over y first
f jointly convex, C convex
(1.5, 1), value 0.5
Relaxation
enlarge the feasible set
gives a bound, not the same problem
{0, 1} → [0, 1]
Explain it to a 10-year-old
Put a marble in a salad bowl. Wherever you drop it, it rolls to the same bottom, because a bowl has only one dip. Now put a wall across the bowl. The marble rolls until it hits the wall and stops there. It still cannot get stuck anywhere else, because there are no hidden dips. Convex problems are bowls with walls.
Common misunderstandings
"At the optimum the gradient is zero." Only when the optimum is unconstrained or inside the feasible set. In the widget's default, ∇f(x*) = (−3, −3). The correct test is ∇f(x*)T(y − x*) ≥ 0 for all feasible y.
"A convex feasible set and a convex objective make a convex problem." The rules themselves must be convex gi and affine hj. The rules x1/(1 + x22) ≤ 0 and (x1 + x2)2 = 0 describe a convex set but break this test; rewritten as x1 ≤ 0 and x1 + x2 = 0, they pass. Boyd & Vandenberghe 2004
"A slack variable always keeps the problem convex." Only for affine rules. For a curved g, g(x) + s = 0 is a curved equality.
"The relaxed answer is the answer." It is a lower bound. It matches only in special cases, such as PCA, where Tibshirani shows the relaxation is exact. Tibshirani 2016
Check yourself
Q1. Which of these is a convex problem in standard form?
Only the third has a convex objective, convex inequalities and an affine equality. The last one is tempting, because −log x is convex, but x3 = 8 is a non-affine equality, so it is not in convex standard form. The second maximizes a convex function, which is not a convex problem.
Q2. At the optimum x* of a convex problem with a differentiable f, the arrow −∇f(x*)…
If −∇f pointed into the feasible set, you could follow it and lower f. In the triangle example −∇f(x*) = (3, 3) points out through the active edge. It is zero only for an interior optimum, so "always zero" is wrong.
Q3. A solver on a convex problem stops at a point where no small feasible step lowers f. What can you conclude?
For convex problems, local optimality implies global optimality. Restarting from several points is the habit from non-convex problems such as x4 − 3x2 + x, where gradient descent from x = 2 stops at a local minimum.
Q4. Rewrite x + 2y ≤ 5 with a slack variable.
The slack is the room left: s = 5 − x − 2y ≥ 0. The second option means x + 2y ≥ 5, the opposite rule. The last also forces x + 2y ≥ 5, and it is a curved equality besides.
Q5. What is the epigraph form of "minimize max(2x + 1, 4 − x)"?
t must sit above both lines, so t ≥ max(2x + 1, 4 − x). The lowest such t is 3, at x = 1. The first option puts t below the lines, so t can go to −∞. The second bounds the sum, not the maximum.
Q6. In a minimization, you relax x ∈ {0, 1} to x ∈ [0, 1]. The relaxed optimal value is…
A bigger feasible set can only help a minimization. For (x − 0.3)2 the relaxed value is 0 and the true value is 0.09. They are equal only in special cases.
Recap: things to remember
Standard form: minimize f(x) s.t. gi(x) ≤ 0, hj(x) = 0. It is convex when f and every gi are convex and every hj is affine.
In a convex problem every local minimum is global, the solution set is convex, and strict convexity means at most one solution.
x is optimal exactly when ∇f(x)T(y − x) ≥ 0 for all feasible y. Without constraints, that is ∇f(x) = 0.
Slack variables, epigraph form, changes of variables, removing equalities and partial optimization give equivalent problems. A relaxation gives a lower bound.
After today you can place a problem in the LP ⊂ QP ⊂ SOCP ⊂ SDP hierarchy and explain why that choice decides which solver you can use.
About 60 min · Needs Day 4 · CO4A chapter 5
Today's big idea
Convex problems come in nested families. Each family allows a richer kind of curvature, and each contains the one before it. Lower families can be handed to more solvers, including small ones built for just that form. So you place your problem in the lowest family that holds it.
1. Why sort problems into families?
When you ship a parcel, you pick the smallest container that fits: an envelope, a box, a padded box, or a climate-controlled crate. Everything fits in the crate, but the crate costs more and fewer carriers take it.
Convex problems are sorted the same way, by the kind of objective and constraints they use. CO4A orders the families like this, where ⊆ means "is a special case of": CO4A 5
LP ⊆ QP ⊆ QCQP ⊆ SOCP ⊆ SDP ⊆ conic
Why does the family matter? Modelling tools such as CVXPY rewrite your problem into a standard form, "e.g., LP, QP, SOCP, or SDP", and hand it to a solver built for that form. Boyd slides Fewer solvers handle each step up. In CVXPY's solver table, 31 solvers accept LPs, 25 accept QPs, 17 accept SOCPs and 9 accept SDPs (as of Oct 2026). CVXPY 2026
The rule of thumb follows: write your problem in the lowest family that holds it. That keeps the most solvers open to you, including the specialised ones built for simpler forms.
Each family is a special case of the one around it. Moving outward lets you model more, but fewer solvers accept the problem. Tibshirani's slides skip QCQP and write LP ⊆ QP ⊆ SOCP ⊆ SDP ⊆ conic. Tibshirani 2016
2. Linear programs: flat cost, flat walls
Tilt a flat tray with a marble on it. The marble rolls until it hits a wall, then slides along the wall into a corner. A linear program behaves the same way.
A linear program (LP) has an affine objective and affine constraints: CO4A 5-1
minimize cTx subject to Gx ⪯ h, Ax = b
Here c is the cost vector, and Gx ⪯ h means each entry of Gx is at most the matching entry of h. The feasible set is a polyhedron, a region cut out by finitely many flat walls. Its corners are vertices.
The key fact: if an LP has a solution and its polyhedron has at least one corner, then some vertex is optimal. The one-line reason: the level sets cTx = k are parallel lines (or planes). Slide one as far downhill as the region allows. The last part of the region it touches is a vertex, or a whole edge in a tie.
Worked example, the classic diet problem. Tibshirani 2016 Food 1 costs $2 per unit and gives 3 g of protein and 1 mg of a vitamin. Food 2 costs $3 per unit and gives 1 g of protein and 3 mg of the vitamin. You need at least 6 g of protein and 6 mg of the vitamin.
The region has three corners. At (0, 6) the cost is $18, at (6, 0) it is $12, and at (1.5, 1.5) it is $7.50. The optimum is 1.5 units of each food, where both nutrient rules are active.
Solvers often want one fixed layout, the standard form LP: minimize cTx subject to Ax = b and x ⪰ 0. You reach it with two tricks. Add a slack (Day 4) to each inequality, so Gx ⪯ h becomes Gx + s = h with s ⪰ 0. Split each free variable into two non-negative parts, x = x+ − x−. Boyd & Vandenberghe 2004 The simplex and interior-point methods (Day 12) work on this form.
Try it: the widget's polygon is x ≥ 0, y ≥ 0, x ≤ 3, x + y ≤ 4 and x + 2y ≤ 6. It maximizes cTx for the direction c = (cos θ, sin θ), which is the same as minimizing (−c)Tx. Slide θ and watch the best corner. Then switch to the QP mode and drag the target.
Notice that at θ = 30° the best corner is (3, 1), where cTx = 3.1. Slide θ past 45° and the optimum jumps to (2, 2); past 63.43° it jumps to (0, 3). Exactly at 45°, c is at right angles to the edge x + y = 4, and every point of that edge ties. The optimum jumps whenever c lines up with an edge's outward direction.
A hand check: maximize 3x + 2y over the same polygon. Its corners give 0, 9, 11, 10 and 6, so (3, 1) wins with 11. The direction (3, 2) has angle 33.7°, inside the 0° to 45° range where the widget picks (3, 1).
Analogy
An LP is a marble on a tilted tray: it always ends up in a corner. A QP is a marble in a round-bottomed bowl set on the tray: it settles at the bowl's lowest point, unless a wall gets in the way first. That is why LP solvers can hop from corner to corner, and QP solvers cannot.
3. Quadratic programs: a bowl on the tray
Keep the flat walls but make the cost curved. A quadratic program (QP) is CO4A 5-2
minimize ½xTPx + qTx subject to Gx ⪯ h, Ax = b
The matrix P must be symmetric and positive semidefinite, written P ⪰ 0: uTPu ≥ 0 for every vector u, or equally, every eigenvalue of P is at least 0. That makes the cost a convex bowl. If P has a negative eigenvalue, the cost bends down in some direction and the problem is no longer convex. Tibshirani 2016 Setting P = 0 gives back an LP, so LP ⊆ QP.
The bowl changes where the optimum can sit. In the widget's QP mode the cost is ½‖x − p‖22, a round bowl centred on a target p. With p = (1, 1) the bowl's bottom is inside the polygon, so x* = (1, 1) and f* = 0. With p = (3.5, 2), the wall x + y ≤ 4 stops it at (2.75, 1.25), the middle of an edge, with f* = 0.5625. With p = (3, 3) it lands on the corner (2, 2), with f* = 1. So a QP optimum can sit inside, on an edge, or at a corner.
A driving example: smooth speed planning. A car is moving at 20 m/s, and a school zone 4 seconds ahead has a 10 m/s limit. The planner picks speeds v1, …, v4 at one-second steps. Harsh braking is uncomfortable, so it penalizes each squared speed change, which is the squared acceleration:
This is a QP: a sum of squares as the cost, one linear rule. The four speed changes must add up to at least −10 m/s, and squares punish big numbers, so the best plan splits the drop evenly. The answer is v = (17.5, 15, 12.5, 10), a steady 2.5 m/s² deceleration, with cost 4 × 2.52 = 25. Braking all at once, v = (20, 20, 20, 10), costs 102 = 100, four times as much. Real planners add speed tracking, jerk and many more steps, but the shape stays a QP. This is the heart of model predictive control on Day 17.
import cvxpy as cp
v = cp.Variable(4) # speeds at t = 1, 2, 3, 4 s
cost = cp.square(v[0] - 20) + cp.sum_squares(cp.diff(v))
prob = cp.Problem(cp.Minimize(cost), [v[3] <= 10, v >= 0])
prob.solve(solver=cp.OSQP) # a QP solver is enough
print(v.value) # about [17.5 15. 12.5 10.]
Many familiar problems are QPs: least squares with linear constraints, the lasso, support vector machines, and Markowitz portfolios. Tibshirani 2016 OSQP, a solver built for exactly this form, is the subject of the OSQP paper card.
4. QCQP: curved walls
Now let the walls curve too. A robot vacuum must stay within 1 m of its dock; that rule is a disc, not a polygon. A QCQP (quadratically constrained quadratic program) allows convex quadratic rules: CO4A 5-3
minimize ½xTP0x + q0Tx + r0 s.t. ½xTPix + qiTx + ri ≤ 0, Ax = b
Every Pi must be positive semidefinite, so each rule describes an ellipse-shaped region (an ellipsoid in higher dimensions). Setting Pi = 0 in the rules gives back a QP, so QP ⊆ QCQP.
Worked example: minimize ‖x − (2, 2)‖22 subject to ‖x‖22 ≤ 1. The target (2, 2) lies outside the unit disc, so the answer pulls it straight back to the circle: x* = (2, 2)/‖(2, 2)‖2 = (0.7071, 0.7071). The cost there is 2 × (2 − 0.7071)2 = 3.343.
In practice a QCQP rarely gets its own solver. CVXPY's target forms are LP, QP, SOCP and SDP, so a convex QCQP is rewritten as an SOCP, the next family up. Boyd slides
5. Second-order cone programs: length limits
Picture an ice-cream cone standing on its tip. The higher you go, the wider it gets. That shape is the second-order cone, the set of points (x, t) with ‖x‖2 ≤ t. Some books call it the ice-cream cone.
A second-order cone program (SOCP) has a linear cost and rules of the form "a length must stay below a linear budget": CO4A 5-4Boyd & Vandenberghe 2004
minimize fTx s.t. ‖Aix + bi‖2 ≤ ciTx + di, Fx = g
Each rule says the point (Aix + bi, ciTx + di) lies inside a second-order cone. With Ai = 0 and bi = 0, a rule becomes an ordinary linear inequality, so LP ⊆ SOCP.
A driving example: the friction circle. A simple tyre model says the total horizontal acceleration a = (alon, alat) is limited by grip, ‖a‖2 ≤ μg. With friction μ = 0.8 and g = 9.81 m/s², the limit is 7.85 m/s². Braking at 6 m/s² while turning at 4 m/s² uses √(36 + 16) ≈ 7.2 m/s², which is allowed. A box rule |alon| ≤ 7.85, |alat| ≤ 7.85 is linear, but it permits the corner (7.85, 7.85), whose length is 11.1 m/s². That is about 41% more grip than the tyres have.
Left: an SOCP rule asks a point to stay inside this cone. Right: the green disc is the grip limit, a second-order cone rule. The green point (6 m/s² braking, 4 m/s² lateral, length 7.2) is allowed. The dashed box is the linear stand-in; its corner has length 11.1 and would ask for more grip than exists.
A second classic SOCP is the robust LP, an LP whose rules must hold for every value of an uncertain coefficient. Boyd & Vandenberghe 2004 Worked example: maximize x1 + x2 subject to aTx ≤ 2 for every a in the disc {(1, 1) + 0.5u : ‖u‖2 ≤ 1}, with x ⪰ 0.
The worst a turns (1, 1)Tx into (1, 1)Tx + 0.5‖x‖2, because uTx is largest when u points along x. So the rule becomes x1 + x2 + 0.5‖x‖2 ≤ 2, an SOC rule. Without uncertainty the best value of x1 + x2 is 2. With it, the best point is x1 = x2 = 0.7388, so x1 + x2 = 1.4776. Being safe for every a in the disc costs about 26%.
Why is a QCQP also an SOCP? A convex quadratic rule can always be rewritten as a length rule. The simplest case: ‖x‖22 ≤ 1 is the same set as ‖x‖2 ≤ 1. The general identity is in the box below. SOCPs also run rockets: powered-descent guidance for landing is solved as an SOCP after a convexification trick, as the lossless convexification paper card explains.
Going deeper (optional): turning a quadratic rule into a cone rule
For Q ⪰ 0, the rule ½xTQx ≤ t holds exactly when ‖(Q½x/√2, (1 − t)/2)‖2 ≤ (1 + t)/2. Square both sides to check: the left gives ½xTQx + (1 − t)2/4, the right gives (1 + t)2/4, and their difference is t − ½xTQx. Apply it to the objective with an epigraph variable t (Day 4) and to each quadratic rule, and any convex QCQP becomes an SOCP. Tibshirani 2016 CO4A 5-4 gives a longer route through eigendecompositions.
6. Semidefinite programs: matrices that never bend the wrong way
An LP asks every number in a list to be non-negative. A semidefinite program asks a whole symmetric matrix to be positive semidefinite: all its eigenvalues non-negative, so uTXu ≥ 0 in every direction u. Think of a bowl that curves up, or stays flat, in every direction and never curves down.
A linear matrix inequality (LMI) is a rule x1F1 + … + xnFn + G ⪯ 0, where the Fi and G are symmetric matrices and "⪯ 0" means negative semidefinite (all eigenvalues ≤ 0). A semidefinite program (SDP) is CO4A 5-5Boyd & Vandenberghe 2004
minimize cTx s.t. x1F1 + … + xnFn + G ⪯ 0, Ax = b
The standard form uses a matrix variable X: minimize tr(CX) subject to tr(AiX) = bi and X ⪰ 0, where tr is the trace, the sum of the diagonal. If every Fi and G is diagonal, the LMI is just n separate linear inequalities, one per diagonal entry. So LP ⊆ SDP.
Worked example: make the largest eigenvalue of a matrix as small as possible. Write matrices row by row, with rows separated by semicolons.
A(x) = [2 + x, 1; 1, −x]
The rule λmax(A(x)) ≤ t is the same as A(x) − tI ⪯ 0, an LMI in (x, t). So "minimize t subject to A(x) − tI ⪯ 0" is an SDP. Here the eigenvalues are 1 ± √(1 + (x + 1)2), so the largest is smallest at x = −1, with t* = 2. At x = 0 it would be 1 + √2 ≈ 2.414.
Every SOCP is also an SDP, through a matrix test called the Schur complement: Tibshirani 2016
‖x‖2 ≤ t ⇔ [tI, x; xT, t] ⪰ 0
Check it with x = (3, 4), whose length is 5. At t = 5 the block matrix has eigenvalues 0, 5 and 10: positive semidefinite, right on the boundary. At t = 4.9 they are −0.1, 4.9 and 9.9: not positive semidefinite, matching 5 > 4.9.
SDPs reach robotics too. Robot mapping (pose-graph SLAM) has an SDP relaxation that can certify a map is globally optimal; see the SE-Sync paper card.
7. Conic programs, and choosing a solver
All these families fit one template. A cone K is a set that stays inside itself when you scale by any α ≥ 0. The generalized inequality u ⪯K v means v − u lies in K. A conic program is CO4A 5-6
minimize cTx s.t. Fx + g ⪯K 0, Ax = b
Choose K = ℝ+n, the non-negative numbers, and you get an LP. Choose a product of second-order cones and you get an SOCP. Choose the cone of positive semidefinite matrices and you get an SDP. Solvers such as SCS and Clarabel work in this form. They also accept an exponential cone, which handles log and exp terms like the geometric programs of Day 4. CVXPY 2026
To place a problem, read its pieces from the bottom of the ladder up, and stop at the first family that fits:
Some rules convex quadratic → QCQP, solved as an SOCP.
Rules like "‖Ax + b‖2 ≤ cTx + d", or worst cases over a ball → SOCP.
Eigenvalues, matrix variables that must be ⪰ 0, matrix norms → SDP.
Here is what that choice means in practice. The table lists a few solvers from CVXPY's solver table, as of Oct 2026. CVXPY 2026
Solver (as of Oct 2026)
LP
QP
SOCP
SDP
Notes
GLPK, GLOP
✓
–
–
–
LP only
OSQP
✓
✓
–
–
ships with CVXPY; built for QPs
ECOS
✓
✓
✓
–
also the exponential cone
Clarabel, SCS
✓
✓
✓
✓
ship with CVXPY; also exp and power cones
MOSEK
✓
✓
✓
✓
commercial; installed separately
All 31 solvers in the table
31
25
17
9
count that accept each family
So the speed plan (a QP) can run on OSQP, the friction-circle plan (an SOCP) needs an SOCP solver such as ECOS or Clarabel, and the eigenvalue problem (an SDP) needs an SDP solver such as SCS, Clarabel or MOSEK. Writing a QP as an SDP would still give the right answer. It would just close the door on most of the table.
Explain it to a 10-year-old
Think of puzzles with harder and harder pieces. The easiest puzzles have only straight-edged pieces. Then come pieces with one curved side, then round pieces, then pieces that are whole shapes inside shapes. A person who can do the hardest puzzles can also do the easy ones, but it takes them longer. So you give each puzzle to the fastest person who can solve it.
Common misunderstandings
"A QP optimum is always at a corner." That is an LP property. In the widget's QP mode, p = (1, 1) gives an interior optimum and p = (3.5, 2) gives one in the middle of an edge, at (2.75, 1.25).
"An LP has exactly one solution." When c is at right angles to an edge, the whole edge ties. In the widget, θ = 45° makes every point from (3, 1) to (2, 2) optimal.
"Any ½xTPx + qTx is a QP." Only with P ⪰ 0. If P has a negative eigenvalue the problem is non-convex. Tibshirani 2016
"Send everything to an SDP solver, since SDP is the most general." You get the same answer, but only from far fewer solvers (9 of 31 in CVXPY's table, as of Oct 2026), and you give up the specialised ones.
"‖x‖2 ≥ t is an SOC rule too." Only ‖x‖2 ≤ t is. The set ‖x‖2 ≥ t is the outside of the cone, which is not convex; "stay at least 2 m from the obstacle" is such a rule, and Day 19 shows how to handle it.
Check yourself
Q1. An LP minimizes cTx (with c ≠ 0) over a bounded polygon. Where is the optimum?
Slide the level line cTx = k as far as you can; the last thing it touches is a corner or an edge. "Exactly one vertex" is tempting but fails in ties, such as θ = 45° in the widget.
Q2. Which family is the lowest that holds "minimize ‖Ax − b‖22 subject to x ⪰ 0"?
‖Ax − b‖22 = xTATAx − 2bTAx + bTb, a convex quadratic with P = 2ATA ⪰ 0, and the rules are linear. It is not an LP because the cost is curved. An SDP solver could solve it, but it is not the lowest family.
Q3. An LP rule aTx ≤ 2 must now hold for every a in a disc around (1, 1). What does the problem become?
The worst case over the disc adds a norm term: (1, 1)Tx + 0.5‖x‖2 ≤ 2. That is a second-order cone rule, so the robust LP is an SOCP. Nothing became quadratic in the cost, so it is not a QP.
Q4. In an SDP, every matrix Fi and G is diagonal. What is the problem really?
A diagonal matrix is ⪯ 0 exactly when each diagonal entry is ≤ 0, and each entry is affine in x. So the LMI splits into separate linear inequalities, and the problem is an LP.
Q5. Why place a problem in the lowest family that fits?
A problem has the same answer whichever family you write it in. What changes is which solvers you can use. SDP solvers can solve LPs, but far fewer of them exist.
Q6. The rule ‖(3, 4)‖2 ≤ t is written as the LMI [tI, x; xT, t] ⪰ 0 with x = (3, 4). What is the smallest t that satisfies it?
The Schur complement makes the LMI the same rule as ‖x‖2 ≤ t, and ‖(3, 4)‖2 = 5. At t = 5 the eigenvalues are 0, 5 and 10. 7 is the sum 3 + 4 (the ‖·‖1 length), and 25 is the squared length.
Recap: things to remember
LP ⊆ QP ⊆ QCQP ⊆ SOCP ⊆ SDP ⊆ conic: each family is a special case of the next.
LP: linear everything, optimum at a vertex or tied edge. QP: convex quadratic cost (P ⪰ 0), optimum can also sit inside or mid-edge.
SOCP: "length ≤ linear budget" rules, such as the friction circle and robust LPs. SDP: a matrix must be positive semidefinite.
Pick the lowest family that holds your problem; that decides how many solvers, and which fast ones, you can use.
After today you can run gradient descent, choose a step size (fixed, backtracking or exact line search), read its O(1/k) and linear convergence rates, and explain why stochastic gradient descent powers machine learning.
About 60 min · Needs Day 3 · CO4A chapter 6
Today's big idea
Gradient descent repeats one move: feel the slope, take a step downhill, feel again. Two numbers decide how well it works. One is the step size t, which you choose. The other is the condition number κ, which measures how stretched the bowl is. Choose t well and the method is simple, cheap and reliable. Choose it badly and it crawls, zig-zags or blows up.
1. The update: walk downhill
Picture yourself on a hillside in thick fog. You cannot see the valley, but you can feel which way the ground tilts under your feet. A sensible plan is to step in the steepest downhill direction, stop, feel the ground again, and repeat. That loop is the whole algorithm.
On Day 3 you met the gradient ∇f(x), the vector of slopes of f at x. It points in the direction where f rises fastest, so −∇f(x) points where f falls fastest. Gradient descent starts at a point x0 and repeats one line: CO4A 6-1
xk+1 = xk − t∇f(xk)
Here xk is the point after k steps. The number t > 0 is the step size; machine learning calls it the learning rate. Steps are long where the ground is steep and short where it is flat, because ∇f itself shrinks near the bottom. You stop when ‖∇f(xk)‖2 is tiny.
There is a second way to read the same rule. At x, gradient descent trusts the tangent plane of f, but it charges a fee for moving far from x. The next point minimizes that "tangent plane plus fee" model: Tibshirani 2016
Set the derivative in y to zero and you get x+ = x − t∇f(x) again. A small t means a big fee, so the steps are cautious. A big t means you trust the tangent plane far away, which is risky because f curves.
Here is today's running example. Take f(x, y) = ½(x² + 10y²), a bowl ten times steeper in y than in x. Its gradient is ∇f = (x, 10y). From the start (10, 1) the gradient is (10, 10). With t = 0.1 the next point is (10 − 1, 1 − 1) = (9, 0). The steep y-direction is solved in one step. After that each step multiplies x by 0.9: 8.1, 7.29, 6.56, and so on. Boyd & Vandenberghe 2004
One step of gradient descent on f = ½(x² + 10y²) with t = 0.1. The gradient (dashed) is at right angles to the contour line and points uphill. The step (red) is −t∇f = (−1, −1). After it, every step shrinks x by the same factor 0.9 on the way to the minimum x* = (0, 0).
Explain it to a 10-year-old
You are blindfolded on a big slide and want to reach the bottom. You feel with your foot which way is down, take one step that way, and feel again. Big steps get you there faster, but if they are too big you jump right over the bottom and land higher up on the other side.
2. Fixed step size and the 2/L cliff
Think of a shower knob. Tiny turns take forever to warm the water. Big turns overshoot to scalding, then to freezing, and each swing can be worse than the last. A fixed step, the same t at every iteration, has the same two failure modes.
The safe range depends on how sharply the bowl can curve. A function is L-smooth (its gradient is L-Lipschitz) if the gradient never changes faster than L: CO4A 6-3-1
‖∇f(x) − ∇f(y)‖2 ≤ L‖x − y‖2
For a twice-differentiable f this means ∇2f(x) ⪯ LI: no direction curves more than L. So L is the steepest curvature of the bowl. Our example curves by 1 in x and by 10 in y, so L = 10.
Why does trouble start at t = 2/L? On our bowl the two coordinates update separately, each multiplied by its own factor:
xk+1 = (1 − t)·xk yk+1 = (1 − 10t)·yk
A coordinate shrinks only if its factor lies strictly between −1 and 1. For y that means 0 < t < 2/10. In general, on a quadratic every curvature λ between the smallest and L gives a factor 1 − tλ, and all of them are safe exactly when 0 < t < 2/L. CO4A 6-2-1
The sign of the factor tells the story, as the figure shows. Between 0 and 1, the coordinate creeps toward 0 from one side. Between −1 and 0, it jumps across the valley floor and back, but each jump is shorter. Below −1, each jump is longer, and the iterates fly away. At t = 2/L exactly the factor is −1, and y flips between +1 and −1 forever.
The steep coordinate of f = ½(x² + 10y²), starting at y = 1, for three fixed steps. Here L = 10, so 2/L = 0.2 is the cliff: 0.19 still settles, 0.21 explodes.
Here are the real counts from (10, 1), stopping when f ≤ 10−6. The best fixed step sits in the middle of the safe window, not at its edge.
Step t
x factor
y factor
Iterations to f ≤ 10⁻⁶
0.01
0.99
0.9
882 (crawls)
0.05
0.95
0.5
173
0.1 = 1/L
0.9
0
85
2/11 ≈ 0.182
0.818
−0.818
45 (best fixed step)
0.19
0.81
−0.9
74 (zig-zags)
0.2 = 2/L
0.8
−1
never: f stalls at 5
0.21
0.79
−1.1
diverges: f > 10¹² at iteration 137
The best fixed step is t = 2/(m + L), where m is the smallest curvature (here m = 1). It balances the two coordinates so that both shrink by the same factor, (κ − 1)/(κ + 1) = 9/11 per step, where κ = L/m. CO4A 6-3-4 The catch: on a real problem you rarely know m or L. So the next section lets the algorithm find t by itself.
3. Let the algorithm choose t: backtracking and exact line search
Think of reversing into a parking spot. You start with a bold move. If you are about to hit the curb, you ease off and try a shorter one. Backtracking line search does exactly this at every iteration.
Fix two numbers, α and β. At each iteration let g = ∇f(x), start with t = 1, and shrink t ← βt as long as Tibshirani 2016
f(x − tg) > f(x) − α·t·‖g‖22
As soon as the inequality is false, you take the step x+ = x − tg. The inequality you are waiting for, f(x − tg) ≤ f(x) − αt‖g‖², is called the sufficient-decrease or Armijo condition.
What do α and β mean? The tangent line predicts that a step of length t lowers f by t‖g‖². That is too hopeful, because f curves upward. Boyd and Vandenberghe read α as the fraction of that predicted drop you insist on getting. With α = 0.3 you say "give me at least 30% of what the tangent line promised." β is how hard you cut t after a failure; β = 0.5 halves it. Boyd & Vandenberghe 2004
They take 0 < α < 0.5 and 0 < β < 1, and report typical values of α between 0.01 and 0.3 and β between 0.1 and 0.8. Conventions differ a little: Tibshirani's slides and CO4A also allow α = ½, and this lesson's example uses α = β = ½. CO4A 6-2-2
The first backtracking step from (10, 1) with α = β = ½. Each trial point must land on or below the green accept line. The first trial, t = 1, gives f = 405, far above the chart.
Here is that first step by hand. At (10, 1) we have f = 55, g = (10, 10) and ‖g‖² = 200. With α = ½ the test asks for f(x − tg) ≤ 55 − 100t.
t = 1: f = 405, but we need at most −45. Shrink.
t = 0.5: f = 92.5, but we need at most 5. Shrink.
t = 0.25: f = 39.4, but we need at most 30. Shrink.
t = 0.125: f = 38.6 ≤ 42.5. Accept, and move to x1 = (8.75, −0.25).
The very next step accepts t = 0.5, which is bigger than 2/L = 0.2, and nothing breaks. The test checks each step before it is taken, so an occasional bold step is safe. The full run needs 30 iterations plus 77 rejected trial points. It keeps the O(1/k) guarantee of Section 4, with t replaced by tmin = min{1, β/L}. CO4A 6-3-3
Exact line search goes one step further. Along the downhill ray, it jumps straight to the lowest point: CO4A 6-2-3
t = argmins ≥ 0 f(x − s∇f(x))
For a quadratic with Hessian H this has a formula, t = gTg / gTHg. From (10, 1) it gives t = 200/(100 + 1000) = 2/11 at every step. The iterates follow xk = 10(9/11)k and yk = (−9/11)k, so f drops by (9/11)² ≈ 0.669 per step and needs 45 iterations. This is Boyd and Vandenberghe's own example. Boyd & Vandenberghe 2004
Exact search matched the best fixed step here, but each step required solving a small optimization problem. For a general f that inner problem is expensive, so exact search is rarely worth it. Backtracking gets most of the benefit for a few extra function evaluations. Tibshirani 2016 The whole method fits in a few lines (see the gradient descent card):
def gradient_descent(f, grad, x, alpha=0.5, beta=0.5, tol=1e-6):
while True:
g = grad(x)
if norm(g) <= tol: # flat enough: stop
return x
t = 1.0
while f(x - t*g) > f(x) - alpha*t*(g @ g):
t = beta * t # backtrack: shorter step
x = x - t*g # the gradient step
Try it: start with the default (κ = 10, t = 1/L), then switch the rule to each option and watch the path and the bars. Next, slide κ up to 100 and see every rule slow down. Tap the plot to start somewhere else.
Notice: from (10, 1) at κ = 10, t = 1/L needs 85 iterations, the best fixed step 2/(1+L) and exact line search 45 each, and backtracking (α = β = ½) 30 plus 77 rejected trials. At 2/L, f stalls at 5. At 2.1/L it diverges at iteration 137. On the log chart every converging rule is close to a straight line.
4. How fast? O(1/k), linear rates and the condition number
There are two speed guarantees. A weak one holds for every smooth convex bowl. A strong one holds for bowls that curve upward in every direction.
The weak guarantee rests on a picture. If f is L-smooth, then at any point x a steep bowl of curvature L sits on top of f and touches it at x. That is the quadratic upper bound: CO4A 6-3-2
f(y) ≤ f(x) + ∇f(x)T(y − x) + (L/2)‖y − x‖22
With t ≤ 1/L the step goes downhill on that upper bowl, so f falls by at least (t/2)‖∇f(x)‖² at every step. Adding up these drops gives the theorem for convex, L-smooth f: CO4A 6-3-1
f(xk) − f* ≤ ‖x0 − x*‖22 / (2tk)
Here x* is a minimizer and f* = f(x*). The error falls like a constant over k, written O(1/k) and called a sublinear rate. To guarantee an error ε you need about 1/ε iterations, so one more correct digit costs ten times more steps.
On our bowl, t = 0.1 and ‖x0 − x*‖² = 101, so the bound is 505/k. Taken at face value it promises 10−6 only after 5.05 × 108 steps. The actual run needs 85. The bound covers the worst smooth convex function; our bowl is much kinder, because it is also strongly convex.
A function is strongly convex with parameter m > 0 if a shallow bowl of curvature m fits underneath it at every point: f(y) ≥ f(x) + ∇f(x)T(y − x) + (m/2)‖y − x‖22. For twice-differentiable f this is ∇2f ⪰ mI. Then every step removes a fixed share of the remaining error: CO4A 6-3-4
f(xk) − f* ≤ ck·(L/2)‖x0 − x*‖22, 0 < c < 1
This is linear convergence: on a log plot the error is a straight line. Reaching ε needs O(log(1/ε)) iterations, so each extra digit costs the same number of steps. For t = 1/L, CO4A's proof gives c = 1 − m/L. On our bowl c = 0.9, and the bound reaches 10−6 by iteration 191. The real error is 50·0.81k, which gets there at 85.
Guarantee versus reality on f = ½(x² + 10y²) with t = 1/L. The O(1/k) bound is true but nearly flat on a log scale. Strong convexity gives a straight line, and the real run is steeper still.
The condition number κ = L/m is the ratio of the steepest curvature to the flattest. It measures how stretched the bowl is. In a round bowl (κ = 1) the downhill arrow points straight at the bottom, and one step of t = 1/L lands on it. In a long narrow canyon the arrow points mostly at the nearest wall, not along the floor. So gradient descent bounces from wall to wall while it creeps along the floor. That bouncing is the zig-zag. Boyd & Vandenberghe 2004
The widget's κ slider shows the cost. From (10, 1), iterations to f ≤ 10−6:
κ
t = 1/L
t = 2/(1+L)
Backtracking (½, ½)
1
1
1
1
2
13
9
2
10
85
45
30
50
439
227
186
100
882
461
327
The count grows roughly in proportion to κ, as Boyd and Vandenberghe's analysis predicts. Boyd & Vandenberghe 2004 Large κ often comes from badly scaled variables. Say a path planner's cost is ½(e² + 100θ²), with lateral error e in metres and heading error θ in radians. Its curvatures are 1 and 100, so κ = 100 even though nothing is wrong with the model. Measuring heading in a new unit, θ′ = 10θ, gives ½(e² + θ′²), a round bowl that one step solves. Day 11's Newton method does this kind of rescaling automatically, using the Hessian.
When should you stop? You cannot measure f − f* directly, but you can measure the gradient. For m-strongly convex f, ‖∇f(x)‖2 ≤ √(2mε) guarantees f(x) − f* ≤ ε. With m = 1 and ε = 10−6, stop once ‖∇f‖ ≤ 1.41 × 10−3. The catch is that you usually do not know m. Boyd & Vandenberghe slides
Analogy
A marble in a round salad bowl rolls straight to the middle. A marble dropped on the side of a long gutter first rolls across, overshoots up the other side, rolls back, and only slowly drifts along the gutter. Gradient descent in a bowl with large κ behaves like that marble in the gutter, except it has no momentum to smooth the trip. Adding momentum is the idea behind Day 8's acceleration.
Common misunderstandings
"A bigger step is always faster." Only up to the middle of the window. At κ = 10, t = 0.19 needs 74 iterations, t = 0.2 never settles and t = 0.21 blows up.
"Zig-zag means a bug." It is what gradient descent does in a stretched bowl. It is the condition number talking, not your code.
"Backtracking's t must stay below 1/L." It changes every step and can be larger: t = 0.5 is accepted on a bowl with L = 10, because each step is checked first.
"The O(1/k) bound predicts the iteration count." It is a worst-case promise. It says 505/k; the real run reached 10−6 in 85 steps.
"Exact line search beats κ." From (10, 1) it looks fast at κ = 50 (41 iterations) only because that start sits near the long axis. From the worst start (κ, 1) it needs 263 iterations at κ = 50 and 559 at κ = 100.
Going deeper (optional): why the error falls like 1/k
Write g = ∇f(x) and x+ = x − tg with t ≤ 1/L. Put y = x+ in the quadratic upper bound: f(x+) ≤ f(x) − t(1 − Lt/2)‖g‖² ≤ f(x) − (t/2)‖g‖². Convexity gives f(x) ≤ f* + gT(x − x*). Combine the two and complete the square:
f(x+) − f* ≤ (‖x − x*‖² − ‖x+ − x*‖²)/(2t)
Add this up over k steps. The right side telescopes to at most ‖x0 − x*‖²/(2t). Since f never goes up, the last error is at most the average, which gives the bound ‖x0 − x*‖²/(2tk). CO4A 6-3-1 writes out every line. Boyd and Vandenberghe (pp. 466–468) prove the linear rate, with c = 1 − m/L for exact search and an explicit c for backtracking.
5. Can we do better?
Picture a speed-limit sign for a whole family of methods. A first-order method learns about f only through gradients. Each new point lies in x0 plus the span of the gradients seen so far. Gradient descent is one such method, but there are cleverer ones.
Nesterov proved a lower bound for this whole family. For any k ≤ (n − 1)/2 and any start, there is an L-smooth convex function on ℝn where every first-order method has CO4A 6-3-6Tibshirani 2016
f(xk) − f* ≥ 3L‖x0 − x*‖22 / (32(k + 1)2)
So no first-order method can beat a rate of 1/k² on the worst functions. Gradient descent only guarantees 1/k, which leaves a gap. Put in our numbers, L = 10 and ‖x0 − x*‖² = 101. At k = 10 the unavoidable error is 0.78, while gradient descent's guarantee is 50.5. The lower bound is about hard functions in many dimensions, not about our 2-D bowl.
The gap is real. Accelerated gradient methods reach O(1/k²), that is O(1/√ε) iterations. For ε = 10−6 that is on the order of a thousand steps instead of a million. That is Day 8 (see the FISTA card). Two other limits of plain gradient descent point to other days. It needs a gradient, so kinks like |x| need Day 7's subgradients. And it ignores curvature, which Day 11's Newton method uses.
6. Gradient boosting: gradient descent on predictions
Picture a line of tutors. Each one looks only at the mistakes the earlier tutors left behind and tries to fix those. Boosting builds simple models one after another, each fitting what the current team still gets wrong. Bagging, by contrast, trains many models independently on resampled data and averages them. CO4A 6-4
Boosting is gradient descent in disguise. Treat the vector of predictions u = (u1, …, un) on the n training points as the variable, with total loss Σi L(yi, ui). A gradient step on u would move along di = −∂L(yi, ui)/∂ui. But the model must also predict new points, so you fit a small tree Tk to d by least squares and step along the tree instead: Tibshirani 2016
u(k) = u(k−1) + αk·Tk
Here αk is the boosting step size (not the backtracking α). The final model is a weighted sum of trees, which is what gradient boosting is. Take two points with labels y = (3, 5), a first guess u(0) = (4, 4), and squared loss ½(y − u)². Then d = y − u = (−1, 1), which is just the residuals. A one-split tree that separates the two points matches d exactly. With α = 1 you get u(1) = (3, 5), a perfect fit. For squared loss, "fit the residuals" and "follow the negative gradient" are the same move. Other losses, such as the logistic loss, only change d.
7. Stochastic gradient descent: why machine learning runs on it
Imagine asking for directions. You could survey the whole town before every step, or you could ask one random passer-by. One answer is noisy, but you get a thousand of them for the price of one survey.
Most learning objectives are sums with one term per training example: f(x) = Σi=1..m fi(x). A batch method such as plain gradient descent needs all m gradients for every step. Stochastic gradient descent (SGD) uses just one: Tibshirani 2016CO4A 6-5
xk+1 = xk − tk∇fik(xk)
The index ik follows the cyclic rule (1, 2, …, m, 1, 2, …) or the randomized rule (uniform at random), and the random one is more common. In cost, m stochastic steps equal about one batch step. When there are 500 million examples, that difference decides whether training is possible at all. The rule of thumb is that SGD thrives far from the optimum and struggles close to it. Tibshirani 2016 (SG)
Why does it struggle near the end? Near x* the individual gradients ∇fi disagree, even though their sum is zero. With a fixed step each one keeps kicking the iterate, so it hovers in a cloud around x*. The theory matches: a fixed step only promises to get within a band around f* whose width grows with t. Steps that shrink, with Σtk = ∞ but Σtk² < ∞ (for example tk = 1/k), close the band. These are called diminishing step sizes or step-size decay. Tibshirani 2016 (SG)
A tiny example shows both behaviours. Let f(x) = Σ ½(x − ai)² with a = (1, 2, 3, 6), so x* = 3, the mean. Batch gradient descent with t = 0.25 from 0 lands on 3 in one step. Cyclic SGD with a fixed t = 0.25 visits 0.25, 0.69, 1.27, 2.45 in its first pass. After 200 passes it is still circling: 2.94, 2.70, 2.78, 3.58. With tk = 1/k, SGD computes a running mean (1, 1.5, 2, 3) and lands on 3 after one pass.
In practice you use a minibatch: average the gradients of b random examples per step. Averaging cuts the noise, and a GPU computes the b gradients in parallel. One epoch is one pass over the data, so each epoch takes m/b steps. Adam is a stochastic gradient method that also adapts a separate step size for each coordinate. Kingma & Ba 2014 As of Oct 2026 it is a common choice for training neural networks. See the SGD card for a summary.
Try it: compare the blue full-gradient path with the orange SGD scribble. Then switch to b = 10, and then to the decaying step. Watch how low the orange band sits at the end, and when blue passes it.
Notice (defaults: b = 1, fixed t = 0.1): after one epoch full GD has taken a single step and still has f − f* = 0.84. In the same work SGD took 1,000 cheap steps and is already in its noise band; at that instant it happens to dip to 6.6×10⁻⁵. It never leaves the band, which has a median of 8.5×10⁻³ in the last epoch. GD keeps falling in a straight line, passes the band at epoch 32 and ends at 5.6×10⁻⁴. With b = 10 or the decaying step, the band drops below 10⁻³.
Check yourself
Q1. On f = ½(x² + 10y²) with a fixed step, which t makes gradient descent diverge?
L = 10, so the cliff is at 2/L = 0.2. With t = 0.21 the y-coordinate is multiplied by 1 − 10·0.21 = −1.1 each step, so it grows. t = 0.19 looks risky but its factor is −0.9, so it still converges (in 74 iterations).
Q2. In backtracking line search, when do you shrink t ← βt?
You shrink until the new point gives at least the fraction α of the drop the tangent line predicts. "Smaller than f(x)" is too weak a test, and backtracking never needs to know L. It happily accepts t = 0.5 when L = 10.
Q3. You raise the condition number κ from 10 to 100 and keep the best fixed step 2/(1+L). What happens?
The best fixed step still shrinks each coordinate by (κ − 1)/(κ + 1) per step. That factor creeps toward 1 as κ grows, so the count grows about tenfold. Choosing t well cannot undo a stretched bowl; rescaling or Newton's method can.
Q4. What does strong convexity add to the O(1/k) guarantee of gradient descent?
A bowl that curves up at least m everywhere means each step removes a fixed share of the error, ck with c = 1 − m/L for t = 1/L. One step from anywhere happens only when κ = 1. O(1/k²) is the accelerated rate of Day 8, a different improvement.
Q5. For L-smooth convex functions, what is the best worst-case rate any first-order method can guarantee?
Nesterov's lower bound, 3L‖x₀ − x*‖²/(32(k+1)²), says no gradient-only method beats 1/k² on the hardest functions, and accelerated methods reach it. Gradient descent's 1/k is short of that limit. Exponential rates need strong convexity.
Q6. SGD with a fixed step t on f(x) = Σ ½(x − ai)² typically…
Near x* the single-example gradients disagree, so each one kicks the iterate. With a = (1, 2, 3, 6) and t = 0.25 the iterate still circles 3 after 200 passes. A decaying step such as 1/k closes in. It does not diverge, because each kick is small.
Recap: things to remember
Gradient descent repeats xk+1 = xk − t∇f(xk): trust the tangent plane, but not too far.
A fixed step must satisfy 0 < t < 2/L. The best fixed step is 2/(m + L), and t = 1/L is the safe default.
Backtracking (shrink t until f drops by at least α·t·‖∇f‖²) chooses t automatically and is the usual choice. Exact line search is rarely worth its cost.
Smooth convex f gives O(1/k). Strong convexity gives a linear rate, whose speed is set by κ = L/m. Large κ means zig-zag, and 1/k² is the limit that acceleration reaches.
SGD and minibatches trade exact gradients for cheap, noisy ones. They are fast far from the optimum, and near it they need a decaying step.
After today you can handle functions with kinks such as |x|, max and the L1 norm, compute subgradients, use the optimality rule 0 ∈ ∂f(x), and run the subgradient method with a sensible step-size rule.
About 60 min · Needs Day 6 · CO4A chapters 7 and 8
Today's big idea
Gradient descent needs a slope, but |x|, max and the L1 norm have corners where no single slope exists. At a corner there is a whole fan of slopes whose lines stay under the graph, and each one is a subgradient. A point is a minimum exactly when the flat slope 0 is in the fan. You can run gradient descent with any slope from the fan, as long as the steps shrink and you remember the best point so far.
1. Why kinks need a new tool
Many objectives worth minimizing have corners. The absolute value |x| has one at 0. The L1 norm ‖x‖1 = |x1| + … + |xn| has one wherever a coordinate is 0. A maximum of several functions has one wherever two of them tie.
These corners are not an accident. A path planner that cares about the worst of several obstacle clearances is working with a maximum. A lane-line fit that should shrug off one bad GPS fix uses absolute errors, because a squared error lets a single outlier dominate. A model that should use only a few of many sensors adds an L1 penalty, and Day 8 builds a fast solver for exactly that.
On Day 6 every function was smooth. For a smooth convex function, the tangent line at any point never rises above the graph Tibshirani 2016:
f(y) ≥ f(x) + ∇f(x)T(y − x) for all y
Check it on f(x) = x² at x = 1. The tangent is 1 + 2(y − 1) = 2y − 1. The gap is y² − (2y − 1) = (y − 1)², which is never negative. So the tangent stays under the bowl everywhere.
Now look at the tip of a V. Coming from the left the slope is −1, coming from the right it is +1, so there is no single tangent. But many lines still pass through the tip and stay under the V. That is today's whole idea: keep the "line under the graph" property, and drop the demand that the line be unique.
A smooth bowl has exactly one line that touches it at x = 1 and stays below it: the tangent, with slope 2. The V has a whole fan of such lines at its tip, with slopes −1, −0.5, 0, 0.5 and 1 drawn here. Every slope between −1 and 1 works.
2. Subgradients: every line that fits under the graph
The right-hand picture above is the definition. Each line in the fan touches the V at its tip and never rises above it. The slope of any such line is called a subgradient.
In symbols: a vector g is a subgradient of f at x if the line (or plane) with slope g through the point (x, f(x)) stays under the graph everywhere CO4A 7-1:
f(y) ≥ f(x) + gT(y − x) for all y
It is the tangent inequality from Section 1, with ∇f(x) replaced by g. A kink is a point where f is continuous but has no derivative, like the tip of the V.
Try it on f(x) = |x| at x = 0. With g = 0.5 the line is 0.5y, and |y| ≥ 0.5y for every y, so 0.5 is a subgradient. With g = 1.2 the line at y = 1 gives 1.2, but |1| = 1. The line pokes above the graph, so 1.2 fails. Any g from −1 to 1 works.
Three facts make subgradients usable. A convex function has at least one subgradient at every point inside its domain. Where a convex f is differentiable, its only subgradient is ∇f(x), so nothing changes for smooth functions. A nonconvex function may have none at all, because no line fits under a dip CO4A 7-2.
Here are the subgradients you will use most often Tibshirani 2016:
Function
Away from the kink
At the kink
|x|
sign(x)
any g in [−1, 1] at x = 0
‖x‖2
x / ‖x‖2
any g with ‖g‖2 ≤ 1 at x = 0
‖x‖1
sign(xi) in each coordinate
any value in [−1, 1] in each coordinate where xi = 0
max{f1, f2}
∇ of the larger piece
any point on the segment between ∇f1 and ∇f2 where they tie
Try it: the widget draws the fan at a point x₀. Drag "Your slope g" to 1.2 and watch the line turn red where it rises above f. Then switch to function (c) and look at the last tile. Move x₀ off the kink to see the fan collapse to one slope.
Notice: at the kink x₀ = 0 of |x|, the fan fills every slope from −1 to 1. The default line g = 0.5 sits inside the fan and stays under the V. And because 0 is in ∂f(0) = [−1, 1], the widget reports that x₀ = 0 is a minimizer.
Analogy
Balance a ruler on the bottom of a V-shaped valley. You can tilt it quite a lot and it still touches the bottom without cutting into either wall. Every tilt that works is a subgradient. On a smooth, round valley floor the ruler has only one resting angle: the tangent.
3. The subdifferential, and the rules for building it
Collect every subgradient at x into one set. That set is the subdifferential ∂f(x), the whole fan of allowed slopes CO4A 7-2:
∂f(x) = { g : f(y) ≥ f(x) + gT(y − x) for all y }
The set is always closed and convex, so in one dimension it is an interval. For convex f it is never empty. It shrinks to the single point {∇f(x)} exactly where f is differentiable.
Take f(x) = max(1 − x, 2x − 2). The two pieces cross at x = 1, where f = 0. The left piece has slope −1 and the right piece has slope 2, so ∂f(1) = [−1, 2]. At x = 0 only 1 − x is active, so ∂f(0) = {−1}: one slope, as at any smooth point.
You rarely check the definition by hand. As with derivatives, a few rules build ∂f from simple pieces CO4A 7-2-2:
Scaling: ∂(af) = a·∂f for a > 0.
Sum: ∂(f1 + f2) = ∂f1 + ∂f2. Add every member of one set to every member of the other.
Affine inside: if h(x) = f(Ax + b), then ∂h(x) = AT∂f(Ax + b).
Maximum: for f = maxi fi, ∂f(x) is the convex hull of the subgradients of the active pieces, meaning all weighted averages of them.
The L1 norm is a sum of |xi| terms, so its subgradient is built one coordinate at a time. At x = (2, 0, −1) the first and third coordinates are fixed at sign(2) = 1 and sign(−1) = −1. The middle one is free in [−1, 1]. So ∂‖x‖1 = {(1, s, −1) : s ∈ [−1, 1]}. That makes (1, 0.3, −1) a subgradient and (1, 1.5, −1) not one.
The sum rule also explains flat-bottomed valleys. Take f(x) = |x| + |x − 2|. At x = 1 both terms are smooth, and ∂f(1) = {1} + {−1} = {0}. At x = 0, ∂f(0) = [−1, 1] + {−1} = [−2, 0], which also contains 0. In fact every x in [0, 2] has 0 in its fan, and f = 2 on that whole stretch.
Constraints fit into the same language. The indicator function IC of a set C is 0 on C and +∞ outside it. Adding IC to an objective is the same as demanding x ∈ C, because any point outside costs infinity.
Picture standing with your back against a wall. You can push in any direction that does not point back into the room. That set of pushes is the normal cone, and it is exactly the subdifferential of the indicator at a point x of C CO4A 7-2-1:
∂IC(x) = NC(x) = { g : gT(y − x) ≤ 0 for all y ∈ C }
Take C = [0, 1] on the number line. At x = 0.5, inside, no push is allowed except g = 0, so NC(0.5) = {0}. At the right end any push to the right is fine: NC(1) = [0, ∞). At the left end, NC(0) = (−∞, 0].
Normal cones of a rectangle C. Inside C you cannot push anywhere without pointing back in, so N = {0}. On an edge the only outward push is straight out. At a corner every direction between the two edge normals points out, so the normal cone is a wedge. On the number line, the "corners" are the two ends of [0, 1].
One more function you will meet is the distance to a convex set, dist(x, C) = ‖x − PC(x)‖2. Here the projection PC(x) is the point of C closest to x. Outside C the distance is smooth, and its gradient is the unit arrow pointing away from the nearest point CO4A 7-3-5:
∇dist(x, C) = (x − PC(x)) / ‖x − PC(x)‖2
Take C = the unit disk and x = (3, 4). The nearest point is PC(x) = (0.6, 0.8), the distance is 4, and the gradient is (0.6, 0.8). The formula needs x outside C, where the distance is positive. CO4A does not say so, but the slides do Tibshirani 2016.
4. The optimality rule: 0 ∈ ∂f(x*)
At a minimum you cannot go lower in any direction. In the picture, the flat line through (x*, f(x*)) fits under the whole graph. That is the same as saying slope 0 is a subgradient. This is the subgradient optimality conditionCO4A 7-3-1:
f(x*) = minx f(x) ⇔ 0 ∈ ∂f(x*)
The proof is one line. Put g = 0 into the definition and you get f(y) ≥ f(x*) for all y, which is what "minimum" means. The rule holds for any function. Convexity is what makes ∂f easy to compute, and so makes the rule easy to use.
For max(1 − x, 2x − 2), ∂f(1) = [−1, 2] contains 0, so x* = 1 and f* = 0. Now take max(0.5x, 2x − 1.5). It also has a kink at x = 1, with ∂f(1) = [0.5, 2]. Zero is not in that interval, so this kink is not a minimum. Both slopes are positive, so moving left lowers f. This is function (c) in the widget above.
Constraints work the same way. To minimize a smooth f over C, minimize f + IC. The sum rule turns 0 ∈ ∂(f + IC) into a simple test: the downhill direction must point out of C CO4A 7-3-2.
−∇f(x*) ∈ NC(x*)
Example: minimize (x − 2)² over C = [0, 1]. At x = 1 the gradient is 2(1 − 2) = −2, so −∇f = 2. That lies in NC(1) = [0, ∞). The ball wants to roll right, the wall at 1 stops it, and x* = 1. Day 10 grows this rule into the KKT conditions.
The rule's most famous use is the lasso: least squares plus an L1 penalty.
minimize ½‖y − Xβ‖22 + λ‖β‖1
Here X is the data matrix (one column per feature), y holds the measurements, β holds the coefficients, and λ > 0 sets how hard the penalty pushes. Write Xi for column i. Applying 0 ∈ ∂f one coordinate at a time gives two cases CO4A 7-3-3:
XiT(y − Xβ) = λ·sign(βi) if βi ≠ 0 |XiT(y − Xβ)| ≤ λ if βi = 0
Read XiT(y − Xβ) as the pull the data exert on coefficient i. A coefficient stays at exactly zero while that pull is at most λ, like a block held by static friction. Only a pull stronger than λ gets it moving. This is why the lasso keeps a few features and sets the rest to zero.
With X = I the conditions solve in closed form. Each βi is yi moved toward 0 by λ, and set to 0 if |yi| ≤ λ. This map is soft-thresholding SλCO4A 7-3-4:
Sλ(y) = y − λ if y > λ Sλ(y) = 0 if |y| ≤ λ Sλ(y) = y + λ if y < −λ
Take y = (3, 0.4, −1.5) and λ = 1, so S1(y) = (2, 0, −0.5). Check coordinate 1: 3 − 2 = 1 = λ·(+1). Coordinate 2: |0.4 − 0| = 0.4 ≤ 1. Coordinate 3: −1.5 − (−0.5) = −1 = λ·(−1). All three conditions hold. Day 8 turns soft-thresholding into a fast solver for any X.
5. The subgradient method
Now the algorithm. Take gradient descent and replace the gradient by any subgradient. That is the whole subgradient methodCO4A 8-1:
xk+1 = xk − tkgk, gk ∈ ∂f(xk)
Here tk > 0 is the step size at step k. Any member of the fan will do, so you never have to compute the whole set.
There is one catch. A negative subgradient need not point downhill. Near a kink a step can jump to the far side and raise f. So this is not a descent method, and you keep the best point found so far. Its value is fbest:
fbest(k) = min{ f(x0), f(x1), …, f(xk) }
Think of walking down a faceted rock in fog. Each step follows the slope of the face under your feet. Sometimes you step over a ridge onto a face that tilts the other way.
A tiny example shows the catch. Take f(x) = |x|, start at x0 = 1, and use a fixed step t = 0.3. While x > 0 the subgradient is 1, so the iterates are 0.7, 0.4, 0.1. The next step jumps past 0 to −0.2, where the subgradient is −1. Then it goes back to 0.1, then −0.2 again, forever. The best value stays at fbest = 0.1.
The subgradient method on |x| with a fixed step of 0.3. It walks down the right arm, overshoots the tip, and then bounces between 0.1 and −0.2. The step at −0.2 raises f from 0.1 to 0.2, which is why the method tracks fbest. The theory ceiling for this step is G²t/2 = 0.15 (Section 6), and fbest = 0.1 sits under it.
In code the method is a few lines. The only additions to gradient descent are the subgradient and the bookkeeping for the best point.
import numpy as np
def subgradient_method(f, subgrad, x0, step, iters=1000):
x = np.array(x0, float)
best_x, best_f = x.copy(), f(x)
for k in range(1, iters + 1):
g = subgrad(x) # any member of ∂f(x)
x = x - step(k, x, g) * g
if f(x) < best_f: # not a descent method,
best_x, best_f = x.copy(), f(x) # so keep the best point
return best_x, best_f
f = lambda x: abs(x[0]) + 2 * abs(x[1])
sg = lambda x: np.array([np.sign(x[0]), 2 * np.sign(x[1])])
print(subgradient_method(f, sg, [2, -1.5], lambda k, x, g: 1 / k)[1]) # ≈ 1.0e-3
Using np.sign(0) = 0 at a kink is fine, because 0 is in [−1, 1]. The subgradient method card collects the update, the rates and the pitfalls in one place.
6. Step sizes, and how fast it can go
The step-size rule decides everything. Unlike on Day 6, the steps are fixed before the run starts. No line search is used CO4A 8-1-1.
Fixed step: tk = t for every k.
Diminishing steps: tk → 0 with Σtk = ∞ and Σtk² < ∞. The standard example is tk = 1/k.
Why those two sums? Σtk = ∞ means the steps add up to enough distance to reach any point. Σtk² < ∞ means the bouncing around the minimum shrinks to nothing. For tk = 1/k, 1 + 1/2 + 1/3 + … grows without bound, while 1 + 1/4 + 1/9 + … = π²/6 ≈ 1.645.
The guarantees assume f is convex with Lipschitz constant G: |f(x) − f(y)| ≤ G‖x − y‖2. In words, f never changes faster than G per unit of distance. Then every subgradient has length at most G CO4A 8-1-3.
One master bound covers every rule. Let R = ‖x0 − x*‖2 be the distance from the start to a minimizer. After k steps the basic inequality says CO4A 8-1-2:
fbest(k) − f* ≤ (R² + G²Σti²) / (2Σti)
With a fixed t the bound becomes R²/(2kt) + G²t/2. The first term dies away, but the second does not. So the method can stall up to about G²t/2 above f*. With diminishing steps both sums grow, their ratio goes to 0, and fbest → f*.
How many steps for accuracy ε? Choose t = ε/G², and the bound drops below ε once k ≥ R²G²/ε². With R = G = 1 and ε = 0.01 that is 10,000 iterations CO4A 8-1-4. Gradient descent on an L-smooth function needs O(1/ε) iterations, roughly 100 here up to constants. That gap, O(1/ε²) against O(1/ε), is the price of kinks.
If you happen to know the optimal value f*, there is a smarter step. The Polyak step picks the t that makes the one-step bound on the distance to x* as small as possible CO4A 8-1-6:
tk = (f(xk) − f*) / ‖gk‖2²
Example: f(x) = |x1| + 2|x2| at x0 = (2, −1.5), where f* = 0. Here f = 5, g = (1, −2) and ‖g‖² = 5, so t = 1. The step lands at (1, 0.5), where f = 2. In the worst case the Polyak step is still O(1/ε²); it just uses information the other rules lack.
Rule
Step tk
Long run
Needs
Fixed
t
stalls, up to about G²t/2 above f*
nothing
Diminishing
for example 1/k
fbest → f*, slowly
nothing
Polyak
(f(xk) − f*)/‖gk‖²
fbest → f*
the value f*
Try it: the widget runs all three rules on f = |x1| + 2|x2| from (2, −1.5), where G = √5 ≈ 2.236. Switch the fixed step to 0.5 and to 0.01. A bigger step stalls higher, and a smaller one starts slower.
Notice: the fixed step t = 0.1 stalls at fbest = 0.2 from about k = 20 on, under its ceiling G²t/2 = 0.25. The rule tk = 1/k keeps improving and reaches about 1.0e−3 at k = 1000. The Polyak step is below 1e−10 by k = 50, but that comes from this sharp test function, which grows linearly away from its minimum. It is not the general rate.
Going deeper (optional): where the basic inequality comes from
Expand one step: ‖xk+1 − x*‖² = ‖xk − x*‖² − 2tkgkT(xk − x*) + tk²‖gk‖². The subgradient inequality at xk, used with y = x*, gives gkT(xk − x*) ≥ f(xk) − f*. So each step obeys ‖xk+1 − x*‖² ≤ ‖xk − x*‖² − 2tk(f(xk) − f*) + tk²G². Add these up from the first step to the last. The distances telescope, the final distance is at least 0, and each f(xi) − f* is at least fbest − f*. Rearranging gives the bound. CO4A 8-1-2 writes it out in full, with a few typos; the slides are cleaner Tibshirani 2016.
The slow rate is not a weakness of this particular method. Nesterov showed that for any k ≤ n − 1, some G-Lipschitz convex function forces f(xk) − f* ≥ RG/(2(1 + √(k + 1))) for every method that only combines past subgradients. With R = G = 1 and k = 99 that floor is 1/22 ≈ 0.045. So O(1/ε²) cannot be beaten in this class Tibshirani 2016. The way out is to use more structure, which is Day 8's topic CO4A 8-3.
7. Constraints: project after each step
Often x must stay in a set C: a box of actuator limits, the nonnegative orthant, a ball. The projected subgradient method takes the usual step, then snaps back to the nearest point of C CO4A 8-1-8:
xk+1 = PC(xk − tkgk)
It keeps the same guarantees, provided the projection is cheap. For C = ℝ2+, the nonnegative quadrant, a raw step that lands at (1, −2) projects to (1, 0): just clip the negative entry to 0. Clipping also projects onto a box, such as limits on steering angle and acceleration.
Easy sets to project onto include {x : Ax = b}, affine images {Ax + b}, the nonnegative orthant, L1, L2 and L∞ balls, and simple cones. A general polyhedron {x : Ax ≤ b} is hard: projecting onto it is itself a quadratic program Tibshirani 2016.
A neat special case finds a point in the intersection of convex sets C1, …, Cm. Minimize f(x) = maxi dist(x, Ci). If the sets meet, f* = 0, so the Polyak step is available. Working it out, each Polyak step simply projects onto the farthest set. For two sets this is alternating projectionsCO4A 8-1-7. CO4A's closing sentence says "closest"; that is a typo, and the slides say farthest Tibshirani 2016.
Here are real numbers. Let C1 be the line x2 = 0 and C2 the disk of radius 1.5 centred at (3, 1). Start at (0, 3). C1 is 3 away and C2 is 2.106 away, so project onto C1: (0, 0). Then C2 is farther, so project onto it: (1.577, 0.526). Then back onto C1: (1.577, 0). The worst distance falls 1.662, 0.526, 0.239, 0.138, 0.083, … toward the meeting point (≈ 1.882, 0).
Alternating projections, the Polyak-step subgradient method on max(dist(x, C1), dist(x, C2)). Step 1 projects onto C1 because it is the farther set (3 vs 2.106). Step 2 projects onto the disk, step 3 back onto the line, and the zig-zag shrinks toward the meeting point (≈ 1.882, 0).
Going deeper (optional): stochastic subgradients
Many objectives are sums, f = f1 + … + fm, one term per data point. The stochastic subgradient method uses a subgradient of just one term per step, picked in a fixed cycle or at random CO4A 8-2-1. Picking at random needs about m times fewer iterations than cycling in the worst-case bounds, in expectation CO4A 8-2-3. In practice it gets close fast and then struggles near the optimum, while the full-batch method is slow but steady CO4A 8-2-4. It is the nonsmooth cousin of SGD on the SGD card.
Explain it to a 10-year-old
Put a stick under a smooth hill so it touches at one spot. There is only one way to hold it without poking into the hill. Now put the stick at the pointy bottom of a V. You can rock it back and forth and it still just touches the bottom. Each of those angles is a subgradient. If you can hold the stick perfectly flat, you are at the lowest spot.
Common misunderstandings
"The subgradient method always goes downhill." It does not. A step can jump past a kink and raise f, as the step from 0.1 to −0.2 does on |x|. Always track fbest.
"A kink is always a minimum." max(0.5x, 2x − 1.5) has a kink at 1 with ∂f(1) = [0.5, 2]. Zero is not in it, and moving left lowers f.
"∂|x| at 0 is one number." It is the whole interval [−1, 1]. Any member is a valid subgradient, so code that uses sign(0) = 0 is fine.
"A fixed step gets there if you wait long enough." It stalls up to about G²t/2 above f*. In the widget, t = 0.1 stops at 0.2.
"The distance gradient works everywhere." The formula (x − PC(x))/dist(x, C) needs x outside C. Inside C, dist = 0 and the formula divides by zero.
Check yourself
Q1. Which number is a subgradient of f(x) = |x| at x = 0?
0.5 works because |y| ≥ 0.5y for every y. Any value in [−1, 1] works. 1.5 and −2 fail: their lines rise above the V on one side. "No slope" confuses the gradient, which does not exist at 0, with subgradients, which do.
Q2. For f(x) = max(1 − x, 2x − 2), what is ∂f(1)?
Both pieces are active at x = 1, with slopes −1 and 2. The max rule takes the convex hull, which is the whole interval [−1, 2], not only its two ends. It contains 0, which is why x = 1 is the minimizer, but the set is far bigger than {0}.
Q3. Which vector is a subgradient of ‖x‖1 at x = (2, 0, −1)?
Nonzero coordinates must equal their sign (1 and −1). The zero coordinate may be anything in [−1, 1], so 0.3 is fine. (1, 1.5, −1) breaks the [−1, 1] limit, (1, 0, 1) has the wrong sign in the third coordinate, and (2, 0, −1) is x itself, not its signs.
Q4. Why does the subgradient method keep track of fbest?
The method is not a descent method. Near a kink a step can overshoot and raise f, so the last iterate may not be the best one. Steps shrink rather than grow, subgradients are usually not unique, and the Polyak step needs f*, not fbest.
Q5. You run a fixed step t = 0.1 on a convex f with Lipschitz constant G = √5. What long-run ceiling on fbest − f* does the theory give?
The ceiling is G²t/2 = 5 × 0.1 / 2 = 0.25. A fixed step does not converge to f* in general; only diminishing steps do. In the widget the actual stall level is 0.2, under the ceiling.
Q6. What is the Polyak step at x = (2, −1.5) for f = |x1| + 2|x2|, where f* = 0?
f(x) = 2 + 3 = 5 and g = (1, −2), so ‖g‖² = 5 and t = (5 − 0)/5 = 1. The value 5 forgets to divide by ‖g‖², 0.2 divides the wrong way, and 2.236 is ‖g‖ rather than ‖g‖².
Recap: things to remember
g is a subgradient of f at x if f(y) ≥ f(x) + gT(y − x) for all y. The set of all of them, ∂f(x), is the fan of slopes. At smooth points it is just {∇f(x)}.
Build ∂f with rules: scaling, sums, affine maps, and the convex hull for a max. ∂|x| at 0 is [−1, 1], and the indicator of C gives the normal cone.
x* is a minimizer exactly when 0 ∈ ∂f(x*). For the lasso this says a coefficient stays at 0 while its pull is at most λ, and with X = I it gives soft-thresholding.
The subgradient method is xk+1 = xk − tkgk. It is not a descent method, so keep fbest. Fixed steps stall near G²t/2; diminishing steps such as 1/k converge.
Its rate is O(1/ε²) iterations, far slower than gradient descent, and no subgradient-only method can do better in the worst case. With constraints, project after each step.
After today you can solve the lasso with ISTA's soft-thresholding step, explain how FISTA's momentum turns O(1/k) into O(1/k²), and recognise projected gradient as a special case.
About 60 min · Needs Day 7 · CO4A chapter 9
Today's big idea
Split the objective into a smooth part g and a simple kinky part h. Take an ordinary gradient step on g, then settle h exactly with a "prox" step. For the lasso the prox is soft-thresholding, and the method, ISTA, runs at gradient-descent speed O(1/k) instead of the subgradient method's O(1/√k). Adding momentum gives FISTA, which improves the rate to O(1/k²).
1. Smooth plus simple: composite objectives
Yesterday's subgradient method treats the whole objective as kinky, and it pays for that with O(1/ε²) iterations. But most kinky objectives are kinky only in a simple, known way. The lasso is a smooth least-squares fit plus a penalty λ‖β‖1, whose kinks all sit where some coordinate is 0.
A composite objective is a sum of two such parts CO4A 9-1:
f(x) = g(x) + h(x)
Here g is convex and differentiable, and h is convex, possibly not differentiable, but simple. The lasso splits as g(β) = ½‖y − Xβ‖2² and h(β) = λ‖β‖1.
A courier drives the highway to the right block, then walks the last bit on foot. Nobody tries to drive through the pedestrian zone. Today's method works the same way: a gradient step handles the smooth part, and a short exact "walk" handles the kinks.
Sparse sensor selection is a lasso. Say a perception stack has 40 candidate input channels, such as radar range bins or lidar features. You want a linear model that uses only the few that matter. The L1 penalty drives useless weights to exactly 0, so the pattern of zeros tells you which channels to keep. The widget in Section 7 solves a small version: 20 measurements, 40 correlated channels, and only 3 that truly matter.
2. Gradient descent as "jump to the bottom of a simple model"
Here is a new way to see a gradient step. At the current point x, replace f by a simple model: its tangent plane plus a round bowl. Then jump to the bottom of the bowl Tibshirani 2016.
The bowl term (1/2t)‖z − x‖² has Hessian (1/t)I. It pretends the curvature is 1/t in every direction. CO4A writes (1/2t)I here, but the ½ already sits in the bowl term, so the Hessian is (1/t)I. Setting the derivative in z to zero gives ∇f(x) + (z − x)/t = 0, so z = x − t∇f(x). That is exactly the Day 6 step.
A number check: f(x) = x², x = 1, t = 0.25. The model is 1 + 2(z − 1) + 2(z − 1)². Its bottom is at z = 1 − 0.25·2 = 0.5, the same point a gradient step reaches.
Now the key move. Use the simple model only for g, and keep h exactly as it is:
Read it as two moves. First take a gradient step on g. Then look for the point that stays close to where that step landed while keeping h small.
3. The proximal operator
That second move has a name. The proximal operator of h with step t is CO4A 9-1:
proxt(x) = argminz (1/2t)‖x − z‖2² + h(z)
It is a compromise. The first term says "stay near x", the second says "make h small", and a larger t gives h more say. Three examples show the range:
h = 0: nothing to fix, so proxt(x) = x.
h = IC, the indicator from Day 7: stay as close to x as possible while staying in C. That is the projection PC(x).
h = λ‖x‖1: soft-thresholding at level λt, the subject of Section 4.
Proximal gradient descent repeats the two moves CO4A 9-1:
xk+1 = proxt(xk − t∇g(xk))
The prox depends only on h, not on g. So g can be as messy as you like, as long as you can compute its gradient. When h's prox is cheap, each iteration costs about as much as a gradient step Tibshirani 2016.
It helps to write the update as xk+1 = xk − tGt(xk), where the generalized gradient is
Gt(x) = (x − proxt(x − t∇g(x))) / t
When h = 0 it is just ∇g. In general it plays the gradient's role: Gt(x) = 0 exactly when x minimizes f.
One proximal gradient step for h = λ‖β‖1 with λt = 0.8. The gradient step on the smooth part lands at z = (2.0, 0.6). The prox step shrinks each coordinate toward 0 by 0.8. The first coordinate becomes 1.2. The second is inside the shaded band |β2| ≤ λt, so it becomes exactly 0. This snapping is where the lasso's zeros come from.
4. ISTA: proximal gradient for the lasso
For h = λ‖β‖1 the prox splits into one tiny problem per coordinate. Each is solved by Day 7's soft-thresholding, at level λt instead of λ:
[Sλt(β)]i = βi − λt if βi > λt [Sλt(β)]i = 0 if −λt ≤ βi ≤ λt [Sλt(β)]i = βi + λt if βi < −λt
CO4A drops the minus sign in the middle case and writes λt ≤ βi ≤ λt. The band is symmetric: −λt ≤ βi ≤ λt Tibshirani 2016.
Think of a flat tax of λt on every coefficient's size. Big coefficients pay it and survive, a little smaller. Anything smaller than the tax is wiped out to exactly zero.
The gradient of g(β) = ½‖y − Xβ‖² is −XT(y − Xβ). Put the gradient step and the prox together and you get ISTA, the iterative soft-thresholding algorithm CO4A 9-1Beck & Teboulle 2009:
β+ = Sλt(β + tXT(y − Xβ))
Try one step on a lasso with a single coefficient: g(β) = ½(4 − 2β)² and λ = 2. Here g′(β) = −2(4 − 2β) and L = 4, so take t = 1/4. Start at β = 0.
Gradient step: 0 − 0.25·(−8) = 2.
Prox: S0.5(2) = 1.5, since λt = 2 × 0.25 = 0.5.
Check Day 7's rule: g′(1.5) = −2(4 − 3) = −2, and −2 + λ·sign(1.5) = 0. So β = 1.5 is optimal.
It lands in one step only because, in one dimension with t = 1/L, the model of g is exact. In many dimensions ISTA needs many steps. Here is one prox with λt = 1: a gradient step that lands at (3, 0.4, −1.5) is soft-thresholded to (2, 0, −0.5). The middle coefficient falls inside the band and is zeroed.
Try it: drag λ and watch the flat band widen. Then drag the input y through the band and watch the output stick at 0.
Notice: at λ = 1 the input y = 2 comes out as S(2) = 1. Every input in the shaded band [−1, 1], such as 0.5, comes out as exactly 0, and −2 comes out as −1. Outside the band the curve has slope 1, shifted toward 0 by λ.
The whole solver fits in a dozen lines. The same loop gives FISTA (Section 7) when the momentum weight is switched on.
import numpy as np
def soft(z, a): # prox of a·‖·‖₁
return np.sign(z) * np.maximum(np.abs(z) - a, 0)
def lasso(X, y, lam, iters=1000, fista=True):
t = 1 / np.linalg.norm(X, 2) ** 2 # t = 1/L, L = λmax(XᵀX)
b = b_old = np.zeros(X.shape[1])
for k in range(1, iters + 1):
w = (k - 2) / (k + 1) if fista else 0.0
v = b + w * (b - b_old) # momentum (FISTA only)
b_old = b
b = soft(v + t * X.T @ (y - X @ v), lam * t)
return b
The rate matches gradient descent. Assume g has a Lipschitz gradient with constant L, also called L-smooth: ‖∇g(x) − ∇g(y)‖2 ≤ L‖x − y‖2. For the lasso, L is the largest eigenvalue of XTX. With a fixed step t ≤ 1/L CO4A 9-2:
f(xk) − f* ≤ ‖x0 − x*‖2² / (2tk)
That is O(1/k) error, or O(1/ε) iterations, against O(1/ε²) for the subgradient method. Take ‖x0 − x*‖² = 1 and t = 1. Reaching ε = 10⁻⁴ needs k ≥ 1/(2·10⁻⁴) = 5,000 iterations by this bound. The subgradient bound with R = G = 1 would ask for R²G²/ε² = 10⁸.
Two cautions. The count is iterations, not work. Each iteration costs one prox, which is cheap for soft-thresholding and expensive when it needs a matrix factorization (Section 6). Also, ISTA's objective never goes up: it is a descent method Beck & Teboulle 2009.
You rarely know L. Backtracking line search works much as on Day 6. Start each iteration at t = 1 and shrink t ← βt, with 0 < β < 1, until the smooth part's quadratic upper model holds at the new point CO4A 9-2:
Only g is tested, never h. The rate becomes ‖x0 − x*‖²/(2tmink) with tmin = min{1, β/L}. Every trial step costs one prox call.
On the seeded lasso from Section 7, computed offline with β = 0.5, 200 backtracking iterations used 1,319 prox calls, about 6.6 per iteration. They accepted steps as large as 0.25, where 1/L = 0.00395, and reached an error of 1.8×10⁻⁴. Fixed-step ISTA was at 9.1×10⁻² after 200 iterations and at 4.9×10⁻⁴ after 1,319. So here the bigger steps were worth their extra prox calls.
6. Special cases: one method, many names
Proximal gradient is also called generalized gradient descent, because familiar methods fall out of it when you choose g or h CO4A 9-4:
h = 0: the prox is the identity, and you get plain gradient descent.
h = IC: the prox is the projection, and you get projected gradient descent, x+ = PC(x − t∇g(x)).
g = 0: you get the proximal minimization algorithm, x+ = proxt(x). It beats the subgradient method, but only when the prox has a closed form.
One update, four familiar methods. Choosing h decides what the prox step does: nothing, a projection, or soft-thresholding. Dropping g leaves only the prox.
A projected-gradient example with numbers: minimize (x − 3)² over C = [0, 1], with L = 2 and t = 0.25, from x = 0. The gradient step goes to 0 − 0.25·(−6) = 1.5, and the projection brings it back to PC(1.5) = 1. From x = 1 the gradient step goes to 1 − 0.25·(−4) = 2, which projects back to 1 again. The point has stopped moving, and a point the step leaves unchanged is the optimum.
Robots use projected gradient all the time. If the variables are steering and acceleration commands with hard limits, C is a box and PC just clips each command to its range. Box limits on inputs come back in Day 17's model predictive control.
One heavier example shows why the cost of a prox matters. In matrix completion you see some entries of a matrix Y, such as a few ratings, and want a low-rank B that matches them. The trace norm ‖B‖tr, the sum of the singular values, is the L1 norm of the singular values. It is a convex stand-in for rank CO4A 9-3.
Its prox soft-thresholds the singular values. Singular values (5, 2, 0.5) with λt = 1 become (4, 1, 0), and the rank drops from 3 to 2. With t = 1 the method is called Soft-Impute: fill the missing entries with your current guess, then shrink the singular values. Each step needs a singular value decomposition (SVD), which is far more work than a soft-threshold.
7. Acceleration: FISTA
ISTA forgets its past. Each step starts from where it stands, so along a long, gently sloping valley it inches forward. Momentum fixes that: before each step, keep going a little in the direction you were already moving.
Think of pushing a swing. Small pushes timed with the motion build speed, because each push adds to the motion already there.
FISTA (fast ISTA) adds one line to ISTA. Set x−1 = x0. Then for k = 1, 2, … CO4A 9-5-1:
One FISTA step. Extend the last step by the momentum weight (here 0.727, its value at k = 10) to reach v. Then take an ordinary proximal gradient step from v. ISTA would have stepped from xk−1 instead.
The momentum weight (k − 2)/(k + 1) starts small and creeps toward 1. It is 0 at k = 2, 0.25 at k = 3, 0.727 at k = 10 and 0.970 at k = 100. At k = 1 it is −0.5, which does no harm because x0 − x−1 = 0.
This is the form CO4A and the CMU slides use. Beck and Teboulle's original paper builds the weight from a sequence tk, which there is a momentum counter, not a step size Beck & Teboulle 2009. Start with t1 = 1 and set
Both forms carry the same guarantee. On the widget's example they differ only slightly: at k = 100 the error is 6.2×10⁻⁴ with CO4A's weights and 5.6×10⁻⁴ with Beck and Teboulle's.
That is O(1/k²) error, or O(1/√ε) iterations. With ‖x0 − x*‖² = 1 and t = 1, ε = 10⁻⁴ needs (k + 1)² ≥ 20,000, so k = 141, against 5,000 for ISTA. In the worst case over smooth convex problems, no method that only uses gradients can do better.
Why does looking back help? On a valley floor, consecutive steps point the same way, so the momentum adds up and the effective step grows. Across a valley, steps alternate in direction, and the momentum mostly cancels.
FISTA is not a descent method. Momentum can carry it past the bottom, so f rises for a while. These bumps are called Nesterov ripplesCO4A 9-5-1. In the widget's example, FISTA's objective rose on 430 of its first 1,000 steps, the first time at k = 35. ISTA never rose. If you need a curve that only goes down, report the best value so far.
Try it: the chart runs ISTA and FISTA on the seeded lasso (20 measurements, 40 correlated channels, λ = 1, t = 1/L with L = 253.1). Switch the FISTA weights between the two forms, and press "Show bounds" to draw both guarantees.
Notice: on this example, at k = 100 ISTA is still 0.465 above f* while FISTA is at 6.2e−4, about 750 times closer. To get within 10⁻³ of f*, ISTA needs 1,146 iterations and FISTA needs 98.
ISTA
FISTA
Step taken from
xk−1
v = xk−1 + wk(xk−1 − xk−2)
Guarantee, t ≤ 1/L
‖x0 − x*‖²/(2tk)
2‖x0 − x*‖²/(t(k + 1)²)
Bound: iterations for ε = 10⁻⁴ (‖x0 − x*‖² = 1, t = 1)
5,000
141
Widget example: iterations to 10⁻³
1,146
98
Objective each step
never goes up
can go up (ripples)
Memory
one point
two points
Acceleration is not always worth it CO4A 9-5-4. A warm start begins a solve from the answer to a nearby problem. Along a path of λ values, λ1 > λ2 > …, each solve starts so close to its answer that plain ISTA often does just as well. In matrix completion, backtracking costs several SVDs per step, and the extrapolated point v need not be low rank, which makes each SVD slower.
Prox steps return later. Day 13's ADMM is built from prox steps on each part of a split problem, and Day 14 shows coordinate descent, another fast lasso solver.
Going deeper (optional): where the rates come from
CO4A states the O(1/k) theorem without proof. A full proof is Theorem 3.1 of Beck and Teboulle: one lemma bounds the progress of a single prox-gradient step, and the bounds telescope. Their version reads F(xk) − F* ≤ αL‖x0 − x*‖²/(2k), with α = 1 for a constant step. Their loss is ‖Ax − b‖² without the ½, so their L is twice ours Beck & Teboulle 2009.
The O(1/k²) proof (their Lemmas 4.1 to 4.3 and Theorem 4.4) rests on two facts about the momentum sequence: tk² = tk+1² − tk+1, and tk ≥ (k + 1)/2. The second makes the error shrink like 1/tk², which is at most 4/(k + 1)². The rate is a worst case. A particular lasso can converge much faster, sometimes almost linearly. The widget's example uses correlated columns and a small λ, so the gap between O(1/k) and O(1/k²) is visible.
Explain it to a 10-year-old
You are tidying a messy room with one rule: every toy pays a one-coin tax, and toys worth less than one coin go in the bin. Each round, you first move things toward where they belong, then apply the tax. The little junk disappears for good, and only the toys that matter are left. FISTA is the same, except you keep walking in the direction you were already going, so you finish much sooner.
Common misunderstandings
"Proximal gradient is the subgradient method with a new name." It handles h exactly through the prox, which is why it gets O(1/k) instead of O(1/√k).
"ISTA thresholds at λ." It thresholds at λt. The zero band is −λt ≤ βi ≤ λt, with a minus sign on the left.
"FISTA's objective falls every step." Ripples are normal. In the widget's example it rose on 430 of 1,000 steps. Report the best value, or use a monotone variant.
"Only iterations count." One prox can be an SVD, and backtracking multiplied the prox calls by about 6.6 on the widget's example.
"Acceleration always helps." With warm starts, or when each prox is costly, it can be neutral or worse.
Check yourself
Q1. For h = λ‖x‖1 and step size t, what is proxt?
The prox minimizes (1/2t)‖x − z‖² + λ‖z‖1. Multiplying by t shows the penalty is λt, so each coordinate shrinks by λt. Thresholding at λ forgets the step size. Hard-thresholding keeps large entries unshrunk, which is not what the L1 penalty does. Projection onto an L1 ball is the prox of an indicator, not of the norm.
Q2. One ISTA step for g(β) = ½(4 − 2β)², λ = 2 and t = 0.25, starting from β = 0, lands at:
The gradient step goes to 2. Soft-thresholding at λt = 0.5 gives 1.5. Stopping at 2 skips the prox step. 1.75 thresholds at 0.25 instead of λt. 0 would mean the whole value sat inside the band.
Q3. Using the guarantees with ‖x0 − x*‖² = 1, t = 1 and ε = 10⁻⁴, how many iterations do ISTA and FISTA need?
ISTA: 1/(2k) ≤ 10⁻⁴ gives k = 5,000. FISTA: 2/(k + 1)² ≤ 10⁻⁴ gives (k + 1)² ≥ 20,000, so k = 141. The 10,000 / 100 pair drops the constants 2 in both bounds, and the swapped pair has the faster method backwards.
Q4. When does proximal gradient become projected gradient descent?
The prox of an indicator is the projection, so the update becomes PC(x − t∇g(x)). h = 0 gives plain gradient descent, and g = 0 gives the proximal minimization algorithm. A squared norm is smooth and adds shrinkage, not a constraint.
Q5. In a FISTA run the objective went up at step 35. What is the most likely reason?
Nesterov ripples are normal. In the widget's example, FISTA rose for the first time at k = 35 with t = 1/L exactly, so the step size is not to blame. Check the best value so far, not each step.
Q6. Backtracking in proximal gradient checks its sufficient-decrease condition on:
The test compares g at the new point with g's quadratic upper model, because only g was replaced by a model. h is handled exactly by the prox, so it needs no test. Fixed steps are allowed, but they are not required.
Recap: things to remember
For f = g + h with g smooth and h simple, take xk+1 = proxt(xk − t∇g(xk)): a gradient step on g, then a prox step for h.
The prox of λ‖·‖1 is soft-thresholding at λt. For the lasso this gives ISTA, β+ = Sλt(β + tXT(y − Xβ)), and its zeros come from the band −λt ≤ βi ≤ λt.
With t ≤ 1/L, ISTA's error is at most ‖x0 − x*‖²/(2tk), the gradient-descent rate. Backtracking tests only g.
h = IC gives projected gradient, h = 0 gives gradient descent, and g = 0 gives proximal minimization.
FISTA adds momentum, (k − 2)/(k + 1) in CO4A's form or tk in Beck and Teboulle's. The rate becomes O(1/k²), but the objective can ripple upward.
After today you can build the Lagrangian and the dual function, use weak duality to get a lower bound on the best value, and tell when strong duality holds (Slater's condition).
About 60 min · Needs Day 4 · CO4A chapters 10 and 11
Today's big idea
Every minimization problem has a twin, its dual, whose job is to find the best guaranteed floor under the answer. You build the floor by putting a price on each rule instead of forbidding violations. Every price gives a valid floor. For convex problems with a little room to spare, the best price gives a floor that touches the answer exactly.
1. A referee who proves "you can't do better"
Picture a factory that must ship at least 2 tons of product. Plant X makes it for $1 a ton and plant Y for $3 a ton. Write x and y for the tons each plant makes. The cheapest plan solves this linear program (LP):
minimize x + 3y s.t. x + y ≥ 2, x ≥ 0, y ≥ 0
Here the answer is obvious: use only the cheap plant, (x, y) = (2, 0), for a cost of 2. With 10,000 variables nothing is obvious. A solver hands you a plan and says it is the best. How could anyone check that claim without trying every plan?
Bring in a referee. She never looks at plans. She only combines the rules that every plan must obey. Take the rule x + y ≥ 2 once and the rule y ≥ 0 twice, and add them: (x + y) + 2y ≥ 2 + 0, which reads x + 3y ≥ 2. The left side is exactly the cost. So no plan can cost less than 2, and the plan (2, 0) is the best one. CO4A 10-01
That is duality in miniature. A floor that matches a plan you hold is a certificate: a short proof of optimality that anyone can check with a few additions. The referee's weights (1, 0 and 2 for the three rules) are the certificate.
Now make the trick systematic. Give each rule a weight: u1 for x + y ≥ 2, u2 for x ≥ 0, and u3 for y ≥ 0. Each weight must be ≥ 0, because multiplying an inequality by a negative number flips it. Adding the weighted rules gives
(u1 + u2)x + (u1 + u3)y ≥ 2u1
If the left side equals the cost, that is u1 + u2 = 1 and u1 + u3 = 3, then 2u1 is a floor under every plan. The referee wants the highest floor, so she solves a problem of her own: CO4A 10-01
maximize 2u1 s.t. u1 + u2 = 1, u1 + u3 = 3, u ≥ 0
Because u2 and u3 cannot be negative, these constraints say u1 ≤ 1 and u1 ≤ 3. The best choice is u1 = 1, with floor 2: exactly the cost of the best plan. The referee's problem is the dual problem. The original one is the primal problem.
The weight u1 also has a price tag. Raise the demand from 2 tons to 2.1 tons, and the cheapest plan costs 2.1 instead of 2. Each extra ton of demand costs u1 = 1 dollar. A multiplier is the price of its rule: what one more unit of tightening would cost you. Boyd & Vandenberghe 2004 Hold on to that reading. It is the story behind everything below.
Explain it to a 10-year-old
Your teacher says: "This maze takes at least 12 steps." She proves it without walking it. The exit is 12 squares away, and every step moves you one square. That is a floor. If you then find a 12-step path, the floor proves your path is the best one possible. Duality is a machine for building floors like that, for any problem.
2. Every LP has a twin
The referee's recipe works for any LP. Take the form "pay as little as possible while meeting every requirement":
primal: minimize cTx s.t. Ax ≥ b, x ≥ 0
Here x ∈ ℝn lists the amounts, c lists their unit costs, and each row of Ax ≥ b is one requirement. Give each row a weight, and collect the weights in a vector u ≥ 0. Every feasible x then obeys uTAx ≥ uTb. If also ATu ≤ c entry by entry, then x ≥ 0 gives cTx ≥ (ATu)Tx = uTAx ≥ bTu. The best floor of this kind is the dual:
dual: maximize bTu s.t. ATu ≤ c, u ≥ 0
The factory is the case c = (1, 3), A = [1 1] and b = 2. Its dual is "maximize 2u1 s.t. u1 ≤ 1, u1 ≤ 3, u1 ≥ 0". In Section 1 the extra weights u2 and u3 did the same job: u1 + u2 = 1 with u2 ≥ 0 just says u1 ≤ 1. Tibshirani 2016
Notice the swap. Each primal requirement becomes one dual variable, and each primal variable becomes one dual constraint. The costs c and the requirements b trade places. The table collects the sign rules. CO4A 10-02
In the primal (minimize)
In the dual (maximize)
a requirement aiTx ≥ bi
a variable ui ≥ 0
a requirement aiTx = bi
a variable ui of any sign
a variable xj ≥ 0
a constraint (ATu)j ≤ cj
a variable xj of any sign
a constraint (ATu)j = cj
the right-hand sides b
the objective bTu
the costs c
the right-hand sides of the constraints
A "≤" requirement is multiplied by −1 first. Why may an equality's weight have any sign? You can scale an equation by a negative number without breaking it: a = b also gives −a = −b. CO4A 10-02 states the same rules for the form "Ax = b, Gx ≤ h". Watch the letters on that page: it uses u for the equalities and v for the inequalities, the reverse of chapter 11 and of this lesson.
A dual you can see: max flow and min cut
Picture water pipes running from a source s to a sink t, each pipe with a capacity. The max flow is the most water per second you can push from s to t. A cut splits the nodes into two groups, one holding s and the other holding t. Its capacity is the total capacity of the pipes that run from the s group to the t group. The min cut is the cut with the smallest capacity.
Every drop of water must cross every cut, so any cut's capacity is a ceiling on the flow. The primal here is a maximum, so the referee's job flips. Her certificate now says "you can't push more than this".
Max flow is an LP. Its variables are the flows fij in the pipes, with 0 ≤ fij ≤ cij on each pipe (CO4A prints < here; it should be ≤) and "flow in = flow out" at every node except s and t. Its dual turns out to be the LP relaxation of min cut: the same problem with the 0-or-1 labels "which side is this node on" allowed to take fractional values. So max flow ≤ relaxed min cut ≤ min cut, and the max-flow min-cut theorem says all three are equal. CO4A 10-03Tibshirani 2016
The figure shows a small case. The best flow sends 4 units. The cut that separates {s, a} from {b, t} crosses three pipes with capacities 2, 1 and 1, so it also totals 4. The other cuts are larger: {s} alone gives 5, {s, b} gives 7 and {s, a, b} gives 5. A flow of 4 and a cut of 4 certify each other, just as the factory plan and the referee's floor did.
A small pipe network. Each pipe is labelled flow/capacity. The best flow pushes 4 units from s to t. The dashed cut separates the green side {s, a} from the blue side {b, t}. It crosses s→b, a→b and a→t, so its capacity is 2 + 1 + 1 = 4. A flow that equals a cut's capacity proves that both are optimal.
3. Prices instead of walls: the Lagrangian
For an LP the referee can combine rules by hand. Curved problems need a recipe that always works. Here it is: turn each hard rule into a price. Instead of a wall that forbids breaking a rule, charge a fine of u for each unit of violation, and pay a rebate of u for each unit of room to spare.
First the letters, because the books disagree. This lesson follows CO4A chapter 11 and Tibshirani's slides.
Item
This lesson (CO4A ch. 11)
Boyd & Vandenberghe
Cost (objective)
f(x)
f0(x)
Inequality rules
hi(x) ≤ 0
fi(x) ≤ 0
Equality rules
ℓj(x) = 0
hi(x) = 0
Their multipliers
ui ≥ 0 and vj
λi ≥ 0 and νi
Dual function
g(u, v)
g(λ, ν)
So in Boyd & Vandenberghe the letter h means an equality, while here it means an inequality. Day 4 followed CO4A chapter 4 and wrote the rules as gi(x) ≤ 0 and hj(x) = 0. Today the letter g belongs to the dual function, so the inequalities become hi and the equalities ℓj. Day 10 keeps hi and ℓj but names the multipliers λ and ν, as CO4A chapter 12 does.
Day 4's standard form, in today's letters, is
minimize f(x) s.t. hi(x) ≤ 0, i = 1, …, m ℓj(x) = 0, j = 1, …, r
Write p* for its best value. The Lagrangian adds every rule to the cost, each with its own price:
L(x, u, v) = f(x) + Σi uihi(x) + Σj vjℓj(x)
The prices ui ≥ 0 and vj (any sign) are the Lagrange multipliers, also called dual variables. There is one for each rule, just like the referee's weights. CO4A 11-1
One fact makes everything work: on the feasible set, L never exceeds f. If x obeys the rules, each hi(x) ≤ 0, so uihi(x) ≤ 0. That term is a rebate, or nothing. Each ℓj(x) = 0, so the v terms vanish. CO4A 11-1
L(x, u, v) ≤ f(x) for every feasible x and every u ≥ 0
A worked example. Take min x2 s.t. x ≥ 1, whose answer is x* = 1 with p* = 1. In "≤ 0" form the rule is h(x) = 1 − x ≤ 0, so
L(x, u) = x2 + u(1 − x)
At the feasible point x = 1.5 with price u = 1, L = 2.25 + (1 − 1.5) = 1.75. That is below f(1.5) = 2.25: the point has 0.5 units of room and earns a rebate of 0.5. At the infeasible point x = 0.5, L = 0.25 + 0.5 = 0.75. That point breaks the rule by 0.5 and pays a fine of 0.5.
Analogy: an emissions cap versus a carbon price
A regulator can impose a hard cap: "emit at most 100 tons". Or it can set a price: pay u for each ton above 100, and earn u in credits for each ton below. Under the price, a firm may break the cap whenever that is cheaper for it. So its cheapest priced cost, g(u), can never be above its cheapest cost under the hard cap, p*. The regulator's dual problem is to find the price that makes the firm's best priced cost as high as possible. When strong duality holds, the right price makes the firm's own cheapest choice land right on the cap. You can watch this in the x2 example: at u = 2 the lowest point of L is x = 1, exactly on the rule.
4. The dual function g(u, v), and why it is always concave
Now set x free. Fix the prices, ignore the rules, and find the lowest point of L over all x. That lowest value is the Lagrange dual function:
g(u, v) = min over all x of L(x, u, v)
(Strictly, "min" should be "inf", the greatest lower bound, because the lowest value may never be reached.) Why is g a floor? Freedom plus a fair fine can only make things cheaper. Formally, let x* be the best feasible point. Then g(u, v) ≤ L(x*, u, v) ≤ f(x*) = p*. The first step holds because g takes the minimum over all x. The second holds because x* is feasible. CO4A 11-2
Back to min x2 s.t. x ≥ 1. For a fixed u, L(x, u) = x2 + u(1 − x) is a bowl in x. Its slope 2x − u is zero at x = u/2. Plug that in:
g(u) = u2/4 + u(1 − u/2) = u − u2/4
Price u
Lowest point of L, x = u/2
Does it obey x ≥ 1?
Floor g(u)
0
0
no
0
1
0.5
no
0.75
2
1
yes (on the boundary)
1
3
1.5
yes
0.75
4
2
yes
0
Every floor is at most p* = 1, as promised. Look at u = 1: the lowest point x = 0.5 breaks the rule. That is fine, because g(u) is a floor, not a plan. The best price, u = 2, gives a floor of exactly 1.
The value of g can also be −∞, which is a useless floor. This happens all the time in LPs. For the factory, L = x + 3y + u1(2 − x − y) − u2x − u3y. Collect terms:
L = (1 − u1 − u2)x + (3 − u1 − u3)y + 2u1
This is linear in x and y. Unless both brackets are zero, x or y can run off and make L as negative as you like. So g = 2u1 when u1 + u2 = 1 and u1 + u3 = 3, and −∞ otherwise. The general recipe has rebuilt the referee's LP from Section 1. CO4A 10-04 Prices with u ≥ 0 and g(u, v) > −∞ are called dual feasible.
Now the surprising part. Fix one x and watch L(x, u) = f(x) + u·h(x) as the price u changes. It is a straight line in u that starts at height f(x) with slope h(x). Each x gives one line, and g(u) is the lowest line at each u: their lower envelope. The figure draws five of these lines for our example.
Each x gives a straight line L(x, u) = x² + u(1 − x) in the price u. Solid lines are feasible points (x ≥ 1): their slope 1 − x is never positive, so each one starts at its cost f(x) and never rises. Dashed lines are infeasible points. The thick purple curve g(u) is the lowest line at each u, and it touches each line at u = 2x. Because it sits under every solid line, it sits under every feasible cost. That is weak duality in one picture.
The lowest of many straight lines always bends down, never up. It is a concave function: a cap shape, the negative of a convex function. Check it with numbers. Halfway between u = 0 and u = 2, the chord sits at (0 + 1)/2 = 0.5, while g(1) = 0.75 sits above it. Nothing in this argument used the shape of f or h. So g is concave for every problem, however nonconvex the primal is. CO4A 11-3
The dual problem asks for the best floor. Write d* for its best value:
d* = maximize g(u, v) s.t. u ≥ 0
Maximizing a concave function over the convex set u ≥ 0 is a convex problem, because maximizing a concave g is the same as minimizing the convex −g. So the dual is always a convex problem, even when the primal is not. There is one catch. Each value of g needs a minimization over x, and that can be hard when f is nonconvex. CO4A 11-3
5. Weak duality, strong duality, and Slater's condition
Back to the referee. Her best floor can never pass the true answer. This is weak duality: CO4A 11-3
d* ≤ p* (always)
The proof is the one line from Section 4: every g(u, v) is at most p*, so the best one is too. It holds for every problem, convex or not. The difference p* − d* ≥ 0 is the optimal duality gap. When it is zero we have strong duality, p* = d*: the referee's best floor touches the answer.
In the x2 example, d* = g(2) = 1 = p*, so there is no gap. The best price u* = 2 also carries the meaning from Section 1. Tighten the rule to x ≥ 1.1, and the best cost rises from 1 to 1.21. That is an increase of 0.21, close to u* × 0.1 = 0.2. The multiplier is the price of the rule. Boyd & Vandenberghe 2004
When is the gap zero? The standard test is Slater's condition. Suppose the problem is convex: f and every hi are convex, and every ℓj is affine. Suppose also that some point is strictly feasible: hi(x) < 0 for every i, and ℓj(x) = 0 for every j. Then p* = d*. Affine inequalities may even hold with equality; only the curved rules need room to spare. CO4A 11-4Tibshirani 2016
In words: a convex problem with a little wiggle room inside every curved rule has no gap. For x2 with x ≥ 1, the point x = 2 has h(2) = 1 − 2 = −1 < 0. Slater holds, and the gap is indeed zero.
An LP has only affine rules, so for LPs feasibility is enough. Strong duality holds whenever the primal or the dual is feasible, and it fails only if both are infeasible. Tibshirani 2016 That is why the max flow equals the relaxed min cut in Section 2.
Without convexity, a real gap can open. Take f(x) = x4 − 50x2 + 100x s.t. x ≥ −4.5. The cost has two valleys, near x = −5.4 and x = 4.4. The rule cuts off the deeper one, so the best feasible point sits on the boundary: p* = f(−4.5) = −1052.4375. CO4A 11-3
The Lagrangian is L = x4 − 50x2 + (100 − u)x − 4.5u. The best price is u = 100. It cancels the linear term and leaves two equal valleys at x = ±5, so g(100) = 625 − 1250 − 450 = −1075. No other price does better, so d* = −1075 and the gap is 22.5625. Note that strict feasibility holds here: x = 0 is strictly inside the rule. What fails is convexity. CO4A 11-3
Weak duality as a ceiling and a floor. The cost of every feasible point sits at or above p*, every floor g(u) sits at or below d*, and d* ≤ p* always. Left: in the convex problem the best floor reaches p* = 1. Right: in the nonconvex quartic the best floor, d* = −1075, stops 22.56 short of p* = −1052.44.
The gap is also useful while a solver runs. For any feasible x and any dual-feasible (u, v), the duality gap is f(x) − g(u, v). Since g(u, v) ≤ p* ≤ f(x), it bounds how far x is from the best value: CO4A 11-5
f(x) − p* ≤ f(x) − g(u, v)
For example, x = 1.2 costs f = 1.44, and the price u = 1.5 gives g = 1.5 − 0.5625 = 0.9375. The gap is 0.5025, so x is at most 0.5025 above the best value. (The truth is 0.44.) A gap of zero proves that both are optimal. Solvers stop once the gap falls below a tolerance ε, because then f(x) − p* ≤ ε is guaranteed. CO4A 11-5
Try it: drag the price u and watch the dashed priced cost L(x, u) tilt. Its lowest point, the orange dot, gives the floor g(u), the purple dot below. Then switch to the nonconvex quartic and hunt for the best price.
Notice: at the default price u = 1 the floor is g(1) = 0.75, a gap of 0.25, and L's lowest point x = 0.5 breaks the rule x ≥ 1. The purple curve stays under p* = 1 everywhere and touches it only at u = 2 (Slater holds: x = 2 is strictly feasible). On the quartic, the best floor is −1075 at u = 100, where L has two lowest points, x = −5 and x = 5. That floor stops 22.56 short of p* = −1052.44.
Common misunderstandings
"Weak duality needs a convex problem." It does not. d* ≤ p* holds for every problem, and the quartic shows it. Convexity matters only for strong duality.
"The multipliers can take any sign." Only the equality ones can. An inequality price must be u ≥ 0. With u < 0 a feasible point would pay a positive amount, L could exceed f, and the floor would break.
"Convex means no gap." Usually, but not always. You also need a condition such as Slater's. A convex example with a gap of 1 is in the box below.
"g(u) is the cost of some plan." It is a floor, not a plan. The x that minimizes L may break the rules: at u = 1 in the x2 example it is x = 0.5, which violates x ≥ 1.
"The quartic has a gap because Slater fails." x = 0 is strictly feasible. The gap comes from nonconvexity, since Slater's condition first needs a convex problem.
"h means the same thing in every book." In CO4A and Tibshirani, hi(x) ≤ 0 are the inequalities. In Boyd & Vandenberghe, hi(x) = 0 are the equalities. Check the letters before you copy a formula.
Going deeper (optional): why Slater closes the gap, and a convex problem with a gap
The proof uses a separating hyperplane. Collect every pair (rule value, cost) that some x can reach, together with everything above and to the right of it. For a convex problem this set is convex. So a hyperplane separates it from the points (0, t) with t < p*, which no x can reach. The tilt of that hyperplane gives the best price. The strictly feasible point stops the hyperplane from standing vertical, which would mean an infinite price. Boyd & Vandenberghe give the full argument in §5.3.2; CO4A does not prove it. Boyd & Vandenberghe 2004
Convexity alone is not enough. Boyd & Vandenberghe's exercise 5.21 minimizes e−x s.t. x2/y ≤ 0, over y > 0. The rule forces x = 0, so p* = 1. No point is strictly feasible, and the dual function is g(u) = 0 for every u ≥ 0: send x to infinity with y = x3, and both terms of L shrink to 0. So d* = 0, and the gap is 1. Boyd & Vandenberghe 2004
6. Worked example: the dual of a least-squares problem
A small robot has two thrusters. Thruster 1 pushes with force x1. Thruster 2 sits on a lever, so its force x2 counts double. Together they must deliver a push of exactly 5, so x1 + 2x2 = 5. Energy grows with the square of each force, so we want the least total effort:
minimize x12 + x22 s.t. x1 + 2x2 = 5
This asks for the shortest solution of a linear equation, a least-squares problem with a constraint. In matrix form it is min ‖x‖22 s.t. Ax = b, with A = [1 2] and b = 5. There is one equality, so there is one multiplier v, of any sign.
Step 1, the Lagrangian:
L(x, v) = x12 + x22 + v(x1 + 2x2 − 5)
Step 2, minimize over x. L is a bowl in x. Its gradient is (2x1 + v, 2x2 + 2v), which is zero at x1 = −v/2 and x2 = −v.
Step 3, plug back in. Then x12 + x22 = 1.25v2 and x1 + 2x2 − 5 = −2.5v − 5, so
g(v) = 1.25v2 + v(−2.5v − 5) = −1.25v2 − 5v
This is a downward parabola, concave as promised. Any v gives a floor. For example, v = −1 gives g = −1.25 + 5 = 3.75.
Step 4, maximize. The slope −2.5v − 5 is zero at v* = −2, so d* = g(−2) = −5 + 10 = 5.
Step 5, compare. Put v* = −2 into Step 2 to get x = (1, 2). It obeys 1 + 2·2 = 5, and its effort is 1 + 4 = 5 = d*. The gap is zero, as Slater predicts: the problem is convex and its only rule is affine.
Two things to notice. The multiplier v* = −2 is negative, which is allowed for an equality. And the dual's answer handed back the primal's answer through Step 2. Day 10 turns that into a rule.
The same five steps work for any A and b. The lowest point of L is x = −ATv/2, and
g(v) = −¼ vTAATv − bTv
Boyd & Vandenberghe work this exact problem in chapter 5, and CO4A 11-2 runs the same steps on quadratic programs. Boyd & Vandenberghe 2004CO4A 11-2 The few lines of Python below check every number.
import numpy as np
A = np.array([[1.0, 2.0]]); b = np.array([5.0]) # x1 + 2*x2 = 5
AAt = A @ A.T
x_star = A.T @ np.linalg.solve(AAt, b) # least-norm solution
g = lambda v: -0.25 * v @ AAt @ v - b @ v # dual function
v_star = -2 * np.linalg.solve(AAt, b) # where g peaks
print(x_star, x_star @ x_star) # [1. 2.] 5.0
print(v_star, g(v_star), g(np.array([-1.0]))) # [-2.] 5.0 3.75
print(-A.T @ v_star / 2) # [1. 2.]: primal from dual
Going deeper (optional): the dual of a general QP
Take min ½xTQx + cTx s.t. Ax = b, x ≥ 0, with Q ≻ 0. The rule x ≥ 0 reads −x ≤ 0 and gets prices u ≥ 0, so L = ½xTQx + cTx − uTx + vT(Ax − b). Its gradient is zero when Qx + c − u + ATv = 0, that is, x = −Q−1w with w = c − u + ATv. Plugging in gives
g(u, v) = −½ wTQ−1w − bTv
CO4A 11-2 prints the zero-gradient condition as Qx − (c − u + ATv) = 0. That is a sign slip, but its final g is right. When Q ⪰ 0 is singular, g = −½ wTQ+w − bTv if w lies in the range of Q, and −∞ otherwise. Here Q+ is the pseudo-inverse. The formula (QTQ)−1QT that the page gives for Q+ does not exist for a singular Q. CO4A 11-2Tibshirani 2016
7. Where duality goes next
Today's ideas carry much of the rest of the course. Three later days use them directly.
Day 10, KKT conditions. When the gap is zero, the best x* and the best prices u* are locked together by four conditions you can check. You have already met one. In the x2 example, u* = 2 is positive and the rule is tight at x* = 1. A rule with room to spare would get a price of zero.
Day 13, dual methods. Instead of solving the primal, climb the concave hill g. In our example the slope of g is g′(u) = 1 − u/2. That equals h(x̂) = 1 − x̂ at L's lowest point x̂ = u/2. So "raise the price while the rule is broken, lower it while there is room" walks uphill on g. That is dual ascent (dual ascent card), and ADMM grows from it (ADMM card).
Day 19, collision avoidance. A self-driving car must keep a safe distance from every obstacle. The distance between two convex shapes is itself a minimization, which is awkward to place inside a planner's constraints. OBCA writes that distance as a dual problem instead. By weak duality, any dual-feasible prices certify "the distance is at least this much". So the planner carries the prices as extra variables and asks the certified floor to exceed the safe distance. Strong duality means nothing is lost. See the OBCA paper.
Check yourself
Q1. For min x + 3y s.t. x + y ≥ 2, x ≥ 0, y ≥ 0, the referee puts weights (u1, u2, u3) = (1, 0, 2) on the three rules. What floor does that prove?
Adding 1·(x + y ≥ 2) + 0·(x ≥ 0) + 2·(y ≥ 0) gives x + 3y ≥ 2. The left side is the cost, so the floor is 2u1 = 2. Only the first rule has a nonzero right side, so the weights on x ≥ 0 and y ≥ 0 add nothing to the floor. That is why 6 and 4 are wrong.
Q2. For min x2 s.t. x ≥ 1, what is the dual function value g(1)?
g(u) = u − u2/4, so g(1) = 1 − 0.25 = 0.75. The number 0.5 is where L(x, 1) has its lowest point (x = 0.5), not the floor itself. The value 1 is p*, which the floor reaches only at u = 2.
Q3. Weak duality, d* ≤ p*, holds…
The one-line proof, g(u, v) ≤ L(x*, u, v) ≤ f(x*), uses only that x* is feasible and u ≥ 0. Convexity and Slater's condition are what you need for strong duality (d* = p*), not for weak duality.
Q4. The quartic problem min x4 − 50x2 + 100x s.t. x ≥ −4.5 is nonconvex. Its dual problem, maximize g(u) s.t. u ≥ 0, is…
For each fixed x, L(x, u) is a straight line in u, and g is their lower envelope. So g is concave for any problem, and maximizing it over u ≥ 0 is a convex problem. The two lowest points at u = 100 only mean that g has a kink there.
Q5. For min x2 s.t. x ≥ 1, the point x = 1.2 and the price u = 1.5 give f = 1.44 and g = 0.9375, a gap of 0.5025. What does that tell you?
Because g ≤ p* ≤ f(x), the gap is an upper bound on how far x is from the best, not the exact distance. Here the true distance is 1.44 − 1 = 0.44. Only a gap of zero would prove that x and u are both optimal.
Q6. Which fact proves strong duality for min x2 s.t. x ≥ 1?
That is Slater's condition: a convex problem with a strictly feasible point. Concavity of g proves nothing about the gap, because g is concave for every problem. The quartic also has a concave g, and its gap is 22.56.
Recap: things to remember
A dual variable is a price on a rule. Prices turn rules into floors, through weighted sums in an LP or the Lagrangian L = f + Σuihi + Σvjℓj in general. Inequality prices must be ≥ 0; equality prices may have any sign.
The dual function g(u, v) = min over x of L is a floor under p* for every u ≥ 0. It is always concave, so the dual problem is always convex.
Weak duality, d* ≤ p*, holds for every problem. Strong duality, d* = p*, holds for convex problems with a strictly feasible point (Slater) and for every feasible LP.
A feasible x and dual-feasible (u, v) bound the error: f(x) − p* ≤ f(x) − g(u, v). A zero gap certifies that both are optimal.
Numbers to keep: min x2 s.t. x ≥ 1 has g(u) = u − u2/4, u* = 2 and p* = d* = 1. The quartic has p* = −1052.44 and d* = −1075, a gap of 22.56.
After today you can write down and check the four KKT conditions, use them to solve problems by hand (equality-constrained QP, water-filling, SVM), and use conjugate functions and dual norms to write duals quickly.
About 60 min · Needs Day 9 · CO4A chapters 12 and 13
Today's big idea
At the best point of a constrained problem, the forces balance. The objective pulls downhill, each constraint you touch pushes back with a force λ ≥ 0, and constraints you don't touch push with zero force. Writing that balance down gives four checks, the KKT conditions. For a convex problem, passing all four proves you have the optimum.
1. Four checks at the bottom of the bowl
Picture a marble in a round bowl, with a straight fence across part of it. If the lowest point of the bowl is on the allowed side, the marble rolls there and the fence does nothing. If the lowest point is behind the fence, the marble ends up pressed against it. It stays put because the fence pushes back exactly as hard as the slope pulls.
Three facts hide in that picture. A fence can push but never pull. A fence the marble is not touching pushes with zero force. And at rest, the pull and all the pushes add up to zero. Add "the marble is on the allowed side", and you have the whole of today's lesson.
Now with numbers. Minimize f(x) = (x1 − 2)2 + (x2 − 1)2, a round bowl with its lowest point at (2, 1). Add one fence: x1 + x2 ≤ 2. The bowl's bottom breaks this rule, since 2 + 1 = 3, so the answer must lie on the fence line x1 + x2 = 2. The figure shows three versions of the problem.
Green is the allowed region; dashed circles are contour lines of f. Left: with the fence x1 + x2 ≤ 3.5, the bottom (2, 1) is allowed, so the fence pushes with zero force. Middle: with x1 + x2 ≤ 2, the marble rests at (1.5, 0.5). The downhill pull points straight through the wall, and the wall pushes back just as hard. Right: adding x2 ≤ 0.2 puts the marble in a corner, where two walls share the push.
Now the general version. A constrained problem asks to minimize f(x) subject to hi(x) ≤ 0 for i = 1, …, m and lj(x) = 0 for j = 1, …, r. As on Day 9, each inequality gets a multiplier and each equality gets a multiplier. Day 9 called them ui and vj, like CO4A's chapter 11 and the CMU slides. From today we switch to the more common names λi and νj. The Lagrangian is
L(x, λ, ν) = f(x) + Σ λihi(x) + Σ νjlj(x)
Think of λi as the force of fence i. The gradient ∇hi(x) points straight out of the allowed region, at right angles to the fence. A constraint with hi(x) = 0 is an active constraint: the marble touches that fence.
The KKT conditions are four checks on a candidate (x, λ, ν). They are named after Karush, who wrote them in a 1939 master's thesis, and Kuhn and Tucker, who published them in 1951. CO4A 12
Check
Formula
Plain meaning
1. Stationarity
∇f(x) + Σ λi∇hi(x) + Σ νj∇lj(x) = 0
the pull and the pushes cancel
2. Primal feasibility
hi(x) ≤ 0 and lj(x) = 0
the marble is on the allowed side
3. Dual feasibility
λi ≥ 0
fences push, never pull
4. Complementary slackness
λi · hi(x) = 0 for every i
an untouched fence pushes with zero force
Read stationarity as −∇f = Σ λi∇hi + Σ νj∇lj. The left side is the downhill direction. The right side mixes the outward normals of the walls you touch, with weights λi ≥ 0. So at the optimum, every downhill direction leads straight through a wall. If f or hi has kinks, use the subgradients of Day 7 in place of gradients. CO4A 12-01
Check the middle panel. Here h(x) = x1 + x2 − 2, so ∇h = (1, 1), and ∇f(x) = (2(x1 − 2), 2(x2 − 1)). Try x⋆ = (1.5, 0.5) with λ = 1. (The star ⋆ marks an optimum; the plain * is saved for section 7.)
The cost is f(x⋆) = 0.5. Day 9's dual function here is g(λ) = λ − λ2/2, which peaks at λ = 1 with value 0.5: the duality gap is zero. In the corner panel, ∇f(1.8, 0.2) = (−0.4, −1.6), and the wall normals (1, 1) and (0, 1) cancel it with λ1 = 0.4 and λ2 = 1.2. Both walls are doing work.
To find λ by hand, guess which constraints are active, solve stationarity with those constraints as equalities, and check the signs. Here the guess "active" gives x1 = 2 − λ/2 and x2 = 1 − λ/2, and x1 + x2 = 2 forces λ = 1. Had λ come out negative, the guess would be wrong, and that fence should be released.
The multiplier is also a price. Move the fence out by a small amount ε, and the best cost drops by about λε: with x1 + x2 ≤ 2.01 the optimum falls from 0.5 to 0.49005. Boyd & Vandenberghe 2004 For a car planner that keeps a margin from the lane edge, λ is the cost saved per centimetre of extra room.
2. When the checks are enough, and when they are required
Two different questions. If a point passes all four checks, is it optimal? That asks whether KKT is sufficient. If a point is optimal, does it pass? That asks whether KKT is necessary.
Sufficient, for convex problems. Suppose f and every hi are convex and every lj is affine (flat, like a line or plane). Then any (x, λ, ν) that passes all four checks is optimal, with zero duality gap. The one-line reason: stationarity says x minimizes the convex function L(·, λ, ν), so g(λ, ν) = L(x, λ, ν). Slackness and feasibility make that equal to f(x). A feasible point whose cost equals a lower bound cannot be beaten. CO4A 12-01Boyd & Vandenberghe 2004
Necessary, when strong duality holds.Strong duality means the primal and dual optimal values are equal. Then every optimal x⋆, paired with any dual optimal (λ⋆, ν⋆), passes the four checks. Day 9 gave an easy test for strong duality, Slater's condition: the problem is convex and some point is strictly feasible, with every hi(x) < 0. CO4A 12-01
Put together: for a convex problem that meets Slater's condition, "x is optimal" and "x passes KKT with some λ, ν" mean the same thing. So solving by hand means writing down the four checks and solving them.
Solvers use the same checks, but a computer never hits zero exactly. So it measures how far each check is from holding. These are the KKT residuals, such as the size of the stationarity left side or the amount of constraint violation. For convex problems, small residuals mean "nearly optimal".
The duality gap f(x) − g(λ, ν) is a second certificate, since it is never smaller than the true error f(x) − f⋆. CO4A 13-01 In our example, the feasible guess x = (1, 1) has f = 1, and λ = 0.5 gives g = 0.375. The gap promises an error of at most 0.625; the true error is 0.5.
This is how a model predictive controller (MPC) decides that it is done. A car's MPC solves a fresh quadratic program many times a second (Day 17). The OSQP solver stops when its primal residual ‖Ax − z‖∞ and dual residual ‖Px + q + ATy‖∞ both drop below a tolerance: 10−3, absolute and relative, by default as of Oct 2026. OSQP docsOSQP settings Its iterates meet complementary slackness by construction, so these two residuals are the KKT checks still open. The OSQP paper and the ADMM card show how it gets there. Interior-point solvers (Day 12) instead aim at a relaxed KKT system with λihi(x) = −1/t and tighten it as t grows. Boyd & Vandenberghe 2004
Going deeper (optional): why every optimum passes KKT under strong duality
Let x⋆ be primal optimal and (λ⋆, ν⋆) dual optimal, with f(x⋆) = g(λ⋆, ν⋆). Then
The last step holds because λ⋆i ≥ 0, hi(x⋆) ≤ 0 and lj(x⋆) = 0. Both ends are equal, so both inequalities are equalities. The first one says x⋆ minimizes L(·, λ⋆, ν⋆), which is stationarity. The second says Σ λ⋆ihi(x⋆) = 0. Every term in that sum is ≤ 0, so every term is 0, which is complementary slackness. CO4A 12-01CMU 10-725 2016
3. Only equality constraints: KKT is one linear system
Now replace the fences with rails: the point must stay on a line or a flat plane. With no inequalities, checks 3 and 4 have nothing to say. Two remain: the pull is balanced by the rails, and the point is on the rails. For a quadratic cost both are linear equations, so the whole problem is one linear solve.
The simplest picture: find the point on the line x1 + x2 = 1 closest to the origin. Your eye says (0.5, 0.5), where the line meets the direction from the origin at a right angle. KKT gets there mechanically.
The general problem is to minimize ½xTPx + qTx + r subject to Ax = b, with P ⪰ 0. Stationarity reads Px + q + ATν = 0 and feasibility reads Ax = b. Stacked, they form one square system: CO4A 12-02Boyd & Vandenberghe 2004
P x + ATν = −q A x = b
[ P AT ; A 0 ] [ x ; ν ] = [ −q ; b ]
Numbers: minimize ½(x12 + x22) subject to x1 + x2 = 1. Here P is the 2×2 identity, q = 0, A = [1 1] and b = 1. The three equations are x1 + ν = 0, x2 + ν = 0 and x1 + x2 = 1. So x⋆ = (0.5, 0.5) and ν⋆ = −0.5. The multiplier is negative, and that is fine. A rail can push either way, so only inequality multipliers carry a sign.
import numpy as np
P = np.eye(2); q = np.zeros(2)
A = np.array([[1.0, 1.0]]); b = np.array([1.0])
K = np.block([[P, A.T], [A, np.zeros((1, 1))]]) # the KKT matrix
sol = np.linalg.solve(K, np.concatenate([-q, b]))
x, nu = sol[:2], sol[2:]
print(x, nu) # [0.5 0.5] [-0.5]
Two links forward. On Day 11, Newton's method for equality-constrained problems solves this same system at every step, with P = ∇2f(x) and q = ∇f(x). CO4A 12-02 And a linear MPC with a quadratic cost, whose only constraints are the vehicle's linear dynamics, is exactly this kind of problem. One linear solve gives the whole plan. Add a steering limit or a lane bound and you get inequalities, which is why the solvers on Day 17 have to iterate.
4. Water-filling: pour the power into the quiet channels
A radio has four channels, each with its own noise level αi, and a fixed power budget P to split across them. Quiet channels turn power into data well, but every channel has diminishing returns. How should you split it?
Draw each channel as a vessel whose floor sits at height αi. Pour the whole budget in as water and let it settle. The water finds one common level, so quiet channels (low floors) get deep water and noisy ones get little or none. The depth in vessel i is its power xi. KKT says this picture gives the exact optimum.
Give λi to the constraint −xi ≤ 0 and ν to the budget. The four checks become
−1/(αi + xi) − λi + ν = 0 λixi = 0, λi ≥ 0, xi ≥ 0, Σ xi = P
Split into two cases. If channel i gets power (xi > 0), slackness forces λi = 0, so αi + xi = 1/ν: its water reaches the level 1/ν. If it gets none (xi = 0), then λi = ν − 1/αi ≥ 0, which means αi ≥ 1/ν: its floor is above the level. One formula covers both cases:
xi = max{0, 1/ν − αi}
Only one number is still unknown, the water level 1/ν. The budget fixes it through Σ max{0, 1/ν − αi} = P. The left side rises steadily with the level, so exactly one level works. This is water-filling. CO4A 12-03
Numbers: α = (0.1, 0.4, 0.6, 1.2) and P = 1. Guess that three channels are wet and write L = 1/ν. Then (L − 0.1) + (L − 0.4) + (L − 0.6) = 1, so 3L = 2.1 and L = 0.7. The guess holds up: the third floor (0.6) is below 0.7 and the fourth (1.2) is above. So x = (0.6, 0.3, 0.1, 0) and ν = 1/0.7 ≈ 1.4286.
The dry channel's multiplier is λ4 = ν − 1/α4 = 1.4286 − 0.8333 ≈ 0.595. Read it as a price again. Force a small amount of power ε into channel 4, taking it from the wet channels, and Σ log(αi + xi) drops by about 0.595ε. At the optimum Σ log(αi + xi) = −0.888, against −1.272 for an equal split of 0.25 each.
Try it: drag the budget and watch the channels switch on one by one. Then drag the level by hand. The formula keeps stationarity, dual feasibility and slackness at zero for any level, so only the budget residual moves. "Match budget" snaps it back.
Notice that at budget 1 the level is 0.700 (ν = 1.4286), the powers are 0.600, 0.300, 0.100 and 0, and the dry channel 4 has λ4 = 0.595. All four KKT residuals read 0.0000. The channels switch on at budgets 0, 0.30, 0.70 and 2.50, as the level reaches each floor.
Explain it to a 10-year-old
Think of a fish tank whose floor has four steps of different heights. You pour in one jug of water. The water's surface is flat, so the low steps end up under deep water and the high steps under shallow water. A step that sticks out above the surface stays dry. That is the best way to split radio power between quiet and noisy channels: deep water means lots of power.
5. SVM: the points that hold the line
A support vector machine separates two classes of points with the widest possible street. Only the points on the edge of the street, or inside it, matter. Delete a point that sits comfortably on its own side, and the street does not move. Complementary slackness is the reason.
A one-dimensional SVM with C = 1. The street runs from −1 to 1. The two points on its edges hold it in place with w = 0.5 each. The point at 3 is clear of the street, its constraint is slack, and its multiplier is 0: delete it and nothing changes.
The soft-margin SVM picks a direction β, an offset β0, and a slack ξi for each point, which measures how far point i intrudes into the street: CO4A 12-04
min ½‖β‖22 + C Σ ξi s.t. yi(xiTβ + β0) ≥ 1 − ξi, ξi ≥ 0
Here xi is a data point, yi = ±1 is its class, and C > 0 is the cost of an intrusion. Give the multiplier wi to the margin constraint and vi to ξi ≥ 0. Stationarity gives
β = Σ wiyixi, Σ wiyi = 0, wi = C − vi
Since vi ≥ 0, every wi lies between 0 and C. Complementary slackness, wi(1 − ξi − yi(xiTβ + β0)) = 0 and viξi = 0, then sorts the points into three groups:
Clear of the street (margin yi(xiTβ + β0) > 1): the constraint is slack, so wi = 0, and the point drops out of β.
On the edge (ξi = 0 and margin exactly 1): wi can be anywhere from 0 to C.
Inside the street or on the wrong side (ξi > 0): then vi = 0, so wi = C.
The points with wi > 0 are the support points, also called support vectors. They alone build β.
Numbers, in one dimension with C = 1: x = −1 (class −1), and x = 1 and x = 3 (class +1). The solution is β = 1 and β0 = 0, with no intrusions, and w = (0.5, 0.5, 0). Check stationarity: β = 0.5·(−1)·(−1) + 0.5·1·1 + 0·1·3 = 1, and Σ wiyi = −0.5 + 0.5 + 0 = 0. The point at 3 has margin 3 > 1, so slackness forces its w to 0. The primal cost ½β2 = 0.5 equals the dual value, so the gap is zero.
6. Budget or price: constrained and penalty forms
You can keep a model simple with a budget ("total size at most t") or with a price ("pay λ per unit of size"). A traveller told "spend at most $200" and one fined for every dollar spent can make the same choices, if the fine is set right. KKT says which price matches which budget.
(C) min f(x) s.t. h(x) ≤ t (L) min f(x) + λ h(x)
The second line is the Lagrange form, also called the penalized form. Going from (C) to (L): if (C) has a strictly feasible point, its KKT multiplier λ⋆ makes x⋆ a solution of (L). The reason is that the stationarity check of (C) is, word for word, the optimality condition of (L). Going back: a solution x⋆ of (L) solves (C) with t = h(x⋆). So as t and λ sweep their ranges, both forms trace out much the same family of solutions. CO4A 12-05CMU 10-725 2016
Numbers, with a one-dimensional lasso and data y = 3. The penalty form min ½(3 − β)2 + 1·|β| gives β = 2: shrink 3 toward zero by λ = 1, the soft-thresholding of Day 8. The budget form min ½(3 − β)2 s.t. |β| ≤ 2 also gives β = 2. Its stationarity check at β = 2 reads −(3 − 2) + λ·1 = 0, so its multiplier is λ = 1, the same price.
One more KKT fact, about the lasso min ½‖y − Xβ‖22 + λ‖β‖1 with n data points and p features. When p > n it could in principle have many solutions, but KKT shows that they all share the fitted values Xβ̂ and, for λ > 0, the value ‖β̂‖1. If the entries of X come from a continuous distribution, the solution is unique with probability 1. It also has at most min{n, p} nonzeros, even when p is far larger than n. CO4A 12-06 So a lasso fit on 50 samples of continuous data picks one answer that uses at most 50 features.
Going deeper (optional): why the lasso answer is unique
The lasso's KKT condition is XT(y − Xβ̂) = λs, where si = sign(β̂i) if β̂i ≠ 0 and si ∈ [−1, 1] otherwise. So every feature's correlation with the residual is at most λ in size, and the features in use sit exactly at ±λ. The equicorrelation set E = {i : |XiT(y − Xβ̂)| = λ} is the same for every solution, because the fit is. If the columns of XE are linearly independent, the KKT equations on E have one answer:
β̂E = (XETXE)−1(XETy − λsE)
with β̂ = 0 off E. Continuous data puts the columns in "general position", which makes them independent with probability 1. CO4A 12-06 prints (XETXET)−1 here; the second transpose is a typo. CO4A 12-06CMU 10-725 2016
7. Writing duals fast: dual norms and conjugates
CO4A chapter 13 collects tools that turn "derive the dual" from a page of algebra into a lookup. Two ideas do most of the work. CO4A 13
Dual norms. How big can zTx get if x must stay inside the unit ball of some norm? Picture a line at right angles to z, sliding outward until it last touches the ball. The point it last touches is the best x.
The orange arrow points along z = (3, −4). The dashed pink line is at right angles to z and is the last such line to touch each unit ball; the pink dot is the best x. The diamond's best point is a corner on an axis, which picks out the single largest entry of z. The square's best point is a corner that uses every entry.
That largest value is the dual norm of z:
‖z‖* = max { zTx : ‖x‖ ≤ 1 }
So |zTx| ≤ ‖x‖ · ‖z‖* for every x and z, a general form of the Cauchy–Schwarz inequality. The pairs to know are ℓ1 ↔ ℓ∞, ℓ2 ↔ ℓ2, and ℓp ↔ ℓq with 1/p + 1/q = 1. For matrices, the trace norm (sum of singular values) pairs with the operator norm (largest singular value). The dual of the dual is the original norm. CO4A 13-03Boyd & Vandenberghe 2004
With z = (3, −4), the diamond's best corner (0, −1) gives 4 = ‖z‖∞. The square's best corner (1, −1) gives 3 + 4 = 7 = ‖z‖1. The circle's best point z/5 gives 5 = ‖z‖2.
A robotics use: suppose a car's position error w is only known to satisfy |wi| ≤ 0.2 m in each coordinate. Then w can add at most 0.2‖c‖1 to cT(x + w), since ℓ1 is the dual of the box's ℓ∞. So a robust planner enforces cTx ≤ d − 0.2‖c‖1 in place of cTx ≤ d.
Conjugate functions. Picture selling x units at price y each, when making them costs f(x). Your best profit at price y is the conjugate of f. On a graph, yx is a line through the origin with slope y. The best profit is the biggest vertical gap between that line and the curve, and it sits where the curve's slope equals y.
f(x) = x² and price y = 2. The gap between the line 2x and the parabola is largest at x = 1, where the parabola's slope is also 2. The gap there is 1, so f*(2) = 1. The tangent with slope 2 meets the vertical axis at −1, which is −f*(2).
In symbols, the conjugate of f is
f*(y) = maxx [ yTx − f(x) ]
f* is always convex, even when f is not, because it is a maximum of functions that are linear in y. Fenchel's inequality, f(x) + f*(y) ≥ xTy, holds for every x and y, with equality when y is a slope (subgradient) of f at x. If f is closed and convex, then f** = f. CO4A 13-04Boyd & Vandenberghe 2004
Numbers with f(x) = x²: the gap yx − x² peaks at x = y/2, so f*(y) = y²/4. Fenchel at x = 1 and y = 2 gives 1 + 1 = 2 = xy, an equality because 2 is the slope of x² at 1. At y = 3 it gives 1 + 2.25 = 3.25 ≥ 3.
The indicator function IC is 0 on a set C and +∞ off it, which turns a constraint into a function. Its conjugate is the support function of C, max over x ∈ C of yTx. Four conjugates cover most needs:
f(x)
f*(y)
Why
x2
y2/4
best x = y/2
½xTQx, Q ≻ 0
½yTQ−1y
best x = Q−1y
‖x‖ (any norm)
0 if ‖y‖* ≤ 1, else +∞
the indicator of the dual-norm ball
IC(x)
maxx∈C yTx
the support function of C
For the quadratic, yTx − ½xTQx is strictly concave in x, and its maximizer is x = Q−1y. CO4A 13-04 copies a slip from the CMU slide and says "concave in y". CO4A 13-04CMU 10-725 2016
The shifting trick. For min f(x) + g(Ax), name z = Ax and give that constraint a multiplier u. Minimizing the Lagrangian over x and over z separately produces two conjugates: CO4A 13-04-03
dual: maxu −f*(ATu) − g*(−u)
With A = I, this splits min f(x) + g(x). When g is a norm, the table turns g*(−u) into the constraint ‖u‖* ≤ 1. CO4A 13-04-02 After solving the dual, you can read off x⋆ as the minimizer of L(x, u⋆), when that minimizer is unique. CO4A 13-02
The lasso shows the trick at work. Write z = Xβ in min ½‖y − z‖22 + λ‖β‖1. Minimizing over z gives z − y + u = 0, so z = y − u. (CO4A 13-04-01 and the CMU slide print "z − y + β = 0"; it should be u.) Minimizing over β leaves the constraint ‖XTu‖∞ ≤ λ, because ℓ∞ is the dual of ℓ1. The dual is CO4A 13-04-01
max ½(‖y‖22 − ‖y − u‖22) s.t. ‖XTu‖∞ ≤ λ
It finds the point of the region {u : ‖XTu‖∞ ≤ λ} closest to y, and that point is the lasso's residual: Xβ⋆ = y − u⋆. With X = 1, y = 3 and λ = 1, the region is |u| ≤ 1, so u⋆ = 1, which is indeed 3 − 2. The dual value ½(9 − 4) = 2.5 matches the primal ½·12 + 1·2 = 2.5.
One subtlety: rewriting that dual as min ‖y − u‖22 keeps the solution u⋆ = 1 but changes the optimal value to 4. A rewritten dual keeps its solution, not necessarily its value. CO4A 13-06
Analogy
A Lagrange multiplier is a price tag on a rule. Complementary slackness says a rule you are not even close to breaking costs nothing. A conjugate f*(y) is a price list: for each price y, the best profit a seller with cost curve f can make. Duality swaps "what should I do?" for "what is each rule worth?", and for convex problems that meet Slater's condition the two answers agree.
Going deeper (optional): dual cones and the double dual
The dual cone of a cone K is K* = {y : yTx ≥ 0 for all x ∈ K}: every vector that makes a non-obtuse angle with all of K. The nonnegative orthant ℝn+ and the cone of PSD matrices are their own dual cones. For min f(x) s.t. Ax ∈ K, the dual is max −f*(ATu) s.t. u ∈ K*. CO4A 13-05 If f and the hi are closed and convex and the lj are affine, the dual of the dual is the primal again. CO4A 13-06
Common misunderstandings
"KKT holds, so I have the minimum, whatever the problem." Only for convex problems. Minimize −x2 on −1 ≤ x ≤ 1: the point x = 0 passes all four checks with λ = 0, yet it is the worst point. The minima are at ±1.
"Every minimum satisfies KKT." Only when strong duality holds. Minimize x subject to x2 ≤ 0. The only feasible point, x = 0, is optimal, but stationarity needs 1 + 2λ·0 = 0, which no λ satisfies. Slater fails, since no x has x2 < 0.
"Equality multipliers must be ≥ 0." Only inequality multipliers carry a sign. In section 3, ν⋆ = −0.5.
"Complementary slackness means exactly one of λi and hi(x) is zero." Both can be zero. Put the fence at x1 + x2 ≤ 3: the bowl's bottom (2, 1) just touches it, so h = 0, and λ = 0 because ∇f = 0 there.
"The conjugate is a kind of inverse function, and needs f convex." It is a maximum over lines. It is defined for any f and is always convex.
Check yourself
Q1. At a KKT point, constraint i has hi(x) = −0.3. What must λi be?
Answer 3. Complementary slackness needs λi · (−0.3) = 0, so λi = 0: an untouched fence pushes with zero force. "Any value ≥ 0" is dual feasibility alone and forgets slackness.
Q2. Water-filling with noise α = (0.1, 0.4, 0.6, 1.2) and budget P = 1. What is the water level 1/ν?
Answer 1. Three channels are wet: 3L − 1.1 = 1 gives L = 0.7, and 0.6 < 0.7 < 1.2 confirms the guess. 0.825 assumes all four are wet, but then channel 4 would get 0.825 − 1.2 < 0. A level of 0.6 uses only 0.7 of the budget.
Q3. For a convex problem that satisfies Slater's condition, the KKT conditions are…
Answer 4. Convexity makes KKT sufficient. Slater gives strong duality, which makes KKT necessary. Without Slater you keep sufficiency but can lose necessity.
Q4. In a soft-margin SVM, a training point lies strictly outside the street: yi(xiTβ + β0) > 1. What is its multiplier wi?
Answer 2. Its margin constraint is slack, so complementary slackness forces wi = 0, and the point is not a support point. wi = C belongs to points inside the street or on the wrong side, and a multiplier can never be negative.
Q5. What is the dual norm of the ℓ1 norm?
Answer 4. Over the ℓ1 diamond, zTx is largest at a corner on an axis, which picks out the largest |zi|: that is ‖z‖∞. ℓ2 is its own dual; the trace norm pairs with the operator norm.
Q6. What is the conjugate f*(y) of f(x) = x2?
Answer 2. yx − x2 peaks at x = y/2 with value y2/2 − y2/4 = y2/4. y2/2 is the conjugate of ½x2, and 2y is the derivative of x2, not its conjugate.
Recap: things to remember
KKT is four checks: stationarity (the pull is balanced by the normals of the walls you touch), primal feasibility, dual feasibility (λ ≥ 0), and complementary slackness (λihi(x) = 0).
For convex problems KKT is sufficient. With Slater's condition it is also necessary. Without convexity a KKT point is only a candidate.
To solve by hand, guess the active constraints, solve, and check the signs. An equality-constrained QP is one linear system. Water-filling gives xi = max(0, 1/ν − αi). In an SVM, only the points with wi > 0 matter.
Multipliers are prices: λ tells how much the optimum improves per unit of loosening. Solvers such as OSQP stop when the KKT residuals are small.
The dual norm is ‖z‖* = max zTx over the unit ball (ℓ1 ↔ ℓ∞, ℓ2 ↔ ℓ2). The conjugate is f*(y) = max yTx − f(x). With them, min f(x) + g(Ax) has the dual max −f*(ATu) − g*(−u).
After today you can explain Newton's method as "minimise the local quadratic model", see why it converges quadratically near the optimum, and choose between gradient descent, Newton, BFGS and L-BFGS by iterations and cost per step.
About 60 min · Needs Day 6 · CO4A chapters 14, 18 and 19
Today's big idea
Newton's method fits a bowl to the function where you stand and jumps to the bowl's bottom. Near the answer the bowl fits so well that the correct digits double every step. The price is the bowl: an n × n matrix that costs O(n³) to solve with. Quasi-Newton methods learn the bowl from gradient changes instead, for O(n²) (BFGS) or O(mn) (L-BFGS) per step.
1. The Newton step: jump to the bottom of a fitted bowl
Gradient descent from Day 6 is like walking downhill in fog: you feel the slope under your feet and take a stride of a set length. Newton's method also feels how the slope is changing, the curvature. Slope plus curvature is enough to fit a bowl to the ground around you, and Newton jumps to the bowl's lowest point.
Start in one dimension. At the current point xk, measure the slope f′(xk) and the curvature f″(xk). The parabola with the same height, slope and curvature is the local quadratic model q(x):
q(x) = f(xk) + f′(xk)(x − xk) + ½f″(xk)(x − xk)2
The bottom of this bowl is where q′(x) = 0. Solving that one linear equation gives the 1-D Newton update:
xk+1 = xk − f′(xk) / f″(xk)
A worked example: f(x) = log(ex + e−x), whose minimum is at 0. At xk = 1 the slope is 0.76 and the curvature is 0.42, so the jump goes to 1 − 0.76/0.42 = −0.81. That overshoots 0 a little. Repeat the recipe and the points go 0.41, −0.047, 0.00007, closing in very fast. Boyd & Vandenberghe 2004
f(x) = log(ex + e−x) (solid) and the bowl q(x) fitted at xk = 1 (dashed). Newton jumps to the bowl's bottom, −0.81. That overshoots the true minimum 0, but the next bowl is fitted closer in.
In n dimensions the slope becomes the gradient ∇f(x) and the curvature becomes the Hessian ∇2f(x), the n × n matrix of second derivatives. The quadratic model of f around x is
Setting the model's gradient to zero gives the Newton step v, the jump to the bottom of the bowl. CO4A 14-01
∇2f(x) v = −∇f(x), x+ = x + v
Written with an inverse, v = −(∇2f(x))−1∇f(x). In code you never form the inverse: you solve the linear system, usually by Cholesky factorisation.
Gradient descent is the same recipe with a lazier bowl: (1/t)I in place of ∇2f, a round bowl whose bottom is x − t∇f(x). Newton's bowl has the right shape, long where the valley is long and steep where it is steep. So gradient descent zig-zags across a narrow valley while Newton heads straight in. CO4A 14-01-01
The cleanest example is a quadratic, f = ½(10x12 + x22) from (1, 1). Its quadratic model is the function itself, so one Newton step lands exactly on (0, 0). Gradient descent needs 106 steps with t = 0.1 to bring f below 10−10, and 62 with the best fixed step, t = 2/11.
A second view: minimising f means solving ∇f(x) = 0, and Newton's method began as a root finder. To solve F(x) = 0, replace F by its tangent and solve that: x+ = x − F′(x)−1F(x). With F = ∇f, F′ is the Hessian, so this is the same step. CMU 10-725 2016CO4A 14-02-01
2. Damped Newton: shorten the jump when the bowl is a poor guide
The bowl is fitted at one point. Near that point it matches f well; far away it can be a poor guide, and a full jump can land somewhere worse than where you started.
The function from section 1 shows this. Its full Newton step is x+ = x − ½sinh(2x). From x0 = 1.1 the points go −1.13, 1.23, −1.70, 5.71, −23,000, each jump overshooting more. Always taking the full step t = 1 is called pure Newton, and here it diverges from every |x0| > 1.0887. Boyd & Vandenberghe 2004
The fix keeps the direction and shortens the jump. Damped Newton picks the step length t by backtracking line search, as on Day 6: try t = 1, and while the drop in f is not "enough", shrink t.
t = 1; while f(x + tv) > f(x) + αt∇f(x)Tv: t = βt
Here α ∈ (0, ½] and β ∈ (0, 1). "Enough" means f falls by at least a fraction α of what the slope along v promises. CO4A 14-04 Boyd and Vandenberghe suggest a small α such as 0.01 and β around 0.5. Boyd & Vandenberghe 2004
Back to x0 = 1.1, now with α = 0.1 and β = 0.7. The first step is shortened once, to t = 0.7, and lands at −0.46. Then every full step passes the test: 0.068, −0.00021, 6·10−12. Four steps, only one damped.
That pattern is general. Near the optimum the full step t = 1 always passes the test (for α < ½), so damped Newton turns into pure Newton by itself and keeps the fast finish. CO4A 14-05
3. The Newton decrement: a built-in progress meter
Before Newton jumps, it already knows how deep its bowl is below the current point. That depth forecasts how much f will drop, and it is almost free once v is computed. The Newton decrement λ(x) measures it:
f(x) minus the bottom of the bowl equals λ2/2. This is the predicted drop.
The slope of f along the Newton step is ∇f(x)Tv = −λ2. That is the term the backtracking test uses.
λ is the length of the step v measured with the Hessian as the ruler: λ2 = vT∇2f(x)v.
The first reading gives a stopping rule. You cannot compute f(x) − p⋆ during a run, because the optimal value p⋆ is unknown, but you can compute λ2/2. Stop when it falls below a tolerance ε. Put together, this is Boyd and Vandenberghe's Algorithm 9.5. Boyd & Vandenberghe 2004
given a start x, tolerance eps, alpha in (0, 0.5], beta in (0, 1)
repeat:
g = grad f(x); H = hess f(x)
v = solve(H, -g) # Newton step (Cholesky)
lam2 = -g @ v # Newton decrement squared
if lam2 / 2 <= eps: stop # stopping rule
t = 1
while f(x + t*v) > f(x) - alpha*t*lam2:
t = beta * t # backtracking
x = x + t*v
How good is the forecast? On the widget's function (section 5), λ2/2 goes 4.45, 0.86, 0.14, 4.7·10−3, 5.6·10−6, 7.9·10−12, against true errors f − p⋆ of 6.60, 1.17, 0.157, 4.8·10−3, 5.6·10−6, 7.9·10−12. Rough at the start, almost exact at the end, which is where a stopping rule needs it.
4. Why it finishes so fast: two phases
Near the answer, Newton's next error is roughly the square of its current error. Square 10−3 and you get 10−6. Square that and you get 10−12. The number of correct digits doubles every step. This is quadratic convergence.
Compare linear convergence, where the error shrinks by a fixed factor each step. Gradient descent on the widget's function shrinks it by about 0.42 per step, one digit every two or three steps. Boyd & Vandenberghe 2004
Newton for x2 − 2 = 0 from x0 = 1: xk+1 = xk − (xk2 − 2)/(2xk). Coloured digits agree with √2. From step 2 the correct digits go 3, 6, 12, because each step roughly squares the error. The CMU slides show the same table.
In symbols, near a minimiser x⋆ there is a constant K with
‖x+ − x⋆‖ ≤ K ‖x − x⋆‖2
The one-line reason: the bowl gets the height, slope and curvature right, so it misses only through the change in curvature, and that miss shrinks like the distance squared. CO4A 14-02-03
This fast finish is local. Far from x⋆, Newton is in the damped phase: backtracking shortens some steps, and the theory promises only a fixed drop γ in f per step. Once the gradient is small enough, it enters the quadratic phase, takes t = 1 every time and never leaves. Counting both phases bounds the total number of steps: CO4A 14-05
iterations ≤ (f(x0) − p⋆)/γ + log2 log2(ε0/ε)
The second term is tiny: six quadratic-phase steps shrink the error bound by 2−64 ≈ 5·10−20. In practice that means some damped steps, then five or six full steps to machine precision. Boyd & Vandenberghe 2004
On the widget's function every Newton step is a full step, and the log10 error goes 0.82, 0.07, −0.80, −2.32, −5.25, −11.10: the last three exponents roughly double. The widget's "log of that sum" option shows both phases, with three shortened steps (t = 0.058, 0.49, 0.49) before the full steps.
Going deeper (optional): the constants, and self-concordance
The classic proof assumes f is m-strongly convex, ∇f is L-Lipschitz and ∇2f is M-Lipschitz. With η = min{1, 3(1 − 2α)}m2/M, the damped phase lasts while ‖∇f(x)‖2 ≥ η and cuts f by at least γ = αβη2m/L2 per step. (CO4A 14-05 prints β2; its own proof gives β.) CO4A 14-05
Nobody knows m, L and M in practice. For a self-concordant function (|f‴| ≤ 2f″3/2 along every line) the bound becomes C(α, β)(f(x0) − p⋆) + log log(1/ε), with no problem constants. The log barrier is self-concordant, which Day 12 relies on. CO4A 14-06CO4A 14-06-02
5. Units don't matter: affine invariance
Draw the same hillside on two maps, one in metres and one with the north–south axis in kilometres. Newton walks the same path on the ground, in the same number of steps, on both maps. Gradient descent does not: its bowl is round in the map's units, so stretching one axis changes its direction and its step count.
The reason in plain words: Newton's bowl is fitted to the function itself. Stretch the map and the bowl stretches with it, so its bottom stays at the same spot on the ground. This is affine invariance: an invertible linear change of coordinates leaves Newton's path unchanged.
In symbols, let x = Au with A invertible, and minimise g(u) = f(Au). The chain rule gives
∇g(u) = AT∇f(x), ∇2g(u) = AT∇2f(x) A
So Newton's step in the new units is Δu = −A−1(∇2f)−1∇f, and AΔu is exactly the old Newton step. The gradient step in the new units maps back to
AΔu = −t AAT∇f(x)
That is a different direction unless AAT is a multiple of I. (CO4A 14-02-02 writes the product as A∇f(x)AT, the wrong order.) The Newton decrement is unchanged too, so the stopping rule ignores units as well. CO4A 14-02-02Boyd & Vandenberghe 2004
The numbers make the point. On Boyd and Vandenberghe's test function (their eq. 9.20, used in the widget below), start at (−1, 1) and measure y in new units, y = s·u. Newton needs 5 steps for every s. Gradient descent needs 29 at s = 1, 53 at s = 0.2, 150 at s = 0.1, 596 at s = 5 and 2,345 at s = 10.
A car's planner mixes metres, radians and metres per second. Gradient descent needs someone to pick good scalings; Newton-type methods are far less sensitive, one reason robotics solvers lean on them.
Try it: read the step counts. Pick "Log of that sum" to see Newton's damped first steps, set "Rescale y by s" to 10, or tap the plot to move the start. (BFGS, the third path, comes in section 7.)
Notice: from (−1, 1), gradient descent needs 29 steps to reach an error of 10−10, BFGS 7 and Newton 5. Newton's error falls 6.6, 1.2, 0.16, 4.8·10−3, 5.6·10−6, 7.9·10−12, all with full steps, while gradient descent zig-zags across the valley.
6. The price of a Newton step
Newton buys few iterations with expensive ones. Each step needs the Hessian (n2 entries) and a linear solve with it. A dense Cholesky solve costs about n3/3 multiply-adds, so a step is O(n3). Gradient descent needs O(n) per step beyond the gradient. CO4A 14-07
With 8-byte numbers, at n = 1,000 the Hessian takes 8 MB and a solve about 3.3·108 operations, a fraction of a second. At n = 106 it would take 8 TB. Measured in seconds, Newton's lead shrinks, and for huge n it vanishes. CMU 10-725 2016
Structure rescues Newton. If the Hessian is banded or sparse, a step can cost O(n). CO4A 14-08 Trajectory problems are the standard case: each time step couples only to its neighbours, so the Hessian is block-banded and the cost grows linearly with the horizon. That is how model predictive control (Day 17) and trajectory optimisation (Day 18) afford Newton-type steps.
Equality-constrained Newton, briefly: to minimise f(x) subject to Ax = b, minimise the bowl while staying on the plane Ax = b. The step v and a multiplier estimate w solve the KKT system from Day 10:
∇2f(x) v + ATw = −∇f(x) A v = −(Ax − b)
Example: minimise ½(10x12 + x22) subject to x1 + x2 = 1 from (0.5, 0.5). The model is exact, so one step lands on the answer (1/11, 10/11) ≈ (0.091, 0.909), with w = −10/11, the optimal multiplier ν⋆. CO4A 14-08
Where Newton runs in practice: interior-point solvers (Day 12) take Newton steps on a smoothed KKT system. IPOPT, an open-source interior-point solver for nonlinear programs, uses exact second derivatives by default (as of Oct 2026) IPOPT docs and is a common back end for robot trajectory optimisation and nonlinear MPC (Day 16). SLAM and other least-squares problems use Newton's cousins Gauss–Newton and Levenberg–Marquardt (LM card). See also the Newton card.
Memory at n = 106 with 8-byte numbers: a vector 8 MB, an n × n matrix 8 TB, L-BFGS's ten pairs 160 MB. Schematic: at true scale each strip would be a millionth of the square's width.
7. Quasi-Newton: learn the curvature from the gradients
Quasi-Newton methods skip the Hessian and measure curvature from gradients they already have. After each step, compare the gradient before and after. The change per unit of step is a curvature reading, and it costs nothing extra.
Analogy
You can estimate a car's acceleration without an accelerometer. Read the speedometer twice, a second apart, and divide the change in speed by the time. Here the gradient plays the speedometer and the Hessian plays the acceleration.
The gradient of f(x) = log(ex + e−x) is tanh x. Two readings, at 0.5 and 1, give the secant slope y/s = 0.599, almost exactly the true curvature 0.597 halfway between.
In n dimensions, call the step s = x+ − x and the change in gradient y = ∇f(x+) − ∇f(x). The new curvature estimate B+ must explain the change you just saw. That requirement is the secant equation: CO4A 18-01
B+s = y, with sTy > 0
The second part is the curvature condition: along the step the slope went up, which a positive definite B+ needs. Strictly convex f gives it for free; otherwise the Wolfe conditions in the line search enforce it.
One vector equation cannot pin down a whole matrix, so each quasi-Newton method picks, in its own sense, the B+ closest to the old B. Three updates matter. CMU 10-725 2016
SR1 (symmetric rank one): B+ = B + uuT/(uTs) with u = y − Bs. Simplest, but it can lose positive definiteness, and the denominator can be near zero. CO4A 18-02
DFP (Davidon–Fletcher–Powell): a rank-2 update of the inverse estimate H = B−1 that stays positive definite when sTy > 0. CO4A 18-03
BFGS (Broyden–Fletcher–Goldfarb–Shanno): DFP with the roles of B and H swapped. It stays positive definite, recovers from bad early estimates better than DFP, and is the standard. CO4A 18-04
BFGS is usually written for the inverse estimate H, so the step is a matrix–vector product, −H∇f, with no linear solve. With ρ = 1/(yTs):
H+ = (I − ρsyT) H (I − ρysT) + ρssT
Both the update and the step cost O(n2), and the start can be H = I, so no Hessian is ever computed. The idea goes back to William Davidon, whose mid-1950s computer runs kept crashing before they finished, so he needed a method that converged faster. CO4A 18
A worked example: f = ½xTQx with Q = diag(10, 1), B = H = I and step s = (1, 1), so y = Qs = (10, 1) and sTy = 11 > 0. SR1 recovers the exact Hessian diag(10, 1) in one update. BFGS gives H+ ≈ [[0.107, −0.074], [−0.074, 1.744]]: it satisfies H+y = s, stays positive definite (eigenvalues 0.104 and 1.747), and its corner 0.107 is already near the true 0.1.
The payoff is superlinear convergence: the ratio between successive errors goes to zero, slower than quadratic but far faster than linear. In the widget, BFGS's first step is exactly gradient descent's, because it starts from H = I; after that it learns the curvature and finishes in 7 steps to Newton's 5. A rough rule of thumb from the slides: n quasi-Newton steps do the work of one Newton step. CO4A 14-09CO4A 18-06
BFGS still stores an n × n matrix, 8 TB at n = 106. L-BFGS (limited-memory BFGS) keeps only the last m pairs (s, y), typically m = 3 to 20, and rebuilds H∇f from them with two loops of dot products, never forming a matrix. Memory is 2mn numbers (160 MB for m = 10, n = 106) and the work about 4mn multiplications per step. Chen 2025 (UW CS726)CO4A 18-07
# L-BFGS direction p = -H g from the last m pairs (s[i], y[i])
q = -g
for i in newest ... oldest: # i = k-1 down to max(k-m, 0)
a[i] = (s[i] @ q) / (y[i] @ s[i])
q = q - a[i] * y[i]
p = gamma * q # gamma = s@y / y@y of the newest pair
for i in oldest ... newest: # i = max(k-m, 0) up to k-1
b = (y[i] @ p) / (y[i] @ s[i])
p = p + (a[i] - b) * s[i]
return p # about 4mn multiplications
CO4A's figure of this recursion, copied from the slides, prints min(k − m, 0) where max(k − m, 0) is meant. The price of the diet is a weaker guarantee, only linear convergence in general, yet L-BFGS is the default for large smooth problems. As of Oct 2026, SciPy's minimize uses BFGS when unconstrained and L-BFGS-B with bounds, SciPy 1.18 docs scikit-learn's logistic regression defaults to lbfgs, scikit-learn 1.9 docs and IPOPT's limited-memory option keeps 6 pairs. IPOPT docs See the BFGS card.
Method
Needs
Memory
Work per step (dense)
Near the answer
Pick it when
Gradient descent
gradient
O(n)
O(n)
linear
n is huge and modest accuracy is enough
Newton
gradient and Hessian
O(n2)
O(n3), or O(n) if banded
quadratic
n is up to a few thousand, or the Hessian is sparse, and you want high accuracy
BFGS
gradient
O(n2)
O(n2)
superlinear
n is moderate and the Hessian is unavailable or too costly
L-BFGS (m pairs)
gradient
O(mn)
O(mn), about 4mn
linear guaranteed, often fast
n is large (millions) and f is smooth
Sources: CO4A 14-07, the CMU slides and Chen's UW notes. BFGS's O(n2) is standard arithmetic, not stated in those sources.
Going deeper (optional): proximal Newton
For f = g + h with g smooth and h nonsmooth (say λ‖x‖1), proximal gradient (Day 8) fits the round bowl (1/t)I to g. Proximal Newton fits H = ∇2g instead: v = argmin ∇gTv + ½vTHv + h(x + v), then x+ = x + tv. This is a scaled proximal map, a prox in the H-norm; h = 0 gives Newton and H = I/t gives proximal gradient. CO4A 19-01-02
It is quadratic near the answer, but each step is a lasso-like subproblem, so it pays off only with a fast inner solver such as coordinate descent (Day 14), as in glmnet and QUIC. CO4A 19-03CO4A 19-05CMU 10-725 2016
Explain it to a 10-year-old
You are blindfolded on a skateboard in a bowl-shaped park and want to stop at the bottom. One friend only says which way is downhill, so you roll a bit and ask again. A second friend also says how the ground curves, so you roll straight to the bottom: that is Newton. A third friend remembers how the slope changed after each roll and learns the shape as you go: that is BFGS.
Common misunderstandings
"Newton always converges because it uses more information." Pure Newton on log(ex + e−x) diverges from x0 = 1.1. You need the line search (damped Newton).
"Quadratic convergence happens from the start." It is local. Far from the answer you are in the damped phase, where the guarantee is only a fixed drop per step.
"Fewer iterations means faster." A dense Newton step costs O(n3), a gradient step O(n). In seconds Newton's lead shrinks, and at n = 106 a dense step is impossible.
"BFGS needs the Hessian to start." H = I is a fine start. The curvature is learned from gradient changes.
"L-BFGS is just as good as BFGS." It trades BFGS's superlinear guarantee for O(mn) memory: usually a good trade for large n, but a trade.
Check yourself
Q1. You run pure Newton on a strictly convex quadratic f(x) = ½xTQx + cTx in ℝn. How many steps does it need to reach the exact minimum?
One step. The quadratic model of a quadratic is the function itself, so the bowl's bottom is the true minimum. "n steps" is the answer for conjugate gradients in exact arithmetic, and the condition number matters for gradient descent, not for Newton.
Q2. What does one Newton step cost with a dense n × n Hessian?
O(n3), for the Cholesky solve (about n3/3 operations). O(n2) is a dense BFGS step, which needs only a matrix–vector product, and O(mn) is L-BFGS. A banded Hessian can bring Newton down to O(n).
Q3. B+ is the new estimate of the Hessian, s = x+ − x and y = ∇f(x+) − ∇f(x). Which equation must B+ satisfy?
The secant equation B+s = y: curvature times step must equal the change in gradient. The tempting B+y = s is the version for the inverse estimate H = B−1, not for B. And sTy must be positive, not zero, to keep B+ positive definite.
Q4. You run pure Newton (always t = 1) on f(x) = log(ex + e−x) from x0 = 1.1. What happens?
It diverges: −1.13, 1.23, −1.70, 5.71, −23,000. Each full jump overshoots the minimum at 0 by more than the last. Damped Newton with backtracking fixes it, converging in four steps.
Q5. In the widget, Newton needs 5 steps. You rescale y by s = 10. How many steps does Newton need now?
Still 5, along the same path. Newton's method is affine invariant: its bowl stretches with the coordinates. 2,345 is gradient descent's count at s = 10.
Q6. You must minimise a smooth function of n = 106 variables. Gradients are cheap and no Hessian is available. Which method fits best?
L-BFGS: it needs only gradients and stores 2mn numbers, about 160 MB. BFGS also needs only gradients, but its n × n matrix would take 8 TB, and so would a dense Hessian for Newton.
Recap: things to remember
Newton fits a quadratic bowl at x and jumps to its bottom: solve ∇2f(x)v = −∇f(x). Gradient descent is the same idea with a round bowl (1/t)I.
Use damped Newton: backtracking from t = 1. Stop when the Newton decrement's forecast λ2/2 falls below ε.
Convergence has two phases, damped and then quadratic. In the quadratic phase the correct digits double each step, so a few full steps reach machine precision.
Newton is affine invariant (units don't matter); gradient descent is not. In the widget a y-rescale moves gradient descent from 29 to 2,345 steps and leaves Newton at 5.
Cost per step: Newton O(n3), BFGS O(n2), L-BFGS O(mn) with m = 3–20. Quasi-Newton methods learn curvature from the secant equation B+s = y.
After today you can explain how a log barrier turns inequality constraints into a smooth penalty, follow the central path to the optimum, and see why interior-point solvers finish in a few tens of Newton steps almost regardless of problem size.
About 60 min · Needs Days 10 and 11 · CO4A chapters 15, 16 and 17
Today's big idea
Replace every hard wall by a smooth penalty that rises to infinity as you approach it, then minimize cost plus penalty with Newton's method. Weaken the penalty step by step, and the minimizers slide along a smooth curve, the central path, to the true optimum. Every point on that curve comes with a certificate: its cost is at most m/t above the best possible.
1. Inequalities are walls: soften them with a log barrier
Picture a robot vacuum heading for the dirtiest spot in a room. If the spot is in the middle, the walls do not matter. If it is in a corner, two walls decide the answer. You do not know in advance which walls you will end up touching.
That is the hard part of every problem with "≤" rules hi(x) ≤ 0. A rule that holds with equality at the answer is active, and the set of active rules is the active set. With m rules there are many possible active sets, and trying them one by one gets slow. CO4A 15-1-1
One exact trick moves the rules into the cost. The indicator function IC(x) is 0 when x is in the feasible set C and +∞ outside it. Minimizing f(x) + IC(x) is the same problem as before. But IC is a cliff: flat, then infinitely high. Newton's method (Day 11) learns from slope and curvature, and a cliff has neither.
The fix is a smooth wall that starts rising before you reach it. For one rule x ≤ b, use the penalty −log(b − x). The gap b − x is the slack, the room you have left. The penalty is 0 at slack 1. It is 2.30 at slack 0.1, 4.61 at slack 0.01 and 6.91 at slack 0.001. Every 10× step closer adds 2.30, and at slack 0 the penalty is infinite.
One rule, x ≤ 3. The exact indicator (black) is 0 and then a vertical cliff. The smooth walls −(1/t)·log(3 − x) are finite everywhere inside and climb to +∞ at the wall. The t = 1 curve is −log(3 − x) itself, and a larger t follows the indicator more closely. (CO4A 15-1-2 draws the same picture.)
For general rules hi(x) ≤ 0, the slack is −hi(x), and the log barrier puts one such wall on every rule: CO4A 15-1-2
φ(x) = −Σi log(−hi(x))
φ is defined only where every hi(x) < 0. Such points are strictly feasible: they keep some room from every wall. If every hi is convex, so is φ, and it is smooth there.
To imitate the cliff, scale the wall by 1/t. The barrier parameter t > 0 sets how sharp the wall is. With t = 2, the penalty at slack 0.01 drops from 4.61 to 2.30, yet the wall itself stays infinite. So a larger t hugs the indicator more closely.
Newton also needs the slope. For a linear rule aiTx ≤ bi, write the slack as si = bi − aiTx. The chain rule gives: CO4A 15-1-3
∇φ(x) = Σi ai / si ∇2φ(x) = Σi aiaiT / si2
Read each term −ai/si as a push away from wall i with strength 1/slack. At slack 1 the push is 1, and at slack 0.01 it is 100. Boyd and Vandenberghe call this a force field. Boyd & Vandenberghe 2004, §11.2
The point where all the pushes cancel minimizes φ by itself. It is the analytic center, the point that is farthest from all the walls in this log sense. Worked example: the pentagon x1 ≥ 0, x2 ≥ 0, x1 ≤ 3, x2 ≤ 3, x1 + x2 ≤ 4. At (1, 1) the five slacks are 1, 1, 2, 2 and 2, and the pushes add up to zero. So (1, 1) is the analytic center. This pentagon is today's running example.
The force picture of ∇φ at (1, 1). Each colored wall pushes the point away from itself with strength 1/slack, drawn as the arrow of the same color. The two near walls push with 1, the three far walls with ½ times their direction ai, and the total is zero.
Analogy: an electric fence
The indicator is an invisible fence that you only notice when you hit it. The log barrier is a fence that buzzes from a few steps away, louder the closer you get. You stay inside without ever touching it. Raising t shrinks the buzz zone, so you can walk closer to the fence before it bothers you.
2. The barrier problem and the central path
Put a ball on a table with springy walls, and tilt the table toward one corner. A gentle tilt leaves the ball near the middle. A steep tilt rolls it close to the low corner, but the springs keep it off the walls. The tilt is t, and the ball's resting place is x*(t).
In symbols, multiply the cost by t and add the barrier. The barrier problem is: CO4A 15-1-2
minimize t·f(x) + φ(x) subject to Ax = b
It has the same minimizer as f + (1/t)·φ, and no inequality rules are left, so Newton's method (Day 11) can solve it. Call its minimizer x*(t).
As t grows from 0 to ∞, x*(t) traces a smooth curve called the central path. Small t means "mostly stay away from the walls", so the path starts near the analytic center. Large t means "mostly care about cost", so the path ends at the optimum x*. CO4A 15-2
The smallest example: minimize x subject to x ≥ 0. The barrier problem is minimize t·x − log x. Setting the slope t − 1/x to zero gives x*(t) = 1/t. So t = 1 gives 1, t = 10 gives 0.1, and t = 100 gives 0.01. The true answer is 0, and the error is exactly 1/t.
Now the pentagon. Minimize cTx with c = (−1, −2), that is, push up and to the right, with x2 counting twice. The optimum is the corner (1, 3), with cost p* = −7. Setting the gradient of t·cTx + φ(x) to zero gives the centering condition:
t·c + Σi ai / si = 0
In words: at x*(t), the pull of the cost, −t·c, balances the total push of the walls. Newton's method gives these points (m = 5 rules; section 3 explains the last column):
t
x*(t)
cost cTx*(t)
true error cTx*(t) − p*
bound m/t
0.1
(1.0429, 1.1321)
−3.3071
3.693
50
1
(1.1384, 2.1161)
−5.3705
1.629
5
10
(1.0062, 2.8985)
−6.8032
0.197
0.5
100
(1.0001, 2.9900)
−6.9800
0.020
0.05
The path bends. x1 first rises to about 1.14, then returns to 1 as the top wall and the diagonal wall close in. In the widget below, the cost line through x*(t) just touches the barrier level curve there, because the two gradients balance. CO4A 15-2
Try it: drag the slider from t = 0.01 to t = 1000, or press the t buttons. The orange dots are the Newton iterates of the last move. A warm start from the previous t usually needs only a few steps.
Notice: at the default t = 1, x*(t) = (1.1384, 2.1161), reached in 6 Newton steps from the analytic center (1, 1). The primal cost −5.3705 minus the dual value −10.3705 is exactly 5 = m/t. Press t = 10 and t = 100: the point moves to (1.0062, 2.8985) and (1.0001, 2.9900), and the guaranteed gap falls to 0.5 and 0.05. The dot never touches a wall.
3. The duality gap m/t: a certificate for free
A delivery app says "at most 5 minutes away". You do not know the exact arrival time, but you have a guaranteed bound. Each central point gives the same kind of promise about cost: you are at most m/t above the best value, even though you do not know that value.
Where does it come from? Day 9 showed that any dual feasible point gives a lower bound on p*, and a central point hands you one. The barrier problem's optimality condition is t∇f(x) + ∇φ(x) + ATw = 0, where w is the multiplier of Ax = b. Set: CO4A 15-3-1
ui(t) = −1 / (t·hi(x*(t))), v(t) = w / t
Each ui is positive, because hi < 0. For an LP it is simply ui = 1/(t·si). Divide the centering condition by t, and it becomes ∇f + Σ ui∇hi + ATv = 0. That is the stationarity condition of Day 10, so x*(t) minimizes the Lagrangian at (u, v), and (u, v) is dual feasible.
Compare the whole list with the KKT conditions. Only one line really changes: complementary slackness becomes "uihi = −1/t" instead of "= 0". These are the perturbed KKT conditions. As t → ∞ they turn back into KKT.
Condition
KKT (Day 10)
Central path at t
Stationarity
∇f + Σ ui∇hi + ATv = 0
the same
Primal feasibility
hi(x) ≤ 0, Ax = b
hi(x) < 0, Ax = b
Dual feasibility
ui ≥ 0
ui > 0
Complementary slackness
uihi(x) = 0
uihi(x) = −1/t
Now the gap. The dual function at (u, v) is the Lagrangian at x*(t). In it, each product uihi equals −1/t, and the term vT(Ax − b) is zero. Adding the m products gives: CO4A 15-3-2
f(x*(t)) − g(u, v) = m / t so f(x*(t)) − p* ≤ m / t
The duality gap, primal value minus dual value, is exactly m/t, where m is the number of inequality rules. Weak duality says g(u, v) ≤ p*, which turns the gap into a bound on the true error.
Check it on the pentagon at t = 1. The slacks at x*(1) give u = (0.8784, 0.4726, 0.5372, 1.1313, 1.3413). This LP's dual value is −bTu = −10.3705, and the primal value is −5.3705. The gap is exactly 5.0000 = 5/1. The true error is only 1.63, so the bound is safe but not tight.
The multipliers also tell you which walls matter. As t → ∞, u approaches (0, 0, 0, 1, 1), the true KKT multipliers u*. They are nonzero only for x2 ≤ 3 and x1 + x2 ≤ 4, the two walls that meet at (1, 3). Check: ATu* + c = (1, 2) + (−1, −2) = 0. In the 1-D example, u(t) = 1/(t·x*(t)) = 1 for every t, which is already the true multiplier.
This also gives a stopping rule. To be within ε of optimal, stop once m/t ≤ ε, that is, once t ≥ m/ε. For the pentagon with ε = 10−6, you need t ≥ 5 × 106.
4. The barrier method: raise t, then re-center with Newton
If t ≥ m/ε is all we need, why not set t = 5 × 106 at once? CO4A calls this barrier method v.0, and it is a bad idea. With a huge t, the barrier problem is badly conditioned: its valley is a steep, narrow canyon pressed against the walls. Newton's method started far away needs many small damped steps to get in. CO4A 15-4
Climb stairs instead. Each riser multiplies t by a factor μ > 1, which divides the guaranteed gap by μ. Each tread is a short Newton run that starts from the previous center. That start is already close to the new center, so Newton is in its fast, quadratic zone (Day 11).
The barrier method. The outer loop raises t; the inner loop is a few Newton steps that re-center. The warm start from the previous center keeps each inner loop short.
Each re-centering is a centering step. Raising t is an outer iteration, and each Newton step inside a centering is an inner iteration. The factor μ is the update factor. In pseudocode: CMU 10-725 2016
given strictly feasible x, t := t0 > 0, mu > 1, eps > 0
repeat
# centering (inner loop): Newton's method on t*f + phi,
# subject to Ax = b, started from the current x
x := argmin t*f(x) + phi(x)
if m / t <= eps: stop # certificate from section 3
t := mu * t # outer iteration
The number of outer iterations is known in advance. After k raises the guaranteed gap is m/(μkt(0)), so you need this many raises, plus the first centering: CO4A 15-5
⌈ log(m / (t(0)ε)) / log μ ⌉
For the pentagon with t(0) = 1 and ε = 10−6, log(5 × 106) = 15.4. With μ = 2 that is ⌈22.2⌉ = 23 raises, so 24 centerings. With μ = 10 there are 8 centerings, and with μ = 50 or μ = 150 there are 5.
So how should you pick μ? A small μ gives many outer iterations, but each needs only 1–3 Newton steps, because the new center is close. A large μ gives few outer iterations, each needing more Newton steps. The totals hardly change. Boyd and Vandenberghe found the total nearly flat for μ from about 3 to 200, and suggest 10 ≤ μ ≤ 100. Boyd & Vandenberghe 2004, p. 573
On the pentagon (start (1, 1), t(0) = 1, ε = 10−6), μ = 2 takes 35 Newton steps in total, μ = 10 takes 39, μ = 50 takes 30 and μ = 150 takes 27. With μ = 2, the centerings take 5, 3, 2, 2, 2, 2, 2 steps and then 1 step each. Centering need not be exact either; practical codes stop each Newton run early (CO4A's barrier method v.2). CO4A 15-6
Try it: read each staircase as the gap m/t against total Newton steps. Then switch to a random LP with m = 100 rules: the problem is 20 times larger, but the totals grow far less.
Notice: on the default pentagon, μ = 2, 10, 50 and 150 need 35, 39, 30 and 27 Newton steps (24, 8, 5 and 5 centerings), and primal-dual reaches η ≤ 10−8 in 13 steps. With m = 100, the barrier totals are 73, 58, 45 and 41, and primal-dual needs 21.
5. Phase I: finding a point strictly inside
The barrier method must start strictly inside every wall, because φ is undefined anywhere else. Often you have no such point. A driving planner may start from a guess that cuts into an obstacle margin. Is there any trajectory that obeys every rule?
Ask a different question whose start is easy: how far must every rule be loosened before my guess obeys it? Add one extra variable s and solve the phase I problem: CO4A 15-7
minimize s over (x, s) subject to hi(x) ≤ s, Ax = b
Any x with Ax = b, together with any s larger than maxi hi(x), is strictly feasible for this problem. So the barrier method can start on it right away.
Then read the sign of the optimal s*. If s* < 0, every rule holds with room to spare: a strictly feasible start. If s* > 0, no point obeys all the rules, so the problem is infeasible. In practice you stop phase I as soon as s drops below 0.
Pentagon example: start from the bad guess x = (5, 5). The rule values aiTx − bi are (−5, −5, 2, 2, 6), so s(0) = 7 is strictly feasible for phase I. The phase I optimum is s* = −4/3 at x = (4/3, 4/3). There the slacks of x1 ≥ 0, x2 ≥ 0 and x1 + x2 ≤ 4 all equal 4/3. Since s* < 0, a strictly feasible start exists.
A variant gives each rule its own slack: minimize 1Ts subject to hi(x) ≤ si, s ≥ 0 and Ax = b. When the problem is infeasible, the nonzero si point to the rules that cannot be met, for example a speed limit that clashes with an arrival deadline. That makes it a good debugging tool. CMU 10-725 2016
Modern solvers rarely run a separate phase I. Primal-dual methods (next section) can start from infeasible points. MOSEK's interior-point optimizer solves a homogeneous self-dual model, which returns either a solution or a certificate that none exists. Clarabel also uses a homogeneous embedding. MOSEK docsClarabel docs
6. Duality revisited, and the primal-dual method
CO4A's chapter 16 looks at an LP from both sides at once. Take an LP in standard form and its dual: CO4A 16-1CMU 10-725 2016
primal: minimize cTx s.t. Ax = b, x ≥ 0 dual: maximize bTy s.t. ATy + s = c, s ≥ 0
Here s is the dual slack. The KKT conditions are Ax = b, ATy + s = c, x ≥ 0, s ≥ 0 and xisi = 0 for every i. The central path relaxes only the last condition, to xisi = τ with τ = 1/t > 0. CO4A 16-2
This view separates two families of LP methods. The simplex method keeps the equations and xisi = 0 true at every step, and fights for x, s ≥ 0. It walks from corner to corner: on the pentagon, from (0, 0) to (0, 3) and then to (1, 3). Interior-point methods keep x, s > 0 true and drive xisi toward 0. They cut through the middle.
The symmetry goes further. The dual of the LP barrier problem is the barrier problem of the dual LP. Semidefinite programs (Day 5) follow the same pattern. The primal "minimize tr(CX) s.t. tr(AiX) = bi, X ⪰ 0" has the dual "maximize bTy s.t. Σ yiAi ⪯ C". The barrier is −log det X, and the central path is XS = τI. CO4A 16-3CO4A 17-5
Now the method. The barrier method walks to each station on the central path before heading for the next one. The primal-dual interior-point method cuts the corner: it never re-centers fully, and aims each step at a moving target on the path. CO4A 17-2
Treat the perturbed KKT conditions as equations r(x, u, v) = 0 in the primal x and the duals u and v together. Each of the three blocks is a residual: how much one group of conditions is violated. CO4A 17-2-1
Day 11's Newton method also solves equations: linearize r around the current point, solve one linear system for the step (Δx, Δu, Δv), and move. The primal-dual method takes one such step, lowers τ, and repeats. There is one loop instead of two.
The iterates need not be feasible: Ax = b and dual feasibility hold only in the limit. So the m/t certificate does not apply directly. Instead the method tracks the surrogate duality gap: CO4A 17-2-2
η = −h(x)Tu = Σi uisi
It equals the true duality gap once rdual = 0 and rprim = 0. Each iteration sets τ = σ·η/m with σ = 1/μ, a fraction of the current average uisi. A careful line search keeps the iterates interior. It caps the step so that u stays positive, starts at 0.99 of that cap, halves until h(x) < 0, and halves again until the residual has shrunk enough. CO4A 17-2-3
Pentagon numbers. Start at x = (1, 1) with ui = 1/si = (1, 1, 0.5, 0.5, 0.5), so η = 5. The dual residual ATu + c has length 2.24, so this u is not dual feasible: an infeasible start. With μ = 10, η goes 5 → 2.31 → 1.64 → 0.75 → 0.40 → 0.22 → 0.020 → 0.0022, and from then on it shrinks about 9× per step. After 13 iterations, η ≤ 10−8 and ‖rdual‖ ≤ 10−8, with x = (1, 3) and u = (0, 0, 0, 1, 1). The barrier method needed 27–39 Newton steps for less accuracy.
A zoomed view of the pentagon (x1 is stretched about 4×). The barrier method (orange) overshoots to the right at t = 1 and then walks back to the center x*(1), then repeats at t = 10, 100, 1000. The primal-dual iterates (blue) take one Newton step each and cut across, never sitting exactly on the path. Both reach the corner (1, 3).
A few slips in the CO4A pages are worth knowing about. In 15-3-1, the rescaled stationarity line carries an extra t in front of ATv; with v = w/t it should read ∇f + Σ ui∇hi + ATv = 0. In 16-1, the boxed LP dual constraint reads ATy + s = 0; it should be ATy + s = c, as in the derivation and the CMU slides. In 16-3, the SDP dual and the barrier SDP dual are written as "minimize"; both are maximizations. In 17-4, the small Boyd–Vandenberghe test LP is described as having 100 equality constraints; in the book it is an inequality-form LP with 100 inequalities and 50 variables. Finally, 15-1-1 says interior-point methods need "20~30" Newton steps without a source; use Boyd and Vandenberghe p. 575 and p. 615 instead (section 7). Boyd & Vandenberghe 2004, p. 571
7. Why a few tens of Newton steps, and who uses interior-point methods
A Newton step is expensive, because it solves a linear system. A gradient step (Day 6) costs about one matrix–vector product. Interior-point methods bet on a few expensive steps; first-order methods such as ADMM (Day 13) bet on many cheap ones.
How few is "a few"? Boyd and Vandenberghe solved 2,000 random standard-form LPs, with m from 10 to 1,000 equality constraints and n = 2m variables, using μ = 100. Cutting the duality gap by a factor of 104 took on average about 21 Newton steps at the small end and 27 at the large end, with a standard deviation near 2. Their summary: the count grows very slowly with size and is almost always around a few tens. Boyd & Vandenberghe 2004, p. 575
The primal-dual method does even better. In the same chapter, it reached a gap of 10−8 in 15 to 35 iterations as the size grew, roughly like log m. On their small inequality-form LP (100 rules, 50 variables), the residual fell to zero, up to rounding, in 24 iterations. Boyd & Vandenberghe 2004, pp. 613–615
Our own quick check agrees: 5 random LPs per size, m rules, m/2 variables, and absolute targets (10−6 for barrier, 10−8 for primal-dual). The size grew 100×; the step count grew less than 2×.
rules m
20
100
500
2000
barrier, μ = 50
34–39
40–49
52–59
56–61
primal-dual, μ = 10
13–18
20–24
27–30
33–40
The worst-case theory is far more pessimistic. With a self-concordant barrier and μ = 1 + 1/√m, the provable bound grows like √m·log(1/ε) Newton steps. For one small LP in the book, that bound is about 8,000 steps, while practice needs a few tens. Nobody runs the theory's tiny μ. Boyd & Vandenberghe 2004, p. 590
Going deeper (optional): the formal barrier method
A self-concordant barrier with parameter ν is a barrier whose curvature changes in a controlled way; the log barrier of m linear rules has ν = m. Measure the distance to the current center by the Newton decrement λt(x) from Day 11. CO4A 15-8 shows: if λt(x) ≤ 1/9 and you raise t by a factor of at most 1 + 1/(8√ν), a single Newton step brings λ back below 1/9. So one Newton step per centering is enough, and about √ν·log(ν/(t(0)ε)) steps reach accuracy ε. The full analysis is in Boyd and Vandenberghe §11.5. CO4A 15-8
What does grow with size is the cost of each step: a dense Newton system in n variables costs about n3 operations. So real solvers exploit sparsity, and MPC solvers (Day 17) exploit the stage-by-stage structure of their Newton systems along the time horizon.
Which solvers use interior-point methods? Here are five common ones, described from their own documentation (as of Oct 2026). Day 21 compares solvers in practice.
IPOPT carries the barrier idea beyond convexity, to the nonlinear problems of Day 16. For contrast, OSQP, a popular QP solver for MPC, is not an interior-point method; it uses ADMM (Day 13, OSQP paper). The algorithm cards summarize both methods of today: barrier card and primal-dual card.
A short history. Dantzig's simplex method (1940s) is fast in practice, but Klee and Minty (1972) built LPs on which it takes about 2n steps. Khachiyan's ellipsoid method (1979) was polynomial but slow. Karmarkar's interior-point method (1984) was polynomial and practical. Modern LP solvers offer both simplex and interior-point methods. CO4A 17-3CMU 10-725 2016
In CVXPY you never write the barrier yourself. You state the problem and pick an interior-point solver:
import cvxpy as cp, numpy as np
A = np.array([[-1, 0], [0, -1], [1, 0], [0, 1], [1, 1]])
b = np.array([0, 0, 3, 3, 4])
x = cp.Variable(2)
rules = [A @ x <= b]
prob = cp.Problem(cp.Minimize(-x[0] - 2 * x[1]), rules)
prob.solve(solver=cp.CLARABEL) # an interior-point solver
print(prob.value, x.value) # about -7 and [1, 3]
print(rules[0].dual_value) # about [0, 0, 0, 1, 1]
print(prob.solver_stats.num_iters) # interior-point iterations
Explain it to a 10-year-old
You want to stand as close as you can to a cookie jar in the corner of a room, but the walls are "lava". At first you play it safe and stand in the middle. Then someone says the lava is cooling, so you take a few careful steps toward the jar. They say it again, and you take a few more steps. You end up right next to the cookies, and you never touched a wall.
Common misunderstandings
"The barrier method moves along the boundary." It stays strictly inside and reaches the boundary only in the limit t → ∞. In the widget, x*(100) = (1.0001, 2.9900) is still 0.01 below the top wall.
"Just set t huge from the start." That is barrier method v.0. The barrier problem becomes badly conditioned, and Newton needs many damped steps. Raise t gradually and warm-start.
"m/t is the error." It is an upper bound. On the pentagon at t = 10, the true error is 0.197, while the bound is 0.5.
"The number of Newton steps is constant." It grows slowly, roughly like log m in the book's tests, and the cost of each step grows with size.
"Primal-dual iterates are feasible." Only u > 0 and h(x) < 0 are kept. Ax = b and dual feasibility are reached only in the limit; the pentagon run starts with a dual residual of 2.24.
Check yourself
Q1. An LP has 5 inequality rules. On the central path at t = 10, the duality gap is…
On the central path the gap is exactly m/t = 5/10 = 0.5. The value 0.05 is the gap at t = 100, and 50 is the gap at t = 0.1. The true error at t = 10 is smaller still, 0.197 on the pentagon.
Q2. Why not start the barrier method with t = m/ε right away?
The answer would be correct, within ε, but finding it is slow: the valley is a narrow canyon against the walls. The barrier φ does not depend on t at all, so it stays defined.
Q3. How do the perturbed KKT conditions differ from the KKT conditions?
Stationarity and Ax = b are unchanged. Only uihi = 0 is relaxed to −1/t, with hi < 0 and ui > 0. Adding the m products gives the gap m/t.
Q4. Phase I returns s* = −4/3. What does this mean?
s* < 0 means hi(x) ≤ −4/3 < 0 for every rule at the phase I solution. Phase I only measures feasibility; it says nothing about the original cost. Infeasibility would show up as s* > 0.
Q5. What is a key difference between the primal-dual method and the barrier method?
Primal-dual applies Newton's method to the perturbed KKT equations in all variables at once, one step per iteration, with no inner loop. It keeps only u > 0 and h(x) < 0. On the pentagon it needs 13 steps; the barrier method needs 27–39.
Q6. In Boyd and Vandenberghe's test, the LPs grew 100× in size. The average number of Newton steps went from about…
The count grew from about 21 to 27 (book p. 575): slowly, but not exactly constant. Each step does get more expensive as the problem grows.
Recap: things to remember
The log barrier φ(x) = −Σ log(−hi(x)) replaces each wall by a smooth penalty that pushes with strength 1/slack. It is defined only at strictly feasible points.
The barrier problem minimizes t·f + φ. Its minimizers x*(t) form the central path, from the analytic center (small t) to the optimum (t → ∞).
On the central path, ui = −1/(t·hi) is dual feasible and the duality gap is exactly m/t: a free stopping rule.
The barrier method re-centers with Newton, stops when m/t ≤ ε, and otherwise sets t ← μt, with μ between about 10 and 100. Phase I finds a strictly feasible start or proves there is none.
The primal-dual method takes one Newton step on the perturbed KKT equations per iteration, may start infeasible, and tracks the surrogate gap η. Both methods finish in a few tens of Newton steps almost regardless of size.
After today you can solve a problem through its dual with dual ascent, add an augmented Lagrangian to make it robust, and run ADMM, the split-and-coordinate method behind solvers such as OSQP, while reading its primal and dual residuals.
About 60 min · Needs Days 9 and 10 · CO4A chapters 20 and 21
Today's big idea
Many big problems are easy pieces tied together by a few shared rules. Put a price on breaking each shared rule, let every piece solve its own small problem at that price, and adjust the price until the pieces agree. ADMM is the robust version of this recipe: it adds a spring that pulls the pieces toward agreement, and it lets them take turns.
1. Solve through the dual: set a price, not a rule
Two delivery robots share a charging station with 4 kWh left. Robot A would like 4 kWh and robot B would like 2, so together they want 6. The station could solve one joint problem for both of them. Instead it posts a price per kWh and lets each robot decide for itself.
On Day 9 a dual variable was the price of breaking a rule. Today the price becomes a control knob. Take the problem: minimize f(x) subject to Ax = b, where x ∈ ℝn and A is a matrix. Attach a price vector u to the rule, one entry per row of A. (This chapter of CO4A calls the equality price u; Day 9 wrote v.) CO4A 20-1
L(x, u) = f(x) + uT(Ax − b) g(u) = minx L(x, u)
The dual function g(u) is the lowest priced cost when x may roam with no rules. Day 9 showed it is a lower bound on the optimum. Today's new fact is about its slope. Let x(u) be the x that minimizes L(x, u). Then the gradient of g at u is the constraint residual Ax(u) − b, how far the rule is from holding. The one-line reason: L is linear in u, with slope Ax − b.
So you improve a price by stepping along the residual. This is dual (sub)gradient ascent: CO4A 20-1
Here k counts iterations and t > 0 is the step size. Too much demand (Ax > b) raises the price, and too little lowers it. If f is strictly convex, x(u) is unique, g is differentiable, and this is plain gradient ascent on g. Otherwise Ax − b is only a subgradient, as on Day 7.
Worked example. The robots' total cost is f(x) = ½(x1 − 4)2 + ½(x2 − 2)2, and the rule is x1 + x2 = 4. At price u, robot A minimizes ½(x1 − 4)2 + u·x1, so it picks x1 = 4 − u. Robot B picks x2 = 2 − u. Start at u = 0 with t = 0.25:
Step k
Robots pick (x1, x2)
Residual x1 + x2 − 4
New price u
1
(4, 2)
+2
0.5
2
(3.5, 1.5)
+1
0.75
3
(3.25, 1.25)
+0.5
0.875
4
(3.125, 1.125)
+0.25
0.9375
The price climbs toward u* = 1, where the robots pick x* = (3, 1) and use exactly 4 kWh. The gap to u* halves at every step. Both robots cut back by the same price, but robot A, which wanted more, still gets more.
The step needs care. With t = 1 the price jumps 0, 2, 0, 2, … and never settles. Here any 0 < t < 1 converges. In general, suppose f is strongly convex with parameter d, meaning it curves upward at least like (d/2)‖x‖22. Then the dual is smooth, and dual ascent converges like gradient descent. The box below has the details. CO4A 20-1-1
Going deeper (optional): why the dual's slope is the residual
Fix a price u and let x(u) minimize L(x, u). For any other price v, g(v) ≤ L(x(u), v) = g(u) + (v − u)T(Ax(u) − b). So Ax(u) − b is a supergradient of the concave function g at u: a subgradient (Day 7), turned upside down for maximizing. CMU 10-725 2016
Now the speed. If f is d-strongly convex, then ∇f* is (1/d)-Lipschitz, where f*(y) = maxx yTx − f(x) is the conjugate. So ∇g is (‖A‖22/d)-Lipschitz. With a fixed step of at most d/‖A‖22, dual gradient ascent needs O(1/ε) iterations to get within ε, or O(log(1/ε)) if ∇f is also Lipschitz. CO4A writes the step as t = d, which is safe only when ‖A‖2 ≤ 1. In the robot example d = 1 and ‖A‖22 = 2, so the safe step is 0.5, and t = 1 is exactly where the price starts to bounce. CO4A 20-1-1
2. Dual decomposition: broadcast a price, gather the usage
Notice what the station did not do. It never looked at the robots' cost functions. It posted one number, each robot solved its own tiny problem, and the station added up the answers. That pattern scales to thousands of pieces.
It works whenever the cost is a sum of separate pieces, f(x) = f1(x1) + … + fB(xB), and the shared rule is linear, A1x1 + … + ABxB = b. For a fixed price the Lagrangian splits into B separate terms. So the x-step splits into B independent problems. This is dual decomposition: CO4A 20-2-1
CO4A calls the two halves broadcast and gather. Broadcast sends the current price to every worker, which can be a separate machine or robot. Gather collects their usage Aixi, and one sum updates the price. Only prices and totals travel, and no worker sees another's cost.
One round of dual decomposition. The station only ever sees the price and the two choices, never the robots' costs. With t = 0.25 the price goes 0.5, 0.75, 0.875, … toward u* = 1, where the robots take (3, 1).
Shared resources are usually limits, not exact amounts: Σi Aixi ≤ b. Then the price must stay non-negative, and the update clips it at zero: CO4A 20-2-2
u(k) = (u(k−1) + t(Σi Aixi(k) − b))+
Here (v)+ = max(v, 0), entry by entry. Now the price story is complete: raise the price of an over-used resource, lower it when there is spare capacity, and never go below zero. Example: give the station 8 kWh instead of 4. At u = 0 the robots ask for 6. The update gives (0 + 0.25(6 − 8))+ = 0, so the price stays at zero. A resource with room to spare is free, which is complementary slackness from Day 10.
3. The augmented Lagrangian: add a spring toward the rule
Dual ascent is fragile in two ways. You saw the first: the step size must suit the problem, or the price bounces. The second is worse. If f is not strictly convex, the x-step can fail outright. Take f(x) = x with the rule x = 1. For any price u ≠ −1, L(x, u) = x + u(x − 1) is a sloped straight line in x, with no minimum.
The fix is to add a spring. The augmented Lagrangian adds a quadratic penalty on the residual: CO4A 20-3
Lρ(x, u) = f(x) + uT(Ax − b) + (ρ/2)‖Ax − b‖22
The penalty parameter ρ > 0 sets how stiff the spring is. The new term is zero at every feasible point, so the solution does not change. But now the x-step always has a minimum. In the example, x + u(x − 1) + (ρ/2)(x − 1)2 is a parabola for every u.
The method of multipliers is dual ascent on Lρ, with the step size set to ρ: CO4A 20-3
Why a step of exactly ρ? The x-step's optimality condition reads 0 ∈ ∂f(x(k)) + AT(u(k−1) + ρ(Ax(k) − b)). The bracket is exactly the new price u(k). So each new pair (x(k), u(k)) meets the stationarity condition from Day 10, and only feasibility is left to fix.
Worked example: the robots again, with ρ = 1. The x-step now gives a total use of (14 − 2u)/3. From u = 0 the total is 4.667, the residual 0.667, and the new price 0.667. Then the price goes 0.889, 0.963, 0.988. The gap to u* = 1 shrinks by a factor 1/(1 + 2ρ) = 1/3 per step, and by 1/21 for ρ = 10. Any ρ > 0 converges here, and nothing bounces. In the f(x) = x example with ρ = 1, the first step gives x = 0 and u = −1, and the second lands on x = 1.
The robot example, all starting from u = 0. Dual ascent needs a step below 1: t = 0.25 creeps up, halving the gap each step, and t = 1 bounces between 0 and 2 forever. The method of multipliers works for any ρ: the gap shrinks by 1/3 per step at ρ = 1 and by 1/21 at ρ = 10.
The spring has a cost of its own. Expand (ρ/2)(x1 + x2 − 4)2 and you find a cross term ρx1x2. Robot A's best choice now depends on robot B's, so the x-step no longer splits. The method of multipliers converges far more reliably, but it gives up dual decomposition. CO4A 20-3CMU 10-725 2016 The dual ascent and method of multipliers card sums up both.
4. ADMM: take turns instead of deciding together
Can we keep the spring and still split the work? Yes, if the pieces take turns. That is the idea behind the alternating direction method of multipliers (ADMM). It works on problems with two blocks of variables, each with its own cost, tied by a linear rule: CO4A 20-4-1
minimize f(x) + g(z) subject to Ax + Bz = c
(Here g names the second cost, not the dual function.) The lasso from Day 8 fits this shape once you make a copy. It minimizes ½‖y − Xβ‖22 + λ‖β‖1 for data X, y and a weight λ > 0. Call the copy α, set f(β) = ½‖y − Xβ‖22 and g(α) = λ‖α‖1, and require β − α = 0. Each piece alone is easy: f is least squares, and g is handled by soft-thresholding. CO4A 21-3
The augmented Lagrangian of the two-block problem is
The method of multipliers would minimize it over x and z together. ADMM minimizes over x, then over z using the new x, then updates the price: CO4A 20-4-1
One pass of x and then z replaces the joint minimization. The x-step sees only f and the spring, and the z-step only g and the spring. So the work splits again, while the spring keeps the robustness.
The formulas get shorter with the scaled dual w = u/ρ. Completing the square folds the price term into the spring: CO4A 20-4-3
x ← argminx f(x) + (ρ/2)‖Ax + Bz − c + w‖22 z ← argminz g(z) + (ρ/2)‖Ax + Bz − c + w‖22 w ← w + (Ax + Bz − c)
Now w is simply the running sum of all residuals so far. It works like the integral term of a PI controller: a disagreement that lasts keeps pushing harder until it is gone.
When the rule is x = z (A = I, B = −I, c = 0), each step is a proximal operator. Recall from Day 8 that proxf,λ(v) = argminx f(x) + ‖x − v‖22/(2λ): "move toward v, but keep f small". CO4A 21-2
x ← proxf,1/ρ(z − w) z ← proxg,1/ρ(x + w) w ← w + x − z
For the lasso this reads: ridge regression, then soft-threshold, then add the disagreement. Soft-thresholding St shrinks each entry toward 0 by t, and sets it to 0 if its size is at most t. CO4A 21-3
One ADMM iteration for the lasso. Step 2 uses the β just computed in step 1, and that ordering is what makes it ADMM. The method of multipliers would do steps 1 and 2 as one joint minimization, which couples them.
Worked example with a single number. Minimize ½(β − 3)2 + |β|, whose answer is β* = S1(3) = 2. Take ρ = 1 and start at β = α = w = 0, so the β-step is β = (3 + α − w)/2. Step 1: β = 1.5, α = S1(1.5) = 0.5, and w = 1. Step 2: β = 1.25 and α = S1(2.25) = 1.25, so w stays at 1. After that β = α = 1.625, 1.8125, 1.906, …, and step 8 reaches 1.988. The gap to 2 halves each step. The price u = ρw = 1 is the slope of |β| at the answer, just as KKT predicts.
The same three lines in Python, with the stopping rule from the next section:
import numpy as np
from scipy.linalg import cho_factor, cho_solve
def admm_lasso(X, y, lam, rho=1.0, tol=1e-4, max_iter=2000):
p = X.shape[1]
F = cho_factor(X.T @ X + rho * np.eye(p)) # factor once
Xty, alpha, w = X.T @ y, np.zeros(p), np.zeros(p)
for k in range(1, max_iter + 1):
beta = cho_solve(F, Xty + rho * (alpha - w)) # ridge step
old, v = alpha, beta + w
alpha = np.sign(v) * np.maximum(np.abs(v) - lam / rho, 0) # soft-threshold
w = w + beta - alpha # add the disagreement
r = np.linalg.norm(beta - alpha) # primal residual
s = rho * np.linalg.norm(alpha - old) # dual residual
if r <= tol and s <= tol:
return alpha, k
return alpha, max_iter
Method
Price update
Splits the work?
Needs
Dual ascent
u + t(Ax − b)
Yes, if f is a sum of pieces
strictly convex f and a well-chosen step t
Method of multipliers
u + ρ(Ax − b)
No: the spring couples the pieces
convex f; any ρ > 0
ADMM
u + ρ(Ax + Bz − c)
Yes: separate x- and z-steps
convex f and g; any ρ > 0, but ρ sets the speed
Analogy
Two specialists edit one report. One polishes the wording (f), and the other enforces the style guide (g). They take turns on a shared draft, each changing only their own part. A referee keeps a running tally of where their versions still differ (w) and tells the next editor to lean that way. ρ is how loudly the referee speaks.
5. When to stop: two residuals, two questions
ADMM's stopping rule asks two questions. Do the two copies agree yet? And have they stopped moving, so that the prices have settled? Each question has its own number: Boyd et al. 2011
The primal residual r measures how badly the rule is broken; for the lasso it is β − α. The dual residual s measures how much z moved in this step, times ρ; for the lasso its size is ρ‖α(k) − α(k−1)‖2. After the z-step, z's own optimality condition holds exactly, and x's is off by s. So when both are small, every KKT condition nearly holds, and f + g is near the optimal value p*. Boyd et al. 2011
Look back at the scalar example. At step 2, β = α = 1.25, so r = 0. Yet the answer is 2, not 1.25. The dual residual gives it away: s = 1 × |1.25 − 0.5| = 0.75. Stop on r alone and you would quit far too early.
Boyd et al. stop when ‖r‖2 ≤ εpri and ‖s‖2 ≤ εdual. Each tolerance mixes an absolute and a relative part:
Here p is the length of r and n the length of x, and εrel = 10−3 or 10−4 is typical. The widget below uses a simpler rule: both norms at most 10−4. Boyd et al. 2011
Does ADMM always get there? The guarantee is broad. Suppose f and g are closed, proper and convex, and the plain Lagrangian has a saddle point. Then for every ρ > 0 the residual goes to 0, f + g goes to p*, and the price goes to an optimal u*. A and B need not have full rank. CO4A 20-4-2
Speed is another matter. Boyd et al. report that ADMM often reaches "modest accuracy" "within a few tens of iterations", but can be very slow to reach high accuracy. Boyd et al. 2011 In the widget's lasso at ρ = 0.1, the tolerances 10−3, 10−4 and 10−6 take 81, 130 and 229 iterations. Each extra digit costs about 50 more iterations, the pattern of a first-order method like gradient descent on Day 6. If you need many digits, an interior-point method (Day 12) is usually the better fit.
Going deeper (optional): why ADMM converges
Boyd et al. prove convergence with a Lyapunov function, a quantity that falls at every step: V = (1/ρ)‖u − u*‖22 + ρ‖B(z − z*)‖22 (their Appendix A). They also bound the objective error by the residuals, f + g − p* ≤ −uTr + (x − x*)Ts, which is why small residuals mean a small error. ADMM is a special case of Douglas–Rachford splitting, itself a proximal point method (§3.5). Faster, linear rates need extra assumptions such as strong convexity; CO4A 20-5 lists the papers. A common speed-up is over-relaxation, which pushes each step further by a factor between 1.5 and 1.8 (§3.4.3). Boyd et al. 2011CO4A 20-5
6. Choosing ρ, and letting it adapt
Think of ρ as how loudly the referee shouts "agree!". Shout too softly, and each copy chases its own cost while agreement comes slowly, so r stays large. Shout too loudly, and the copies agree at once but barely move toward the optimum, so s stays large. CO4A puts it this way: a large ρ puts too little weight on minimizing f + g, and a small ρ too little on feasibility. CO4A 21-3CMU 10-725 2016
The widget's lasso shows both patterns. At ρ = 0.1 the first three steps give ‖r‖ = 2.568, 1.597, 0.581 and ‖s‖ = 0.000, 0.110, 0.129, so r is on top. At ρ = 10 they give ‖r‖ = 0.065, 0.002, 0.003 and ‖s‖ = 2.946, 2.637, 2.304. Now s is on top, and it is still 0.92 at step 10.
Since the two residuals pull ρ in opposite directions, a simple rule can balance them. Residual balancing raises ρ when r is much larger than s, and lowers it in the opposite case: Boyd et al. 2011
if ‖r‖ > μ‖s‖: ρ ← τρ and w ← w/τ if ‖s‖ > μ‖r‖: ρ ← ρ/τ and w ← τw
Typical values are μ = 10 and τ = 2. Rescaling w keeps the real price u = ρw unchanged. If the x-step reuses a factorization, it must be refactored whenever ρ changes. One caution: the convergence proof assumes a fixed ρ, so it covers adaptive ρ only if ρ eventually stops changing. Boyd et al. 2011
Try it: the widget runs scaled ADMM on a seeded lasso with 30 data points and 10 features (λ = 0.2516). The answer is β* ≈ (1.825, −1.336, 0, 0, 0.925, 0, …, 0), which recovers the three true features 1, 2 and 5. Slide ρ, or tap a preset, and watch which residual stays on top. Then switch on adaptive ρ and try the ends of the slider, 0.01 and 100.
Notice that at the default ρ = 1 both residuals fall below 10−4 after 16 iterations. The lower chart is a U: 130 iterations at ρ = 0.1 and 123 at ρ = 10, about 8× more, and over 1,000 at the two ends of the slider. With adaptive ρ the purple line is nearly flat: 18, 17 and 19 iterations from starts of 0.1, 1 and 10, and 16 to 25 from any start.
7. ADMM at work: lasso, consensus, projections, and OSQP
The lasso at scale. The β-step solves with the same matrix XTX + ρI every time, and that matrix is always invertible. So you factor it once, with a Cholesky factorization costing O(p3) for p features. After that each iteration costs only O(p2). CO4A 21-3 Boyd et al. report a lasso with 1,500 examples and 5,000 features, also with one factorization up front. With ρ = 1 it met the stopping rule in 15 iterations, and the whole solve took about 1.5 s, of which about 1 s was the first factorization. Boyd et al. 2011 The group lasso, which zeroes whole groups of features at once, swaps in group soft-thresholding, Rt(v) = (1 − t/‖v‖2)+v. CO4A 21-3
Consensus: many machines, one answer. Suppose the cost is a sum f1(x) + … + fN(x), and each fi lives on a different machine, for example because each holds part of the data. Give machine i its own copy xi, and require every copy to equal one shared value x̄. This is consensus ADMM: CO4A 21-5
xi ← argmin fi(xi) + (ρ/2)‖xi − x̄ + wi‖22 x̄ ← average of the xi wi ← wi + xi − x̄
The xi-steps run in parallel, as in dual decomposition, but each has a spring, as in the method of multipliers. (Strictly, the z-step averages xi + wi. The wi start at zero and always sum to zero, so this is a plain average.)
Worked example: three machines hold the numbers a = 1, 2 and 6, with fi(x) = (x − ai)2 and ρ = 1. The shared value goes 2.0, 2.667, 2.889, 2.963, 2.988, 2.996, toward the mean 3, which is the true minimizer. The primal residual shrinks by about 2/3 per step: 2.49, 1.66, 1.11, 0.74, 0.49, 0.33. The prices wi approach (−4, −2, 6). Each one records how hard, and in which direction, that machine's data pulls away from the shared answer.
Alternating projections. To find a point in the overlap of two convex sets C and D, minimize IC(x) + ID(z) subject to x = z. The indicator function IC is 0 on C and +∞ off it, so its prox step is the projection PC, the closest point of C: CO4A 20-4-4CMU 10-725 2016
x ← PC(z − w), z ← PD(x + w) w ← w + x − z
Without w this would be the classical back-and-forth between the two sets. Boyd et al. note that the ADMM version is like Dykstra's alternating projections, which is far more efficient than the classical method. Boyd et al. 2011
More splits. Robust PCA writes a video as a low-rank background L plus a sparse foreground S. ADMM alternates singular-value soft-thresholding for L with entrywise soft-thresholding for S. CO4A 21-4 And how you split matters. For a 2-D fused lasso on an image, splitting into row and column problems that are each solved exactly converges much faster than the generic split, at a similar cost per cycle. CO4A 21-6
OSQP and model predictive control. OSQP is a free solver for quadratic programs: minimize ½xTPx + qTx subject to l ≤ Ax ≤ u, with P ⪰ 0. (Here l and u are bounds, not prices.) It runs ADMM on a split chosen so that the x-step's linear system has the same matrix at almost every iteration. OSQP factors that matrix once. After that, each iteration is cheap vector work plus clipping into the box [l, u]. It is the lasso's factor-once trick, applied to any convex QP. Stellato 2020
That suits model predictive control (Day 17). There a controller solves a QP of the same shape at every control step, and only the measured state changes. OSQP can warm-start from the last solution and reuse its factorization. In the paper's MPC benchmark with a 10-step horizon, this cut the solve time from 7 ms to 2 ms with 20 states, and from 67 ms to 22 ms with 80 states. The iteration counts barely changed, so the saving came from reusing the factorization. Stellato 2020 The OSQP paper page and the ADMM card have more.
The trade-offs are ADMM's own. On the paper's 1,400 test QPs at low accuracy (10−3), OSQP was the fastest solver overall and failed on none. It is still a first-order method, though. On hard, badly scaled problems GUROBI was faster, and the authors call the choice of ρ "still an open research question". The paper's defaults adapt ρ during the solve and over-relax with a factor of 1.6. The current default starting ρ is 0.1 (as of Oct 2026). Stellato 2020OSQP docs
Going deeper (optional): fixes if you read CO4A alongside
20-04-04 (alternating projection): the objective should read IC(x) + ID(z), and the dual update w ← w + x − z, as in the CMU slides and Boyd et al.
20-04-02: the residual is Ax + Bz − c, and the objective is f(x(k)) + g(z(k)).
21-03 (lasso): the costs are O(p3) for the factorization and O(p2) per iteration, where p is the number of features.
21-03 (group lasso): group soft-thresholding is Rt(x) = (1 − t/‖x‖2)+x; the t is missing.
Explain it to a 10-year-old
Two friends draw one picture. Mia is good at shapes and Leo is good at colours. They take turns: Mia fixes the shapes, then Leo colours Mia's new drawing. After each turn they write down where their two versions still don't match. A mismatch that stays on the list gets an extra star, and the next person works harder to fix it. Soon the two versions match, and the picture is good at both shapes and colours.
Common misunderstandings
"ADMM's x- and z-steps can run at the same time." The z-step must use the new x. Updating both from the old values is a different, Jacobi-style method without ADMM's guarantee. (In consensus ADMM the many xi-steps do run in parallel with each other; the averaging waits for all of them.)
"A tiny primal residual means you are done." In the scalar example r = 0 at step 2, with β = α = 1.25, but the answer is 2. The dual residual, 0.75, showed that α was still moving. Check both.
"A bigger ρ is stricter, so it is better." In the widget, ρ = 10 takes 123 iterations and ρ = 1 takes 16. Too large a ρ makes the copies agree early and then crawl.
"ADMM is fast, so it is fast to high accuracy." It is quick to modest accuracy and slow after that: 81, 130 and 229 iterations for 10−3, 10−4 and 10−6 at ρ = 0.1.
"u and w are the same price." u = ρw. If you change ρ in the scaled form, rescale w, or you silently change the price.
Check yourself
Q1. In dual ascent, what is the gradient of the dual function g at the price u?
g(u) = L(x(u), u), and L is linear in u with slope Ax − b. So the price rises exactly where demand exceeds supply. ∇f(x(u)) is tempting, but at the minimizer it equals −ATu, which tells you about x, not about how to change the price.
Q2. Why can dual decomposition run on many machines at once?
With f = Σfi(xi) and Ax = ΣAixi, L splits into Σ[fi(xi) + uTAixi] − uTb. The penalty option is backwards: (ρ/2)‖Ax − b‖2 is what couples the blocks in the method of multipliers. The constraint does not disappear either; the price update still enforces it.
Q3. In the method of multipliers, why is the price step exactly ρ?
The x-step's optimality reads 0 ∈ ∂f(x) + AT(u + ρ(Ax − b)), and the bracket is the new u. Only feasibility is left to fix. It does not make x feasible at once: in the robot example the total use after step 1 was 4.667, not 4.
Q4. What does ADMM give up, compared with the method of multipliers, to get splitting back?
ADMM keeps Lρ and its dual step ρ. It only replaces "minimize over x and z together" with one pass of x and then z. Dropping the penalty instead would give back plain dual decomposition, with its fragile step size.
Q5. In a run, ‖r‖ is already 0.002 but ‖s‖ is still 2.6 and falling slowly. What is the most likely cause?
A large ρ forces the copies to agree at once, so r is tiny, while z and the prices keep crawling. These are the widget's ρ = 10 numbers: ‖r‖ = 0.002 and ‖s‖ = 2.637 at step 2, and 123 iterations in all. A small ρ gives the opposite pattern, with r on top.
Q6. Which description of ADMM's convergence matches practice and the Boyd et al. monograph?
ADMM behaves like a first-order method: each extra digit costs about as much as the last. At ρ = 0.1 the widget needs 81, 130 and 229 iterations for 10−3, 10−4 and 10−6. It converges for every ρ > 0; ρ only changes the speed.
Recap: things to remember
Dual ascent: for a fixed price, minimize the Lagrangian, then move the price along the residual Ax − b. It needs a strictly convex f and a careful step.
If f is a sum of pieces, the x-step splits into independent problems: broadcast the price, gather the usage. That is dual decomposition.
The augmented Lagrangian adds (ρ/2)‖Ax − b‖2. The method of multipliers uses step ρ and converges for any ρ, but loses the splitting.
ADMM: an x-step, a z-step that uses the new x, then w ← w + residual. Stop when both the primal residual r and the dual residual s are small.
ρ trades r against s, and residual balancing adapts it. ADMM reaches modest accuracy fast and high accuracy slowly. OSQP uses it to solve the QPs of MPC.
After today you can minimize over a constraint set without projecting by using Frank–Wolfe's linear-minimization step, and decide when updating one coordinate at a time (coordinate descent) is the fastest way to solve problems like the lasso.
About 60 min · Needs Days 6 and 8 · CO4A chapters 22 and 23
Today's big idea
Two cheap tricks replace an expensive step. Frank–Wolfe never projects: it asks which corner of the allowed set is best for a straight-line guess of the cost, and leans toward it. Coordinate descent never takes a full gradient step: it fixes every variable but one and solves that one exactly. Each trick is fast when the problem has the right shape, and today is about recognising that shape.
1. When the fence is the hard part
Recall projected gradient from Day 8. You take a step downhill, and if you land outside the allowed set C, you snap back to the nearest allowed point. Picture a dog on a walk that runs past the park fence and is pulled back to the closest spot inside.
For a box or a ball the snap is one line of code: clip each entry, or rescale the vector. For many other sets the snap is an optimization problem of its own. The projection of a point y onto C is
PC(y) = argminx ∈ C ‖x − y‖22
That is a quadratic problem over C. Frank–Wolfe asks an easier question instead: which point of C is best for a linear cost gTs? A linear cost over a polytope is always smallest at a corner, as you saw for linear programs on Day 5. So the answer is "the corner furthest in the direction −g". CO4A 22-02
Left: the gradient step lands outside C, and a projection pulls it back. Right: Frank–Wolfe looks along −∇f(x), picks the corner s that a straight line (dotted) touches last, and moves part of the way there. The new point x⁺ is a blend of x and s, so it is inside C automatically.
Here is a case where the gap in cost is large. Recommender systems fill in a ratings matrix by asking it to be low-rank. A common convex way to ask is a ball in the nuclear norm, the sum of a matrix's singular values. Projecting onto that ball needs a full singular value decomposition (SVD). The linear question needs only the top singular vector pair, which a few rounds of the power method find. CO4A 22-02Jaggi 2013
A projection-free method is one that never projects onto C. The oldest one is due to Marguerite Frank and Philip Wolfe (1956). It is also called the conditional gradient method. CO4A 22
Analogy
You are inside a fenced park and want to get as close as possible to an ice-cream van parked outside. You may not climb the fence. From where you stand, you can see which corner post is nearest the van. Walk part of the way toward that post, look again, and repeat. You never leave the park, and you never need to work out the closest point of the fence exactly.
2. The Frank–Wolfe step: lean toward the best corner
Stand at the current point x. Near x, the cost f looks like its tangent plane. Ask: "if f really were this plane, where in C would I go?" The answer is a corner s. The plane is only a guess, so you move only part of the way toward s.
sk ∈ argmins ∈ C ∇f(xk)Ts xk+1 = (1 − γk) xk + γk sk γk = 2/(k + 2), k = 0, 1, 2, …
The first line is the linear minimization oracle (LMO): a routine that returns the best point of C for the linear cost ∇f(xk)Ts. The second line blends the old point with that corner. The weight γk runs 1, 2/3, 1/2, 2/5, …, so later steps are more cautious. This default, the 2/(k+2) step, needs no tuning.
Why does x stay feasible? Because xk+1 lies on the segment between two points of C, and a convex set contains every such segment (Day 2). No projection is ever needed. A note if you read CO4A: it writes the step as 2/(k + 1) with k starting at 1. That is the same sequence 1, 2/3, 1/2, … with the count shifted by one. CMU 10-725 2016
Worked example. Let C be the triangle with corners (0, 0), (1, 0) and (0, 1), and let f(x) = ‖x − p‖22 with p = (0.9, 0.5). The point p lies outside C, so the best point is the closest point of C to p: x* = (0.7, 0.3), with f* = 0.22 + 0.22 = 0.08.
Start at x0 = (0, 0). The gradient is ∇f = 2(x − p) = (−1.8, −1.0). The oracle scores each corner: (0, 0) gives 0, (1, 0) gives −1.8 and (0, 1) gives −1.0. The lowest is (1, 0). With γ0 = 1 you jump all the way, so x1 = (1, 0).
At x1 the gradient is (0.2, −1.0), so now the corner (0, 1) wins with −1.0. With γ1 = 2/3, x2 = ⅓(1, 0) + ⅔(0, 1) = (0.333, 0.667). The next points are (0.667, 0.333), (0.8, 0.2), (0.533, 0.467) and (0.667, 0.333). The iterates zig-zag between the two corners of the edge that holds x*, closing in on (0.7, 0.3).
import numpy as np
V = np.array([[0, 0], [1, 0], [0, 1]]) # corners of C
p = np.array([0.9, 0.5]) # f(x) = ||x - p||^2
x = np.zeros(2)
for k in range(10):
g = 2 * (x - p) # gradient
s = V[np.argmin(V @ g)] # LMO: the best corner
x = x + 2 / (k + 2) * (s - x) # lean toward it
g = 2 * (x - p); s = V[np.argmin(V @ g)]
print(x, g @ (x - s)) # [0.727 0.273] and its gap 0.079
That is the whole method: no step size to tune and no projection to code. The price, as you will see, is speed.
3. Cheap oracles, sparse answers
For a linear cost, the best point of a polytope is a corner, so the oracle only compares corners. For the common sets you do not even need a list of corners. One pass over the gradient tells you which corner wins.
The same gradient ∇f = (1, −2) on three sets. The ℓ1 ball answers with a single nonzero entry. The box answers with every entry at ±1.
Here are the oracles you will meet most. In each row, g = ∇f(x) and t is the radius of the set. CO4A 22-02Jaggi 2013
Set C
Its corners (atoms)
Oracle answer s
Cost
Probability simplex: s ≥ 0, Σsi = 1
e1, …, en
ei with i = argminj gj
O(n)
ℓ1 ball: ‖s‖1 ≤ t
±t·ei
i = argmaxj |gj|, s = −t·sign(gi)·ei
O(n)
ℓ∞ ball (box): ‖s‖∞ ≤ t
every sign pattern ±t
si = −t·sign(gi) for each i
O(n)
ℓp ball, 1/p + 1/q = 1
(a curved boundary)
si ∝ −sign(gi)·|gi|q−1, scaled so ‖s‖p = t
O(n)
Nuclear-norm ball: ‖S‖* ≤ t
rank-one matrices
S = −t·u1v1T, the top singular pair of g
a few power steps
Worked example. Take g = (0.3, −2, 1) and t = 1. On the ℓ1 ball the largest |gj| is 2, at j = 2, so s = −sign(−2)·e2 = (0, 1, 0), with gTs = −2. On the box, s = −sign(g) = (−1, 1, −1), with gTs = −3.3. On the simplex the smallest entry is −2, so s = e2 = (0, 1, 0) again. The widget's triangle works the same way, with (0, 0) as one more corner.
A sanity check for the ℓp row: with p = q = 2 it gives s = −t·g/‖g‖2. On the round ball, the best point for a linear cost is straight downhill, at the edge. For g = (0.3, −2, 1), ‖g‖2 = 2.256 and s = (−0.133, 0.887, −0.443).
Reading CO4A alongside? Three fixes
ℓ1 oracle. CO4A 22-02 picks argmaxi ∇if without the absolute value. You need argmaxi |∇if|: a steep negative slope is as useful as a steep positive one, and the sign is applied afterwards.
ℓp oracle. CO4A 22-02 and the CMU slides write the exponent as p/q with ‖s‖q = t. Use Jaggi's version in the table: exponent q − 1, scaled so ‖s‖p = t. Jaggi 2013
Gap inequality. The proof in CO4A 22-03 writes g(x) ≤ f(x) − f*. It must be ≥, as section 4 explains and as 22-02 states correctly. The same proof's "(k − 1/k + 1)" should read (k − 1)/(k + 1).
Now a bonus. Each step mixes in exactly one corner, so after k steps from a corner, x is a blend of at most k + 1 corners. The corners are called atoms: the building blocks whose convex hull is C. A point made of only a few atoms is a sparse iterate. On the ℓ1 ball, starting from x0 = 0, that means at most k nonzero entries after k steps. On the nuclear-norm ball it means rank at most k.
A lasso example from Day 13's 30 × 10 data, written as a constraint ‖β‖1 ≤ 4.0856 (the ℓ1 norm of the lasso answer). Frank–Wolfe touches only coordinates 1, 2 and 5. It has 1 nonzero for k = 1 to 3, 2 at k = 5, and 3 from k = 10 on. The error f − f* is 2.2 × 10−1 at k = 10, 1.2 × 10−3 at k = 100 and 3.4 × 10−5 at k = 1000. The iterates are sparse and each step is cheap, but high accuracy is slow to arrive.
A robotics reading of the same idea: suppose a planner blends a library of precomputed motion primitives, with weights on the simplex. The oracle picks the single primitive that best fits the current gradient. Started from one primitive, after 5 steps the plan mixes at most 6, which is easy to inspect and to execute.
This trade between sparsity and accuracy is the best possible. Jaggi shows that for f = ‖x‖22 on the simplex, any point with at most k nonzeros has error at least 1/k − 1/n. So about 1/ε atoms are unavoidable for accuracy ε. Jaggi 2013
4. A free certificate, and the O(1/k) rate
A convex function lies above every tangent plane (Day 3). So the tangent plane at x, pushed to its lowest point over C, is a floor under f*. And the oracle has already found that lowest point: it is s.
f(z) = 0.6(z − 2.4)2 + 0.6 on C = [0.4, 3], at x = 1. The tangent line slopes down, so its lowest point on C is the right end, s = 3. The drop from f(x) = 1.776 to the tangent's value there is the gap, 3.36. The true distance to the best value, 1.18, is always smaller.
Write that floor down. Convexity gives f* ≥ f(x) + ∇f(x)T(s − x). Rearranged, it says the Frank–Wolfe duality gap is an upper bound on how far you are from optimal: CO4A 22-02CMU 10-725 2016
g(x) = ∇f(x)T(x − s) ≥ f(x) − f*
You get g(x) for free, because the oracle already computed s. So you can stop the moment g(x) ≤ ε, without knowing f*. The name "duality gap" comes from a Fenchel dual of the problem; you do not need that view to use it.
Check it on the triangle. At x0 = (0, 0) with s = (1, 0), g = (−1.8, −1.0)T(−1, 0) = 1.8. The true error is f(x0) − f* = 1.06 − 0.08 = 0.98, which is indeed below 1.8. At k = 10 the error is 1.5 × 10−3 and the gap is 7.9 × 10−2. At k = 100 they are 1.3 × 10−4 and 1.0 × 10−2. The gap does not fall every step, but it never drops below the error.
How fast does the error fall? With γk = 2/(k + 2), for k ≥ 1: CO4A 22-03Jaggi 2013
f(xk) − f* ≤ 2Cf / (k + 2) Cf ≤ L · diam(C)2
Here Cf is the curvature constant, which CO4A calls M. It measures how far f bends away from its tangent planes over C. L is the Lipschitz constant of ∇f from Day 6, and the diameter diam(C) is the largest distance between two points of C. The one-line reason: each step lowers f by at least γ times the gap, minus a bending penalty of (γ2/2)Cf. Since the gap is at least the error, the error shrinks like 1/k.
On the triangle, f = ‖x − p‖2 has L = 2, and the longest distance in C is from (1, 0) to (0, 1), so diam2 = 2. Hence Cf ≤ 4 and the bound reads 8/(k + 2): 0.67 at k = 10, 0.078 at k = 100 and 0.008 at k = 1000. The actual errors, 1.5 × 10−3, 1.3 × 10−4 and 1.8 × 10−8, are far smaller. The bound is a worst case.
O(1/k) is the same rate as gradient descent on a smooth problem, and slower than FISTA's O(1/k2) from Day 8. In the worst case, each extra correct digit costs ten times as many steps. Frank–Wolfe has one more nice property, affine invariance: stretching or skewing the coordinates does not change its iterates, and Cf does not change either. CMU 10-725 2016
Going deeper (optional): the O(1/k) proof in three lines
The definition of Cf gives f(xk+1) ≤ f(xk) − γkg(xk) + (γk2/2)Cf. Write hk = f(xk) − f* and use g ≥ h: hk+1 ≤ (1 − γk)hk + (γk2/2)Cf. With γk = 2/(k + 2) and the guess hk ≤ 2Cf/(k + 2), the right side is 2Cf(k + 1)/(k + 2)2 ≤ 2Cf/(k + 3), because (k + 1)(k + 3) ≤ (k + 2)2. That is the induction step. Jaggi also shows that the smallest gap seen in the first k steps falls like O(1/k) too. Jaggi 2013CO4A 22-03
Try it: in mode A, slide k and watch the path bounce between the corners (1, 0) and (0, 1). The orange ring marks the corner the oracle picks next. In the chart, compare the gap (orange) with the true error (pink). Switch p to the inside preset, then try exact line search on both presets. Tap the plot to move p anywhere.
Notice that after k = 10 steps with γ = 2/(k+2), the error f − f* is 1.5e−3 while the gap g(x) is 7.9e−2. The gap sits above the error, as promised, and you computed it without knowing x*. The worst-case bound 8/(k+2) = 0.667 is far looser than both.
The zig-zag is the method's weak spot. When x* lies on an edge, the oracle keeps pointing at the edge's two corners, and the path bounces between them. With exact line search (γ chosen to minimize f along the segment to s) on the edge preset, f − f* is 3.1 × 10−3 at k = 100 and 3.4 × 10−4 at k = 1000: exactly 1/k behaviour. Here the plain 2/(k+2) step does better (1.3 × 10−4 at k = 100). That is a property of this example, not a rule.
When x* is inside the triangle, line search is fast: f − f* = 2.9 × 10−6 at k = 10, and it hits the limit of floating-point arithmetic before k = 100. Two standard fixes target the zig-zag. Fully corrective Frank–Wolfe re-optimizes over all atoms found so far. An away step moves weight away from the worst atom currently in use. With away steps, Lacoste-Julien and Jaggi (2013) prove linear convergence for strongly convex f over a polytope. CO4A 22-04
5. Coordinate descent: one knob at a time
Think of an old shower with separate hot and cold taps. You turn the hot tap until the water is as good as it gets, then the cold tap, then the hot one again. Each turn is easy because you only move one knob. That is coordinate descent.
Coordinate descent (CD) minimizes f over one coordinate at a time, keeping the others fixed. The cyclic version sweeps through i = 1, …, n and repeats: CO4A 23-01
xi ← argminxi f(x1, …, xi, …, xn) for i = 1, 2, …, n, then repeat
One sweep over all n coordinates is a cycle. Each update uses the newest values of the other coordinates. This one-at-a-time scheme is called Gauss–Seidel, and it matters: updating every coordinate at once from the old values (the Jacobi scheme) need not converge. You can also visit coordinates at random, or greedily pick the one with the largest gradient entry (the Gauss–Southwell rule). Blocks of coordinates work too. CMU 10-725 2016
Does it find the true minimum? For a smooth convex f, yes. Stop at a point where no single coordinate can improve, a coordinatewise minimum. There every partial derivative is zero, so the whole gradient is zero, and on Day 4 you saw that ∇f = 0 means a global minimum.
Worked example: a tilted bowl, f(x) = ½(x12 + 2c·x1x2 + x22) with a coupling c between 0 and 1. Setting ∂f/∂x1 = x1 + c·x2 to zero gives the exact update x1 = −c·x2. Likewise x2 = −c·x1. From (2, 1.5) with c = 0.9 the path is (−1.35, 1.5), (−1.35, 1.215), (−1.0935, 1.215), … an axis-aligned staircase. Each cycle multiplies the coordinates by c2 = 0.81.
Coupling c
0
0.5
0.8
0.9
0.95
0.99
CD cycles to f ≤ 10−10
1
9
26
52
102
479
GD steps, t = 1/L
1
25
80
167
333
1554
At c = 0 the bowl is round and aligned with the axes, so one cycle solves it. As c grows the bowl tilts and stretches, and both methods slow down. CD stays about three times faster here. Is that a fair race? Yes, because one CD cycle costs about one gradient. Each coordinate update reads one row of the problem, and a cycle reads every row once.
For least squares, ½‖y − Xβ‖22 with n data rows and p features, the update for feature i is βi ← βi + XiTr / ‖Xi‖22, where Xi is column i and r = y − Xβ is the residual. The residual trick keeps r up to date after each change, at a cost of O(n). So a full cycle costs O(np), the same as one gradient step. CO4A 23-02
Try it: here is the same widget in mode B. Slide the coupling c and watch the orange staircase and the blue gradient-descent path. Tap the plot to start somewhere else.
Notice that at coupling c = 0.9, coordinate descent needs 52 cycles to reach f ≤ 10⁻¹⁰, while gradient descent with step 1/L needs 167 steps, about 3.2 times as many for the same work per step. Slide c to 0 and both finish in one move.
6. Where coordinate descent gets stuck
Now add a kink that runs diagonally. Take f(x) = |x1 − x2| + 0.1(x12 + x22). It is convex, and its minimum is at (0, 0) with f = 0. Start CD at (2, 1), where f = 1.5.
Fix x2 = 1 and minimize |x1 − 1| + 0.1x12. At x1 = 1 the slope jumps from −1 + 0.2 = −0.8 to +1 + 0.2 = 1.2, so zero slope sits inside the jump, and x1 = 1 is the minimizer. Then fix x1 = 1 and minimize over x2: the same sum gives x2 = 1. CD is stuck at (1, 1), with f = 0.2.
The level set through (1, 1) (purple) has a sharp corner on the diagonal kink. Moving along either axis climbs out of the valley, so CD stops. Moving along the diagonal, toward the green minimum, goes down.
Is (1, 1) special? No. Every point (a, a) with |a| ≤ 5 is a coordinatewise minimum, so CD stops wherever it first lands on the diagonal. The direction downhill points along the diagonal, and both axis moves go uphill. A smooth convex function cannot do this, because at a smooth point "no axis move helps" already means "no move helps".
Analogy
A taxi may only drive north–south or east–west. It is looking for the lowest point of a V-shaped valley that runs diagonally across the city grid. Once it reaches the valley floor, every street leads uphill, even though the valley keeps sloping down along its length.
So when is a kink harmless? When it runs along the axes. The safe shape is a smooth part plus a separable function, a sum of one-variable pieces: CO4A 23-01
f(x) = g(x) + Σi hi(xi)
Here g is smooth and convex, and each hi is convex but may have kinks. Then a coordinatewise minimum is a global minimum. The one-line reason: every kink of Σhi(xi) lies along a coordinate direction, so single-coordinate moves can "see" it. The lasso penalty λ‖β‖1 = λΣ|βi| is separable. So are box constraints li ≤ xi ≤ ui, written as indicator functions.
Tseng (2001) turned this into a convergence theorem for cyclic CD. Assume f has this form and is continuous on the closed and bounded set {x : f(x) ≤ f(x0)}, and that its minimum is attained. Then every limit point of cyclic CD is a minimizer. CO4A states the result without these conditions; the CMU slides give them. CMU 10-725 2016
What breaks it is a nonsmooth term that ties coordinates together. Examples are |x1 − x2| above, the fused lasso Σ|βi+1 − βi|, and total variation in images. The support vector machine dual has a coupling constraint αTy = 0, which is why its classic solver, SMO, updates two coordinates at a time and needs its own analysis. CMU 10-725 2016 In the widget, mode C shows a separable kink that CD handles, and mode D shows the diagonal kink that stops it.
Going deeper (optional): why separable kinks are safe
Let x be a coordinatewise minimum of g + Σhi. For each i, the one-variable problem in xi is solved, so −∇ig(x) ∈ ∂hi(xi) (a subgradient condition from Day 7). For any y, convexity gives f(y) − f(x) ≥ ∇g(x)T(y − x) + Σ[hi(yi) − hi(xi)]. Regroup it as Σi[∇ig(x)(yi − xi) + hi(yi) − hi(xi)]. Each bracket is ≥ 0 by the subgradient condition, so f(y) ≥ f(x). The regrouping needs h to split by coordinate; |x1 − x2| cannot be split, and the proof fails. CO4A 23-01
7. The lasso, one coordinate at a time
The lasso, min ½‖y − Xβ‖22 + λ‖β‖1, is the poster child for CD. Its penalty is separable, so Tseng's theorem applies. And the one-coordinate problem has a closed-form answer: do least squares on feature i alone, then shrink the result toward zero.
βi ← Sλ/‖Xi‖²( XiTr−i / ‖Xi‖22 ) r−i = y − X−iβ−i
Here r−i is the residual with feature i left out, and St(z) = sign(z)·max(|z| − t, 0) is soft-thresholding from Day 8. It shrinks z toward 0 by t, and sets it to exactly 0 if |z| ≤ t. That is how the lasso produces exact zeros. CO4A 23-03
Worked example in 2-D: f = ½(x12 + 1.6x1x2 + x22) − x1 − 0.2x2 + 0.1(|x1| + |x2|). The two updates are x1 = S0.1(1 − 0.8x2) and x2 = S0.1(0.2 − 0.8x1). Start at (−1, 2). Cycle 1 gives x1 = S(−0.6) = −0.5, then x2 = S(0.6) = 0.5. Cycle 2 gives (0.5, −0.1).
After 10 cycles the point is (1.7958, −1.1366), and the limit is x* = (11/6, −7/6) ≈ (1.8333, −1.1667), with f* = −0.65. Check it with the optimality condition: the smooth part's gradient at x* is (−0.1, 0.1), exactly −λ·sign(x*) = −0.1·(1, −1). CD reaches f − f* ≤ 10−10 in 27 cycles. On Day 13's 30 × 10 lasso, cyclic CD reaches f − f* ≤ 10−8 in 5 full sweeps, with the same β* as ADMM.
import numpy as np
def lasso_cd(X, y, lam, cycles=100):
n, p = X.shape
beta = np.zeros(p)
r = y.copy() # residual y - X beta
sq = (X ** 2).sum(axis=0) # ||X_i||^2 for each column
for _ in range(cycles):
for i in range(p):
r += X[:, i] * beta[i] # leave feature i out: r_{-i}
z = X[:, i] @ r / sq[i] # least squares on feature i
beta[i] = np.sign(z) * max(abs(z) - lam / sq[i], 0)
r -= X[:, i] * beta[i] # put it back, O(n)
return beta
Real lasso solvers wrap this loop in a pathwise scheme, popularized by Friedman, Hastie and Tibshirani's glmnet. Friedman 2010 You rarely want one λ; you want a whole path of them. Start at the λ where β = 0 is optimal, then step down a grid λ1 > λ2 > …. Each solve begins from the previous answer, a warm start, so it needs only a few cycles. CO4A 23-04
Inside each solve, the active set trick saves more. Run a few cycles, then cycle only over the nonzero coordinates until they settle. Finally check the optimality condition |XiT(y − Xβ)| ≤ λ for every zero coordinate, and add back any that break it. "Strong rules" (Tibshirani and colleagues, 2012) screen out likely-zero features even before that. Tibshirani 2012CO4A 23-04
Why is this so fast in practice? Each update is a closed form with no step size to tune. Each costs O(n) thanks to the residual trick. Most coordinates are zero and stay zero, so they are skipped. And warm starts mean each λ needs few cycles. On CO4A's regression and lasso examples, CD beats gradient descent, accelerated gradient and proximal gradient. CO4A 23-02CO4A 23-03
The theory is less complete than the practice. For smooth problems, randomized and cyclic CD both have O(1/k) error, and linear convergence under strong convexity (Nesterov 2010; Beck and Tetruashvili 2013, as summarized by CO4A). Greedy selection can beat random selection. CO4A 23
So which tool when? Frank–Wolfe suits a cheap oracle with a costly projection, when modest accuracy is enough. CD suits a smooth loss plus a separable penalty or box. If a nonsmooth term couples the variables, or you need high accuracy, reach for proximal methods, ADMM (Day 13) or interior-point methods (Day 12).
Week 2 in one table
This closes Week 2. Here is every method so far on one page. Each rate is the one stated on that day, where you will find its sources. Tap a method's name for its algorithm card.
O(1/k) when smooth; linear when strongly convex; fast in practice
a cycle ≈ one gradient (O(np) for least squares)
smooth loss + separable penalty or box: lasso, elastic net, many features
Explain it to a 10-year-old
Frank–Wolfe: you are inside a fenced playground and want the spot nearest the ice-cream van outside. You look for the corner nearest the van and walk a little way toward it. Then you look again. You never climb the fence.
Coordinate descent is an Etch A Sketch. One knob moves left and right, the other up and down. Turn one knob until the line is as low as it goes, then the other. That works in a round bowl. It fails in a ditch that runs from corner to corner, because no single knob can follow the ditch.
Common misunderstandings
"Frank–Wolfe is projected gradient with a different step." It never takes a gradient step. It moves toward a corner chosen by a linear problem, and the gradient only decides which corner.
"Frank–Wolfe reaches high accuracy quickly." O(1/k) means about ten times more steps per extra digit, and it zig-zags when x* sits on an edge or face. On Day 13's lasso it needed 1000 steps to reach 3.4 × 10−5.
"The gap is a lower bound on the error." It is an upper bound: g(x) ≥ f(x) − f*. CO4A 22-03 prints the inequality the wrong way round.
"Exact line search always beats the 2/(k+2) step." Not on the edge preset: 3.1 × 10−3 versus 1.3 × 10−4 at k = 100. Which wins depends on the problem.
"Coordinate descent works on any convex function." A nonsmooth term that couples coordinates can stop it, as at (1, 1) for |x1 − x2| + 0.1‖x‖2.
"Compare one coordinate update with one gradient step." Compare a full cycle with one gradient step; for least squares both cost O(np).
"Updating all coordinates at once from the old values is coordinate descent." That is the Jacobi scheme, and it need not converge. Use each new value immediately.
Check yourself
Q1. What does each Frank–Wolfe iteration need to compute?
Frank–Wolfe calls a linear minimization oracle and then blends x with its answer. A projection, which is the same thing as the prox of the indicator of C, is exactly what it avoids.
Q2. ∇f(x) = (0.5, −3, 2) and C is the ℓ1 ball of radius 1. What does the oracle return?
The largest |entry| is 3, at position 2, and s = −sign(−3)·e2 = (0, 1, 0), which gives ∇fTs = −3. (0, −1, 0) forgets the minus sign and gives +3. (−1, 1, −1) is the box answer, and the scaled gradient is the round-ball answer.
Q3. A Frank–Wolfe run reports the gap g(x) = 0.004. What do you know?
Convexity puts f* above the tangent plane's lowest value over C, so the gap bounds the error from above. CO4A 22-03 prints this inequality the wrong way round. On the triangle at k = 10, the error is 1.5e−3 and the gap is 7.9e−2.
Q4. You run 10 Frank–Wolfe steps on an ℓ1 ball in ℝ1000, starting from x0 = 0. At most how many entries of x10 are nonzero?
Each step blends in one corner ±t·ei, which adds at most one new nonzero. Ten steps give at most 10. "1" would be true only if the oracle kept picking the same coordinate.
Q5. Cyclic coordinate descent on f = |x1 − x2| + 0.1‖x‖2, started at (2, 1), ends at…
The x1-update lands on the diagonal kink at (1, 1), where f = 0.2. From there both axis moves go uphill, though a diagonal move to (0.5, 0.5) gives f = 0.05. The function is convex, which is why (0, 0) is tempting, but its kink couples the coordinates.
Q6. For which problem do Tseng's conditions guarantee that cyclic coordinate descent finds a minimizer?
The lasso is smooth plus separable: λΣ|βi| splits by coordinate. The other three couple coordinates through a nonsmooth term or a constraint. The SVM dual is why SMO updates two coordinates at a time.
Recap: things to remember
Frank–Wolfe swaps projection for a linear minimization oracle: s = argmins∈C ∇f(x)Ts, then x ← (1 − γ)x + γs with γ = 2/(k + 2). It stays feasible with no projection.
The oracles are cheap: the best ei on the simplex, one signed coordinate with the largest |∇if| on the ℓ1 ball, −t·sign(∇f) on the box, the top singular pair on the nuclear-norm ball. The iterates are sparse or low-rank.
The gap ∇f(x)T(x − s) ≥ f(x) − f* comes free as a stopping test, and the error is at most 2Cf/(k + 2): an O(1/k) method that zig-zags when x* is on an edge.
Coordinate descent solves for one coordinate at a time. It finds a global minimum when f is smooth plus separable, and can get stuck when a kink couples coordinates.
For the lasso, each update is a soft-threshold, and a full cycle costs about one gradient. With warm starts and active sets (glmnet), CD is often the fastest lasso solver.
After today you can model yes/no decisions with binary variables and big-M constraints, explain why integer problems are hard, and solve small ones with LP relaxations, branch and bound and cutting planes.
About 60 min · Needs Days 5 and 9 · CO4A chapters 24 and 25
Today's big idea
Some decisions are switches, not dials: take the parcel or leave it, pass the obstacle on the left or on the right. Forbid fractions and the problem stops being convex, but a convex problem still hides inside it. Drop the "whole numbers only" rule and you get a relaxation whose value bounds the answer. Branch and bound and cutting planes use those bounds to find the true optimum, and to prove it, without trying every combination.
1. Switches, not dimmers
So far every variable was a dimmer that could sit anywhere, such as 0.3 or 0.71. Many real decisions are light switches instead. A robot takes a parcel or leaves it; a car passes an obstacle on the left or on the right.
An integer program (IP) is an optimization problem in which some variables must be whole numbers. CO4A writes it as a convex problem plus one extra rule: CO4A 24-1
minimize f(x) subject to x ∈ C, xj ∈ ℤ for j ∈ J
Here f is a convex function, C is a convex set, ℤ is the set of integers, and J lists the variables that must be integers. If J holds every variable, the problem is a pure integer program. If J holds only some, it is a mixed-integer program (MIP). A binary variable is an integer limited to 0 or 1: a yes/no switch.
The names follow the convex part, using the zoo from Day 5. A linear objective over a polyhedron gives a MILP (mixed-integer LP). A convex quadratic objective gives a MIQP. With a general convex f and C it is a mixed-integer convex program.
Our running example is a delivery robot that can carry 11 kg. Four parcels are waiting, each with a fee and a weight.
Parcel
Pays
Weight
$ per kg
A
$60
4 kg
15
B
$30
9 kg
3.33
C
$15
5 kg
3
D
$10
7 kg
1.43
Let xA = 1 mean "take A" and xA = 0 mean "leave it", and the same for B, C and D. Choosing items to maximize value under a weight limit is the knapsack problem: CO4A 24-2
There are only 24 = 16 ways to choose, so we can check them all. The best is A + C: $75 for 9 kg. Next come A + D ($70, 11 kg) and A alone ($60). With 50 parcels there would be 250 ≈ 1015 choices, and checking them all is no longer an option.
Combinatorial optimization, picking the best subset from a finite set of options, is full of binary IPs like this one. CO4A's examples include assignment, facility location, K-medoids clustering and best subset selection. CO4A 24-2
2. Why not just round the LP?
The obvious shortcut: forget the switch rule, solve the easy problem, then round. Replacing "x is 0 or 1" with 0 ≤ x ≤ 1 gives the LP relaxation. It is a plain LP from Day 5, so it solves fast.
For a knapsack the LP has a simple answer. Fill the bag in order of dollars per kilogram, and cut the first item that does not fit. A earns $15/kg, so take all of it: 4 kg, leaving 7 kg. B is next at $3.33/kg but weighs 9 kg, so take 7/9 of it. The bag is now full.
x = (1, 7/9, 0, 0) value = 60 + 30 · 7/9 = 250/3 ≈ 83.33
Now round. Rounding B up packs 13 kg, which breaks the 11 kg limit. Rounding B down leaves A alone, worth $60. The true optimum is $75, and it uses C, an item the LP did not touch at all. Figure 1 shows the four packings side by side.
Figure 1. Each bar is one packing, drawn to scale (25 px per kg). The LP fills the bag exactly by cutting B. Neither rounding gives the best packing, A + C, which the LP never suggested.
The distance between the relaxation's optimum and the integer optimum is the integrality gap. Here it is 83.33 − 75 = 8.33, or 11.1% of the answer. CO4A lists three ways rounding goes wrong: integer-feasible points can be hard to find, the relaxed optimum can sit far from the integer one, and the rounded point can be poor. CO4A 24-3
Is there a clever trick that always works? Almost certainly not. Integer programming is NP-hard in general, so no known method solves every instance in time that grows only polynomially with its size. CO4A 24-3 The methods below are exact, but on bad instances they can still take exponential time.
3. Modelling yes/no decisions with binaries
Binaries become powerful when wired into other constraints. Think of a binary as the lock on a gate: locked, the rule holds; open, the rule is switched off.
Counting and linking. Σ zi ≤ k means "at most k of these", and Σ zi = 1 means "exactly one". "Serve customer i from depot j only if depot j is open" becomes xij ≤ yj, where yj = 1 means open, as in CO4A's facility-location model. CO4A 24-2
Fixed costs. Renting a van costs $50 a day, whether you ship one parcel or a hundred, plus $3 per parcel. Let y = 1 if you rent the van, and let x be the number of parcels (at most 100):
cost = 50y + 3x, x ≤ 100y
If y = 0, then x must be 0. If y = 1, up to 100 parcels can go. Shipping 20 parcels costs 50 + 60 = $110.
A big-M constraint uses a binary to switch a whole inequality on or off. To make the rule g(x) ≤ 0 switchable, write
g(x) ≤ M · b, b ∈ {0, 1}
With b = 0 it reads g(x) ≤ 0: the rule is on. With b = 1 it reads g(x) ≤ M. For that to be harmless, M must be at least the largest value g can take on the region you care about. Example: x lies in [0, 10] and the rule is x ≤ 2, so g(x) = x − 2. Its largest value is 10 − 2 = 8, so M = 8 is the smallest valid choice, and the switchable rule is x ≤ 2 + 8b.
Logical OR. The constraints of a convex problem are joined by AND. To demand "x ≤ 2 OR x ≥ 4", give each side its own switch and insist that at least one stays on:
x ≤ 2 + 8b1, x ≥ 4 − 4b2 b1 + b2 ≤ 1
The second M is 4, because 4 − x is at most 4 on [0, 10]. Check x = 5: set b2 = 0 and b1 = 1, and every row holds. Check x = 3: both rules fail, so b1 = b2 = 1, which breaks the last row, and x = 3 is excluded. The allowed set [0, 2] ∪ [4, 10] is not convex; the binaries let a convex solver handle it anyway.
Many solvers also accept an indicator constraint, "if z = 1 then g(x) ≤ 0", and handle it without a hand-picked M. It is the safer choice when M is hard to bound.
You want
Write it as
Example
At most k of n
Σ zi ≤ k
best subset: at most k features
Use only what is open
xij ≤ yj
depot j serves customers only if open
A fixed cost
50y + 3x, x ≤ 100y
pay $50 for the van only if used
Switch a rule off
g(x) ≤ M · b
x ≤ 2 + 8b on [0, 10]
Either-or
one switch per side, Σ b ≤ sides − 1
x ≤ 2 or x ≥ 4
Not both
xA + xB ≤ 1
A and B together are too heavy
4. Bounds from both sides
A convex problem tells you it is solved through a local test, such as the KKT conditions of Day 10. An integer program has no such test, so CO4A squeezes instead: guaranteed limits from one side, real solutions from the other, until they meet. CO4A 24-3
Picture a negotiation. The best offer so far is a price you can actually get; the walk-away limit is a price nobody will beat. When they meet, the deal is done. For our maximization problem:
a floor: the value of the incumbent, the best integer-feasible solution found so far. Any real packing gives one; rounding down gave $60.
a ceiling: a bound (or dual bound), a guaranteed limit on how good any solution can be. The LP relaxation gave $83.33.
Why is the LP value a ceiling you can trust? A relaxation is an easier problem whose feasible set contains the original one and whose objective is never worse on the original points. CO4A 24-4 Every packing is also a feasible point of the LP, so the LP's best is at least as good as the best packing. CO4A states it for minimization, where the relaxation gives a lower bound:
X ⊆ Y and g(x) ≤ f(x) for x ∈ X ⇒ minx∈Y g(x) ≤ minx∈X f(x)
For a maximization problem, flip it: the relaxation gives an upper bound. The difference between ceiling and floor is the optimality gap (MIP gap). Solvers report it as they run and stop when it falls below a tolerance you choose; a gap of zero means proven optimal. In our example the gap starts at 83.33 − 60 = 23.33. Figure 2 shows how the search in section 5 closes it.
Figure 2. The true optimum is always inside the shaded band between the best ceiling and the best floor. Relaxations push the ceiling down, real packings push the floor up, and at $75 they meet. Scale: 7.5 px per dollar.
This is Day 9's idea in new clothes. There, every dual-feasible point gave a lower bound on a minimization problem. Here, Lagrangian relaxation does the same: move a hard constraint into the objective with a price u ≥ 0 per unit. CO4A 24-4
For the knapsack, rent the robot's capacity at u dollars per kilogram. You collect 11u for all 11 kg, and each parcel is worth taking only if its fee vi beats its rent u · wi, where wi is its weight:
L(u) = 11u + Σi max(0, vi − u · wi)
The one-line reason it is a ceiling: for any packing that fits, the unused capacity 11 − Σ wixi is ≥ 0, so adding u times it can only raise the value. Try a few prices: L(0) = 115, L(3) = 84, L(10/3) = 83.33, L(4) = 88. The lowest ceiling is at u = 10/3, which is B's dollars per kilogram, and it equals the LP bound. For a single knapsack row the two always agree.
5. Branch and bound
Rounding failed, but the LP did point at B, the item it could not decide on. So split on B: one branch says "take B" (xB = 1), the other "skip B" (xB = 0). Every packing lands in exactly one branch, so the best packing is the better of the two branch optima.
Each branch is a smaller knapsack with its own LP ceiling. The key move: if a branch's ceiling is no better than a packing you already hold, nothing inside it can win, so discard the whole branch unopened.
Picture hunting for the cheapest flight. You already hold a $400 ticket. If the most optimistic fare through Tokyo is $450, you never look at a single Tokyo route.
Branch and bound (B&B) repeats this move. Each piece is a node in a tree. CO4A writes the splitting rule for minimization over a set X cut into pieces X1, …, Xk: CO4A 24-5
minx∈X f(x) = mini ( minx∈Xi f(x) )
Pruning (or fathoming) discards a node for good, in one of three ways:
its relaxation is infeasible, so the node holds no points;
its relaxation's solution is already integer, so record it as a candidate incumbent;
its bound is no better than the incumbent (for our maximization, bound ≤ incumbent).
Otherwise, branch on a fractional variable and add the two children to the list of open nodes. Here is the whole search on the robot's parcels:
Root: x = (1, 7/9, 0, 0), bound $83.33. B is fractional, so split on B.
B = 1 fills 9 kg and leaves 2 kg, so half of A fits: x = (1/2, 1, 0, 0), bound $60. B = 0 takes A, then C (9 kg in all), then 2/7 of D: x = (1, 0, 1, 2/7), bound 545/7 ≈ $77.86.
Open the more promising node, B = 0, and split on D. D = 1 gives x = (1, 0, 0, 1), $70, integer: the first incumbent. D = 0 gives x = (1, 0, 1, 0), $75, integer: the new incumbent.
Only B = 1 is left. Its bound $60 ≤ $75, so prune it. Nothing is open, so $75 is proven optimal.
That took 5 LP solves instead of 16 packings. The tree itself is the proof: every branch was either solved or shown unable to beat $75.
Which open node comes next? CO4A leaves this open; two standard rules are worth knowing. Best-bound search always opens the node with the highest ceiling. It tends to solve the fewest nodes but can keep many open at once. Depth-first search keeps diving down one branch before backing up. It finds feasible points early and uses little memory, but a dive into a poor branch wastes work.
On our parcels, depth-first search that tries "take" first dives into B = 1. With no incumbent yet, nothing can be pruned, so it digs four levels deep, meets three infeasible nodes (13, 14 and 16 kg), and finds B alone, worth $30. Then it backs up to B = 0 and finds $70 and $75. Total: 11 LP solves instead of 5. See the branch-and-bound card for the general algorithm.
Try it: the widget opens on the finished best-bound search. Press Reset, then Step to open one node at a time, and read the log below the tree. Then switch to "Depth-first, take first" and watch the dive.
Notice that the root bound is $83.33, and best-bound proves $75 (A + C) optimal with 5 LP solves, pruning B = 1 because $60 ≤ $75. Switch to depth-first, take first: it needs 11 LP solves (3 infeasible), and its best-so-far goes $30 → $70 → $75.
The same best-bound search in plain Python, where lp is the greedy fill from section 2:
import heapq
v, w, W = [60, 30, 15, 10], [4, 9, 5, 7], 11 # items sorted by $ per kg
def lp(fix): # LP bound with some items fixed to 0 or 1
cap = W - sum(w[i] for i in fix if fix[i])
if cap < 0: return None, None # infeasible: too heavy already
x = [fix.get(i, 0) for i in range(4)]
for i in (i for i in range(4) if i not in fix):
x[i] = min(1, cap / w[i]); cap -= x[i] * w[i] # greedy fill, one item may be cut
return sum(a * b for a, b in zip(v, x)), x
best, solves = 0, 1
bound, x = lp({}); heap = [(-bound, 0, {}, x)] # best-bound: largest bound first
while heap:
nb, _, fix, x = heapq.heappop(heap)
if -nb <= best: continue # prune: cannot beat the incumbent
j = next(i for i in range(4) if 0 < x[i] < 1) # the fractional item
for f in (1, 0): # take it, then skip it
b, xc = lp({**fix, j: f}); solves += 1
if b is None: continue
if all(t in (0, 1) for t in xc): best = max(best, b)
else: heapq.heappush(heap, (-b, solves, {**fix, j: f}, xc))
print(best, solves) # 75 5
6. Cutting planes and branch and cut
Branching splits the region in two; a cutting plane shaves it instead. Picture whittling a block of wood toward the shape hidden inside, the integer points. Each cut slices off a corner that contains none of them.
The ideal finished shape is the convex hull of the integer points: the smallest convex set that contains them all. With a linear objective, the LP over the convex hull has the same optimum as the integer program, because an LP's optimum sits at a corner and every corner of the hull is an integer point. CO4A 25-1-1 The catch is that the hull can need exponentially many inequalities, so nobody writes it down in full.
Instead, add inequalities one at a time. A valid inequality is one that every integer-feasible point satisfies. It is a cutting plane (or cut) if the current fractional LP solution x(k) violates it: CO4A 25-1-2
valid: πTx ≤ π0 for every integer-feasible x cut: valid, and πTx(k) > π0
The loop: solve the LP; if the answer is integer, stop; otherwise add a cut and solve again.
The robot's parcels give the easiest cuts. A cover cut says that if a set of items is too heavy for the bag, you cannot take all of them. A and B weigh 13 kg > 11 kg, so
xA + xB ≤ 1
Every packing obeys it, but the LP point (1, 7/9, 0, 0) has xA + xB = 1.78, so it is cut off. The new LP optimum is (1, 0, 1, 2/7), worth $77.86. C and D weigh 12 kg > 11 kg, so xC + xD ≤ 1 is valid too. With both cuts the LP optimum is (1, 0, 1, 0), worth $75. That point is integer, so it is optimal, with no branching at all. In the widget, pick one cut and best-bound needs 3 LP solves; pick both and it needs 1.
Cover cuts only work on knapsack rows. In 1958 Gomory found a recipe for any integer program with integer data. CO4A 25-1 It rests on one fact: if a ≤ b and a is an integer, then a ≤ ⌊b⌋, where ⌊b⌋ means b rounded down. CO4A 25-1-3
A tiny example. Maximize x2 subject to 3x1 + 2x2 ≤ 6 and −3x1 + 2x2 ≤ 0, with x1, x2 ≥ 0 and integer. The LP region is the triangle in Figure 3, and the LP optimum is its top corner (1, 1.5), with value 1.5.
Figure 3. The LP region (blue) has its optimum at the fractional corner (1, 1.5). The Gomory cut x₂ ≤ 1 removes the pink cap, which holds no integer point. After the cut, the integer point (1, 1) reaches the LP's best value, 1. Goal: maximize x₂ (go up).
Add slack variables s1 = 6 − 3x1 − 2x2 and s2 = 3x1 − 2x2, both ≥ 0. All the data are integers, so s1 and s2 are integers at every integer point. The simplex method's final row for x2 reads
x2 + ¼s1 + ¼s2 = 3/2
Keep only the fractional part of each number: 0 for x2's coefficient 1, and ½ for the right side 3/2. Since x2 is an integer, the remaining terms must make up at least that ½:
¼s1 + ¼s2 ≥ ½, that is, s1 + s2 ≥ 2
Since s1 + s2 = 6 − 4x2, the cut is 6 − 4x2 ≥ 2, or x2 ≤ 1. The new LP value is 1, and the integer point (1, 1) reaches it, so (1, 1) is optimal. In general, a Gomory cut comes from any tableau row Σ ajxj = a0 with fractional a0 and integer xj ≥ 0: CO4A 25-1-3
Σj (aj − ⌊aj⌋) xj ≥ a0 − ⌊a0⌋
Real solvers do both moves. Branch and cut is branch and bound with cuts added at the nodes: solve the relaxation; stop if it is infeasible or integer; otherwise either add a cut and solve again, or branch. CO4A 25-1-4 CO4A names Gurobi, CPLEX and FICO as examples.
The history, as CO4A reports it: Dantzig, Fulkerson and Johnson used cuts on the travelling salesman problem in 1954, and Gomory gave a general method in 1958. For about 30 years cuts were thought impractical. Around 1990 they were combined with branch and bound, and branch and cut became the core of commercial solvers. CO4A 25-1 CO4A also reports that from 1990 to 2016 MIP solving got more than 500,000 times faster from algorithms and more than 500,000 times faster from hardware, about 2.5 × 1011 combined. CO4A 25-1-4
So: hard in theory, often fine in practice. The worst case still grows exponentially with the number of integer variables. Yet branch and cut solves many practical models in seconds to minutes, as the footstep planner below shows. For modellers, a tight relaxation (small M, good cuts) often matters more than a faster computer.
7. Integers at work: statistics and robots
CO4A's chapter 25 ends with two statistics examples. Best subset selection asks for the best regression model that uses only k of p features. Give each coefficient βi a switch zi, so that zi = 0 forces βi = 0: CO4A 25-2-1
minimize ½‖y − Xβ‖22 subject to |βi| ≤ Mizi, Σ zi ≤ k z ∈ {0, 1}p
Here y holds n measurements, X is the n × p data, and Mi comes from preprocessing. CO4A's tip for this MIQP is a warm start: start the solver from a good solution, found by cheap gradient steps that keep only the k largest coefficients. In CO4A's figures (n = 350, p = 64, k = 6) the good solution appears early, most of the time goes into proving it optimal, and warm starts beat cold starts. CO4A 25-2-1
The second example fits a line that ignores outliers by minimizing the q-th smallest absolute residual. CO4A says it tolerates about 50% outliers but is NP-hard; binaries choose which residuals sit below a threshold. (The page is titled "least mean squares", but it covers least median, or quantile, of squares.) CO4A 25-2-2
Which side of the obstacle? A point robot drives in the square [0, 10] × [0, 10] (in metres). A box obstacle covers [2, 4] × [1, 3]. Being outside the box means: left of x = 2, OR right of x = 4, OR below y = 1, OR above y = 3. That set is not convex, so give each side a binary, with b = 1 meaning "this side is switched off":
x ≤ 2 + M b1, x ≥ 4 − M b2 y ≤ 1 + M b3, y ≥ 3 − M b4 b1 + b2 + b3 + b4 ≤ 3
The last row keeps at least one side on. How big must M be? A switched-off row must still hold everywhere in the square. Row 1 needs x − 2 ≤ M, and x − 2 is at most 10 − 2 = 8. The other rows need 4 − 0 = 4, 10 − 1 = 9 and 3 − 0 = 3. One shared M must cover the largest, so the smallest valid shared M is 9 (M = 10 also works).
Check the point (5, 2): switch on row 2 (b2 = 0, and x ≥ 4 holds) and switch the rest off. Allowed. Check the obstacle's center (3, 2): every row fails when switched on, so all four b's must be 1, and their sum 4 breaks the last row. Excluded.
Now the warning. In the LP relaxation each b may be fractional. With M = 10 and b = (0.1, 0.1, 0.1, 0.1), the rows read x ≤ 3, x ≥ 3, y ≤ 2 and y ≥ 2, so the center (3, 2) is allowed, and the sum 0.4 ≤ 3 is fine. The relaxation drives straight through the obstacle. With M = 1000, b = 0.001 each is enough. A bigger M gives a weaker relaxation and worse bounds, so use the smallest valid M.
For a trajectory, repeat the four rows for every time step and obstacle, a pattern Deits and Tedrake credit to Richards and colleagues' UAV planners. Deits & Tedrake 2014 With 20 time steps and 3 obstacles that is 4 × 20 × 3 = 240 binaries.
Figure 4. Left, to scale: the obstacle [2, 4] × [1, 3] in the 10 m square. Each dashed side is a rule a binary can switch off, and at least one must stay on. Right, a sketch of the footstep idea: safe patches are convex, and a binary puts each footstep (blue) into exactly one patch.
Footstep planning. Deits and Tedrake turn the question around (see the footstep paper). Instead of one binary per obstacle side, they first compute R convex patches of safe, flat ground, using the IRIS method from the IRIS paper. Then a binary Hr,j says "footstep j lies in region r": Deits & Tedrake 2014
Hr,j = 1 ⇒ Arfj ≤ br Σr Hr,j = 1 for each step j
Here fj is the position of footstep j, and Arf ≤ br describes region r. Once every H is fixed, the rest of the problem is convex. A reachability rule keeps each step inside two discs placed relative to the previous foot, which is a convex quadratic constraint. Turning enters through sin and cos, replaced by piecewise-linear pieces that more binaries choose, built so the robot never overestimates its reach. Because of the quadratic constraints, the authors call the problem a MIQCQP: a mixed-integer program with a quadratic objective and quadratic constraints. Deits & Tedrake 2014
With Gurobi on an Intel i7 2.9 GHz laptop, typical plans with 10–20 footsteps and 10 safe regions took from a few seconds to one minute, and a few steps took well under a second. Every plan shown was within 0.1% of the global optimum, as reported by Gurobi. The limits are honest ones: a person had to seed the safe regions, and only the foot positions are checked for collisions, not the swing between them. Deits & Tedrake 2014Day 19 returns to obstacles and convex pieces, and the GCS paper builds formulations whose relaxations are much tighter.
Analogy
Packing a suitcase. You take the camera or you don't; you can't pack 7/9 of it (binary). A quick estimate that pretends you could pack fractions tells you the best you could hope for (relaxation). If a whole family of plans, say "everything with the big boots", cannot beat the bag you already packed, you stop considering it (pruning). And noticing "the boots and the tripod never fit together" removes nonsense plans before you even start (a cut).
Explain it to a 10-year-old
Your backpack holds 11 kg of toys, and each toy has a fun score. First you cheat and pretend you can saw a toy in half. That tells you the most fun you could ever get. Then you ask: "Do I take the heavy toy or not?" For each answer you cheat again to see the best you could get. If one answer can't beat a backpack you already packed, you never think about it again.
Common misunderstandings
"Round the LP solution and call it optimal." B = 7/9 rounds to a 13 kg packing that does not fit, or to A alone at $60. The optimum is $75.
"Pick M really big, to be safe." A huge M makes the relaxation weak: with M = 10 the obstacle's center is LP-feasible at b = 0.1 each, and with M = 1000 at b = 0.001. It also hurts the numerics. Use the smallest M that is valid on bounded variables, or an indicator constraint.
"The relaxation is always a lower bound." Only for minimization. For a maximization like the knapsack it is an upper bound.
"Branch and bound tries every combination." Here it solved 5 LPs instead of checking 16 packings, because the bounds did the pruning. The worst case is still exponential.
"A cut may throw away integer solutions." A valid cut removes only fractional points. Every packing still obeys xA + xB ≤ 1.
Going deeper (optional): why each step is exact
Branching. The children xj = 0 and xj = 1 split the parent's integer points into two groups with nothing lost, so the better child optimum is the parent optimum (CO4A 24-5's identity). Fractional points in between are dropped, which is the point.
Lagrangian bounds. For any feasible x and u ≥ 0 the price term uT(Ax − b) is ≤ 0, so the relaxed value bounds the true one. L(u) is a pointwise minimum of affine functions of u, so it is concave (in CO4A's minimization form) and can be maximized with subgradient steps from Day 7. CO4A 24-4
Gomory cuts. Split each coefficient into its integer part and its fractional part fj ∈ [0, 1). At an integer point the integer parts give an integer, so Σ fjxj differs from f0 by a whole number. It is also ≥ 0, so it is at least f0. Making a pure cutting-plane method finish in finitely many steps needs extra rules, which we skip.
The convex hull. If the data A and b are rational, the convex hull of the integer points of {x : Ax ≤ b} is a polyhedron, but it can need exponentially many inequalities. CO4A 25-1-1 Other cut families (Chvátal, split, lift-and-project) are named in CO4A 25-1-3.
Check yourself
Q1. The LP relaxation of the robot knapsack is worth $83.33. What does that tell you?
Every packing is a feasible point of the LP, so the LP's value is a ceiling for this maximization problem. No packing reaches it here: the best is $75, and the LP point itself uses 7/9 of B.
Q2. Node "B = 1" has bound $60, and the incumbent is $75. What happens to the node?
The bound is the best any packing with B can earn. Since $60 ≤ $75, branching on A would only waste LP solves. $60 is a bound, not a packing, so it cannot be an incumbent.
Q3. Why did depth-first search (take first) need 11 LP solves when best-bound needed 5?
Depth-first does prune by bound, but there was nothing to compare against until it found $30 at the bottom of the B = 1 branch. Best-bound opened B = 0 first, found $75, and pruned B = 1 at once.
Q4. On x ∈ [0, 10] you write the switchable rule x ≤ 2 + M·b. What is the smallest valid M?
With b = 1 the row must hold for every x in [0, 10], so 2 + M ≥ 10, giving M ≥ 8. M = 10 also works but is weaker, and 1000 makes the relaxation much weaker.
Q5. Why does a very large M hurt, even though it is still valid?
The integer problem is unchanged, so its optimum is the same. But tiny fractional b values now switch rules almost fully off: with M = 1000, b = 0.001 lets the relaxed robot drive through the obstacle's center.
Q6. What is a cutting plane?
A cut must be valid (keeps every integer point) and must slice off the current LP solution. xA + xB ≤ 1 is one: every packing obeys it, but (1, 7/9, 0, 0) does not.
Recap: things to remember
A mixed-integer program is a convex problem plus "some variables are whole numbers". Binaries model yes/no choices, counts, links, fixed costs and OR.
Big-M switches a rule off with b = 1. Choose the smallest M that is valid on the bounded region; bigger M means a weaker relaxation.
Dropping integrality gives a relaxation and a bound (upper for max, lower for min). Rounding its answer can be infeasible or poor: $60 versus $75.
Branch and bound splits on a fractional variable and prunes nodes that are infeasible, integer, or bounded below the incumbent. Best-bound took 5 LPs here; depth-first took 11.
Cuts shave fractional corners without losing integer points. Branch and cut combines both, and it is how modern solvers, and planners like Deits and Tedrake's footstep MIQCQP, work.
Knapsack, Lagrangian, branch-and-bound, cover-cut and Gomory numbers: computed for this course in Python (exact fractions) and in the widget, 2026-10-26.
Week 3 · Day 16
When it isn't convex: nonlinear optimization
After today you can tell local from global minima and saddle points, read the KKT conditions for nonlinear programs, and explain how SQP, Gauss–Newton and Levenberg–Marquardt solve the nonconvex problems that robots actually face.
About 70 min · Needs Days 10 and 11 · No CO4A chapter (this day is new)
Today's big idea
Most robot problems are not convex. Rotations, camera projections and vehicle dynamics bend the landscape into many valleys. Local solvers still work well, but they only promise the floor of a nearby valley, and the starting point decides which one. The best nonconvex solvers are built from convex pieces: each step solves a convex model, and a convex relaxation can sometimes prove that the answer is global.
1. Many valleys: local minima, saddles and the starting point
On Day 1 a convex function was a single bowl. Walk downhill from anywhere and you reach the one bottom. A nonconvex function is a mountain range. Walking downhill takes you to the floor of whichever valley you started above.
Two words make this precise. A point x* is a local minimum if no feasible point near it is lower: f(x*) ≤ f(x) for every feasible x close to x*. It is a global minimum if no feasible point anywhere is lower. In a convex problem every local minimum is global (Day 4). Without convexity that promise is gone.
A stationary point is a point where the gradient is zero, ∇f(x) = 0. Every unconstrained minimum of a smooth function is stationary, but so is every hilltop and every mountain pass. To tell them apart you look at the Hessian ∇2f, the matrix of second derivatives, which measures how the surface curves.
∇f(x*) = 0 and ∇2f(x*) ≻ 0 ⇒ x* is a strict local minimum
The symbol ≻ 0 means positive definite: the function curves upward in every direction. At any local minimum the Hessian is at least ⪰ 0, so it never curves down. A saddle point is a stationary point that curves up in some directions and down in others, like a mountain pass. The standard example is g(x, y) = x2 − y2 at the origin: ∇g(0, 0) = 0, and the Hessian is diag(2, −2), so the surface rises along x and falls along y.
Now a number. Day 1's bumpy curve, a "double well" (there called g), is f(x) = x4 − 4x2 + x. It has three stationary points on [−2, 2], where f′(x) = 4x3 − 8x + 1 = 0:
x
f(x)
f″(x)
What it is
−1.4730
−5.4442
18.04 > 0
global minimum
0.1260
0.0627
−7.81 < 0
local maximum (a hilltop)
1.3470
−2.6186
13.77 > 0
local minimum, not global
A solver that stops at x ≈ 1.347 passes every local test, yet its answer is 2.83 above the best one.
The set of starts that a method sends to the same minimum is that minimum's basin of attraction. Run gradient descent (Day 6, step 0.02, 2,000 steps) from the nine starts −2, −1.5, …, 2. The five starts at or below 0 reach the global minimum. The four starts at 0.5 and above get stuck at 1.347. The hilltop at x ≈ 0.126 is the border between the two basins.
Day 1's bumpy curve, the double well. The dots on the bottom line are nine starting points x₀ for gradient descent, coloured by where they end. The dashed line at the hilltop (x ≈ 0.126) splits the two basins of attraction. Computed for this lesson.
The cheapest fix is multi-start: run a local solver from many starting points and keep the best result. The starts can be random or on a grid, and they run in parallel.
x̂ = best of local_solve(x₀(k)), k = 1 … K
On the double well, 5 of the 9 grid starts land in the right basin, so the grid finds the global minimum. But multi-start gives no certificate: more starts only raise the odds. Boyd and Vandenberghe put the trade simply. Local methods are fast but say little about how far from global they ended. Global methods can certify the answer, at a worst-case cost that grows exponentially. Boyd & Vandenberghe 2004 §1.4
Analogy
A hiker in thick fog has only a slope sensor. She can always walk downhill, and she can tell when the ground is flat and rises on every side. That proves "I'm at a low point nearby". It can never prove "this is the lowest point in the country". Sending several hikers from different places, and comparing altimeters at the end, is multi-start.
2. Constraints: the KKT conditions for nonlinear programs
A nonlinear program (NLP) is an optimization problem whose objective or constraints are nonlinear, and possibly nonconvex. We use Day 10's notation, writing its lj as ℓj so it is not mistaken for a 1:
minimize f(x) subject to hi(x) ≤ 0, ℓj(x) = 0
Recall Day 10's picture: a ball rests against some walls. Its downhill pull is exactly cancelled by the push of the walls it touches. A wall can only push, never pull, and a wall it is not touching pushes with zero force.
The formula says the same thing. The Lagrangian is L(x, λ, ν) = f(x) + Σ λihi(x) + Σ νjℓj(x). Each Lagrange multiplier λi or νj is the force (or price) of one constraint. An inequality that holds with equality at x is an active constraint: it is a wall you are touching.
These are the same four KKT conditions as on Day 10. Two things change when the problem is not convex. Wikipedia: KKT
First, KKT is necessary only under a constraint qualification. A constraint qualification is a regularity condition on the constraints. The common one is LICQ (linear independence constraint qualification): the gradients of the active constraints at x* are linearly independent. If LICQ holds at a local minimum, the KKT conditions hold there, with unique multipliers.
Here is what goes wrong without one. Minimize x subject to x2 ≤ 0. The only feasible point is x = 0, so it is optimal. But ∇h(0) = 2·0 = 0, so LICQ fails, and stationarity would need 1 + λ·0 = 0, which is impossible. The optimum is not a KKT point. The wall exists, but it has no direction to push in.
Second, KKT is no longer sufficient. On Day 10, any KKT point of a convex problem was optimal. Now KKT points include maxima and saddles, so you also check curvature. In plain words: stand at the KKT point and look along every direction that keeps the active constraints satisfied, to first order. If the Lagrangian curves upward along all of them, you are at a strict local minimum. This is the second-order sufficient condition:
sT∇2xxL(x*, λ, ν) s > 0 for every such direction s ≠ 0
A worked example shows both points. Minimize x₁ + x₂ on the circle x₁2 + x₂2 = 2, so ℓ(x) = x₁2 + x₂2 − 2. The gradient ∇ℓ = (2x₁, 2x₂) is never zero on the circle, so LICQ holds everywhere. Stationarity reads 1 + 2νx₁ = 0 and 1 + 2νx₂ = 0, so x₁ = x₂ = −1/(2ν). Putting that on the circle gives ν = ±½.
KKT point
ν
f
∇2xxL = 2νI
Verdict
(−1, −1)
½
−2
I, curves up
minimum
(1, 1)
−½
2
−I, curves down
maximum
A note on sources. The nonlinear-programming theory in Sections 2 and 3 is standard textbook material, taken here from the Wikipedia articles on KKT and SQP and from Boyd and Vandenberghe. No page of Nocedal and Wright's Numerical Optimization, the usual reference, was opened while writing this lesson.
Left: at both KKT points the gradient ∇f and the constraint term ν∇ℓ are equal and opposite, so ∇f + ν∇ℓ = 0. One point is the minimum and the other the maximum, and only curvature tells them apart. Right: a zoom on the dashed square, showing SQP from x₀ = (−1.5, −0.5). The first step lands on the straight-line model of the circle at x₀. By x₂ the iterates are already close to x* = (−1, −1).
3. SQP: solve a QP at every step
Picture driving a winding road in the dark. You fit a parabola to the stretch your headlights show, drive to its best point, and fit again. Sequential quadratic programming (SQP) does this with a problem. At the current guess xk it builds a QP (Day 5): a quadratic model of the Lagrangian and straight-line models of the constraints. It solves the QP for a step d, moves, and repeats. Wikipedia: SQP
minimize over d: ∇f(xk)Td + ½ dT∇2xxL(xk) d subject to ℓ(xk) + ∇ℓ(xk)Td = 0 h(xk) + ∇h(xk)Td ≤ 0
With only equality constraints, the QP's own KKT conditions are one linear system. That system is exactly Newton's method (Day 11) applied to the KKT equations of the original problem. This is why SQP converges fast once it is close. ν⁺ is the new multiplier estimate:
∇2xxL · d + ∇ℓ · ν⁺ = −∇f ∇ℓTd = −ℓ(xk)
Run it on the circle from x₀ = (−1.5, −0.5) with ν₀ = 1. This start is off the circle: ℓ(x₀) = 2.25 + 0.25 − 2 = 0.5. Here ∇ℓ(x₀) = (−3, −1) and ∇2xxL = 2ν₀I = 2I. The system becomes 2d₁ − 3ν⁺ = −1, 2d₂ − ν⁺ = −1 and −3d₁ − d₂ = −0.5. Its solution is d = (0.25, −0.25) with ν⁺ = 0.5, so x₁ = (−1.25, −0.75).
k
xk
νk
constraint error ℓ(xk)
0
(−1.5, −0.5)
1
0.5
1
(−1.25, −0.75)
0.5
0.125
2
(−1.0368, −1.0221)
0.4853
0.119
3
(−1.00024, −1.00066)
0.4994
1.8×10⁻³
4
(−1.000000, −1.000000)
0.5000
4.9×10⁻⁷
5
(−1.000000, −1.000000)
0.5000
1.8×10⁻¹³
From step 3 on, the error roughly squares each step (10⁻³, 10⁻⁷, 10⁻¹³): Newton speed. The figure above draws this path on the right.
Real SQP solvers add safety gear. On a nonconvex problem ∇2xxL can curve down, which makes the QP nonconvex. Solvers then regularize the matrix, or replace it by a BFGS approximation kept positive definite (BFGS card). A merit function or a filter judges whether a step made progress on both the objective and the constraint violation. A line search or trust region decides how far to go. Codes that implement SQP include SciPy's SLSQP, SNOPT, KNITRO and acados. Wikipedia: SQP See also the SQP card.
The robotics payoff: nonlinear vehicle dynamics in a model predictive controller do not stop you from using the QP machinery of Day 17. SQP turns the nonlinear problem into a sequence of QPs of that kind.
4. Interior points for nonconvex problems: IPOPT
Recall Day 12. A barrier method replaces each inequality hi(x) ≤ 0 by a log penalty that shoots to infinity at the wall. It then shrinks the barrier weight μ step by step, following the central path from deep inside the feasible set toward the boundary.
minimize f(x) − μ Σ log(−hi(x)) s.t. ℓ(x) = 0 then let μ → 0
This is Day 12's t·f(x) + φ(x) divided by t, with μ = 1/t, so shrinking μ is the same as growing t.
Nothing in that recipe needs convexity. The open-source solver IPOPT applies it to general NLPs of the form "minimize f(x) subject to gL ≤ g(x) ≤ gU and xL ≤ x ≤ xU". Its home page calls it an "interior point line search filter method that aims to find a local solution". The functions may be nonconvex but must be twice continuously differentiable. Ipopt docs This makes IPOPT an interior-point method for NLPs. Compare the barrier card and the primal–dual card.
What changes without convexity? Each Newton step uses the Hessian of the Lagrangian. If that Hessian curves down somewhere, which convexity rules out, the step may head for a maximum or a saddle. IPOPT therefore needs a sparse linear solver that reports the matrix's inertia, meaning how many positive and negative eigenvalues it has. MA27, MA57, MUMPS and PARDISO can do this. Ipopt docs The solver uses that count to spot bad curvature and correct it before stepping. The answer is still a local solution, so IPOPT also needs a sensible start.
SQP
Interior point (IPOPT)
Each step solves
a QP model
a Newton system for the barrier problem
Inequalities
linearized; the QP picks which are active
a log barrier keeps x strictly inside
Progress test
merit function or filter
filter line search
Result
a local solution
a local solution
5. Nonlinear least squares and Gauss–Newton
Most robot estimation is fitting: choose parameters so that predictions match measurements. In pose-graph SLAM you choose robot poses so that odometry and loop closures agree. In bundle adjustment you refine camera poses and 3-D points so that their projections land on the measured pixels. In calibration you choose camera intrinsics, lidar-to-camera mounting or IMU biases. All of these are the same problem, and rotations sit inside the residuals, which makes them nonconvex.
The common form is nonlinear least squares. Each residual ri(x) is a prediction minus a measurement. The Jacobian J = ∂r/∂x stacks the residual gradients as rows. Global minimization is intractable in general, so solvers settle for a local minimum. Ceres Solver docs
minimize F(x) = ½ Σ ri(x)2 = ½‖r(x)‖22
Gauss–Newton pretends every residual is linear near the current x: r(x + δ) ≈ r(x) + Jδ. Then F becomes a convex quadratic in δ, an ordinary linear least-squares problem. Its solution comes from the normal equations:
(JTJ) δ = −JTr, then x ← x + δ
Compare Newton (Day 11). The gradient of F is JTr, and its Hessian is JTJ + Σ ri∇2ri. Gauss–Newton drops the second term. It never needs second derivatives, and JTJ ⪰ 0 always. The dropped term is small when the residuals are small, so near a good fit the method is fast: quadratic convergence if the fit is exact, linear otherwise. Wikipedia: Gauss–Newton
Now real numbers. Nine measurements were taken at t = 0, 0.5, …, 4: y = 4.86, 4.05, 3.08, 2.57, 2.17, 2.02, 1.47, 0.96, 0.91 (made as 5e−0.4t plus a little noise). Fit the model y = a·ebt. The residual is ri = a·ebti − yi, and row i of J is [ebti, a·tiebti].
Start at (a, b) = (1, 0). Every prediction is 1, so F = 16.82. The rows of J are [1, ti], which gives JTJ = [[9, 18], [18, 51]] and JTr = (−13.09, −11.76). Solving gives δ = (3.377, −0.961), so the new point is (4.377, −0.961) with F = 7.09. One step cut the cost by more than half.
Keep going and something odd happens: F goes 16.8 → 7.09 → 62.9 → 6.16 → 0.359 → 0.0773 → 0.0761. Step 2 made the fit nearly 9 times worse. The linear model was trusted too far, where the exponential bends hard. The method recovers and converges in 6 steps to a = 4.86548, b = −0.40969, with F = 0.07607 (RMS residual 0.13). From the start (1, −3) it is worse: the first step jumps to b ≈ 31.9, where e31.9·4 is astronomically large, and F ≈ 7.5×10¹¹¹. Ceres's documentation warns that the plain iteration may not converge. Ceres Solver docs
6. Levenberg–Marquardt: Gauss–Newton on a leash
Think of walking a dog. When it walks nicely you give it a long leash. After it bolts into the road you shorten the leash. Levenberg–Marquardt (LM) puts Gauss–Newton on a leash by adding a penalty on the step length.
(JTJ + λI) δ = −JTr
The damping parameter λ is the leash. With λ = 0 you get the Gauss–Newton step. With a large λ the equation becomes δ ≈ −JTr / λ, a short step straight downhill, as in gradient descent (Day 6). Any λ > 0 gives a direction that goes downhill. Madsen et al. 2004 (This λ is LM's traditional name. It has nothing to do with the multipliers of Section 2.)
Here are the first steps from (1, 0) for four values of λ:
λ
step δ = (Δa, Δb)
step length
new F
0 (Gauss–Newton)
(3.377, −0.961)
3.51
7.09
1
(2.393, −0.602)
2.47
5.94
10
(0.703, −0.015)
0.70
9.84
100
(0.109, 0.065)
0.13
14.86
As λ grows, the step shrinks and turns toward steepest descent. Here λ = 1 beats plain Gauss–Newton (5.94 against 7.09), and λ = 100 barely moves.
The first step from (1, 0) in the (a, b) plane, drawn to scale. Gauss–Newton overshoots the optimum's b = −0.41 and lands at b = −0.96. A larger λ shortens the step and bends it toward steepest descent. Computed for this lesson.
A fixed λ is a poor compromise, so LM adjusts it as it goes. The simplest rule, used in the widget below: try the step. If F drops, accept it and divide λ by 10. If not, reject it and multiply λ by 10. Careful solvers instead compare the actual decrease with the decrease the linear model predicted. That ratio is the gain ratio ρ:
ρ near 1 means the model was right (loosen the leash); a small or negative ρ means it was wrong (tighten it). Marquardt's rule doubles λ when ρ < 0.25 and divides it by 3 when ρ > 0.75. Madsen et al. 2004 Seen this way, LM is a trust region method in disguise: a large λ means a small region where you trust the model. Ceres writes it with an explicit radius that it doubles or halves. It also scales the penalty with D = √diag(JTJ), so the units of a and b do not matter. Ceres Solver docs
Adaptive LM pays off on our data. From (1, 0) with λ₀ = 1, F goes 16.8 → 5.94 → 2.53 → 0.144 → 0.0762 → 0.0761: 5 steps, every one downhill. From (1, −3), where Gauss–Newton blew up, it converges in 6 iterations with one rejected step. A fixed leash is slow if it is short: λ = 10 needs 54 steps, and λ = 100 has still not converged after 200 (F = 0.0885).
lam = 1.0
for k in range(200):
r, J = residuals(x), jacobian(x)
d = solve(J.T @ J + lam * I, -J.T @ r)
if F(x + d) < F(x): # model was good enough
x, lam = x + d, lam / 10 # accept, loosen the leash
else:
lam = lam * 10 # reject, tighten the leash
if converged(x): break
Robot-scale problems run the same loop with a huge, sparse J. In bundle adjustment JTJ splits into camera and point blocks, and Ceres uses the Schur complement trick: it eliminates the points, solves a much smaller system for the cameras, then recovers the points. Ceres Solver docs See the Gauss–Newton and LM card.
Try it: with the defaults (Gauss–Newton from (1, 0)), press Step six times and watch the curve and the cost. Then pick "LM, adaptive λ" and do the same. Finally choose the start (1, −3) and compare the two methods again.
Notice: by default (Gauss–Newton from (1, 0)) the log reads 16.8 → 7.09 → 62.9 → 6.16 → 0.359 → 0.0773 → 0.0761. The cost jumps up at step 2, and the run still converges in 6 steps, ending at a = 4.8655, b = −0.4097. Switch to adaptive LM and it takes 5 steps, all downhill. From (1, −3), Gauss–Newton diverges at step 1, while adaptive LM converges in 6 (5 accepted, 1 rejected).
7. Where convexity still helps
You cannot flatten the mountains, but convex tools still give you a good place to start, a reliable map of the valley floor around you, and sometimes an altimeter that proves nothing is lower. Boyd and Vandenberghe list the same roles: convex starting points, convex heuristics, and bounds from relaxations and duality. Boyd & Vandenberghe 2004 §1.4
1. Good starting points. Take logs of the model: ln y = ln a + bt. This is linear in (ln a, b), so fitting it is ordinary least squares, a convex problem with a closed-form answer. It gives a = 4.9644, b = −0.4247 and F = 0.0851. One Gauss–Newton step from there reaches 0.07607, against 6 steps and a scary detour from (1, 0). Try the "log-linear fit" start in the widget. SLAM solvers also start from a carefully built guess: the Gauss–Newton baseline in the SE-Sync paper uses the "chordal initialization". SE-Sync, arXiv v2
2. Convex subproblems. SQP solves a QP at each step, and Gauss–Newton solves a linear least-squares problem. Sequential convex programming (SCP) generalizes the idea. At x(k) it replaces the problem by a convex approximation and solves it inside a trust region:
T(k) = { x : |xi − xi(k)| ≤ ρi }
In the Stanford EE364b version, a step is accepted if the true decrease is at least 10% of the predicted one. Then ρ grows by a factor 1.1; otherwise it halves. The same slides note that this kind of method, for least squares, is often called Gauss–Newton, and some variants Levenberg–Marquardt. Stanford EE364bDay 18 builds trajectory optimization on SCP (SCP card).
3. Lower bounds. The Lagrange dual of any problem, convex or not, is a convex problem whose value is a lower bound (Day 9). EE364b runs SCP from 10 starts on a nonconvex QP with 20 variables. The runs end between about −60 and −50, and the dual bound is about −66.5. So the best run is provably within about 6.5 (roughly 10%) of the true optimum. (These values are read off the slides' plot, so they are approximate.) Multi-start alone never gives such a guarantee. Stanford EE364b
4. Certifiable SLAM. Pose-graph SLAM looks for rotations Ri and translations ti that best explain noisy relative measurements R̃ij and t̃ij, each with a weight κij or τij. The maximum-likelihood problem is:
minimize Σ κij‖Rj − RiR̃ij‖F2 + τij‖tj − ti − Rit̃ij‖2 over ti ∈ ℝd, Ri ∈ SO(d)
The set of rotations SO(d) is not convex, so the problem is not either, and Gauss–Newton is the de facto standard solver for it. SE-Sync eliminates the translations and solves an SDP relaxation instead: minimize tr(Q̃Z) subject to Z ⪰ 0 with every diagonal block of Z equal to the identity. Every true set of rotations is feasible, so the SDP value is a lower bound. Below a noise threshold the relaxation is an exact relaxation: its solution gives the global optimum. You can also check this after solving, which makes SE-Sync a certifiably correct algorithm. SE-Sync, arXiv v2
Dataset
Poses
Gauss–Newton
SE-Sync
Speed-up
garage
1,661
17.81 s
5.33 s
3.3×
cubicle
5,750
136.86 s
13.08 s
10.5×
rim
10,195
575.42 s
36.66 s
15.7×
On all six benchmarks in the paper's Table 1, both methods reached the same objective value, but only SE-Sync came with a proof: its certified suboptimality was at most 5.6×10⁻¹¹. In simulations the relaxation stayed exact up to about 15° RMS rotation noise, roughly 10 times typical sensor noise. The limits are real: the model assumes no outliers, and it covers pose graphs only, not bundle adjustment. SE-Sync, arXiv v2 Read the SE-Sync paper review.
Explain it to a 10-year-old
You are looking for the lowest spot in a bumpy playground at night. Your flashlight only shows the ground at your feet. You can always walk downhill until you stop in a dip, but it might be a small dip and not the deepest one. So friends start in different places, and you compare. Gauss–Newton guesses the shape of the ground and jumps to the bottom of the guess. Levenberg–Marquardt takes smaller jumps after a guess turns out wrong.
Common misunderstandings
"The solver converged, so it found the best answer." Converged means a stationary or KKT point. On the circle, (1, 1) passes the KKT test and is the maximum. The double well's x ≈ 1.347 is a local minimum 2.83 above the global one.
"Gauss–Newton always goes downhill." On the widget's data, F jumps from 7.09 to 62.9 at step 2, and from (1, −3) the method diverges. Use LM, a trust region or a line search.
"Crank λ up to be safe." Damping trades speed for caution: a fixed λ = 100 had not converged after 200 iterations, while adaptive LM needed 5.
"Every optimum satisfies KKT." Only under a constraint qualification. For minimize x subject to x2 ≤ 0, the optimum x = 0 is not a KKT point.
"Nonconvex means convex tools are useless." Convex starting points, convex subproblems (SQP, SCP, each Gauss–Newton step) and SDP relaxations such as SE-Sync's are the standard toolkit.
Going deeper (optional): the fine print
Second-order conditions. Precisely, sᵀ∇2xxL s ≥ 0 is necessary and > 0 is sufficient for s in the "critical cone". These are directions tangent to the equality constraints and to the active inequalities with positive multipliers. Degenerate cases need higher-order terms. Wikipedia: KKT
Other constraint qualifications. Weaker ones than LICQ, such as MFCQ, also make KKT necessary. Slater's condition (Day 10) plays this role for convex problems.
SQP's speed. Near a solution where LICQ and the second-order condition hold, the Newton-on-KKT view gives quadratic convergence. With BFGS Hessians it is superlinear.
The IPOPT facts come from its home page. How it corrects bad curvature is in the Wächter–Biegler paper the home page cites, which was not opened, just as no Nocedal and Wright page was.
Check yourself
Q1. A solver reports ∇f(x) = 0 on a nonconvex function. What can you conclude?
Zero gradient only means flat. The double well's hilltop at x ≈ 0.126 and the saddle of x² − y² both have ∇f = 0. You need the Hessian to say more, and even a local minimum need not be global.
Q2. Minimize x₁ + x₂ subject to x₁² + x₂² = 2. Which KKT point is the minimum?
Both (−1, −1) and (1, 1) are KKT points, which is exactly the trap. The second-order check separates them: ∇²L = 2νI is I at (−1, −1) (minimum, f = −2) and −I at (1, 1) (maximum, f = 2). The point (0, √2) fails stationarity.
Q3. What does SQP solve at each iteration?
SQP replaces the problem near xk by a QP and steps to its solution. With equality constraints only, this is Newton's method on the KKT equations, which is why the circle example's constraint error went 10⁻³ → 10⁻⁷ → 10⁻¹³.
Q4. Gauss–Newton approximates the Hessian of F = ½‖r(x)‖² by …
The exact Hessian is JᵀJ + Σ rᵢ∇²rᵢ. Gauss–Newton keeps only JᵀJ, which needs no second derivatives and is always ⪰ 0. JJᵀ has the wrong size: it is m × m (residuals), not n × n (parameters).
Q5. In adaptive LM, a trial step makes F larger (the gain ratio ρ is negative). What should happen?
A negative ρ means the linear model promised a decrease that did not happen. So LM stays put and tightens the leash: a larger λ gives a shorter step, closer to steepest descent. From (1, −3) the widget's adaptive LM rejects one step this way and still converges in 6 iterations.
Q6. What does SE-Sync's certificate tell you when it succeeds?
If the rounded solution attains the SDP's lower bound, nothing can be better, so it is the global optimum. The relaxation is exact only below a noise threshold. Above it, SE-Sync still returns an estimate and a bound, but no certificate.
Recap: things to remember
Without convexity, zero gradient means a minimum, a maximum or a saddle. Local solvers find a nearby valley, and the start decides which one. Multi-start raises the odds but proves nothing.
NLP KKT conditions are necessary only under a constraint qualification such as LICQ, and they are not sufficient. Check that the Lagrangian curves up along the constraints.
SQP solves a QP model at every step (Newton on KKT). IPOPT applies Day 12's barrier idea to nonconvex problems and returns a local solution.
Gauss–Newton solves (JᵀJ)δ = −Jᵀr and can overshoot or diverge. LM adds λI as a leash: it rejects bad steps, raises λ, and lowers it again when the model behaves.
Convexity still helps through convex starting points, convex subproblems (SQP, SCP) and relaxations that can certify a global answer (SE-Sync).
All worked numbers (double well, circle SQP, curve fit, LM runs) were recomputed in Node.js for this lesson on 2026-10-26. The NLP theory is standard and rests on sources 1, 6 and 7. Nocedal and Wright's Numerical Optimization was not opened.
Week 3 · Day 17
Model predictive control as a QP
After today you can write a vehicle MPC problem as a quadratic program, explain the receding-horizon loop, and reason about horizon length, weights, constraints and warm starts in a real-time controller.
About 60 min · Needs Days 5, 10 and 12 · No CO4A chapter (this day is new)
Today's big idea
Model predictive control steers by optimising. Ten times a second the car plans its next two seconds, applies only the first input, measures where it is, and plans again. With a linear model, a quadratic cost and linear limits, each plan is a convex QP like those of Day 5, solvable in milliseconds because every tick's problem is almost the same.
1. Plan, act a little, re-plan
Picture driving on a dark road. Your headlights show the next stretch. You plan a path through what you can see, but you only turn the wheel for this instant. A moment later the beams reach further, and you adjust.
That is model predictive control (MPC): control by repeatedly solving a short optimal-control problem and applying only its first input. The plan looks N steps ahead. N is the horizon, covering N·dt seconds for a time step dt. The window slides forward one step every tick, so this is a receding horizon.
Three ticks of the widget below at its defaults (N = 20; the first 8 inputs are drawn). Only the solid bar reaches the car. Even with a perfect model the new plan (2.00, 2.00, 1.61) differs from the old one shifted (2.00, 1.93, 1.54), because the window now reaches 0.1 s further.
One tick solves the problem below. xk is the predicted state k steps ahead, uk the input, xr the target and x̄ the state measured right now. OSQP docs: MPC
minimize Σk (xk − xr)TQ(xk − xr) + ukTRuk
subject to xk+1 = Axk + Buk, x0 = x̄
umin ≤ uk ≤ umax, xmin ≤ xk ≤ xmax
The weight matrices Q and R price being off target and using input. The term inside the sum is the stage cost, paid at every step. Many formulations add a terminal cost, an extra penalty with its own weight QN on the last predicted state. Then: apply u0*, wait one tick, measure x̄, solve again.
In numbers: in the widget below, a car wants the lane 3.5 m to its left. At t = 0 its 2-second plan is u = 2.00, 2.00, 1.93, 1.54, 1.20, … m/s², and only the first 2.00 is used. At t = 0.5 s the fresh plan starts with 1.17. At t = 1.5 s it starts with −0.29, already braking the sideways motion. Feedback comes from re-solving, not from following the old plan.
Analogy
A chess player thinks five moves ahead but plays only one. After the opponent replies, the old plan is thrown away and a new one is worked out from the new position. Looking ahead makes the move good; re-planning makes the player hard to surprise.
2. The car, sideways: a double integrator
Think of a shopping cart on ice. Push it sideways and its sideways speed changes. That speed, in turn, changes where it is. With no friction, nothing else happens.
That chain is a double integrator: the input is an acceleration, which integrates once to a velocity and again to a position. In a lane change at constant forward speed, the car's lateral error y behaves almost exactly like this. Lateral error is the sideways distance from a reference line, here the start-lane centre. The input u is lateral acceleration in m/s², and v is lateral speed.
Top: the widget's lane change, from the start lane to the target lane 3.5 m to the left. Bottom: the model, where u integrates to v and v integrates to y. Lane width, speeds and limits on this page are illustrative.
A computer holds u constant during each tick of length dt. This is a zero-order hold, and with it the one-tick update is exact:
yk+1 = yk + dt·vk + ½dt²·uk
vk+1 = vk + dt·uk
So x = (y, v), A = [[1, dt], [0, 1]] and B = [½dt², dt]T. With dt = 0.1 s, B = [0.005, 0.1]T. From rest, one tick at u = 2 m/s² gives y1 = 0.010 m and v1 = 0.20 m/s. Pushing at the full 2 m/s² and then braking at the full 2 m/s², a 3.5 m move from rest to rest takes 2·√(3.5/2) ≈ 2.65 s. The widget's MPC takes 4.4 s, because it also pays for effort.
What does this mean at the steering wheel? The kinematic bicycle model treats the car as one front and one rear wheel and ignores tyre forces. On a straight road and for small angles it gives u ≈ (V²/L)·δ, with forward speed V, wheelbase L and road-wheel angle δ. At V = 25 m/s and L = 2.7 m, |u| ≤ 2 m/s² means |δ| ≤ 0.0086 rad, about 0.5°. These numbers (25 m/s, 2.7 m, 2 m/s², 3.5 m lanes) are illustrative, not comfort or road-design standards.
Going deeper (optional): where the double integrator comes from
Track a path of curvature κ with lateral error ey and heading error eψ. For small angles the kinematic bicycle gives ėy ≈ V·eψ and ėψ ≈ (V/L)·δ − V·κ. Differentiate the first and substitute the second:
ëy ≈ (V²/L)·δ − V²·κ
At constant V this is a double integrator with input u = (V²/L)·δ − V²·κ, a standard small-angle derivation written for this lesson. Kong et al. compared kinematic and dynamic bicycle models on experimental data. Their abstract argues that kinematic-model MPC costs less computation and works at low speed, where tyre models become singular. Kong 2015
3. What the controller wants: cost and constraints
Give the planner three wishes: be in the target lane, arrive without still drifting sideways, and push gently. They conflict, because arriving fast needs hard pushes, so weights decide the trade. The widget's cost has target yref = 3.5 m and weights qy, qv and r:
J = Σk=1…N [qy(yk − yref)² + qvvk²]
+ Σk=0…N−1 r·uk²
Each term squares something linear in the inputs, so J is a convex quadratic. With all weights at 1, being 1 m off the lane costs as much as moving sideways at 1 m/s, or pushing at 1 m/s² for one tick. The widget uses no terminal cost.
Constraints are the hard rules. The three common kinds are all linear, so the problem stays a QP:
Input bounds |uk| ≤ umax limit how hard the car may push (here 2 m/s²).
Rate bounds |uk − uk−1| ≤ Δmax limit how fast the push may change; u−1 is last tick's input. With an illustrative Δmax = 0.3 m/s² per tick, ramping from 0 to 2 m/s² takes at least 7 ticks.
State bounds xmin ≤ xk ≤ xmax keep the car on the road, −1.75 m ≤ yk ≤ 5.25 m for our two lanes, or cap its lateral speed.
When each variable has its own lower and upper limit and nothing more, that is a box constraint. A variable sitting on its bound is in saturation. The widget keeps only the input box, which a few lines of browser code can solve exactly.
Try it: press Play to watch the car re-plan every tick; the orange dots are its current plan. Then try N = 5, qv = 0 or r = 0.1, and watch the arrival time, the overshoot and the solver iterations. Reset restores the defaults.
Notice: at the defaults (N = 20, qy = qv = r = 1, umax = 2 m/s²) the car reaches the target lane at 4.4 s, about 110 m of road at 25 m/s, and overshoots by only 2.6 cm. Its peak |u| is 2.00 m/s², on the bound for the first 3 ticks. Of each 20-input plan, only the first input is applied.
The sliders teach three lessons. First, a short horizon is not "more aggressive". At N = 5 (0.5 s of look-ahead) the car is timid: it peaks at 0.40 m/s² and reaches the lane only at 9.3 s. Within half a second a push buys a few centimetres but costs effort at once. Arrival takes 5.6 s at N = 10, 4.7 s at 15, 4.4 s at 20 and 4.3 s at 30 or 40, so past about 20 steps a longer horizon buys little.
Second, the speed weight qv makes the car brake its sideways motion before it arrives. With qv = 0 and N = 5 the car overshoots by 2.91 m, nearly a full lane, and has not settled after 15 s. With N = 20 the overshoot shrinks to 0.32 m, because the planner sees it coming. Third, the bound shapes the motion. At umax = 4 it never touches (peak 2.70 m/s², still 4.4 s); at 0.5 the car saturates for 20 ticks and arrives at 5.5 s.
4. Two ways to hand the QP to a solver
Picture a spreadsheet with one row per time step, each row depending only on the row above. You can keep every row as an unknown and add rules linking neighbours. Or, as with dominoes, you can note that the pushes decide every row, and write each row directly in terms of the pushes.
The first is the sparse formulation: states and inputs are all variables, and the dynamics are equality constraints. The second is the condensed formulation: eliminate the states and keep a small, dense QP in the inputs only.
The same problem twice, drawn for N = 4. Left: the sparse equality matrix is a thin staircase of nonzeros. Right: the condensed Hessian H is small but completely full.
OSQP, the ADMM solver from Day 13, takes QPs in the form below. Its own names for the constraint matrix and the upper bound, A and u, clash with ours, so here they are C and h. Stellato 2020
minimize ½zTPz + qTz
subject to l ≤ Cz ≤ h
For MPC, z = (x0, …, xN, u0, …, uN−1), and P holds Q, QN and R in diagonal blocks. The rows of C encode x0 = x̄ (with l = h = x̄), the dynamics xk+1 − Axk − Buk = 0 (with l = h = 0), and the bounds (an identity block, with l and h holding the limits). OSQP docs: MPC
Between ticks only x̄ changes, and it appears only in l and h. P and C never change, so one matrix factorization from start-up serves every tick. This is factorization caching, and it is why the sparse form suits OSQP. OSQP factors with a sparse direct solver, and the staircase has only a few nonzeros per row however long the horizon. For our car (nx = 2, nu = 1) the sparse QP has nx(N+1) + nu·N variables and nx(N+1) equality rows: 17 and 12 at N = 5, 62 and 42 at N = 20, 122 and 82 at N = 40. Stellato 2020, App. A.3
The condensed form writes the stacked states X = (x1, …, xN) in terms of the inputs U = (u0, …, uN−1):
X = Φx̄ + ΓU
Φ stacks A, A², …, AN. Γ is lower-triangular, because input j moves state k > j through Ak−1−jB. Substituting into J leaves a QP in U alone, where Q̄ and R̄ repeat Q and R down the diagonal:
J(U) = ½UTHU + fTU + const
H = 2(ΓTQ̄Γ + R̄)
f = 2ΓTQ̄(Φx̄ − Xref)
Only f changes each tick. Input bounds stay a box on U, but state bounds become xmin ≤ Φx̄ + ΓU ≤ xmax, with dense rows. At N = 20 that is 20 variables and a dense 20 × 20 H, which is what the widget solves.
Which wins? Condensing has quadratic complexity in the horizon length. Verschueren 2021, §2.7 Interior-point solvers that keep the stage structure (FORCES, HPMPC, HPIPM) avoid this. Liniger et al. report FORCES solve times growing linearly with the horizon, which let them use 40 steps. Liniger 2015 As a rough guide, condensing suits short horizons with few inputs, and the sparse form suits long ones. Partial condensing sits between: it condenses blocks of stages into a shorter, denser horizon. acados' chain-of-masses benchmark used a partially condensed horizon of 5. Verschueren 2021, Table 3
In practice a modelling tool such as CVXPY builds the sparse form and hands it to OSQP. This sketch is the widget's problem at its defaults:
import cvxpy as cp, numpy as np
dt, N, u_max, y_ref = 0.1, 20, 2.0, 3.5
A = np.array([[1, dt], [0, 1]]); B = np.array([0.5*dt**2, dt])
x, u = cp.Variable((2, N+1)), cp.Variable(N) # states (y, v), inputs
x0 = cp.Parameter(2) # measured state: changes every tick
cost, cons = 0, [x[:, 0] == x0]
for k in range(N):
cons += [x[:, k+1] == A @ x[:, k] + B * u[k], cp.abs(u[k]) <= u_max]
cost += cp.square(x[0, k+1] - y_ref) + cp.square(x[1, k+1]) + cp.square(u[k])
mpc = cp.Problem(cp.Minimize(cost), cons)
x0.value = np.zeros(2) # every tick: measure, solve, apply u[0]
mpc.solve(solver=cp.OSQP, warm_start=True)
print(u.value[:4].round(2)) # about [2. 2. 1.93 1.54]
5. A two-step example you can check by hand
Suppose your first push is capped. The car moves less than planned, so a good planner pushes a little harder on the next step. Clipping the unconstrained answer never does this, because it changes one input without telling the others.
Take the smallest case: N = 2, dt = 1 s for round numbers, qy = 1, qv = 0, r = 1, target 3.5 m, start at rest. Then y1 = 0.5u0 and y2 = 1.5u0 + 0.5u1, so:
J = (0.5u0 − 3.5)² + (1.5u0 + 0.5u1 − 3.5)²
+ u0² + u1²
H = [[7, 1.5], [1.5, 2.5]], f = (−14, −3.5)
H has eigenvalues 2.05 and 7.45, so J is a strictly convex bowl. The limit |u0|, |u1| ≤ 1.5 is a square box.
The bowl's centre (blue) lies outside the box. Clipping slides it straight left onto the fence (pink), but the cheapest feasible point is higher up the same fence (green), where a contour just touches the box.
No limits. Solving HU = −f gives U = (1.951, 0.230) and J = 10.44, but u0 breaks the limit.
Clip it. U = (1.5, 0.230) and J = 11.15: feasible, not optimal.
Solve the QP. With u0 at 1.5, J is a parabola in u1 with its minimum at 0.5, so U = (1.5, 0.5) and J = 11.06.
The true answer raises the second input from 0.23 to 0.5, the "make up for it" move. It predicts y1 = 0.75 m and y2 = 2.50 m.
To confirm it, check the KKT conditions of Day 10. At (1.5, 0.5) the gradient HU + f is (−2.75, 0). The free input u1 has zero gradient. The saturated u0 has a negative gradient: the cost wants it larger, but it sits on its upper bound with multiplier λ = 2.75 ≥ 0, the price of the fence. At the clipped point the gradient is (−3.16, −0.68), and the free u1 still has a nonzero gradient, so KKT fails. With 20 or 40 coupled inputs and state bounds there is no clipping shortcut, which is why MPC needs a real QP solver.
6. How solvers find the plan
The simplest method that respects a box walks downhill, and stops at the fence when a step would cross it. That is projected gradient: a gradient step, then projection onto the feasible set, which for a box just clips each entry. It is the proximal gradient of Day 8 with the box as the constraint.
U ← clip(U − (HU + f)/L, −umax, umax)
L = λmax(H) is the steepest curvature, which makes 1/L a safe step. In the two-step example L = 7.454. From U = 0 one step lands at (1.88, 0.47), clipped to (1.5, 0.47), already close to (1.5, 0.5). The widget runs this rule every tick.
The number of steps depends on the condition number κ = λmax/λmin, the ratio of steepest to flattest curvature (Day 6). At the widget defaults L = 8.14 and λmin ≈ 2.0, so κ ≈ 4 and the first solve takes 33 iterations. With r = 0.1, κ ≈ 31 and it takes 213. Why? The last planned input acts for one tick at the very end and barely moves the car. In that direction only its own r·u² term curves the cost, so λmin ≈ 2r. At N = 40, L rises to 58 and κ to about 29, and the first solve takes 203 iterations.
OSQP uses ADMM, the Day 13 splitting method that alternates simple sub-steps (ADMM card, OSQP paper). Each iteration solves one linear system with a fixed matrix, clips its estimate of Cz into [l, h], and updates the multipliers. The matrix is factored once, and after that no iteration divides. Stellato 2020 OSQP also detects infeasible problems and returns a certificate, which matters when a state bound can no longer be met. As of Oct 2026 its documented defaults are ρ = 0.1, σ = 10⁻⁶, α = 1.6, εabs = εrel = 10⁻³, at most 4,000 iterations, warm starting on and polishing off. OSQP docs 2026
Interior-point methods (Day 12, primal-dual card) take Newton steps on smoothed KKT conditions and need a few tens of iterations almost regardless of size. Boyd & Vandenberghe 2004 Each iteration factors a new matrix, but in MPC that matrix is banded in time. FORCES, HPMPC and HPIPM exploit this, so the work grows only linearly with N. Verschueren 2021 Their weak spot is that interior-point methods are not easily warm started. Stellato 2020
All of them stop on KKT residuals, not on looks. OSQP checks the primal residual ‖Cz − w‖∞, which asks whether the constraints hold (w is its clipped estimate of Cz). It also checks the dual residual ‖Pz + q + CTy‖∞, which asks whether the multipliers y balance the gradient. Both must fall below εabs plus εrel times the size of the terms. Stellato 2020, §3.4 Liniger et al. stopped FORCES at residuals of 10⁻⁵ and a duality gap of 10⁻⁴. Liniger 2015 The widget stops when no input moves more than 10⁻⁵, which is a KKT test too: a projected-gradient step leaves U unchanged exactly at a KKT point. From (1.5, 0.5) the step pushes u0 to 1.87, the clip returns it to 1.5, and u1 stays put.
7. Real time: warm starts, real-time iteration, honest timings
Consecutive MPC problems are nearly identical, so the last plan shifted by one step is a good first guess. It is like re-planning a road trip after an hour of driving: you drop the first hour of the old plan instead of starting over. A warm start starts the solver from the previous solution. The usual shift repeats the last input:
Ustart = (u1*, u2*, …, uN−1*, uN−1*)
In the widget, over the first 8 s (80 ticks), warm starting cuts iterations from 1,821 to 1,392 at N = 20 (24%) and from 9,365 to 3,365 at N = 40 (64%). At N = 5 it saves nothing (401 against 390), because each solve is only a handful of iterations. OSQP warm starts its primal and dual iterates together. In the OSQP paper's MPC tests (20 to 80 states, horizon 10), warm start plus caching made solves 2.6 to 4 times faster: 7 ms became 2 ms at 20 states. Yet at 40 to 80 states the iterations barely moved (32 to 31.75 at 80), so the gain came mainly from reusing the factorization. Stellato 2020, Table 7
Real cars are not double integrators. Large steering angles break the small-angle model, and near the grip limit the tyres matter. The dynamics xk+1 = f(xk, uk) are then nonlinear, and each problem is a nonconvex NLP (Day 16). Fast controllers linearise around the shifted previous plan (x̂k, ûk) and solve one QP:
xk+1 ≈ f(x̂k, ûk) + Ak(xk − x̂k)
+ Bk(uk − ûk)
acados calls this the real-time iteration (RTI): one SQP-type iteration, so one QP, per sample (SQP card). Verschueren 2021, §2.8 Liniger et al.'s contouring controller raced 1:43-scale cars this way. Every 20 ms it linearised a bicycle model with tyre forces around the shifted last trajectory, "the basic version of the real-time iterations". Liniger 2015Day 18 turns this loop into sequential convex programming.
Question
Linear MPC (today)
Nonlinear MPC (preview of Day 18)
Model
xk+1 = Axk + Buk, fixed A and B
xk+1 = f(xk, uk), e.g. a bicycle model with tyres
Each tick solves
one convex QP, to tolerance
a nonconvex NLP, often just one QP of it (RTI)
What you get
the best plan for the model
an improvement around the last plan
Fits
lane keeping and lane changes at steady speed
racing, large steering angles, the grip limit
Fast enough means finished before the next tick, every tick. OSQP, FORCES and acados offer code generation: they emit problem-specific C code for the embedded target. OSQP's generated code needs no dynamic memory, no libraries and no divisions. OSQP docs: codegen Below are published timings. They are different problems on different hardware, so read each row alone and do not rank them.
17.4 iterations per tick on average warm, 22.8 cold (first 8 s)
computed here
Two lessons hide in the table. The worst case matters more than the mean. Liniger's contouring controller averaged 15 ms against a 20 ms tick but peaked at 21 ms, and it missed the deadline in 4.4% of samples, "(soft) real-time" in the authors' words. It still lapped faster: 8.9 to 9.2 s, against 9.5 to 9.8 s for the tracking controller. Liniger 2015 And a laptop is not a car computer: acados' engine controller ran about 3 times slower on the 900 MHz automotive box than on a 2.5 GHz Core i7. Verschueren 2021, §5.3
Explain it to a 10-year-old
Walk across a playground towards a friend. You think "ten steps that way", but you only take one. Then you look again, because a ball might have rolled in front of you, and you think of ten new steps. A self-driving car does this ten times a second. Its computer picks the steps by finding the cheapest plan that obeys rules like "don't turn too hard".
Common misunderstandings
"The car follows its plan." Only u0 is applied; the rest is a forecast, re-optimised next tick.
"Clip the unconstrained solution and you have the constrained one." In the two-step example clipping gives J = 11.15; the true optimum (1.5, 0.5) gives 11.06. Clipping ignores how the inputs are coupled.
"A shorter horizon is more aggressive." At N = 5 the car is timid (peak 0.40 m/s², 9.3 s to the lane). Without a speed weight, N = 5 overshoots by 2.91 m instead. Short horizons are myopic, not bold.
"This solver takes 2 ms." A timing means nothing without the problem size and hardware. OSQP's 2 ms on a Xeon with 20 states and Liniger's 15 ms on a phone-class ARM chip with N = 40 cannot be compared.
"Warm starting always cuts iterations." In the widget it saves 24% at N = 20 and nothing at N = 5. In OSQP's MPC runs with 40 to 80 states, iterations barely changed; the speed-up came from factorization caching.
Check yourself
Q1. In receding-horizon MPC, what is sent to the actuator at each tick?
Only u0* is applied; then the state is measured and the problem is solved again. Running the whole plan open loop throws away the feedback that makes MPC robust.
Q2. The lateral double integrator has nx = 2 and nu = 1. With N = 20, how many decision variables does the condensed QP have?
Condensing eliminates the states and keeps only the inputs: N·nu = 20. 62 is the sparse count, nx(N+1) + nu·N, and 42 is the number of sparse equality rows.
Q3. In the sparse OSQP formulation, what changes between two consecutive MPC solves?
x̄ enters only the bounds of the initial-state rows. P and the constraint matrix stay fixed, so their factorization is computed once and reused: factorization caching.
Q4. Two-step example: the unconstrained optimum is (1.95, 0.23) and the limit is |u| ≤ 1.5. What is the constrained optimum?
With u0 stuck at 1.5, the second input should push harder to make up: J = 11.06 at (1.5, 0.5) against 11.15 for the clipped point. The gradient (−2.75, 0) with multiplier 2.75 ≥ 0 confirms KKT.
Q5. Lowering the effort weight r from 1 to 0.1 makes the widget's first solve take 213 iterations instead of 33. Why?
λmin(H) ≈ 2r, because the last input barely moves the car. Smaller r flattens the valley, κ rises, and gradient steps crawl. The cost stays convex and the box is unchanged.
Q6. Liniger et al.'s contouring MPC (N = 40) ran on a 1.6 GHz ARM Cortex-A15 with a 20 ms tick. What did its QP take?
Mean 15.03 ms, max 21.16 ms; the controller missed the deadline in 4.4% of samples. The last option is the tempting one: the mean fits the tick, but the worst case did not.
Recap: things to remember
MPC plans N steps, applies the first input, measures, and plans again. Feedback comes from re-solving.
A linear model, a quadratic cost and linear bounds make each tick a convex QP. The lateral double integrator has A = [[1, dt], [0, 1]] and B = [½dt², dt]T.
The sparse form suits OSQP: only l and h change, so one factorization serves every tick. The condensed form is small and dense, and its input bounds stay a box.
Clipping is not optimal; KKT residuals define "solved". Conditioning, set by r and N, decides how many first-order iterations you need.
Real time means the worst case on the target hardware. Warm starts, factorization caching, code generation and RTI are the standard tools.
Convex Optimization, S. Boyd and L. Vandenberghe, Cambridge University Press 2004, Ch. 11 (accessed 2026-10-26).
Week 3 · Day 18
Trajectory optimization & SCP
After today you can turn a motion-planning problem into a finite optimisation by direct transcription, solve nonconvex trajectory problems with sequential convex programming (linearise, add a trust region, solve, repeat), and explain how lossless convexification makes rocket landing an exact convex problem.
About 60 min · Needs Days 16 and 17 · No CO4A chapter (new material)
Today's big idea
Planning a whole motion is a big nonconvex problem, because obstacles leave holes in the free space and the dynamics are curved. Sequential convex programming does not fight that head-on. It replaces the hard parts with convex stand-ins that are only trusted near the current guess, solves that convex problem fast, and repeats. In a few special cases, such as rocket landing, a clever reformulation is exactly convex, and one solve gives the true best answer.
1. Trajectory optimisation: MPC with a long horizon
Think of parallel parking. A good driver does not pick only the next steering angle. They picture the whole manoeuvre (back up, turn in, straighten out) and then follow it. A computer can plan the same way.
Trajectory optimisation chooses a whole time-indexed path of states and inputs at once: where the vehicle is at each moment, and what the controls do. On Day 17, MPC solved a short-horizon QP with a linear model. Trajectory optimisation is the same idea stretched out: a long horizon, often the whole manoeuvre, and the real nonlinear dynamics. A common split is that a trajectory optimiser plans the manoeuvre and a fast MPC loop tracks it.
There is a catch: a path holds infinitely many numbers, and a solver needs a finite list. Direct transcription fixes this, like planning a hike by pushing pins into a map. Chop time into K steps of length dt. Make the state xk and the input uk at every node an unknown. Then require each pin to be reachable from the previous one. Malyuta 2022
Direct transcription with K = 5 steps. The path becomes 6 states and 5 inputs, and the dynamics become 5 links that the solver must close. Until it does, the gap in each link is called the defect.
Here ℓ is the running cost (fuel, effort or time), F is the one-step model, and g collects the path rules, such as speed limits and obstacles. Each equation "next state minus predicted next state = 0" is a defect constraint.
F needs a rule for integrating the dynamics ẋ = f(x, u) across one step. Collocation is the family of such rules: describe the path between two nodes by a simple polynomial, and require it to obey the dynamics at chosen points. The simplest is the trapezoidal rule. The change over a step equals the average of the slopes at its two ends:
xk+1 − xk = (dt/2)·[f(xk, uk) + f(xk+1, uk)]
Here the input is held constant over the step (zero-order hold). GuSTO's experiments use exactly this rule with 30 to 40 nodes. Bonalli 2019
A worked example: a cart on a rail with position p and velocity v, so ṗ = v and v̇ = u. Start at rest, push with u = 2 m/s², and take dt = 0.1 s. Velocity: v1 = 0 + 0.05·(2 + 2) = 0.2 m/s. Position: p1 = 0 + 0.05·(0 + 0.2) = 0.010 m. The exact answer is ½·2·0.1² = 0.010 m: the trapezoid is exact here because velocity grows linearly. With 20 steps the problem has 21 × 2 states plus 20 inputs, which is 62 unknowns, tied together by 40 defect equations.
For a car, the kinematic bicycle model is ẋ = v cos θ, ẏ = v sin θ, θ̇ = (v/L) tan δ. Here θ is the heading, L the wheelbase and δ the steering angle. Those sines and cosines end up inside F, and that is where the trouble starts.
2. Why trajectory problems are not convex
Day 4 gave the test: a convex problem needs a convex feasible set, so every equality constraint must be affine. Trajectory problems usually break this in three ways. Malyuta 2022
Obstacles. Take a round obstacle with centre c = (5, 0.5) and radius r = 2. The points (2.5, 0.5) and (7.5, 0.5) are both 2.5 m from the centre, so both are free. Their midpoint is the centre itself. The free space has a hole, and a set with a hole is not convex.
Nonlinear dynamics. A defect constraint with sin θ inside describes a curved surface, not a flat one. Curved equality sets fail the midpoint test too. The points (1, 0) and (−1, 0) both satisfy ‖p‖ = 1, but their midpoint (0, 0) does not.
Nonconvex input limits. A rocket engine cannot throttle below a minimum thrust. With limits 4972 N ≤ ‖T‖ ≤ 13260 N, the thrusts (8000, 0) N and (−8000, 0) N are both allowed. Their midpoint is zero thrust, which is not. Blackmore 2010
Source of nonconvexity
Robot example
Today's fix
Obstacles (state constraints)
A car must stay outside a parked truck
SCP: replace the obstacle by a halfspace, re-drawn every iteration
Nonlinear dynamics
Bicycle model, quadrotor attitude
SCP: linearise around the last trajectory, inside a trust region
Nonconvex input limits
Minimum engine thrust
Lossless convexification: an exact convex reformulation
Day 16 handed such problems to general nonlinear solvers such as SQP. Today keeps a convex solver at the core instead, and there are two routes. Route one is lossless convexification, a reformulation that is exactly convex: rare, but one solve gives the global optimum. Route two is sequential convex programming: approximate, solve, repeat. Malyuta 2022
3. The SCP loop: linearise, fence, trust region, slack
Sequential convex programming (SCP) builds a convex model of the problem around the current guess, solves that model, moves to its answer, and repeats. The current guess is the reference trajectory, written with a bar: x̄, p̄. Four ingredients make the loop work. See the SCP card for the one-page version.
Ingredient 1: linearise the dynamics. A curve looks straight if you zoom in far enough. So near the reference, replace the one-step model by its tangent:
F(x, u) ≈ F(x̄, ū) + A(x − x̄) + B(u − ū)
A and B are the Jacobians of F at the reference, the same idea as Newton's method on Day 11. The defect constraints become linear equalities, which are convex. A quick check: around θ̄ = 0.5, sin θ ≈ 0.479 + 0.878(θ − 0.5). At θ = 0.6 that gives 0.567 against the true 0.565. At θ = 1.5 it gives 1.357 against 0.997, badly wrong. The model is only good near the reference.
Ingredient 2: turn the obstacle into a fence. Picture walking around a round pond. Instead of tracking the curved shore, you stand behind a straight fence placed at the point of the shore closest to you. The far side of a straight fence is a halfspace, and halfspaces are convex.
In symbols, the rule "waypoint pi stays outside the disk" is ‖pi − c‖ ≥ r. At the reference waypoint p̄i, take the unit vector pointing from the centre to it, and keep the waypoint on the far side of the tangent line:
ni = (p̄i − c) / ‖p̄i − c‖ niT(pi − c) ≥ r
Why is this safe? For any unit vector, nT(p − c) ≤ ‖p − c‖, so every point that obeys the fence is at least r from the centre. The fence is an inner (conservative) approximation: a convex set that sits inside the true free space. Worked example: c = (5, 0.5), r = 2, and the guess p̄ = (5, 0) is inside the obstacle, 0.5 m below the centre. Then n = (0, −1), the fence reads −(y − 0.5) ≥ 2, and so y ≤ −1.5. The fence is 1.5 m below the guess.
The worked example as a picture. The fence (purple) touches the obstacle at the point closest to the guess, so its far side is safe. With a trust radius of Δ = 1, the guess can only reach y = −1, which is 0.5 m short of the fence. The red bar is the slack that keeps this subproblem solvable.
Ingredient 3: a trust region. When you cross thin ice, you only step where you have tapped with your stick. The linear model and the fence are only trustworthy near the reference, so each iteration may move each point at most Δ:
‖pi − p̄i‖ ≤ Δ
This trust region also prevents artificial unboundedness: a linearised cost can slope downhill forever, so without a limit the subproblem runs off to infinity. SCvx and GuSTO use norm constraints or penalties like this one Malyuta 2022, while TrajOpt uses a box around the current iterate Schulman 2014. Back to the example with Δ = 1 m: the best the point can do is y = −1.0, still 0.5 m short of the fence. The subproblem has no solution, although the real problem has plenty.
Ingredient 4: virtual control, or slack. That dead end is called artificial infeasibility: the subproblem is infeasible only because of the linearisation and the trust region. The fix works like a rental car's late-return fee. You may break a rule, but it costs a lot, so you only do it when you must. Malyuta 2022
For a path constraint, add a slack si ≥ 0 and charge for it in the cost. For the dynamics, SCvx adds a fictitious input νk, the virtual control, with weight λ:
niT(pi − c) ≥ r − si, cost + λ·Σ si xk+1 = Akxk + Bkuk + ck + Eνk, cost + λ‖ν‖1
In the example, the smallest slack that works is s = 2 − (0.5 + 1) = 0.5 m. At convergence the slack must be zero. A converged answer that still uses virtual control does not solve the real problem; the tutorial calls this a "soft failure". Malyuta 2022
Put together, the loop is short:
p̄ ← initial guess # e.g. a straight line
repeat
linearise dynamics, draw one fence per waypoint around p̄
solve the convex subproblem (a QP or SOCP):
min cost(p) + λ·(total slack)
s.t. linearised constraints with slack
‖p_i − p̄_i‖ ≤ Δ # trust region
ρ ← actual drop / predicted drop # Section 4
if ρ < ρ0: reject p, shrink Δ
else: p̄ ← p; shrink, keep or grow Δ
until the step is tiny and the slack is zero
4. Grading each step: the accuracy ratio, SCvx and GuSTO
Think of a weather forecaster. If her forecasts keep coming true, you start trusting her further ahead. If they miss, you only trust tomorrow's. SCP grades its convex model the same way after every step.
Let J be the real cost, including the penalty for violating the real constraints, and let L be the convex model's version of it. After solving the subproblem from x̄ to x*, compare what happened with what was promised. This is the accuracy ratio:
ρ = [J(x̄) − J(x*)] / [J(x̄) − L(x*)] = actual drop ÷ predicted drop
The rule uses three thresholds 0 ≤ ρ0 < ρ1 < ρ2 < 1. Below ρ0, the model was badly wrong: reject the step and shrink Δ. Between ρ0 and ρ1, accept but shrink. Between ρ1 and ρ2, accept and keep Δ. Above ρ2, accept and grow Δ, up to a cap. The predicted drop doubles as the stopping test: when it is about zero, nothing is left to gain. Malyuta 2022
The trust-region rule with example thresholds. Left of ρ0 the model over-promised, so the step is thrown away. Far right, the promise (nearly) came true, and the next step may be bolder.
A worked example with made-up numbers: J(x̄) = 6.0, the model predicts L(x*) = 5.0, and the real cost turns out to be J(x*) = 5.8. Then ρ = 0.2 / 1.0 = 0.2, which lies between 0.1 and 0.7, so the step is accepted and Δ is kept. If the real cost had been 6.1, then ρ = −0.1: the step made things worse, so it is rejected and Δ shrinks.
This recipe of linearisation, virtual control and a ρ-based trust region is called SCvx (successive convexification). Mao, Szmuk and Açıkmeşe described it, with a convergence analysis, in 2016 Mao 2016. A follow-up claims global convergence with a superlinear rate, and fewer iterations than SQP and a general interior-point solver on a quadrotor problem. Mao 2018 See the SCvx / GuSTO paper card.
GuSTO (Guaranteed Sequential Trajectory Optimization) keeps the same skeleton but changes the safeguards. It targets control-affine systems with drift, handles goal sets and free final time, and moves the state constraints and the trust region into the cost as penalties whose weight grows. Its convergence proof works in continuous time with Pontryagin's maximum principle, so the guarantee does not depend on the discretisation. The guarantee is convergence to a stationary point, not to the global optimum. Bonalli 2019
GuSTO's numbers: in 100 runs of a 12-state free-flyer robot in a mock-up of the space station, started from straight lines, GuSTO and TrajOpt each succeeded 97% of the time, and GuSTO was faster with lower cost. On an 8-state airplane model, from the best initial guess, GuSTO took 0.55 s against TrajOpt's 2.67 s. GuSTO can also reuse the subproblem's dual variables (Day 9) to warm-start a shooting method, which cut run time by 52% on a Dubins car and 74% on the free-flyer. Bonalli 2019
Try it: the widget runs real SCP on a path from (0, 0) to (10, 0) around an obstacle at (5, 0.5) with r = 2, using K = 20 segments. Press Step, or click a table row. Then set Δ to 0.25, and try the "bowed above" start.
Notice: the default view is iteration 1. The straight start runs through the obstacle, and the middle waypoint, 0.5 m from the centre, can move only Δ = 1 m, so it needs 0.5 m of slack (red). Path length goes 10.000 → 10.202 → 10.574 → 10.457 → 10.455 → 10.455 m. The waypoints are collision-free from iteration 2, and SCP stops at iteration 5. With Δ = 0.25 it takes 12 iterations, and the first five need slack. Here ρ reads 1.000 every time, because the fence is conservative and the cost is not linearised. So the model never over-promises, and Δ only sets the pace. In SCvx's main use, linearised nonlinear dynamics, the model can over-promise; then ρ drops below ρ1 and shrinking Δ matters.
5. The honest caveat: the answer depends on the guess
SCP only ever looks near its reference, so it can only promise a local optimum: no nearby path is better, but a different initial guess may find a better one. The widget shows this directly. From a straight line, SCP slides under the obstacle and settles at 10.455 m. From a path bowed above, it settles over the top at 11.248 m, about 0.79 m (7.6%) longer. Neither run made a mistake; they started in different valleys.
You can check both answers by geometry. The shortest continuous path below the obstacle (two tangent lines and an arc) is 10.458 m, and the one above is 11.256 m. The 20-segment answers are slightly shorter than these, because straight segments cut the corner around the arc.
That corner-cutting is a known artefact of the toy. Only the waypoints are constrained, so the segments between them can clip the obstacle. At the end, every waypoint is at least 2.000 m from the centre, yet the closest segment passes at 1.983 m, a 1.7 cm clip. With K = 10 the clip grows to 7 cm. The Malyuta tutorial notes the same clipping in its quadrotor example Malyuta 2022. Real planners inflate obstacles by a margin or check the swept volume between time steps, as TrajOpt does. Schulman 2014
In practice, people manage the guess dependence in three ways. They try several initial guesses, they seed SCP with a rough path from a graph search or sampling planner, or they warm-start from the previous plan, as MPC does. TrajOpt's authors list the strong dependence on initialisation as a main limitation. Schulman 2014Day 19 shows a way to choose the "valley" globally with convex pieces.
6. SCP for robot arms: TrajOpt, and why CHOMP is different
TrajOpt plans robot-arm motions from the laziest guess possible: a straight line in joint space, which may pass right through a shelf. SCP turns that into a collision-free motion. Schulman 2014
Instead of hard constraints plus slack, TrajOpt moves every violation into the cost with an absolute-value penalty. Write |a|+ = max(a, 0). Its merit function is:
f(x) + μ Σ |gi(x)|+ + μ Σ |hi(x)|
Here f is the smoothness cost, gi ≤ 0 are the inequalities and hi = 0 the equalities. This is an exact (ℓ1) penalty: once the weight μ is large enough, minimising it gives the constrained solution exactly, not approximately. TrajOpt solves a QP inside a box trust region, and multiplies μ by 10 until the constraints hold. Schulman 2014
Collisions use the signed distance sd(A, B) between two shapes: their distance apart, or minus their penetration depth when they overlap. The penalty is |dsafe − sd(A, B)|+, which is linearised through the robot's Jacobian at every iteration. With made-up numbers, dsafe = 5 cm and a gripper 2 cm from the shelf costs μ × 3 cm, and at 8 cm it costs nothing. A swept-volume version checks the space between time steps too. Schulman 2014
Planner (198 arm problems, PR2, 7 joints)
Success rate
Average time
Path length (normalised)
TrajOpt
0.82
0.19 s
1.16
TrajOpt, several initial guesses
0.96
–
–
OMPL RRT-Connect (sampling)
0.85
0.62 s
1.56
CHOMP-HMC (gradient)
0.65
4.91 s
2.04
On 96 full-body problems with 18 degrees of freedom, TrajOpt succeeded 0.73 of the time (0.88 with several initial guesses), against 0.41 for RRT-Connect, taking 2.2 s against 20.3 s. Schulman 2014 See the TrajOpt paper card.
CHOMP is often mentioned in the same breath, but it is not SCP. CHOMP runs covariant gradient descent on a smoothness-plus-obstacle cost. It builds no convex subproblem and uses no trust region. Ratliff 2009 The GuSTO paper groups it with "variational methods" and notes that it does not include dynamics constraints. Bonalli 2019 Think of CHOMP as TrajOpt's gradient cousin.
The same loop fits a car. Linearise the bicycle model around the last plan, turn each nearby obstacle into a halfspace, cap how far each node may move, solve a QP, and repeat. Day 19 replaces "one halfspace per obstacle" with better convex pieces, and Day 20 adds safety filters.
7. Lossless convexification: landing a rocket with one convex solve
Back to the rocket engine with a minimum and a maximum thrust. The allowed thrust vectors form a ring, which is not convex. Powered descent guidance computes the thrust profile for the final landing burn, and it has to handle that ring. Lossless convexification is a relaxation that is proven to give the original problem's global optimum. Açıkmeşe & Ploen 2007
The trick works like a taxi meter. Add a new variable Γ, the thrust you pay fuel for, which may run anywhere between the limits. The actual thrust only has to stay below the meter. A cost-minded passenger never lets the meter run ahead of the pedal.
Left: thrust (8000, 0) N and its opposite are allowed, but their midpoint, zero thrust, is not, so the ring is not convex. Right: one thrust component T against the meter Γ. The relaxed set is convex, and its thick green edges, where ‖T‖ = Γ, are the settings a real engine can produce. The pink dot pays for 4972 N but pushes with only 3000 N.
In symbols, the original constraint and its relaxation are:
Here T is the thrust vector, m the mass, and α converts thrust into fuel flow. (These ρ1 and ρ2 are thrust limits, as in the papers, not the thresholds of Section 4.) The relaxed set is convex. Under the theorem's conditions, the optimum of the relaxed problem always has ‖T(t)‖ = Γ(t), so it is feasible for the real engine, and globally optimal. A change of variables to the logarithm of the mass, plus time discretisation, turns the whole problem into an SOCP (Day 5), which interior-point solvers (Day 12) handle reliably. Açıkmeşe & Ploen 2007Blackmore 2010
Blackmore, Açıkmeşe and Scharf give Mars numbers. Gravity is 3.7114 m/s², the lander has a mass of 1905 kg wet and 1505 kg dry, so 400 kg of fuel is on board, and thrust runs from ρ1 = 4972 N to ρ2 = 13260 N. A glide-slope cone (4° here) stops the lander from coming in too low over the terrain. Hovering at full mass needs 1905 × 3.7114 ≈ 7070 N, inside the range. The pair T = 3000 N with Γ = 4972 N is allowed by the relaxation but not by the engine, and the theorem says the optimiser never picks it. Blackmore 2010
In their first case the target is reachable. The optimal landing uses 399.4 kg of fuel with a flight time of 78.4 s. The flight time comes from an outer golden-section search (23 iterations, with 55 time nodes per convex solve), which took 14.3 s in total on a 2.4 GHz MacBook Pro with JPL's G-OPT solver. In the second case the lander starts with an extra 40 m/s sideways. Reaching the target would need at least 414 kg of fuel, more than the 400 kg on board. A minimum-landing-error version of the problem then lands 404 m from the target, after 77.7 s, using all 400 kg. Blackmore 2010 See the lossless convexification paper card.
JPL has flown LCvx-based guidance (G-FOLD) on Masten's Xombie test rocket, including a 750 m divert. Malyuta 2022 On SpaceX, stay with the primary source. Lars Blackmore, writing as a SpaceX engineer, says SpaceX uses CVXGEN to generate flight code for "very high-speed onboard convex optimization", and that the landing trajectory must be computed autonomously "in a fraction of a second". He cites the 2007 and 2010 papers above. Blackmore 2017 He does not publish the formulation. The Malyuta tutorial only hypothesises that LCvx is a close relative of Falcon 9's landing algorithm, and states that SpaceX's methods are undisclosed. We found no public description of SpaceX's current formulation as of Oct 2026. Malyuta 2022
The limits matter. The model is a point mass with constant gravity, the flight time is searched outside the convex solve, and the lossless guarantee holds only for problems whose nonconvexity has the right structure. Otherwise you use SCP, possibly with LCvx inside each subproblem. Malyuta 2022 The Malyuta tutorial card is the best next read; it won the 2023 IEEE Control Systems Magazine Outstanding Paper Award. UW 2024
Going deeper (optional): why the relaxation is lossless
Why can't the optimiser cheat by metering more thrust than it uses? Intuitively, that pays fuel for nothing. But "just lower Γ" is not a proof: Γ cannot go below ρ1, and burning less fuel changes the mass and so the motion. The real proof uses Pontryagin's maximum principle. Along an optimal path, a "costate" vector sets the best thrust direction and size. As long as that vector is not zero over a whole time interval, the best choice puts T on the edge ‖T‖ = Γ. Showing that the costate cannot vanish for a stretch is where the problem's structure is needed: linear dynamics, constant gravity, and the specific constraints. Malyuta et al. walk through the conditions and later extensions. Malyuta 2022
Analogy
SCP is like steering a boat through fog with a short-range sonar. You trust the sonar only within its range (the trust region). You treat each rock as a straight wall facing you (the fence). If no route avoids every wall, you allow yourself a small, expensive scrape (the slack). Then you ping again and redraw the walls. Lossless convexification is the rare harbour whose chart is exact, so one plan is enough.
Explain it to a 10-year-old
You want to walk around a big round pond, but it is foggy and you can only see a few steps ahead. So you put up a straight fence at the edge of the pond nearest to you, and promise to stay behind it. You take a few steps, look again, and move the fence. After a few tries you are around the pond with dry shoes. If you had started on the other side, you would have walked around the other way.
Common misunderstandings
"SCP found the optimal trajectory." It found a local optimum. In the widget, a bowed start ends at 11.248 m, while a straight start ends at 10.455 m. The guess picks the valley.
"It converged, so it is feasible." Check that the slack and virtual control are zero. Converging with virtual control left over is a soft failure, not a solution.
"The waypoints are clear, so the path is clear." The segments between waypoints can clip the obstacle: 1.7 cm with 20 segments, 7 cm with 10. Inflate obstacles or check swept volumes.
"Lossless convexification works on any nonconvex problem." It applies to specific problem classes where the maximum-principle argument goes through. Elsewhere, use SCP.
"CHOMP is SCP." CHOMP is a covariant gradient method. TrajOpt is SCP, with convex subproblems, a trust region and ℓ1 penalties.
"SpaceX lands Falcon 9 with the 2007 algorithm." That is not public. The sourced statement is that SpaceX uses CVXGEN-generated flight code for onboard convex optimisation; the link to LCvx is a hypothesis.
Check yourself
Q1. A waypoint guess sits at p̄ = (5, 0). The obstacle has centre c = (5, 0.5) and radius 2. Which fence does SCP use for this waypoint?
The unit vector from c to p̄ is n = (0, −1), so the fence nT(p − c) ≥ 2 reads −(y − 0.5) ≥ 2, which is y ≤ −1.5. The line y ≥ 2.5 is also outside the disk, but it is the tangent on the far side, facing away from the guess, so it would drag the waypoint across the whole obstacle.
Q2. SCvx computes ρ = 0.05 with thresholds ρ0 = 0, ρ1 = 0.1, ρ2 = 0.7. What does it do?
0.05 lies between ρ0 and ρ1: the real cost did drop, but only by 5% of what the model promised. The step is kept, and the trust region shrinks so the next model is used closer to home. Convergence is judged by the predicted drop being near zero, not by ρ.
Q3. A converged SCP run still uses 0.3 m of slack on one waypoint. What does that mean?
Slack and virtual control are bookkeeping that keeps each subproblem solvable. If they are not zero at the end, the waypoint is still 0.3 m inside the obstacle. Try another initial guess, a larger penalty weight, or check whether the real problem is feasible at all.
Q4. In the widget, a bowed start converges to 11.248 m and a straight start to 10.455 m. Why?
The cost Σ‖pi+1 − pi‖² is convex; the obstacle is what makes the problem nonconvex, with one valley above and one below. Changing Δ changes the pace, not the valley: every Δ from the straight start reaches the same 10.455 m path.
Q5. How does lossless convexification handle the thrust ring ρ1 ≤ ‖T‖ ≤ ρ2?
The lifted set is convex, and the proof shows the optimum sits on its edge ‖T‖ = Γ, so nothing is lost. Dropping the lower bound gives a different problem whose answer may ask for thrust the engine cannot make. A binary variable gives a mixed-integer program (Day 15), which is much harder to solve onboard.
Q6. Which source directly states that SpaceX uses CVXGEN-generated flight code?
Blackmore, writing from SpaceX, makes the statement. The Malyuta tutorial only hypothesises a link between LCvx and Falcon 9 and says SpaceX's methods are undisclosed. The 2007 paper is the method SpaceX's author cites, not a statement about SpaceX.
Recap: things to remember
Direct transcription turns a path into a finite list of node states and inputs, with the dynamics as defect constraints; collocation rules such as the trapezoid define those links.
Obstacles, nonlinear dynamics and minimum-thrust limits are the usual sources of nonconvexity.
SCP repeats four moves: linearise around the last path, replace obstacles by safe halfspaces, limit the step with a trust region, and use penalised slack so every subproblem is solvable. The slack must be zero at the end.
SCvx grows or shrinks the trust region by ρ = actual drop ÷ predicted drop; GuSTO uses penalties and continuous-time guarantees. Both give local, guess-dependent answers.
Lossless convexification lifts the thrust ring with a meter Γ and proves the convex answer is exact: Blackmore 2010's Mars landing used 399.4 kg of fuel in 78.4 s.
Autonomous Precision Landing of Space Rockets, L. Blackmore, in Frontiers of Engineering: Reports on Leading-Edge Engineering from the 2016 Symposium, National Academy of Engineering, 2017 (accessed 2026-10-26).
After today you can explain why obstacle avoidance is nonconvex and name four convex ways around it: OBCA's duality trick, safe corridors, IRIS's convex free-space regions, and Graphs of Convex Sets.
About 60 min · Needs Days 9, 15 and 18 · No CO4A chapter (this day is new in this course)
Today's big idea
The set of places a robot may go has holes in it, so it is not convex. You cannot make the holes go away, but you can work around them. Either carry a small dual "proof of clearance" as an extra variable (OBCA), or cover free space with overlapping convex pieces and plan piece by piece (safe corridors, IRIS, Graphs of Convex Sets). Inside one convex piece, every straight move is safe, so the hard part becomes choosing which pieces to use.
1. Why "stay out of the box" is nonconvex
Picture a car park with one concrete pillar. You can park left of it or right of it. But if you average those two parking spots, you land inside the pillar. That one fact is the whole problem of today.
The free space is every position where the robot touches nothing. On Day 2 a set was convex if the segment between any two of its points stays in the set. Free space around an obstacle fails this test, because the segment between two safe points can pass through the obstacle. So "stay outside" is a nonconvex constraint: averaging two allowed points can break it.
Write the obstacle as a polytope, the set of points that satisfy every face inequality:
O = {x : aiTx ≤ bi, i = 1…m} = {x : Ax ≤ b}
Here ai is the outward normal of face i, bi is its offset, and A stacks the rows aiT. To be outside, you only need to break one face inequality:
x ∉ O ⇔ maxi (aiTx − bi) > 0
Read it as "beyond face 1 OR beyond face 2 OR …". That is a disjunctive (OR) constraint. Each half-plane is convex, but their union, with the obstacle cut out of the middle, is not. A max of affine functions is convex, and asking a convex function to be large (≥, not ≤) can give a nonconvex set, as it does here.
Numbers: take the square obstacle [−1, 1]2, so A = [I; −I] and b = (1, 1, 1, 1). The points (−2, 0) and (2, 0) are both outside. Their midpoint (0, 0) is inside. One counterexample is enough: this free space is not convex.
Left: (−2, 0) and (2, 0) are both outside the square, but their midpoint (0, 0) is inside, so free space is not convex. Right: "outside" is the union of four half-planes, one per face. Each band is convex; their union, with a hole in the middle, is not.
2. Three families of fixes
Think of crossing a river. You can list every stepping stone and decide stone by stone which to use. You can start on a rough route and nudge your feet toward safety. Or you can first lay planks across, then walk only on planks. These are the three families of fixes.
The first family keeps the OR exactly with 0/1 switch variables. On Day 15 you met big-M / mixed-integer modelling: one binary per face says "I am beyond this face". It finds the global optimum, but the number of binaries grows with faces × obstacles × time steps, and branch and bound can blow up. The OBCA authors note that integer variables "should generally be avoided" in real-time nonlinear control. Zhang 2021
The second family works locally. On Day 18, sequential convex programming replaced the round obstacle by one straight fence near the current guess, solved a convex problem, and repeated. OBCA (section 3) also belongs here: it keeps the exact shape but makes the constraint smooth, then hands it to a local solver.
The third family is today's main topic. Cover free space with convex pieces. Inside one piece any straight move is safe, so planning becomes "pick the pieces, then solve a convex problem inside them".
Regions cost time to build and leave some free space out
Safe corridors, IRIS, GCS, safe boxes
3. OBCA: distance as a small dual problem
To demand "stay at least 0.5 m from the wall", you need the distance. But distance has no simple formula: it is itself a small optimization, "find the closest point of the obstacle". OBCA (Optimization-Based Collision Avoidance) uses duality from Day 9 to turn that inner problem inside out. Zhang 2021
The intuition is a signed note. Instead of re-measuring the gap at every step, the robot carries a certificate: a straight line that touches the obstacle, plus the claim "I am at least dmin beyond this line". If the claim holds, the robot is safe. The optimizer moves the robot and the note together.
Each λ picks a line that touches the obstacle (dashed). For p = (3, 0.5) the best λ = (1, 0, 0, 0) certifies distance 2. The diagonal line, λ = (0.71, 0.71, 0, 0), certifies only 1.06 for that point, but it is the best line for p = (3, 3), where it certifies 2.83.
For a point robot at p, strong duality gives the distance as a maximum over multipliers λ, one per face: Zhang 2021, Prop. 1
dist(p, O) = maxλ ⪰ 0 (Ap − b)Tλ s.t. ‖ATλ‖2 ≤ 1
So the hard constraint "distance at least dmin" becomes "some λ proves it":
∃ λ ⪰ 0 : (Ap − b)Tλ ≥ dmin ‖ATλ‖2 ≤ 1
Such a λ is a dual certificate (witness). The vector w = ATλ is the normal of a line that touches the obstacle, and (Ap − b)Tλ is how far p sits beyond that line. Any valid λ gives a lower bound on the distance (weak duality). The best λ gives the exact distance (strong duality, which holds here because the constraints are linear).
Numbers, with the square [−1, 1]2 and p = (3, 0.5). Then Ap − b = (2, −0.5, −4, −1.5). The choice λ = (1, 0, 0, 0) picks the face x ≤ 1, has ‖ATλ‖ = 1, and gives value 2, the true distance. The choice λ = (0.71, 0.71, 0, 0) is also valid but gives only (2 − 0.5) × 0.71 = 1.06, a weaker bound. For p = (3, 3), λ = (0.71, 0.71, 0, 0) gives 2√2 ≈ 2.83, the distance to the corner (1, 1).
A car is not a point. OBCA models the car as a fixed shape 𝔹 = {y : Gy ≤ g}, here a 4.7 × 2 m rectangle, rotated by R(x) and shifted by t(x), where x is the car's state. Adding a second multiplier μ for the car's own faces gives the full-shape version: Zhang 2021, Prop. 3
You add one (λ, μ) pair per obstacle per time step. Every constraint is smooth (square the norm constraint), so a standard nonlinear solver such as IPOPT can handle it. The problem is still nonconvex, through the car dynamics and the rotation R(x), so it needs a good starting guess, a warm start.
In parking, that warm start comes from Hybrid A*, a grid search over (x, y, heading) with car-like motion pieces. Its paths are drivable but jerky; OBCA smooths them. In the paper's test the car had a 2.7 m wheelbase, and it started from 84 poses near a reverse spot (2.6 × 5.2 m) and a parallel spot (2.5 × 6 m). Every run succeeded. With the distance form, average times were 0.60 s (reverse) and 0.87 s (parallel), on a 2013 MacBook Pro with IPOPT. A plain A* warm start, which ignores turning limits, was typically not good enough. Zhang 2021, Table 2
Plain distance is 0 for every overlap, so it cannot say how deep a collision is. OBCA's second form uses signed distance: the distance when apart, minus the penetration depth when overlapping. You get it by changing ‖ATλ‖ ≤ 1 to = 1. Then slack variables can find the least-intrusive path when contact cannot be avoided. The price is a nonconvex equality: 1.03 s and 1.67 s on average in the same tests, and 7.7 s and 9.2 s in the worst case including Hybrid A*. Zhang 2021, Thm 1 More in the OBCA paper entry.
Going deeper (optional): where the dual formula comes from
Let w = p − y be the gap from an obstacle point y to the robot. Then dist(p, O) = min ‖w‖2 subject to A(p − w) ≤ b. The Lagrangian is ‖w‖ + λT(Ap − Aw − b) with λ ⪰ 0. Minimising over w, the term ‖w‖ − (ATλ)Tw is bounded below only if ‖ATλ‖ ≤ 1 (Cauchy–Schwarz), and then its minimum is 0. So the dual function is (Ap − b)Tλ on that set, which is the formula above. Weak duality also has a one-line check: for any y in O, ‖p − y‖ ≥ wT(p − y) ≥ (Ap − b)Tλ when w = ATλ and ‖w‖ ≤ 1. The constraints are linear and the problem is feasible, so the duality gap is zero.
4. Safe flight corridors: plan room by room
If free space cannot be made convex, cover it with convex rooms. Inside one room every straight move is safe. You then plan room by room and only need consecutive rooms to overlap, like stepping stones that touch.
A safe flight corridor is a chain of overlapping convex polyhedra around a rough path, inside which a drone trajectory is optimized. Liu and colleagues built it like this for quadrotors flying through point clouds. The original paper was not checked for this lesson, so the pipeline below comes from the authors' code README and a 2024 description by other researchers: DecompUtil READMEWu 2024
Find a rough path of line segments with a grid search (Jump Point Search).
Around each segment, grow an ellipsoid until it touches obstacle points.
At each contact, keep the tangent half-space. Together they form one polyhedron per segment.
The overlapping polyhedra form the corridor.
Optimize the trajectory as a QP that keeps each piece inside its polyhedron.
In formulas, room i is Pi = {x : Aix ≤ bi}, and piece i of the trajectory must satisfy Aix(t) ≤ bi. Those constraints are linear in the trajectory. With a quadratic cost on acceleration or jerk the whole problem is a QP, like the MPC of Day 17. The exact cost, and how the constraint is enforced over time, are in the paper and were not checked here. Liu 2017
Step 3 is worth one number. Say the current ellipsoid is the unit disk at the origin and the closest obstacle point is x* = (2, 1). The wall normal is a = x*/‖x*‖ = (0.894, 0.447) and the offset is b = aTx* = √5 ≈ 2.236. So the room keeps 0.894x + 0.447y ≤ 2.236: the line through x* at right angles to the radius. IRIS uses the same step.
5. IRIS: grow the biggest convex room
Picture blowing up a balloon in a cluttered cupboard. It grows until it presses on the shelves, and the shelves it touches become the walls of its room. IRIS (Iterative Regional Inflation by Semidefinite programming) does this with math: it grows one large obstacle-free polytope, with an ellipse inside, from a seed point. Deits & Tedrake 2015
Describe the ellipse as a stretched unit ball, E = {Cu + d : ‖u‖2 ≤ 1}, with a symmetric matrix C ⪰ 0 and a centre d. Its area (or volume) is proportional to det C. IRIS alternates two convex problems:
Planes (a QP). For each convex obstacle, find its point closest to E, measured after mapping E back to the unit ball. Add the tangent plane there. Skip obstacles already cut off by earlier planes. The planes give a polytope P = {x : Ax ≤ b}.
Ellipse (an SDP). Find the biggest ellipse inside P. This maximum-volume inscribed ellipsoid problem is:
maxC ⪰ 0, d log det C s.t. ‖Cai‖2 + aiTd ≤ bi, i = 1…m
Why this constraint? The point of E that reaches farthest in direction ai reaches aiTd + ‖Cai‖. Keeping that below bi keeps the whole ellipse inside face i. log det is concave, so this is a convex problem, in fact an SDP from the zoo of Day 5. Repeat both steps until det C stops growing. The ellipse can only grow, so the loop converges.
Numbers: in the rectangle [−2, 2] × [−1, 1], the biggest ellipse has C = diag(2, 1) and d = 0. For the face x ≤ 2, ‖Ca‖ = 2 ≤ 2, so it touches. Its area is π · 2 · 1 = 6.283, which is 78.5% of the rectangle's area 8.
IRIS on four convex obstacles. (i) Start from the unit disk (red, area π ≈ 3.14) around the seed (centre dot). Each obstacle's closest point (blue dot) gives one tangent line. (ii) The four lines bound a polygon (shaded). The biggest ellipse inside it touches all four sides and has area 12.47, four times the start. The real algorithm now repeats step (i) with this ellipse. The numbers were computed for this figure.
IRIS is fast. Its run time grows linearly with the number of obstacles, and it converged in seconds with a million obstacles. The closest-point QP took under 20 µs with a code-generated solver. Two limits: obstacles must be convex (split non-convex ones first), and the seed ended up inside the final region only 95% of the time. Deits & Tedrake 2015 See the IRIS paper entry.
For robot arms, the obstacles live in joint space and have no explicit formula. Newer variants handle that case: IRIS-NP2 and IRIS-ZO grow joint-space regions faster, and FIRI (T-RO 2025) speeds up the 2-D and 3-D case. As of Oct 2026 these tools change quickly. Werner 2024Wang 2025
6. Graphs of Convex Sets: one convex program picks the rooms
Corridors and IRIS give you rooms, but someone still has to choose which rooms to pass through. Think of a road trip. The discrete choice is which towns to drive through. The continuous choice is where exactly you cross each town line. Dijkstra's algorithm solves the first only if road lengths are fixed, and here they depend on the crossing points.
A Graph of Convex Sets (GCS) puts both choices in one problem. Each vertex v holds a convex set Xv and a movable point xv ∈ Xv. Each edge (u, v) has a convex length, here ‖xv − xu‖2. The shortest-path problem is: Marcucci 2024
min over paths and points: Σedges (u,v) on the path ‖xv − xu‖2
If you fix the chain of sets, what is left is convex. Call the chain K1, …, Km, the start S and the goal G. You pick one breakpoint pj in each overlap, or "door":
This convex restriction is an SOCP. Its answer is safe: segment j joins pj−1 and pj, which both lie in the convex box Kj, so the whole segment does too.
The widget's map as a graph of convex sets. Each vertex is a box with one movable point; each edge means two boxes overlap. A and C do not overlap, so there is no A–C edge. Edge lengths depend on where the points sit, which is why the 4-box route can beat the 3-box ones.
Try it: the default view solves every chain from box A (holding the start) to box C (holding the goal) and draws each shortest path. Pick one chain to see its breakpoints and segment lengths. Then tap "Box D1" to remove that box and watch the answer change.
Notice: the 4-box chain A→D1→D2→C (9.6287) beats both 3-box chains, A→F→C (13.6619) and A→B→C (17.2315). Its breakpoints sit on door corners, (3, 4), (3.5, 5) and (3.5, 6), where a taut string would bend. It is 20.4% longer than the blocked straight line of 8. Remove D1 and the best route becomes A→F→C, 13.6619.
The widget tries all three chains. Real maps have thousands of regions and far too many chains to try, and finding the best one is NP-hard in general. GCS writes the choice with one binary φe ∈ {0, 1} per edge, "this edge is used". It then uses a perspective function φ·f(x/φ), a scaled copy of each cost and constraint that switches off cleanly when φe = 0. Marcucci 2024
The convex relaxation loosens φe ∈ {0, 1} to φe ∈ [0, 1]. With Euclidean lengths it is one SOCP. Its optimal cost is a lower bound, and the perspective trick makes it unusually tight. Rounding turns the fractional φ into one path, and the convex restriction of that path gives a real cost. That brackets the true optimum:
Crelax ≤ Copt ≤ Cround
gap ≤ (Cround − Crelax) / Crelax
This optimality gap bound comes free with the solve. In one example of the paper, Crelax = 27.29 and Cround = 28.10, so the path is at most 0.81/27.29 = 2.97% above the best. A mixed-integer solver later showed the true gap was 0%. Marcucci 2023
Robots need smooth curves, not polylines. GCS gives each region a Bézier curve, a polynomial curve that stays inside the convex hull of its control points. Put the control points in a convex region and the whole curve stays in that region, with no sampling. Continuity and velocity limits are linear or conic, so the problem stays an SOCP.
The results are strong. A 2,500-cell maze needed 5,198 binaries instead of 6.25 million for an older formulation, and one SOCP returned the global optimum. For a quadrotor among buildings, 95% of plans were within 1% of the global optimum (worst 2.9%), with a median relaxation time of 3.7 s. On a 7-joint KUKA arm, GCS found shorter paths than a sampling planner (PRM), ran faster than plain PRM, and reached the global optimum on all 5 tasks. These numbers come from the arXiv v1 preprint of the Science Robotics paper and may differ in the published version. Marcucci 2023 See the GCS paper entry.
Limits: the regions must be built first (8 IRIS regions took 53 s for the arm). Full dynamics make the problem nonconvex. Rounding is not guaranteed to find the optimum. Solve times are seconds, not milliseconds. Drake implements the method as GcsTrajectoryOptimization; its SolveConvexRestriction is exactly what the widget does for a fixed chain. Drake docs
import cvxpy as cp, numpy as np
S, G = np.array([1.0, 1.0]), np.array([1.0, 9.0])
# doors of the chain A→D1→D2→C as (lower corner, upper corner)
doors = [((3, 3), (4, 4)), ((3.5, 4.8), (4, 5)), ((3.5, 6), (4.5, 7))]
P = cp.Variable((len(doors), 2)) # one breakpoint per door
cons = []
for j, (lo, hi) in enumerate(doors):
cons += [P[j] >= np.array(lo), P[j] <= np.array(hi)]
pts = [S] + [P[j] for j in range(len(doors))] + [G]
length = sum(cp.norm(pts[k + 1] - pts[k], 2) for k in range(len(pts) - 1))
cp.Problem(cp.Minimize(length), cons).solve()
print(round(length.value, 4), P.value.round(3))
# expected: 9.6287, breakpoints (3, 4), (3.5, 5), (3.5, 6)
Analogy
GCS is a road trip planner that also chooses where you cross each border. A normal planner adds up fixed road lengths. GCS lets each border crossing slide, so a route through more towns can still be shorter, just as the widget's 4-box chain beats the 3-box ones.
7. Scaling up: fast planning through safe boxes (2024)
A warehouse or a village can need ten thousand safe regions, and then even one GCS relaxation gets slow. Marcucci, Nobel, Tedrake and Boyd traded the optimality bound for speed. They use only axis-aligned boxes, and they split the work into a graph search and a few small convex problems. Marcucci 2024b
Offline: build a graph of which boxes overlap and label its edges with approximate distances, using one convex program.
Online: a weighted shortest-path search gives a box chain and a polygonal path, which is then shortened.
Online: a few convex problems turn the polygon into smooth Bézier curves inside the same boxes.
It is complete: it finds a path if one exists and otherwise proves there is none. It is not guaranteed optimal. With 25,600 boxes, the offline step took 25 s and the online steps 0.12 s (polygon) plus 3.4 s (smooth). For a quadrotor in a village of 10,150 boxes, online planning took 0.22 s plus 7.5 s for a path through 135 boxes. See the safe-boxes paper entry.
The ideas keep moving, as of Oct 2026. GCS* runs an A*-style search over an implicit graph of convex sets. A 2025 paper plans shortest walks, where a path may revisit sets, guided by an SDP lower bound on the cost-to-go. Chia 2024Morozov 2025
Method
What is convex
Guarantee
Reported time
OBCA
Nothing overall; the collision constraints become smooth and exact
Local optimum from a warm start
0.6–0.9 s on average for parking (2013 laptop)
Safe flight corridor
The trajectory QP inside fixed polyhedra
Stays inside the corridor where the constraints are enforced; quality depends on the rough path
Not checked for this lesson
IRIS
Each step: a QP for planes, an SDP for the ellipse
One large region per seed, not the largest
Seconds even with 106 obstacles
GCS
The relaxation (an SOCP) and each fixed-chain problem
Certified gap; often globally optimal
Seconds (median 3.7 s for the quadrotor)
Safe boxes
The distance labels and the smoothing steps
Complete; not guaranteed optimal
0.2 s polygon + a few seconds smoothing
Explain it to a 10-year-old
Your room has a big toy box in the middle. You want to walk from the door to your bed without bumping it. First put down a few rugs that do not touch the box, so that each rug touches the next. On one rug you can walk straight anywhere. So you only have to choose which rugs to use, and then walk straight from rug to rug.
Common misunderstandings
"OBCA makes collision avoidance convex." It makes the collision constraints smooth and exact. The full problem, with car dynamics and rotation, is still nonconvex, so it finds a local optimum and needs a warm start such as Hybrid A*.
"A minimum-distance constraint tells you how deep a collision is." Distance is 0 for every overlap, shallow or deep. To minimise penetration you need signed distance, OBCA's ‖ATλ‖ = 1 form.
"Convex pieces cover all of free space." IRIS regions and boxes are inner approximations. They leave some free space out, the seeds matter, and joint-space regions for arms are usually only approximately certified.
"Fewest regions means shortest path." In the widget the 4-box chain (9.63) beats both 3-box chains (13.66 and 17.23).
"The certified gap is the true gap." It is only an upper bound. In the GCS paper one certified gap of 27.1% hid a true gap of 2.3%.
Check yourself
Q1. Why is "stay outside a square obstacle" a nonconvex constraint?
A convex set must contain the segment between any two of its points, and free space does not. Corners are not the cause: a round obstacle (Day 18) has the same problem. ‖x‖² is convex; the trouble is that we ask it to be large, not small.
Q2. In OBCA, what is the extra variable λ?
λ comes from the dual of the distance problem. A valid λ (λ ⪰ 0, ‖ATλ‖ ≤ 1) with (Ap − b)Tλ ≥ dmin proves the clearance. It is a multiplier, but of the inner distance problem, not of the dynamics.
Q3. Obstacle [−1, 1]² with rows x ≤ 1, y ≤ 1, −x ≤ 1, −y ≤ 1, and p = (3, 0.5), so Ap − b = (2, −0.5, −4, −1.5). Which λ certifies the true distance 2?
(1, 0, 0, 0) gives 2 with ‖ATλ‖ = 1. (0.71, 0.71, 0, 0) is valid too but proves only 1.06, a weaker lower bound. (0, 1, 0, 0) gives −0.5, and (1, 1, 1, 1) gives −4: valid but useless.
Q4. What does IRIS alternate between?
Step (i) puts a tangent plane at each obstacle's closest point to the current ellipsoid (a small QP). Step (ii) solves max log det C inside those planes (an SDP). Sampling and smoothing describe planners like PRM, not IRIS.
Q5. A GCS relaxation costs 27.29 and the rounded path costs 28.10. What can you say?
Crelax ≤ Copt ≤ Cround, so the gap is at most 0.81/27.29 = 2.97%. The bound does not tell you the true gap; in this case a MIP solver showed it was 0%. A relaxation gives a lower bound, not an upper one.
Q6. Why does GCS give each region a Bézier curve?
The convex hull property turns "the whole curve is safe" into a few linear constraints on control points, with no sampling and no gaps between samples. Regions must still overlap so that consecutive curves can join.
Recap: things to remember
Free space has holes, so "stay outside" is an OR over faces and is nonconvex: (−2, 0) and (2, 0) are safe, their midpoint is not.
The fixes are binaries (exact, slow), local methods (fast, need a warm start), and convex pieces (convex once the pieces are chosen).
OBCA writes distance as a dual problem. A multiplier λ with (Ap − b)Tλ ≥ dmin and ‖ATλ‖ ≤ 1 proves clearance, and the constraints are smooth.
Safe corridors and IRIS build convex rooms. IRIS alternates tangent planes (QP) with the biggest inscribed ellipse (SDP).
GCS chooses the rooms and the path in one convex relaxation and certifies the gap. More rooms can mean a shorter path: 9.63 vs 13.66.
Sources
Optimization-Based Collision Avoidance (arXiv 1711.03449; PDF v3), X. Zhang, A. Liniger, F. Borrelli. IEEE Trans. Control Systems Technology 29(3):972–983, 2021 (accessed 2026-10-26).
Shortest Paths in Graphs of Convex Sets, T. Marcucci, J. Umenberger, P. A. Parrilo, R. Tedrake. SIAM J. Optimization 34(1):507–532, 2024 (accessed 2026-10-26).
After today you can build a control-barrier-function QP that minimally corrects any controller to keep a robot safe, and explain how differentiable optimization layers and learned warm starts let neural networks and solvers work together.
About 60 min · Needs Days 10 and 17 · No CO4A chapter (new material)
Today's big idea
Keep the controller you already have, even a neural network, and put a tiny QP between it and the motors. The QP changes the command as little as possible, under one rule: the safety margin h may shrink only slowly as it nears zero, so it never crosses zero. The KKT conditions that solve this QP in one line also let you backpropagate through it. That is how optimization and learning end up in the same loop.
1. The safety filter: a referee between controller and motors
Think of a driving-school car with a second brake pedal on the instructor's side. While the student drives well, the instructor does nothing. When the student heads for trouble, the instructor presses just hard enough to fix it, and no harder. A safety filter is that instructor, written as an optimization problem.
The student is the nominal controller: whatever turns the current state x into a command unom(x). It can be the MPC from Day 17, a hand-tuned PID loop, or a neural-network policy that nobody can verify. The filter does not need to know how it works. It only sees the command and the state.
At every control step the filter solves
u* = argminu ½‖u − unom‖22 subject to: the safety rule holds for u
and sends u* to the motors. The cost measures how much the command was changed, not how large it is. Ames and co-authors describe this as modifying an existing controller "in a minimally invasive fashion". Ames 2019
The filter sees only the planner's command and the measured state. When the command already obeys the safety rule, it passes through unchanged: u* = unom.
The safety rule turns out to be linear in u, so the filter is a one-constraint QP (Day 5) with a one-line solution. In today's widget, a planner drives a point robot at 1 m/s past a round obstacle. With the default setting, the filter leaves the planner's command untouched for the first 1.64 s, until the robot is 1.40 m from the obstacle.
2. Barrier functions: you may approach, but slow down
Picture walking toward a wall in the dark, with one rule: each second, you may close at most half of the remaining gap. At 2 m you may walk at 1 m/s. At 20 cm you may walk at only 10 cm/s. You get closer and closer, but you never touch the wall.
To write this down, pick a barrier function h(x), a number that measures your safety margin. The safe set is C = {x : h(x) ≥ 0}. Its edge is where h = 0, and inside it h > 0. A set is forward invariant if every motion that starts inside it stays inside. Being safe means C is forward invariant. Ames 2019
Three barriers you will meet today: h = 5 − x for a wall at x = 5; h = ‖x − c‖2 − r2 for a round obstacle of radius r centred at c; and h = D − 1.8v for a car that keeps a gap D of at least 1.8 seconds' worth of its speed v.
The rule from the wall picture is
ḣ ≥ −γ·h, with γ > 0
In words: far from the edge, h is large and may fall quickly. Near the edge, h is small and may fall only slowly. At the edge, h = 0 and may not fall at all. The rate γ (units 1/s) sets how fast the margin may shrink. The wall walk above is γ = 0.5.
Why can h never cross zero? Take the fastest allowed approach, ḣ = −γh exactly. Its solution is h(t) = h(0)·e−γt, which stays positive forever. Any motion that obeys the rule shrinks h no faster, so it stays positive too.
Now bring in the robot. Most robot models are control-affine: ẋ = f(x) + g(x)u. Here f is the drift (what happens with no input) and g(x) says how the input u pushes the state. The chain rule gives
ḣ = ∇h(x)Tẋ = Lfh(x) + Lgh(x)·u
Lfh = ∇hTf and Lgh = ∇hTg are the Lie derivatives of h: its rate of change along the drift and along the input. The key fact is that ḣ is linear in u. So the rule ḣ ≥ −γh is one linear inequality on u:
Lfh(x) + Lgh(x)·u ≥ −γ·h(x)
h is a control barrier function (CBF) if at every state some input satisfies this inequality. In general, γh may be any extended class-K function α(h): strictly increasing, with α(0) = 0. The main theorem: any Lipschitz controller that always picks such a u keeps C forward invariant, and it pulls the state back if noise pushes it slightly out. Ames 2019
A worked example in 1-D. A robot on a line has ẋ = u and a wall at x = 5, so h = 5 − x and ḣ = −u. The rule −u ≥ −γ(5 − x) becomes
u ≤ γ·h (a speed limit: γ times the gap)
The planner wants unom = 2 m/s. At x = 4 the gap is h = 1 m. With γ = 0.5 the limit is 0.5 m/s, so the filter sends u* = 0.5. With γ = 1 it sends 1. With γ = 5 the limit is 5 m/s, more than the planner wants, so u* = 2 and the filter stays silent. In general u* = min(unom, γh).
How fast does the gap close? If the robot always drives right at the speed limit, then h(t) = h(0)e−γt. From a 2 m gap, one second later it is 1.213 m with γ = 0.5, 0.736 m with γ = 1 and 0.0135 m with γ = 5. A bigger γ lets you get close sooner.
The CBF rule for a wall is a speed limit γ(5 − x) that falls to zero at the wall. Left of each kink, the planner's 2 m/s is allowed. On the dotted line x = 4, the robot may drive 0.5, 1 or 2 m/s for γ = 0.5, 1 or 5.
Explain it to a 10-year-old
You ride your bike toward a wall, and the rule is: the closer you are, the slower you must go. Far away you can zoom. Near the wall you have to creep, and right next to it you have to stop. So you can get very close, but you never bump into it.
3. The CBF-QP is a projection with a closed form
Picture a field split by a straight fence. You stand on the wrong side and want the nearest spot on the right side. You walk straight at the fence, at right angles to it, and stop as soon as you reach it. That walk is the whole solution of the safety filter.
Name the data a = Lgh(x)T (a vector) and b = −γh(x) − Lfh(x) (a number). The constraint reads aTu ≥ b. In the space of inputs that is a half-space, the "right side of the fence". The cost is the squared distance to unom. So u* is the point of the half-space nearest to unom, its projection.
The KKT conditions from Day 10 give the answer. Stationarity says u* − unom = λa for a multiplier λ ≥ 0. Complementary slackness says λ = 0 unless the constraint is tight. Solving the two cases gives CO4A 12-1
λ = max(0, (b − aTunom) / ‖a‖2) u* = unom + λ·a
If unom already obeys the rule, λ = 0 and the command passes through untouched. Otherwise the filter adds just enough of a to land on the boundary. The CBF tutorial notes this closed form, the min-norm controller, follows from the KKT conditions. No solver is needed. Ames 2019
The correction always points along a = LghT, the direction in which the input raises h fastest. Next to an obstacle, that is straight away from it. Keep this in mind, because it explains the deadlock in Section 5.
The CBF-QP in the input plane (u1, u2) for the robot at x = (−2, 0.2) with γ = 1. The planner's unom = (1.00, −0.03) breaks the rule, so the filter moves it at right angles to the boundary, along a, to u* = (0.76, −0.01).
Here is a worked 2-D example that matches the widget. A point robot has ẋ = u, so f = 0 and g = I. A disk of radius 1 sits at the origin, so h = ‖x‖2 − 1, a = 2x and Lfh = 0. At x = (−2, 0.2) we get h = 3.04 and a = (−4, 0.4). The planner's unit vector toward the goal (4, 0) is unom = (0.9994, −0.0333), so aTunom = −4.011.
γ = 1: b = −3.04. The rule is broken, because −4.011 < −3.04. So λ = 0.971/16.16 = 0.0601 and u* = (0.759, −0.009). The robot slows from 1.00 to 0.76 m/s.
γ = 0.5: b = −1.52, λ = 0.154 and u* = (0.383, 0.028). It is slower still, and already steering up, away from the disk.
γ = 5: b = −15.2. The rule holds, so u* = unom.
In code, the closed form takes two lines. The CVXPY version handles several barriers or input limits, and its Parameters return in Section 6.
import numpy as np, cvxpy as cp
def cbf_filter(x, u_nom, gamma): # point robot, unit disk at 0
a, b = 2*x, -gamma*(x @ x - 1)
lam = max(0.0, (b - a @ u_nom) / (a @ a))
return u_nom + lam*a
cbf_filter(np.array([-2, .2]), np.array([.9994, -.0333]), 1.0)
# -> about [0.759, -0.009]
u = cp.Variable(2) # the same QP for a solver
un, a, b = cp.Parameter(2), cp.Parameter(2), cp.Parameter()
qp = cp.Problem(cp.Minimize(cp.sum_squares(u - un)), [a @ u >= b])
Try it: the widget starts at γ = 1 with the filter on. Drag the time slider and watch the two arrows: the planner's dashed unom and the solid u that the QP sends. Then try the γ buttons, switch the filter off, and press "Head-on start".
Notice: at γ = 1 the filter stays silent for 1.64 s, then bends the path so the robot passes 0.031 m from the disk and reaches the goal at 11.9 s. Without the filter the robot arrives at 10.0 s, but only by driving 0.75 m into the disk. At t = 3.0 s the planner asks for (1.00, −0.07) and the QP sends (0.45, 0.08) with λ = 0.192. On the chart, the filtered h(x) dips toward 0 but never below it.
Analogy
A safety filter is a strict but lazy copy editor. You hand in your sentence, and the editor checks one rule. If the sentence obeys it, it comes back untouched. If not, the editor makes the smallest change that fixes it and leaves everything else alone. The editor never rewrites your story, which is also why it cannot rescue a story that is heading the wrong way.
4. Adding a goal: the CLF-CBF QP
Picture adaptive cruise control. The driver sets 22 m/s, and then a slow truck appears ahead. Two wishes now collide: "drive at 22 m/s" and "keep a safe gap". The gap must win. The speed wish should give way gracefully, and come back once the road clears.
The "make progress" wish is written with a control Lyapunov function (CLF) V(x). It is an energy-like number that is zero at the goal and that the controller can always make decrease. Its rule mirrors the barrier rule: V̇ ≤ −cV, with c > 0. Ames and co-authors put both rules into one QP, the CLF-CBF QP: Ames 2017
H(x) is a positive definite weight on effort. The relaxation variable δ is a slack on the progress rule, and p > 0 is its price. Both constraints are linear in (u, δ), so this is still a QP.
Why does only the progress rule get a slack? If both rules were hard, they could contradict each other. Then no u satisfies both, and the QP is infeasible. With δ, the progress rule can always be met by paying for a large δ. So the QP has a solution whenever the safety rule alone does, and safety is never traded away. The paper also shows that this controller is Lipschitz continuous, which the safety theorem needs. Ames 2017
Now the paper's cruise-control numbers. The state is the follower's speed vf, the lead car's speed vl and the gap D. The hard rule is the "half the speedometer" headway D ≥ 1.8vf: a gap in metres of half your speed in km/h. So h = D − 1.8vf. The soft goal is V = (vf − 22)2, a desired speed of 22 m/s (79.2 km/h). Starting from (vf, vl, D) = (18, 10, 150), the car cruises at 22 m/s while the gap is large. When the headway rule binds, it settles to the lead car's speed. At 10 m/s the rule asks for a gap of at least 1.8 × 10 = 18 m. Ames 2017
The paper is honest about a catch. Without force limits, the commanded acceleration went past the comfort bounds drawn in its plot. But adding a bound on the wheel force can make the QP infeasible, because braking hard enough may no longer be possible. So the paper builds force-aware barrier functions that stay feasible under braking limits. Ames 2017
5. Tuning knobs and honest limits
γ is a "how late may I brake" knob. A small γ lets the margin shrink only slowly, so the filter brakes early and keeps a wide berth. A large γ lets the robot rush in and brake late. These are the widget's numbers from the default start (−4, 0.5):
Setting
Closest gap to the disk
Filter first acts
Reaches the goal
No filter
−0.750 m (inside)
never
10.0 s
γ = 0.5
0.172 m
at t = 0, 3.03 m away
13.3 s
γ = 1
0.031 m
at t = 1.64 s, 1.40 m away
11.9 s
γ = 5
0.0004 m
at t = 2.84 s, 0.21 m away
11.4 s
For a head-on approach at unit speed, the rule breaks once 2‖x‖ > γ(‖x‖2 − 1). So the filter wakes up at a distance (1 + √(1 + γ2))/γ − 1 from the surface: 3.24 m for γ = 0.5, 1.41 m for γ = 1 and 0.22 m for γ = 5.
One warning: the guarantee is for continuous time. A real controller holds u for a step dt, so keep γ·dt well below 1. The widget uses dt = 0.01 s and γ ≤ 10 (see the Going deeper box).
Next comes relative degree, which asks whether the input shows up in ḣ at all. Picture pressing a car's brake pedal. The car's position does not jump. Its speed changes first, and only then its position. If h depends only on position and the input is an acceleration, then ḣ contains no u at all. Lgh = 0, and the rule cannot be enforced through u. The number of times you must differentiate h before u appears is its relative degree. A plain CBF needs relative degree 1.
Take a point mass with position p, velocity v and acceleration input u. The obstacle barrier h = ‖p‖2 − 1 gives ḣ = 2pTv, with no u in it. One more derivative gives ḧ = 2‖v‖2 + 2pTu, where u appears, so the relative degree is 2. Two fixes are common. Fold speed into h, as the headway rule does: v̇f depends on the wheel force u, so ḣ = vl − vf − 1.8v̇f contains u. Or use an exponential (high-order) CBF, which puts a rule on h and its derivatives together. Ames 2019
Now three honest limits. First, h ≥ 0 is the promise, not h ≥ 5 cm. With γ = 5 the widget's robot skims the disk at 0.4 mm. The math is satisfied, but a real bumper would not be. Build the margin into h instead. For a 0.3 m margin, use h = ‖x − c‖2 − (r + 0.3)2.
Second, a filter is not a planner. Press "Head-on start" in the widget. The robot starts at (−4, 0), exactly on the line through the obstacle's centre. It creeps up to (−1, 0), touching the disk, and stays there. The cause is the direction of the correction. Here unom points straight at the centre and a = 2x points straight away from it, so the two are parallel. Adding λa can cancel the forward motion, but it cannot create a sideways one. This stuck state is a deadlock. Off the centre line, a has a small sideways part, and that part steers the default run around the disk. The fix belongs upstream: a planner that picks a side, as on Day 19.
Third, the guarantee is about the model. The proof assumes ẋ = f(x) + g(x)u holds exactly, and tyre slip, actuator delay or a slow control loop break that. The tutorial notes that noise and modelling errors might push the system out of C, and the CBF condition then drives it back. Ames 2019 In practice that means a margin inside h, a conservative γ, and robust CBF variants when the model is uncertain.
Going deeper (optional): why ḣ ≥ −γh keeps h ≥ 0, even with time steps
Continuous time: d/dt(eγth) = eγt(ḣ + γh) ≥ 0. So eγth(t) never decreases, and h(t) ≥ h(0)e−γt ≥ 0. For a general class-K α the same idea works through a comparison lemma.
Discrete time, for the widget's disk: h = ‖x‖2 − 1 is convex, so it lies above its tangent. One Euler step x+ = x + dt·u therefore gives h(x+) ≥ h(x) + dt·∇hTu ≥ (1 − γ·dt)·h(x). With γ·dt ≤ 0.1, each step keeps at least 90% of the margin, so h stays ≥ 0 at every sample. For a non-convex h or drift f ≠ 0 this tidy bound is gone, and you need a smaller dt or a discrete-time CBF.
Picture a clamp: z* = min(q, 1). At q = 0.5, nudging q moves z* by the same amount. At q = 2, the clamp holds z* at 1, and nudging q does nothing. That clamp is the solution of a tiny QP, and its slope (1 or 0) is exactly what backpropagation needs.
The QP is z*(q) = argminz ½z2 − qz subject to z ≤ 1. Its KKT conditions are z − q + λ = 0, λ(z − 1) = 0 and λ ≥ 0. Instead of differentiating a solver's steps, differentiate these equations at the solution. This is implicit differentiation:
dz + dλ = dq λ·dz + (z − 1)·dλ = 0
At q = 0.5 we have z = 0.5 and λ = 0. The second line forces dλ = 0, so dz/dq = 1. At q = 2 we have z = 1 and λ = 1. The second line forces dz = 0, so dz/dq = 0. Finite differences agree. An active constraint blocks the gradient.
The solution of the toy QP as a function of its data. Where the constraint is slack, the gradient passes through (slope 1). Where it is active, the gradient is zero. At the kink q = 1 there is no single slope, only a subgradient.
OptNet makes this a neural-network layer. The layer outputs zi+1 = argminz ½zTQz + qTz subject to Az = b and Gz ≤ w, where Q, q, A, b, G and w may come from the previous layer. (The paper writes h for w; we keep h for the barrier.) The backward pass differentiates the KKT system and gets gradients for all six inputs from one linear solve. That solve reuses the factorization that the interior-point solver (primal-dual card) has already computed, so the backward pass is almost free. Amos & Kolter 2017
Its batched GPU solver, qpth, solved 128 QPs of 100 variables and 100 inequalities in 0.18 s, against 4.7 s for Gurobi. The paper also learned the rules of 4×4 mini-Sudoku from examples alone. The limit is cost, which is cubic in the number of variables or constraints. The authors put the practical size below about 1,000 dimensions, and "substantially less" for real time. Amos & Kolter 2017 More on the OptNet paper card.
cvxpylayers removes the hand work. You write the problem in CVXPY with Parameters and wrap it as a PyTorch or TensorFlow layer. The problem must follow DPP (disciplined parametrized programming), CVXPY's rules for where parameters may appear. A parameter times a variable is fine. A product of two parameters times a variable is not, until you replace the product by one new parameter. DPP guarantees that the map from parameters to solver data is affine. Agrawal 2019
Every DPP problem then runs in the ASA form: an affine canonicalizer, a cone solver and an affine retriever. Its derivative is the chain rule through those three pieces. Caching the affine map cut canonicalization from 18.9 ms to 1.49 ms on a logistic-regression example. On a sparse QP with 1,024 variables it ran about 5× faster than qpth. Agrawal 2019 It first shipped with CVXPY 1.1. As of Oct 2026 the latest release is 1.2.0 (May 2026), so check the current API before copying 2019 code. PyPI 2026 See the cvxpylayers paper card.
Differentiable MPC applies the same trick to the controller from Day 17. The MPC becomes the last layer of a policy, and its cost and dynamics become learnable. Gradients come from the KKT conditions of the convex approximation at the solver's fixed point, instead of unrolling every iLQR iteration. The authors report that the backward pass is essentially free. Trained by imitation on a pendulum and a cartpole, it needed less data than a generic neural policy. Amos 2018
The CBF-QP of Section 3 fits here too. In the code above it is a DPP problem in unom, a and b, so a policy can be trained with its own safety filter inside the loop. Remember the clamp, though. Where the filter is active, the derivative of u* with respect to unom is I − aaT/‖a‖2. That matrix wipes out the gradient along a, so the policy gets no signal from pushing harder into the constraint.
7. Learning inside optimization: amortized solves and warm starts
Picture a commuter who drives the same road every day. They do not plan from a blank map each morning. Memory gives a near-perfect first guess, and they only correct for today's traffic. A robot is in the same position, because its MPC solves almost the same problem many times a second.
Amortized optimization learns that memory. A model ŷθ(x) maps the problem's context x (state, goal, obstacles) to an approximate solution of argminy f(y; x). Most of the work is paid once, at training time. Amos 2023 There are two flavours:
Fully amortized: one network pass gives the answer, and f is not touched at run time.
Semi-amortized: the model runs some solver steps inside. Examples are unrolled gradient steps, learned versions of ISTA (ISTA card), and RLQP, which keeps the OSQP solver inside.
Training can regress onto solved examples, minimizing E‖ŷθ(x) − y*(x)‖2. Or it can minimize the objective itself, E f(ŷθ(x); x), which needs no labels. Amos 2023
The safest use of a prediction is as a warm start, the solver's first guess. Here is why that helps, in numbers. Run gradient descent (Day 6) on f = ½xTQx − bTx with Q = diag(1, 10) and b = (1, 10), so x* = (1, 1). Use step 0.1 and stop when ‖x − x*‖ ≤ 10−6. From x = 0 it takes 132 iterations. From a guess 0.01 off in the slow direction it takes 88, and from 10−4 off it takes 44. Each 100× better guess saves 44 iterations, because the error shrinks by 0.9 per step and 0.944 ≈ 1/100.
On Day 17 the warm start was the previous solution, shifted by one step. A learned warm start replaces or improves that guess. Either way the solver still enforces the constraints, which a network alone cannot promise.
Where does this sit in a driving stack? Each piece of today has a natural place:
Layer
What the optimizer does
Today's tool
Planner or policy (possibly learned)
Proposes the command unom or a trajectory
MPC (Day 17), warm-started or amortized
Safety filter
Edits the command as little as possible so the safety rules hold
CBF-QP: closed form for one rule, a QP solver such as OSQP for several
Training (offline)
Tunes costs, models or policies through the optimizer
OptNet, cvxpylayers, differentiable MPC
Keep the claims in proportion to the evidence. The automotive examples in these papers are adaptive cruise control and lane keeping. They were shown in simulation and on small Khepera mobile robots, not on road cars, and the tutorial frames them as driver-assistance examples. Ames 2019 The differentiable-MPC results are on a pendulum and a cartpole. Amos 2018 None of today's sources describes a production vehicle. Treat these as well-founded design patterns, not as a description of any car on the road.
Common misunderstandings
"A CBF keeps a safety margin." It guarantees h ≥ 0, not h ≥ some ε. With γ = 5 the widget's robot passes within 0.4 mm. Put the margin inside h, for example ‖x − c‖2 − (r + 0.3)2.
"The CBF-QP always has a solution." One rule with no input limits always does. With force limits or several barriers, the half-spaces may not overlap, and the QP is infeasible. That is why the cruise-control paper builds force-aware barriers. Softening the CBF with a slack restores feasibility, but it also gives up the guarantee.
"The filter will steer around obstacles." It only adds a push along a = LghT. On the centre line that push is parallel to unom, and the robot freezes at (−1, 0). Route choice belongs to the planner.
"A differentiable layer is free." OptNet-style layers cost cubic time in the problem size. Their gradients are zero through active constraints and undefined at kinks, like q = 1 in the clamp. Amos & Kolter 2017
"A well-trained network's solution is safe." Amortized predictions carry no feasibility guarantee. Use them as warm starts for a solver that checks the constraints, or pass them through a safety filter.
Check yourself
Q1. What does the CBF-QP minimize at each control step?
The filter's job is to edit the planner as little as possible, so the cost is the squared change. Minimizing ‖u‖2 would ignore what the planner wanted and would happily stop the robot. Safety lives in the constraint, not in the cost.
Q2. A robot has ẋ = u and a wall at x = 5, so h = 5 − x. With γ = 1, the planner asks for unom = 2 m/s at x = 4. What does the filter send?
The rule ḣ ≥ −γh becomes u ≤ γh = 1 × 1 = 1. The planner's 2 m/s breaks it, so the projection gives exactly 1. You would get 2 m/s with γ = 5, where the limit is 5 m/s. Stopping or reversing would change the command more than needed.
Q3. In the widget, you raise γ from 1 to 5. What happens?
γ is how fast h may shrink. With γ = 5 the filter wakes up 0.21 m from the disk instead of 1.40 m, so the robot skims the edge and arrives 0.5 s sooner. It still never enters: h ≥ 0 holds for every γ > 0.
Q4. Why does the CLF-CBF QP put the slack δ on the CLF rule but not on the CBF rule?
Two hard rules can contradict each other, and then the QP has no solution. The slack lets the progress rule bend at a price p·δ2, so safety never has to. Both rules are linear in u, and the QP is convex with or without δ.
Q5. The robot starts at (−4, 0), heading straight through the obstacle's centre toward (4, 0), with the filter on. What happens?
On the centre line, a = 2x points straight back along unom. Adding λa can only cancel forward motion, so the robot slows to a stop at the edge: a deadlock. The guarantee still holds (h ≥ 0), and λ is never negative. Choosing a side is a planner's job.
Q6. How does OptNet compute gradients through a QP layer?
The solution satisfies the KKT equations, so implicit differentiation of those equations gives exact gradients from one linear solve with a matrix that is already factored. Unrolling the iterations also works, but it costs memory and only approximates the answer. Differentiable MPC avoids it for the same reason.
Recap: things to remember
A safety filter solves min ½‖u − unom‖2 subject to the CBF rule at every step. It leaves safe commands untouched and edits unsafe ones minimally.
The rule ḣ ≥ −γh means "approach, but slow down near the edge". It is linear in u for control-affine systems, and it keeps h ≥ 0, because h can shrink no faster than h(0)e−γt.
With one rule, the KKT conditions give u* = unom + λa with λ = max(0, (b − aTunom)/‖a‖2): a half-space projection. The CLF-CBF QP adds a goal with a slack, while safety stays hard.
Know the limits: no margin unless you put it in h, deadlock on the centre line, model error, relative degree, and infeasibility under input limits. γ trades margin (0.172 m at 0.5) for speed (0.0004 m at 5).
Implicit differentiation of the KKT conditions (OptNet, cvxpylayers, differentiable MPC) puts solvers inside networks. Amortized models put networks inside solvers, best as warm starts behind a constraint-checking solver.
Control Barrier Functions: Theory and Applications, Aaron D. Ames, Samuel Coogan, Magnus Egerstedt, Gennaro Notomista, Koushil Sreenath, Paulo Tabuada, European Control Conference 2019, pp. 3420–3431; arXiv 1903.11199 (accessed 2026-10-26).
Tutorial on Amortized Optimization, Brandon Amos, Foundations and Trends in Machine Learning 16(5):592–732, 2023; arXiv 2202.00665 (accessed 2026-10-26).
Week 3 · Day 21
Solvers in practice & what's next
After today you can pick a modelling tool and a solver for a given problem, diagnose the usual failures (infeasible, unbounded, inaccurate, too slow), and plan what to study next.
About 60 min · Needs Days 5, 12, 13 and 17 · No CO4A chapter (new material)
Today's big idea
You will rarely write a solver yourself. You name the problem's class, write the model in a modelling tool, and hand it to a solver built for that class. Then you do the part no solver does for you: scale the data, read the status, check the answer, and plan for the day it fails.
1. Classify first: the class picks the solver
Analogy
When you are ill you can see a general doctor or a specialist. The specialist is faster and more reliable, but only for their speciality. Solvers work the same way. OSQP specializes in quadratic programs. SCS is a generalist: CVXPY's docs say it handles every class "except mixed-integer". CVXPY docs
So the first job is to name your problem's class exactly. Day 5 built the ladder LP ⊂ QP ⊂ SOCP ⊂ SDP, where each class contains the ones before it. Two labels sit beside the ladder. Add "MI" (mixed-integer) if any variable must be an integer, as on Day 15. Say "NLP" (nonlinear program) if some function is smooth but not convex, as on Day 16.
The problem ladder of Day 5 with solvers that fit each class. A QP solver can solve an LP, but the specialist for the narrowest class is usually faster. Integers and nonconvex functions (right) need other families.
Pick the narrowest class that fits. A QP solver expects exactly one shape. Here is OSQP's standard form: OSQP docs
minimize ½xTPx + qTx subject to l ≤ Ax ≤ u
Here x ∈ ℝn holds the decision variables. P ⪰ 0 is the curvature of the cost and q its linear part. The rows of A, with lower bounds l and upper bounds u, hold every constraint. An equality is a row with li = ui, and a one-sided limit uses li = −∞.
Now a worked example. Take a vehicle MPC like Day 17's, with 10 states, 3 inputs and a horizon of 20 steps. It has (10 + 3) × 20 = 260 variables and 10 × 20 = 200 dynamics equalities. A quadratic cost with box limits makes it a QP. It must be re-solved at 100 Hz, which leaves 10 ms per solve on an embedded computer. That calls for a sparse QP solver with warm starts and C code, such as OSQP through CVXPYgen or HPIPM inside acados. Schaller 2022acados docs
2. The modelling layer: who writes the matrices
You could type P, q, A, l and u by hand. For a 260-variable MPC that means thousands of numbers, and one index slip silently changes the problem. A modelling tool lets you write the math almost as on paper and builds the matrices for you, the way a compiler turns readable code into machine code.
The translation step is called canonicalization: rewriting your model into a solver's standard form. Good tools also check your model on the way. CVXPY checks convexity, and CasADi computes derivatives.
What happens inside prob.solve(). You write the model. The modelling tool checks it and rewrites it into the solver's standard form. The solver returns a point x, multipliers y and a status. The dashed loop back is your job (Section 5).
CVXPY (Python) checks convexity with disciplined convex programming (DCP). You build expressions from atoms whose curvature it knows: sum_squares is convex, log is concave. You combine them by rules that keep convexity. If the rules cannot prove your model convex, CVXPY refuses to solve it, even when the model happens to be convex. CVXPY docs
Disciplined parametrized programming (DPP) adds parameters: data that changes between solves, such as the robot's current state. If the model follows the DPP rules, CVXPY canonicalizes once and re-uses that work. With warm_start on, which is the default, the solver can also re-use its matrix factorization. In the docs' example (m = 2000, n = 1000) the second solve drops from 11.14 s to 2.95 s. CVXPY docs
import cvxpy as cp, numpy as np
A = np.array([[1., 2.], [3., 1.]])
b = cp.Parameter(2) # data that changes every tick
x = cp.Variable(2)
cons = [x >= 0]
prob = cp.Problem(cp.Minimize(cp.sum_squares(A @ x - b)), cons)
print(prob.is_dcp(), prob.is_dpp()) # True True
b.value = np.array([1., -1.])
prob.solve(solver=cp.CLARABEL)
print(prob.status, x.value) # optimal, x ≈ [0, 0.2]
b.value = np.array([1., 2.]) # next tick: only b changes
prob.solve(solver=cp.CLARABEL) # x ≈ [0.6, 0.2]
Check the numbers. Without the bound, the best x would be A−1b = (−0.6, 0.8), which breaks x ≥ 0. So the solver returns x* = (0, 0.2) with cost 1.8. For the next tick, b = (1, 2), the unconstrained answer (0.6, 0.2) is already feasible and the cost is 0.
Four other tools cover most robotics work. Pick by language and by whether your model is convex.
Tool
Language
Best at
Worth knowing
CVXPY
Python
Convex models checked by DCP; parameters, C code (CVXPYgen), differentiable layers (Day 20)
Every solver walks toward the answer, but with different strides. Picture crossing a city. An interior-point method takes a taxi: a few long, expensive rides, each landing very close to the target. A first-order method walks: many cheap steps that start fast but take a while over the last metre. An active-set method guesses which walls you are touching and corrects the guess.
solve time = (number of steps) × (cost of one step)
Interior point wins the first factor and first-order methods win the second. The OSQP paper reports it is "typically ten times faster than competing interior-point methods" on its benchmarks, but by default it stops at moderate accuracy. Clarabel's authors report it is faster and more robust than the solvers they compared, especially when the objective is quadratic. Stellato 2020Goulart & Chen 2024 See the primal–dual IPM card, the ADMM card and the OSQP paper.
The car's computer cannot run Python, so you need code generation. It writes a small C solver for one problem family, once. On the robot you pass new parameter values each tick, with no parsing and no memory allocation. CVXPYgen does this for any DPP model in CVXPY, with OSQP, SCS or ECOS underneath. OSQP, acados and CasADi can also emit C code. Schaller 2022CasADi
Here are the CVXPYgen paper's numbers. On a portfolio back-test the generated code was 6× faster than CVXPY at problem size N = 10 and 2.5× faster at N = 100. Including the time to generate and compile, it broke even after about 5,000 solves. A 4-year daily back-test over 100 hyper-parameter settings is 250 × 4 × 100 = 100,000 solves, far past that point. The authors also flew a 14 × 14 cm quadcopter with MPC at 30 Hz on an Intel Atom. Schaller 2022
Try it: choose a problem class, a size and a time budget. The widget looks up this lesson's mapping table and lists modelling tools and solvers, best first, each with a reason, a source and the day to revisit. The size cut-offs are rules of thumb, not sharp limits.
Notice that the default, a small QP with a real-time budget like the 260-variable MPC of Section 1, puts OSQP with CVXPYgen C code first, then qpOASES, HPIPM inside acados and DAQP, and sends you back to Days 13 and 17. Switch the class to SDP and the first line becomes "Keep SDPs out of the loop".
Explain it to a 10-year-old
Choosing a solver is like choosing how to travel. For a short trip you will repeat every day, you ride the same bike and know every turn. For a long trip once a year, you take the train and don't mind the wait. You don't take a plane to the corner shop, and you don't cycle across the ocean.
4. Three knobs: scaling, tolerances and warm starts
Before comparing prices from three countries, you convert them to one currency. Solvers want the same thing: numbers of similar size. A model that mixes metres with micrometres, or newtons with kilonewtons, has entries that differ by a factor of 106. Iterative solvers then crawl, and a tolerance no longer means the same thing for every constraint.
Scaling, also called equilibration, multiplies rows and columns by positive numbers so that all entries are about 1. OSQP solves a scaled copy of your QP: Stellato 2020
P̄ = cDPD, q̄ = cDq, Ā = EAD
Here D and E are positive diagonal matrices and c > 0 rescales the cost. The scaled answer maps back to yours by undoing D and E, so nothing is lost. OSQP picks D and E by a modified Ruiz equilibration. It repeatedly divides each row and column of the KKT matrix by the square root of its largest entry. The default runs 10 passes (scaling = 10). OSQP settings
Here is a number. Take P = diag(100, 0.01) and one constraint row A = [1 1]. The condition number measures how much rounding errors can grow; you met it as κ on Day 6. For this KKT matrix it drops from 100 to 1.15 after a single pass with D = (0.1, 1, 1).
One pass of Ruiz equilibration on the KKT matrix [P AT; A 0] for P = diag(100, 0.01), A = [1 1]. Row 1 and column 1 are divided by √100 = 10, which changes the shaded cells. The condition number falls from 100 to 1.15, so rounding errors and tolerances behave far better.
Iterative solvers never land exactly on the optimum. They stop when the leftover errors, the residuals, are small enough. So "optimal" really means "optimal to about 10−3", and you choose the size of that "about". That threshold is the tolerance. For the primal residual, OSQP stops when Stellato 2020
‖Ax − z‖∞ ≤ εabs + εrel·max(‖Ax‖∞, ‖z‖∞)
Here z is OSQP's copy of Ax that already satisfies l ≤ z ≤ u, so Ax − z measures how far the constraints are violated. εabs is an absolute floor, and εrel adds a part that grows with the size of the numbers. A similar test covers the dual residual. OSQP's own defaults are εabs = εrel = 10−3, with up to 4,000 iterations. OSQP settings
A worked example: suppose Ax = (3.0, −250.0) and z = (3.0005, −250.1). The residual is 0.1. The threshold is 0.001 + 0.001 × 250.1 = 0.2511, so OSQP reports "solved" while one constraint is off by 0.1. The relative part dominated because one value was 250, which is one more reason to scale. Defaults also differ between interfaces: as of Oct 2026, CVXPY's docs list eps_abs = 10−5 for OSQP, against OSQP's own 10−3. Always print the tolerances you actually ran with. CVXPY docs
A robot re-solves almost the same problem every tick: the state moved a little and the obstacles barely changed. A warm start starts the solver from last tick's answer, shifted one step along the horizon. It helps in two separate ways. A better first guess means fewer iterations. And if the matrices did not change, factorization caching re-uses the expensive matrix factorization, so only the vectors are new.
The numbers: Day 20's gradient-descent example needed 132 iterations from a cold start, 88 from a guess 10−2 off, and 44 from a guess 10−4 off. CVXPY's example saved about 8.2 s of 11.14 s from caching alone. Interior-point methods gain less from a good first guess. They work best from a well-centred point far from the boundary, and last tick's answer sits right on it. CVXPY docs
5. When it fails: statuses, certificates and your own KKT check
A solver always answers, but not always with "here is x". Treat the status as part of the answer. OSQP's list is typical: solved; solved inaccurate, which means only tolerances 10× looser were met; primal infeasible; dual infeasible (unbounded); maximum iterations; time limit; and non-convex. OSQP warns that it "may not detect non-convexity reliably". CVXPY reports the inaccurate case as optimal_inaccurate. OSQP status values
Use this table as a first-aid kit.
Symptom
Usual cause
First thing to try
Infeasible (primal infeasible)
Constraints contradict, e.g. a deadline the speed limit cannot meet, a sign error, or mixed units
Read the certificate: its nonzero entries name the conflicting constraints. Soften them with slack variables and a penalty (Day 4).
Unbounded (dual infeasible)
A missing limit lets the cost fall forever, e.g. a reward on progress with no speed limit
Add the physical limits; check the sign of the objective.
Inaccurate (solved inaccurate, max iterations)
Poor scaling, or a problem that is nearly infeasible
Fix units, raise the iteration limit, turn on OSQP's polishing, or switch to an interior-point solver such as Clarabel.
Too slow
Wrong class or solver, or the model is rebuilt every tick
Use parameters (DPP) and warm starts, generate C code, or shorten the horizon. Use GPUs only for huge problems.
DCP error in CVXPY
The rules cannot prove the model convex
Rewrite it with DCP atoms (Day 4), or move to an NLP tool (Day 16).
Polishing is an optional OSQP clean-up step, off by default. It guesses which constraints are active and solves one small linear system for a more accurate answer. OSQP settings In a control loop, every status other than solved needs a planned fallback, such as last tick's plan shifted by one step, or a safe stop. Never send an unchecked x to the actuators.
A good solver doesn't just say "infeasible". It hands you a proof that you can check with one matrix product, like a referee who shows you the rule that was broken. This is Day 9's duality at work. When the primal has no feasible point, the dual can be pushed to +∞ along some direction, and that direction is a certificate of infeasibility.
For constraints Ax = b, x ≥ 0, Farkas' lemma says that exactly one of two things holds: MOSEK Cookbook
(1) some x ≥ 0 has Ax = b, or (2) some y has ATy ≤ 0 and bTy > 0
The one-line reason why (2) rules out (1): if both held, then bTy = xT(ATy) ≤ 0, because x ≥ 0 and ATy ≤ 0. That contradicts bTy > 0.
Here is the MOSEK Cookbook's example. The constraints are x1 + x2 + 2x3 = 1, −2x1 − x2 + x3 = −0.5, −x1 + 5x3 = −0.1, and x ≥ 0. Take y = (1, 2, −1): add row 1, twice row 2, and minus row 3. The result is −2x1 − x2 − x3 = 0.1, that is, ATy = (−2, −1, −1) and bTy = 0.1. With x ≥ 0 the left side can never be positive, so no feasible x exists. MOSEK Cookbook
OSQP's form l ≤ Ax ≤ u has the same kind of proof: a y with ATy = 0 and uTmax(y, 0) + lTmin(y, 0) < 0. SCS and Clarabel also detect infeasibility. Stellato 2020SCS docs
Even "solved" deserves a check, and it takes a few lines. On Day 10 you met the KKT conditions. For a convex problem, any point that passes them is optimal, so they make a complete test. For minimizing f(x) subject to x ≥ 0, with a multiplier λ, they read:
b.value = np.array([1., -1.]) # the first tick of Section 2
prob.solve(solver=cp.CLARABEL)
x_, lam = x.value, cons[0].dual_value
grad = 2 * A.T @ (A @ x_ - b.value) # ∇f(x) for f = ‖Ax − b‖²
print(np.abs(grad - lam).max()) # stationarity: want ≈ 0
print(-x_.min(), -lam.min()) # signs: want ≤ about 0
print(abs(lam @ x_)) # complementarity: want ≈ 0
Do it by hand at x* = (0, 0.2). Then Ax − b = (0.4 − 1, 0.2 + 1) = (−0.6, 1.2), so ∇f = 2AT(Ax − b) = (6, 0). Stationarity forces λ = (6, 0), which is ≥ 0. Complementarity holds, since 6 × 0 = 0 and 0 × 0.2 = 0. The multiplier also has a meaning: loosening x1 ≥ 0 to x1 ≥ −δ would lower the cost by about 6δ. A solver's residuals should be near its tolerance; if one is far larger, distrust the answer.
Common misunderstandings
"An NLP solver is the safe choice, since it handles everything." IPOPT and SNOPT treat a convex problem "as general nonlinear", as Drake's docs put it. You give up the certificates and robustness a conic solver offers. Drake docs
"OPTIMAL means exact." It means optimal to a tolerance. OSQP's default 10−3 is fine for MPC and loose for science, and "solved inaccurate" is 10× looser still. Report the tolerance with the answer. OSQP status values
"A GPU solver is always faster." HiGHS itself says its PDLP on a CPU is "unlikely to be competitive". GPUs pay off on very large sparse problems, not on a 10 ms MPC. HiGHS docs
"Warm starts always help." Factorization caching needs unchanged matrices. If A is a parameter, only the first guess helps, and interior-point methods gain little from that. CVXPY docs
"Infeasible means the solver is broken." Usually the model is. Read the certificate, check units and signs, and keep a fallback in the control loop for infeasible, max-iteration and time-limit outcomes.
6. The frontier, as of Oct 2026
Picture a factory with 10,000 workers. A job that splits into 10,000 independent pieces finishes fast. A job where each step waits for the one before leaves most workers idle. A GPU is that factory. Interior-point and simplex methods depend on sparse factorizations, which are the second kind of job. A matrix–vector product is the first kind.
Why first-order methods suit GPUs. An interior-point step factorizes one big sparse matrix (left icon: a triangular factor), a chain of dependent operations. A PDHG step multiplies by the constraint matrix K and its transpose, and every row can be computed at once on its own GPU core (right icon).
PDHG (primal–dual hybrid gradient) is a first-order method that needs only such products. PDLP is PDHG tuned for LPs, with restarts and preconditioning. Its 2025 journal version took on 11 huge LPs with 125 million to 6.3 billion nonzeros. PDLP solved 8 of them to a 1% gap within 6 days, while Gurobi's barrier solved 3 within a 1 TB memory limit. Applegate 2025
The cuPDLP.jl paper moved the whole method onto one GPU. On an NVIDIA H100, at tolerance 10−4 and without presolve, it was 3× faster than Gurobi on medium and 3.7× on large LP relaxations from the MIPLIB benchmark. With Gurobi's presolve it solved 381 of 383 of them. At 10−8 it still trailed Gurobi's barrier. A GPU run also carries a fixed overhead of about a second, so small problems gain nothing. Lu & Yang 2025
Industry adopted the idea quickly. As of Oct 2026:
HiGHS ships cuPDLP-C as its "pdlp" solver, which runs on NVIDIA GPUs. HiGHS docscuPDLP-C 2023
Gurobi 13.0 added PDHG for LP with an optional GPU build. The GPU version "matured from the beta state" in 13.0.2. Gurobi 13 notes
NVIDIA cuOpt (docs version 26.10) runs GPU PDLP, a GPU barrier and CPU dual simplex at the same time. cuOpt docs
For QPs and cones: OSQP 1.0 merged a CUDA backend (cuOSQP), CuClarabel runs interior point on a GPU, and SCS has a cuDSS GPU backend. OSQP releasesCuClarabel 2024SCS docs
Going deeper (optional): the PDHG update
Write the LP as a saddle-point problem with L(x, y) = cTx − yTKx + qTy. PDHG alternates one primal and one dual step, with step sizes τ and σ: Lu & Yang 2025
Each projection just clips onto simple bounds, so the only heavy work is one product with KT and one with K. The term 2x⁺ − x extrapolates the primal step, which keeps the method stable. PDLP adds diagonal preconditioning, adaptive restarts, adaptive step sizes, primal-weight updates and infeasibility detection.
The second trend is learning to optimize. A robot solves nearly the same problem 100 times a second, so why not learn the map from situation to solution? Amortized optimization trains a model that predicts solutions across many related problems. The prediction is used directly or as a warm start. Day 20 covered the other direction: optimization layers you can differentiate (OptNet, cvxpylayers). Predictions carry no feasibility guarantee, so in a safety-critical loop use them only as warm starts for a solver that still checks the constraints. Amos 2023
Third, convex pieces at scale. GCS (Day 19) plans through a graph of convex sets with one convex program. A 2024 follow-up restricts the safe sets to boxes and gives up GCS's optimality bound for speed. A quadrotor flew through a village split into 10,150 boxes. After 101 s of offline work, finding the box path took 0.22 s and smoothing it 7.5 s. It is built on CVXPY and Clarabel, the tools of today's lesson. Marcucci 2024 See the safe-boxes paper.
Versions move fast. Here is what PyPI listed as of Oct 2026. PyPI
Package
Version (as of Oct 2026)
Uploaded
cvxpy
1.9.3
2026-09-19
osqp
1.1.3 (1.0.0 was 2025-03-23)
2026-06-12
clarabel
0.11.1
2025-06-11
scs
3.3.1
2026-09-05
highspy (HiGHS)
1.15.1
2026-07-02
casadi
3.8.1
2026-09-16
cvxpygen
1.0.2
2026-10-22
7. The course in one page, and where to go next
Twenty-one days fit on one page. Each row links back to its lesson.
Drake's GcsTrajectoryOptimization; an acados NMPC on a bicycle model
Keep CO4A open as your reference. It covers the theory of Weeks 1 and 2 in full, including the proofs this course moved into optional boxes. When a solver surprises you, the answer is usually in one of three places: the problem class, the scaling, or the duality behind its status.
Check yourself
Q1. A 260-variable MPC QP must be solved at 100 Hz on a car's embedded computer. What is the best first choice?
It is a small sparse QP re-solved every 10 ms, so you want a QP specialist that warm-starts and compiles to C. An NLP solver ignores the QP structure and Python adds overhead. GPU solvers carry a fixed overhead that only pays off on huge problems.
Q2. You write an SOCP in CVXPY and call prob.solve() without naming a solver. Which solver does CVXPY pick by default (as of Oct 2026)?
CVXPY calls the solver most specialized to the problem: Clarabel for SOCPs, OSQP for QPs, and SCS as the catch-all. OSQP cannot handle second-order cones. ECOS is an embedded SOCP solver you can choose, but it is not the default, and Gurobi is commercial and not shipped with CVXPY.
Q3. For the constraints Ax = b, x ≥ 0, a solver returns a vector y with ATy ≤ 0 and bTy > 0. What does y prove?
Combine the equations with weights y: (ATy)Tx = bTy. For x ≥ 0 the left side is at most 0, but the right side is positive, so no feasible x exists (Farkas). Unboundedness needs a different certificate, a direction along which the cost falls forever.
Q4. OSQP runs with εabs = εrel = 10−3, and ‖Ax‖∞ ≈ 250. Roughly how large a primal residual can it accept and still report "solved"?
The threshold is εabs + εrel·max(‖Ax‖∞, ‖z‖∞) ≈ 0.001 + 0.001 × 250 ≈ 0.25. The absolute part 0.001 alone would apply only if all values were near zero. Large raw values are one more reason to scale your units.
Q5. Between ticks your MPC changes only the initial state; the matrices stay fixed. Why does warm starting help so much here?
Unchanged matrices mean the expensive KKT factorization can be cached, and only vectors change. The shifted previous solution is also close to the new one, so fewer iterations are needed. Tolerances and checks stay the same.
Q6. A planning LP for a whole delivery network has 109 nonzeros. Which approach is the most promising as of Oct 2026?
At that size, factorizations run out of memory. PDLP solved LPs with up to 6.3 billion nonzeros using only matrix–vector products, and GPU versions now ship in HiGHS, Gurobi 13 and cuOpt. ECOS and qpOASES are built for small embedded problems, and a dense matrix of that size would not fit in memory.
Recap: things to remember
Classify first: LP ⊂ QP ⊂ SOCP ⊂ SDP, plus MI for integers and NLP for smooth nonconvex functions. The narrowest class that fits picks the solver family.
Write the model in a modelling tool: CVXPY (DCP, DPP) for convex models, CasADi for nonlinear ones, Drake for robotics. Use parameters and warm starts for repeated solves, and code generation for embedded targets.
Interior point takes few, accurate steps. First-order methods take many cheap steps, warm-start well and scale to GPUs. Active-set methods suit small, warm-started MPC QPs.
Scale your units, print your tolerances, read every status, and check the KKT residuals yourself. An infeasibility certificate is a proof you can verify with one matrix product.
As of Oct 2026, GPU first-order solvers win on huge LPs, not on small real-time problems.
Embedded Code Generation with CVXPY, Maximilian Schaller, Goran Banjac, Steven Diamond, Akshay Agrawal, Bartolomeo Stellato, Stephen Boyd, IEEE Control Systems Letters 6:2653–2658, 2022 (accessed 2026-10-26).
One card per algorithm, covering what it does in one sentence, when to use it, the update rule, how fast it converges, what each step costs, and the usual pitfalls. Each card links to the day where you can watch it run. Cards are in course order.
Day 6 · first-order
Gradient descent
Repeatedly steps downhill, against the gradient, to minimize a smooth function.
In one sentence
Feel the slope where you stand, take a step downhill whose length is the step size times the steepness, and repeat until the ground is flat.
When to use it
f is smooth: its gradient ∇f does not change too fast. Formally ∇f is L-Lipschitz: the slope changes by at most L per unit of distance.
Many variables. Each step needs one gradient and O(n) memory, so millions of variables are fine.
Moderate accuracy, or a nearly round bowl (well conditioned).
Not for kinks such as |x| or ‖x‖1: use the subgradient or proximal gradient card. Not for long, narrow valleys where you need high accuracy: Newton or BFGS take far fewer steps there.
The update
xk+1 = xk − t∇f(xk)
t > 0 is the step size. CO4A 6-1 Example: f(x, y) = ½(x2 + 10y2) at (10, 1) has ∇f = (10, 10). With t = 0.1 the next point is (9, 0). Backtracking picks t for you. It starts at t = 1 and shrinks t by a factor β until f drops by at least a fraction α of what the slope predicts. Boyd and Vandenberghe suggest α between 0.01 and 0.3 and β between 0.1 and 0.8. Boyd & Vandenberghe 2004
x ← x0
repeat
g ← ∇f(x)
if ‖g‖ ≤ tol: stop
t ← 1 # backtracking
while f(x − t·g) > f(x) − α·t·‖g‖²:
t ← β·t # shrink the step
x ← x − t·g
Bigger is not faster. On the example above (L = 10), reaching f ≤ 10−6 takes 85 steps at t = 0.1 and 45 at t = 2/11. At t = 0.2 = 2/L it never settles, and at t = 0.21 it blows up.
Zig-zag is normal in a stretched bowl. It is the condition number κ talking, not a bug.
The O(1/k) bound is a worst case. On the example it promises 505/k, which would need 5 × 108 steps for 10−6. The real run needs 85.
See it run
Open Day 6: the gd2d widget, pick κ and a step rule, and watch the zig-zag. Related cards: SGD (cheap noisy steps), FISTA (acceleration to 1/k2) and Newton (uses curvature).
Sources
CO4A 6-1 Gradient descent, 6-3-1, 6-3-3, 6-3-4 and 6-3-6 (convergence pages), CO4A team (accessed 2026-10-26).
Gradient descent that uses the gradient of one random data term per step instead of the whole sum.
In one sentence
Instead of surveying the whole town before every step, ask one random passer-by for directions: each answer is cheap and noisy, but on average it points the right way.
When to use it
The objective is a sum of m terms, f(x) = Σi fi(x), one per data point, and m is large. Training a model on many lane-marking images is a typical case.
You want fast early progress and low accuracy is fine. SGD does well far from the optimum. CMU 10-725 2016
Not when you need a precise answer: it struggles near the optimum. CO4A 8-2-4 For small m, use full gradients (gradient descent) or L-BFGS.
The update
xk = xk−1 − tk∇fik(xk−1)
The index ik is drawn at random (the usual choice) or taken in a fixed cycle. m stochastic steps cost about as much as one full-gradient step. CO4A 6-5 Example: f(x) = Σ ½(x − ai)2 with a = (1, 2, 3, 6) has its minimum at the mean, x* = 3. Cyclic SGD with a fixed t = 0.25 from 0 never settles: after 200 passes it still visits 2.94, 2.70, 2.78, 3.58. With tk = 1/k each iterate is the running mean of the ai seen so far, and it lands on 3.
x ← x0
for k = 1, 2, …
i ← random index in 1…m # or cycle 1, 2, …, m
t ← t0 / k # shrinking step
x ← x − t·∇f_i(x)
How fast, and at what cost
Setting
Rate
Cost per step
Convex, each term G-Lipschitz, fixed t
Only gets close: the cyclic version ends within 5m2G2t/2 of f* CO4A 8-2-2
Random order: O(m2G2/ε2) in expectation. Cyclic: O(m3G2/ε2) CO4A 8-2-3
Same
G bounds each term's (sub)gradient; the rates come from the stochastic subgradient method. "In expectation" means on average over the random choices, not for every run. CMU 10-725 2016
Pitfalls
A fixed step never settles. It hovers around the optimum, as in the toy example. Shrink tk to converge.
f does not drop every step. A single term's gradient is noisy and can point the wrong way.
Count epochs, not steps. One pass of m SGD steps costs about one gradient-descent step.
Like gradient descent, but steps along any subgradient, so it works on convex functions with kinks.
In one sentence
At a kink there is a whole fan of slopes whose lines fit under the graph; pick any one, step against it, and remember the best point you have seen.
When to use it
f is convex but has kinks (a maximum of linear pieces, ‖x‖1, a hinge loss), and one subgradient is cheap to compute.
Huge problems that need only low accuracy, and dual problems (dual ascent, the Lagrangian bounds of Day 15).
An easy-to-project constraint set C (a box, a ball, x ≥ 0)? Use the projected version.
Not when f is smooth plus a simple kink, as in the lasso: proximal gradient is far faster. Not when you need high accuracy.
The update
A subgradient g of f at x satisfies f(y) ≥ f(x) + gT(y − x) for every y. For |x| at 0, any g in [−1, 1] works. CO4A 7-1 The set of all of them is the subdifferential ∂f(x).
xk = xk−1 − tkgk−1, gk−1 ∈ ∂f(xk−1)
A step can raise f, so you keep the best value fbest. CO4A 8-1 Step sizes are fixed or shrinking (for example tk = 1/k), set in advance rather than by line search. CO4A 8-1-1 Example: f = |x| from x0 = 1 with t = 0.3 gives 0.7, 0.4, 0.1, −0.2, 0.1, −0.2, … forever, with fbest = 0.1.
x ← x0; best ← x0
for k = 1, 2, …
g ← any subgradient of f at x
t ← t0 / k # pre-set, no line search
x ← x − t·g # projected: x ← P_C(x − t·g)
if f(x) < f(best): best ← x
return best
k ≥ R2G2/ε2: O(1/ε2) steps. R = G = 1, ε = 0.01 needs 10,000 CO4A 8-1-4
Same
Pitfalls
It is not a descent method. Return fbest, not the last point.
A fixed step does not reach f*. The |x| run above stalls at 0.1, under the ceiling G2t/2 = 0.15.
A kink is not automatically a minimum. x* is optimal exactly when 0 ∈ ∂f(x*). CO4A 7-3-1 max(0.5x, 2x − 1.5) has a kink at 1 with ∂f(1) = [0.5, 2], which does not contain 0.
Takes a gradient step on the smooth part of the objective, then a cheap "prox" step that handles the kinky part exactly.
In one sentence
A courier drives the highway (a gradient step on the smooth part) and walks the last block on foot (the prox step for the simple kinky part).
When to use it
The objective splits as f(x) = g(x) + h(x). g is convex and smooth (∇g is L-Lipschitz). h is convex, maybe kinky, and has an easy prox.
Lasso and sparse regression (h = λ‖x‖1), matrix completion (h = trace norm), and simple constraints (h = 0 inside C and +∞ outside, which gives projected gradient).
Not when h has no cheap prox, or when h couples the variables in a hard way (try ADMM). If plain ISTA is too slow, use FISTA.
The update
proxt(z) = argminu (1/2t)‖u − z‖2 + h(u)
xk = proxt(xk−1 − t∇g(xk−1))
The prox finds a point close to z that also keeps h small. It depends only on h. CO4A 9-1 For h = λ‖x‖1 it is soft-thresholding at λt: shrink each entry toward 0 by λt, and set it to 0 if |zi| ≤ λt. Example: g(β) = ½(4 − 2β)2 and λ = 2, so L = 4 and t = ¼. From β = 0 the gradient step gives 2, and soft-thresholding at 0.5 gives 1.5. That is the optimum, since g′(1.5) + λ = −2 + 2 = 0. Special cases: h = 0 gives gradient descent, and h = indicator of C gives projected gradient, x+ = PC(x − t∇g(x)). CO4A 9-4
β ← 0; t ← 1/L # L = largest eigenvalue of XᵀX
repeat # lasso: ½‖y − Xβ‖² + λ‖β‖₁
z ← β + t·Xᵀ(y − X·β) # gradient step
for each i: # prox = soft-threshold at λt
β_i ← sign(z_i)·max(|z_i| − λ·t, 0)
until β stops changing
One prox per trial step (about 6.6 per step in the Day 8 lasso)
Pitfalls
Threshold at λt, not λ. The zero band is −λt ≤ zi ≤ λt.
Count prox calls, not only iterations. One prox can be a full SVD, and backtracking multiplies the calls.
See it run
Open Day 8: the ista widget for the soft-threshold curve, and the ista_fista widget for ISTA against FISTA on a seeded lasso. Related cards: FISTA, coordinate descent (also solves the lasso) and ADMM.
Proximal gradient plus momentum: each step first slides along the last move, which lifts the rate from 1/k to 1/k².
In one sentence
Like pushing a swing, small well-timed pushes along the current motion build speed: FISTA keeps part of its last move and then takes an ordinary ISTA step from there.
When to use it
The same problems as ISTA: smooth g plus an h with an easy prox. With h = 0 it is accelerated gradient descent.
You need many iterations and each prox is cheap.
Little gain when you warm-start along a path of λ values, or when the prox is costly. In matrix completion, backtracking needs several SVDs, and the extrapolated point may not be low rank. CO4A 9-5-4
The update
v = xk−1 + ((k − 2)/(k + 1))(xk−1 − xk−2)
xk = proxt(v − t∇g(v))
Start with x−1 = x0. CO4A 9-5-1 The momentum weight is 0 at k = 2, 0.25 at k = 3, 0.73 at k = 10 and 0.97 at k = 100. Beck and Teboulle's original version uses a sequence θ1 = 1, θk+1 = (1 + √(1 + 4θk2))/2 and weight (θk − 1)/θk+1. Both versions reach O(1/k2). Beck & Teboulle 2009
x_prev ← x0; x ← x0; t ← 1/L
for k = 1, 2, …
v ← x + ((k − 2)/(k + 1))·(x − x_prev) # momentum
x_prev ← x
x ← prox_t(v − t·∇g(v)) # ISTA step from v
remember the best f(x) so far # f can go up
No better than O(1/k2), so FISTA's rate is the best possible CO4A 6-3-6
—
Backtracking
Same order; start each search from the previous t CO4A 9-5-2
One prox per trial step
Pitfalls
f does not fall every step. These bumps are called "Nesterov ripples". In the Day 8 seeded lasso, FISTA's objective rose on 430 of 1,000 steps, while ISTA's never rose. Report the best value.
"Optimal" is a worst-case claim over all smooth convex problems. A particular lasso can converge much faster than either bound.
Fits a quadratic bowl to the function from its gradient and Hessian, then jumps to the bottom of that bowl.
In one sentence
Gradient descent walks downhill with a fixed kind of stride; Newton also measures the curvature, fits a bowl, and jumps to its lowest point, so near the answer the number of correct digits roughly doubles every step.
When to use it
f is twice differentiable and convex near the answer, so the Hessian ∇2f (the matrix of second derivatives) is positive definite.
Up to a few thousand dense variables, or more when the Hessian is sparse or banded. A banded Hessian makes a step O(n). CO4A 14-8
High accuracy, or badly scaled problems: Newton is affine invariant, so rescaling the axes does not change its path. CO4A 14-2-2
Not for millions of dense variables (a dense Hessian at n = 106 takes 8 TB), for kinks, or when the Hessian is unavailable. Use L-BFGS instead.
The update
xk+1 = xk − tk(∇2f(xk))−1∇f(xk)
t = 1 is pure Newton. Damped Newton picks t by backtracking. CO4A 14-4 The Newton decrement λ2 = ∇fT(∇2f)−1∇f measures progress: λ2/2 is the drop the bowl predicts, which makes a good stopping test. CO4A 14-3 Example: Newton for the root of x2 − 2 from x = 1 gives 1.5, 1.416667, 1.414216, 1.41421356. The errors are 0.086, 0.0025, 2.1·10−6 and 1.6·10−12. CMU 10-725 2016
x ← x0
repeat
g ← ∇f(x); H ← ∇²f(x)
v ← solve H·v = −g # Cholesky; never form H⁻¹
λ² ← −gᵀv # Newton decrement squared
if λ²/2 ≤ ε: stop
t ← 1
while f(x + t·v) > f(x) + α·t·gᵀv:
t ← β·t # damping
x ← x + t·v
How fast, and at what cost
Setting
Rate
Cost per step
Strongly convex, Lipschitz Hessian, far from x*
Damped phase: f drops by at least a fixed amount per step CO4A 14-5
O(n2) memory; dense solve O(n3), about 3.3·108 flops at n = 1000 CO4A 14-7
Near x*, t = 1
Quadratic: the error roughly squares. About six such steps shrink it by 5·10−20Boyd & Vandenberghe 2004
Same
Self-concordant f (log barriers)
A step count with no unknown constants: C(α, β)(f0 − f*) + log log(1/ε) CO4A 14-6-2
Same
Pitfalls
Pure Newton can diverge. For f(x) = log(ex + e−x) it converges from x0 = 1 but runs off to −2.3·104 from 1.1. Damped Newton from 1.1 converges in 5 steps. Boyd & Vandenberghe 2004
Fewer iterations is not less time. A step costs O(n3) against O(n) for gradient descent, and plotted against time Newton's lead shrinks. CO4A 14-7
On nonconvex f the Hessian can be indefinite and the step can point uphill. See the SQP and Levenberg–Marquardt cards.
Newton-like steps without the Hessian: the method learns the curvature from how the gradient changes between steps.
In one sentence
You can estimate a car's acceleration from two speedometer readings; BFGS estimates curvature the same way from two gradients, and L-BFGS keeps only the last few readings.
When to use it
Smooth unconstrained problems where you have gradients but the Hessian is unavailable or too costly.
BFGS: up to a few thousand variables, since it stores an n × n matrix. L-BFGS: millions of variables, since it stores only m vector pairs (typically m = 3 to 20). UW CS726 2025 It is the usual workhorse for large smooth problems.
Not for kinks: gradient differences across a kink give a meaningless curvature estimate. Not for general constraints.
The update
s = xk+1 − xk, y = ∇f(xk+1) − ∇f(xk)
The new curvature model must reproduce the observed gradient change (the secant equation), and sTy > 0 must hold to keep it positive definite. CO4A 18-1 BFGS updates H, its estimate of the inverse Hessian:
Hk+1 = (I − ρsyT)Hk(I − ρysT) + ρssT
ρ = 1/(yTs), step direction p = −H∇f
A line search picks the step length. CO4A 18-4 Example: true Hessian diag(10, 1), start H = I, step s = (1, 1), so y = (10, 1). One update gives H11 ≈ 0.107, already close to the true 0.1. L-BFGS never forms H. It rebuilds H∇f from the stored pairs with two loops of dot products. CO4A 18-7
q ← ∇f(x) # L-BFGS two-loop recursion
for each stored pair, newest first:
a_i ← (s_iᵀq)/(y_iᵀs_i); q ← q − a_i·y_i
p ← γ·q, γ = sᵀy / yᵀy (newest pair)
for each stored pair, oldest first:
b ← (y_iᵀp)/(y_iᵀs_i); p ← p + (a_i − b)·s_i
x_new ← x − t·p # t from a line search
store the new (s, y); drop the oldest if more than m
How fast, and at what cost
Setting
Rate
Cost per step
BFGS, Wolfe line search, Lipschitz Hessian
Superlinear: the error ratio ‖xk+1 − x*‖/‖xk − x*‖ → 0 CO4A 18-6
O(n2) memory and work (a dense matrix)
L-BFGS with m pairs
Only linear is guaranteed in general; often fast in practice UW CS726 2025
O(mn) memory, about 4mn multiplications
Newton, for comparison
Quadratic near x*
O(n3) solve
At n = 106 a dense Hessian needs 8 TB. L-BFGS with m = 10 stores 2·107 numbers, about 160 MB.
Pitfalls
Guard the curvature condition. sTy > 0 holds automatically for strictly convex f. Otherwise use a Wolfe line search, or skip the update. CMU 10-725 2016
L-BFGS is not BFGS in theory. It trades the superlinear guarantee for memory.
No Hessian is needed to start. H0 = I or γI works.
Replaces each inequality wall with a smooth log "fence", solves that easier problem with Newton, then stiffens the fence and repeats.
In one sentence
Picture a ball on a tilted table ringed by springy walls: tilting the table more (raising t) rolls the ball toward the best corner without it ever touching a wall.
When to use it
Convex problems with smooth inequality constraints hi(x) ≤ 0 (and Ax = b): LP, QP, SOCP, SDP. Small to medium size, high accuracy.
You have a strictly feasible start, or can find one with phase I (below).
Not when one Newton system is too big to solve. Then use first-order methods such as ADMM or the GPU LP method in the cuPDLP paper.
The update
minimize t·f(x) + φ(x) subject to Ax = b
φ(x) = −Σi log(−hi(x)), i = 1, …, m
φ is the log barrier. It is finite only strictly inside, and it blows up near each wall. CO4A 15-1-2 Its minimizers x*(t) trace the central path, and f(x*(t)) − p* ≤ m/t. CO4A 15-3-2 Example: minimize x subject to x ≥ 0. The barrier problem, minimize tx − log x, gives x*(t) = 1/t, so the error is exactly m/t with m = 1. Phase I finds a start by minimizing s subject to hi(x) ≤ s and Ax = b. If the optimal s is negative, that x is strictly feasible. CO4A 15-7
x ← strictly feasible point # phase I if needed
t ← t0; μ ← 10 to 100
repeat
x ← Newton on t·f(x) + φ(x), starting from x # centering
if m/t ≤ ε: stop # certified gap
t ← μ·t
How fast, and at what cost
Setting
Rate
Cost per step
Exact centering
Gap ≤ m/(μkt0) after k outer steps; ⌈log(m/(t0ε))/log μ⌉ outer steps plus the first centering CO4A 15-5
A few Newton steps per outer step
Practice: 2000 random LPs, m = 10 to 1000, μ = 100
About 21 → 27 Newton steps to cut the gap by 104, while the size grew 100× Boyd & Vandenberghe 2004
One linear (KKT) solve per Newton step; grows with size
Don't jump to a huge t. The barrier problem becomes badly conditioned. Raise t step by step and warm-start Newton. CO4A 15-4
m/t is a bound, not the error. In the toy LP at t = 10 the true gap is 0.197, against a bound of 0.5.
The Newton count grows slowly with size, but each step gets more expensive.
See it run
Open Day 12: the centralpath widget, slide t, and watch x*(t) move along the central path to the optimal corner. The centralpath_iters widget counts Newton steps for different μ. Related cards: primal-dual IPM and Newton.
Takes one Newton step at a time on slightly relaxed KKT equations, for the primal and dual variables together, and tightens the relaxation as it goes.
In one sentence
The barrier method walks to each station on the central path before heading on; the primal-dual method cuts the corner, one Newton step at a time toward a moving target.
When to use it
LP, QP, SOCP and SDP of small to medium size (larger if sparse), when you want high accuracy such as 10−8 in a predictable number of iterations.
Equality constraints need not hold at the start: the iterates may be infeasible. CO4A 17-2
Not when one Newton system is too big to factor. Then use ADMM or a first-order LP method (cuPDLP paper). Nonconvex problems need the safeguards of an NLP solver (SQP card).
The update
Problem: minimize f(x) subject to hi(x) ≤ 0 and Ax = b, with multipliers u ≥ 0 and v. The method drives three residuals to zero:
rdual = ∇f(x) + ∇h(x)u + ATv
rcent = diag(u)h(x) + τ1, rprim = Ax − b
Only complementary slackness changes from the KKT conditions: uihi = 0 becomes uihi = −τ. CO4A 16-2 The surrogate duality gap is η = −h(x)Tu. Each iteration sets τ = σ·η/m with σ ∈ (0, 1), takes one Newton step on all variables, and backtracks to keep u > 0 and h(x) < 0. CO4A 17-2-3
pick x with h(x) < 0, u > 0, any v
repeat
η ← −h(x)ᵀu; τ ← σ·η/m # aim for a smaller gap
if η, ‖r_dual‖, ‖r_prim‖ ≤ ε: stop
Δ ← solve the Newton system ∇r·Δ = −r
θ ← 0.99 · (largest step ≤ 1 keeping u > 0)
shrink θ until h(x + θΔx) < 0 and ‖r‖ drops
(x, u, v) ← (x, u, v) + θ·Δ
How fast, and at what cost
Setting
Rate
Cost per step
General
Usually faster than the barrier method, better than linear; no inner loop CO4A 17-2
13 iterations to η ≤ 10−8, ending at x = (1, 3), u = (0, 0, 0, 1, 1)
Tiny
Pitfalls
The iterates are not feasible along the way. Only u > 0 and h(x) < 0 are kept. Ax = b and dual feasibility hold only in the limit.
Counts depend on settings. Tolerances, σ and the line-search constants all change the iteration count.
SDP needs care. The plain Newton step breaks the symmetry of the matrix variables, so solvers use special scalings such as Nesterov–Todd. CMU 10-725 2016
Solves a constrained problem by putting prices on its constraints: minimize the priced objective, then raise or lower each price by how much its constraint is violated.
In one sentence
A shared charging station posts an electricity price, each robot plans its own charging for that price, and the station raises the price whenever total demand exceeds capacity.
When to use it
Linear constraints Ax = b (or ≤ b) that couple otherwise separate pieces, f(x) = Σi fi(xi). Dual ascent then splits into independent subproblems that run in parallel. This is dual decomposition. CO4A 20-2-1
The method of multipliers when plain dual ascent is fragile, for example when f is not strictly convex.
Not when you want both the parallel split and robustness: that combination is ADMM.
The update
The Lagrangian is L(x, u) = f(x) + uT(Ax − b), where u is the price vector (see Day 9).
xk ∈ argminx L(x, uk−1)
uk = uk−1 + t(Axk − b)
The violation Ax − b is the gradient of the dual function. CO4A 20-1 For ≤ constraints, prices are clipped at zero: u ← max(0, u + t(Ax − b)). CO4A 20-2-2 The method of multipliers adds (ρ/2)‖Ax − b‖2 to L, minimizes that over x, and updates u ← u + ρ(Ax − b). The step exactly ρ makes every iterate satisfy stationarity, so only feasibility is left. CO4A 20-3
Example: minimize ½(x12 + x22) subject to x1 + x2 = 2. At price u each "agent" picks xi = −u. With t = 0.25 from u = 0, x goes 0, 0.5, 0.75, 0.875 toward 1: the error halves each step. The method of multipliers at ρ = 1 cuts it to 1/3 per step.
u ← 0
repeat
for each block i, in parallel: # dual decomposition
x_i ← argmin f_i(x_i) + uᵀA_i x_i
r ← Σ A_i x_i − b # constraint violation
u ← u + t·r # raise price if over-used
until ‖r‖ ≤ ε
How fast, and at what cost
Setting
Rate
Cost per step
Dual ascent, f d-strongly convex
Dual is smooth: O(1/ε) steps; O(log(1/ε)) if ∇f is also L-Lipschitz CO4A 20-1-1
One x-minimization (split into parallel pieces) and one product Ax
Method of multipliers
More robust convergence than dual ascent CO4A 20-3
One joint x-minimization; the blocks no longer separate
Pitfalls
Dual ascent needs strong convexity. Without it the x-step can be unbounded or have many answers.
Mind the step. The dual gradient is (‖A‖22/d)-Lipschitz, so t ≤ d/‖A‖22 is safe. In the example, t = 1 makes u bounce 0, −2, 0, −2 forever.
The penalty couples the blocks. The method of multipliers loses the parallel split.
Splits a problem into two easier parts, f(x) and g(z), and alternates: update x, update z, then update a price that pushes them to agree.
In one sentence
Two specialists edit one document in turns, one polishing the wording (f) and one enforcing the style guide (g), while a referee (the dual variable) keeps track of how much they still disagree.
When to use it
minimize f(x) + g(z) subject to Ax + Bz = c, where each part alone is easy: the lasso (least squares plus ℓ1), QPs with box constraints, consensus across many machines or robots.
Moderate accuracy is enough, and you can factor one matrix and reuse it. The OSQP solver for MPC is built this way (OSQP paper).
The update
Scaled form, with w = u/ρ the running sum of residuals and ρ > 0 a penalty weight:
xk = argminx f(x) + (ρ/2)‖Ax + Bzk−1 − c + wk−1‖2
zk = argminz g(z) + (ρ/2)‖Axk + Bz − c + wk−1‖2
wk = wk−1 + Axk + Bzk − c
The z-step uses the new x, and that order is what makes it ADMM. CO4A 20-4-1 For the lasso the steps are a ridge regression, β ← (XTX + ρI)−1(XTy + ρ(α − w)), then a soft-threshold, α ← Sλ/ρ(β + w), then w ← w + β − α. CO4A 21-3 Example: minimize ½(β − 3)2 + |β|, whose answer is 2. With ρ = 1, β goes 1.5, 1.25, 1.625, 1.813, 1.906 toward 2.
z ← 0; w ← 0
repeat
x ← argmin f(x) + (ρ/2)‖Ax + Bz − c + w‖²
z_old ← z
z ← argmin g(z) + (ρ/2)‖Ax + Bz − c + w‖² # uses new x
r ← Ax + Bz − c # primal residual: agree yet?
w ← w + r
s ← ρ·AᵀB·(z − z_old) # dual residual: z settled?
until ‖r‖ ≤ ε_pri and ‖s‖ ≤ ε_dual
One x-solve, one z-solve (often a prox), vector work
Practice
Modest accuracy in a few tens of iterations; slow to high accuracy Boyd et al. 2011
Lasso: factor XTX + ρI once, O(p3), then O(p2) per step CO4A 21-3
OSQP, linear MPC with 20 states, 10 inputs, horizon 10
7 ms cold, 2 ms with warm start and factorization caching Stellato 2020
Factor once, then cheap vector work and a box projection
Pitfalls
Check both residuals. ‖r‖ can be tiny while z is still drifting.
ρ matters. In the Day 13 lasso, ρ = 10 took 123 iterations against 16 at ρ = 1. Residual balancing helps: double ρ if ‖r‖ > 10‖s‖, halve it if ‖s‖ > 10‖r‖, and rescale w by ρold/ρnew. Boyd et al. 2011
Stays inside the constraint set without projections: each step finds the best corner for the current linear model and moves part of the way toward it.
In one sentence
You cannot teleport back inside a fenced park, but from any spot you can see which corner post lies furthest downhill and walk part of the way toward it.
When to use it
A smooth convex f over a bounded convex set C where minimizing a linear function over C is cheap but projection is costly. Examples: the trace-norm ball (needs only the top singular pair, not a full SVD), ℓ1 balls, polytopes given by their corners. CO4A 22-2
You want sparse or low-rank iterates: after k steps, x mixes at most k + 1 corners.
Not for high accuracy. Not when projection is easy anyway: then use projected gradient (ISTA card).
The update
sk ∈ argmins ∈ C ∇f(xk)Ts
xk+1 = (1 − γk)xk + γksk, γk = 2/(k + 2)
The first line is the linear minimization oracle (LMO). Here k counts from 0; CO4A's 2/(k + 1) from k = 1 is the same sequence. A mix of two points of C stays in C, so no projection is needed. For the ℓ1 ball of radius τ, the LMO picks the entry with the largest |∂f/∂xi| and returns s = −τ·sign(∂f/∂xi)·ei, an O(n) operation. Jaggi 2013 The same oracle gives a free duality gap: ∇f(x)T(x − s) ≥ f(x) − f*. CO4A 22-2
Example: minimize ‖x − (0.9, 0.5)‖2 over the triangle with corners (0, 0), (1, 0), (0, 1); the optimum is (0.7, 0.3). From (0, 0) the LMO picks (1, 0) and γ0 = 1 jumps there. The next steps zig-zag between corners toward the optimum.
x ← any point in C
for k = 0, 1, 2, …
g ← ∇f(x)
s ← argmin over s in C of gᵀs # LMO: often a corner
if gᵀ(x − s) ≤ ε: stop # certified gap
γ ← 2/(k + 2)
x ← (1 − γ)·x + γ·s
Minimizes over one coordinate at a time, holding the others fixed, and cycles through the coordinates.
In one sentence
A taxi that may only drive north–south or east–west: each move is easy, and on the right kind of landscape it still reaches the lowest point.
When to use it
f(x) = g(x) + Σi hi(xi): a smooth convex g plus a nonsmooth part that is separable (a sum of one-variable terms). Lasso, elastic net and box constraints fit. Then a point that no single coordinate can improve is a global minimum. CO4A 23-1
Cheap closed-form one-variable updates, many features, and warm-started paths over λ (pathwise coordinate descent, as in glmnet). CO4A 23-4
Not when the nonsmooth part couples variables, such as |x1 − x2| or total variation: it can get stuck.
The update
xi ← argminxi f(x1, …, xi, …, xn), i = 1, …, n
Always use the newest values of the other coordinates. For the lasso, with Xi the i-th column of X:
βi ← Sλ/‖Xi‖²(XiT(y − X−iβ−i)/‖Xi‖2)
S is soft-thresholding, and X−iβ−i is the fit without feature i. CO4A 23-3 Example: for f = ½(x12 + 2c·x1x2 + x22) the exact updates are x1 = −c·x2 and x2 = −c·x1, so each cycle multiplies the error by c2. At c = 0.9, reaching f ≤ 10−10 takes 52 cycles, against 167 gradient steps with t = 1/L.
β ← 0; r ← y # residual r = y − Xβ
repeat
for i = 1 … p:
z ← β_i + X_iᵀr / ‖X_i‖² # best 1-D fit
new ← sign(z)·max(|z| − λ/‖X_i‖², 0)
r ← r − X_i·(new − β_i) # O(n) residual update
β_i ← new
until β stops changing
How fast, and at what cost
Setting
Rate
Cost per step
Smooth g plus separable h, cyclic order
Every limit point is a minimizer (Tseng 2001, under mild conditions) CMU 10-725 2016
Least squares: one full cycle is O(np), the same as one gradient step CO4A 23-2
Random order, smooth convex
O(1/ε); O(log(1/ε)) if strongly convex (Nesterov 2010, as cited by CO4A) CO4A 23
One coordinate per step
Pitfalls
Coupled kinks break it. For f = |x1 − x2| + 0.1(x12 + x22) from (2, 1), it stops at (1, 1) with f = 0.2, though the minimum is (0, 0) with f = 0.
Updating all coordinates at once from old values (Jacobi style) is not coordinate descent and need not converge. CMU 10-725 2016
Compare a full cycle with one gradient step, not one coordinate update with one gradient step.
Finds the best integer solution by splitting the problem into branches, bounding each branch with a convex relaxation, and discarding branches that cannot win.
In one sentence
When hunting for the cheapest flight, if even the most optimistic price via Tokyo is above a ticket you already hold, you never look at Tokyo routes again.
When to use it
Mixed-integer programs: some variables are 0/1 or whole numbers (on or off, which side of an obstacle, which safe region a footstep lands in), and dropping integrality leaves a convex problem (LP, QP, SOCP).
You need a certified optimum or a known gap. Deits and Tedrake plan 10–20 footsteps over 10 convex regions in seconds to a minute this way. Deits & Tedrake 2014 See the footstep paper.
Not when a large instance needs a guaranteed fast answer: the worst case is exponential, and integer programs are NP-hard in general. CO4A 24-3
The update
The relaxation drops integrality. Its value bounds the true optimum (from below for a minimization, from above for a maximization). CO4A 24-4 The best integer point found so far, the incumbent, gives the other bound, and you stop when the two meet. A node is pruned if its relaxation is infeasible, if its solution is already integer (record it), or if its bound cannot beat the incumbent. CO4A 24-5
Example (Day 15): a robot carries 11 kg. Parcels are worth $60, $30, $15 and $10 and weigh 4, 9, 5 and 7 kg. The root LP takes 7/9 of parcel B and bounds the value at $83.33. Branch on B. B = 1 gives bound $60. B = 0 gives $77.86, so branch on D: the children give integer plans worth $70 and $75. Now the B = 1 branch is pruned (60 ≤ 75). Best-first search solves 5 LPs (depth-first: 11) instead of checking all 16 subsets.
best ← −∞ (maximization); open ← {root}
while open is not empty:
node ← pick one (best bound, or depth first)
solve its relaxation → value v, point x
if infeasible or v ≤ best: prune # bound
else if x is integer: best ← v # new incumbent
else: pick a fractional x_j and add two children:
x_j ≤ ⌊x_j⌋ and x_j ≥ ⌈x_j⌉ # branch
return best
One relaxation per node, warm-started from its parent
Two cuts, xA + xB ≤ 1 and xC + xD ≤ 1 (each pair is too heavy), make the root LP integer at $75 with no branching. Solvers mix such cuts with branching (branch and cut). CO4A 25-1-4
Pitfalls
Rounding the LP is not optimal. B = 7/9 rounds up to an overweight bag or down to a $60 plan. The optimum is $75.
Keep big-M small. Use the smallest M the variable bounds allow. A huge M weakens the relaxation and the bounds.
A valid cut removes only fractional points, never an integer solution.
Solves a nonlinear constrained problem by solving a quadratic program at every step, built from a quadratic model of the Lagrangian and linearized constraints.
In one sentence
Drive a curvy road by fitting a parabola to the next stretch, driving to its bottom, and fitting again.
When to use it
Smooth nonlinear programs, minimize f(x) subject to g(x) ≤ 0 and h(x) = 0, with f, g, h twice differentiable and possibly nonconvex.
Nonlinear MPC and trajectory optimization. acados' real-time iteration runs one SQP-type iteration, that is one QP, per sampling time. Verschueren 2021
Not when you need the global optimum: it finds local solutions. Use multi-start or a convex relaxation. A common alternative for large NLPs is an interior-point solver such as Ipopt, which also aims for a local solution. Ipopt
The update
At the current point xk with multipliers λk, find the step d from the QP:
mind ∇f(xk)Td + ½dT∇2xxL(xk, λk)d
s.t. h(xk) + ∇h(xk)Td = 0
g(xk) + ∇g(xk)Td ≤ 0
L = f + μTg + λTh is the Lagrangian. With equality constraints only, solving this QP is exactly one Newton step on the KKT equations of Day 10. Wikipedia: SQP Example: minimize x1 + x2 on the circle x12 + x22 = 2, from (−1.5, −0.5) with λ = 1. The constraint error goes 0.125, 0.119, 1.8·10−3, 4.9·10−7, 1.8·10−13, roughly squaring each step, and the iterates reach (−1, −1).
x ← x0; λ ← λ0
repeat
build the QP: quadratic model of L at (x, λ),
constraints linearized at x
(d, λ_qp) ← solve the QP # λ_qp: new multipliers
t ← line search on a merit function # or filter / trust region
x ← x + t·d; λ ← λ_qp
until the KKT residual ≤ ε
How fast, and at what cost
Setting
Rate
Cost per step
Near a regular local solution
Newton-fast, because the equality case is Newton's method on KKT Wikipedia: SQP
Derivatives plus one QP solve
Far from a solution
Needs a merit function or filter, with a line search or trust region, to make progress Wikipedia: SQP
Extra function evaluations
Real-time NMPC (acados RTI)
One SQP-type iteration per sampling time, without waiting for convergence Verschueren 2021
One structured QP per control tick
Pitfalls
A KKT point need not be a minimum. On the circle, (1, 1) passes the first-order test but is the maximum, with f = 2.
The Lagrangian's Hessian can be indefinite. Regularize it, or use a positive definite BFGS-type approximation. Wikipedia: SQP
The linearized constraints can contradict each other, so the QP is infeasible and the solver needs a fallback.
Fits a nonlinear model to data by repeatedly linearizing the residuals and solving a linear least-squares problem, with a damping knob (LM) that keeps the steps safe.
In one sentence
Gauss–Newton pretends the model is linear near the current guess; Levenberg–Marquardt adds a leash that you loosen when steps go well and shorten after a bad one.
When to use it
Nonlinear least squares, minimize F(x) = ½Σi ri(x)2, where each residual ri is a prediction minus a measurement. SLAM, bundle adjustment, camera and lidar calibration, and curve fitting all look like this.
Gauss–Newton is the de facto standard for pose-graph SLAM. SE-Sync paper It is fastest when the model fits well (small residuals). LM is safer from a poor start.
Not for objectives that are not sums of squares (use Newton or BFGS). It finds only a local minimum, so the start matters.
The update
J = ∂r/∂x is the Jacobian. The gradient of F is JTr, and Gauss–Newton approximates the Hessian by JTJ, dropping the terms that involve second derivatives of r. Wikipedia: Gauss–Newton
Gauss–Newton: (JTJ)δ = −JTr, x ← x + δ
LM: (JTJ + λD)δ = −JTr
D = I (Levenberg) or diag(JTJ) (Marquardt). A small λ gives the Gauss–Newton step. A large λ gives a short step along steepest descent. Madsen et al. 2004 Example (Day 16): fit y = a·ebt to 9 points from (a, b) = (1, 0). Gauss–Newton gives F = 16.82, 7.09, 62.93 (up!), 6.16, 0.359, 0.0773, 0.0761. LM with λ0 = 1 gives 16.82, 5.94, 2.53, 0.144, 0.0762, 0.0761, downhill every step. From (1, −3) Gauss–Newton diverges; LM still converges.
x ← x0; λ ← 1
repeat
r ← residuals(x); J ← Jacobian(x)
δ ← solve (JᵀJ + λ·D)·δ = −Jᵀr # λ = 0: Gauss–Newton
if F(x + δ) < F(x):
x ← x + δ; λ ← λ/10 # trust the model more
else:
λ ← 10·λ # reject; shorter step
until ‖Jᵀr‖ ≤ ε
The ÷10/×10 rule is a simplification. Marquardt's rule uses the ratio of actual to predicted decrease: below 0.25, double λ; above 0.75, divide it by 3. Madsen et al. 2004
Solves a nonconvex problem, such as a collision-free trajectory, as a sequence of convex subproblems built around the current guess and kept inside a trust region.
In one sentence
As on a frozen lake, trust the ice only where you have tapped it: build a convex model near your current plan, move a little, check, and repeat.
When to use it
Trajectory optimization with nonlinear dynamics, obstacles or nonconvex control limits: rockets, quadrotors, robot arms, cars. Malyuta 2022
You have a reasonable initial guess (a straight line, the last plan) and want a good, dynamically feasible plan quickly.
Not when you need a global optimum: the result depends on the start. For special thrust limits, lossless convexification solves a single convex problem exactly (lossless paper).
The update
Around the current guess x̄, linearize the dynamics and the nonconvex constraints. For example, "stay outside the circle" ‖p − c‖ ≥ r becomes a halfspace:
nT(p − c) ≥ r, n = (p̄ − c)/‖p̄ − c‖
Since nT(p − c) ≤ ‖p − c‖ for every p, any point that meets the halfspace also clears the circle. A trust region ‖x − x̄‖ ≤ Δ stops steps from going where the model is wrong. A penalized slack ("virtual control") keeps every subproblem feasible. Then compare the real improvement with the predicted one. If the ratio ρ is low, reject the step and shrink Δ. If it is high, accept it and grow Δ. Malyuta 2022 Example: obstacle center (5, 0.5), r = 2, guess point (5, 0). Then n = (0, −1) and the fence is y ≤ −1.5. With Δ = 1 the point reaches only y = −1, so iteration 1 needs slack 0.5.
x̄ ← initial guess (e.g., a straight line); Δ ← Δ0
repeat
build a convex model at x̄: linear dynamics, halfspaces
x ← solve min cost + λ·‖slack‖₁
s.t. model and ‖x − x̄‖ ≤ Δ
ρ ← actual decrease / predicted decrease
if ρ is too low: reject x, Δ ← Δ/2
else: x̄ ← x; grow Δ if ρ is high
until the predicted decrease ≈ 0
check that the slack is 0
How fast, and at what cost
Setting
Rate
Cost per step
Plain SCP
A heuristic: no global optimality, and the answer depends on the start EE364b
One convex QP or SOCP
SCvx (virtual control and trust region)
Global convergence to a stationary point, with a superlinear rate, under assumptions Mao 2018
Not globally optimal. In the Day 18 widget, a guess bowed above the obstacle converges to an 11.248 m path, while a straight-line start finds 10.455 m.
Nonzero slack at convergence is a "soft failure". The answer does not solve the real problem. Malyuta 2022
Safe waypoints do not mean safe segments. In the widget every waypoint is at least 2.000 m from the center, yet one segment passes at 1.983 m.
The papers behind Week 3, where convex optimization made robots, rockets, and cars work. Each is explained three ways: in one sentence, for a 10-year-old, and step by step.
2007 · Açıkmeşe, Ploen · J. Guidance, Control, and Dynamics
Convex Programming Approach to Powered Descent Guidance for Mars Landing
Showed that a Mars lander's fuel-optimal landing burn, which looks nonconvex because the engine has a minimum thrust, can be solved exactly as one convex program.
In one sentence
A minimum thrust makes the set of allowed thrusts a ring, so the problem is nonconvex. The paper swaps the ring for a convex set using one extra variable, proves the optimum never uses the extra room, and so gets the true fuel-optimal landing from one second-order cone program.
Explain it to a 10-year-old
A toy rocket's engine has a rule: once it is on, it must push at least "medium" and at most "full". That rule leaves a hole in your choices, and holes make planning hard. So add a fuel meter. The new rule: push no harder than the meter reads, and keep the meter between medium and full. You pay for what the meter reads, not for the push. Paying for push you don't use is a waste, so the cheapest plan always pushes exactly what the meter says. That plan obeys the real rule too.
About the sources for this entry
The 2007 full text could not be opened (the publisher refused access). This entry relies on the paper's abstract plus two later papers that restate its method: Blackmore, Açıkmeşe and Scharf (2010) and the Malyuta et al. tutorial (2022). All numbers below come from the 2010 paper.
The problem
A Mars landing ends with powered descent: the engines fire to fly the lander to the target and set it down softly. The thrust profile must be computed onboard, within seconds, with a guarantee of an answer in bounded time. Açıkmeşe 2007 abstract
The goal is the minimum-fuel profile. Thrust has a maximum ρ2 and, during the burn, a minimum ρ1 > 0. A glide-slope constraint keeps the lander inside a cone above the target. The minimum is the troublemaker. For the 3-D thrust vector Tc, the rule
0 < ρ1 ≤ ‖Tc‖ ≤ ρ2
allows a thick shell with a hole in the middle, which is not convex (Day 2). With the 2010 paper's Mars values, ρ1 = 4972 N and ρ2 = 13260 N, the thrusts (6000, 0, 0) N and (−6000, 0, 0) N are allowed, but their average (0, 0, 0) is not. Blackmore 2010
The key idea
Add a slack variable Γ(t), read "gamma", and replace the shell by two convex constraints:
‖Tc(t)‖ ≤ Γ(t), ρ1 ≤ Γ(t) ≤ ρ2
Fuel is charged for Γ instead of ‖Tc‖: the mass falls at rate αΓ, with α a fixed engine constant. The first constraint is a second-order cone, and the second is a pair of bounds. Blackmore 2010
The new set is bigger. A thrust of 3000 N with Γ = 4972 N passes the relaxed rules, though the engine cannot make 3000 N. The theorem, proved with Pontryagin's maximum principle, says the optimum never does this: ‖Tc(t)‖ = Γ(t) at every time. Malyuta 2022
So the relaxed optimum obeys the real limits. No original plan can beat it, because the relaxation allows everything the original allows. Nothing is lost, which is why this is called lossless convexification.
Left: the engine's allowed thrusts form a ring, so the midpoint of two allowed thrusts can be forbidden. Right: one thrust component T against the slack Γ. The shaded truncated cone is convex. Its thick slanted edges, where ‖T‖ = Γ, are exactly the ring on the left, and the theorem says the optimum always lies on them. Own drawing, not to scale.
How it works
Model the lander as a point mass: 3-D position and velocity, constant gravity, and a mass that falls as fuel burns. An inner loop handles attitude.
Relax the thrust bounds as above.
Change variables using the logarithm of the mass. This removes the division of thrust by mass from the dynamics. Malyuta 2022
Split time into N steps (Day 18). The result is, in the abstract's words, "a finite-dimensional convex optimization problem, specifically … second-order cone programming" (Day 5).
Solve it with an interior-point method (Day 12) in polynomial time. The time of flight tf is searched outside the convex solve; the 2010 paper uses a golden-section search.
Results
The 2010 follow-up uses the same relaxation with g = 3.7114 m/s², a wet mass of 1905 kg and a dry mass of 1505 kg (400 kg of fuel). Hovering at full mass needs 1905 × 3.7114 ≈ 7070 N, inside the thrust range. Blackmore 2010
Reachable target: 399.4 kg of fuel, tf = 78.4 s and 55 time nodes. The search took 23 golden-section iterations and 14.3 s in total on a 2.4 GHz MacBook Pro with JPL's G-OPT solver.
Unreachable target, which would need at least 414 kg: the minimum-landing-error version lands 404 m away using all 400 kg.
Why it mattered
The Malyuta tutorial calls it "the first time that convex optimization was shown to be applicable to PDG" (powered-descent guidance). It gave a polynomial-time method with guaranteed convergence. It also underlies JPL's G-FOLD flight tests on Masten's Xombie rocket, including a 750 m divert. Malyuta 2022
Lars Blackmore of SpaceX cites the paper in a 2017 chapter, which states that "SpaceX uses CVXGEN (Mattingley and Boyd 2012) to generate customized flight code" for "very high-speed onboard convex optimization". Blackmore 2017 The chapter does not say which problem that code solves. The Malyuta tutorial only hypothesizes a close link to the Falcon 9 landing algorithm.
Limitations
Point-mass model, constant gravity, no aerodynamics in the base form.
The time of flight is searched outside the convex solve.
The guarantee needs this problem structure. Later work added state and pointing constraints and drag. Malyuta 2022
Solve times in 2010 were seconds, not milliseconds.
How to read the paper
Read the 2007 abstract, then the 2010 paper. Its Problem 2 and equations 11–13 hold the same relaxation, and its Section V has the Mars examples. For the picture, see Part I of the Malyuta tutorial and its sidebar figure S1, which shows the thrust ring and its relaxation.
Where it appears in the course
Day 18 uses it as the main example of lossless convexification. Day 2 shows why a ring is not convex, Day 5 introduces SOCPs, and Day 12 solves them.
Check yourself
Q1. What makes the original powered-descent problem nonconvex?
The minimum turns the allowed set into a ring with a hole. The glide slope is tempting, but it is a convex cone and does no harm.
Q2. The relaxation allows 3000 N of thrust with Γ = 4972 N, which the engine cannot produce. Why is that harmless?
The extra room exists, but the optimum never uses it. No rounding is needed: the relaxed optimum already fits the real engine.
Q3. What does Blackmore's 2017 chapter, written at SpaceX, actually state?
That is the chapter's statement. It does not say which problem the flight code solves, so "Falcon 9 runs the 2007 algorithm" goes beyond the source.
Footstep Planning on Uneven Terrain with Mixed-Integer Convex Optimization
Planned where a humanoid robot puts each foot by letting yes/no variables pick a convex safe patch for every step, then solved the whole plan to proven global optimality.
In one sentence
Cut the walkable ground into a few convex safe regions, and let binary variables pick one region, and one piece of a sin/cos approximation, for each footstep. What remains is convex, so a mixed-integer solver returns the globally best plan or proves that none exists.
Explain it to a 10-year-old
To cross a stream on stepping stones, you choose which stone each foot goes on. Once the stones are picked, finding the exact spot on each one is easy, like sliding your foot around a flat rock. The hard part is the picking, because there are so many ways to pick. The computer skips any group of choices that cannot beat its best plan so far. So in the end it can say "this is the best plan" or "there is no way across".
The problem
A humanoid such as Atlas must choose x, y, z and a yaw angle θ for each of N footsteps toward a goal. Each step must avoid obstacles and be reachable from the last one. Deits 2014 Both rules are nonconvex. The floor around an obstacle has a hole in it (Day 2), and turning the foot brings in sin θ and cos θ.
Earlier planners each gave something up. Graph search (A*, RRT) over a fixed menu of steps trades menu size against coverage. The authors' own nonconvex optimizer from the 2013 DARPA Robotics Challenge had no optimality guarantee and could not route around obstacles. QP planners fixed the foot angles and ignored obstacles.
The key idea
Let integer variables absorb every nonconvex part, so the rest is convex once they are fixed. Branch and bound (Day 15, branch-and-bound card) then returns the global optimum or proves that no plan exists.
Obstacles become region choices. The companion IRIS algorithm covers the walkable floor with R convex obstacle-free regions. Each is a polytope in (x, y, yaw) on a flat terrain plane. Step j gets one binary Hr,j per region:
Hr,j = 1 ⇒ Arfj ≤ br, Σr Hr,j = 1
Here fj is the pose of step j, and Arf ≤ br describes region r. The sum puts each step in exactly one region, and the implication is written with big-M or indicator constraints. With 10 regions and 20 steps that is only 200 region binaries. The older drone pattern (Richards et al.) needed one binary per obstacle face. Deits 2014
Rotation becomes a piece choice. Variables sj and cj stand in for sin θj and cos θj, and more binaries pick one straight piece of each curve. The pieces never overstate how far the foot can reach.
Reach becomes two discs. Each step must lie where two discs, placed in the previous foot's frame, overlap. These are convex quadratic constraints. So the problem is a mixed-integer quadratically constrained QP (MIQCQP), the authors' own term. It is not a plain MIQP, which would have only linear constraints.
Top view, own drawing. The free floor (all three colours together) is not convex, because the obstacle bites into it. Each coloured region is convex. Every footstep (filled oval) has binaries that say "I am in region r", so the plan goes over the obstacle through region 2. Steps 5 and 10 sit where two regions overlap, and either choice is valid.
How it works
Grow the regions with IRIS, from seed points that a human picked.
Fix N step slots. A trim binary tj = 1 pins step j to the current foot position, and a negative cost qt rewards plans with fewer real steps.
Minimize distance to the goal pose g, the trim reward and step size, with weight matrices Qg and Qr:
(fN − g)TQg(fN − g) + Σj qttj
+ Σj (fj+1 − fj)TQr(fj+1 − fj)
Add the region implications, the sin/cos pieces, the reach discs, the "exactly one" sums and bounds.
Solve with Gurobi in MATLAB, inside the Drake toolbox. Mosek and CPLEX also worked, but Gurobi was generally faster.
Results
With 10–20 footsteps and 10 regions, solves took a few seconds to one minute on an Intel i7 2.9 GHz laptop. A few steps took "well under one second". Deits 2014
Every plan shown was within 0.1% of the global optimum, as reported by Gurobi. That is the gap between the best plan and a proven lower bound.
In simulation, Atlas climbs a pedestal in one stride. It detours when the pedestal is twice its maximum step height, and turns sideways through a narrow gap.
On real LIDAR scans of cinderblocks, 7 regions covered the walkable tops. Atlas's stride was 40 cm at most, about 20 cm nominal.
Why it mattered
To the authors' knowledge, it was the first method to solve a whole footstep plan to global optimality with guaranteed obstacle avoidance. It is also complete within its model: "infeasible" means no plan exists. Precomputed convex safe sets plus one binary choice per contact became a standard way to plan contacts in robotics.
Limitations
It needs enough regions, and seeding them by hand "clearly sacrifices autonomy", in the authors' words.
Each region must be flat terrain.
Only foot placements are checked for collisions, not the swing between them.
Up to a minute is too slow for long horizons while walking.
It is optimal only within the model. The sin/cos pieces shrink the reach away from multiples of π/2.
Worst-case solve time grows exponentially with steps and regions.
How to read the paper
Read Section II in order. Part A (assigning steps to regions) is the core trick, Part B (reachability) has the sin/cos pieces and the discs, Part C covers the trim variables, and Part D the complete formulation. Then read Section III's results. Section IV lists the limits.
Where it appears in the course
Day 15 uses it as the robotics example of binaries and branch and bound. Day 19 returns to convex safe pieces, and the IRIS paper shows how the regions are grown.
Check yourself
Q1. In the planner, what does Hr,j = 1 mean?
Hr,j = 1 switches on region r's constraints for step j. Trimming has its own binary, tj.
Q2. Why do the authors call the problem an MIQCQP rather than an MIQP?
An MIQP has a quadratic cost but only linear constraints. The disc constraints are quadratic, hence "quadratically constrained".
Q3. Gurobi reports a plan within 0.1% of the global optimum. What does that mean?
Branch and bound keeps a best plan and a lower bound, and the gap between them is the certificate. Obstacle avoidance is never traded away.
2014 · Schulman, Duan, Ho, Lee, Awwal, Bradlow, Pan, Patil, Goldberg, Abbeel · Int. J. Robotics Research
Motion Planning with Sequential Convex Optimization and Convex Collision Checking
Turned robot-arm motion planning into a loop of small convex QPs that push a straight-line guess out of collision, finding short, smooth paths in a fraction of a second.
In one sentence
Start from a straight-line path that may pass through obstacles. Then repeatedly solve a convex QP in which collisions are a linearized penalty on signed distance and each step stays inside a box trust region, raising the penalty until the path is collision-free.
Explain it to a 10-year-old
Stretch a rubber band straight from one hand to the other, right through a table leg. That band is a path that crashes. Now nudge it a little away from the leg, and nudge again. Each nudge is small, so you can guess where the band will go. After a few nudges it bends around the leg. TrajOpt plans robot-arm motions this way, and each nudge is a small, easy math problem.
The problem
A robot arm with 7 joints, or a whole robot with 18 or even 34, must move between two poses without hitting anything. The plan is a list of joint angles at T time steps. The authors wanted short, smooth, collision-free paths, found quickly from a straight-line guess that may pass right through obstacles. Schulman 2014
The no-collision rule is nonconvex, because the space outside an obstacle has a hole in it (Day 16). The rivals were sampling planners such as RRT, which give longer paths, and CHOMP, a gradient method on a smoothness-plus-obstacle cost.
The key idea
Use sequential convex optimization. Around the current path, build a convex model and solve it as a QP, but move only within a small box called the trust region. Then repeat (SCP card). Three choices make this work for robots.
Exact ℓ1 penalties. Instead of enforcing gi(x) ≤ 0 and hi(x) = 0 strictly, TrajOpt adds their violations to the cost:
f(x) + μ Σi |gi(x)|+ + μ Σi |hi(x)|
Here |a|+ = max(a, 0) and μ is a penalty weight. With μ large enough, the minimizer satisfies the constraints, which is why the penalty is called exact. Every subproblem stays feasible, even from a guess deep in collision.
Collisions as a hinge. The signed distance sd between two shapes is their gap, or minus their overlap depth. TrajOpt penalizes |dsafe − sd|+ for each nearby pair, where dsafe is a safety margin. With illustrative numbers, take dsafe = 5 cm: a 2 cm overlap costs 7 cm times μ, and a 10 cm gap costs nothing. The signed distance is linearized through the robot's Jacobian, so it becomes linear in the joint angles.
Safety between time steps. TrajOpt also checks the convex hull of a link at two neighbouring time steps, which covers the volume it sweeps in between.
Own sketch of a 2-D joint space with 11 waypoints, like the benchmark's T = 11 time steps. Each iteration may move a waypoint only inside its trust-region box, so iteration 1 is still in collision. As the penalty and the boxes adapt, the path is pushed over the obstacle.
How it works
Start from a straight line in joint space, collision or not.
Convexify around the current path, with linearized constraints inside ℓ1 penalties.
Solve the QP inside the box trust region.
Compare the true improvement with the model's predicted improvement. If the ratio beats a threshold, accept and grow the box. Otherwise shrink it and solve again.
If constraints are still violated when steps stop helping, multiply μ by 10 and go back to step 2.
In the benchmarks, stop after 40 iterations, or when the improvement ratio or box size falls below 10−4.
Distance queries use the Bullet physics library, and the QPs go to Gurobi or BPMPD.
Results
On 198 arm problems for the PR2 robot (7 joints, T = 11), on an Intel i7 at 3.5 GHz: Schulman 2014, Table I
Planner
Success rate
Average time
Path length (normalized)
TrajOpt
0.82
0.19 s
1.16
OMPL RRTConnect
0.85
0.62 s
1.56
CHOMP (HMC variant)
0.65
4.91 s
2.04
With several initial guesses, TrajOpt's success rose to 0.96. On 96 whole-body problems with 18 joints, it succeeded on 0.73 (0.88 with several guesses) against 0.41 for RRTConnect, in 2.2 s against 20.3 s.
Why it mattered
It showed that sequential convex optimization is a practical, fast planner for arms and humanoids, and it came with open-source BSD code. TrajOpt project page Many later SCP methods in robotics build on it or compare against it, including GuSTO.
Limitations
Results depend strongly on the initial guess, and several guesses are often needed.
There is no guarantee of a collision-free path, since the constraint is nonconvex.
It gets stuck when obstacles push waypoints in conflicting directions.
Self-collisions are checked only at the discrete time steps.
Start with Section III and Algorithm 1: the whole solver loop is there. Then read Section IV on the no-collision constraint, where Fig. 3 shows the hinge penalty. Section V has the benchmark tables. Read Section IX on initialization before you use the method. Sections VII and VIII are optional.
Where it appears in the course
Day 18 uses it as the SCP example in manipulation. Day 16 explains why the initial guess matters, and Day 19 covers convex collision checking.
Check yourself
Q1. How does TrajOpt handle the no-collision constraint?
The hinge is zero beyond the margin and grows with penetration. Binary region choices belong to the footstep paper.
Q2. Why can TrajOpt start from a straight line through an obstacle?
With hard constraints, a guess deep in collision could make the QP infeasible. Penalties turn violation into cost, and raising μ drives it to zero.
Q3. Which statement matches the 198 PR2 arm problems?
From one guess it succeeded on 82%, just below RRTConnect's 85%. Several guesses lifted it to 96%, and its paths were the shortest.
SCvx and GuSTO: Sequential Convex Programming with Convergence Guarantees
Two closely related recipes that make the "linearize, solve a convex problem, repeat" loop safe to use on robots and spacecraft, with proofs that it converges.
In one sentence
Both methods linearize around the last trajectory, solve a convex subproblem inside a trust region, and use slack (virtual control in SCvx, soft penalties in GuSTO) so every subproblem has a solution. A predicted-versus-actual test accepts or rejects each step, and proofs show the loop converges to a stationary, locally optimal point.
Explain it to a 10-year-old
You are walking in fog with a map that is only right near you, so you step only as far as you can see. If the ground matched the map, take bigger steps next time; if not, smaller ones. Sometimes the map says "no way through" only because you can't see far. Then you may cheat a little, but you pay a big fine, so you stop cheating as soon as you can.
The problem
Sequential convex programming (SCP) means: linearize around your current trajectory, solve the convex subproblem, move, repeat (Day 18, SCP card). Done naively, it breaks in two ways. Malyuta 2022
Artificial infeasibility means the linearized subproblem has no solution though the real problem does. Say a point sits 0.5 m from the centre of a round obstacle of radius 2 m and may move at most 1 m. The linearized rule puts the safe line 1.5 m away, so the point falls 0.5 m short. Artificial unboundedness means that, without a step limit, a linear model can promise endless improvement.
The theory had a gap too. SCP methods popular in robotics, such as TrajOpt, lacked guarantees for general dynamics and free final time. Methods with guarantees did not handle collision constraints well. Bonalli 2019
The key idea
SCvx (Mao, Szmuk and Açıkmeşe, 2016) adds a virtual control ν, a fictitious input that may break the linearized dynamics at a price. Mao 2016
xk+1 = Akxk + Bkuk + ck + Eνk
Ak, Bk and ck come from linearizing around the last trajectory, and E says where ν enters. The cost gains λ‖ν‖1 with a large weight λ. A slack on the obstacle rule works the same way: in the example, 0.5 m of slack makes the first subproblem feasible, and the next iteration needs none. At convergence the slack must be zero; otherwise the result is a "soft failure".
SCvx also judges each step by comparing the real improvement with the promised one:
ρ = (J(x̄) − J(x*)) ÷ (J(x̄) − L(x*))
J is the real penalized cost, L its convex model, x̄ the current trajectory and x* the subproblem's answer. Take example thresholds ρ0 = 0, ρ1 = 0.1 and ρ2 = 0.7. If J(x̄) = 6.0, L(x*) = 5.0 and J(x*) = 5.8, then ρ = 0.2 / 1.0 = 0.2: accept and keep the trust region. If J(x*) were 6.1, ρ = −0.1: reject and shrink.
The SCvx step test, own drawing with the zones drawn equal width (not to scale). Δ is the trust-region size. With the example numbers, ρ = 0.2 lands in "accept, keep Δ" and ρ = −0.1 in "reject, shrink Δ".
GuSTO (Bonalli, Cauligi, Bylard and Pavone, 2019) keeps the loop but moves state constraints, such as collision avoidance, and the trust region into the cost as soft penalties whose weight grows. It covers control-affine dynamics with drift, ẋ = f0(x) + Σi uifi(x), plus goal sets and free final time. Its proof works in continuous time with Pontryagin's maximum principle, so it does not depend on how finely time is split. The subproblem's dual variables can also warm-start a fast shooting method. Bonalli 2019
Both guarantees are about reaching a stationary point, one that meets the first-order optimality conditions, not the global optimum. A later SCvx paper claims "global convergence" with a superlinear rate. There, "global" means from any starting guess, not to the best trajectory. Mao 2018
How it works
Pick an initial guess; a straight line, even through obstacles, is common.
Linearize and discretize. GuSTO's experiments use a trapezoidal rule with 30–40 nodes.
Solve the convex subproblem (a QP or SOCP) with the trust region and slack or penalties.
Run the acceptance test, accept or reject, and resize the trust region. GuSTO also raises the penalty weight.
GuSTO only: optionally try a shooting method from the dual variables, at under 1 ms per try.
Stop when the predicted improvement and the slack are both about zero.
Results
NASA's Astrobee free-flyer (a 12-D model) in a mock-up of the ISS, 100 trials from straight-line guesses: GuSTO and TrajOpt each succeeded 97% of the time, with GuSTO faster and lower in cost. Mao et al.'s method failed often. Bonalli 2019
An 8-D airplane with its best initialization: GuSTO took 0.55 s against TrajOpt's 2.67 s, and improved the cost by 55% against TrajOpt's 49%.
The shooting warm start cut solve time by 52% on a Dubins car and 74% on the free-flyer.
In the Malyuta tutorial's quadrotor example, SCvx and GuSTO were "equally fast". GuSTO's subproblem had 542 variables against 640, because it has no dynamics virtual control. Malyuta 2022
Why it mattered
These papers brought SCP with proofs into mainstream robotics at speeds comparable to TrajOpt. SCvx and GuSTO are the two SCP methods the Malyuta tutorial teaches, with open-source code. A practitioner can now say why the loop stopped and what kind of point it found.
Limitations
A stationary point is not the global optimum, and another guess may do better.
GuSTO assumes control-affine dynamics.
On the airplane, straight-line guesses failed for all three methods.
Testing was mostly in simulation, with a small hardware demo.
Slack can stay nonzero, and the weights and thresholds need tuning.
How to read the paper
Start with Part II of the Malyuta tutorial: Fig. 16 shows SCvx's update rule and Fig. 17 GuSTO's. Then read the GuSTO paper's Sections II-B, III-A and IV-B (with Fig. 3). Leave the proofs in Section III-B and the appendix for later. The SCvx paper is a short CDC 2016 paper with the convergence analysis.
Where it appears in the course
Day 18 builds the trust region, virtual control and ρ test step by step. Day 16 explains stationary points, and Day 19 uses SCP for collision avoidance.
Check yourself
Q1. What is SCvx's virtual control for?
It patches artificial infeasibility, and a big penalty pushes it to zero. It works alongside the trust region, not instead of it.
Q2. SCvx computes ρ = 0.05 with ρ0 = 0, ρ1 = 0.1 and ρ2 = 0.7. What does it do?
0.05 lies between ρ0 and ρ1. The step helped, so keep it, but the model was too optimistic, so step shorter next time.
Q3. What does GuSTO's guarantee promise?
It is a local guarantee. On the airplane, straight-line guesses failed for every method.
2019 · Rosen, Carlone, Bandeira, Leonard · Int. J. Robotics Research
SE-Sync: A Certifiably Correct Algorithm for Synchronization over the Special Euclidean Group
Solved pose-graph SLAM, a nonconvex problem, through a convex semidefinite relaxation that is usually exact, and returned a certificate proving the answer is the global optimum.
In one sentence
Remove the translations in closed form, relax the remaining rotation problem to a semidefinite program that is exact when noise is moderate, solve that SDP fast with a low-rank Riemannian method, round, and check that the result reaches the SDP's lower bound, which proves global optimality.
Explain it to a 10-year-old
You walk around a building with a step counter and a compass, writing notes like "from the door, the stairs are 3 steps north". The notes are a little wrong, and you want the map that fits them best. The usual way fixes a guessed map bit by bit, and it might get stuck on a wrong map without knowing. SE-Sync also solves a looser puzzle whose score no real map can beat: a floor. If your map's score sits on the floor, nothing better exists.
The problem
In pose-graph SLAM, a robot estimates its poses x1, …, xn along a route, each a rotation Ri plus a translation ti. The data are noisy relative measurements: odometry between neighbours, plus loop closures when it revisits a place. Rosen 2017 Under the paper's noise model, the maximum-likelihood estimate (MLE) solves
min Σij κij‖Rj − RiR̃ij‖F2
+ τij‖tj − ti − Rit̃ij‖22
over ti ∈ ℝd and rotations Ri ∈ SO(d). The tilde marks a measurement, κij and τij are confidence weights, and ‖·‖F is the Frobenius norm.
The rotation constraint makes this nonconvex. The 2-D rotations by +90° and −90° are [[0, −1], [1, 0]] and [[0, 1], [−1, 0]], and their average is the zero matrix, not a rotation. The standard solver, Gauss–Newton (Gauss–Newton card), needs a good start, can stop in a local minimum, and cannot tell when it has.
The key idea
First eliminate the translations: for fixed rotations, they come from a linear least-squares solve. Then stack R = [R1 … Rn] and form Z = RTR, whose (i, j) block is RiTRj. The cost becomes linear in Z. The relaxation keeps two properties every such Z has and drops the hard one, that Z must factor into rotations:
min tr(Q̃Z) s.t. Z ⪰ 0, Zii = Id
Q̃ is a fixed data matrix and Zii are the d × d diagonal blocks. This convex semidefinite program (SDP) (Day 5) comes from Lagrangian duality (Day 9). Every true set of rotations gives a feasible Z, so the SDP's value pSDP is a lower bound on the MLE cost. Rosen 2017
Two results make this useful. Below a critical noise level, the SDP has a unique solution Z* = R*TR*, which gives the exact global MLE. And you can check it afterwards: if a rounded estimate's cost equals pSDP, it is provably the global optimum. If not, the gap bounds how far off it can be.
The certificate as a sandwich, own drawing. The convex SDP is solved to its global optimum, so its value is a guaranteed floor. Any real estimate costs at least the true optimum, which costs at least the floor. When the estimate touches the floor (top), nothing can beat it. When it does not (bottom), you still learn how much you might be losing.
How it works
General interior-point SDP solvers stall beyond a few thousand dimensions, and real SLAM problems are one to two orders of magnitude larger. SE-Sync uses the problem's structure instead.
Low rank. Write Z = YTY, where each block of Y is an r × d matrix with orthonormal columns and r is much smaller than dn. Then Z ⪰ 0 holds automatically. This is the Burer–Monteiro idea.
Riemannian Staircase. Find a second-order critical point at rank r. If it is rank-deficient, it solves the SDP. Otherwise raise r and repeat, starting from r = 5. The authors note that one or two "stairs" typically suffice.
Solve each level with a truncated-Newton trust-region method that uses only Hessian-vector products (Day 11).
Round with a rank-d SVD, project each block onto SO(d), and recover the translations in closed form.
Certify by comparing the estimate's cost with pSDP.
Results
The runs used MATLAB on a 2.8 GHz laptop, against Gauss–Newton started from the standard chordal initialization. On six 3-D SLAM benchmarks, both methods reached the same cost, but only SE-Sync's answer was certified, with a suboptimality bound of at most 5.6 × 10−11. Rosen 2017, Table 1
Dataset
Poses
Gauss–Newton
SE-Sync
Speed-up
sphere
2500
14.98 s
2.81 s
5.3×
torus
5000
31.94 s
5.67 s
5.6×
grid
8000
130.35 s
22.37 s
5.8×
garage
1661
17.81 s
5.33 s
3.3×
cubicle
5750
136.86 s
13.08 s
10.5×
rim
10195
575.42 s
36.66 s
15.7×
So the speed-ups ran from 3.3× to 15.7×. In simulated cube worlds, the relaxation stayed exact up to about 15° RMS rotation noise, roughly 10 times typical sensor noise by the authors' estimate.
Why it mattered
SE-Sync made "certifiably correct" estimation practical in robotics. A standard nonconvex robot problem could be solved to global optimality, with a proof, faster than the local methods in use. It needs no good initial guess to reach the global optimum, though a good guess still saves time.
Limitations
Exactness holds only below a noise threshold. Above it you get a feasible estimate and a bound, but no certificate.
It assumes isotropic Gaussian and Langevin noise and no outliers.
In the worst case the Staircase can climb to rank dn + 1.
It covers pose graphs only, not landmarks or camera projection models.
The numbers here come from the arXiv v2 preprint and may differ from the IJRR version.
How to read the paper
Read Section 1 and Section 2.2 (the problem). In Section 3, skim 3.1 and read 3.2 slowly: Problem 7 and the exactness result are the heart of the paper. Sections 4.1.2 (the Staircase) and 4.2 (rounding) explain the speed. Then read Section 5, with Fig. 2 for the noise threshold and Table 1 for the benchmarks. The manifold background in Section 2.1 can wait.
Where it appears in the course
Day 16 uses it as the main example of a convex relaxation solving a nonconvex robot problem. Day 5 introduces SDPs and Day 9 the duality behind the bound.
Check yourself
Q1. Why is the pose-graph MLE nonconvex?
The cost is a sum of squares, and the translations are easy least squares. The rotation set is the hard part, as the ±90° example shows.
Q2. What does SE-Sync's certificate tell you?
No estimate can beat the floor, so touching it proves optimality. Above the noise threshold you get a bound instead.
Q3. On the six SLAM benchmarks, how did SE-Sync compare with Gauss–Newton?
Table 1 gives 3.3× (garage) to 15.7× (rim) at the same objective. The extra value is the proof, not a lower cost.
OSQP: An Operator Splitting Solver for Quadratic Programs
A free ADMM-based QP solver that factors one matrix once and then iterates with cheap vector steps, which makes it fast for MPC loops and embedded code.
In one sentence
Run ADMM on the QP "min ½xTPx + qTx subject to l ≤ Ax ≤ u" with a splitting whose only linear system keeps the same matrix at almost every iteration. Factor it once, and each iteration is a cheap solve plus a clip to the box [l, u], with infeasibility detection and warm starts built in.
Explain it to a 10-year-old
Sorting a huge pile of LEGO, the slow part is building a sorting tray. Once the tray exists, each round is quick: drop pieces in, and push back any piece that sticks out. Tomorrow's pile is similar, so you keep the tray and start from yesterday's bins. OSQP builds its tray (a matrix factorization) once. A robot's controller gets a new, similar pile every few milliseconds, so the trick pays off again and again.
The problem
A quadratic program (QP) has a convex quadratic cost and linear constraints. OSQP writes every QP in one form: Stellato 2020
min ½xTPx + qTx s.t. l ≤ Ax ≤ u
P is positive semidefinite (P ⪰ 0), so the cost is a convex bowl. Each row of A gets a lower bound in l and an upper bound in u. Setting li = ui makes an equality. For a car, the steering limit −0.5 ≤ δ ≤ 0.5 rad is one row.
Model predictive control solves one such QP every control cycle, and consecutive QPs differ only a little (Day 17). The authors wanted a solver that is robust (P may be singular), detects infeasible problems, reuses work and runs on embedded hardware. Interior-point methods (Day 12) are accurate, but their linear-system matrix changes at every iteration, so the expensive factorization is repeated.
The key idea
OSQP runs ADMM (Day 13, ADMM card) on a copy z = Ax of the constraint values. The splitting makes the only linear system use the same matrix at almost every iteration:
K = [ P + σI AT ; A −ρ−1I ]
Here σ and ρ are positive step parameters. K is quasi-definite (positive definite top-left block, negative definite bottom-right), so it always has an LDLT factorization. Factor K once, and every later iteration costs two triangular solves, some vector additions and a clip. Stellato 2020
OSQP's loop, own drawing. The only expensive work, factoring K, happens once. In MPC only q, l and u change between solves, so the factor is kept and the next solve starts from the last answer (dashed arrow).
How it works
Setup. Scale the data and factor K once.
Solve. With the saved factor, solve K·(x̃, ν) = (σxk − q, zk − ρ−1yk). Set z̃ = zk + ρ−1(ν − yk) and xk+1 = αx̃ + (1 − α)xk, with α = 1.6.
Clip onto the box:
zk+1 = Π[l,u](αz̃ + (1 − α)zk + ρ−1yk)
With l = −0.5 and u = 0.5, the clip sends 0.8 to 0.5 and leaves −0.2 alone.
Check. Stop when the residuals are small. Differences of successive iterates certify primal or dual infeasibility.
Polish (optional): guess the active constraints and solve one equality-constrained QP for high accuracy.
The paper's defaults are σ = 10−6, α = 1.6 and an adaptive ρ. Changing ρ forces a new factorization, hence "almost" every iteration. For a new problem with the same P and A, keep the factor and warm-start from (x*, Ax*, y*). The generated embedded C code is malloc-free, library-free and division-free. OSQP docs
Results
On 1400 benchmark QPs (7 classes, up to 104 variables and 105 constraints), times are normalized so the fastest solver scores 1.00, and failures count as 1000 s. Runs were single-threaded on an Intel Xeon cluster. Stellato 2020, Table 1
Solver
Time, low accuracy (10−3)
Time, high accuracy (10−5)
Failures, low / high
OSQP
1.000
1.000
0% / 0%
GUROBI
4.285
1.886
1.4% / 1.4%
MOSEK
2.522
6.234
0.07% / 11.0%
ECOS
28.847
52.718
20.7% / 45.6%
qpOASES
149.932
66.254
31.9% / 31.7%
In the MPC test (Table 7), warm starting plus factorization caching cut the time from 7 ms to 2 ms with 20 states, and from 67 ms to 22 ms with 80. At 80 states the iteration count barely moved (32.0 to 31.75), so most of the gain came from reusing the factorization.
Why it mattered
OSQP made a robust, free (Apache 2.0), dependency-free QP solver available from C, Python, Matlab, Julia, R and Rust, with embedded code generation. The authors reported "tens of thousands of users" in 2020. Stellato 2020 It became a standard backend for MPC prototypes. OSQP MPC example
Limitations
As a first-order method, it gives moderate accuracy unless polishing works. Polishing succeeded on 42.8% of problems at low accuracy and 83.2% at high.
On hard, badly scaled problems (the Maros–Mészáros set), GUROBI is faster. OSQP's normalized time there is 1.464 at low accuracy and 5.247 at high.
Choosing ρ is "still an open research question", in the paper's words.
The benchmarks ran on server CPUs, not microcontrollers.
Defaults have changed: the docs now list rho 0.1 and polishing off, as of Oct 2026. OSQP settings
How to read the paper
Read Section 1.3 for the pitch, then Section 3: 3.1 explains the quasi-definite system, and 3.2 gives Algorithm 1, the whole solver in a few lines. Section 3.3 on infeasibility is short and worth it. Skip Sections 4 and 5 (polishing, parameters) on a first pass. MPC users need Section 6 on warm starts and caching. In Section 8, see Table 1, then Table 7.
Where it appears in the course
Day 17 builds an MPC problem as an OSQP QP. Day 13 covers the ADMM underneath, and Day 21 compares solvers in practice.
Check yourself
Q1. What makes each OSQP iteration cheap?
After one factorization, an iteration is triangular solves, vector updates and a clip. The benchmarks are single-threaded CPU runs.
Q2. In the MPC test, the time at 80 states fell from 67 ms to 22 ms. Where did most of the gain come from?
The iteration count hardly moved at that size, so the saving is the skipped factorization, not fewer iterations.
Q3. The clip step projects onto [l, u] with l = −0.5 and u = 0.5. Where does 0.8 go?
A box projection moves each entry to the nearest allowed value. 0.8 is above u, so it becomes 0.5.
2022 · Malyuta, Reynolds, Szmuk, Lew, Bonalli, Pavone, Açıkmeşe · IEEE Control Systems Magazine
Convex Optimization for Trajectory Generation: A Tutorial on Generating Dynamically Feasible Trajectories Reliably and Efficiently
A 68-page tutorial on the two main ways to plan vehicle trajectories with convex optimization, lossless convexification and sequential convex programming, with theory, worked examples and code.
In one sentence
If a trajectory problem's nonconvexity has a special structure, lossless convexification solves it exactly with one convex program. Otherwise, sequential convex programming (SCvx or GuSTO) solves a chain of convex approximations with trust regions and slack, and converges to a locally optimal trajectory.
Explain it to a 10-year-old
Think of a cookbook for rocket and drone paths. Chapter one: some hard puzzles have a secret easy twin with the same answer, and you learn to spot them. Chapter two: for the other puzzles, solve a chain of easy ones, each a small fix to the last. Chapter three: three full recipes, a rocket landing, a drone dodging obstacles and a robot floating in a space station, with code you can run.
The problem
Rockets, spacecraft, drones and ground robots need trajectories that obey their dynamics and limits. These problems are nonconvex for three common reasons: nonconvex control limits (a minimum engine thrust), nonconvex state limits (keeping out of obstacles) and nonlinear dynamics. Malyuta 2022
Onboard use needs speed and reliability, which favours convex optimization (Day 1). Practitioners lacked one implementable account of how to make convex methods handle these nonconvex problems.
The key idea
The tutorial offers two routes. In its own image, lossless convexification is "a surgical knife to remove acute nonconvexity", and SCP is "a catch-all sledgehammer". Malyuta 2022
Route 1: lossless convexification (LCvx). When the nonconvexity has a special structure, a convex relaxation can be proved to give the original problem's global optimum. One convex solve does the job. The classic case is the thrust ring of the Açıkmeşe & Ploen paper.
Route 2: sequential convex programming (SCP). Otherwise, linearize around a guess, add a trust region and slack, solve, and iterate. The tutorial teaches two such methods, SCvx and GuSTO, each guaranteed to converge to a locally optimal point.
The tutorial's map as a decision, own drawing. LCvx can also sit inside an SCP loop, handling the structured part of a problem while SCP handles the rest.
How it works
Part I, LCvx. The theory for nonconvex input constraints such as the thrust ring, then for some state constraints, then LCvx embedded inside SCP. The proofs use Pontryagin's maximum principle.
Part II, SCP. A generic loop of starting, iterating and stopping (Fig. 11). Time discretization, the two failure modes (artificial infeasibility and unboundedness) and their cures. Then SCvx's ρ-ratio trust-region rule (Fig. 16) and GuSTO's penalties and acceptance rule (Fig. 17).
Part III, examples. A 3-DoF rocket landing with LCvx, a quadrotor flying around obstacles, and a 6-DoF free-flyer in a space station, the last two solved with both SCvx and GuSTO. The code reproduces every plot and offers a CVX-like interface to both methods.
Results
As a tutorial, its results are worked examples rather than new benchmarks. It runs 68 pages with 42 figures and 5 tables. arXiv 2106.09125
Quadrotor example: 30 time nodes, 15 iterations, ECOS on an Intel i5-7200U laptop. SCvx's subproblem has 640 variables and GuSTO's 542, because GuSTO has no dynamics virtual control (Table 3). The two are "equally fast", roughly 1 s in total as read from the axes of Fig. 24. Malyuta 2022
Flight record it reports: JPL's LCvx-based tests on Masten's Xombie rocket, including a 750 m divert (Fig. 18), and a NASA–Blue Origin partnership testing an SCP algorithm aboard New Shepard.
It won the 2023 IEEE Control Systems Magazine Outstanding Paper Award. UW news 2024
Why it mattered
It is the standard entry point to convex trajectory optimization. It gathers the theory behind flight-tested methods in one notation, with code that reproduces every figure. A reader can go from "why is this nonconvex?" to running SCvx on their own vehicle model.
Limitations
It focuses on the authors' own methods. It is not a neutral benchmark against SQP or IPOPT-based methods (SQP card).
SCP can converge to local optima, or to "soft failure" points where the slack never reaches zero.
LCvx covers only narrow problem classes.
Its industry remarks are hedged. It writes "we hypothesize that LCvx is also a close relative of the SpaceX Falcon 9 terminal landing algorithm" and notes that SpaceX's methods are undisclosed. Treat those lines as hypotheses.
How to read the paper
Read it in passes. Pass 1: the introduction and Fig. 11, for the map. Pass 2: Part I up to the rocket-landing relaxation, with sidebar figure S1. Pass 3: Part II on artificial infeasibility and unboundedness, then SCvx (Fig. 16) and GuSTO (Fig. 17). Pass 4: Part III's quadrotor example with the code open beside it. Leave the detailed proofs for a second reading.
Where it appears in the course
Day 18 follows its structure, from direct transcription to lossless convexification. Day 19 uses its obstacle examples, and Day 5 introduces the SOCPs in every subproblem.
Check yourself
Q1. When does lossless convexification apply instead of SCP?
LCvx needs structure plus a proof of exactness. Obstacles and general nonlinear dynamics are where you reach for SCP.
Q2. In the quadrotor example, why is GuSTO's subproblem smaller (542 variables against 640)?
Both use 30 nodes and ECOS. SCvx adds virtual-control variables, while GuSTO uses penalties instead.
Q3. What does the tutorial say about SpaceX?
It labels the remark a hypothesis. The first-hand statement is Blackmore's 2017 chapter, covered in the lossless convexification entry.
2015 · Deits, Tedrake · Algorithmic Foundations of Robotics XI (WAFR 2014)
Computing Large Convex Regions of Obstacle-Free Space Through Semidefinite Programming
IRIS grows one large obstacle-free convex region around a seed point by alternating a tiny QP and an ellipsoid SDP, and it stays fast with a million obstacles.
In one sentence
Put a flat wall between a small ellipsoid and every obstacle, fit the biggest ellipsoid inside the walls, and repeat until it stops growing. The walls then outline a big convex "room" that a planner can use as plain linear constraints.
Explain it to a 10-year-old
You stand in a messy playroom with a balloon. You put a flat sheet of cardboard between the balloon and each nearby toy. Then you blow the balloon up as big as it can go without pushing through a sheet. With the bigger balloon, you move the sheets out as far as the toys allow, and blow again. Soon the balloon stops growing. The sheets now fence off a big toy-free space where you can walk in any straight line.
The problem
Free space around obstacles is not convex. Two safe points can have an unsafe point between them, like two people on opposite sides of a pillar (Day 19). Convex solvers need convex constraints, so a planner needs another way in.
The authors came to this from footstep planning for the Atlas humanoid. They turned steep terrain cells into obstacles and wanted convex patches where an optimizer could place each foot. Deits 2015
One idea is to split free space into the fewest convex pieces. That is NP-hard even in 2-D. The paper also argues it is the wrong goal: a few large regions near useful spots beat a complete cover. Deits 2015
The key idea
IRIS (Iterative Regional Inflation by Semidefinite programming) keeps two objects. A polytope P = {x : Ax ≤ b} is the room, with one row of A per wall. An ellipsoid is written as a stretched unit ball:
E = { Cx̃ + d : ‖x̃‖2 ≤ 1 }
Here d is the centre and the matrix C ⪰ 0 does the stretching. The volume of E is proportional to det C, and log det C is concave, so "make E as big as possible" is a convex problem. Deits 2015
Finding the walls and the ellipsoid together is hard. Each one alone is easy. So IRIS alternates: fix the ellipsoid and find walls, then fix the walls and find the biggest ellipsoid.
One IRIS round, own drawing. Left: from a small ball at the seed, find each obstacle's closest point and put a wall there. Right: inflate the largest ellipse that fits behind the walls. The next round moves the walls out against it.
How it works
Seed. Pick a point q0 in free space, for example where an operator clicked. Start with a tiny ball there: d = q0 and C = εI for a small ε.
Walls, one small QP per obstacle. Map the obstacle into "ball space", x̃ = C−1(x − d), where the ellipsoid becomes the unit ball. Finding the obstacle point nearest the origin there is a tiny QP. Map that point back and put a wall through it, tangent to a grown copy of the ellipsoid. Skip obstacles that an earlier wall already blocks.
Biggest ellipsoid, one SDP. With the walls fixed, solve
maximize log det C
s.t. ‖Cai‖2 + aiTd ≤ bi for every wall i
Here aiT is row i of A. The left side is how far the ellipsoid reaches in direction ai, so each line says "stay behind wall i".
Repeat until det C grows by less than a tolerance. The timing runs used 2%. Deits 2015, Fig. 5
It always stops. The old ellipsoid still fits behind the new walls, and the SDP finds the global maximum, so the volume never drops. The room is bounded, so the volume cannot grow forever. Deits 2015, Sect. 3.5
A worked example: the biggest ellipse inside the rectangle [−2, 2] × [−1, 1] has d = 0 and C = diag(2, 1). Check the wall x ≤ 2: a = (1, 0), so ‖Ca‖ = 2, and 2 + 0 ≤ 2 holds exactly. The area is π·2·1 ≈ 6.28, which is 78.5% of the rectangle's area of 8.
Results
Each closest-point QP is tiny. A solver generated by CVXGEN handled a typical 8-vertex 3-D obstacle in under 20 µs on an Intel i7, while MOSEK and Gurobi needed over 1 ms. The SDPs went to MOSEK. Deits 2015
The scaling test ran 1,200 times in MATLAB, in 2-D and 3-D, with 10 to 106 obstacles. Time grew about linearly with the obstacle count, and with a million obstacles a region converged in seconds. Deits 2015, Fig. 5 The wall step is linear work, but the number of walls needed stayed nearly constant, so the SDP took nearly constant time.
The seed ended up inside the final region 95% of the time. The method also ran in 3-D, in the 3-D configuration space of a rod-shaped robot, and in a 4-D example. Deits 2015
Why it mattered
IRIS made "cover free space with convex pieces" practical. Its regions feed mixed-integer footstep planning (footstep paper) and Graphs of Convex Sets (GCS paper), where Drake's IrisInConfigurationSpace builds regions for a robot arm. Marcucci 2022, arXiv
Faster successors include IRIS-NP2 and IRIS-ZO (ISRR 2024) and FIRI (T-RO 2025), as of Oct 2026. IRIS-ZO 2024FIRI 2025
Limitations
Obstacles must be convex. Non-convex ones are first split into convex pieces.
No guarantee of the largest region, or that the seed stays inside (95% in the tests).
One region per seed. A human or a heuristic must choose the seeds.
For a robot arm, obstacles in configuration space are not explicit polytopes. That needed later extensions.
How to read the paper
Read Sect. 1 with Fig. 1, then Sect. 3.1 (Algorithm 1, five lines) and Fig. 3, which shows three iterations. Sects. 3.3–3.5 give the QP, the SDP and the convergence argument. Finish with Sect. 4 and Fig. 5. Skip Sect. 2 at first. About 40 minutes.
Where it appears in the course
Day 19 uses IRIS as one of three ways to handle collisions. Day 2 covers polytopes and ellipsoids, Day 5 introduces SDPs, the class of the ellipsoid step, and Day 15 uses convex regions in mixed-integer footstep planning.
Check yourself
Q1. Which two problems does IRIS alternate between?
Each round solves a small closest-point QP per obstacle to place walls, then one log-det SDP for the biggest ellipsoid inside them. No sampling or graph search is involved.
Q2. Why can the ellipsoid's volume never decrease from one round to the next?
The old ellipsoid is a feasible point of the new SDP. A globally optimal answer can only be at least as large. Obstacles never disappear; they are just skipped once a wall blocks them.
Q3. The biggest ellipse in the rectangle [−2, 2] × [−1, 1] has C = diag(2, 1). What share of the rectangle does it cover?
The ellipse area is π·2·1 ≈ 6.28 and the rectangle area is 4·2 = 8, so the share is π/4 ≈ 78.5%. An ellipse can never fill a rectangle completely.
Book chapter (DOI), Crossref: Algorithmic Foundations of Robotics XI, Springer STAR, pp. 109–124, 2015, DOI 10.1007/978-3-319-16595-0_7 (accessed 2026-10-26).
iris-distro, Deits, GitHub: the code linked from the paper (accessed 2026-10-26).
Control Barrier Function Based Quadratic Programs for Safety Critical Systems
Turned "stay safe" into one linear constraint on the control, so a tiny QP at every time step can overrule any controller just enough to keep a car or robot safe.
In one sentence
Write safety as a margin h(x) ≥ 0 that may shrink only slowly near zero, ḣ ≥ −α(h). That rule is linear in the control, so "reach the goal, never break safety" becomes a small QP solved at every step.
Explain it to a 10-year-old
A learner driver has an instructor with a second brake pedal. While the learner drives well, the instructor does nothing. Close to the car in front, the instructor presses the brake a little, and harder the closer they get, so they never bump. When the road clears, the instructor lets go. The CBF-QP is that instructor, written as a tiny math problem the computer solves many times a second.
The problem
Safety and performance often fight. Adaptive cruise control (ACC) wants to hold a set speed, but must slow behind a slower car to keep a safe gap, then speed up when the lead car leaves. Ames 2017
Switching between separate "cruise" and "follow" controllers is fragile. An earlier way of combining safety and goal conditions only worked when both could be met at once. This paper keeps safety strict and lets the goal give way. Ames 2017, Sect. V
The key idea
Take a control-affine system: the state x changes as
ẋ = f(x) + g(x)u
The safe set is C = {x : h(x) ≥ 0}, so h is a safety margin. Along the motion, the margin changes at rate
ḣ = Lfh(x) + Lgh(x)u
Here Lfh = ∇hTf and Lgh = ∇hTg. Notice that ḣ is affine in u. A control barrier function is an h for which some u can always satisfy
Lfh(x) + Lgh(x)u ≥ −α(h(x))
α is increasing with α(0) = 0, for example α(h) = γh. Far from the edge, h may shrink fast. Near the edge, the allowed shrinking goes to zero, so h never crosses zero. Start safe, stay safe: C is forward invariant. Ames 2019, Thm 2
The paper also defines a reciprocal barrier, B = 1/h, which blows up at the edge. This page uses the zeroing form above, as the 2019 tutorial does. Ames 2017, Sects. II–III
How it works
Safety margin. For ACC, the rule "keep half the speedometer" in metres becomes D ≥ 1.8 vf, where D is the gap and vf is your speed. So h = D − 1.8 vf. Ames 2017
Goal. A control Lyapunov function V measures distance from the goal. For ACC, V = (vf − vd)2 with desired speed vd = 22 m/s.
One QP per control step. Solve for the input u and a slack δ:
minu, δ ½uTHu + pδ2
s.t. LfV + LgV u ≤ −cV + δ
Lfh + Lgh u ≥ −α(h)
The goal row has the slack δ, paid for in the cost with weight p. The safety row has none.
Apply, measure, repeat. The QP has only a few variables, so re-solving it every step is cheap.
The tutorial's version keeps an existing controller and edits its command as little as possible. This is the safety filter: Ames 2019
minu ½‖u − unom‖2 s.t. aTu ≥ b
Here a = Lgh(x)T and b = −α(h) − Lfh. With one constraint and no input bounds, the KKT conditions give a closed form (Day 10). If unom already satisfies the rule, keep it. Otherwise project it onto the half-space:
u* = unom + (b − aTunom) a / ‖a‖2
A worked example: a robot moves as ẋ = u toward a wall at x = 5. So h = 5 − x, ḣ = −u, and with α(h) = γh the rule is u ≤ γh. At x = 4 the margin is h = 1. With nominal u = 2 and γ = 1, the filter outputs u* = min(2, 1) = 1. With γ = 5 the limit is 5, so u = 2 passes untouched.
The safety filter, own drawing. Any controller proposes an input. A one-constraint QP edits it as little as possible so the margin h cannot fall too fast. When the rule already holds, the input passes unchanged.
Results
The ACC simulation starts at (vf, vl, D) = (18 m/s, 10 m/s, 150 m), with a 1650 kg car. The car speeds up toward 22 m/s while the gap is large. As it closes on the slower lead car, it slows to follow at the headway limit, and h stays non-negative throughout. Ames 2017, Fig. 2
There was a catch. With no limit on wheel force, the commanded acceleration went past typical comfort bounds. Simply bounding the force can make the QP infeasible, so the paper builds force-aware barriers. With them, all constraints held. Zeroing barriers gave smoother inputs than reciprocal ones, and lane keeping was shown too. Ames 2017, Sect. VI
Why it mattered
Safety became a cheap per-step QP, the template for modern safety filters around learned or legacy controllers. The 2019 tutorial collects uses in walking on stepping stones, ACC and lane keeping, Segway balancing, and multi-robot autonomy. Ames 2019
Limitations
You need a valid barrier, which is hard to build under input limits or for high relative degree. Ames 2019, Sects. III–IV
The QP can become infeasible with input bounds or several active constraints.
The filter looks one step ahead. It slows motion toward an obstacle but never plans a detour, so a head-on approach can deadlock (Day 20).
The guarantee is h ≥ 0, not a margin; put the margin inside h. The proofs assume continuous time and an exact model.
How to read the paper
Start with the 2019 ECC tutorial, Sect. II: definitions, Theorem 2 and the CBF-QP fit in a few pages. Then read the TAC paper's Sect. IV (QPs mediating safety and performance), Sect. V-A (ACC setup) and Sect. VI (Figs. 2, 4, 5). Leave the proofs in Sect. II for later.
Where it appears in the course
Day 20 builds the CBF-QP, its closed form and the widget around it. Day 10 supplies the KKT step behind the closed form, and Day 17 covers MPC, which plans a whole horizon where the filter looks one step ahead.
Check yourself
Q1. In the CLF-CBF QP, why does the slack δ go on the goal (CLF) row and not on the safety (CBF) row?
The slack lets the solver miss the goal rate when it must, and it pays for that in the cost. Safety has no slack, so it is never traded away. Both rows are already linear in u, so convexity does not depend on δ.
Q2. ẋ = u, a wall at x = 5, h = 5 − x and γ = 1. At x = 4 the nominal command is u = 2. What does the filter output?
The rule −u ≥ −γh means u ≤ γh = 1. The nominal 2 breaks it, so the filter clips to the nearest allowed value, 1. It does not stop the robot or reverse it.
Q3. In the ACC simulation without force limits, what went wrong?
Safety held: h stayed non-negative. The problem was the size of the commanded force. Simply bounding it can make the QP infeasible, so the paper designs barriers that respect braking limits.
ECC 2019 tutorial (DOI), Crossref: ECC 2019, pp. 3420–3431, DOI 10.23919/ECC.2019.8796030 (accessed 2026-10-26).
2017 · Amos, Kolter · ICML
OptNet: Differentiable Optimization as a Layer in Neural Networks
Made a quadratic program a layer of a neural network: the forward pass solves the QP, and the backward pass differentiates its KKT conditions.
In one sentence
Let a layer output z*, the solution of a QP whose data can come from earlier layers or be learned. Gradients come from differentiating the KKT conditions at z*, one extra linear solve with a factorization the solver already built.
Explain it to a 10-year-old
A marble rolls to the lowest spot of a bowl that has a little fence inside. Where it stops depends on the bowl's shape and where the fence stands. OptNet lets a computer ask: if I tilt the bowl a bit, or move the fence a bit, how far does the resting spot move? It does not replay the whole roll. It looks only at the resting spot, where everything balances, and works out how the balance shifts. A learning program can then keep reshaping the bowl and the fence until the marble stops where it should.
The problem
Standard layers (linear, convolution, ReLU) are good at smooth patterns. They are bad at hard rules, like "each row of a Sudoku holds each number once". An optimization problem captures such rules naturally, but it was not a building block you could train. Amos 2017
Off-the-shelf QP solvers did not help. Gurobi or CPLEX solve one problem at a time on a CPU and return no gradients. Training needs a whole mini-batch of QPs per step, plus derivatives.
The key idea
Define the layer's output as the solution of a QP:
z* = argminz ½zTQz + qTz
s.t. Az = b, Gz ≤ h
At the solution, the KKT conditions hold (Day 10). The multipliers are ν for the equalities and λ ≥ 0 for the inequalities:
Qz* + q + ATν + GTλ = 0
Az* = b, λi(Gz* − h)i = 0
These equations pin down z*. Nudge the data, differentiate the equations, and you get a linear system for how z* moves. This is implicit differentiation: you never differentiate the solver's steps, only the conditions its answer satisfies. Amos 2017, Sect. 3
A tiny worked example: z*(q) = argmin ½z2 − qz subject to z ≤ 1, so z* = min(q, 1). The KKT conditions are z − q + λ = 0 and λ(z − 1) = 0. At q = 0.5 the constraint is slack, λ = 0, and dz*/dq = 1. At q = 2, z* = 1 and λ = 1. Differentiating gives dz = 0: the active constraint holds z fixed, so no gradient flows.
Where OptNet sits, own drawing. The QP layer behaves like any other layer: it takes inputs, returns z*, and passes gradients back. The backward pass reuses the matrix factorization from the forward solve.
How it works
Forward. A primal-dual interior-point method (Day 12) solves all QPs in the mini-batch at once on the GPU. The authors released it as the PyTorch library qpth. qpth
Backward. Given the loss gradient with respect to z*, solve one linear system with the KKT matrix. The paper writes closed-form gradients for all of Q, q, A, b, G and h from that one solve.
Reuse. The interior-point method already factored that matrix at its last iteration, so the backward pass is almost free. Amos 2017, Sect. 3.1
Train with Adam like any other layer. The QP data can be fixed, learned directly, or produced by earlier layers.
Results
Speed first. For a batch of 128 random QPs with 100 variables and 100 inequality constraints, qpth on a Titan X GPU took 0.18 s on average. Gurobi on a quad-core i7 took 4.7 s. Amos 2017, Fig. 2
The showcase was 4×4 mini-Sudoku. The model was told nothing about the rules. It saw 9,000 puzzles with solutions and was tested on 1,000 new ones. A 10-layer convolutional network learned the training set and overfit. The OptNet model learned most of the hard constraints and generalized much better. Amos 2017, Fig. 5
OptNet also improved total-variation denoising by learning the difference operator instead of fixing it by hand, and worked as a generic layer on MNIST. Amos 2017, Sect. 4
Why it mattered
It started the field of differentiable optimization layers. The cvxpylayers paper generalized it to any disciplined convex problem. Differentiable MPC used the same fixed-point trick to learn controller costs and dynamics end to end. Amos 2018 For robotics, it means a constraint or a cost inside a controller can be learned from data.
Limitations
Cost grows with the cube of the number of variables or constraints, against the square for a linear layer. The authors put the practical limit below 1,000 dimensions, and "substantially less" for real time. Amos 2017, Sect. 3.3
QPs only, and the solver uses dense matrices, so sparsity is not exploited.
Gradients are zero across active constraints (the toy example) and undefined at degenerate points.
Training needs more tuning than usual: rescaling a constraint row and its right side changes the parameters but not the problem.
How to read the paper
Read Sect. 1, then Sect. 3 up to the gradient formulas: that is the whole method. Sect. 3.1 explains the batched solver if you care about implementation. Sect. 3.3 is a short, honest list of limits. In the experiments, read Sect. 4.1 (Fig. 2) and Sect. 4.4 (Sudoku, Fig. 5). Skip the representational-power results in Sect. 3.2 on a first pass.
Where it appears in the course
Day 20 covers optimization layers and differentiable MPC. Day 10 gives the KKT conditions being differentiated, Day 12 the interior-point solver inside, and Day 21 places learning-to-optimize on the frontier.
Check yourself
Q1. How does OptNet compute gradients through a QP layer?
Implicit differentiation needs only the conditions the answer satisfies. Unrolling would also work but costs memory and time for every iteration; OptNet avoids it.
Q2. For z* = min(q, 1), what is dz*/dq at q = 2?
At q = 2 the constraint is active, so small changes in q do not move z*. The derivative is 1 only while the constraint is slack, for q < 1.
Q3. Why not simply call Gurobi inside the layer?
Gurobi solves QPs accurately. The obstacles were batching on a GPU and the missing backward pass, both of which qpth provides.
Lets you write a convex problem in CVXPY, with Parameters, and use it as a PyTorch or TensorFlow layer that returns gradients of the solution.
In one sentence
A rule set called DPP makes the map from parameters to solver data affine, so every DPP problem runs as canonicalize (affine) → cone solver → retrieve (affine). The derivative is then the chain rule through those three pieces: you write natural math, and the library builds the layer.
Explain it to a 10-year-old
Imagine a super calculator that only understands one strict format. Before, you had to rewrite every question into that format by hand, and one slip gave a wrong answer. cvxpylayers is a translator. You say the question in normal words, it rewrites it for the calculator, gets the answer and translates it back. Because each translation step is simple, it can also tell you how the answer changes if you nudge a number in your question. That second trick is what learning programs need.
The problem
Optimization layers such as OptNet worked, but only for problems written in a rigid canonical form. Users had to transform each problem by hand, which the authors call tedious, error-prone and expert-only. Agrawal 2019
Modelling languages like CVXPY already do that transformation, called canonicalization, for solving (Day 21). But it was not differentiable, and it was redone from scratch for every new parameter value.
The key idea
View a parametrized problem as a function S that maps parameters θ to a solution x*. The paper writes S as a chain of three maps:
x* = S(θ) = R(s(C(θ)))
The canonicalizer C turns θ into cone-program data (A, b, c). The cone solver s returns a solution x̃. The retriever R maps x̃ back to the variables you wrote. If C and R are affine, the problem is in ASA form (affine–solver–affine). Then the chain rule gives the backward pass: Agrawal 2019, Sect. 4
DTS(θ) = DTC(θ) · DTs(A, b, c) · DTR(x̃)
The two affine pieces are just sparse matrices. The hard middle piece, differentiating a cone program, comes from the diffcp package.
DPP (disciplined parametrized programming) is the rule set that guarantees ASA form. It is DCP (Day 3) with two changes. Parameters count as affine, like variables. And a product is allowed only when one side is a constant, or one side is parameter-affine and the other parameter-free. So F x with parameter F and variable x is fine. A product of two parameters times x is not, unless you rewrite it with a new parameter. Agrawal 2019, Sect. 4.1
ASA form, own drawing. Only the middle box is nonlinear. DPP guarantees that the two outer boxes are affine, so their derivatives are fixed sparse matrices computed once.
How it works
Write the problem in CVXPY with cp.Parameter objects and check problem.is_dpp().
Build a CvxpyLayer once. This canonicalizes the problem a single time and stores C and R as sparse matrices.
Call the layer with tensors. New parameter values become (A, b, c) by one sparse multiply, the cone solver runs, and R maps the answer back.
Call backward. diffcp differentiates the cone program, and the transposed sparse maps finish the chain.
Adapted from the paper's Sect. 5 example, which still matches the README's usage pattern as of Oct 2026: cvxpylayers README
import cvxpy as cp, torch
from cvxpylayers.torch import CvxpyLayer
m, n = 20, 10
x = cp.Variable((n, 1))
F = cp.Parameter((m, n)); g = cp.Parameter((m, 1))
lambd = cp.Parameter((1, 1), nonneg=True)
obj = cp.norm(F @ x - g) + lambd * cp.norm(x)
problem = cp.Problem(cp.Minimize(obj), [x >= 0])
assert problem.is_dpp()
layer = CvxpyLayer(problem, parameters=[F, g, lambd], variables=[x])
F_t = torch.randn(m, n, requires_grad=True)
g_t = torch.randn(m, 1, requires_grad=True)
lambd_t = torch.rand(1, 1, requires_grad=True)
x_star, = layer(F_t, g_t, lambd_t)
x_star.sum().backward() # gradients land in F_t.grad, g_t.grad, lambd_t.grad
Results
Caching the canonicalization paid off at once. Going from CVXPY 1.0.23 to 1.1, canonicalizing the paper's logistic-regression example fell from 18.9 ms to 1.49 ms, and the stochastic-control example from 12.5 ms to 1.39 ms. Agrawal 2019, Table 1
Against OptNet's specialized qpth: on a dense QP (n = 128, batch 128) cvxpylayers was competitive, even with qpth on a GPU. On a sparse QP with n = m = p = 1024 and 1% nonzeros (batch 32), it was about 5 times faster. That QP was too large for qpth's GPU mode. cvxpylayers ran on the CPU, batching with 12 threads. Agrawal 2019, Fig. 3
Two applications show the range: gradients of a classifier's test loss with respect to its training data (data poisoning), and learning a control-Lyapunov policy for stochastic control. Agrawal 2019, Sect. 6
Why it mattered
"Put a convex problem inside a network" became a few lines of code. That opened the door for decision-focused learning, learned MPC costs and quick prototypes of safety layers. The package lives on: cvxpylayers 1.2.0 was released on 2026-05-19, as of Oct 2026, and version 1.0 added GPU back ends. PyPIREADME
Limitations
A general cone solver is slower and less accurate than a specialized one. The authors planned QP solver back ends as future work.
The problem must be DPP. Products of parameters must be rewritten, for example xTPx with P a parameter becomes ‖P½x‖2 with P½ as the parameter.
The method assumes a unique solution and a differentiable solution map. At kinks, as in OptNet, the gradient may not exist.
How to read the paper
Read Sect. 1 for the motivation, then the start of Sect. 4 for the ASA chain rule. Sect. 4.1 on DPP is the most useful part in practice; its list of non-DPP expressions and their rewrites is worth bookmarking. Then read the code in Sect. 5 and the evaluation in Sect. 7. Skip Sects. 4.2–4.4 unless you are implementing something similar.
Where it appears in the course
Day 20 uses it for optimization layers. Day 21 covers CVXPY, DPP and Parameters as the modelling layer, and Day 3 introduces the DCP rules that DPP extends.
Check yourself
Q1. What does DPP guarantee?
DPP is about how parameters enter the problem. Uniqueness is a separate assumption, and the problem must still be convex.
Q2. Which expression breaks the DPP rules? (p1, p2, F, g and λ ≥ 0 are parameters; x is a variable.)
A product of two parameters is not parameter-affine. Rewrite it with a new parameter p3 = p1p2. The other three are DPP, as the paper's own example shows.
Q3. In ASA form, which piece is not affine?
Solving a cone program is a nonlinear map, and diffcp supplies its derivative. The outer two pieces are affine by design.
2021 · Zhang, Liniger, Borrelli · IEEE Trans. Control Systems Technology
Optimization-Based Collision Avoidance
Used duality to turn "keep this car-shaped box away from that obstacle" into smooth, exact constraints for a standard NLP solver, and showed tight autonomous parking.
In one sentence
Distance between two convex shapes is itself a small convex problem, so by strong duality "distance > dmin" means "some dual multipliers prove it". Add those multipliers as variables, and the non-smooth collision rule becomes a few smooth, exact constraints.
Explain it to a 10-year-old
You want to prove two toys are not touching, without measuring every point. Here is a trick: slide a sheet of paper between them. If it fits with room to spare on both sides, they are not touching. OBCA asks the computer to plan the car's motion and, at the same time, keep carrying such a sheet between the car and every obstacle. If a sheet always fits, the car never crashes.
The problem
Staying outside a polytope is a non-convex, non-smooth constraint. You must be beyond face 1 or face 2 or face 3, which is an OR (Day 19). Distance and signed distance have no closed form, and their gradients jump at corners.
The usual exact fix uses integer variables, which the authors say should generally be avoided for real-time nonlinear control. Shrinking the car to a point inside a ball is simpler, but too conservative for tight parking spots. Zhang 2021
The key idea
Take an obstacle O = {y : Ay ≤ b}. The distance from a point p to O is a convex problem: minimize ‖p − y‖2 over y in O. Its dual problem (Day 9) is Zhang 2021, Prop. 1
dist(p, O) = maxλ (Ap − b)Tλ
s.t. ‖ATλ‖2 ≤ 1, λ ⪰ 0
Weak duality says every feasible λ gives a lower bound on the distance. Strong duality says the best λ gives the distance exactly. So:
dist(p, O) > dmin ⇔
(Ap − b)Tλ > dmin for some feasible λ
That λ is a dual certificate. Geometrically, ATλ is the direction of a separating plane, the sheet of paper. The optimizer moves the robot and the certificate together, and every constraint involved is smooth.
A worked example with the square [−1, 1]2: its rows are x ≤ 1, y ≤ 1, −x ≤ 1, −y ≤ 1. For p = (3, 0.5), Ap − b = (2, −0.5, −4, −1.5). λ = (1, 0, 0, 0) is feasible and gives 2, the true distance. For p = (3, 3), λ = (1/√2, 1/√2, 0, 0) gives 2√2 ≈ 2.83, the distance to the corner (1, 1).
The dual vector picks a separating plane, own drawing. Facing a face, λ uses one row of A. Facing a corner, it mixes two rows, and the plane tilts. In both cases (Ap − b)Tλ equals the true distance.
How it works
A car is not a point. Its footprint is a rotated, shifted rectangle E(x) = R(x)𝔹 + t(x). Here 𝔹 = {y : Gy ≤ g} is the rectangle in the car's own frame, R(x) is the rotation and t(x) the position. A second multiplier μ handles the car's own faces: Zhang 2021, Prop. 3
−gTμ + (At(x) − b)Tλ > dmin
GTμ + R(x)TATλ = 0
‖ATλ‖2 ≤ 1, λ ⪰ 0, μ ⪰ 0
Model each obstacle as a union of convex polytopes and the car as a 4.7 × 2 m rectangle.
For every time step and every obstacle, add one (λ, μ) pair and the three constraints above.
Add the dynamics: a kinematic bicycle with wheelbase 2.7 m, steering within ±0.6 rad, acceleration within ±1 m/s2. The cost trades time against control effort.
Warm-start with Hybrid A*, a grid search with car-like motions, and solve the smooth NLP with IPOPT (Day 16).
If a collision cannot be avoided, use the signed-distance form, ‖ATλ‖ = 1, with slack variables. It finds the least-penetrating trajectory.
Results
The parking tests used 84 start poses on a 21 × 4 grid. The reverse spot was 2.6 × 5.2 m and the parallel spot 2.5 × 6 m, both off a 6 m road. Both formulations parked from all 84 starts. Times are on a 2013 MacBook Pro with JuMP and IPOPT. Zhang 2021, Table 2
Mean time
Hybrid A* warm start
Distance form
Signed distance
Reverse parking
0.55 s
0.60 s
1.03 s
Parallel parking
0.30 s
0.87 s
1.67 s
The worst case, Hybrid A* plus the signed-distance form, took 7.7 s for reverse and 9.2 s for parallel parking. The authors still call this real-time parking in tight spaces. A quadcopter crossing a room through a window took about 15 s on average. Zhang 2021, Sects. 5–6
Why it mattered
It gave autonomous-driving and robotics engineers an exact, smooth way to write rectangle-against-polytope collision rules inside standard NLP solvers. The paper's pipeline, a coarse Hybrid A* search followed by OBCA smoothing, fits tight parking well, and the authors' Julia code is public. OBCA code
Limitations
The problem is smooth but still non-convex: dynamics, rotations and the λ·R(x) products remain. Solutions are local and need a good warm start. Plain A* paths, which ask the car to slide sideways, typically could not be repaired. Zhang 2021, footnote 4
Each obstacle adds multipliers at every time step, so problem size grows with obstacles × horizon.
The signed-distance form is slower, roughly twice as slow in the parking tests.
Times are seconds, not milliseconds, on 2013 hardware.
How to read the paper
Read Sect. 1, then Sect. 2.4 on why collision constraints are hard. Sect. 3.1 holds the core trick for a point (Prop. 1), about one page. Sect. 4.1 extends it to full shapes (Prop. 3). Then read Sect. 6 on parking with Table 2 and Figs. 4–9. Leave the signed-distance parts (3.2, 4.2) and the quadcopter in Sect. 5 for a second pass.
Where it appears in the course
Day 19 presents OBCA as the first of three escape routes. Day 9 supplies the duality behind the certificate, Day 2 the polytopes and separating planes, and Day 16 the NLP solvers.
Check yourself
Q1. In OBCA, what does the dual vector λ represent?
Any feasible λ gives a lower bound on the distance, and ATλ points along a separating plane. It is a decision variable, not a tuning knob.
Q2. For p = (3, 0.5) and the square [−1, 1]2 with rows x ≤ 1, y ≤ 1, −x ≤ 1, −y ≤ 1, which λ certifies distance 2?
With Ap − b = (2, −0.5, −4, −1.5), λ = (1, 0, 0, 0) gives 2. The choice (½, ½, 0, 0) is feasible but only proves 0.75, and (1, 1, 1, 1) gives a useless negative bound.
Q3. Does OBCA make the parking problem convex?
OBCA trades a non-smooth constraint for smooth ones. The problem as a whole stays non-convex, which is why Hybrid A* warm starts mattered so much.
Journal version (DOI), Crossref: IEEE TCST 29(3):972–983, 2021 (accessed 2026-10-26).
OBCA code, Zhang, GitHub: the Julia implementation linked from the paper (accessed 2026-10-26).
2023 · Marcucci, Petersen, von Wrangel, Tedrake · Science Robotics
Motion Planning around Obstacles with Convex Optimization
Covers free space with convex regions, links the overlapping ones in a graph, and plans with one convex program whose answer is usually the global optimum, with a certificate.
In one sentence
Write "which regions" and "which exact curve" as one shortest-path problem in a graph of convex sets. Its convex relaxation is so tight that one solve plus cheap rounding usually gives the globally optimal path, with a bound on the gap.
Explain it to a 10-year-old
You walk across a city of parks joined by gates. You must choose which parks to cross and exactly where to pass each gate. GCS chooses both at once. Its trick is to first solve an easy, blurry version that may send 30% of you through one park and 70% through another. Usually the blurry answer already says 100% for one route, and then the computer knows it has the best walk.
The problem
Each planner family has a weak spot. Trajectory optimization gets stuck in local minima in clutter (TrajOpt). Sampling planners struggle in high dimensions and with smoothness, so their paths need post-processing. Mixed-integer planners are exact but slow. Marcucci 2022, arXiv v1
The classic mixed-integer setup gives each trajectory segment a binary for each safe region. If the path might visit every region, that is |I|2 binaries for |I| regions, far too many for big maps.
The key idea
A graph of convex sets has a convex set Xv at each vertex v and a point xv that must lie inside it. An edge e = (u, v) has a convex length ℓe(xu, xv), for example ‖xv − xu‖2. The shortest-path problem chooses the path and the points together:
min Σe ∈ path ℓe(xu, xv), xv ∈ Xv
Plain Dijkstra cannot do this, because edge lengths depend on where you cross. The problem is NP-hard in general. Marcucci 2024, SIAM J. Optim.
The companion SIAM paper writes it as a mixed-integer convex program with a binary φe per edge. Perspective functions (Day 3) let an unused edge drop out cleanly. Relaxing φe ∈ {0, 1} to [0, 1] gives a convex program (an SOCP for Euclidean lengths), and that relaxation is very tight.
It also gives a free bound. The relaxed cost Crelax is a lower bound, and any rounded path's cost Cround is an upper bound: Marcucci 2022, Sect. 4.2
Crelax ≤ Copt ≤ Cround
δrelax = (Cround − Crelax) / Crelax
In the paper's 2-D example, Crelax = 27.29 and Cround = 28.10, so δrelax = 0.81 / 27.29 ≈ 3.0%. The rounded path is certified within 3% of optimal. A mixed-integer solver later confirmed it was exactly optimal.
A toy graph of convex sets, own drawing. Each region is a vertex and each overlap an edge. Top or bottom route is a discrete choice; where to cross each overlap is continuous. GCS decides both at once and picks the shorter top route.
How it works
Regions. Build convex safe regions, for example with the IRIS paper's method. Every pair of overlapping regions gets edges.
A curve per region. Each region holds a Bézier curve, which stays inside the convex hull of its control points. So control points inside the region keep the whole curve safe, not just samples of it.
Time. A second Bézier curve maps path position to time. Costs on duration, length and energy, and limits on derivatives, are all convex in the control points.
Edges. Continuity of position and derivatives between neighbouring curves is a set of linear equalities.
Solve, round, polish. Solve the convex relaxation (MOSEK), round the fractional edges into one path, re-solve the convex problem for that fixed path, and report δrelax.
Results
All numbers below come from the arXiv v1 preprint of May 2022. The published Science Robotics version may differ slightly. Marcucci 2022, Sect. 7
Test
Headline result
Maze, 50 × 50 = 2,500 cells
5,198 binaries instead of 6.25 × 106; a single SOCP returned the globally optimal path
Quadrotor, 100 random building maps
95% of plans within 1% of the global optimum, worst 2.9%; relaxation time median 3.7 s, mean 6.4 s, max 31.2 s
KUKA iiwa arm, 7 joints, 5 tasks
8 IRIS regions built in 53 s; shorter paths than PRM and shortcut PRM, faster than plain PRM; global optimum on all 5 tasks
Two arms, 14 joints, 3 tasks
4.0 s, 8.4 s and 12.9 s
The certificates were often conservative. The largest certified gap on the quadrotor maps was 27.1%, yet that path was only 2.3% from optimal. On the arm, the certified gap averaged 4.1% while the true gap was 0. Marcucci 2022, Sects. 7.3–7.4
Why it mattered
It showed that convex optimization can reliably plan around obstacles with global-optimality certificates, uniting route choice and smoothing in one solve. It started a research line: GCS* for planar pushing (2024), shortest walks in GCS (2025), and the faster safe-boxes planner. GCS* 2024Shortest walks 2025 Drake ships it as GcsTrajectoryOptimization, as of Oct 2026. Drake docs
Limitations
The regions must be built first. For the arm this took 53 s for 8 regions. They came from a fast non-convex method that is reliable in practice but gives no rigorous collision-free certificate. Marcucci 2022, Sect. 7.4
Only kinematic limits and derivative bounds stay convex. Full dynamics constraints break convexity.
Rounding is not guaranteed to find the optimum; the problem is NP-hard in general. The certificate is an upper bound and can be loose.
Solve times are seconds, not milliseconds. MOSEK numerical issues forced a slower, stabler mode. Marcucci 2022, Sect. 7.3
How to read the paper
Section numbers follow arXiv v1; the published article regroups them into Results, Discussion and Methods. Start with Sect. 1 and Fig. 1, the whole method in one picture. Then read Sects. 4.1 (shortest paths in GCS) and 4.2 (rounding and the gap). Sect. 3 on Bézier curves is short, and Sect. 5 builds the graph. For results, read Sects. 7.2 (maze) and 7.4 (arm versus PRM), then Sect. 8 for comparisons with other planners. For theory, read the SIAM paper by Marcucci, Umenberger, Parrilo and Tedrake.
Where it appears in the course
Day 19 builds GCS and its widget, which solves the convex restriction for a fixed chain of boxes. Day 15 explains relaxation, rounding and bounds, Day 5 the SOCP class, and Day 3 the perspective function.
Check yourself
Q1. The relaxation costs 27.29 and the rounded path costs 28.10. What can you guarantee?
The relaxation is a lower bound, so the optimum lies between 27.29 and 28.10. The true gap could be anything from 0 to 3.0%; here it was 0.
Q2. Why do Bézier curves suit GCS?
The convex-hull property turns "the whole curve is safe" into a few linear constraints on control points. Overlaps are still needed to pass from one region to the next.
Q3. In the 2,500-cell maze, how many binary variables did GCS need, against the classic mixed-integer setup?
GCS uses about two binaries per pair of overlapping cells, roughly 2|I|. The classic setup needs |I|2 = 2,5002. That gap is a factor of about 1,200.
Fast Path Planning Through Large Collections of Safe Boxes
Trades GCS's optimality bound for speed: with axis-aligned boxes, a graph search plus a few convex smoothing steps plans through 10,000+ boxes in seconds, and always finds a path if one exists.
In one sentence
With axis-aligned boxes, find the overlaps and build a graph once, offline. Online, a graph search gives a safe polygonal path, and a few small convex problems pull it tight and smooth it into Bézier curves: no optimality bound, but complete and fast.
Explain it to a 10-year-old
Picture a giant playground made of overlapping cardboard boxes you can crawl through. Before anyone plays, a helper marks every spot where two boxes overlap and draws a map of which spots connect. When you want to cross, you first find the shortest chain of spots on the map, like a dot-to-dot. Then you pull the dotted line tight like a string. Finally you round off its corners so you can crawl smoothly without stopping.
The problem
Think of a drone inspecting an industrial plant, or a robot carrying packages through a large warehouse. The map is static but huge. The authors note that, for a flight like theirs, existing methods took a few seconds to plan through fewer than 100 safe boxes. Marcucci 2024 The GCS paper gives tight bounds, but it was not built for maps of thousands of regions.
Exact mixed-integer planning is hopeless at that scale. Its worst-case cost is super-exponential in the number of boxes, and the paper shows CPLEX needing 584 s on even the smallest instance of its scaling study. Marcucci 2024, Sect. VII-D
The key idea
Give up the optimality bound and use the structure of boxes everywhere. Box overlaps are cheap to find, and "stay in a box" is just lower and upper bounds on each coordinate. The planner splits the problem into a discrete part, a graph search, and a continuous part, a few convex optimal-control problems (Day 17).
Safety is exact. The path is a chain of Bézier curves, one per box, with control points inside that box, so the whole path is safe at all times. It is also complete: if a safe path exists it finds one, and otherwise it reports infeasibility. Marcucci 2024, Sect. II
The three phases on a toy map of four boxes, own drawing. Everything outside the boxes is obstacle. The times are the paper's village quadrotor example with 10,150 boxes. The lower-right box is a dead end, so the search never uses it.
How it works
Offline: the line graph. Find every pair of overlapping boxes. Each overlap becomes a vertex, and two vertices are joined if their overlaps share a box. Each vertex gets a representative point inside its overlap, chosen by one convex program that minimizes the total edge length. Marcucci 2024, Sect. III
Online, polygonal phase. Connect start and goal to the graph and run a shortest-path search. That gives a safe polygonal curve. Then alternate: fix the box sequence and shorten the curve, which is convex; then fix the curve and improve the box sequence. This took 1 to 4 iterations in the scaling study.
Online, smooth phase. Freeze the box sequence. Put one Bézier curve in each box, with derivative continuity at the joins. Shape and traversal times together make a non-convex problem. So alternate two convex ones: fix the times and optimize the shape, then improve the times with a local convex approximation. This took 5 to 6 iterations in the scaling study.
The cost penalizes squared derivatives of the path. For a quadrotor the paper penalizes snap, the fourth derivative, because a smooth flat-output path then gives feasible thrusts and orientations.
Results
Runs used an 8-core 2.4 GHz Intel i9, with CVXPY 1.4.1 and Clarabel 0.6.0. CVXPY's own overhead was removed from the reported times. Marcucci 2024, Sect. VII
Example
Boxes
Offline
Polygonal
Smooth
2-D scaling study, largest
25,600
25 s
0.12 s
3.4 s
3-D village, quadrotor
10,150
101 s
0.22 s
7.5 s
The village has buildings, trees and bushes. Its line graph has 70,907 vertices and 1,022,782 edges, and the final path crosses 135 boxes. The first smooth iteration cut the cost by 84.3%, and the final path cost 99.3% less than the initial guess. Marcucci 2024, Sect. VII-C
On a 9-box toy problem the planner took 17.2 ms with cost 1.0001, essentially the global minimum of 1. The best mixed-integer formulation reached 1.01 and took 439 ms with CPLEX, the fastest of three commercial solvers. Marcucci 2024, Fig. 9
Why it mattered
It shows the convex-pieces idea scaling to city- or warehouse-sized maps, with online times of seconds. It is a practical bridge from GCS theory to deployment, and the code is open source as fastpathplanning. fastpathplanning
Limitations
No optimality bound. On the smallest scaling-study map, the mixed-integer path was about three times cheaper, though it took 584 s instead of 43 ms.
Boxes only. Axis-aligned boxes describe free space conservatively, and general convex sets would slow the offline steps.
The map must be static and known. A changed map means redoing the offline step, 101 s for the village.
Online times are still seconds for the largest maps.
Adding derivative limits with a fixed final time breaks completeness, unless the final time is also optimized. Marcucci 2024, Sect. VIII
How to read the paper
Look at Fig. 1 and read Sect. I. Sect. II-D outlines all three phases on one page. Sects. III, IV and V each end with the same small example (III-C, IV-C, V-D), so read those examples first and the details second. Then read Sect. VII-B and VII-C for scale, and VII-D for the mixed-integer comparison. Skip the derivations in Sect. V-C on a first pass.
Where it appears in the course
Day 19 ends with this planner as the scaled-up version of GCS. Day 21 lists it on the frontier, Day 14 covers alternating between blocks of variables, and Day 18 covers trajectory optimization more generally.
Check yourself
Q1. What does this planner give up compared with GCS?
The path is still safe at all times and smooth, and the method is complete. What is lost is the certified gap that GCS's relaxation provides.
Q2. In the village example, what must be recomputed when a new start and goal arrive?
The line graph depends only on the boxes, so it is built once. Each new query runs the two online phases.
Q3. Why is the smooth phase solved by alternating two problems?
Times multiply the shape variables, which breaks convexity. Fixing one part makes the other a convex problem. The box sequence is frozen during this phase.
cuPDLP.jl: A GPU Implementation of Restarted Primal-Dual Hybrid Gradient for Linear Programming in Julia
Showed that a first-order LP method running entirely on one GPU can match Gurobi on standard benchmarks, answering "are GPUs useful for LP?" with yes.
In one sentence
PDHG needs only products with the constraint matrix and its transpose, which GPUs do very fast, instead of the factorizations simplex and interior point need. Run every iteration of restarted PDHG on the GPU, and a Julia prototype keeps up with a commercial solver at moderate accuracy.
Explain it to a 10-year-old
Two players play a game. One decides how much of each thing to make. The other sets prices that punish breaking the rules. They take turns making small changes, and when neither wants to change anything, the game's answer is the best plan. Each turn needs only simple multiplications. A GPU is like a classroom of thousands of kids who can each do one multiplication at the same moment, so every turn goes very fast.
The problem
Classic LP solvers, simplex and interior point (Day 12), must solve linear systems by LU or Cholesky factorization. A sparse matrix can have a much denser factorization, which eats memory. Factorizations are also hard to spread over thousands of parallel cores. Lu 2025
So "are GPUs useful for solving linear programming?" was a long-standing open question. GPUs had transformed deep learning, but not LP.
The key idea
Use a method whose main cost is a matrix–vector product. Write the LP as
min cTx s.t. Gx ≥ h, Ax = b, l ≤ x ≤ u
Stack K = [G; A] and q = [h; b]. Dualizing the constraints (Day 9) gives a saddle-point problem. Here x stays in the box X = [l, u], and the multipliers y lie in Y, where the part for G is non-negative:
minx ∈ X maxy ∈ Y cTx − yTKx + qTy
PDHG (primal-dual hybrid gradient) takes a step in x, then a step in y, with step sizes τ and σ: Lu 2025, Sect. 2.1
x+ = projX(x − τ(c − KTy))
y+ = projY(y + σ(q − K(2x+ − x)))
Each step needs one product with K, one with KT, and a clip. No linear system is solved. That is exactly the kind of work a GPU is built for.
A worked example: minimize x subject to x ≥ 1, so c = K = q = 1. The answer is x = 1 with multiplier y = 1. Start at (0, 0) with τ = σ = 0.5:
Step
x
y
1
−0.5
1.0
3
−0.125
2.125
5
1.0
1.844
40
0.997
1.006
The pair circles in toward (1, 1) slowly. Plain PDHG is not strong enough on real LPs, so PDLP adds five upgrades: diagonal preconditioning, adaptive restarts, adaptive step sizes, primal-weight updates and infeasibility detection. Lu 2025, Sect. 2.2
Where the work happens, own drawing. Moving data between CPU and GPU is slow, so the scaled LP goes in once and the solution comes out once. Restart checks and the stopping test also run on the GPU.
How it works
CPU. Read the LP and precondition it, rescaling rows and columns (Day 21).
Copy in. Move the scaled LP to GPU memory, once.
GPU loop. Run restarted PDHG with adaptive steps. The one algorithmic change from CPU PDLP: restarts are triggered by the KKT error, because the old restart test needs a sequential computation. The same order of linear convergence is proved. Lu 2025, Sect. 3
Stop when the relative KKT error, checked on the original LP, falls below 10−4 (moderate) or 10−8 (high accuracy).
Copy out the solution, once.
Results
The tests used an NVIDIA H100 GPU for cuPDLP.jl and a 16-thread Xeon for the CPU solvers, including Gurobi 11.0 with crossover off. The benchmarks were 383 LP relaxations from MIPLIB 2017 and 49 LPs from Mittelmann's set. Lu 2025, Sect. 4
Comparison
Result
Against Gurobi, 10−4, no presolve
3× faster on medium instances (4 more solved), 3.7× faster on large ones
With Gurobi presolve
381 of 383 solved (99.5%) at 10−4; 97.4% at 10−8
Against Gurobi, 10−8
Comparable to primal and dual simplex, behind barrier
Against CPU PDLP in Julia
4×, 10× and 20× faster on small, medium and large; 30 more instances solved
The GPU has a cost. Kernel launches add about one second to every solve, while Gurobi finishes about 35% of the instances within one second. Lu 2025, Sect. 4.2
Why it mattered
It was the first evidence that a GPU first-order LP method can match commercial solvers on standard benchmarks. Adoption was fast, as of Oct 2026. HiGHS offers cuPDLP-C, the C rewrite, as its "pdlp" solver on NVIDIA GPUs. HiGHS docs Gurobi 13.0 added PDHG with an optional GPU mode. Gurobi 13.0 notes NVIDIA cuOpt runs GPU PDLP alongside barrier and dual simplex. cuOpt docs
For robotics and driving, this matters for huge planning or fleet LPs solved offline or at low rate. It does not help the small MPC QPs inside a controller.
Limitations
LP only. QPs and cone programs need other work, such as the GPU versions of OSQP and Clarabel.
Weaker at high accuracy: at 10−8 Gurobi's barrier still wins.
About one second of GPU overhead per solve, so small problems gain nothing. HiGHS itself warns that PDLP on a CPU is unlikely to be competitive. HiGHS docs
It needs a GPU. The Julia prototype was later rewritten in C as cuPDLP-C. cuPDLP-C 2023
How to read the paper
Read Sect. 1 with Table 1, which compares simplex, barrier and first-order methods. Then read Sect. 2.1 (the PDHG update) and Sect. 2.2 (the five PDLP upgrades, Algorithm 1). Sect. 3.2 shows the two-transfer design and Sect. 3.4 the KKT restarts. In Sect. 4.2, read Fig. 3 and the bulleted findings. Skip the appendix proof at first.
Where it appears in the course
Day 21 places it on the solver frontier. Day 9 gives the Lagrangian behind the saddle point, Day 5 the LP class, and Day 13 the splitting methods it is related to (see the ADMM card).
Check yourself
Q1. Why does PDHG suit a GPU better than simplex or interior point?
PDHG usually needs many more iterations, but each is cheap and parallel. It uses K constantly; it just never factors it.
Q2. Is cuPDLP.jl a good choice for a small MPC QP solved 100 times per second?
It is an LP solver built for very large instances. A small QP in a control loop wants something like OSQP or an active-set solver on the CPU.
Q3. At 10−8 tolerance on the MIPLIB relaxations, how did cuPDLP.jl compare with Gurobi?
High accuracy is where first-order methods struggle. The 20× figure was the speed-up over the CPU version of PDLP, not over Gurobi.
Tap a term for its meaning and the day that introduces it.
Sets & functions
Affine function
A linear part plus a constant, f(x) = aTx + b, so its graph is flat (a line or a plane). A convex problem allows only affine equality constraints.
Concave function
A function whose negative is convex, so it bends down like a cap. Maximizing a concave function is a convex problem.
Cone
A set that stays inside itself when you stretch any of its points by a factor θ ≥ 0. A convex cone also contains every nonnegative sum of its points.
Convex combination
A weighted average θ1x1 + … + θkxk in which every weight θi ≥ 0 and the weights add up to 1.
Convex function
A bowl-shaped function: the chord between any two points of its graph lies on or above the graph, f(θx + (1 − θ)y) ≤ θf(x) + (1 − θ)f(y) for θ ∈ [0, 1].
Convex hull
The smallest convex set that contains a given set, like a rubber band snapped around the points. It holds every convex combination of them. Written conv S.
Convex set
A set with no dents: the straight segment between any two of its points stays inside the set.
Disciplined convex programming (DCP)
A rule set for building functions from known convex pieces and convexity-preserving moves, so convexity is checked automatically. CVXPY uses it to accept or reject a model.
Ellipsoid
A stretched and rotated ball, {xc + Au : ‖u‖2 ≤ 1}. It is convex, and it is often used to describe uncertainty or a region of free space.
Epigraph
The region on or above a function's graph, epi f = {(x, t) : f(x) ≤ t}. A function is convex exactly when its epigraph is a convex set.
First-order condition
A differentiable f is convex exactly when every tangent plane lies below its graph: f(y) ≥ f(x) + ∇f(x)T(y − x) for all x and y.
Gradient
The vector of partial derivatives ∇f(x), one slope per variable. It points in the direction of fastest increase, so −∇f(x) points downhill.
Hessian
The matrix of second derivatives ∇2f(x), which describes curvature. A twice-differentiable f is convex exactly when ∇2f(x) ⪰ 0 everywhere (the second-order condition).
Hyperplane
A flat wall {x : aTx = b} with normal vector a. It splits space into two halfspaces, such as {x : aTx ≤ b}, and both are convex.
Indicator function
IC(x) is 0 inside the set C and +∞ outside. It turns the rule “x ∈ C” into a cost, and it is convex when C is convex.
Jensen's inequality
For a convex f, the value at an average is at most the average of the values: f(E[x]) ≤ E[f(x)]. It is the chord test applied to many points at once.
L-smooth
The gradient never changes faster than L: ‖∇f(x) − ∇f(y)‖2 ≤ L‖x − y‖2, or ∇2f ⪯ LI. It makes the step size t = 1/L safe for gradient descent.
Norm
A measure of a vector's length ‖x‖. Common ones are ‖x‖1 (sum of absolute entries), ‖x‖2 (straight-line length) and ‖x‖∞ (largest entry). Every norm is convex.
Norm ball
All points within distance r of a centre, {x : ‖x − xc‖ ≤ r}. The ℓ2 ball is round, the ℓ1 ball a diamond and the ℓ∞ ball a square. All are convex.
Perspective function
P(z, t) = z/t for t > 0, the pin-hole camera map, which keeps convex sets convex. The perspective of a function, t·f(x/t), keeps convexity too.
Polyhedron
The intersection of finitely many halfspaces and hyperplanes, {x : Ax ⪯ b, Cx = d}: a flat-sided convex region. A bounded polyhedron is a polytope.
Positive semidefinite (PSD)
A symmetric matrix X with all eigenvalues ≥ 0, written X ⪰ 0. Equivalently, vTXv ≥ 0 for every vector v. The PSD matrices form a convex cone, S+n.
Projection
PC(x), the point of the set C closest to x. For a closed convex C it exists and is unique. For a box it is simple clipping.
Second-order cone
The ice-cream cone {(x, t) : ‖x‖2 ≤ t}. It is a convex cone, and an SOCP keeps affine expressions inside it.
Strictly convex
The chord lies strictly above the graph between any two different points, so there are no flat stretches. A strictly convex function has at most one minimizer.
Strongly convex
At least as curved as a quadratic: f − (m/2)‖x‖22 is still convex for some m > 0, or ∇2f ⪰ mI. It gives a unique minimizer and linear convergence for gradient descent.
Subdifferential
∂f(x), the set of all subgradients at x. At a kink it is a whole fan of slopes, such as [−1, 1] for |x| at 0. Where f is smooth it is just {∇f(x)}.
Subgradient
A slope g whose line or plane through (x, f(x)) never rises above f: f(y) ≥ f(x) + gT(y − x). It replaces the gradient at kinks, where f has no derivative.
Sublevel set
All inputs that score at most α, {x : f(x) ≤ α}. Every sublevel set of a convex function is convex. Functions with only that property are called quasiconvex.
Supporting hyperplane
A flat wall that touches a set at a boundary point while the whole set stays on one side. Every boundary point of a convex set has one.
Problems
Active constraint
An inequality that holds with equality at x, gi(x) = 0: you are touching that fence. Constraints you are not touching push with zero force at the optimum.
Big-M constraint
A constraint loosened by M times a binary variable, so the binary can switch it on or off. M must be large enough to be safe but small enough to keep the relaxation tight.
Box constraint
Each variable has its own lower and upper bound, l ≤ x ≤ u, and nothing more. Projecting onto a box is clipping. An input sitting on its bound is in saturation.
Conic program
Minimize cTx subject to Fx + g ⪯K 0 and Ax = b, for a cone K. The nonnegative orthant gives an LP, the second-order cone an SOCP, and the PSD cone an SDP.
Constraint
A rule the variables must obey, written as an inequality gi(x) ≤ 0 or an equality hj(x) = 0.
Convex optimization problem
Minimize a convex objective subject to convex inequality constraints gi(x) ≤ 0 and affine equality constraints. Then every local minimum is a global minimum.
Cutting plane
A valid inequality, true for every integer-feasible point, that slices off the current fractional LP solution. Gomory and cover cuts are examples. Branch and cut adds cuts inside branch and bound.
Feasible set
The set of all points that satisfy every constraint. A point in it is a feasible point. If it is empty, the problem is infeasible.
Global minimum
A feasible point where no feasible point anywhere has a lower objective value. In a convex problem every local minimum is global.
Integrality gap
The difference between the optimum of the relaxed problem, where fractions are allowed, and the true integer optimum. A small gap means the relaxation's bound is informative.
Lasso
Least squares plus an ℓ1 penalty: minimize ½‖y − Xβ‖22 + λ‖β‖1. The kink at zero drives many coefficients exactly to zero, giving a sparse model.
Linear matrix inequality (LMI)
A constraint x1F1 + … + xnFn + G ⪯ 0: a symmetric matrix that depends affinely on x must stay negative semidefinite. Its feasible set is convex.
Linear program (LP)
Minimize a linear objective cTx subject to linear inequalities and equalities. The feasible set is a polyhedron, and if an optimum exists and the polyhedron has a corner, some vertex is optimal.
Local minimum
A feasible point that no nearby feasible point beats. It may not be the best overall, unless the problem is convex.
LP relaxation
The LP you get by dropping the “must be an integer” (for example 0/1) rule. When minimizing, its optimal value is a lower bound on the integer problem's optimum.
Mixed-integer program (MIP)
A problem in which some variables must be integers, often 0/1 binary switches, and the rest are continuous. MILP and MIQP have linear and quadratic objectives. Integrality makes it nonconvex.
Objective function
The score f(x) you want to make as small as possible, or as large for a maximization. Also called the cost or criterion.
Optimal solution
A feasible point x* that achieves the optimal value p*. Also called a minimizer. A problem may have none, one or many.
Optimal value
The best achievable objective value p* over the feasible set. It is +∞ if the problem is infeasible and −∞ if it is unbounded below.
Optimality gap
In a MIP solver, the distance between the incumbent (the best integer solution found so far) and the best proven bound. A gap of zero means the incumbent is proven optimal.
Optimization variable
The knobs x ∈ ℝn that you get to choose.
Quadratic program (QP)
Minimize a convex quadratic ½xTPx + qTx, with P ⪰ 0, subject to linear constraints. Linear MPC for cars and robots solves one QP per control step.
Relaxation
A problem solved over a bigger feasible set that contains the original one. With more choices, its optimal value is a lower bound on the original optimum.
Second-order cone program (SOCP)
A linear objective with constraints ‖Aix + bi‖2 ≤ ciTx + di, each keeping an affine expression inside the ice-cream cone. It includes LPs and convex QPs.
Semidefinite program (SDP)
A linear objective with a linear matrix inequality constraint, so a matrix built from the variables must stay PSD. LPs and SOCPs are special cases.
Slack variable
An extra variable s ≥ 0 that measures the room left in an inequality, turning Gx ⪯ h into Gx + s = h.
Standard form
The agreed way to write a problem: minimize f(x) subject to gi(x) ≤ 0 and hj(x) = 0. It is convex when f and every gi are convex and every hj is affine.
Methods
Active-set method
A solver family that guesses which inequality constraints are tight, solves the resulting equality-constrained problem, and corrects the guess. It suits small, warm-started MPC QPs.
Alternating direction method of multipliers (ADMM)
For min f(x) + g(z) s.t. Ax + Bz = c: minimize the augmented Lagrangian over x, then over z, then update the price. OSQP runs on it.
Start with a step t, then shrink it by a factor β until f drops enough: f(x − t∇f) ≤ f(x) − αt‖∇f‖2. That test is the Armijo, or sufficient-decrease, condition.
Barrier method
Solve a sequence of barrier problems, minimize t·f(x) + φ(x), each by Newton's method from the last answer, multiplying t by a factor μ each round. It follows the central path.
The standard quasi-Newton update: a rank-two correction of the curvature estimate that satisfies the secant equation and stays positive definite. L-BFGS keeps only the last m step pairs.
An exact method for integer problems: split on a fractional variable, bound each piece with a relaxation, and prune pieces that are infeasible or cannot beat the incumbent.
The curve of barrier minimizers x*(t) as t grows from 0 to ∞. On it the duality gap equals m/t, so it leads to the optimum through the inside of the feasible set.
Condition number
κ = L/m, the ratio of the largest to the smallest curvature: how stretched the bowl is. A large κ makes gradient descent zig-zag and slow, and amplifies numerical errors.
Coordinate descent
Minimize over one coordinate (or block) at a time, keeping the others fixed, and cycle through them. It is very fast for the lasso, where each coordinate step is a soft-threshold.
Solve a problem through its dual: minimize the Lagrangian over x at the current prices u, then move u along the constraint residual Ax − b. Also called dual (sub)gradient ascent.
A method that learns about f only through gradients or subgradients. Each new point lies in x0 plus the span of past gradients. Steps are cheap, but you need many.
FISTA
ISTA plus Nesterov momentum: each step starts from a point pushed a little further along the last move. It improves the rate from O(1/k) to O(1/k2) at almost no extra cost.
Also called conditional gradient. A linear minimization oracle returns the best point s of C for the cost ∇f(x)Ts, then x ← (1 − γ)x + γs. No projection is needed.
Repeat xk+1 = xk − t∇f(xk): step against the slope, scaled by a step size t (Day 1 writes η). The simplest first-order method; Day 1 meets it, Day 6 studies it.
A method that replaces inequality walls by a smooth barrier and follows the central path through the inside of the feasible set. It takes a few tens of Newton steps, each costly but accurate.
ISTA
Iterative soft-thresholding: proximal gradient descent for the lasso. Take a gradient step on the least-squares part, then soft-threshold for the ℓ1 part.
The error shrinks by a constant factor c < 1 each step, so it falls along a straight line on a log plot. Gradient descent achieves it on strongly convex problems.
Log barrier
φ(x) = −Σ log(−hi(x)), a smooth penalty that is defined only strictly inside the feasible set and blows up at every wall. It stands in for the hard inequality constraints.
Method of multipliers
Dual ascent on the augmented Lagrangian, with the penalty ρ as the step size. It converges under weaker conditions than plain dual ascent, but the x-step no longer splits into pieces.
Fit a quadratic bowl to f at x and jump to its bottom: Δx = −(∇2f(x))−1∇f(x). Damped Newton picks the step length by backtracking. Near the optimum convergence is quadratic.
Primal–dual hybrid gradient: a first-order method that needs only products with the constraint matrix and its transpose, so it runs well on GPUs. PDLP is PDHG tuned for LPs.
Primal-dual interior-point method
Newton steps on the perturbed KKT equations in the primal x and the duals together. It aims each step at a moving target on the central path instead of fully re-centering.
For a composite objective g(x) + h(x), with g smooth and h simple: take a gradient step on g, then apply the proximal operator of h. With h = IC it is projected gradient descent.
proxt(x) = argminz (1/2t)‖x − z‖22 + h(z): a point that balances staying near x against making h small. For an indicator it is projection; for λ‖·‖1, soft-thresholding.
Quadratic convergence
The error roughly squares each step, so the number of correct digits doubles. Newton's method converges this way once it is close to the optimum.
Quasi-Newton method
Newton-like steps with an approximate Hessian built from gradient changes. Each update must satisfy the secant equation B+s = y. SR1, DFP and BFGS are the classic updates.
How much a group of equations or conditions is violated. Interior-point methods track primal, dual and centrality residuals; ADMM stops once its primal and dual residuals fall below a tolerance.
Soft-thresholding
Sλ(x) shrinks each entry toward 0 by λ and sets anything within ±λ to exactly 0. It is the proximal operator of λ‖x‖1, which is why the lasso gives sparse answers.
Step size
t > 0, how far each step moves along the search direction; machine learning calls it the learning rate. Common choices are a fixed step, backtracking, and diminishing steps.
Stochastic gradient descent (SGD)
Gradient descent that uses the gradient of one random term (or a minibatch) of a sum f = Σfi per step. Steps are cheap but noisy, so step sizes usually shrink over time.
x ← x − t·g with any subgradient g ∈ ∂f(x). It is not a descent method, so you keep the best value seen. It needs O(1/ε2) iterations, against O(1/ε) for gradient descent.
An error that falls like a constant over k, such as O(1/k): slower than any fixed shrink factor. One more correct digit costs about ten times more steps.
Superlinear convergence
The ratio between successive errors goes to 0: faster than linear, slower than quadratic. BFGS converges this way near the optimum.
Warm start
Start a solver from the solution of a nearby problem, such as the previous λ on a path or the previous MPC time step. It often cuts the number of iterations sharply.
Duality
Augmented Lagrangian
The Lagrangian plus a quadratic penalty on the constraint residual: Lρ(x, u) = f(x) + uT(Ax − b) + (ρ/2)‖Ax − b‖22. The penalty ρ makes dual methods robust.
Certificate of infeasibility
A vector that proves no feasible point exists. For Ax = b, x ≥ 0, Farkas' lemma says exactly one holds: a feasible x exists, or some y has ATy ≤ 0 and bTy > 0.
Complementary slackness
A KKT condition: λihi(x) = 0 for every inequality. Either the constraint is tight or its multiplier is zero, so an untouched fence pushes with zero force.
Conjugate function
f*(y) = supx (yTx − f(x)), the largest gap between the line yTx and the graph of f. It is convex even when f is not, and duals are often written with it.
Dual cone
K* = {y : yTx ≥ 0 for all x ∈ K}: all vectors that make a non-obtuse angle with every vector of K. Weights from it pick out the minimal (Pareto-optimal) points.
Dual feasible
Multipliers (u, v) with u ⪰ 0 and g(u, v) > −∞. Every dual-feasible point gives a lower bound on the primal optimum p*.
Dual norm
‖z‖* = max{zTx : ‖x‖ ≤ 1}, how large zTx gets over the original unit ball. The dual of ‖·‖1 is ‖·‖∞, and ‖·‖2 is its own dual.
Dual problem
Maximize the dual function g(u, v) subject to u ⪰ 0: the search for the best lower bound on the original, or primal, problem. It is always a convex problem.
Duality gap
f(x) − g(u, v) for a feasible x and a dual-feasible (u, v). It is never negative and bounds how far f(x) is from optimal, so solvers use it to decide when to stop.
KKT conditions
Four checks at a point: stationarity, primal feasibility, dual feasibility (λ ⪰ 0) and complementary slackness. For convex problems they are sufficient for optimality, and necessary when strong duality holds.
Lagrange dual function
g(u, v) = min over x of the Lagrangian L(x, u, v). It is always concave and, for u ⪰ 0, always a lower bound on p*, even when the problem is not convex.
Lagrange multiplier
The price on one constraint, also called a dual variable: ui ≥ 0 for an inequality, and vj of any sign for an equality. At the optimum it is the force that constraint exerts.
Lagrangian
The objective plus priced constraints: L(x, u, v) = f(x) + Σuihi(x) + Σvjℓj(x). On the feasible set, with u ⪰ 0, it never exceeds f(x).
Lagrangian relaxation
Move hard constraints into the objective with prices u ≥ 0 and solve the easier problem that is left. Each price vector gives a bound on the original optimum.
Slater's condition
If a convex problem has a strictly feasible point, strong duality holds: p* = d*. Affine inequalities may hold with equality; only the curved rules need room to spare.
Stationarity
A KKT condition: ∇f(x) + Σλi∇hi(x) + Σνj∇ℓj(x) = 0. The downhill pull of the objective is exactly balanced by the pushes of the constraints.
Strictly feasible
A point that satisfies every inequality with room to spare, hi(x) < 0, and every equality exactly. Slater's condition asks for one.
Strong duality
The primal and dual optimal values are equal, d* = p*, so the optimal duality gap is zero. Convex problems that satisfy Slater's condition have it.
Weak duality
d* ≤ p* for every problem, convex or not: the best lower bound never exceeds the true optimum. The difference p* − d* is the optimal duality gap.
Beyond convex & robotics
Amortized optimization
Learn a model that maps a problem's context (state, goal, obstacles) to an approximate solution, paying most of the cost once at training time. Its output can warm-start a solver.
CBF-QP
A safety filter solved every control step: minimize ‖u − unom‖2 subject to the CBF condition, which is linear in u. It changes the nominal command only when it must.
Constraint qualification
A regularity condition on the constraints that makes the KKT conditions necessary at a local optimum. The common one, LICQ, asks that the gradients of the active constraints be linearly independent.
Control barrier function (CBF)
A margin function h, with safe set h(x) ≥ 0, such that some input can always keep ḣ ≥ −γh. Enforcing that rule keeps the safe set forward invariant: once inside, you stay inside.
Direct transcription
Turn a continuous trajectory into a finite problem: chop time into K steps, make the state and input at each node unknowns, and enforce the dynamics between nodes as defect constraints.
Factorization caching
Reusing one matrix factorization for every solve because the problem matrices never change, only vectors such as the current state. It is why OSQP suits sparse MPC.
Gauss–Newton
For nonlinear least squares: linearize the residuals with their Jacobian J and solve a linear least-squares step, which approximates the Hessian by JTJ. Standard in SLAM and bundle adjustment.
A graph whose vertices are convex regions, each holding a movable point, with convex edge costs that depend on those points. Its convex relaxation, tightened by perspective functions, plans paths with a lower bound.
IPOPT
An open-source interior-point solver for general nonlinear programs, using a barrier, a line search and a filter. It finds a local solution and needs twice-differentiable functions.
IRIS
Iterative Regional Inflation by Semidefinite programming. From a seed point it alternates two convex problems, growing a large obstacle-free polytope with an ellipse inside, to give convex regions for planning.
Kinematic bicycle model
A car model with one front and one rear wheel and no tyre forces, only geometry. For small angles it links lateral acceleration to steering: u ≈ (V2/L)·δ.
Levenberg–Marquardt (LM)
Gauss–Newton plus a damping term λ that shortens risky steps. The gain ratio, actual over predicted decrease, decides whether to accept a step and whether to loosen or tighten λ.
A relaxation that is proven to give the original problem's global optimum. In rocket landing (powered descent guidance) it turns the nonconvex thrust ring into a convex SOCP.
Model predictive control (MPC)
Control by repeatedly solving a finite-horizon optimal-control problem from the current state, applying only the first input, and re-planning at the next tick (receding horizon). With linear models it is a QP.
Modelling tool
Software that turns the math you write into solver-ready matrices (canonicalization), such as CVXPY, JuMP, CasADi, YALMIP or Drake. You state the problem; it calls a solver.
Nonlinear least squares
Minimize the sum of squared nonlinear residuals, ½‖r(x)‖22, where each residual is prediction minus measurement. Pose-graph SLAM and bundle adjustment are examples.
Nonlinear program (NLP)
An optimization problem with a nonlinear, possibly nonconvex, objective or constraints. Solvers usually find only a local optimum, so the starting point matters.
OBCA
Optimization-Based Collision Avoidance: it rewrites “stay at least dmin from the obstacle” with dual variables that certify the distance, giving smooth constraints. Hybrid A* warm-starts it in parking.
OptNet
A neural-network layer whose output is the solution of a QP. Its gradients come from implicit differentiation of the KKT conditions, not from unrolling the solver's steps.
Real-time iteration (RTI)
In nonlinear MPC, do one SQP iteration, a single QP, per sample instead of solving the NLP fully, starting from the previous plan.
Saddle point
A stationary point that is a minimum in some directions and a maximum in others, like a mountain pass. Its Hessian has both positive and negative eigenvalues.
Safe flight corridor
A chain of overlapping convex polyhedra around a coarse path through free space. Keeping each trajectory segment inside its corridor avoids collisions with convex constraints only.
Safety filter
An optimizer between the controller and the motors that minimally edits the nominal command so a safety rule holds. A CBF-QP is the standard example.
SDP relaxation
Replace a hard nonconvex problem by a semidefinite program over a larger set, which gives a lower bound. When the relaxation is exact, as in SE-Sync below a noise threshold, it yields the global optimum.
Sequential convex programming (SCP)
Repeatedly replace a nonconvex problem by a convex approximation around the current guess and solve it inside a trust region. It is a workhorse of trajectory optimization.
Solve a nonlinear program by repeatedly solving a QP model built from the Lagrangian's Hessian and linearized constraints. A merit function or filter judges each step.
The distance between two shapes when they are apart, and minus their penetration depth when they overlap. Collision constraints keep it above a safety margin.
Trajectory optimization
Choosing a whole time-indexed path of states and inputs at once, minimizing a cost subject to the dynamics, input limits and obstacles.
Trust region
A region around the current point where the local model is trusted, such as |xi − xi(k)| ≤ ρi. It grows when the model predicts well and shrinks when it does not.
Virtual control
A fictitious slack input added to the linearized dynamics so SCP subproblems stay feasible, at a heavy cost. It must vanish at convergence. SCvx uses it.