ADMM
Split what is smooth from what kinks, solve each half alone, and let prices negotiate agreement. That alternating deal is ADMM, Lasso's engine.
Why Does This Exist?
Lasso couples smooth squares with kinky : neither pure gradient nor pure thresholding applies, and monolithic solvers ignore the split structure. Distributed cousins couple per-machine losses with one consensus variable. Solving jointly wastes the separability.
ADMM splits over via the augmented Lagrangian, alternating , , and price updates. Each subproblem uses its best solver; the price negotiates agreement. It operationalizes Lagrangian duality for the nonsmooth halves in subgradients.
The one idea you need first
The scaled form iterates , , . Primal residual and dual residual both must vanish; paces them.
Think of It Like This
Two shops and a mediator
A baker (smooth costs) and a florist (kinky staffing) share one storefront window. The mediator proposes a split, each optimizes privately, then the mediator adjusts the rent (price) by the disagreement and repeats.
Neither shop solves the joint problem; the rent does. Where it stops: stubborn rents ( fixed badly) stall haggling. Adaptive rebalances when one residual dominates.
How It Actually Works
Lasso split over : solves a ridge-like linear system, soft-thresholds , accumulates . Consensus form gives distributed learning with per-node and global . Converges for closed convex (residual, objective, dual all converge); linearly under strong convexity plus smoothness. Over-relaxation often halves iterations.
Worked example
Scalar Lasso : optimum soft-thresholds . ADMM with , : ... precisely ; ; . Next , ... iterates walk down toward ? Standard path converges with : residual under 0.01 within about 15 steps. The halves meet at the kink-aware point neither reaches alone.
Code
b, lam, rho = 0.9, 0.5, 1.0x = z = u = 0.0for _ in range(50): x = (b + rho * (z - u)) / (1 + rho) # smooth solve z = float(__import__('math').copysign(max(abs(x + u) - lam / rho, 0.0), x + u)) u = u + x - z # price updateprint(round(x, 3), round(z, 3)) # -> 0.4 0.4Fifty rounds land both at 0.4. The price absorbs the 0.5 threshold shift.
Watch Out For
Stopping on one residual
Primal small with dual large means agreed but suboptimal (prices wrong); dual small with primal large means optimal pieces that disagree. Single-residual stops ship either failure.
Stop when both sit under tolerance with scaling. If one stalls while the other shrinks, retune instead of iterating.
Fixing rho forever
default on badly scaled problems imbalances residuals 100-to-1 and crawls. Practitioners blame ADMM while the pace parameter idles.
Adapt to balance residuals (residual balancing rule). If the ratio exceeds 10 for many steps, rescale and continue.
The Quick Version
- Split smooth from kink, alternate private solves, price the disagreement.
- Scalar Lasso 0.9 with penalty 0.5 converges both halves to 0.4.
- ridge-solves, soft-thresholds, accumulates the gap.
- Both primal and dual residuals must vanish; paces them.
- Consensus form distributes learning with per-node solves.
- Adapt and over-relax near 1.7 for speed.