Imports
import Mathlib.Analysis.Calculus.Gradient.Basic import Mathlib.Analysis.Calculus.LineDeriv.Basic import Mathlib.Analysis.Convex.Function import Mathlib.Analysis.Convex.Deriv import Mathlib.Analysis.Convex.Slope import Mathlib.Analysis.Convex.Jensen import Mathlib.Analysis.InnerProductSpace.Basic import Mathlib.Tactic

33.3 Gradient Descent

This section formalizes the gradient-descent algorithm for minimizing a convex function from CLRS §33.3. Given a convex differentiable function f : E → ℝ on a real inner product space E and a starting point x₀, the algorithm repeatedly moves in the direction of steepest descent, the negative gradient: x_{k+1} = x_k - η · ∇f(x_k) for a fixed learning rate η > 0.

Main results:

  • Definition gradientStep: one gradient-descent update.

  • Definition gdIterates: the sequence of iterates generated from x₀.

  • Definition avgIterate: the arithmetic mean of the first K iterates.

  • Theorem gradient_inner_le_sub: the gradient-descent lemma — for a convex differentiable f, the first-order characterization of convexity ⟪∇f(x), y - x⟫ ≤ f(y) - f(x) holds for all x, y.

  • Theorem gdStep_potential_le: one gradient-descent step shrinks the squared distance to any point x* by at least 2η·(f(x) - f(x*)), up to the additive η²·G² term coming from a bound ‖∇f‖ ≤ G on the gradient norm.

  • Theorem gdIterates_potential_le / sum_suboptimality_le: the telescoping potential chain over K steps and the resulting total-suboptimality bound.

  • Theorem avgIterate_suboptimality_le (Theorem 33.8): the convergence bound — if x* minimizes f, then the average of the first K iterates satisfies f(x̄) - f(x*) ≤ ‖x₀ - x*‖² / (2·η·K) + η·G² / 2.

The proof follows CLRS §33.3. The gradient-descent lemma is the analytic engine: it is proved from ConvexOn and differentiability by restricting f to the segment [x, y] and taking the limit, as t → 0⁺, of the convexity chord inequality (f(x + t(y-x)) - f(x)) / t ≤ f(y) - f(x). This feeds the per-step potential inequality ‖x_{k+1} - x*‖² ≤ ‖x_k - x*‖² - 2η(f(x_k) - f(x*)) + η²G², which telescopes over the K steps and combines with Jensen's inequality for the average iterate to give the convergence bound. The bound is stated for the average iterate; individual iterates can overshoot, and only the amortized progress is guaranteed to converge.

Notation conventions used in this section:

  • E : the ambient real inner product (Hilbert) space

  • f : a convex differentiable function E → ℝ to be minimized

  • η : the learning rate (0 < η)

  • x₀ : the starting point

  • x* : a point minimizing f

  • G : a bound on the norm of the gradient, ‖∇f(x)‖ ≤ G

  • : the average of the first K iterates

noncomputable sectionopen scoped BigOperatorsopen scoped RealInnerProductSpacenamespace CLRSnamespace GradientDescentvariable {E : Type*} [NormedAddCommGroup E] [InnerProductSpace E] [CompleteSpace E]

The gradient-descent lemma. For a convex differentiable function f, the gradient supports the graph from below at every point: for all x, y, ⟪∇f(x), y - x⟫ ≤ f(y) - f(x) (CLRS §33.3). This is the first-order characterization of convexity. The proof restricts f to the segment from x to y; convexity gives the chord bound (f(x + t·(y - x)) - f(x)) / t ≤ f(y) - f(x) for every t ∈ (0, 1], and differentiability of f at x lets t → 0⁺.

Used `tac1 <;> tac2` where `(tac1; tac2)` would suffice Note: This linter can be disabled with `set_option linter.unnecessarySeqFocus false` theorem gradient_inner_le_sub {x y : E} {f : E } (hf : ConvexOn Set.univ f) (hd : DifferentiableAt f x) : gradient f x, y - x f y - f x := by rw [inner_gradient_left] let g : := fun t => f (x + t (y - x)) have hg_convex : ConvexOn (Set.univ : Set ) g := by refine convex_univ, ?_ intro t₁ ht₁ t₂ ht₂ a b ha hb hab have hseg : x + (a t₁ + b t₂) (y - x) = a (x + t₁ (y - x)) + b (x + t₂ (y - x)) := by match_scalars <;> simp [smul_eq_mul] Used `tac1 <;> tac2` where `(tac1; tac2)` would suffice Note: This linter can be disabled with `set_option linter.unnecessarySeqFocus false`<;> nlinarith [hab] calc g (a t₁ + b t₂) = f (x + (a t₁ + b t₂) (y - x)) := rfl _ = f (a (x + t₁ (y - x)) + b (x + t₂ (y - x))) := by rw [hseg] _ a f (x + t₁ (y - x)) + b f (x + t₂ (y - x)) := by have hx : x + t₁ (y - x) (Set.univ : Set E) := by simp have hy : x + t₂ (y - x) (Set.univ : Set E) := by simp exact hf.2 hx hy ha hb hab _ = a g t₁ + b g t₂ := rfl have hg_diff : HasDerivAt g (fderiv f x (y - x)) 0 := by have hf' : HasFDerivAt f (fderiv f x) x := hd.hasFDerivAt exact (hf'.hasLineDerivAt (y - x)) have hslope_le : fderiv f x (y - x) slope g 0 1 := by exact ConvexOn.le_slope_of_hasDerivWithinAt hg_convex (Set.mem_univ 0) (Set.mem_univ 1) (by norm_num) hg_diff.hasDerivWithinAt have hslope : slope g 0 1 = f y - f x := by rw [slope_def_field] have hg1 : g 1 = f y := by simp [g] have hg0 : g 0 = f x := by simp [g, zero_smul] rw [hg1, hg0] norm_num rw [ hslope] exact hslope_le

One gradient-descent step: x ↦ x - η·∇f(x), moving from x in the direction of steepest descent (the negative gradient) with learning rate η (CLRS §33.3).

def gradientStep (η : ) (x : E) (f : E ) : E := x - η gradient f x

The sequence of gradient-descent iterates generated from x₀: x_{k+1} = x_k - η·∇f(x_k) (CLRS §33.3).

def gdIterates (η : ) (x₀ : E) (f : E ) : E | 0 => x₀ | k + 1 => gradientStep η (gdIterates η x₀ f k) f

The average iterate after K steps: the arithmetic mean of the first K iterates x₀, ..., x_{K-1} (CLRS §33.3). For K = 0 the junk value 0 is returned, since (0 : ℝ)⁻¹ = 0.

def avgIterate (η : ) (x₀ : E) (f : E ) (K : ) : E := (K : )⁻¹ k Finset.range K, gdIterates η x₀ f k

Per-step potential bound. One gradient-descent step from x shrinks the squared distance to any point x* by at least 2·η·(f x - f x*), up to the additive η²·G² term:

‖gradientStep η x f - x*‖² ≤ ‖x - x*‖² - 2·η·(f x - f x*) + η²·G²,

where G bounds the gradient norm at x. This is the engine of the convergence analysis: each step makes progress proportional to the current suboptimality, minus a small error term (CLRS §33.3).

Try this: [apply] abel_nf lemma gdStep_potential_le {x xstar : E} {η G : } {f : E } (hf : ConvexOn Set.univ f) (hd : DifferentiableAt f x) ( : 0 η) (hG : gradient f x G) : gradientStep η x f - xstar ^ 2 x - xstar ^ 2 - 2 * η * (f x - f xstar) + η ^ 2 * G ^ 2 := by have hg : f x - f xstar gradient f x, x - xstar := by have hle := gradient_inner_le_sub (x := x) (y := xstar) hf hd have hrewrite : gradient f x, x - xstar = -gradient f x, xstar - x := by rw [inner_sub_right] rw [inner_sub_right] ring rw [hrewrite] linarith have hgnorm : gradient f x ^ 2 G ^ 2 := by nlinarith [hG, norm_nonneg (gradient f x)] calc gradientStep η x f - xstar ^ 2 = (x - xstar) - η gradient f x ^ 2 := by rw [gradientStep] congr 1 Try this: [apply] abel_nfabel _ = x - xstar ^ 2 - 2 * η gradient f x, x - xstar + η gradient f x ^ 2 := by rw [norm_sub_sq (𝕜 := )] simp [real_inner_smul_left, real_inner_comm] _ = x - xstar ^ 2 - 2 * η * gradient f x, x - xstar + η gradient f x ^ 2 := by rw [real_inner_smul_left] ring _ x - xstar ^ 2 - 2 * η * (f x - f xstar) + η gradient f x ^ 2 := by have hinner : 2 * η * (f x - f xstar) 2 * η * gradient f x, x - xstar := by exact mul_le_mul_of_nonneg_left hg (by positivity) nlinarith _ x - xstar ^ 2 - 2 * η * (f x - f xstar) + η ^ 2 * G ^ 2 := by have hsmul : η gradient f x ^ 2 = η ^ 2 * gradient f x ^ 2 := by rw [norm_smul, Real.norm_eq_abs, abs_of_nonneg ] ring have hsqG : η ^ 2 * gradient f x ^ 2 η ^ 2 * G ^ 2 := by exact mul_le_mul_of_nonneg_left hgnorm (sq_nonneg η) rw [hsmul] nlinarith

Telescoping potential chain. After K gradient-descent steps the squared distance to x* satisfies

‖x_K - x*‖² ≤ ‖x₀ - x*‖² - 2·η·Σ_{k<K}(f(x_k) - f(x*)) + K·η²·G².

Each step's potential loss compounds into a cumulative suboptimality sum (CLRS §33.3).

lemma gdIterates_potential_le {x₀ xstar : E} {η G : } {f : E } (hf : ConvexOn Set.univ f) (hd : y, DifferentiableAt f y) ( : 0 η) (hG : y, gradient f y G) (K : ) : gdIterates η x₀ f K - xstar ^ 2 x₀ - xstar ^ 2 - 2 * η * ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) + (K : ) * η ^ 2 * G ^ 2 := by induction K with | zero => simp [gdIterates] | succ K ih => let xK : E := gdIterates η x₀ f K have hrec : gdIterates η x₀ f (K + 1) - xstar ^ 2 xK - xstar ^ 2 - 2 * η * (f xK - f xstar) + η ^ 2 * G ^ 2 := by simpa [xK, gdIterates] using (gdStep_potential_le hf (hd xK) (hG xK)) calc gdIterates η x₀ f (K + 1) - xstar ^ 2 xK - xstar ^ 2 - 2 * η * (f xK - f xstar) + η ^ 2 * G ^ 2 := hrec _ x₀ - xstar ^ 2 - 2 * η * ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) + (K : ) * η ^ 2 * G ^ 2 - 2 * η * (f xK - f xstar) + η ^ 2 * G ^ 2 := by dsimp [xK] nlinarith [ih] _ = x₀ - xstar ^ 2 - 2 * η * ( k Finset.range (K + 1), (f (gdIterates η x₀ f k) - f xstar)) + ((K + 1 : ) : ) * η ^ 2 * G ^ 2 := by rw [Finset.sum_range_succ] simp [xK] ring

Total-suboptimality bound. The sum of suboptimalities over the first K iterates is bounded by ‖x₀ - x*‖²/(2·η) + K·η·G²/2:

Σ_{k<K} (f(x_k) - f(x*)) ≤ ‖x₀ - x*‖²/(2·η) + (K:ℝ)·η·G²/2.

This is the telescoped potential chain with the (nonnegative) final-distance term dropped (CLRS §33.3).

lemma sum_suboptimality_le {x₀ xstar : E} {η G : } {f : E } (hf : ConvexOn Set.univ f) (hd : y, DifferentiableAt f y) ( : 0 < η) (hG : y, gradient f y G) (K : ) : ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) x₀ - xstar ^ 2 / (2 * η) + (K : ) * η * G ^ 2 / 2 := by have hpot : gdIterates η x₀ f K - xstar ^ 2 x₀ - xstar ^ 2 - 2 * η * ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) + (K : ) * η ^ 2 * G ^ 2 := gdIterates_potential_le hf hd (le_of_lt ) hG K have h0 : 0 gdIterates η x₀ f K - xstar ^ 2 := sq_nonneg _ have hlin : 2 * η * ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) x₀ - xstar ^ 2 + (K : ) * η ^ 2 * G ^ 2 := by nlinarith [hpot, h0] have hdiv : ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) (x₀ - xstar ^ 2 + (K : ) * η ^ 2 * G ^ 2) / (2 * η) := by rw [le_div_iff₀ (by positivity : 0 < 2 * η)] simpa [mul_comm] using hlin exact le_trans hdiv (by field_simp [.ne'] exact le_rfl)

Convergence bound (Theorem 33.8). If x* minimizes f, then the average iterate of the first K iterates satisfies

f(x̄) - f(x*) ≤ ‖x₀ - x*‖²/(2·η·K) + η·G²/2.

The proof combines Jensen's inequality for the convex f — the average suboptimality is at most the average of the suboptimalities — with the total-suboptimality bound divided by K (CLRS §33.3).

theorem avgIterate_suboptimality_le {x₀ xstar : E} {η G : } {f : E } (hf : ConvexOn Set.univ f) (hd : y, DifferentiableAt f y) ( : 0 < η) (hG : y, gradient f y G) {K : } (hK : 0 < K) : f (avgIterate η x₀ f K) - f xstar x₀ - xstar ^ 2 / (2 * η * K) + η * G ^ 2 / 2 := by have hKc : (K : ) 0 := by exact_mod_cast (ne_of_gt hK) have hJ : f ( k Finset.range K, (K : )⁻¹ gdIterates η x₀ f k) k Finset.range K, (K : )⁻¹ f (gdIterates η x₀ f k) := by refine hf.map_sum_le ?_ ?_ ?_ · intro i hi exact inv_nonneg.mpr (Nat.cast_nonneg K) · rw [Finset.sum_const, Finset.card_range, nsmul_eq_mul, mul_inv_cancel₀ hKc] · intro i hi exact Set.mem_univ _ have hJensen : f (avgIterate η x₀ f K) (K : )⁻¹ ( k Finset.range K, f (gdIterates η x₀ f k)) := by calc f (avgIterate η x₀ f K) = f ( k Finset.range K, (K : )⁻¹ gdIterates η x₀ f k) := by rw [avgIterate, Finset.smul_sum] _ k Finset.range K, (K : )⁻¹ f (gdIterates η x₀ f k) := hJ _ = (K : )⁻¹ ( k Finset.range K, f (gdIterates η x₀ f k)) := by rw [Finset.smul_sum] have hCancel : (K : )⁻¹ * ((K : ) * f xstar) = f xstar := by rw [ mul_assoc, inv_mul_cancel₀ hKc] simp have hshift_in : ( k Finset.range K, f (gdIterates η x₀ f k)) - (K : ) * f xstar = k Finset.range K, (f (gdIterates η x₀ f k) - f xstar) := by rw [show (K : ) * f xstar = k Finset.range K, f xstar by rw [Finset.sum_const, Finset.card_range, nsmul_eq_mul]] rw [ Finset.sum_sub_distrib] have hshift : (K : )⁻¹ ( k Finset.range K, f (gdIterates η x₀ f k)) - f xstar = (K : )⁻¹ ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) := by rw [smul_eq_mul, smul_eq_mul, hshift_in, mul_sub, hCancel] have hmain : f (avgIterate η x₀ f K) - f xstar (K : )⁻¹ ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) := by calc f (avgIterate η x₀ f K) - f xstar (K : )⁻¹ ( k Finset.range K, f (gdIterates η x₀ f k)) - f xstar := by linarith [hJensen] _ = (K : )⁻¹ ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) := hshift have hsum : ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) x₀ - xstar ^ 2 / (2 * η) + (K : ) * η * G ^ 2 / 2 := sum_suboptimality_le hf hd hG K have hscale : (K : )⁻¹ * ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) (K : )⁻¹ * (x₀ - xstar ^ 2 / (2 * η) + (K : ) * η * G ^ 2 / 2) := by exact mul_le_mul_of_nonneg_left hsum (inv_nonneg.mpr (Nat.cast_nonneg K)) have hfinal : f (avgIterate η x₀ f K) - f xstar (K : )⁻¹ * (x₀ - xstar ^ 2 / (2 * η) + (K : ) * η * G ^ 2 / 2) := by calc f (avgIterate η x₀ f K) - f xstar (K : )⁻¹ ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) := hmain _ = (K : )⁻¹ * ( k Finset.range K, (f (gdIterates η x₀ f k) - f xstar)) := by rfl _ (K : )⁻¹ * (x₀ - xstar ^ 2 / (2 * η) + (K : ) * η * G ^ 2 / 2) := hscale have hsimpl : (K : )⁻¹ * (x₀ - xstar ^ 2 / (2 * η) + (K : ) * η * G ^ 2 / 2) = x₀ - xstar ^ 2 / (2 * η * K) + η * G ^ 2 / 2 := by field_simp [hKc, .ne'] exact le_trans hfinal (le_of_eq hsimpl)
end GradientDescentend CLRS