diff --git a/LeanPool/PLAcceleratedNesterovLean/Convergence/Bootstrap/Main.lean b/LeanPool/PLAcceleratedNesterovLean/Convergence/Bootstrap/Main.lean index 5fe156d784..1f60fe7cc9 100644 --- a/LeanPool/PLAcceleratedNesterovLean/Convergence/Bootstrap/Main.lean +++ b/LeanPool/PLAcceleratedNesterovLean/Convergence/Bootstrap/Main.lean @@ -27,6 +27,138 @@ namespace PLAcceleratedNesterovLean open scoped Topology NNReal open Manifold +/-- `√(c ^ m) = (√c) ^ m` for `0 ≤ c`. -/ +private theorem sqrt_pow_eq_pow_sqrt {c : ℝ} (hc : 0 ≤ c) (m : ℕ) : + Real.sqrt (c ^ m) = Real.sqrt c ^ m := by + induction m with + | zero => simp only [pow_zero, Real.sqrt_one] + | succ k ihk => rw [pow_succ, Real.sqrt_mul (pow_nonneg hc k), ihk, pow_succ] + +/-- The contraction factor `c = 1 - (1 - θ)·√(μ'η)` satisfies `0 ≤ c ≤ 1` and `√c < 1`. -/ +private theorem contraction_factor_bounds {μ' η θ : ℝ} (hμ' : 0 < μ') (hη_pos : 0 < η) + (hμη_lt1 : μ' * η < 1) (hθ_pos : 0 < θ) (hθ_lt1 : θ < 1) : + 0 ≤ 1 - (1 - θ) * Real.sqrt (μ' * η) ∧ 1 - (1 - θ) * Real.sqrt (μ' * η) ≤ 1 ∧ + Real.sqrt (1 - (1 - θ) * Real.sqrt (μ' * η)) < 1 := by + have hμη_pos : 0 < μ' * η := mul_pos hμ' hη_pos + have ha_pos : 0 < Real.sqrt (μ' * η) := Real.sqrt_pos_of_pos hμη_pos + have ha_lt1 : Real.sqrt (μ' * η) < 1 := by + calc Real.sqrt (μ' * η) < Real.sqrt 1 := Real.sqrt_lt_sqrt (le_of_lt hμη_pos) hμη_lt1 + _ = 1 := Real.sqrt_one + have hc_pos : 0 < 1 - (1 - θ) * Real.sqrt (μ' * η) := by + nlinarith [mul_pos (sub_pos.mpr hθ_lt1) ha_pos] + have hc_lt1 : 1 - (1 - θ) * Real.sqrt (μ' * η) < 1 := by + nlinarith [mul_pos (sub_pos.mpr hθ_lt1) ha_pos] + refine ⟨le_of_lt hc_pos, le_of_lt hc_lt1, ?_⟩ + calc Real.sqrt (1 - (1 - θ) * Real.sqrt (μ' * η)) < Real.sqrt 1 := + Real.sqrt_lt_sqrt (le_of_lt hc_pos) hc_lt1 + _ = 1 := Real.sqrt_one + +/-- Triangle inequality for a translated point: `dist (y + h) m ≤ dist y m + ‖h‖`. -/ +private theorem dist_add_le_dist_add_norm {d : ℕ} (y h m : E d) : + dist (y + h) m ≤ dist y m + ‖h‖ := by + rw [dist_eq_norm, dist_eq_norm] + calc ‖y + h - m‖ = ‖(y - m) + h‖ := by congr 1; abel + _ ≤ ‖y - m‖ + ‖h‖ := norm_add_le _ _ + +/-- Triangle inequality for a translated point: `dist (y - v) m ≤ dist y m + ‖v‖`. -/ +private theorem dist_sub_le_dist_add_norm {d : ℕ} (y v m : E d) : + dist (y - v) m ≤ dist y m + ‖v‖ := by + rw [dist_eq_norm, dist_eq_norm] + calc ‖y - v - m‖ = ‖(y - m) - v‖ := by congr 1; abel + _ ≤ ‖y - m‖ + ‖v‖ := norm_sub_le _ _ + +/-- A geometric partial sum of displacements is bounded by `A·√L₀/(1-√c)`. -/ +private theorem geometric_displacement_le {A L₀ c r : ℝ} (hA : 0 ≤ A) + (hsqrt_c_lt1 : Real.sqrt c < 1) + (hdisp : A * Real.sqrt L₀ / (1 - Real.sqrt c) ≤ r / 4) (n : ℕ) : + A * Real.sqrt L₀ * (Finset.range n).sum (fun k => Real.sqrt c ^ k) ≤ r / 4 := by + have hle := partial_geom_series_bound (Real.sqrt c) (Real.sqrt_nonneg c) hsqrt_c_lt1 n + calc A * Real.sqrt L₀ * (Finset.range n).sum (fun k => Real.sqrt c ^ k) + ≤ A * Real.sqrt L₀ * (1 / (1 - Real.sqrt c)) := + mul_le_mul_of_nonneg_left hle (mul_nonneg hA (Real.sqrt_nonneg _)) + _ = A * Real.sqrt L₀ / (1 - Real.sqrt c) := by ring + _ ≤ r / 4 := hdisp + +/-- **Abstract displacement induction** behind both bootstrap theorems. + +Let `X n` be the iterates, `Y n` the look-ahead points with steps `Y (n + 1) = Y n + H n`, +and `X n = Y n - V n`. If, while both stay in `Ω` with Lyapunov value `Lf n ≤ R²`, the +Lyapunov value contracts by `c` and the steps `H n`, `V (n + 1)` are controlled by `√(Lf n)`, +then a start close enough to `m_star` keeps every iterate in `ball m_star r ⊆ Ω` and +`Lf n ≤ c ^ n · Lf 0`. -/ +private theorem bootstrap_displacement_induction {d : ℕ} + (X Y H V : ℕ → E d) (Lf : ℕ → ℝ) (Ω : Set (E d)) (m_star : E d) + (r R c A B : ℝ) (hA : 0 ≤ A) (hB : 0 ≤ B) + (hc_nonneg : 0 ≤ c) (hc_le_one : c ≤ 1) (hsqrt_c_lt1 : Real.sqrt c < 1) + (hball_Ω : Metric.ball m_star r ⊆ Ω) + (hY_step : ∀ n, Y (n + 1) = Y n + H n) (hX_eq : ∀ n, X n = Y n - V n) + (hcontract : ∀ n, X n ∈ Ω → Y n ∈ Ω → Lf n ≤ R ^ 2 → Lf (n + 1) ≤ c * Lf n) + (hH : ∀ n, X n ∈ Ω → Y n ∈ Ω → Lf n ≤ R ^ 2 → ‖H n‖ ≤ A * Real.sqrt (Lf n)) + (hV : ∀ n, X n ∈ Ω → Y n ∈ Ω → Lf n ≤ R ^ 2 → ‖V (n + 1)‖ ≤ B * Real.sqrt (Lf n)) + (hX0 : dist (X 0) m_star < r / 4) (hY0 : dist (Y 0) m_star < r / 4) + (hL0_R : Lf 0 ≤ R ^ 2) (hL0_nonneg : 0 ≤ Lf 0) + (hdisp : A * Real.sqrt (Lf 0) / (1 - Real.sqrt c) ≤ r / 4) + (hvel : B * Real.sqrt (Lf 0) ≤ r / 4) (n : ℕ) : + (X n ∈ Ω ∧ Y n ∈ Ω) ∧ (dist (X n) m_star < r ∧ dist (Y n) m_star < r) ∧ + Lf n ≤ c ^ n * Lf 0 := by + have hr_pos : 0 < r := by linarith [dist_nonneg (x := X 0) (y := m_star)] + -- While the displacement-sum bound holds, the look-ahead stays within `r / 2` of `m_star`. + have hY_half : ∀ k, dist (Y k) m_star ≤ dist (Y 0) m_star + A * Real.sqrt (Lf 0) * + (Finset.range k).sum (fun j => Real.sqrt c ^ j) → dist (Y k) m_star < r / 2 := by + intro k hk + linarith [geometric_displacement_le hA hsqrt_c_lt1 hdisp k] + have hinv : ∀ n, dist (X n) m_star < r ∧ Lf n ≤ c ^ n * Lf 0 ∧ + dist (Y n) m_star ≤ dist (Y 0) m_star + A * Real.sqrt (Lf 0) * + (Finset.range n).sum (fun k => Real.sqrt c ^ k) := by + intro n + induction n with + | zero => + refine ⟨by linarith, by simp only [pow_zero, one_mul, le_refl], ?_⟩ + simp only [Finset.range_zero, Finset.sum_empty, mul_zero, add_zero, le_refl] + | succ n ih => + obtain ⟨hXn, hLn, hYn⟩ := ih + have hXn_Ω : X n ∈ Ω := hball_Ω (Metric.mem_ball.mpr hXn) + have hYn_Ω : Y n ∈ Ω := hball_Ω (Metric.mem_ball.mpr (by linarith [hY_half n hYn])) + have hLn_le : Lf n ≤ Lf 0 := by + have := mul_le_of_le_one_left hL0_nonneg (pow_le_one₀ hc_nonneg hc_le_one (n := n)) + linarith + have hLn_R : Lf n ≤ R ^ 2 := le_trans hLn_le hL0_R + have hsqrt_Ln : Real.sqrt (Lf n) ≤ Real.sqrt c ^ n * Real.sqrt (Lf 0) := by + calc Real.sqrt (Lf n) ≤ Real.sqrt (c ^ n * Lf 0) := Real.sqrt_le_sqrt hLn + _ = Real.sqrt c ^ n * Real.sqrt (Lf 0) := by + rw [Real.sqrt_mul (pow_nonneg hc_nonneg n), sqrt_pow_eq_pow_sqrt hc_nonneg] + have hH_geom : ‖H n‖ ≤ A * Real.sqrt (Lf 0) * Real.sqrt c ^ n := by + calc ‖H n‖ ≤ A * Real.sqrt (Lf n) := hH n hXn_Ω hYn_Ω hLn_R + _ ≤ A * (Real.sqrt c ^ n * Real.sqrt (Lf 0)) := + mul_le_mul_of_nonneg_left hsqrt_Ln hA + _ = A * Real.sqrt (Lf 0) * Real.sqrt c ^ n := by ring + have hYn1 : dist (Y (n + 1)) m_star ≤ dist (Y 0) m_star + A * Real.sqrt (Lf 0) * + (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) := by + calc dist (Y (n + 1)) m_star ≤ dist (Y n) m_star + ‖H n‖ := by + rw [hY_step n]; exact dist_add_le_dist_add_norm _ _ _ + _ ≤ (dist (Y 0) m_star + A * Real.sqrt (Lf 0) * + (Finset.range n).sum (fun k => Real.sqrt c ^ k)) + + A * Real.sqrt (Lf 0) * Real.sqrt c ^ n := by linarith + _ = dist (Y 0) m_star + A * Real.sqrt (Lf 0) * + (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) := by + rw [Finset.sum_range_succ]; ring + have hV_small : ‖V (n + 1)‖ ≤ r / 4 := by + calc ‖V (n + 1)‖ ≤ B * Real.sqrt (Lf n) := hV n hXn_Ω hYn_Ω hLn_R + _ ≤ B * Real.sqrt (Lf 0) := + mul_le_mul_of_nonneg_left (Real.sqrt_le_sqrt hLn_le) hB + _ ≤ r / 4 := hvel + refine ⟨?_, ?_, hYn1⟩ + · calc dist (X (n + 1)) m_star ≤ dist (Y (n + 1)) m_star + ‖V (n + 1)‖ := by + rw [hX_eq (n + 1)]; exact dist_sub_le_dist_add_norm _ _ _ + _ < r := by linarith [hY_half (n + 1) hYn1] + · calc Lf (n + 1) ≤ c * Lf n := hcontract n hXn_Ω hYn_Ω hLn_R + _ ≤ c * (c ^ n * Lf 0) := mul_le_mul_of_nonneg_left hLn hc_nonneg + _ = c ^ (n + 1) * Lf 0 := by ring + obtain ⟨hXn, hLn, hYn⟩ := hinv n + have hYn_lt : dist (Y n) m_star < r := by linarith [hY_half n hYn] + exact ⟨⟨hball_Ω (Metric.mem_ball.mpr hXn), hball_Ω (Metric.mem_ball.mpr hYn_lt)⟩, + ⟨hXn, hYn_lt⟩, hLn⟩ + /-- **Bootstrap via total displacement control.** There exists α > 0 such that for Ubar_{m⋆} = B(m⋆, α) ∩ U and every start point in @@ -37,7 +169,7 @@ Ubar_{m⋆} with zero initial velocity: The budget-split parameter θ ∈ (0,1) is inherited from the contraction hypothesis. -/ -private abbrev bootstrapTotalDisplacementProof +private theorem bootstrapTotalDisplacementProof {d : ℕ} (_hd : 0 < d) -- The objective function (f : E d → ℝ) @@ -110,21 +242,10 @@ private abbrev bootstrapTotalDisplacementProof lyapunov P μ' π f η ρ x₁ (n + 1) ≤ (1 - (1 - θ) * a) ^ (n + 1) * lyapunov P μ' π f η ρ x₁ 0) := by -- ── Contraction rate and auxiliary constants ──────────────────────────── + obtain ⟨hc_nonneg, hc_le_one, hsqrt_c_lt1⟩ := + contraction_factor_bounds hμ' hη_pos hμη_lt1 hθ_pos hθ_lt1 set a := Real.sqrt (μ' * η) with ha_def set c := 1 - (1 - θ) * a with hc_def - have hμη_pos : 0 < μ' * η := mul_pos hμ' hη_pos - have ha_pos : 0 < a := Real.sqrt_pos_of_pos hμη_pos - have ha_lt1 : a < 1 := by - calc a = Real.sqrt (μ' * η) := rfl - _ < Real.sqrt 1 := Real.sqrt_lt_sqrt (le_of_lt hμη_pos) (by linarith) - _ = 1 := Real.sqrt_one - have hc_pos : (0 : ℝ) < c := by simp only [c]; nlinarith [mul_pos (sub_pos.mpr hθ_lt1) ha_pos] - have hc_lt1 : c < 1 := by simp only [c]; nlinarith [mul_pos (sub_pos.mpr hθ_lt1) ha_pos] - have hc_nonneg : (0 : ℝ) ≤ c := le_of_lt hc_pos - have hc_le_one : c ≤ 1 := le_of_lt hc_lt1 - have hsqrt_c_lt1 : Real.sqrt c < 1 := by - calc Real.sqrt c < Real.sqrt 1 := Real.sqrt_lt_sqrt hc_nonneg (by linarith) - _ = 1 := Real.sqrt_one have h1_sub_sqrt_c_pos : (0 : ℝ) < 1 - Real.sqrt c := by linarith -- ── Step 1: Get r from Ω being open at m⋆ ────────────────────────────── obtain ⟨r, hr_pos, hball_Ω⟩ := Metric.isOpen_iff.mp hΩ_open m_star hm_star_Ω @@ -207,169 +328,23 @@ private abbrev bootstrapTotalDisplacementProof calc C_mov * Real.sqrt (L 0) ≤ K * Real.sqrt (L 0) := mul_le_mul_of_nonneg_right this (Real.sqrt_nonneg _) _ ≤ r / 4 := hKL0 - -- ── Main induction ───────────────────────────────────────────────────── - -- Invariant: Ω-membership + Lyapunov decay + lookahead displacement bound - -- D(n) := dist(x'_n, m⋆) ≤ dist(x₁,m⋆) + C_h·√η·√(L 0)·Σ_{k Real.sqrt c ^ k) := by - intro n - induction n with - | zero => - refine ⟨⟨hx₁_Ω, ?_⟩, by simp only [pow_zero, one_mul, le_refl], ?_⟩ - · -- x'₀ ∈ Ω (v₀ = 0 so x'₀ = x₁) - simp only [NesterovState.lookahead, nesterovSeq, smul_zero, add_zero]; exact hx₁_Ω - · -- displacement base case - simp only [NesterovState.lookahead, nesterovSeq, - smul_zero, add_zero, Finset.range_zero, - Finset.sum_empty, mul_zero, le_refl] - | succ n ih => - obtain ⟨⟨hxn_Ω, hxn'_Ω⟩, hLn, hDn⟩ := ih - -- L n ≤ R² (from c^n ≤ 1 and L 0 ≤ R²) - have hLn_R : L n ≤ R ^ 2 := by - have hcn : c ^ n ≤ 1 := pow_le_one₀ hc_nonneg hc_le_one - have hcnL0 : c ^ n * L 0 ≤ L 0 := mul_le_of_le_one_left hL0_nonneg hcn - linarith - -- Motion bounds - have hh_bound : ‖nesterovH f η ρ x₁ n‖ ≤ C_h * Real.sqrt η * Real.sqrt (L n) := - hstep_bound x₁ n hxn_Ω hxn'_Ω hLn_R - have hv_bound : ‖Real.sqrt η • (nesterovSeq f η ρ x₁ (n + 1)).v‖ ≤ - C_mov * Real.sqrt (L n) := - hvel_bound x₁ n hxn_Ω hxn'_Ω hLn_R - -- √(c^m) = (√c)^m for any m - have sqrt_pow_c : ∀ m : ℕ, Real.sqrt (c ^ m) = Real.sqrt c ^ m := by - intro m; induction m with - | zero => simp only [pow_zero, Real.sqrt_one] - | succ k ihk => - rw [pow_succ, Real.sqrt_mul (pow_nonneg hc_nonneg k), ihk, pow_succ] - -- √(L n) ≤ (√c)^n · √(L 0) - have hsqrt_Ln : Real.sqrt (L n) ≤ Real.sqrt c ^ n * Real.sqrt (L 0) := by - calc Real.sqrt (L n) ≤ Real.sqrt (c ^ n * L 0) := - Real.sqrt_le_sqrt hLn - _ = Real.sqrt (c ^ n) * Real.sqrt (L 0) := - Real.sqrt_mul (pow_nonneg hc_nonneg n) (L 0) - _ = Real.sqrt c ^ n * Real.sqrt (L 0) := by rw [sqrt_pow_c] - -- ‖h_n‖ ≤ C_h·√η·√(L 0)·(√c)^n - have hh_geom : ‖nesterovH f η ρ x₁ n‖ ≤ - C_h * Real.sqrt η * Real.sqrt (L 0) * Real.sqrt c ^ n := by - calc ‖nesterovH f η ρ x₁ n‖ - ≤ C_h * Real.sqrt η * Real.sqrt (L n) := hh_bound - _ ≤ C_h * Real.sqrt η * (Real.sqrt c ^ n * Real.sqrt (L 0)) := by - apply mul_le_mul_of_nonneg_left hsqrt_Ln - apply mul_nonneg (le_of_lt hC_h) (Real.sqrt_nonneg _) - _ = C_h * Real.sqrt η * Real.sqrt (L 0) * Real.sqrt c ^ n := by ring - -- ── Displacement bound for x'_{n+1} ──────────────────────────────── - -- x'_{n+1} = x'_n + h_n (by definition of nesterovH) - -- dist(x'_{n+1}, m⋆) ≤ dist(x'_n, m⋆) + ‖h_n‖ - have hDn1 : dist ((nesterovSeq f η ρ x₁ (n + 1)).lookahead η) m_star ≤ - dist x₁ m_star + C_h * Real.sqrt η * Real.sqrt (L 0) * - (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) := by - -- h_n = x'_{n+1} - x'_n - have hH_def : nesterovH f η ρ x₁ n = - (nesterovSeq f η ρ x₁ (n + 1)).lookahead η - + -- ── Main induction (abstract displacement argument) ─────────────────── + have hmain := bootstrap_displacement_induction + (fun n => (nesterovSeq f η ρ x₁ n).x) (fun n => (nesterovSeq f η ρ x₁ n).lookahead η) + (nesterovH f η ρ x₁) (fun n => Real.sqrt η • (nesterovSeq f η ρ x₁ n).v) L Ω m_star + r R c (C_h * Real.sqrt η) C_mov (by positivity) hC_mov.le hc_nonneg hc_le_one hsqrt_c_lt1 + hball_Ω + (fun n => by + have hH_def : nesterovH f η ρ x₁ n = (nesterovSeq f η ρ x₁ (n + 1)).lookahead η - (nesterovSeq f η ρ x₁ n).lookahead η := rfl - -- So x'_{n+1} = x'_n + h_n - have hla_step : (nesterovSeq f η ρ x₁ (n + 1)).lookahead η = - (nesterovSeq f η ρ x₁ n).lookahead η + nesterovH f η ρ x₁ n := by - rw [hH_def]; abel - calc dist ((nesterovSeq f η ρ x₁ (n + 1)).lookahead η) m_star - = dist ((nesterovSeq f η ρ x₁ n).lookahead η + - nesterovH f η ρ x₁ n) m_star := by rw [hla_step] - _ ≤ dist ((nesterovSeq f η ρ x₁ n).lookahead η) m_star + - ‖nesterovH f η ρ x₁ n‖ := by - rw [dist_eq_norm, dist_eq_norm] - calc ‖(nesterovSeq f η ρ x₁ n).lookahead η + - nesterovH f η ρ x₁ n - m_star‖ - = ‖((nesterovSeq f η ρ x₁ n).lookahead η - m_star) + - nesterovH f η ρ x₁ n‖ := by congr 1; abel - _ ≤ ‖(nesterovSeq f η ρ x₁ n).lookahead η - m_star‖ + - ‖nesterovH f η ρ x₁ n‖ := norm_add_le _ _ - _ ≤ (dist x₁ m_star + C_h * Real.sqrt η * Real.sqrt (L 0) * - (Finset.range n).sum (fun k => Real.sqrt c ^ k)) + - C_h * Real.sqrt η * Real.sqrt (L 0) * Real.sqrt c ^ n := by - linarith [hDn, hh_geom] - _ = dist x₁ m_star + C_h * Real.sqrt η * Real.sqrt (L 0) * - (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) := by - rw [Finset.sum_range_succ]; ring - -- Tighter displacement upper bound: dist(x'_{n+1}, m⋆) ≤ r/4 + r/4 = r/2 - have hDn1_le_half : dist ((nesterovSeq f η ρ x₁ (n + 1)).lookahead η) m_star ≤ - r / 2 := by - have hsum_bound : C_h * Real.sqrt η * Real.sqrt (L 0) * - (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) ≤ r / 4 := by - have hle := partial_geom_series_bound (Real.sqrt c) - (Real.sqrt_nonneg c) hsqrt_c_lt1 (n + 1) - calc C_h * Real.sqrt η * Real.sqrt (L 0) * - (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) - ≤ C_h * Real.sqrt η * Real.sqrt (L 0) * (1 / (1 - Real.sqrt c)) := by - apply mul_le_mul_of_nonneg_left hle - apply mul_nonneg (mul_nonneg (le_of_lt hC_h) (Real.sqrt_nonneg _)) - (Real.sqrt_nonneg _) - _ = C_h * Real.sqrt η * Real.sqrt (L 0) / (1 - Real.sqrt c) := by ring - _ ≤ r / 4 := hdisp_bound - linarith [hDn1, hx₁_dist] - have hDn1_lt_r : dist ((nesterovSeq f η ρ x₁ (n + 1)).lookahead η) m_star < r := by - linarith - -- ── Velocity bound for x_{n+1} ───────────────────────────────────── - -- C_mov · √(L n) ≤ C_mov · √(L 0) ≤ r/4 - have hvel_Ln : C_mov * Real.sqrt (L n) ≤ r / 4 := by - have hLn_le_L0 : L n ≤ L 0 := by - have := pow_le_one₀ hc_nonneg hc_le_one (n := n) - have := mul_le_of_le_one_left hL0_nonneg this - linarith - calc C_mov * Real.sqrt (L n) - ≤ C_mov * Real.sqrt (L 0) := by - apply mul_le_mul_of_nonneg_left (Real.sqrt_le_sqrt hLn_le_L0) (le_of_lt hC_mov) - _ ≤ r / 4 := hvel_comp - -- ── x_{n+1} ∈ Ω ── - -- dist(x'_{n+1}, m⋆) ≤ r/2, dist(x_{n+1}, m⋆) ≤ r/2 + r/4 = 3r/4 < r - have hxn1_mem : (nesterovSeq f η ρ x₁ (n + 1)).x ∈ Ω := by - apply hball_Ω; rw [Metric.mem_ball] - -- x = x' - √η · v, so dist(x, m⋆) ≤ dist(x', m⋆) + ‖√η · v‖ - have hx_eq : (nesterovSeq f η ρ x₁ (n + 1)).x = - (nesterovSeq f η ρ x₁ (n + 1)).lookahead η - - Real.sqrt η • (nesterovSeq f η ρ x₁ (n + 1)).v := by - simp only [NesterovState.lookahead, add_sub_cancel_right] - calc dist (nesterovSeq f η ρ x₁ (n + 1)).x m_star - = dist ((nesterovSeq f η ρ x₁ (n + 1)).lookahead η - - Real.sqrt η • (nesterovSeq f η ρ x₁ (n + 1)).v) m_star := by - rw [hx_eq] - _ ≤ dist ((nesterovSeq f η ρ x₁ (n + 1)).lookahead η) m_star + - ‖Real.sqrt η • (nesterovSeq f η ρ x₁ (n + 1)).v‖ := by - rw [dist_eq_norm, dist_eq_norm] - calc ‖(nesterovSeq f η ρ x₁ (n + 1)).lookahead η - - Real.sqrt η • (nesterovSeq f η ρ x₁ (n + 1)).v - m_star‖ - = ‖((nesterovSeq f η ρ x₁ (n + 1)).lookahead η - m_star) - - Real.sqrt η • (nesterovSeq f η ρ x₁ (n + 1)).v‖ := by - congr 1; abel - _ ≤ ‖(nesterovSeq f η ρ x₁ (n + 1)).lookahead η - m_star‖ + - ‖Real.sqrt η • (nesterovSeq f η ρ x₁ (n + 1)).v‖ := - norm_sub_le _ _ - _ ≤ dist ((nesterovSeq f η ρ x₁ (n + 1)).lookahead η) m_star + - C_mov * Real.sqrt (L n) := by linarith [hv_bound] - _ ≤ r / 2 + r / 4 := by linarith [hDn1_le_half, hvel_Ln] - _ < r := by linarith - -- ── x'_{n+1} ∈ Ω ─────────────────────────────────────────────────── - have hxn1'_mem : (nesterovSeq f η ρ x₁ (n + 1)).lookahead η ∈ Ω := by - apply hball_Ω; exact Metric.mem_ball.mpr hDn1_lt_r - -- ── Assemble ──────────────────────────────────────────────────────── - refine ⟨⟨hxn1_mem, hxn1'_mem⟩, ?_, hDn1⟩ - -- Lyapunov decay: L(n+1) ≤ c^{n+1} · L 0 - calc L (n + 1) ≤ c * L n := hcontract x₁ n hxn_Ω hxn'_Ω hLn_R - _ ≤ c * (c ^ n * L 0) := by - apply mul_le_mul_of_nonneg_left hLn hc_nonneg - _ = c ^ (n + 1) * L 0 := by ring - refine ⟨fun n => (hinduction n).1, fun n => ?_, fun n => ?_⟩ - · -- (2) All iterates remain in U - exact hΩ_sub_U (hinduction n).1.1 - · -- (3) Geometric decay - exact (hinduction (n + 1)).2.1 - + rw [hH_def]; abel) + (fun n => by simp only [NesterovState.lookahead, add_sub_cancel_right]) + (fun n h₁ h₂ h₃ => hcontract x₁ n h₁ h₂ h₃) (fun n h₁ h₂ h₃ => hstep_bound x₁ n h₁ h₂ h₃) + (fun n h₁ h₂ h₃ => hvel_bound x₁ n h₁ h₂ h₃) hx₁_dist + (by simp only [NesterovState.lookahead, nesterovSeq, smul_zero, add_zero]; exact hx₁_dist) + hL0_bound hL0_nonneg hdisp_bound hvel_comp + exact ⟨fun n => (hmain n).1, fun n => hΩ_sub_U (hmain n).1.1, fun n => (hmain (n + 1)).2.2⟩ --- Bootstrap argument requires additional heartbeats for the proof term /-- **Generalized bootstrap via total displacement control.** @@ -381,7 +356,7 @@ Generalization of `bootstrap_total_displacement` supporting nonzero initial velo which is essential for the Nesterov algorithm where velocity carries across iterations. -/ -private abbrev bootstrapTotalDisplacementGenProof +private theorem bootstrapTotalDisplacementGenProof {d : ℕ} (f : E d → ℝ) (μ' : ℝ) (hμ' : 0 < μ') @@ -442,21 +417,10 @@ private abbrev bootstrapTotalDisplacementGenProof (1 - (1 - θ) * a) ^ (n + 1) * lyapunovOfState P μ' π f η s₀) := by -- ── Contraction rate and auxiliary constants ──────────────────────────── + obtain ⟨hc_nonneg, hc_le_one, hsqrt_c_lt1⟩ := + contraction_factor_bounds hμ' hη_pos hμη_lt1 hθ_pos hθ_lt1 set a := Real.sqrt (μ' * η) with ha_def set c := 1 - (1 - θ) * a with hc_def - have hμη_pos : 0 < μ' * η := mul_pos hμ' hη_pos - have ha_pos : 0 < a := Real.sqrt_pos_of_pos hμη_pos - have ha_lt1 : a < 1 := by - calc a = Real.sqrt (μ' * η) := rfl - _ < Real.sqrt 1 := Real.sqrt_lt_sqrt (le_of_lt hμη_pos) (by linarith) - _ = 1 := Real.sqrt_one - have hc_pos : (0 : ℝ) < c := by simp only [c]; nlinarith [mul_pos (sub_pos.mpr hθ_lt1) ha_pos] - have hc_lt1 : c < 1 := by simp only [c]; nlinarith [mul_pos (sub_pos.mpr hθ_lt1) ha_pos] - have hc_nonneg : (0 : ℝ) ≤ c := le_of_lt hc_pos - have hc_le_one : c ≤ 1 := le_of_lt hc_lt1 - have hsqrt_c_lt1 : Real.sqrt c < 1 := by - calc Real.sqrt c < Real.sqrt 1 := Real.sqrt_lt_sqrt hc_nonneg (by linarith) - _ = 1 := Real.sqrt_one have h1_sub_sqrt_c_pos : (0 : ℝ) < 1 - Real.sqrt c := by linarith -- ── Step 1: Get r from Ω being open at m⋆ ────────────────────────────── obtain ⟨r, hr_pos, hball_Ω⟩ := Metric.isOpen_iff.mp hΩ_open m_star hm_star_Ω @@ -476,10 +440,6 @@ private abbrev bootstrapTotalDisplacementGenProof lt_of_lt_of_le (Metric.mem_ball.mp hs₀_x) hδ_le_r4 have hs₀_la_dist : dist (s₀.lookahead η) m_star < r / 4 := lt_of_lt_of_le (Metric.mem_ball.mp hs₀_la) hδ_le_r4 - have hs₀_x_Ω : s₀.x ∈ Ω := - hball_Ω (Metric.mem_ball.mpr (by linarith)) - have hs₀_la_Ω : s₀.lookahead η ∈ Ω := - hball_Ω (Metric.mem_ball.mpr (by linarith)) -- L₀ ≤ R² have hL₀_R : lyapunovOfState P μ' π f η s₀ ≤ R ^ 2 := le_trans hL₀_small (by nlinarith [hδ_le_R]) @@ -516,239 +476,19 @@ private abbrev bootstrapTotalDisplacementGenProof calc C_mov * Real.sqrt L₀ ≤ K * Real.sqrt L₀ := mul_le_mul_of_nonneg_right this (Real.sqrt_nonneg _) _ ≤ r / 4 := hKL₀ - -- ── Main induction ───────────────────────────────────────────────────── + -- ── Main induction (abstract displacement argument) ─────────────────── set Ln := fun n => lyapunovOfState P μ' π f η (nesterovSeqGen f η ρ s₀ n) with hLn_def - have hinduction : ∀ n, - ((nesterovSeqGen f η ρ s₀ n).x ∈ Ω ∧ - (nesterovSeqGen f η ρ s₀ n).lookahead η ∈ Ω) ∧ - Ln n ≤ c ^ n * L₀ ∧ - dist ((nesterovSeqGen f η ρ s₀ n).lookahead η) m_star ≤ - dist (s₀.lookahead η) m_star + C_h * Real.sqrt η * Real.sqrt L₀ * - (Finset.range n).sum (fun k => Real.sqrt c ^ k) := by - intro n - induction n with - | zero => - refine ⟨⟨hs₀_x_Ω, hs₀_la_Ω⟩, ?_, ?_⟩ - · -- Ln 0 ≤ c ^ 0 * L₀ - have h1 : Ln 0 = L₀ := rfl - linarith [pow_zero c] - · simp only [nesterovSeqGen, Finset.range_zero, Finset.sum_empty, mul_zero, - add_zero, le_refl] - | succ n ih => - obtain ⟨⟨hxn_Ω, hxn'_Ω⟩, hLn_decay, hDn⟩ := ih - -- Ln ≤ R² - have hLn_R : Ln n ≤ R ^ 2 := by - have hcn : c ^ n ≤ 1 := pow_le_one₀ hc_nonneg hc_le_one - have hcnL₀ : c ^ n * L₀ ≤ L₀ := mul_le_of_le_one_left hL₀_nonneg hcn - linarith - -- Motion bounds at step n - have hh_bound : ‖stepDispOfState f η ρ (nesterovSeqGen f η ρ s₀ n)‖ ≤ - C_h * Real.sqrt η * Real.sqrt (Ln n) := - hstep_bound s₀ n hxn_Ω hxn'_Ω hLn_R - have hv_bound : ‖Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v‖ ≤ - C_mov * Real.sqrt (Ln n) := - hvel_bound s₀ n hxn_Ω hxn'_Ω hLn_R - -- √(c^m) = (√c)^m - have sqrt_pow_c : ∀ m : ℕ, Real.sqrt (c ^ m) = Real.sqrt c ^ m := by - intro m; induction m with - | zero => simp only [pow_zero, Real.sqrt_one] - | succ k ihk => - rw [pow_succ, Real.sqrt_mul (pow_nonneg hc_nonneg k), ihk, pow_succ] - -- √(Ln n) ≤ (√c)^n · √L₀ - have hsqrt_Ln : Real.sqrt (Ln n) ≤ Real.sqrt c ^ n * Real.sqrt L₀ := by - calc Real.sqrt (Ln n) ≤ Real.sqrt (c ^ n * L₀) := - Real.sqrt_le_sqrt hLn_decay - _ = Real.sqrt (c ^ n) * Real.sqrt L₀ := - Real.sqrt_mul (pow_nonneg hc_nonneg n) L₀ - _ = Real.sqrt c ^ n * Real.sqrt L₀ := by rw [sqrt_pow_c] - -- ‖h_n‖ ≤ C_h·√η·√L₀·(√c)^n - have hh_geom : ‖stepDispOfState f η ρ (nesterovSeqGen f η ρ s₀ n)‖ ≤ - C_h * Real.sqrt η * Real.sqrt L₀ * Real.sqrt c ^ n := by - calc ‖stepDispOfState f η ρ (nesterovSeqGen f η ρ s₀ n)‖ - ≤ C_h * Real.sqrt η * Real.sqrt (Ln n) := hh_bound - _ ≤ C_h * Real.sqrt η * (Real.sqrt c ^ n * Real.sqrt L₀) := by - apply mul_le_mul_of_nonneg_left hsqrt_Ln - apply mul_nonneg (le_of_lt hC_h) (Real.sqrt_nonneg _) - _ = C_h * Real.sqrt η * Real.sqrt L₀ * Real.sqrt c ^ n := by ring - -- ── Displacement bound for lookahead at n+1 ──────────────────────── - have hla_step : (nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η = - (nesterovSeqGen f η ρ s₀ n).lookahead η + - stepDispOfState f η ρ (nesterovSeqGen f η ρ s₀ n) := by - simp only [stepDispOfState, nesterovSeqGen]; abel - have hDn1 : dist ((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η) m_star ≤ - dist (s₀.lookahead η) m_star + C_h * Real.sqrt η * Real.sqrt L₀ * - (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) := by - calc dist ((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η) m_star - = dist ((nesterovSeqGen f η ρ s₀ n).lookahead η + - stepDispOfState f η ρ (nesterovSeqGen f η ρ s₀ n)) m_star := by - rw [hla_step] - _ ≤ dist ((nesterovSeqGen f η ρ s₀ n).lookahead η) m_star + - ‖stepDispOfState f η ρ (nesterovSeqGen f η ρ s₀ n)‖ := by - rw [dist_eq_norm, dist_eq_norm] - calc ‖(nesterovSeqGen f η ρ s₀ n).lookahead η + - stepDispOfState f η ρ (nesterovSeqGen f η ρ s₀ n) - m_star‖ - = ‖((nesterovSeqGen f η ρ s₀ n).lookahead η - m_star) + - stepDispOfState f η ρ (nesterovSeqGen f η ρ s₀ n)‖ := by - congr 1; abel - _ ≤ ‖(nesterovSeqGen f η ρ s₀ n).lookahead η - m_star‖ + - ‖stepDispOfState f η ρ (nesterovSeqGen f η ρ s₀ n)‖ := - norm_add_le _ _ - _ ≤ (dist (s₀.lookahead η) m_star + C_h * Real.sqrt η * Real.sqrt L₀ * - (Finset.range n).sum (fun k => Real.sqrt c ^ k)) + - C_h * Real.sqrt η * Real.sqrt L₀ * Real.sqrt c ^ n := by - linarith [hDn, hh_geom] - _ = dist (s₀.lookahead η) m_star + C_h * Real.sqrt η * Real.sqrt L₀ * - (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) := by - rw [Finset.sum_range_succ]; ring - -- dist(x'_{n+1}, m⋆) ≤ r/2 - have hDn1_le_half : dist ((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η) m_star ≤ - r / 2 := by - have hsum_bound : C_h * Real.sqrt η * Real.sqrt L₀ * - (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) ≤ r / 4 := by - have hle := partial_geom_series_bound (Real.sqrt c) - (Real.sqrt_nonneg c) hsqrt_c_lt1 (n + 1) - calc C_h * Real.sqrt η * Real.sqrt L₀ * - (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) - ≤ C_h * Real.sqrt η * Real.sqrt L₀ * (1 / (1 - Real.sqrt c)) := by - apply mul_le_mul_of_nonneg_left hle - apply mul_nonneg (mul_nonneg (le_of_lt hC_h) (Real.sqrt_nonneg _)) - (Real.sqrt_nonneg _) - _ = C_h * Real.sqrt η * Real.sqrt L₀ / (1 - Real.sqrt c) := by ring - _ ≤ r / 4 := hdisp_bound - linarith [hDn1, hs₀_la_dist] - have hDn1_lt_r : dist ((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η) m_star < r := by - linarith - -- ── Velocity bound ───────────────────────────────────────────────── - have hvel_Ln : C_mov * Real.sqrt (Ln n) ≤ r / 4 := by - have hLn_le_L₀ : Ln n ≤ L₀ := by - have := pow_le_one₀ hc_nonneg hc_le_one (n := n) - have := mul_le_of_le_one_left hL₀_nonneg this - linarith - calc C_mov * Real.sqrt (Ln n) - ≤ C_mov * Real.sqrt L₀ := by - apply mul_le_mul_of_nonneg_left (Real.sqrt_le_sqrt hLn_le_L₀) (le_of_lt hC_mov) - _ ≤ r / 4 := hvel_comp - -- ── x_{n+1} ∈ Ω ─────────────────────────────────────────────────── - have hxn1_mem : (nesterovSeqGen f η ρ s₀ (n + 1)).x ∈ Ω := by - apply hball_Ω; rw [Metric.mem_ball] - have hx_eq : (nesterovSeqGen f η ρ s₀ (n + 1)).x = - (nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η - - Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v := by - simp only [NesterovState.lookahead, add_sub_cancel_right] - calc dist (nesterovSeqGen f η ρ s₀ (n + 1)).x m_star - = dist ((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η - - Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v) m_star := by - rw [hx_eq] - _ ≤ dist ((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η) m_star + - ‖Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v‖ := by - rw [dist_eq_norm, dist_eq_norm] - calc ‖(nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η - - Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v - m_star‖ - = ‖((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η - m_star) - - Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v‖ := by - congr 1; abel - _ ≤ ‖(nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η - m_star‖ + - ‖Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v‖ := - norm_sub_le _ _ - _ ≤ dist ((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η) m_star + - C_mov * Real.sqrt (Ln n) := by linarith [hv_bound] - _ ≤ r / 2 + r / 4 := by linarith [hDn1_le_half, hvel_Ln] - _ < r := by linarith - -- ── x'_{n+1} ∈ Ω ────────────────────────────────────────────────── - have hxn1'_mem : (nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η ∈ Ω := - hball_Ω (Metric.mem_ball.mpr hDn1_lt_r) - -- ── Assemble ─────────────────────────────────────────────────────── - refine ⟨⟨hxn1_mem, hxn1'_mem⟩, ?_, hDn1⟩ - -- Lyapunov decay: L_{n+1} ≤ c^{n+1} · L₀ - calc Ln (n + 1) ≤ c * Ln n := hcontract s₀ n hxn_Ω hxn'_Ω hLn_R - _ ≤ c * (c ^ n * L₀) := - mul_le_mul_of_nonneg_left hLn_decay hc_nonneg - _ = c ^ (n + 1) * L₀ := by ring - -- Ball containment follows from the induction: dist(la, m_star) ≤ r/2 and dist(x, m_star) < r - have hball_contain : ∀ n, - (nesterovSeqGen f η ρ s₀ n).x ∈ Metric.ball m_star r ∧ - (nesterovSeqGen f η ρ s₀ n).lookahead η ∈ Metric.ball m_star r := by - intro n - obtain ⟨_, hLn_decay, hDn⟩ := hinduction n - -- lookahead distance bound: dist(la(n), m_star) < r/2 - have hla_dist : dist ((nesterovSeqGen f η ρ s₀ n).lookahead η) m_star < r := by - have hsum_bound : C_h * Real.sqrt η * Real.sqrt L₀ * - (Finset.range n).sum (fun k => Real.sqrt c ^ k) ≤ r / 4 := by - have hle := partial_geom_series_bound (Real.sqrt c) - (Real.sqrt_nonneg c) hsqrt_c_lt1 n - calc C_h * Real.sqrt η * Real.sqrt L₀ * - (Finset.range n).sum (fun k => Real.sqrt c ^ k) - ≤ C_h * Real.sqrt η * Real.sqrt L₀ * (1 / (1 - Real.sqrt c)) := by - apply mul_le_mul_of_nonneg_left hle - apply mul_nonneg (mul_nonneg (le_of_lt hC_h) (Real.sqrt_nonneg _)) - (Real.sqrt_nonneg _) - _ = C_h * Real.sqrt η * Real.sqrt L₀ / (1 - Real.sqrt c) := by ring - _ ≤ r / 4 := hdisp_bound - linarith [hDn, hs₀_la_dist] - refine ⟨?_, Metric.mem_ball.mpr hla_dist⟩ - -- x distance bound: x = lookahead - √η • v, so dist(x, m*) ≤ dist(la, m*) + ‖√η•v‖ - rcases n with _ | n - · have hr4_lt_r := div_lt_self hr_pos (by norm_num : (1 : ℝ) < 4) - exact Metric.mem_ball.mpr (lt_trans hs₀_x_dist hr4_lt_r) - · -- For n+1: we know Ln(n) ≤ L₀, so velocity ≤ C_mov·√L₀ ≤ r/4 - have hLn_le_L₀ : Ln n ≤ L₀ := by - have hcn := pow_le_one₀ hc_nonneg hc_le_one (n := n) - have hLn_bound := (hinduction n).2.1 - nlinarith - -- Need velocity bound at step n+1 from hypothesis at step n - have hn_mem := (hinduction n).1 - have hLn_R : Ln n ≤ R ^ 2 := by - linarith [mul_le_of_le_one_left hL₀_nonneg - (pow_le_one₀ hc_nonneg hc_le_one (n := n))] - have hv_bound_n := hvel_bound s₀ n hn_mem.1 hn_mem.2 hLn_R - have hvel_small : C_mov * Real.sqrt (Ln n) ≤ r / 4 := by - calc C_mov * Real.sqrt (Ln n) - ≤ C_mov * Real.sqrt L₀ := - mul_le_mul_of_nonneg_left (Real.sqrt_le_sqrt hLn_le_L₀) (le_of_lt hC_mov) - _ ≤ r / 4 := hvel_comp - have hx_eq : (nesterovSeqGen f η ρ s₀ (n + 1)).x = - (nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η - - Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v := by - simp only [NesterovState.lookahead, add_sub_cancel_right] - -- la_{n+1} distance bound: ≤ r/2 (tighter than hla_dist) - have hla_n1_half : dist ((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η) m_star ≤ - r / 2 := by - have hDn1 := (hinduction (n + 1)).2.2 - have hsum_bound1 : C_h * Real.sqrt η * Real.sqrt L₀ * - (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) ≤ r / 4 := by - have hle := partial_geom_series_bound (Real.sqrt c) - (Real.sqrt_nonneg c) hsqrt_c_lt1 (n + 1) - calc C_h * Real.sqrt η * Real.sqrt L₀ * - (Finset.range (n + 1)).sum (fun k => Real.sqrt c ^ k) - ≤ C_h * Real.sqrt η * Real.sqrt L₀ * (1 / (1 - Real.sqrt c)) := by - apply mul_le_mul_of_nonneg_left hle - apply mul_nonneg (mul_nonneg (le_of_lt hC_h) (Real.sqrt_nonneg _)) - (Real.sqrt_nonneg _) - _ = C_h * Real.sqrt η * Real.sqrt L₀ / (1 - Real.sqrt c) := by ring - _ ≤ r / 4 := hdisp_bound - linarith [hDn1, hs₀_la_dist] - have hv_bound_small : ‖Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v‖ ≤ r / 4 := by - linarith [hv_bound_n, hvel_small] - rw [Metric.mem_ball] - calc dist (nesterovSeqGen f η ρ s₀ (n + 1)).x m_star - = dist ((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η - - Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v) m_star := by - rw [hx_eq] - _ ≤ dist ((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η) m_star + - ‖Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v‖ := by - rw [dist_eq_norm, dist_eq_norm] - calc ‖(nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η - - Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v - m_star‖ - = ‖((nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η - m_star) - - Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v‖ := by - congr 1; abel - _ ≤ ‖(nesterovSeqGen f η ρ s₀ (n + 1)).lookahead η - m_star‖ + - ‖Real.sqrt η • (nesterovSeqGen f η ρ s₀ (n + 1)).v‖ := - norm_sub_le _ _ - _ ≤ r / 2 + r / 4 := by linarith [hla_n1_half, hv_bound_small] - _ < r := by linarith - refine ⟨fun n => (hinduction n).1, hball_contain, fun n => ?_⟩ - exact (hinduction (n + 1)).2.1 + have hmain := bootstrap_displacement_induction + (fun n => (nesterovSeqGen f η ρ s₀ n).x) (fun n => (nesterovSeqGen f η ρ s₀ n).lookahead η) + (fun n => stepDispOfState f η ρ (nesterovSeqGen f η ρ s₀ n)) + (fun n => Real.sqrt η • (nesterovSeqGen f η ρ s₀ n).v) Ln Ω m_star + r R c (C_h * Real.sqrt η) C_mov (by positivity) hC_mov.le hc_nonneg hc_le_one hsqrt_c_lt1 + hball_Ω (fun n => by simp only [stepDispOfState, nesterovSeqGen]; abel) + (fun n => by simp only [NesterovState.lookahead, add_sub_cancel_right]) + (fun n h₁ h₂ h₃ => hcontract s₀ n h₁ h₂ h₃) (fun n h₁ h₂ h₃ => hstep_bound s₀ n h₁ h₂ h₃) + (fun n h₁ h₂ h₃ => hvel_bound s₀ n h₁ h₂ h₃) hs₀_x_dist hs₀_la_dist + hL₀_R hL₀_nonneg hdisp_bound hvel_comp + exact ⟨fun n => (hmain n).1, fun n => (hmain n).2.1, fun n => (hmain (n + 1)).2.2⟩ /-- Public theorem wrapper for `bootstrapTotalDisplacementProof`. -/ diff --git a/LeanPool/PLAcceleratedNesterovLean/Convergence/GenLocalArgument.lean b/LeanPool/PLAcceleratedNesterovLean/Convergence/GenLocalArgument.lean index 458b011afa..e396fb60d1 100644 --- a/LeanPool/PLAcceleratedNesterovLean/Convergence/GenLocalArgument.lean +++ b/LeanPool/PLAcceleratedNesterovLean/Convergence/GenLocalArgument.lean @@ -46,12 +46,303 @@ open scoped Topology NNReal open Manifold +/-- From `ε ≤ √(μ_minus / η)` deduce `ε * η ≤ √(μ_minus * η)`. -/ +private theorem mul_le_sqrt_mul_of_le_sqrt_div {ε μ_minus η : ℝ} (hε_pos : 0 < ε) + (hμ_minus : 0 < μ_minus) (hη_pos : 0 < η) (hε_le : ε ≤ Real.sqrt (μ_minus / η)) : + ε * η ≤ Real.sqrt (μ_minus * η) := by + have hε_sq : ε ^ 2 ≤ μ_minus / η := + (Real.le_sqrt hε_pos.le (div_pos hμ_minus hη_pos).le).mp hε_le + rw [← Real.sqrt_sq (mul_pos hε_pos hη_pos).le] + apply Real.sqrt_le_sqrt + calc + (ε * η) ^ 2 = ε ^ 2 * η ^ 2 := mul_pow _ _ _ + _ ≤ (μ_minus / η) * η ^ 2 := + mul_le_mul_of_nonneg_right hε_sq (sq_nonneg η) + _ = μ_minus * η := by field_simp + +/-- A linear map satisfying the Pythagorean identity `‖v‖² = ‖P v‖² + ‖v - P v‖²` is +norm-nonincreasing. -/ +private theorem norm_apply_le_of_pythagorean {d : ℕ} {P : E d →L[ℝ] E d} + (hP_ortho : ∀ v : E d, ‖v‖ ^ 2 = ‖P v‖ ^ 2 + ‖v - P v‖ ^ 2) (w : E d) : + ‖P w‖ ≤ ‖w‖ := by + have hPw_sq : ‖P w‖ ^ 2 ≤ ‖w‖ ^ 2 := + (le_add_of_nonneg_right (sq_nonneg ‖w - P w‖)).trans_eq (hP_ortho w).symm + calc ‖P w‖ = Real.sqrt (‖P w‖ ^ 2) := (Real.sqrt_sq (norm_nonneg _)).symm + _ ≤ Real.sqrt (‖w‖ ^ 2) := Real.sqrt_le_sqrt hPw_sq + _ = ‖w‖ := Real.sqrt_sq (norm_nonneg _) + +/-- The derivative of an idempotent map at one of its fixed points is idempotent. -/ +private theorem fderiv_apply_fderiv_of_idempotent {d : ℕ} {π : E d → E d} {mstar : E d} + (h_pipi : ∀ x, π (π x) = π x) (hπm : π mstar = mstar) + (hπ_diff : DifferentiableAt ℝ π mstar) (x : E d) : + fderiv ℝ π mstar (fderiv ℝ π mstar x) = fderiv ℝ π mstar x := by + have h_eq : fderiv ℝ (fun x => π (π x)) mstar = fderiv ℝ π mstar := by + have : (fun x => π (π x)) = π := funext h_pipi + rw [this] + have h_chain : fderiv ℝ (fun x => π (π x)) mstar = + (fderiv ℝ π mstar).comp (fderiv ℝ π mstar) := by + have hπ_diff_at_πm : DifferentiableAt ℝ π (π mstar) := by rwa [hπm] + have := fderiv_comp mstar hπ_diff_at_πm hπ_diff + rwa [hπm] at this + have h_comp_eq : (fderiv ℝ π mstar).comp (fderiv ℝ π mstar) = fderiv ℝ π mstar := by + rw [← h_chain, h_eq] + have := ContinuousLinearMap.ext_iff.mp h_comp_eq x + simp only [ContinuousLinearMap.comp_apply] at this + exact this + +/-- A map agreeing on an open set `U ∋ mstar` with a map that is `C¹` at `mstar` is +differentiable on a ball around `mstar`. -/ +private theorem exists_ball_differentiableAt_of_eqOn {d : ℕ} {π π' : E d → E d} + {U : Set (E d)} {mstar : E d} (hU : IsOpen U) (hmU : mstar ∈ U) + (hC1 : ContDiffAt ℝ 1 π' mstar) (hπ_eq_on_U' : ∀ y ∈ U, π y = π' y) : + ∃ δ_diff > 0, ∀ z ∈ Metric.ball mstar δ_diff, DifferentiableAt ℝ π z := by + have hfda := (contDiffAt_succ_iff_hasFDerivAt (n := 0)).mp (by exact_mod_cast hC1) + obtain ⟨f', ⟨u, hu_nhds, hf'_u⟩, _⟩ := hfda + obtain ⟨δ₁, hδ₁_pos, hδ₁_sub⟩ := Metric.mem_nhds_iff.mp hu_nhds + obtain ⟨δ₂, hδ₂_pos, hδ₂_sub⟩ := Metric.isOpen_iff.mp hU mstar hmU + refine ⟨min δ₁ δ₂, lt_min hδ₁_pos hδ₂_pos, fun z hz => ?_⟩ + have hdz := Metric.mem_ball.mp hz + have hz_u : z ∈ u := hδ₁_sub (lt_of_lt_of_le hdz (min_le_left _ _)) + have hz_U : z ∈ U := + hδ₂_sub (Metric.mem_ball.mpr (lt_of_lt_of_le hdz (min_le_right _ _))) + have hπ'_diff : DifferentiableAt ℝ π' z := (hf'_u z hz_u).differentiableAt + have h_evt_z : π =ᶠ[𝓝 z] π' := + (hU.eventually_mem hz_U).mono (fun y hy => hπ_eq_on_U' y hy) + exact h_evt_z.differentiableAt_iff.mpr hπ'_diff + +/-- Along a segment inside `U_plus`, a lower Hessian bound `-ε` gives the first-order +estimate `⟪∇f x, x - z⟫ ≥ f x - f z - ε / 2 * ‖x - z‖ ^ 2`. -/ +private theorem inner_gradient_ge_of_hessian_lower_on_segment {d : ℕ} + (f : E d → ℝ) (ε : ℝ) {U_plus U : Set (E d)} + (hU_plus_open : IsOpen U_plus) (hU_open : IsOpen U) (hU_sub : closure U_plus ⊆ U) + (hf_C2_on_U : ContDiffOn ℝ 2 f U) + (hHessLow : ∀ x ∈ U_plus, ∀ ξ : E d, hessianQuadForm f x ξ ≥ -ε * ‖ξ‖ ^ 2) + (x z : E d) (hseg : ∀ t : ℝ, 0 ≤ t → t ≤ 1 → (1 - t) • z + t • x ∈ U_plus) : + @inner ℝ _ _ (gradient f x) (x - z) ≥ f x - f z - ε / 2 * ‖x - z‖ ^ 2 := by + have hf_diffOn_Up : DifferentiableOn ℝ f U_plus := + (hf_C2_on_U.differentiableOn (by decide : (2 : WithTop ℕ∞) ≠ 0)).mono + (subset_closure.trans hU_sub) + set ξ := x - z with hξ_def + set φ : ℝ → ℝ := fun t => f (z + t • ξ) with hφ_def + have hφ0 : φ 0 = f z := by simp only [hφ_def, zero_smul, add_zero] + have hφ1 : φ 1 = f x := by + simp only [hφ_def, one_smul, hξ_def]; congr 1; abel + have hpath : ∀ t, HasDerivAt (fun (s : ℝ) => z + s • ξ) ξ t := by + intro t + have h := ((hasDerivAt_id t).smul_const ξ).const_add z + simpa [one_smul] using h + have hseg' : ∀ t : ℝ, 0 ≤ t → t ≤ 1 → z + t • ξ ∈ U_plus := by + intro t ht0 ht1 + have : z + t • ξ = (1 - t) • z + t • x := by + simp only [smul_sub, sub_smul, one_smul, ξ]; abel + rw [this]; exact hseg t ht0 ht1 + have hφ_hd : ∀ t, 0 ≤ t → t ≤ 1 → + HasDerivAt φ (fderiv ℝ f (z + t • ξ) ξ) t := by + intro t ht0 ht1 + have hpt_Up : z + t • ξ ∈ U_plus := hseg' t ht0 ht1 + have hda : DifferentiableAt ℝ f (z + t • ξ) := + hf_diffOn_Up.differentiableAt (hU_plus_open.mem_nhds hpt_Up) + exact hda.hasFDerivAt.comp_hasDerivAt t (hpath t) + have hderiv1 : deriv φ 1 = @inner ℝ _ _ (gradient f x) ξ := by + rw [(hφ_hd 1 zero_le_one le_rfl).deriv] + have hone : z + (1 : ℝ) • ξ = x := by + simp only [one_smul, hξ_def]; abel + rw [hone] + exact (inner_gradient_left (𝕜 := ℝ) (f := f) (x := x) (y := ξ)).symm + have hφ''_eq : ∀ t, 0 ≤ t → t ≤ 1 → + deriv (deriv φ) t = hessianQuadForm f (z + t • ξ) ξ := by + intro t ht0 ht1 + have hpt_Up : z + t • ξ ∈ U_plus := hseg' t ht0 ht1 + have hpt_U : z + t • ξ ∈ U := hU_sub (subset_closure hpt_Up) + have hC2at : ContDiffAt ℝ 2 f (z + t • ξ) := + hf_C2_on_U.contDiffAt (hU_open.mem_nhds hpt_U) + exact fiber_path_second_deriv f z ξ t hC2at + have hφ''_lower : ∀ t, 0 ≤ t → t ≤ 1 → + deriv (deriv φ) t ≥ -ε * ‖ξ‖ ^ 2 := by + intro t ht0 ht1 + rw [hφ''_eq t ht0 ht1] + exact hHessLow (z + t • ξ) (hseg' t ht0 ht1) ξ + have hφ_C2at : ∀ t ∈ Set.Icc (0:ℝ) 1, ContDiffAt ℝ 2 φ t := by + intro t ht + exact fiber_path_C2at_on_segment f z ξ hU_open hf_C2_on_U + (fun s hs => hU_sub (subset_closure (hseg' s hs.1 hs.2))) t ht + have hφ_cont : ContinuousOn φ (Set.Icc 0 1) := + fun t ht => (hφ_C2at t ht).continuousAt.continuousWithinAt + have hφ_diffon : DifferentiableOn ℝ φ (Set.Ioo 0 1) := + fun t ht => ((hφ_C2at t (Set.Ioo_subset_Icc_self ht)).differentiableAt + (by decide : (2 : WithTop ℕ∞) ≠ 0)).differentiableWithinAt + have hφ'_cont : ContinuousOn (deriv φ) (Set.Icc 0 1) := by + intro t ht + have hfda := (hφ_C2at t ht).fderiv_right + (show (1 : WithTop ℕ∞) + 1 ≤ 2 by decide) + have h_eq : deriv φ = fun s => fderiv ℝ φ s 1 := by + ext s; exact fderiv_apply_one_eq_deriv.symm + rw [h_eq] + exact (hfda.continuousAt.clm_apply continuousAt_const).continuousWithinAt + have hφ'_diffon : DifferentiableOn ℝ (deriv φ) (Set.Ioo 0 1) := by + intro t ht + have hfda := (hφ_C2at t (Set.Ioo_subset_Icc_self ht)).fderiv_right + (show (1 : WithTop ℕ∞) + 1 ≤ 2 by decide) + have hfda_diff := hfda.differentiableAt + (show (1 : WithTop ℕ∞) ≠ 0 by decide) + have h_eq : deriv φ = fun s => fderiv ℝ φ s 1 := by + ext s; exact fderiv_apply_one_eq_deriv.symm + rw [h_eq] + exact (hfda_diff.clm_apply (differentiableAt_const _)).differentiableWithinAt + have hest := segment_estimate_from_hessian φ (-ε * ‖ξ‖ ^ 2) + hφ_cont hφ_diffon hφ'_cont hφ'_diffon hφ''_lower + rw [hderiv1, hφ1, hφ0] at hest + linarith + +/-- Per-step motion bounds on `Ω`: coercivity and the gradient Lipschitz bound control +the step displacement and the next velocity by the square root of the Lyapunov value. -/ +private theorem nesterov_step_motion_bounds {d : ℕ} + (f : E d → ℝ) (L : ℝ≥0) (μ_minus : ℝ) (hmu4_pos : 0 < μ_minus) + (η : ℝ) (hη_pos : 0 < η) (ρ C_coer : ℝ) (hC_coer : 0 < C_coer) + (π : E d → E d) (P : E d →L[ℝ] E d) {Ω U : Set (E d)} + (hf_lip : LipschitzOnWith (↑L) (gradient f) U) (hΩ_sub_U : Ω ⊆ U) + (hπ_in_U : ∀ x, π x ∈ U) (hgrad_zero_π : ∀ x, gradient f (π x) = 0) + (hcoer : ∀ s : NesterovState d, s.x ∈ Ω → s.lookahead η ∈ Ω → + ‖s.v‖ ^ 2 + μ_minus * ‖normalDispOfState π η s‖ ^ 2 ≤ + C_coer * lyapunovOfState P μ_minus π f η s) : + ∃ Ch > 0, ∃ Cmov > 0, ∀ s : NesterovState d, s.x ∈ Ω → s.lookahead η ∈ Ω → + ‖stepDispOfState f η ρ s‖ ≤ Ch * Real.sqrt η * + Real.sqrt (lyapunovOfState P μ_minus π f η s) ∧ + ‖Real.sqrt η • (nesterovStep f η ρ s).v‖ ≤ + Cmov * Real.sqrt (lyapunovOfState P μ_minus π f η s) := by + have hη_nn : (0 : ℝ) ≤ η := le_of_lt hη_pos + have hsqrt_η_nn : (0 : ℝ) ≤ Real.sqrt η := Real.sqrt_nonneg η + have hL_nn : (0 : ℝ) ≤ (↑L : ℝ) := L.coe_nonneg + have hC_coer_nn : (0 : ℝ) ≤ C_coer := le_of_lt hC_coer + -- Constants + let K := C_coer / μ_minus + let Ce := Real.sqrt K + let Cg := (↑L : ℝ) * Ce + let Cv := Real.sqrt C_coer + let Cv' := |ρ| * (Cv + Real.sqrt η * Cg) + let Ch := Cv' + Real.sqrt η * Cg + 1 + let Cmov := Real.sqrt η * Cv' + 1 + refine ⟨Ch, by positivity, Cmov, by positivity, ?_⟩ + intro s hsx hslx + set Ln := lyapunovOfState P μ_minus π f η s + set s' := nesterovStep f η ρ s + set gn := gradient f (s.lookahead η) + set en := normalDispOfState π η s + -- Coercivity on Ω + have hcoer_here := hcoer s hsx hslx + -- (1) ‖s.v‖ ≤ Cv * √Ln + have hv_sq : ‖s.v‖ ^ 2 ≤ C_coer * Ln := + (le_add_of_nonneg_right (mul_nonneg hmu4_pos.le (sq_nonneg ‖en‖))).trans hcoer_here + have hv_bound : ‖s.v‖ ≤ Cv * Real.sqrt Ln := by + rw [show Cv = Real.sqrt C_coer from rfl, + ← Real.sqrt_mul hC_coer_nn, + ← Real.sqrt_sq (norm_nonneg s.v)] + exact Real.sqrt_le_sqrt hv_sq + -- (2) ‖en‖ ≤ Ce * √Ln + have he_sq : ‖en‖ ^ 2 ≤ K * Ln := by + calc + ‖en‖ ^ 2 ≤ (C_coer * Ln) / μ_minus := + (le_div_iff₀' hmu4_pos).mpr + ((le_add_of_nonneg_left (sq_nonneg ‖s.v‖)).trans hcoer_here) + _ = K * Ln := (div_mul_eq_mul_div C_coer μ_minus Ln).symm + have he_bound : ‖en‖ ≤ Ce * Real.sqrt Ln := by + have hK_nn : (0 : ℝ) ≤ K := by positivity + rw [show Ce = Real.sqrt K from rfl, + ← Real.sqrt_mul hK_nn, + ← Real.sqrt_sq (norm_nonneg en)] + exact Real.sqrt_le_sqrt he_sq + -- (3) ‖gn‖ ≤ ↑L * ‖en‖ ≤ Cg * √Ln + have hg_raw : ‖gn‖ ≤ (↑L : ℝ) * ‖en‖ := by + change ‖gradient f (s.lookahead η)‖ ≤ + (↑L : ℝ) * ‖s.lookahead η - π (s.lookahead η)‖ + exact gradient_bound_from_lipschitz f L hf_lip _ _ + (hΩ_sub_U hslx) + (hπ_in_U _) + (hgrad_zero_π _) + have hg_bound : ‖gn‖ ≤ Cg * Real.sqrt Ln := by + calc ‖gn‖ ≤ (↑L : ℝ) * ‖en‖ := hg_raw + _ ≤ (↑L : ℝ) * (Ce * Real.sqrt Ln) := by + apply mul_le_mul_of_nonneg_left he_bound hL_nn + _ = Cg * Real.sqrt Ln := by ring + -- (4) s'.v = ρ • (s.v - √η • gn) + have hv'_eq : s'.v = ρ • (s.v - Real.sqrt η • gn) := by + simp only [s', nesterovStep, gn, NesterovState.lookahead] + -- (5) ‖s'.v‖ ≤ Cv' * √Ln + have hv'_bound : ‖s'.v‖ ≤ Cv' * Real.sqrt Ln := by + have hv'_norm : ‖s'.v‖ ≤ |ρ| * (‖s.v‖ + |Real.sqrt η| * ‖gn‖) := by + rw [hv'_eq] + exact velocity_bound_from_step s.v gn ρ (Real.sqrt η) + rw [abs_of_nonneg hsqrt_η_nn] at hv'_norm + calc ‖s'.v‖ + ≤ |ρ| * (‖s.v‖ + Real.sqrt η * ‖gn‖) := hv'_norm + _ ≤ |ρ| * (Cv * Real.sqrt Ln + + Real.sqrt η * (Cg * Real.sqrt Ln)) := by + apply mul_le_mul_of_nonneg_left _ (abs_nonneg ρ) + linarith [hv_bound, hg_bound, + mul_le_mul_of_nonneg_left hg_bound hsqrt_η_nn] + _ = Cv' * Real.sqrt Ln := by ring + -- (6) stepDispOfState decomposition: h = √η • s'.v - η • gn + have hhn_eq : stepDispOfState f η ρ s = + Real.sqrt η • s'.v - η • gn := by + simp only [stepDispOfState, s', nesterovStep, gn, NesterovState.lookahead] + abel + -- (7) Prove both bounds + constructor + · -- Step bound: ‖h‖ ≤ Ch * √η * √Ln + have hstep_raw : ‖stepDispOfState f η ρ s‖ ≤ + |Real.sqrt η| * ‖s'.v‖ + |η| * ‖gn‖ := by + rw [hhn_eq] + exact step_bound s'.v gn (Real.sqrt η) η + rw [abs_of_nonneg hsqrt_η_nn, abs_of_nonneg hη_nn] at hstep_raw + have hsqrt_Ln_nn := Real.sqrt_nonneg Ln + calc ‖stepDispOfState f η ρ s‖ + ≤ Real.sqrt η * ‖s'.v‖ + η * ‖gn‖ := hstep_raw + _ ≤ Real.sqrt η * (Cv' * Real.sqrt Ln) + + η * (Cg * Real.sqrt Ln) := by + linarith [mul_le_mul_of_nonneg_left hv'_bound hsqrt_η_nn, + mul_le_mul_of_nonneg_left hg_bound hη_nn] + _ = (Cv' + Real.sqrt η * Cg) * Real.sqrt η * Real.sqrt Ln := by + have hη_sq := (Real.mul_self_sqrt hη_nn).symm + linear_combination Cg * Real.sqrt Ln * hη_sq + _ ≤ Ch * Real.sqrt η * Real.sqrt Ln := by + have : 0 ≤ 1 * (Real.sqrt η * Real.sqrt Ln) := + mul_nonneg one_pos.le (mul_nonneg hsqrt_η_nn hsqrt_Ln_nn) + change (Cv' + Real.sqrt η * Cg) * Real.sqrt η * Real.sqrt Ln ≤ + (Cv' + Real.sqrt η * Cg + 1) * Real.sqrt η * Real.sqrt Ln + linarith + · -- Velocity bound: ‖√η • s'.v‖ ≤ Cmov * √Ln + have hsqrt_Ln_nn := Real.sqrt_nonneg Ln + calc ‖Real.sqrt η • s'.v‖ + = Real.sqrt η * ‖s'.v‖ := by + rw [norm_smul, Real.norm_eq_abs, abs_of_nonneg hsqrt_η_nn] + _ ≤ Real.sqrt η * (Cv' * Real.sqrt Ln) := by + exact mul_le_mul_of_nonneg_left hv'_bound hsqrt_η_nn + _ = (Real.sqrt η * Cv') * Real.sqrt Ln := by ring + _ ≤ Cmov * Real.sqrt Ln := by + have : 0 ≤ 1 * Real.sqrt Ln := mul_nonneg one_pos.le hsqrt_Ln_nn + change (Real.sqrt η * Cv') * Real.sqrt Ln ≤ + (Real.sqrt η * Cv' + 1) * Real.sqrt Ln + linarith + +/-- If `π` agrees on an open set `U` with a projection `π'` whose derivative kills normal +displacements, then so does the derivative of `π`. -/ +private theorem fderiv_kills_normal_of_eqOn {F : Type*} [NormedAddCommGroup F] + [NormedSpace ℝ F] {S U : Set F} {π π' : F → F} (hU : IsOpen U) (hSU : S ⊆ U) + (hπ_mem : ∀ x ∈ U, π x ∈ S) (hπ_eq : ∀ y ∈ U, π y = π' y) + (hπ'_kills : ∀ x ∈ U, fderiv ℝ π' (π' x) (x - π' x) = 0) {x : F} (hxU : x ∈ U) : + fderiv ℝ π (π x) (x - π x) = 0 := by + have h_evt_eq : π =ᶠ[𝓝 (π x)] π' := + (hU.eventually_mem (hSU (hπ_mem x hxU))).mono fun y hy => hπ_eq y hy + have h := hπ'_kills x hxU + rw [← hπ_eq x hxU] at h + rwa [← h_evt_eq.fderiv_eq] at h + /-- Per-phase gen convergence at a single base point m⋆ ∈ M. Same hypotheses as `local_convergence_at_base_point` but with a gen conclusion: existence of a ball where any initial state s₀ with small Lyapunov value produces iterates staying in Ω with geometric Lyapunov decay. -/ -private abbrev localConvergenceAtBasePointGenProof +private theorem localConvergenceAtBasePointGenProof {d : ℕ} (hd : 0 < d) (L : ℝ≥0) (hL : 0 < (L : ℝ)) (μ : ℝ) (hμ : 0 < μ) (hμ_le_L : μ ≤ ↑L) @@ -169,25 +460,9 @@ private abbrev localConvergenceAtBasePointGenProof intro x y simp only [hP_def, h_fderiv_eq'] exact hπ'_self_adj mstar hmstar x y - have hP_idem : ∀ x : E d, P (P x) = P x := by - have h_pipi : ∀ x, π (π x) = π x := fun x => hπ_fix (π x) (hπ_in_S x) - have hπ_diff : DifferentiableAt ℝ π mstar := - h_evt_eq'.differentiableAt_iff.mpr (hπ'_diff mstar hmstar) - have h_eq : fderiv ℝ (fun x => π (π x)) mstar = fderiv ℝ π mstar := by - have : (fun x => π (π x)) = π := funext h_pipi - rw [this] - have hπm : π mstar = mstar := hπ_fix mstar hmstar - have h_chain : fderiv ℝ (fun x => π (π x)) mstar = - (fderiv ℝ π mstar).comp (fderiv ℝ π mstar) := by - have hπ_diff_at_πm : DifferentiableAt ℝ π (π mstar) := by rwa [hπm] - have := fderiv_comp mstar hπ_diff_at_πm hπ_diff - rwa [hπm] at this - have h_comp_eq : (fderiv ℝ π mstar).comp (fderiv ℝ π mstar) = fderiv ℝ π mstar := by - rw [← h_chain, h_eq] - intro x - have := ContinuousLinearMap.ext_iff.mp h_comp_eq x - simp only [ContinuousLinearMap.comp_apply] at this - exact this + have hP_idem : ∀ x : E d, P (P x) = P x := + fderiv_apply_fderiv_of_idempotent (fun x => hπ_fix (π x) (hπ_in_S x)) + (hπ_fix mstar hmstar) (h_evt_eq'.differentiableAt_iff.mpr (hπ'_diff mstar hmstar)) have hmu4_le_L : μ_minus ≤ ↑L := by linarith have hμη_lt1_pre : μ_minus * η < 1 := by change μ_minus * (1 / ↑L) < 1 @@ -204,45 +479,15 @@ private abbrev localConvergenceAtBasePointGenProof P hP_idem hP_self_adj hP_ortho U_plus hπ_metric_Up hQG -- ── Curvature absorption (gen) ────────────────────────────────── -- Prerequisites - have hε_bound : ε * η ≤ Real.sqrt (μ_minus * η) := by - have hε_sq : ε ^ 2 ≤ μ_minus / η := - (Real.le_sqrt hε_pos.le (div_pos hμ_minus hη_pos).le).mp hε_le - rw [← Real.sqrt_sq (mul_pos hε_pos hη_pos).le] - apply Real.sqrt_le_sqrt - calc - (ε * η) ^ 2 = ε ^ 2 * η ^ 2 := mul_pow _ _ _ - _ ≤ (μ_minus / η) * η ^ 2 := - mul_le_mul_of_nonneg_right hε_sq (sq_nonneg η) - _ = μ_minus * η := by field_simp - have hπ_kills_normal : ∀ x ∈ U_plus, - fderiv ℝ π (π x) (x - π x) = 0 := by - intro x hx - have hxU : x ∈ U := hU_sub (subset_closure hx) - have hπxS : π x ∈ S := (hπ_on_U x hxU).1 - have hπxU : π x ∈ U := hTub_sub.subset hπxS - have h_evt_eq : π =ᶠ[𝓝 (π x)] π' := - (hTub_sub.isOpen.eventually_mem hπxU).mono - (fun y hy => hπ_eq_on_U' y hy) - have h := hπ'_kills x hxU - rw [← hπ_eq_on_U' x hxU] at h - rwa [← h_evt_eq.fderiv_eq] at h + have hε_bound : ε * η ≤ Real.sqrt (μ_minus * η) := + mul_le_sqrt_mul_of_le_sqrt_div hε_pos hμ_minus hη_pos hε_le + have hπ_kills_normal : ∀ x ∈ U_plus, fderiv ℝ π (π x) (x - π x) = 0 := fun x hx => + fderiv_kills_normal_of_eqOn hTub_sub.isOpen hTub_sub.subset + (fun y hy => (hπ_on_U y hy).1) hπ_eq_on_U' hπ'_kills (hU_sub (subset_closure hx)) have hπ_diff_near : ∃ δ_diff > 0, - ∀ z ∈ Metric.ball mstar δ_diff, DifferentiableAt ℝ π z := by - have hfda := (contDiffAt_succ_iff_hasFDerivAt (n := 0)).mp - (by exact_mod_cast hπ'_C1 mstar hmstar) - obtain ⟨f', ⟨u, hu_nhds, hf'_u⟩, _⟩ := hfda - obtain ⟨δ₁, hδ₁_pos, hδ₁_sub⟩ := Metric.mem_nhds_iff.mp hu_nhds - obtain ⟨δ₂, hδ₂_pos, hδ₂_sub⟩ := - Metric.isOpen_iff.mp hTub_sub.isOpen mstar (hTub_sub.subset hmstar) - refine ⟨min δ₁ δ₂, lt_min hδ₁_pos hδ₂_pos, fun z hz => ?_⟩ - have hdz := Metric.mem_ball.mp hz - have hz_u : z ∈ u := hδ₁_sub (lt_of_lt_of_le hdz (min_le_left _ _)) - have hz_U : z ∈ U := - hδ₂_sub (Metric.mem_ball.mpr (lt_of_lt_of_le hdz (min_le_right _ _))) - have hπ'_diff : DifferentiableAt ℝ π' z := (hf'_u z hz_u).differentiableAt - have h_evt_z : π =ᶠ[𝓝 z] π' := - (hTub_sub.isOpen.eventually_mem hz_U).mono (fun y hy => hπ_eq_on_U' y hy) - exact h_evt_z.differentiableAt_iff.mpr hπ'_diff + ∀ z ∈ Metric.ball mstar δ_diff, DifferentiableAt ℝ π z := + exists_ball_differentiableAt_of_eqOn hTub_sub.isOpen (hTub_sub.subset hmstar) + (hπ'_C1 mstar hmstar) hπ_eq_on_U' -- Apply curv_absorb_assembly_gen obtain ⟨R_abs, hR_abs_pos, h_curv_absorb_hyp⟩ := curv_absorb_assembly_gen f L hL μ_minus hμ_minus θ hθ η ρ hη_pos hμη_lt1_pre rfl @@ -257,79 +502,9 @@ private abbrev localConvergenceAtBasePointGenProof have hSegment_hyp : ∀ x z : E d, x ∈ U_plus → z ∈ U_plus → (∀ t : ℝ, 0 ≤ t → t ≤ 1 → (1 - t) • z + t • x ∈ U_plus) → @inner ℝ _ _ (gradient f x) (x - z) ≥ - f x - f z - ε / 2 * ‖x - z‖ ^ 2 := by - intro x z hxU hzU hseg - set ξ := x - z with hξ_def - set φ : ℝ → ℝ := fun t => f (z + t • ξ) with hφ_def - have hφ0 : φ 0 = f z := by simp only [hφ_def, zero_smul, add_zero] - have hφ1 : φ 1 = f x := by - simp only [hφ_def, one_smul, hξ_def]; congr 1; abel - have hpath : ∀ t, HasDerivAt (fun (s : ℝ) => z + s • ξ) ξ t := by - intro t - have h := ((hasDerivAt_id t).smul_const ξ).const_add z - simpa [one_smul] using h - have hseg' : ∀ t : ℝ, 0 ≤ t → t ≤ 1 → z + t • ξ ∈ U_plus := by - intro t ht0 ht1 - have : z + t • ξ = (1 - t) • z + t • x := by - simp only [smul_sub, sub_smul, one_smul, ξ]; abel - rw [this]; exact hseg t ht0 ht1 - have hφ_hd : ∀ t, 0 ≤ t → t ≤ 1 → - HasDerivAt φ (fderiv ℝ f (z + t • ξ) ξ) t := by - intro t ht0 ht1 - have hpt_Up : z + t • ξ ∈ U_plus := hseg' t ht0 ht1 - have hda : DifferentiableAt ℝ f (z + t • ξ) := - hf_diffOn_Up.differentiableAt (hU_open.mem_nhds hpt_Up) - exact hda.hasFDerivAt.comp_hasDerivAt t (hpath t) - have hderiv1 : deriv φ 1 = @inner ℝ _ _ (gradient f x) ξ := by - rw [(hφ_hd 1 zero_le_one le_rfl).deriv] - have hone : z + (1 : ℝ) • ξ = x := by - simp only [one_smul, hξ_def]; abel - rw [hone] - exact (inner_gradient_left (𝕜 := ℝ) (f := f) (x := x) (y := ξ)).symm - have hφ''_eq : ∀ t, 0 ≤ t → t ≤ 1 → - deriv (deriv φ) t = hessianQuadForm f (z + t • ξ) ξ := by - intro t ht0 ht1 - have hpt_Up : z + t • ξ ∈ U_plus := hseg' t ht0 ht1 - have hpt_U : z + t • ξ ∈ U := hU_sub (subset_closure hpt_Up) - have hC2at : ContDiffAt ℝ 2 f (z + t • ξ) := - hf_C2_on_U.contDiffAt (hTub_sub.isOpen.mem_nhds hpt_U) - exact fiber_path_second_deriv f z ξ t hC2at - have hφ''_lower : ∀ t, 0 ≤ t → t ≤ 1 → - deriv (deriv φ) t ≥ -ε * ‖ξ‖ ^ 2 := by - intro t ht0 ht1 - rw [hφ''_eq t ht0 ht1] - exact hHessLow (z + t • ξ) (hseg' t ht0 ht1) ξ - have hφ_C2at : ∀ t ∈ Set.Icc (0:ℝ) 1, ContDiffAt ℝ 2 φ t := by - intro t ht - exact fiber_path_C2at_on_segment f z ξ hTub_sub.isOpen hf_C2_on_U - (fun s hs => hU_sub (subset_closure (hseg' s hs.1 hs.2))) t ht - have hφ_cont : ContinuousOn φ (Set.Icc 0 1) := - fun t ht => (hφ_C2at t ht).continuousAt.continuousWithinAt - have hφ_diffon : DifferentiableOn ℝ φ (Set.Ioo 0 1) := - fun t ht => ((hφ_C2at t (Set.Ioo_subset_Icc_self ht)).differentiableAt - (by decide : (2 : WithTop ℕ∞) ≠ 0)).differentiableWithinAt - have hφ'_cont : ContinuousOn (deriv φ) (Set.Icc 0 1) := by - intro t ht - have hfda := (hφ_C2at t ht).fderiv_right - (show (1 : WithTop ℕ∞) + 1 ≤ 2 by decide) - have h_eq : deriv φ = fun s => fderiv ℝ φ s 1 := by - ext s; exact fderiv_apply_one_eq_deriv.symm - rw [h_eq] - exact (hfda.continuousAt.clm_apply continuousAt_const).continuousWithinAt - have hφ'_diffon : DifferentiableOn ℝ (deriv φ) (Set.Ioo 0 1) := by - intro t ht - have hfda := (hφ_C2at t (Set.Ioo_subset_Icc_self ht)).fderiv_right - (show (1 : WithTop ℕ∞) + 1 ≤ 2 by decide) - have hfda_diff := hfda.differentiableAt - (show (1 : WithTop ℕ∞) ≠ 0 by decide) - have h_eq : deriv φ = fun s => fderiv ℝ φ s 1 := by - ext s; exact fderiv_apply_one_eq_deriv.symm - rw [h_eq] - exact (hfda_diff.clm_apply (differentiableAt_const _)).differentiableWithinAt - have hest := segment_estimate_from_hessian φ (-ε * ‖ξ‖ ^ 2) - hφ_cont hφ_diffon hφ'_cont hφ'_diffon hφ''_lower - rw [hderiv1, hφ1, hφ0] at hest - linarith + f x - f z - ε / 2 * ‖x - z‖ ^ 2 := fun x z _ _ hseg => + inner_gradient_ge_of_hessian_lower_on_segment f ε hU_open hTub_sub.isOpen hU_sub + hf_C2_on_U hHessLow x z hseg -- ── lyapunov_contraction_gen ─────────────────────────────────── obtain ⟨Ω, _Ω_plus, R, hΩ_open, _, hR_pos, hm_in_Ω, hΩ_sub_Ωp, hΩp_sub_Up, hLC⟩ := @@ -367,131 +542,11 @@ private abbrev localConvergenceAtBasePointGenProof let Ln := lyapunovOfState P μ_minus π f η s s.x ∈ Ω → s.lookahead η ∈ Ω → Ln ≤ R ^ 2 → ‖Real.sqrt η • s'.v‖ ≤ C_mov * Real.sqrt Ln := by - -- Setup - have hη_pos_local : 0 < η := one_div_pos.mpr hL - have hη_nn : (0 : ℝ) ≤ η := le_of_lt hη_pos_local - have hsqrt_η_nn : (0 : ℝ) ≤ Real.sqrt η := Real.sqrt_nonneg η - have hL_nn : (0 : ℝ) ≤ (↑L : ℝ) := le_of_lt hL - have hC_coer_nn : (0 : ℝ) ≤ C_coer := le_of_lt hC_coer - have hmu4_pos : (0 : ℝ) < μ_minus := by linarith - -- Constants - let K := C_coer / μ_minus - let Ce := Real.sqrt K - let Cg := (↑L : ℝ) * Ce - let Cv := Real.sqrt C_coer - let Cv' := |ρ| * (Cv + Real.sqrt η * Cg) - let Ch := Cv' + Real.sqrt η * Cg + 1 - let Cmov := Real.sqrt η * Cv' + 1 - -- State-based bounds helper - have hbounds : ∀ (s : NesterovState d), - s.x ∈ Ω → - s.lookahead η ∈ Ω → - ‖stepDispOfState f η ρ s‖ ≤ Ch * Real.sqrt η * - Real.sqrt (lyapunovOfState P μ_minus π f η s) ∧ - ‖Real.sqrt η • (nesterovStep f η ρ s).v‖ ≤ - Cmov * Real.sqrt (lyapunovOfState P μ_minus π f η s) := by - intro s hsx hslx - set Ln := lyapunovOfState P μ_minus π f η s - set s' := nesterovStep f η ρ s - set gn := gradient f (s.lookahead η) - set en := normalDispOfState π η s - -- Coercivity (via Ω ⊆ U_plus) - have hcoer_here := (hcoer_bound s (hΩ_sub_Up hsx) (hΩ_sub_Up hslx)).1 - -- (1) ‖s.v‖ ≤ Cv * √Ln - have hv_sq : ‖s.v‖ ^ 2 ≤ C_coer * Ln := - (le_add_of_nonneg_right (mul_nonneg hmu4_pos.le (sq_nonneg ‖en‖))).trans hcoer_here - have hv_bound : ‖s.v‖ ≤ Cv * Real.sqrt Ln := by - rw [show Cv = Real.sqrt C_coer from rfl, - ← Real.sqrt_mul hC_coer_nn, - ← Real.sqrt_sq (norm_nonneg s.v)] - exact Real.sqrt_le_sqrt hv_sq - -- (2) ‖en‖ ≤ Ce * √Ln - have he_sq : ‖en‖ ^ 2 ≤ K * Ln := by - calc - ‖en‖ ^ 2 ≤ (C_coer * Ln) / μ_minus := - (le_div_iff₀' hmu4_pos).mpr - ((le_add_of_nonneg_left (sq_nonneg ‖s.v‖)).trans hcoer_here) - _ = K * Ln := (div_mul_eq_mul_div C_coer μ_minus Ln).symm - have he_bound : ‖en‖ ≤ Ce * Real.sqrt Ln := by - have hK_nn : (0 : ℝ) ≤ K := by positivity - rw [show Ce = Real.sqrt K from rfl, - ← Real.sqrt_mul hK_nn, - ← Real.sqrt_sq (norm_nonneg en)] - exact Real.sqrt_le_sqrt he_sq - -- (3) ‖gn‖ ≤ ↑L * ‖en‖ ≤ Cg * √Ln - have hg_raw : ‖gn‖ ≤ (↑L : ℝ) * ‖en‖ := by - change ‖gradient f (s.lookahead η)‖ ≤ - (↑L : ℝ) * ‖s.lookahead η - π (s.lookahead η)‖ - exact gradient_bound_from_lipschitz f L hf_lip _ _ - (hΩ_sub_U hslx) - (hTub_sub.subset (hπ_in_S _)) - (hgrad_zero _ (hπ_in_S _)) - have hg_bound : ‖gn‖ ≤ Cg * Real.sqrt Ln := by - calc ‖gn‖ ≤ (↑L : ℝ) * ‖en‖ := hg_raw - _ ≤ (↑L : ℝ) * (Ce * Real.sqrt Ln) := by - apply mul_le_mul_of_nonneg_left he_bound hL_nn - _ = Cg * Real.sqrt Ln := by ring - -- (4) s'.v = ρ • (s.v - √η • gn) - have hv'_eq : s'.v = ρ • (s.v - Real.sqrt η • gn) := by - simp only [s', nesterovStep, gn, NesterovState.lookahead] - -- (5) ‖s'.v‖ ≤ Cv' * √Ln - have hv'_bound : ‖s'.v‖ ≤ Cv' * Real.sqrt Ln := by - have hv'_norm : ‖s'.v‖ ≤ |ρ| * (‖s.v‖ + |Real.sqrt η| * ‖gn‖) := by - rw [hv'_eq] - exact velocity_bound_from_step s.v gn ρ (Real.sqrt η) - rw [abs_of_nonneg hsqrt_η_nn] at hv'_norm - calc ‖s'.v‖ - ≤ |ρ| * (‖s.v‖ + Real.sqrt η * ‖gn‖) := hv'_norm - _ ≤ |ρ| * (Cv * Real.sqrt Ln + - Real.sqrt η * (Cg * Real.sqrt Ln)) := by - apply mul_le_mul_of_nonneg_left _ (abs_nonneg ρ) - linarith [hv_bound, hg_bound, - mul_le_mul_of_nonneg_left hg_bound hsqrt_η_nn] - _ = Cv' * Real.sqrt Ln := by ring - -- (6) stepDispOfState decomposition: h = √η • s'.v - η • gn - have hhn_eq : stepDispOfState f η ρ s = - Real.sqrt η • s'.v - η • gn := by - simp only [stepDispOfState, s', nesterovStep, gn, NesterovState.lookahead] - abel - -- (7) Prove both bounds - constructor - · -- Step bound: ‖h‖ ≤ Ch * √η * √Ln - have hstep_raw : ‖stepDispOfState f η ρ s‖ ≤ - |Real.sqrt η| * ‖s'.v‖ + |η| * ‖gn‖ := by - rw [hhn_eq] - exact step_bound s'.v gn (Real.sqrt η) η - rw [abs_of_nonneg hsqrt_η_nn, abs_of_nonneg hη_nn] at hstep_raw - have hsqrt_Ln_nn := Real.sqrt_nonneg Ln - calc ‖stepDispOfState f η ρ s‖ - ≤ Real.sqrt η * ‖s'.v‖ + η * ‖gn‖ := hstep_raw - _ ≤ Real.sqrt η * (Cv' * Real.sqrt Ln) + - η * (Cg * Real.sqrt Ln) := by - linarith [mul_le_mul_of_nonneg_left hv'_bound hsqrt_η_nn, - mul_le_mul_of_nonneg_left hg_bound hη_nn] - _ = (Cv' + Real.sqrt η * Cg) * Real.sqrt η * Real.sqrt Ln := by - have hη_sq := (Real.mul_self_sqrt hη_nn).symm - linear_combination Cg * Real.sqrt Ln * hη_sq - _ ≤ Ch * Real.sqrt η * Real.sqrt Ln := by - have : 0 ≤ 1 * (Real.sqrt η * Real.sqrt Ln) := - mul_nonneg one_pos.le (mul_nonneg hsqrt_η_nn hsqrt_Ln_nn) - change (Cv' + Real.sqrt η * Cg) * Real.sqrt η * Real.sqrt Ln ≤ - (Cv' + Real.sqrt η * Cg + 1) * Real.sqrt η * Real.sqrt Ln - linarith - · -- Velocity bound: ‖√η • s'.v‖ ≤ Cmov * √Ln - have hsqrt_Ln_nn := Real.sqrt_nonneg Ln - calc ‖Real.sqrt η • s'.v‖ - = Real.sqrt η * ‖s'.v‖ := by - rw [norm_smul, Real.norm_eq_abs, abs_of_nonneg hsqrt_η_nn] - _ ≤ Real.sqrt η * (Cv' * Real.sqrt Ln) := by - exact mul_le_mul_of_nonneg_left hv'_bound hsqrt_η_nn - _ = (Real.sqrt η * Cv') * Real.sqrt Ln := by ring - _ ≤ Cmov * Real.sqrt Ln := by - have : 0 ≤ 1 * Real.sqrt Ln := mul_nonneg one_pos.le hsqrt_Ln_nn - change (Real.sqrt η * Cv') * Real.sqrt Ln ≤ - (Real.sqrt η * Cv' + 1) * Real.sqrt Ln - linarith - -- Provide existential witnesses - refine ⟨Ch, by positivity, ?_, Cmov, by positivity, ?_⟩ + obtain ⟨Ch, hCh, Cmov, hCmov, hbounds⟩ := + nesterov_step_motion_bounds f L μ_minus hμ' η hη_pos ρ C_coer hC_coer π P hf_lip + hΩ_sub_U (fun x => hTub_sub.subset (hπ_in_S x)) (fun x => hgrad_zero _ (hπ_in_S x)) + (fun s h1 h2 => (hcoer_bound s (hΩ_sub_Up h1) (hΩ_sub_Up h2)).1) + refine ⟨Ch, hCh, ?_, Cmov, hCmov, ?_⟩ · intro s₀ n_step _s _Ln hsx hslx _hLn_le exact (hbounds (nesterovSeqGen f η ρ s₀ n_step) hsx hslx).1 · intro s₀ n_step _s _s' _Ln hsx hslx _hLn_le @@ -508,13 +563,7 @@ private abbrev localConvergenceAtBasePointGenProof hcontract C_h hC_h hstep_bound C_mov hC_mov hvel_bound -- ── Assemble the local result ── -- Derive ‖Pv‖ ≤ ‖v‖ from the Pythagorean identity - have hP_norm : ∀ w : E d, ‖P w‖ ≤ ‖w‖ := by - intro w - have hPw_sq : ‖P w‖ ^ 2 ≤ ‖w‖ ^ 2 := - (le_add_of_nonneg_right (sq_nonneg ‖w - P w‖)).trans_eq (hP_ortho w).symm - calc ‖P w‖ = Real.sqrt (‖P w‖ ^ 2) := (Real.sqrt_sq (norm_nonneg _)).symm - _ ≤ Real.sqrt (‖w‖ ^ 2) := Real.sqrt_le_sqrt hPw_sq - _ = ‖w‖ := Real.sqrt_sq (norm_nonneg _) + have hP_norm : ∀ w : E d, ‖P w‖ ≤ ‖w‖ := norm_apply_le_of_pythagorean hP_ortho refine ⟨Ω, δ_boot, r_ball, C_coer, hΩ_open, hm_in_Ω, hΩ_sub_U, hδ_boot, hr_ball, hC_coer, hball_Ω, hP_idem, hP_norm, hμη_lt1_pre, ?_, ?_⟩ · -- Coercivity on Ω diff --git a/LeanPool/PLAcceleratedNesterovLean/Convergence/LocalGeometry/Main.lean b/LeanPool/PLAcceleratedNesterovLean/Convergence/LocalGeometry/Main.lean index 90ed3b4a9b..5633de7b58 100644 --- a/LeanPool/PLAcceleratedNesterovLean/Convergence/LocalGeometry/Main.lean +++ b/LeanPool/PLAcceleratedNesterovLean/Convergence/LocalGeometry/Main.lean @@ -45,7 +45,7 @@ Given f C² on an open set V containing the segment {m + t·e | t ∈ ℝ}, the fiber path φ(t) = f(m + t·e) satisfies φ''(t) ≥ μ' * ‖e‖² for t ∈ [0,1], where e = x − π(x) is a normal direction. This is used for both quadratic growth and strong aiming. -/ -private abbrev fiber_path_hessian_lower_bound +private theorem fiber_path_hessian_lower_bound {d : ℕ} (f : E d → ℝ) (μ' : ℝ) (m e : E d) {V : Set (E d)} (hV : IsOpen V) (hf_C2 : ContDiffOn ℝ 2 f V) @@ -59,6 +59,456 @@ private abbrev fiber_path_hessian_lower_bound hf_C2.contDiffAt (hV.mem_nhds (hseg t ⟨ht0, ht1⟩)) rw [fiber_path_second_deriv f m e t hf_at] exact hbound t ht0 ht1 +/-- Two nearest-point projections onto `S` agree on a tubular neighborhood `U`, +by uniqueness of the nearest point. -/ +private theorem projection_eq_of_isTubular {d : ℕ} {S U : Set (E d)} + (hTub_sub : IsTubularNeighborhoodOfSubmanifold S U) {π π' : E d → E d} + (hπ_proj : ∀ x ∈ U, π x ∈ S ∧ dist x (π x) = Metric.infDist x S) + (hπ'_proj : ∀ x ∈ U, π' x ∈ S ∧ ‖x - π' x‖ = Metric.infDist x S) : + ∀ x ∈ U, π x = π' x := by + intro x hxU + obtain ⟨p, hp, huniq⟩ := hTub_sub.uniqueProj x hxU + exact (huniq (π x) (hπ_proj x hxU)).trans + (huniq (π' x) ⟨(hπ'_proj x hxU).1, + by rw [dist_eq_norm]; exact (hπ'_proj x hxU).2⟩).symm + +/-- If `S` is locally a graph over `T` at `m` and `π'` is a map fixing `S` that is +differentiable at `m`, then `Dπ'(m)` fixes every tangent vector `w ∈ T`: differentiate +`π' ∘ γ = γ` along the curve `γ(t) = m + t w + ψ(t w)` in `S`. -/ +private theorem fderiv_apply_eq_self_of_mem_tangent {d : ℕ} {S : Set (E d)} {m : E d} + {T : Submodule ℝ (E d)} (hsub : IsLocalSubmanifoldAt S m T) + {π' : E d → E d} (hπ'_fix : ∀ x ∈ S, π' x = x) (hπ_diff_m : DifferentiableAt ℝ π' m) + {w : E d} (hw : w ∈ T) : + fderiv ℝ π' m w = w := by + obtain ⟨U_chart, hU_chart_nhds, ψ, hψ_C1, hψ0, hDψ0, hgraph⟩ := hsub.2 + set w_T : ↥T := ⟨w, hw⟩ + set γ : ℝ → E d := + fun t => m + t • w + (↑(ψ (t • w_T)) : E d) + -- HasDerivAt γ w 0 + have hψ_diff : DifferentiableAt ℝ ψ 0 := + hψ_C1.differentiableAt (by norm_num : (1 : WithTop ℕ∞) ≠ 0) + have hβ : HasDerivAt (fun t : ℝ => t • w_T) w_T 0 := by + simpa using (hasDerivAt_id (0 : ℝ)).smul_const w_T + have hψβ : HasDerivAt (fun t : ℝ => ψ (t • w_T)) 0 0 := by + have h := hψ_diff.hasFDerivAt.comp_hasDerivAt_of_eq 0 hβ (zero_smul ℝ w_T).symm + rwa [hDψ0, zero_apply] at h + have hγ_deriv : HasDerivAt γ w 0 := by + have h1 : HasDerivAt (fun t : ℝ => m + t • w) w 0 := by + simpa using ((hasDerivAt_id (0 : ℝ)).smul_const w).const_add m + have h2 : HasDerivAt + (fun t : ℝ => (↑(ψ (t • w_T)) : E d)) (0 : E d) 0 := by + have h := (ContinuousLinearMap.hasFDerivAt + T.orthogonal.subtypeL).comp_hasDerivAt (0 : ℝ) hψβ + simp only [map_zero] at h + exact h + have h3 := h1.add h2 + rwa [add_zero] at h3 + -- γ(t) ∈ S for small t + have hγ0 : γ 0 = m := by + change m + (0 : ℝ) • w + (↑(ψ ((0 : ℝ) • w_T)) : E d) = m + rw [zero_smul, zero_smul, hψ0]; simp only [add_zero, ZeroMemClass.coe_zero] + have hγ_cont := hγ_deriv.continuousAt + have hpre : ∀ᶠ t in 𝓝 (0 : ℝ), γ t ∈ U_chart := by + exact hγ_cont.preimage_mem_nhds (by rw [hγ0]; exact hU_chart_nhds) + have hγ_in_S : ∀ᶠ t in 𝓝 (0 : ℝ), γ t ∈ S := by + filter_upwards [hpre] with t ht + have hgr := (hgraph (γ t) ht).mpr + apply hgr + -- γ(t) - m = t•(w_T : E d) + ↑(ψ(t•w_T)) + have hγ_sub : γ t - m = t • (w_T : E d) + (↑(ψ (t • w_T)) : E d) := by + simp only [γ]; abel + have hψ_proj : T.orthogonalProjectionOnto (ψ (t • w_T) : E d) = 0 := + Submodule.orthogonalProjectionOnto_eq_zero_iff.mpr (ψ (t • w_T)).property + have hw_perp_proj : Tᗮ.orthogonalProjectionOnto (w_T : E d) = 0 := + Submodule.orthogonalProjectionOnto_eq_zero_iff.mpr + (Submodule.le_orthogonal_orthogonal T w_T.property) + rw [hγ_sub, map_add, map_smul, map_add, map_smul] + rw [Submodule.orthogonalProjectionOnto_mem_subspace_eq_self w_T, + hψ_proj, + add_zero, + hw_perp_proj, + smul_zero, zero_add, + Submodule.orthogonalProjectionOnto_mem_subspace_eq_self (ψ (t • w_T))] + -- Differentiate π' ∘ γ = γ to get fderiv ℝ π' m w = w + have hπγ_eq : (π' ∘ γ) =ᶠ[𝓝 (0 : ℝ)] γ := by + filter_upwards [hγ_in_S] with t ht + exact hπ'_fix (γ t) ht + have hπγ_deriv1 : HasDerivAt (π' ∘ γ) w 0 := + hπγ_eq.hasDerivAt_iff.mpr hγ_deriv + have hπγ_deriv2 : HasDerivAt (π' ∘ γ) ((fderiv ℝ π' m) w) 0 := + hπ_diff_m.hasFDerivAt.comp_hasDerivAt_of_eq (0 : ℝ) hγ_deriv hγ0.symm + exact hπγ_deriv2.unique hπγ_deriv1 + +/-- PL ⟹ Morse–Bott: at a minimizer `m ∈ S`, the Hessian quadratic form is at least +`μ‖ξ‖²` on normal directions `ξ ∈ ker Dπ(m)`. The Hessian kernel is the tangent space +of `S` (fixed by the self-adjoint `Dπ(m)`), so `ξ ⊥ ker H`, and the PL Rayleigh-quotient +bound (Rebjock & Boumal, Cor 2.17) applies. -/ +private theorem normal_hessian_bound_at_minimizer {d : ℕ} (f : E d → ℝ) (μ : ℝ) + (hμ : 0 < μ) {S U : Set (E d)} (hM_argmin : S = argminSet f) + (hTub_sub : IsTubularNeighborhoodOfSubmanifold S U) + (hPL : PolyakLojasiewicz f μ U) (hf_C2 : ContDiffOn ℝ 2 f U) {π : E d → E d} + (hπ_proj : ∀ x ∈ U, π x ∈ S ∧ dist x (π x) = Metric.infDist x S) + {m : E d} (hmS : m ∈ S) {ξ : E d} (hξ_normal : fderiv ℝ π m ξ = 0) : + hessianQuadForm f m ξ ≥ μ * ‖ξ‖ ^ 2 := by + have hmin : ∀ y, f m ≤ f y := by rw [hM_argmin] at hmS; exact hmS + have hmin_local : IsLocalMin f m := Filter.Eventually.of_forall hmin + have hmU : m ∈ U := hTub_sub.subset hmS + have hf_C2_at_m : ContDiffAt ℝ 2 f m := + hf_C2.contDiffAt (hTub_sub.isOpen.mem_nhds hmU) + have hPL_ext : ExternalThm3.PolyakLojasiewicz f μ U := + ⟨hμ, fun x hxU => by + have := hPL.2.2 x hxU + rw [norm_mathlibGradient_eq_norm_fderiv] at this + exact this⟩ + -- Canonical projection π' (differentiable, self-adjoint derivative) agreeing with π + obtain ⟨π', hπ'_proj, hπ'_fix, _, _, _, _, _, hπ'_diff, hπ'_sa, _⟩ := + tubular_neighborhood_projection_Ed hTub_sub ⟨m, hmS⟩ + have hπ_ev : π =ᶠ[𝓝 m] π' := + Filter.eventually_of_mem (hTub_sub.isOpen.mem_nhds hmU) + (projection_eq_of_isTubular hTub_sub hπ_proj hπ'_proj) + have hfderiv_eq : fderiv ℝ π m = fderiv ℝ π' m := hπ_ev.fderiv_eq + -- PL → MuPL → S = localMinSet f m is a submanifold with tangent space ker H + have hMuPL : MuPL f μ m := + ExternalThm3.pl_to_muPL f μ U m + (by rw [hM_argmin] at hmS; exact hmS) + (hTub_sub.isOpen.mem_nhds hmU) hPL_ext + have hsub' : IsLocalSubmanifoldAt (localMinSet f m) m (hessianKer f m) := + MuPL.implies_submanifold f μ m hμ hf_C2_at_m hmin_local hMuPL + have hS_eq : S = localMinSet f m := by + ext x; constructor + · intro hxS; rw [hM_argmin] at hxS + exact ⟨Filter.Eventually.of_forall hxS, le_antisymm (hxS m) (hmin x)⟩ + · intro ⟨_, hfx⟩; rw [hM_argmin] + intro z; linarith [hmin z] + rw [← hS_eq] at hsub' + -- ξ ⊥ ker H: ⟪w, ξ⟫ = ⟪Dπ'(m) w, ξ⟫ = ⟪w, Dπ(m) ξ⟫ = 0 + have hξ_hess_orth : ξ ∈ (hessianKer f m).orthogonal := by + rw [(hessianKer f m).mem_orthogonal] + intro w hw + have hPw : fderiv ℝ π' m w = w := + fderiv_apply_eq_self_of_mem_tangent hsub' hπ'_fix (hπ'_diff m hmS) hw + rw [← hPw, hπ'_sa m hmS w ξ, ← hfderiv_eq, hξ_normal, inner_zero_right] + have hm_ext : m ∈ ExternalThm3.argminSet f := by + rw [hM_argmin] at hmS + exact hmS + have hbound := ExternalThm3.hessianQuadForm_bound f μ U m ξ + hf_C2_at_m hPL_ext hm_ext (hTub_sub.isOpen.mem_nhds hmU) hξ_hess_orth + have hgrad_fun : ExternalThm3.gradient f = gradient f := by + funext x + exact externalThm3_gradient_eq_gradient f x + simpa [ExternalThm3.hessianQuadForm, hessianQuadForm, hgrad_fun] using hbound + +/-- The Hessian quadratic form `(x, ξ) ↦ ξᵀ D²f(x) ξ` is continuous on `U × E` +when `f` is C² on the open set `U`. -/ +private theorem hessianQuadForm_continuousOn {d : ℕ} {f : E d → ℝ} {U : Set (E d)} + (hU_is_open : IsOpen U) (hf_C2 : ContDiffOn ℝ 2 f U) : + ContinuousOn (fun p : E d × E d => hessianQuadForm f p.1 p.2) (U ×ˢ Set.univ) := by + have hfderiv_C1 : ContDiffOn ℝ 1 (fderiv ℝ f) U := + hf_C2.fderiv_of_isOpen hU_is_open (show (1 : WithTop ℕ∞) + 1 ≤ 2 by norm_num) + have hgrad_C1 : ContDiffOn ℝ 1 (gradient f) U := + ((InnerProductSpace.toDual ℝ (E d)).symm.toContinuousLinearEquiv.contDiff.of_le + le_top).comp_contDiffOn hfderiv_C1 + have hDgrad_cont : ContinuousOn (fderiv ℝ (gradient f)) U := + (hgrad_C1.fderiv_of_isOpen hU_is_open + (show (0 : WithTop ℕ∞) + 1 ≤ 1 by norm_num)).continuousOn + simp only [hessianQuadForm] + exact ((hDgrad_cont.comp continuousOn_fst (fun p hp => hp.1)).clm_apply + continuousOn_snd).inner continuousOn_snd + +/-- A lower bound `a` for the Hessian quadratic form on unit vectors satisfying a +scaling-invariant condition `P` extends to `a‖ξ‖²` for all `ξ` satisfying `P`. -/ +private theorem hessianQuadForm_ge_of_unit_sphere {d : ℕ} {f : E d → ℝ} {x : E d} {a : ℝ} + {P : E d → Prop} (hP_smul : ∀ (c : ℝ) (ξ : E d), P ξ → P (c • ξ)) + (hunit : ∀ ξ₀ ∈ Metric.sphere (0 : E d) 1, P ξ₀ → hessianQuadForm f x ξ₀ ≥ a) + {ξ : E d} (hξP : P ξ) : + hessianQuadForm f x ξ ≥ a * ‖ξ‖ ^ 2 := by + by_cases hξ : ξ = 0 + · subst hξ; simp only [hessianQuadForm, map_zero, inner_self_eq_norm_sq_to_K, norm_zero, + ne_eq, OfNat.ofNat_ne_zero, not_false_eq_true, zero_pow, mul_zero, ge_iff_le, le_refl] + · have hξ_norm_pos : (0 : ℝ) < ‖ξ‖ := norm_pos_iff.mpr hξ + set c := ‖ξ‖ with hc_def + set ξ₀ := c⁻¹ • ξ with hξ₀_def + have hξ₀_norm : ‖ξ₀‖ = 1 := by + rw [hξ₀_def, norm_smul, norm_inv, norm_norm, + inv_mul_cancel₀ (ne_of_gt hξ_norm_pos)] + have hξ₀_sphere : ξ₀ ∈ Metric.sphere (0 : E d) 1 := by + rw [Metric.mem_sphere, dist_zero_right]; exact hξ₀_norm + have hbound₀ : hessianQuadForm f x ξ₀ ≥ a := hunit ξ₀ hξ₀_sphere (hP_smul _ _ hξP) + -- ξ = c • ξ₀ + have hξ_eq : ξ = c • ξ₀ := by + rw [hξ₀_def, smul_smul, mul_inv_cancel₀ (ne_of_gt hξ_norm_pos), one_smul] + -- Homogeneity: hessianQuadForm f x ξ = c² * hessianQuadForm f x ξ₀ + have hhomog : hessianQuadForm f x ξ = c ^ 2 * hessianQuadForm f x ξ₀ := by + conv_lhs => rw [hξ_eq] + simp only [hessianQuadForm, map_smul, real_inner_smul_left, real_inner_smul_right] + ring + rw [hhomog] + have hc_sq_nonneg : (0 : ℝ) ≤ c ^ 2 := sq_nonneg c + nlinarith [hbound₀, hc_sq_nonneg] + +/-- Local compactness of `S` near `m⋆`: some closed ball piece of `S` is compact. -/ +private theorem exists_compact_local_piece {d : ℕ} {S U : Set (E d)} + (hTub_sub : IsTubularNeighborhoodOfSubmanifold S U) {m_star : E d} + (hm_star : m_star ∈ S) : + ∃ r > 0, IsCompact (S ∩ Metric.closedBall m_star r) := by + obtain ⟨r_U, hr_U_pos, hr_U_sub⟩ := + Metric.isOpen_iff.mp hTub_sub.isOpen m_star (hTub_sub.subset hm_star) + refine ⟨r_U / 2, half_pos hr_U_pos, hTub_sub.isCompact_inter_closedBall ?_⟩ + exact (Metric.closedBall_subset_ball (half_lt_self hr_U_pos)).trans hr_U_sub + +/-- Step 2a: the normal Hessian bound `≥ μ` on `S` extends, with the slack `μ' < μ`, +to a neighborhood `V₁` of `m⋆` (compactness of `S_loc × sphere` + thickening). -/ +private theorem exists_normal_hessian_neighborhood {d : ℕ} (f : E d → ℝ) {μ μ' : ℝ} + (hμ'_lt : μ' < μ) {S U : Set (E d)} + (hTub_sub : IsTubularNeighborhoodOfSubmanifold S U) (hf_C2 : ContDiffOn ℝ 2 f U) + {π : E d → E d} (hπ_proj : ∀ x ∈ U, π x ∈ S ∧ dist x (π x) = Metric.infDist x S) + (h_normal_hess_M : ∀ m ∈ S, ∀ ξ : E d, + fderiv ℝ π m ξ = 0 → hessianQuadForm f m ξ ≥ μ * ‖ξ‖ ^ 2) + {m_star : E d} (hm_star : m_star ∈ S) : + ∃ V₁ : Set (E d), IsOpen V₁ ∧ m_star ∈ V₁ ∧ + ∀ x ∈ V₁, ∀ ξ : E d, + fderiv ℝ π (π x) ξ = 0 → + hessianQuadForm f x ξ ≥ μ' * ‖ξ‖ ^ 2 := by + have hU_is_open : IsOpen U := hTub_sub.isOpen + set g : E d × E d → ℝ := fun p => hessianQuadForm f p.1 p.2 with hg_def + have hg_contOn : ContinuousOn g (U ×ˢ Set.univ) := + hessianQuadForm_continuousOn hU_is_open hf_C2 + -- ── Local compactness: S ∩ closedBall(m⋆, r_loc) is compact ── + obtain ⟨r_loc, hr_loc_pos, hS_loc_compact⟩ := exists_compact_local_piece hTub_sub hm_star + set S_loc := S ∩ Metric.closedBall m_star r_loc + have hSphere_compact' : IsCompact (Metric.sphere (0 : E d) 1) := isCompact_sphere 0 1 + have hSlxS_compact := hS_loc_compact.prod hSphere_compact' + have hSlxS_closed := hSlxS_compact.isClosed + have hSlxS_sub : S_loc ×ˢ Metric.sphere (0 : E d) 1 ⊆ U ×ˢ Set.univ := + Set.prod_mono (Set.inter_subset_left.trans hTub_sub.subset) (Set.subset_univ _) + -- ── N = {(m,ξ) ∈ S_loc × sphere | hessianQuadForm f m ξ ≥ μ} is compact ── + set N : Set (E d × E d) := + (S_loc ×ˢ Metric.sphere (0 : E d) 1) ∩ g ⁻¹' Set.Ici μ with hN_def + have hN_compact : IsCompact N := + hSlxS_compact.of_isClosed_subset + ((hg_contOn.mono hSlxS_sub).preimage_isClosed_of_isClosed hSlxS_closed isClosed_Ici) + Set.inter_subset_left + -- ── V_nbhd = (U ×ˢ univ) ∩ {(x,ξ) | hessianQuadForm f x ξ > μ'} is open ── + set V_nbhd : Set (E d × E d) := + (U ×ˢ Set.univ) ∩ g ⁻¹' Set.Ioi μ' with hV_def + have hV_open : IsOpen V_nbhd := + hg_contOn.isOpen_inter_preimage (hU_is_open.prod isOpen_univ) isOpen_Ioi + have hN_sub : N ⊆ V_nbhd := by + intro ⟨x, ξ⟩ ⟨hmem, hge⟩ + exact ⟨hSlxS_sub hmem, by + simp only [Set.mem_preimage, Set.mem_Ioi, Set.mem_Ici] at hge ⊢; linarith⟩ + -- ── Thickening: ∃ δ > 0, thickening δ N ⊆ V_nbhd ── + obtain ⟨δ, hδ_pos, hthick⟩ := hN_compact.exists_thickening_subset_open hV_open hN_sub + -- ── V₁ = U ∩ ball(m⋆, min(δ, r_loc/2)) ── + set δ' := min δ (r_loc / 2) with hδ'_def + have hδ'_pos : 0 < δ' := lt_min hδ_pos (half_pos hr_loc_pos) + refine ⟨U ∩ Metric.ball m_star δ', + hTub_sub.isOpen.inter Metric.isOpen_ball, + ⟨hTub_sub.subset hm_star, Metric.mem_ball_self hδ'_pos⟩, + fun x ⟨hxU, hx_near⟩ ξ hξ_normal => ?_⟩ + refine hessianQuadForm_ge_of_unit_sphere (P := fun ξ => fderiv ℝ π (π x) ξ = 0) + (fun c ξ h => by simp only [map_smul, h, smul_zero]) (fun ξ₀ hξ₀_sphere hξ₀_normal => ?_) + hξ_normal + have hξ₀_norm : ‖ξ₀‖ = 1 := mem_sphere_zero_iff_norm.mp hξ₀_sphere + -- π(x) ∈ S, and dist(x, m_star) < δ' ≤ r_loc/2, so π(x) ∈ S_loc + have hπ_in_S : π x ∈ S := (hπ_proj x hxU).1 + have hx_dist : dist x m_star < δ' := Metric.mem_ball.mp hx_near + have hinfDist_le : Metric.infDist x S ≤ dist x m_star := + Metric.infDist_le_dist_of_mem hm_star + have hπ_in_S_loc : π x ∈ S_loc := by + refine ⟨hπ_in_S, Metric.mem_closedBall.mpr ?_⟩ + have h1 := dist_triangle (π x) x m_star + rw [dist_comm (π x) x] at h1 + have h2 : dist x (π x) = Metric.infDist x S := (hπ_proj x hxU).2 + linarith [min_le_right δ (r_loc / 2)] + -- hessianQuadForm f (π x) ξ₀ ≥ μ (by h_normal_hess_M) + have hge_mu : hessianQuadForm f (π x) ξ₀ ≥ μ := by + have := h_normal_hess_M (π x) hπ_in_S ξ₀ hξ₀_normal + rw [hξ₀_norm, one_pow, mul_one] at this; exact this + have hπξ_in_N : (π x, ξ₀) ∈ N := by + refine ⟨Set.mk_mem_prod hπ_in_S_loc hξ₀_sphere, ?_⟩ + simp only [Set.mem_preimage, Set.mem_Ici]; exact hge_mu + -- dist((x, ξ₀), (π(x), ξ₀)) = dist(x, π(x)) < δ + have hdist_pair : dist (x, ξ₀) (π x, ξ₀) = dist x (π x) := by + simp only [Prod.dist_eq, dist_self, dist_nonneg, sup_of_le_left] + have hx_near_π : dist x (π x) = Metric.infDist x S := (hπ_proj x hxU).2 + have h_in_thick : (x, ξ₀) ∈ Metric.thickening δ N := by + rw [Metric.mem_thickening_iff] + exact ⟨(π x, ξ₀), hπξ_in_N, by + rw [hdist_pair, hx_near_π]; linarith [min_le_left δ (r_loc / 2)]⟩ + have hmem := (hthick h_in_thick).2 + simp only [Set.mem_preimage, Set.mem_Ioi] at hmem + exact le_of_lt hmem + +/-- Step 2b: `D²f ≽ 0` on `S` extends to `D²f ≽ -ε₀ I` on a neighborhood `V₂` of `m⋆` +(tube lemma on `S_loc × sphere`). -/ +private theorem exists_hessian_lower_neighborhood {d : ℕ} (f : E d → ℝ) {ε₀ : ℝ} + (hε₀_pos : 0 < ε₀) {S U : Set (E d)} + (hTub_sub : IsTubularNeighborhoodOfSubmanifold S U) (hf_C2 : ContDiffOn ℝ 2 f U) + (h_hess_psd_M : ∀ m ∈ S, ∀ ξ : E d, hessianQuadForm f m ξ ≥ 0) + {m_star : E d} (hm_star : m_star ∈ S) : + ∃ V₂ : Set (E d), IsOpen V₂ ∧ m_star ∈ V₂ ∧ + ∀ x ∈ V₂, ∀ ξ : E d, + hessianQuadForm f x ξ ≥ -ε₀ * ‖ξ‖ ^ 2 := by + have hU_is_open : IsOpen U := hTub_sub.isOpen + set g₂ : E d × E d → ℝ := fun p => hessianQuadForm f p.1 p.2 with hg₂_def + have hg₂_contOn : ContinuousOn g₂ (U ×ˢ Set.univ) := + hessianQuadForm_continuousOn hU_is_open hf_C2 + -- S_loc₂ = S ∩ closedBall(m⋆, r_loc₂) is compact (local compactness) + obtain ⟨r_loc₂, hr_loc₂_pos, hS_loc₂_compact⟩ := exists_compact_local_piece hTub_sub hm_star + set S_loc₂ := S ∩ Metric.closedBall m_star r_loc₂ + have hSphere_compact : IsCompact (Metric.sphere (0 : E d) 1) := isCompact_sphere 0 1 + -- hessianQuadForm ≥ 0 on S × sphere (PSD at minimizers) + have hg_K : ∀ p ∈ S ×ˢ Metric.sphere (0 : E d) 1, + (0 : ℝ) ≤ g₂ p := by + rintro ⟨x, ξ⟩ ⟨hx, -⟩ + exact h_hess_psd_M x hx ξ + -- V_prod = (U ×ˢ univ) ∩ {p | g₂ p > -ε₀} is open, contains S × sphere + set V_prod : Set (E d × E d) := + (U ×ˢ Set.univ) ∩ g₂ ⁻¹' Set.Ioi (-ε₀) with hVp_def + have hV_prod_open : IsOpen V_prod := + hg₂_contOn.isOpen_inter_preimage (hU_is_open.prod isOpen_univ) isOpen_Ioi + have hK_V_prod : S ×ˢ Metric.sphere (0 : E d) 1 ⊆ V_prod := by + intro ⟨x, ξ⟩ ⟨hx, hξ⟩ + exact ⟨⟨hTub_sub.subset hx, Set.mem_univ _⟩, + by simp only [Set.mem_preimage, Set.mem_Ioi]; linarith [hg_K (x, ξ) ⟨hx, hξ⟩]⟩ + have hK_V_prod_loc : S_loc₂ ×ˢ Metric.sphere (0 : E d) 1 ⊆ V_prod := + (Set.prod_mono Set.inter_subset_left (le_refl _)).trans hK_V_prod + have hg_bound : ∀ p ∈ V_prod, (0 : ℝ) - ε₀ ≤ g₂ p := by + intro p ⟨_, hmem⟩ + simp only [Set.mem_preimage, Set.mem_Ioi] at hmem; linarith + -- Apply generalized_tube_lemma with S_loc₂ (local compactness) + obtain ⟨V₂, W, hV₂_open, _, hSloc_V₂, hSphere_W, hVW⟩ := + generalized_tube_lemma hS_loc₂_compact hSphere_compact hV_prod_open hK_V_prod_loc + have hm_V₂ : m_star ∈ V₂ := + hSloc_V₂ ⟨hm_star, Metric.mem_closedBall_self (le_of_lt hr_loc₂_pos)⟩ + refine ⟨V₂, hV₂_open, hm_V₂, fun x hx ξ => ?_⟩ + -- (x, ξ₀) ∈ V₂ ×ˢ W ⊆ V_prod for unit ξ₀, so hessianQuadForm f x ξ₀ ≥ -ε₀ + refine hessianQuadForm_ge_of_unit_sphere (P := fun _ => True) (fun _ _ _ => trivial) + (fun ξ₀ hξ₀_sphere _ => ?_) trivial + have := hg_bound (x, ξ₀) (hVW (Set.mk_mem_prod hx (hSphere_W hξ₀_sphere))) + simp only [g₂] at this + linarith + +/-- Step 3: a ball `U₊` around `m⋆` with compact closure inside an open `W ⊆ U` +whose fiber segments `[π(x), x]` stay in `W`. -/ +private theorem exists_fiber_saturated_ball {d : ℕ} {S U W : Set (E d)} {π : E d → E d} + (hπ_proj : ∀ x ∈ U, π x ∈ S ∧ dist x (π x) = Metric.infDist x S) + (hW_open : IsOpen W) (hW_U : W ⊆ U) {m_star : E d} (hm_star : m_star ∈ S) + (hm_W : m_star ∈ W) : + ∃ U_plus : Set (E d), IsOpen U_plus ∧ m_star ∈ U_plus ∧ + IsCompact (closure U_plus) ∧ closure U_plus ⊆ W ∧ Convex ℝ U_plus ∧ + ∀ x ∈ U_plus, ∀ t : ℝ, 0 ≤ t → t ≤ 1 → π x + t • (x - π x) ∈ W := by + obtain ⟨r, hr_pos, hball_sub⟩ := Metric.isOpen_iff.mp hW_open m_star hm_W + -- Take U₊ = B(m⋆, r/2) + refine ⟨Metric.ball m_star (r / 2), Metric.isOpen_ball, + Metric.mem_ball_self (by linarith), Metric.isBounded_ball.isCompact_closure, ?_, + convex_ball _ _, ?_⟩ + -- closure (ball m⋆ (r/2)) ⊆ W + · intro y hy + have h_in_cl : y ∈ Metric.closedBall m_star (r / 2) := + closure_minimal Metric.ball_subset_closedBall Metric.isClosed_closedBall hy + have : dist y m_star < r := + lt_of_le_of_lt (Metric.mem_closedBall.mp h_in_cl) (by linarith) + exact hball_sub (Metric.mem_ball.mpr this) + -- fiber segments from ball(m_star, r/2) stay in ball(m_star, r) ⊆ W + · intro x hx t ht0 ht1 + have hx_ball_r : x ∈ Metric.ball m_star r := + Metric.ball_subset_ball (by linarith : r / 2 ≤ r) hx + have hxU : x ∈ U := hW_U (hball_sub hx_ball_r) + have hπx_ball : π x ∈ Metric.ball m_star r := by + rw [Metric.mem_ball] + have h1 : dist x (π x) < r / 2 := by + calc dist x (π x) = Metric.infDist x S := (hπ_proj x hxU).2 + _ ≤ dist x m_star := Metric.infDist_le_dist_of_mem hm_star + _ < r / 2 := Metric.mem_ball.mp hx + have h2 : dist x m_star < r / 2 := Metric.mem_ball.mp hx + linarith [dist_triangle (π x) x m_star, dist_comm (π x) x] + apply hball_sub + have hy_eq : π x + t • (x - π x) = (1 - t) • π x + t • x := by + simp only [smul_sub, sub_smul, one_smul]; abel + rw [hy_eq] + exact convex_ball m_star r hπx_ball hx_ball_r (by linarith) ht0 (by linarith) + +/-- Regularity of the fiber path `φ(t) = f(m + t e)` needed by the Step 2 helpers. -/ +private theorem fiber_path_regularity {d : ℕ} (f : E d → ℝ) (m e : E d) {U : Set (E d)} + (hU : IsOpen U) (hf_C2 : ContDiffOn ℝ 2 f U) + (hseg_U : ∀ t : ℝ, t ∈ Set.Icc 0 1 → m + t • e ∈ U) : + ContinuousOn (fun t : ℝ => f (m + t • e)) (Set.Icc 0 1) ∧ + DifferentiableOn ℝ (fun t : ℝ => f (m + t • e)) (Set.Ioo 0 1) ∧ + ContinuousOn (deriv fun t : ℝ => f (m + t • e)) (Set.Icc 0 1) ∧ + DifferentiableOn ℝ (deriv fun t : ℝ => f (m + t • e)) (Set.Ioo 0 1) := by + set φ : ℝ → ℝ := fun t => f (m + t • e) with hφ_def + have hφ_C2at := fiber_path_C2at_on_segment f m e hU hf_C2 hseg_U + have h_eq : deriv φ = fun s => fderiv ℝ φ s 1 := by + ext s; exact fderiv_apply_one_eq_deriv.symm + refine ⟨fun t ht => (hφ_C2at t ht).continuousAt.continuousWithinAt, + fun t ht => ((hφ_C2at t (Set.Ioo_subset_Icc_self ht)).differentiableAt + (by norm_num : (2 : WithTop ℕ∞) ≠ 0)).differentiableWithinAt, ?_, ?_⟩ + · intro t ht + have hfda := (hφ_C2at t ht).fderiv_right (show (1 : WithTop ℕ∞) + 1 ≤ 2 by norm_num) + rw [h_eq]; exact (hfda.continuousAt.clm_apply continuousAt_const).continuousWithinAt + · intro t ht + have hfda := (hφ_C2at t (Set.Ioo_subset_Icc_self ht)).fderiv_right + (show (1 : WithTop ℕ∞) + 1 ≤ 2 by norm_num) + have hfda_diff := hfda.differentiableAt (show (1 : WithTop ℕ∞) ≠ 0 by norm_num) + rw [h_eq]; exact (hfda_diff.clm_apply (differentiableAt_const _)).differentiableWithinAt + +/-- Derivative of the fiber path `t ↦ f(m + t e)` at `s`: `⟨∇f(m + s e), e⟩`. -/ +private theorem fiber_path_deriv_eq_inner {d : ℕ} (f : E d → ℝ) (m e : E d) (s : ℝ) + (hf : DifferentiableAt ℝ f (m + s • e)) : + deriv (fun t : ℝ => f (m + t • e)) s = @inner ℝ _ _ (gradient f (m + s • e)) e := by + have hg : HasDerivAt (fun t : ℝ => m + t • e) e s := by + simpa using ((hasDerivAt_id s).smul_const e).const_add m + have key := hf.hasFDerivAt.comp_hasDerivAt s hg + simp only [Function.comp_def] at key + rw [key.deriv] + exact (inner_gradient_left (𝕜 := ℝ) (f := f) (x := m + s • e) (y := e)).symm + +/-- Steps (b)–(c): along a fiber `t ↦ m + t(x − m)` from a minimizer `m` with +second derivative `≥ μ'‖x − m‖²`, the function has quadratic growth and satisfies +the strong aiming inequality. -/ +private theorem fiber_growth_and_aiming {d : ℕ} (f : E d → ℝ) {U : Set (E d)} + (hU : IsOpen U) (hf_C2 : ContDiffOn ℝ 2 f U) {μ' : ℝ} {m x : E d} + (hm_min : ∀ y, f m ≤ f y) (hgrad_m : gradient f m = 0) + (hseg_U : ∀ t : ℝ, t ∈ Set.Icc 0 1 → m + t • (x - m) ∈ U) + (hbound : ∀ t : ℝ, 0 ≤ t → t ≤ 1 → + hessianQuadForm f (m + t • (x - m)) (x - m) ≥ μ' * ‖x - m‖ ^ 2) : + f x - fStar f ≥ μ' / 2 * ‖x - m‖ ^ 2 ∧ + @inner ℝ _ _ (gradient f x) (x - m) ≥ f x - fStar f + μ' / 2 * ‖x - m‖ ^ 2 := by + set e := x - m with he_def + set φ : ℝ → ℝ := fun t => f (m + t • e) with hφ_def + -- φ(0) = f(m) = f⋆ since m minimizes f + have hφ0 : φ 0 = fStar f := by + simp only [hφ_def, zero_smul, add_zero] + unfold fStar + exact le_antisymm (le_ciInf hm_min) + (ciInf_le ⟨f m, fun _ ⟨y, hy⟩ => hy ▸ hm_min y⟩ m) + have hme1 : m + (1 : ℝ) • e = x := by simp only [he_def, one_smul, add_sub_cancel] + have hφ1 : φ 1 = f x := by simp only [hφ_def, hme1] + have hf_diff_on : DifferentiableOn ℝ f U := hf_C2.differentiableOn two_ne_zero + have hm_U : m + (0 : ℝ) • e ∈ U := hseg_U 0 ⟨le_rfl, zero_le_one⟩ + have hx_U : m + (1 : ℝ) • e ∈ U := hseg_U 1 ⟨zero_le_one, le_rfl⟩ + -- φ'(0) = ⟨∇f(m), e⟩ = 0 and φ'(1) = ⟨∇f(x), e⟩ + have hφ'0 : deriv φ 0 = 0 := by + rw [fiber_path_deriv_eq_inner f m e 0 (hf_diff_on.differentiableAt (hU.mem_nhds hm_U)), + zero_smul, add_zero, hgrad_m, inner_zero_left] + have hφ'1 : deriv φ 1 = @inner ℝ _ _ (gradient f x) e := by + rw [fiber_path_deriv_eq_inner f m e 1 (hf_diff_on.differentiableAt (hU.mem_nhds hx_U)), + hme1] + obtain ⟨hφ_cont, hφ_diffon, hφ'_cont, hφ'_diffon⟩ := + fiber_path_regularity f m e hU hf_C2 hseg_U + have hφ''_lb : ∀ t, 0 ≤ t → t ≤ 1 → deriv (deriv φ) t ≥ μ' * ‖e‖ ^ 2 := + fiber_path_hessian_lower_bound f μ' m e hU hf_C2 hseg_U hbound + have hgrowth := quadratic_growth_from_hessian φ (μ' * ‖e‖ ^ 2) + hφ_cont hφ_diffon hφ'_cont hφ'_diffon hφ'0 hφ''_lb + have hsa := strong_aiming_from_hessian φ (μ' * ‖e‖ ^ 2) + hφ_cont hφ_diffon hφ'_cont hφ'_diffon hφ'0 hφ''_lb + rw [hφ1, hφ0] at hgrowth + rw [hφ1, hφ0, hφ'1] at hsa + have : μ' * ‖e‖ ^ 2 / 2 = μ' / 2 * ‖e‖ ^ 2 := by ring + constructor <;> linarith + /-- **Local fiberwise geometry from PL near M.** @@ -69,7 +519,7 @@ of m⋆ with U₊ ⊂⊂ U, and ε > 0 with ε ≤ √(μ'/η), satisfying: (c) strong aiming inequality, (d) global Hessian bound ≥ -ε. -/ -private abbrev localFiberwiseGeometryProof +private theorem localFiberwiseGeometryProof -- Dimensions {d : ℕ} (_hd : 0 < d) -- The objective function @@ -144,250 +594,9 @@ private abbrev localFiberwiseGeometryProof -- PL ⟹ Morse-Bott: normal Hessian ξᵀD²f(m)ξ ≥ μ‖ξ‖² on M have h_normal_hess_M : ∀ m ∈ S, ∀ ξ : E d, fderiv ℝ π m ξ = 0 → - hessianQuadForm f m ξ ≥ μ * ‖ξ‖ ^ 2 := by - intro m hmS ξ hξ_normal - -- ══════════════════════════════════════════════════════════════════ - -- Goal: hessianQuadForm f m ξ ≥ μ * ‖ξ‖ ^ 2 - -- Proof: Rayleigh quotient minimizer on the unit sphere of ker(H)⊥, - -- combined with PL ⟹ μ·⟨Hv,v⟩ ≤ ‖Hv‖² (Rebjock & Boumal, Cor 2.17). - -- ══════════════════════════════════════════════════════════════════ - -- ═══ BASIC SETUP ═══ - have hmin : ∀ y, f m ≤ f y := by rw [hM_argmin] at hmS; exact hmS - have hmin_local : IsLocalMin f m := Filter.Eventually.of_forall hmin - have hmU : m ∈ U := hTub_sub.subset hmS - have hf_C2_at_m : ContDiffAt ℝ 2 f m := - hf_C2.contDiffAt (hU_is_open.mem_nhds hmU) - -- DifferentiableAt ℝ f m and DifferentiableAt ℝ (gradient f) m from local C² - have hf_da_m : DifferentiableAt ℝ f m := - hf_C2_at_m.differentiableAt (by norm_num : (2 : WithTop ℕ∞) ≠ 0) - have hfderiv_da_m : DifferentiableAt ℝ (fderiv ℝ f) m := - (hf_C2_at_m.fderiv_right le_rfl).differentiableAt one_ne_zero - have hgrad_da_m : DifferentiableAt ℝ (gradient f) m := by - exact ((InnerProductSpace.toDual ℝ (E d)).symm - |>.toContinuousLinearEquiv - |>.differentiable |>.differentiableAt - |>.comp m hfderiv_da_m) - -- The gradient-Hessian operator H := D(∇f)(m) : E d →L[ℝ] E d - set H := fderiv ℝ (gradient f) m with hH_def - set K : Submodule ℝ (E d) := LinearMap.ker H.toLinearMap with hK_def - -- ═══ BRIDGE 1: projection condition → ξ ∈ K⊥ ═══ - have hξ_orth : ξ ∈ K.orthogonal := by - rw [K.mem_orthogonal] - intro w hw - -- w ∈ K = ker(H), need: ⟪w, ξ⟫ = 0 - -- Morse-Bott: K ⊆ range(Dπ(m)). Under PL + C², S is a smooth minimizer - -- manifold with T_mS = ker(H), so every w ∈ ker(H) is tangent to S, - -- hence w = Dπ(m)(u) for some u. - have hMB : w ∈ LinearMap.range (fderiv ℝ π m).toLinearMap := by - -- ── Step 1: Connect π with π' from tubular_neighborhood_projection ── - obtain ⟨π', hπ'_proj, hπ'_fix, _, _, _, _, _, hπ'_diff, _, _⟩ := - tubular_neighborhood_projection_Ed hTub_sub ⟨m_star, hm_star⟩ - have hmU : m ∈ U := hTub_sub.subset hmS - have hπ_eq' : ∀ x ∈ U, π x = π' x := by - intro x hxU - obtain ⟨p, hp, huniq⟩ := hTub_sub.uniqueProj x hxU - exact (huniq (π x) (hπ_proj x hxU)).trans - (huniq (π' x) ⟨(hπ'_proj x hxU).1, - by rw [dist_eq_norm]; exact (hπ'_proj x hxU).2⟩).symm - have hπ_ev : π =ᶠ[𝓝 m] π' := - Filter.eventually_of_mem (hTub_sub.isOpen.mem_nhds hmU) hπ_eq' - have hfderiv_eq : fderiv ℝ π m = fderiv ℝ π' m := hπ_ev.fderiv_eq - -- Suffices to show fderiv ℝ π' m w = w - suffices hPw : fderiv ℝ π' m w = w by - exact LinearMap.mem_range.mpr - ⟨w, by rw [ContinuousLinearMap.coe_coe, hfderiv_eq, hPw]⟩ - -- ── Step 2: Convert PL → MuPL → submanifold ── - have hPL_ext : ExternalThm3.PolyakLojasiewicz f μ U := - ⟨hμ, fun x hxU => by - have := hPL.2.2 x hxU - rw [norm_mathlibGradient_eq_norm_fderiv] at this; exact this⟩ - have hMuPL : MuPL f μ m := - ExternalThm3.pl_to_muPL f μ U m - (by rw [hM_argmin] at hmS; exact hmS) - (hTub_sub.isOpen.mem_nhds hmU) hPL_ext - have hsub' : IsLocalSubmanifoldAt (localMinSet f m) m (hessianKer f m) := by - exact MuPL.implies_submanifold f μ m hμ hf_C2_at_m hmin_local hMuPL - -- ── Step 3: localMinSet f m = S ── - have hS_eq : S = localMinSet f m := by - ext x; constructor - · intro hxS; rw [hM_argmin] at hxS - exact ⟨Filter.Eventually.of_forall hxS, le_antisymm (hxS m) (hmin x)⟩ - · intro ⟨_, hfx⟩; rw [hM_argmin] - intro z; linarith [hmin z] - -- ── Step 4: w ∈ hessianKer f m ── - have hw' : fderiv ℝ (gradient f) m w = 0 := by - have := LinearMap.mem_ker.mp hw; rwa [ContinuousLinearMap.coe_coe] at this - have hw_hess : w ∈ hessianKer f m := by - rw [hessianKer, LinearMap.mem_ker, ContinuousLinearMap.coe_coe] - have hbridge : ∀ u', (fderiv ℝ (fderiv ℝ f) m) w u' = 0 := by - intro u' - have h1 : fderiv ℝ (fun z => @inner ℝ (E d) _ (gradient f z) u') m w = - @inner ℝ (E d) _ (fderiv ℝ (gradient f) m w) u' := by - rw [fderiv_inner_apply (𝕜 := ℝ) (hgrad_da_m) (differentiableAt_const u')] - simp only [fderiv_fun_const, Pi.zero_apply, - zero_apply, - inner_zero_right, zero_add] - have hDf_diff' : DifferentiableAt ℝ (fderiv ℝ f) m := hfderiv_da_m - have hcomp : HasFDerivAt (fun y => (fderiv ℝ f y) u') - ((ContinuousLinearMap.apply ℝ ℝ u').comp (fderiv ℝ (fderiv ℝ f) m)) m := - ((ContinuousLinearMap.apply ℝ ℝ u').hasFDerivAt).comp m hDf_diff'.hasFDerivAt - have h2 : fderiv ℝ (fun z => @inner ℝ (E d) _ (gradient f z) u') m w = - (fderiv ℝ (fderiv ℝ f) m) w u' := by - have heq : (fun z => @inner ℝ (E d) _ (gradient f z) u') =ᶠ[𝓝 m] - (fun y => (fderiv ℝ f y) u') := by - filter_upwards [hU_is_open.mem_nhds hmU] with z hz - exact inner_gradient_left (𝕜 := ℝ) (f := f) (x := z) (y := u') - rw [heq.fderiv_eq, hcomp.fderiv] - rfl - rw [← h2, h1, hw', inner_zero_left] - have : (fderiv ℝ (fderiv ℝ f) m) w = 0 := - ContinuousLinearMap.ext fun u' => hbridge u' - exact this - -- ── Step 5: Construct curve γ in S through m with γ'(0) = w ── - set T := hessianKer f m with hT_def - obtain ⟨U_chart, hU_chart_nhds, ψ, hψ_C1, hψ0, hDψ0, hgraph⟩ := hsub'.2 - rw [← hS_eq] at hgraph - set w_T : ↥T := ⟨w, hw_hess⟩ - set γ : ℝ → E d := - fun t => m + t • w + (↑(ψ (t • w_T)) : E d) - -- HasDerivAt γ w 0 - have hψ_diff : DifferentiableAt ℝ ψ 0 := - hψ_C1.differentiableAt (by norm_num : (1 : WithTop ℕ∞) ≠ 0) - have hβ : HasDerivAt (fun t : ℝ => t • w_T) w_T 0 := by - simpa using (hasDerivAt_id (0 : ℝ)).smul_const w_T - have hψβ : HasDerivAt (fun t : ℝ => ψ (t • w_T)) 0 0 := by - have h := hψ_diff.hasFDerivAt.comp_hasDerivAt_of_eq 0 hβ (zero_smul ℝ w_T).symm - rwa [hDψ0, zero_apply] at h - have hγ_deriv : HasDerivAt γ w 0 := by - have h1 : HasDerivAt (fun t : ℝ => m + t • w) w 0 := by - simpa using ((hasDerivAt_id (0 : ℝ)).smul_const w).const_add m - have h2 : HasDerivAt - (fun t : ℝ => (↑(ψ (t • w_T)) : E d)) (0 : E d) 0 := by - have h := (ContinuousLinearMap.hasFDerivAt - T.orthogonal.subtypeL).comp_hasDerivAt (0 : ℝ) hψβ - simp only [map_zero] at h - exact h - have h3 := h1.add h2 - rwa [add_zero] at h3 - -- ── Step 6: γ(t) ∈ S for small t ── - have hγ0 : γ 0 = m := by - change m + (0 : ℝ) • w + (↑(ψ ((0 : ℝ) • w_T)) : E d) = m - rw [zero_smul, zero_smul, hψ0]; simp only [add_zero, ZeroMemClass.coe_zero] - have hγ_cont := hγ_deriv.continuousAt - have hpre : ∀ᶠ t in 𝓝 (0 : ℝ), γ t ∈ U_chart := by - exact hγ_cont.preimage_mem_nhds (by rw [hγ0]; exact hU_chart_nhds) - have hγ_in_S : ∀ᶠ t in 𝓝 (0 : ℝ), γ t ∈ S := by - filter_upwards [hpre] with t ht - have hgr := (hgraph (γ t) ht).mpr - apply hgr - -- γ(t) - m = t•(w_T : E d) + ↑(ψ(t•w_T)) - have hγ_sub : γ t - m = t • (w_T : E d) + (↑(ψ (t • w_T)) : E d) := by - simp only [γ]; abel - have hψ_proj : T.orthogonalProjectionOnto (ψ (t • w_T) : E d) = 0 := - Submodule.orthogonalProjectionOnto_eq_zero_iff.mpr (ψ (t • w_T)).property - have hw_perp_proj : Tᗮ.orthogonalProjectionOnto (w_T : E d) = 0 := - Submodule.orthogonalProjectionOnto_eq_zero_iff.mpr - (Submodule.le_orthogonal_orthogonal T w_T.property) - rw [hγ_sub, map_add, map_smul, map_add, map_smul] - rw [Submodule.orthogonalProjectionOnto_mem_subspace_eq_self w_T, - hψ_proj, - add_zero, - hw_perp_proj, - smul_zero, zero_add, - Submodule.orthogonalProjectionOnto_mem_subspace_eq_self (ψ (t • w_T))] - -- ── Step 7: Differentiate π' ∘ γ = γ to get fderiv ℝ π' m w = w ── - -- π' fixes S, so π' ∘ γ =ᶠ[𝓝 0] γ - have hπγ_eq : (π' ∘ γ) =ᶠ[𝓝 (0 : ℝ)] γ := by - filter_upwards [hγ_in_S] with t ht - exact hπ'_fix (γ t) ht - -- From EventuallyEq + HasDerivAt γ w 0: HasDerivAt (π' ∘ γ) w 0 - have hπγ_deriv1 : HasDerivAt (π' ∘ γ) w 0 := - hπγ_eq.hasDerivAt_iff.mpr hγ_deriv - -- From chain rule: HasDerivAt (π' ∘ γ) ((fderiv ℝ π' m) w) 0 - have hπ_diff_m : DifferentiableAt ℝ π' m := hπ'_diff m hmS - have hπγ_deriv2 : HasDerivAt (π' ∘ γ) ((fderiv ℝ π' m) w) 0 := - hπ_diff_m.hasFDerivAt.comp_hasDerivAt_of_eq (0 : ℝ) hγ_deriv hγ0.symm - -- By uniqueness of derivatives - exact hπγ_deriv2.unique hπγ_deriv1 - obtain ⟨u, hu⟩ := LinearMap.mem_range.mp hMB - simp only [ContinuousLinearMap.coe_coe] at hu - -- Self-adjointness of Dπ(m): for the nearest-point projection onto a smooth - -- submanifold, the derivative at a point on the manifold is an orthogonal - -- projector, hence self-adjoint: ⟪Dπ(m) u, v⟫ = ⟪u, Dπ(m) v⟫. - have hπ_sa : @inner ℝ (E d) _ (fderiv ℝ π m u) ξ = - @inner ℝ (E d) _ u (fderiv ℝ π m ξ) := by - -- Get canonical projection π' with self-adjointness from tubular neighborhood - obtain ⟨π', hπ'_proj, _, _, _, _, _, _, _, hπ'_sa, _⟩ := - tubular_neighborhood_projection_Ed hTub_sub ⟨m_star, hm_star⟩ - have hmU : m ∈ U := hTub_sub.subset hmS - -- π and π' agree on U by uniqueness of nearest-point projection - have hπ_eq : ∀ x ∈ U, π x = π' x := by - intro x hxU - obtain ⟨p, hp, huniq⟩ := hTub_sub.uniqueProj x hxU - have h1 : π x ∈ S ∧ dist x (π x) = Metric.infDist x S := hπ_proj x hxU - have h2' := hπ'_proj x hxU - have h2 : π' x ∈ S ∧ dist x (π' x) = Metric.infDist x S := - ⟨h2'.1, by rw [dist_eq_norm]; exact h2'.2⟩ - exact (huniq (π x) h1).trans (huniq (π' x) h2).symm - -- π =ᶠ[𝓝 m] π' since they agree on the open set U containing m - have hπ_eq_nhds : π =ᶠ[𝓝 m] π' := - Filter.eventually_of_mem (hTub_sub.isOpen.mem_nhds hmU) hπ_eq - rw [hπ_eq_nhds.fderiv_eq] - exact hπ'_sa m hmS u ξ - rw [← hu, hπ_sa, hξ_normal, inner_zero_right] - have hξ_hess_orth : ξ ∈ (hessianKer f m).orthogonal := by - rw [(hessianKer f m).mem_orthogonal] - intro w hw - have hwK : w ∈ K := by - rw [hK_def, LinearMap.mem_ker] - have hw_hess_zero : (fderiv ℝ (fderiv ℝ f) m) w = 0 := by - exact LinearMap.mem_ker.mp hw - apply ext_inner_right ℝ - intro u' - have hbridge : @inner ℝ (E d) _ (H w) u' = - (fderiv ℝ (fderiv ℝ f) m) w u' := by - set G : E d → ℝ := fun y => (fderiv ℝ f y) u' - have hG_inner_nhds : G =ᶠ[𝓝 m] - fun z => @inner ℝ (E d) _ (gradient f z) u' := by - filter_upwards [hU_is_open.mem_nhds hmU] with z hz - exact (inner_gradient_left (𝕜 := ℝ) (f := f) (x := z) (y := u')).symm - have hleft : fderiv ℝ G m w = @inner ℝ (E d) _ (H w) u' := by - rw [hG_inner_nhds.fderiv_eq] - rw [fderiv_inner_apply (𝕜 := ℝ) hgrad_da_m (differentiableAt_const u')] - simp only [fderiv_fun_const, Pi.zero_apply, - zero_apply, inner_zero_right, ← hH_def, zero_add] - have hright : fderiv ℝ G m w = (fderiv ℝ (fderiv ℝ f) m) w u' := by - have hcomp : HasFDerivAt G - ((ContinuousLinearMap.apply ℝ ℝ u').comp - (fderiv ℝ (fderiv ℝ f) m)) m := - ((ContinuousLinearMap.apply ℝ ℝ u').hasFDerivAt).comp - m hfderiv_da_m.hasFDerivAt - rw [hcomp.fderiv] - rfl - linarith - change @inner ℝ (E d) _ (H w) u' = @inner ℝ (E d) _ (0 : E d) u' - calc - @inner ℝ (E d) _ (H w) u' - = (fderiv ℝ (fderiv ℝ f) m) w u' := hbridge - _ = 0 := by rw [hw_hess_zero, zero_apply] - _ = @inner ℝ (E d) _ (0 : E d) u' := by rw [inner_zero_left] - have hξK := hξ_orth - rw [K.mem_orthogonal] at hξK - exact hξK w hwK - have hPL_ext : ExternalThm3.PolyakLojasiewicz f μ U := - ⟨hμ, fun x hxU => by - have := hPL.2.2 x hxU - rw [norm_mathlibGradient_eq_norm_fderiv] at this - exact this⟩ - have hm_ext : m ∈ ExternalThm3.argminSet f := by - rw [hM_argmin] at hmS - exact hmS - have hbound := ExternalThm3.hessianQuadForm_bound f μ U m ξ - hf_C2_at_m hPL_ext hm_ext (hU_is_open.mem_nhds hmU) hξ_hess_orth - have hgrad_fun : ExternalThm3.gradient f = gradient f := by - funext x - exact externalThm3_gradient_eq_gradient f x - simpa [ExternalThm3.hessianQuadForm, hessianQuadForm, hgrad_fun] using hbound + hessianQuadForm f m ξ ≥ μ * ‖ξ‖ ^ 2 := fun m hmS ξ hξ_normal => + normal_hessian_bound_at_minimizer f μ hμ hM_argmin hTub_sub hPL hf_C2 hπ_proj hmS + hξ_normal -- D²f(m) ≽ 0 at global minimizers (PSD, by hessian_psd_at_minimizer) have h_hess_psd_M : ∀ m ∈ S, ∀ ξ : E d, hessianQuadForm f m ξ ≥ 0 := by @@ -400,324 +609,30 @@ private abbrev localFiberwiseGeometryProof -- ================================================================ -- Step 2: Extend bounds to neighborhoods by continuity + compactness -- ================================================================ - -- The gap μ - μ' > 0 provides room to relax constants - have hgap : 0 < μ - μ' := by linarith - -- V₁: neighborhood of S where normal Hessian ≥ μ'‖ξ‖² - -- (continuous_lower_bound_neighborhood applied to the normal Hessian map) - obtain ⟨V₁, hV₁_open, hm_V₁, h_normal_V₁⟩ : - ∃ V₁ : Set (E d), IsOpen V₁ ∧ m_star ∈ V₁ ∧ - ∀ x ∈ V₁, ∀ ξ : E d, - fderiv ℝ π (π x) ξ = 0 → - hessianQuadForm f x ξ ≥ μ' * ‖ξ‖ ^ 2 := by - -- ── Setup: hessianQuadForm ContinuousOn from C² ── - set g : E d × E d → ℝ := fun p => hessianQuadForm f p.1 p.2 with hg_def - have hg_contOn : ContinuousOn g (U ×ˢ Set.univ) := by - have hfderiv_C1 : ContDiffOn ℝ 1 (fderiv ℝ f) U := - hf_C2.fderiv_of_isOpen hU_is_open (show (1 : WithTop ℕ∞) + 1 ≤ 2 by norm_num) - have hgrad_C1 : ContDiffOn ℝ 1 (gradient f) U := - ((InnerProductSpace.toDual ℝ (E d)).symm.toContinuousLinearEquiv.contDiff.of_le - le_top).comp_contDiffOn hfderiv_C1 - have hDgrad_cont : ContinuousOn (fderiv ℝ (gradient f)) U := - (hgrad_C1.fderiv_of_isOpen hU_is_open - (show (0 : WithTop ℕ∞) + 1 ≤ 1 by norm_num)).continuousOn - simp only [hg_def, hessianQuadForm] - exact ((hDgrad_cont.comp continuousOn_fst (fun p hp => hp.1)).clm_apply - continuousOn_snd).inner continuousOn_snd - -- ── Local compactness: S ∩ closedBall(m⋆, r_loc) is compact ── - have : ProperSpace (E d) := FiniteDimensional.proper ℝ (E d) - have hm_star_U := hTub_sub.subset hm_star - obtain ⟨r_U, hr_U_pos, hr_U_sub⟩ := Metric.isOpen_iff.mp hTub_sub.isOpen m_star hm_star_U - set r_loc := min 1 (r_U / 2) with hr_loc_def - have hr_loc_pos : 0 < r_loc := lt_min one_pos (half_pos hr_U_pos) - have hr_loc_le1 : r_loc ≤ 1 := min_le_left _ _ - have hcball_sub_U : Metric.closedBall m_star r_loc ⊆ U := by - intro x hx - exact hr_U_sub (Metric.closedBall_subset_ball - (lt_of_le_of_lt (min_le_right 1 (r_U / 2)) (half_lt_self hr_U_pos)) hx) - set S_loc := S ∩ Metric.closedBall m_star r_loc - have hS_loc_compact : IsCompact S_loc := - hTub_sub.isCompact_inter_closedBall hcball_sub_U - have hSphere_compact' : IsCompact (Metric.sphere (0 : E d) 1) := isCompact_sphere 0 1 - have hSlxS_compact := hS_loc_compact.prod hSphere_compact' - have hSlxS_closed := hSlxS_compact.isClosed - have hSlxS_sub : S_loc ×ˢ Metric.sphere (0 : E d) 1 ⊆ U ×ˢ Set.univ := - Set.prod_mono (Set.inter_subset_left.trans hTub_sub.subset) (Set.subset_univ _) - -- ── Define N = {(m,ξ) ∈ S_loc × sphere | hessianQuadForm f m ξ ≥ μ} ── - -- N is compact: closed subset of compact S_loc × sphere - set N : Set (E d × E d) := - (S_loc ×ˢ Metric.sphere (0 : E d) 1) ∩ g ⁻¹' Set.Ici μ with hN_def - have hN_compact : IsCompact N := - hSlxS_compact.of_isClosed_subset - ((hg_contOn.mono hSlxS_sub).preimage_isClosed_of_isClosed hSlxS_closed isClosed_Ici) - Set.inter_subset_left - -- ── V_nbhd = (U ×ˢ univ) ∩ {(x,ξ) | hessianQuadForm f x ξ > μ'} is open ── - set V_nbhd : Set (E d × E d) := - (U ×ˢ Set.univ) ∩ g ⁻¹' Set.Ioi μ' with hV_def - have hV_open : IsOpen V_nbhd := - hg_contOn.isOpen_inter_preimage (hU_is_open.prod isOpen_univ) isOpen_Ioi - -- ── N ⊆ V_nbhd (since S_loc ⊆ S, hessianQuadForm ≥ μ > μ' on N) ── - have hN_sub : N ⊆ V_nbhd := by - intro ⟨x, ξ⟩ ⟨hmem, hge⟩ - exact ⟨hSlxS_sub hmem, by - simp only [Set.mem_preimage, Set.mem_Ioi, Set.mem_Ici] at hge ⊢; linarith⟩ - -- ── Thickening: ∃ δ > 0, thickening δ N ⊆ V_nbhd ── - obtain ⟨δ, hδ_pos, hthick⟩ := hN_compact.exists_thickening_subset_open hV_open hN_sub - -- ── V₁ = U ∩ ball(m⋆, min(δ, r_loc/2)): local neighborhood ── - set δ' := min δ (r_loc / 2) with hδ'_def - have hδ'_pos : 0 < δ' := lt_min hδ_pos (half_pos hr_loc_pos) - refine ⟨U ∩ Metric.ball m_star δ', - hTub_sub.isOpen.inter Metric.isOpen_ball, - ⟨hTub_sub.subset hm_star, Metric.mem_ball_self hδ'_pos⟩, - fun x ⟨hxU, hx_near⟩ ξ hξ_normal => ?_⟩ - -- Main bound - · by_cases hξ : ξ = 0 - · subst hξ; simp only [hessianQuadForm, map_zero, inner_self_eq_norm_sq_to_K, norm_zero, - ne_eq, OfNat.ofNat_ne_zero, not_false_eq_true, zero_pow, mul_zero, ge_iff_le, le_refl] - · have hξ_norm_pos : (0 : ℝ) < ‖ξ‖ := norm_pos_iff.mpr hξ - set c := ‖ξ‖ with hc_def - set ξ₀ := c⁻¹ • ξ with hξ₀_def - have hξ₀_norm : ‖ξ₀‖ = 1 := by - rw [hξ₀_def, norm_smul, norm_inv, norm_norm, - inv_mul_cancel₀ (ne_of_gt hξ_norm_pos)] - have hξ₀_sphere : ξ₀ ∈ Metric.sphere (0 : E d) 1 := by - rw [Metric.mem_sphere, dist_zero_right]; exact hξ₀_norm - -- fderiv ℝ π (π x) ξ₀ = 0 (linearity) - have hξ₀_normal : fderiv ℝ π (π x) ξ₀ = 0 := by - rw [hξ₀_def, map_smul, hξ_normal, smul_zero] - -- π(x) ∈ S - have hπ_in_S : π x ∈ S := (hπ_proj x hxU).1 - -- Derive: dist(x, m_star) < δ' ≤ r_loc/2, so π(x) ∈ S_loc - have hx_dist : dist x m_star < δ' := Metric.mem_ball.mp hx_near - have hinfDist_le : Metric.infDist x S ≤ dist x m_star := - Metric.infDist_le_dist_of_mem hm_star - have hπ_in_S_loc : π x ∈ S_loc := by - refine ⟨hπ_in_S, Metric.mem_closedBall.mpr ?_⟩ - have h1 := dist_triangle (π x) x m_star - rw [dist_comm (π x) x] at h1 - have h2 : dist x (π x) = Metric.infDist x S := (hπ_proj x hxU).2 - linarith [min_le_right δ (r_loc / 2)] - -- hessianQuadForm f (π x) ξ₀ ≥ μ (by h_normal_hess_M) - have hge_mu : hessianQuadForm f (π x) ξ₀ ≥ μ := by - have := h_normal_hess_M (π x) hπ_in_S ξ₀ hξ₀_normal - rw [hξ₀_norm, one_pow, mul_one] at this; exact this - -- (π(x), ξ₀) ∈ N - have hπξ_in_N : (π x, ξ₀) ∈ N := by - refine ⟨Set.mk_mem_prod hπ_in_S_loc hξ₀_sphere, ?_⟩ - simp only [Set.mem_preimage, Set.mem_Ici]; exact hge_mu - -- dist((x, ξ₀), (π(x), ξ₀)) = dist(x, π(x)) < δ - have hdist_pair : dist (x, ξ₀) (π x, ξ₀) = dist x (π x) := by - simp only [Prod.dist_eq, dist_self, dist_nonneg, sup_of_le_left] - have hx_near_π : dist x (π x) = Metric.infDist x S := (hπ_proj x hxU).2 - -- (x, ξ₀) ∈ thickening δ N - have h_in_thick : (x, ξ₀) ∈ Metric.thickening δ N := by - rw [Metric.mem_thickening_iff] - exact ⟨(π x, ξ₀), hπξ_in_N, by - rw [hdist_pair, hx_near_π]; linarith [min_le_left δ (r_loc / 2)]⟩ - -- hessianQuadForm f x ξ₀ > μ/4 - have hbound₀ : hessianQuadForm f x ξ₀ ≥ μ' := by - have hmem := (hthick h_in_thick).2 - simp only [Set.mem_preimage, Set.mem_Ioi] at hmem - linarith - -- ξ = c • ξ₀ - have hξ_eq : ξ = c • ξ₀ := by - rw [hξ₀_def, smul_smul, mul_inv_cancel₀ (ne_of_gt hξ_norm_pos), one_smul] - -- Homogeneity: hessianQuadForm f x ξ = c² * hessianQuadForm f x ξ₀ - have hhomog : hessianQuadForm f x ξ = c ^ 2 * hessianQuadForm f x ξ₀ := by - conv_lhs => rw [hξ_eq] - simp only [hessianQuadForm, map_smul, real_inner_smul_left, real_inner_smul_right] - ring - rw [hhomog] - have hc_sq_nonneg : (0 : ℝ) ≤ c ^ 2 := sq_nonneg c - nlinarith [hbound₀, hc_sq_nonneg] - -- Choose ε₀ = min 1 (√(μ/(4η))), which satisfies 0 < ε₀ ≤ √(μ/(4η)) + -- V₁: neighborhood of m⋆ where normal Hessian ≥ μ'‖ξ‖² (uses the gap μ - μ' > 0) + obtain ⟨V₁, hV₁_open, hm_V₁, h_normal_V₁⟩ := + exists_normal_hessian_neighborhood f hμ'_lt hTub_sub hf_C2 hπ_proj h_normal_hess_M hm_star + -- Choose ε₀ = min 1 (√(μ'/η)), which satisfies 0 < ε₀ ≤ √(μ'/η) let ε₀ : ℝ := min 1 (Real.sqrt (μ' / η)) have hε₀_pos : 0 < ε₀ := by exact lt_min one_pos (Real.sqrt_pos_of_pos (div_pos hμ' hη_pos)) have hε₀_le : ε₀ ≤ Real.sqrt (μ' / η) := min_le_right _ _ - -- V₂: neighborhood of S where D²f(x) ≽ -ε₀·I - -- (D²f(m) ≽ 0 on M extends to ≽ -ε₀ by continuity) - obtain ⟨V₂, hV₂_open, hm_V₂, h_hess_V₂⟩ : - ∃ V₂ : Set (E d), IsOpen V₂ ∧ m_star ∈ V₂ ∧ - ∀ x ∈ V₂, ∀ ξ : E d, - hessianQuadForm f x ξ ≥ -ε₀ * ‖ξ‖ ^ 2 := by - -- Strategy: hessianQuadForm ≥ 0 on compact S (PSD at minimizers). - -- Apply continuous_lower_bound_neighborhood on E d × E d with - -- K = S ×ˢ sphere to get ≥ -ε₀ on unit vectors near S. - -- Use generalized_tube_lemma to separate variables. - -- Extend to all ξ by quadratic homogeneity. - -- Step 1-2: hessianQuadForm ContinuousOn from C² - set g₂ : E d × E d → ℝ := fun p => hessianQuadForm f p.1 p.2 with hg₂_def - have hg₂_contOn : ContinuousOn g₂ (U ×ˢ Set.univ) := by - have hfderiv_C1 : ContDiffOn ℝ 1 (fderiv ℝ f) U := - hf_C2.fderiv_of_isOpen hU_is_open (show (1 : WithTop ℕ∞) + 1 ≤ 2 by norm_num) - have hgrad_C1 : ContDiffOn ℝ 1 (gradient f) U := - ((InnerProductSpace.toDual ℝ (E d)).symm.toContinuousLinearEquiv.contDiff.of_le - le_top).comp_contDiffOn hfderiv_C1 - have hDgrad_cont : ContinuousOn (fderiv ℝ (gradient f)) U := - (hgrad_C1.fderiv_of_isOpen hU_is_open - (show (0 : WithTop ℕ∞) + 1 ≤ 1 by norm_num)).continuousOn - simp only [hg₂_def, hessianQuadForm] - exact ((hDgrad_cont.comp continuousOn_fst (fun p hp => hp.1)).clm_apply - continuousOn_snd).inner continuousOn_snd - -- Step 3: S_loc₂ = S ∩ closedBall(m⋆, r_loc₂) is compact (local compactness) - have : ProperSpace (E d) := FiniteDimensional.proper ℝ (E d) - have hm_star_U₂ := hTub_sub.subset hm_star - obtain ⟨r_U₂, hr_U₂_pos, hr_U₂_sub⟩ := Metric.isOpen_iff.mp hTub_sub.isOpen m_star hm_star_U₂ - set r_loc₂ := min 1 (r_U₂ / 2) with hr_loc₂_def - have hr_loc₂_pos : 0 < r_loc₂ := lt_min one_pos (half_pos hr_U₂_pos) - have hcball₂_sub_U : Metric.closedBall m_star r_loc₂ ⊆ U := by - intro x hx - exact hr_U₂_sub (Metric.closedBall_subset_ball - (lt_of_le_of_lt (min_le_right 1 (r_U₂ / 2)) (half_lt_self hr_U₂_pos)) hx) - set S_loc₂ := S ∩ Metric.closedBall m_star r_loc₂ - have hS_loc₂_compact : IsCompact S_loc₂ := - hTub_sub.isCompact_inter_closedBall hcball₂_sub_U - -- Step 4: Unit sphere is compact (E d is finite-dimensional, hence proper) - have hSphere_compact : IsCompact (Metric.sphere (0 : E d) 1) := isCompact_sphere 0 1 - -- Step 5: hessianQuadForm ≥ 0 on S × sphere (PSD at minimizers) - have hg_K : ∀ p ∈ S ×ˢ Metric.sphere (0 : E d) 1, - (0 : ℝ) ≤ g₂ p := by - rintro ⟨x, ξ⟩ ⟨hx, -⟩ - exact h_hess_psd_M x hx ξ - -- Step 6: V_prod = (U ×ˢ univ) ∩ {p | g₂ p > -ε₀} is open, contains K = S × sphere - set V_prod : Set (E d × E d) := - (U ×ˢ Set.univ) ∩ g₂ ⁻¹' Set.Ioi (-ε₀) with hVp_def - have hV_prod_open : IsOpen V_prod := - hg₂_contOn.isOpen_inter_preimage (hU_is_open.prod isOpen_univ) isOpen_Ioi - have hK_V_prod : S ×ˢ Metric.sphere (0 : E d) 1 ⊆ V_prod := by - intro ⟨x, ξ⟩ ⟨hx, hξ⟩ - exact ⟨⟨hTub_sub.subset hx, Set.mem_univ _⟩, - by simp only [Set.mem_preimage, Set.mem_Ioi]; linarith [hg_K (x, ξ) ⟨hx, hξ⟩]⟩ - -- S_loc₂ ×ˢ sphere ⊆ V_prod (since S_loc₂ ⊆ S) - have hK_V_prod_loc : S_loc₂ ×ˢ Metric.sphere (0 : E d) 1 ⊆ V_prod := - (Set.prod_mono Set.inter_subset_left (le_refl _)).trans hK_V_prod - have hg_bound : ∀ p ∈ V_prod, (0 : ℝ) - ε₀ ≤ g₂ p := by - intro p ⟨_, hmem⟩ - simp only [Set.mem_preimage, Set.mem_Ioi] at hmem; linarith - -- Step 7: Apply generalized_tube_lemma with S_loc₂ (local compactness) - obtain ⟨V₂, W, hV₂_open, _, hSloc_V₂, hSphere_W, hVW⟩ := - generalized_tube_lemma hS_loc₂_compact hSphere_compact hV_prod_open hK_V_prod_loc - have hm_V₂ : m_star ∈ V₂ := - hSloc_V₂ ⟨hm_star, Metric.mem_closedBall_self (le_of_lt hr_loc₂_pos)⟩ - refine ⟨V₂, hV₂_open, hm_V₂, fun x hx ξ => ?_⟩ - -- Case ξ = 0: hessianQuadForm f x 0 = 0 ≥ 0 = -ε₀ * 0 - by_cases hξ : ξ = 0 - · subst hξ; simp only [hessianQuadForm, map_zero, inner_self_eq_norm_sq_to_K, norm_zero, - ne_eq, OfNat.ofNat_ne_zero, not_false_eq_true, zero_pow, mul_zero, ge_iff_le, le_refl] - · -- Case ξ ≠ 0: normalize to unit vector, apply bound, scale by ‖ξ‖² - have hξ_norm_pos : (0 : ℝ) < ‖ξ‖ := norm_pos_iff.mpr hξ - set c := ‖ξ‖ with hc_def - set ξ₀ := c⁻¹ • ξ with hξ₀_def - -- ‖ξ₀‖ = 1 - have hξ₀_norm : ‖ξ₀‖ = 1 := by - rw [hξ₀_def, norm_smul, norm_inv, norm_norm, - inv_mul_cancel₀ (ne_of_gt hξ_norm_pos)] - -- ξ₀ ∈ unit sphere - have hξ₀_sphere : ξ₀ ∈ Metric.sphere (0 : E d) 1 := by - rw [Metric.mem_sphere, dist_zero_right]; exact hξ₀_norm - -- (x, ξ₀) ∈ V₂ ×ˢ W ⊆ V_prod, so hessianQuadForm f x ξ₀ ≥ -ε₀ - have hbound₀ : hessianQuadForm f x ξ₀ ≥ -ε₀ := by - have := hg_bound (x, ξ₀) (hVW (Set.mk_mem_prod hx (hSphere_W hξ₀_sphere))) - linarith - -- ξ = c • ξ₀ - have hξ_eq : ξ = c • ξ₀ := by - rw [hξ₀_def, smul_smul, mul_inv_cancel₀ (ne_of_gt hξ_norm_pos), one_smul] - -- Homogeneity: hessianQuadForm f x ξ = c² * hessianQuadForm f x ξ₀ - have hhomog : hessianQuadForm f x ξ = c ^ 2 * hessianQuadForm f x ξ₀ := by - conv_lhs => rw [hξ_eq] - simp only [hessianQuadForm, map_smul, real_inner_smul_left, real_inner_smul_right] - ring - -- c² * hessianQuadForm f x ξ₀ ≥ c² * (-ε₀) = -ε₀ * ‖ξ‖² - rw [hhomog] - have hc_sq_nonneg : (0 : ℝ) ≤ c ^ 2 := sq_nonneg c - nlinarith [hbound₀, hc_sq_nonneg] + -- V₂: neighborhood of m⋆ where D²f(x) ≽ -ε₀·I + obtain ⟨V₂, hV₂_open, hm_V₂, h_hess_V₂⟩ := + exists_hessian_lower_neighborhood f hε₀_pos hTub_sub hf_C2 h_hess_psd_M hm_star -- ================================================================ -- Step 3: Construct fiber-saturated U₊ ⊂⊂ V₁ ∩ V₂ ∩ U -- ================================================================ - -- V₁ ∩ V₂ ∩ U is an open neighborhood of m_star (since m_star ∈ S ⊆ each). - -- By the tubular neighborhood structure, we extract a fiber-saturated - -- open set U₊ with compact closure inside V₁ ∩ V₂ ∩ U. - obtain ⟨U_plus, hU_open, hm_in, hU_compact, hU_cl_U, hU_convex, - hU_V₁, hU_V₂, hU_fiber_V₁, hU_fiber_U⟩ : - ∃ U_plus : Set (E d), IsOpen U_plus ∧ m_star ∈ U_plus ∧ - IsCompact (closure U_plus) ∧ closure U_plus ⊆ U ∧ - Convex ℝ U_plus ∧ - U_plus ⊆ V₁ ∧ U_plus ⊆ V₂ ∧ - (∀ x ∈ U_plus, ∀ t : ℝ, 0 ≤ t → t ≤ 1 → - π x + t • (x - π x) ∈ V₁) ∧ - (∀ x ∈ U_plus, ∀ t : ℝ, 0 ≤ t → t ≤ 1 → - π x + t • (x - π x) ∈ U) := by - -- V₁ ∩ V₂ ∩ U is open and contains m⋆ - have hW_open : IsOpen (V₁ ∩ V₂ ∩ U) := (hV₁_open.inter hV₂_open).inter hTub_sub.isOpen - have hm_in_W : m_star ∈ V₁ ∩ V₂ ∩ U := - ⟨⟨hm_V₁, hm_V₂⟩, hTub_sub.subset hm_star⟩ - obtain ⟨r, hr_pos, hball_sub⟩ := Metric.isOpen_iff.mp hW_open m_star hm_in_W - -- Take U₊ = B(m⋆, r/2) - refine ⟨Metric.ball m_star (r / 2), Metric.isOpen_ball, - Metric.mem_ball_self (by linarith), ?_, ?_, convex_ball _ _, ?_, ?_, ?_, ?_⟩ - -- (1) IsCompact (closure (ball m⋆ (r/2))): bounded in proper space - · exact Metric.isBounded_ball.isCompact_closure - -- (2) closure (ball m⋆ (r/2)) ⊆ U - · intro y hy - have h_in_cl : y ∈ Metric.closedBall m_star (r / 2) := - closure_minimal Metric.ball_subset_closedBall Metric.isClosed_closedBall hy - have : dist y m_star < r := - lt_of_le_of_lt (Metric.mem_closedBall.mp h_in_cl) (by linarith) - exact (hball_sub (Metric.mem_ball.mpr this)).2 - -- (3) ball m⋆ (r/2) ⊆ V₁ - · exact fun x hx => - (hball_sub (Metric.ball_subset_ball (by linarith : r / 2 ≤ r) hx)).1.1 - -- (4) ball m⋆ (r/2) ⊆ V₂ - · exact fun x hx => - (hball_sub (Metric.ball_subset_ball (by linarith : r / 2 ≤ r) hx)).1.2 - -- (5) fiber segments from ball(m_star, r/2) stay in V₁ - · intro x hx t ht0 ht1 - have hx_ball_r : x ∈ Metric.ball m_star r := - Metric.ball_subset_ball (by linarith : r / 2 ≤ r) hx - have hxU : x ∈ U := (hball_sub hx_ball_r).2 - obtain ⟨hπx_S, hπx_dist⟩ := hπ_proj x hxU - have hπx_ball : π x ∈ Metric.ball m_star r := by - rw [Metric.mem_ball] - have h1 : dist x (π x) < r / 2 := by - calc dist x (π x) = Metric.infDist x S := hπx_dist - _ ≤ dist x m_star := Metric.infDist_le_dist_of_mem hm_star - _ < r / 2 := Metric.mem_ball.mp hx - have h2 : dist x m_star < r / 2 := Metric.mem_ball.mp hx - linarith [dist_triangle (π x) x m_star, dist_comm (π x) x] - suffices π x + t • (x - π x) ∈ Metric.ball m_star r from - (hball_sub this).1.1 - have hy_eq : π x + t • (x - π x) = (1 - t) • π x + t • x := by - simp only [smul_sub, sub_smul, one_smul]; abel - rw [hy_eq] - exact convex_ball m_star r hπx_ball hx_ball_r (by linarith) ht0 (by linarith) - -- (6) fiber segments from ball(m_star, r/2) stay in U - · intro x hx t ht0 ht1 - have hx_ball_r : x ∈ Metric.ball m_star r := - Metric.ball_subset_ball (by linarith : r / 2 ≤ r) hx - have hxU : x ∈ U := (hball_sub hx_ball_r).2 - obtain ⟨hπx_S, hπx_dist⟩ := hπ_proj x hxU - have hπx_ball : π x ∈ Metric.ball m_star r := by - rw [Metric.mem_ball] - have h1 : dist x (π x) < r / 2 := by - calc dist x (π x) = Metric.infDist x S := hπx_dist - _ ≤ dist x m_star := Metric.infDist_le_dist_of_mem hm_star - _ < r / 2 := Metric.mem_ball.mp hx - have h2 : dist x m_star < r / 2 := Metric.mem_ball.mp hx - linarith [dist_triangle (π x) x m_star, dist_comm (π x) x] - suffices π x + t • (x - π x) ∈ Metric.ball m_star r from - (hball_sub this).2 - have hy_eq : π x + t • (x - π x) = (1 - t) • π x + t • x := by - simp only [smul_sub, sub_smul, one_smul]; abel - rw [hy_eq] - exact convex_ball m_star r hπx_ball hx_ball_r (by linarith) ht0 (by linarith) + obtain ⟨U_plus, hU_open, hm_in, hU_compact, hU_cl_W, hU_convex, hU_fiber_W⟩ := + exists_fiber_saturated_ball hπ_proj ((hV₁_open.inter hV₂_open).inter hU_is_open) + Set.inter_subset_right hm_star ⟨⟨hm_V₁, hm_V₂⟩, hTub_sub.subset hm_star⟩ + have hU_cl_U : closure U_plus ⊆ U := fun y hy => (hU_cl_W hy).2 + have hU_fiber_U : ∀ x ∈ U_plus, ∀ t : ℝ, 0 ≤ t → t ≤ 1 → + π x + t • (x - π x) ∈ U := fun x hx t ht0 ht1 => (hU_fiber_W x hx t ht0 ht1).2 obtain ⟨π', hπ'_proj, _, _, _, _, hπ'_fiber_dist, hπ'_normal, _, _, _⟩ := tubular_neighborhood_projection_Ed hTub_sub ⟨m_star, hm_star⟩ - have hπ_eq_U : ∀ x ∈ U, π x = π' x := by - intro x hxU - obtain ⟨p, hp, huniq⟩ := hTub_sub.uniqueProj x hxU - exact (huniq (π x) (hπ_proj x hxU)).trans - (huniq (π' x) ⟨(hπ'_proj x hxU).1, - by rw [dist_eq_norm]; exact (hπ'_proj x hxU).2⟩).symm + have hπ_eq_U : ∀ x ∈ U, π x = π' x := + projection_eq_of_isTubular hTub_sub hπ_proj hπ'_proj have hfderiv_normal : ∀ x ∈ U_plus, fderiv ℝ π (π x) (x - π x) = 0 := by intro x hx have hxU : x ∈ U := hU_cl_U (subset_closure hx) @@ -742,198 +657,40 @@ private abbrev localFiberwiseGeometryProof obtain ⟨p, hp, huniq⟩ := hTub_sub.uniqueProj y hyU exact (huniq (π y) (hπ_proj y hyU)).trans (huniq (π x) ⟨hm_S, by rw [dist_eq_norm]; exact h_realizes⟩).symm + -- Fiber path φ(t) = f(π(x) + t·(x − π(x))): quadratic growth and strong aiming, + -- since φ''(t) = eᵀ D²f(π x + t e) e ≥ μ'‖e‖² (e = x − π(x) is normal and the + -- fiber point lies in V₁ with the same projection π(x)). + have hfiber : ∀ x ∈ U_plus, + f x - fStar f ≥ μ' / 2 * ‖x - π x‖ ^ 2 ∧ + @inner ℝ _ _ (gradient f x) (x - π x) ≥ + f x - fStar f + μ' / 2 * ‖x - π x‖ ^ 2 := by + intro x hx + have hxU : x ∈ U := hU_cl_U (subset_closure hx) + have hm_S : π x ∈ S := (hπ_proj x hxU).1 + have hm_min : ∀ y, f (π x) ≤ f y := by rw [hM_argmin] at hm_S; exact hm_S + exact fiber_growth_and_aiming f hU_is_open hf_C2 hm_min (hgrad_zero _ hm_S) + (fun t ⟨ht0, ht1⟩ => hU_fiber_U x hx t ht0 ht1) + (fun t ht0 ht1 => h_normal_V₁ _ (hU_fiber_W x hx t ht0 ht1).1.1 (x - π x) (by + rw [hπ_fiber_const x hx t ht0 ht1] + exact hfderiv_normal x hx)) -- ================================================================ -- Step 4: Assemble the conclusion -- ================================================================ refine ⟨U_plus, ε₀, hU_open, hm_in, hU_compact, hU_cl_U, hU_convex, - hε₀_pos, hε₀_le, ?_, ?_, ?_, ?_, ?_, ?_⟩ - -- ---------------------------------------------------------------- + hε₀_pos, hε₀_le, ?_, ?_, ?_, ?_, ?_, hU_fiber_U⟩ -- (a) Normal Hessian lower bound: inherited from V₁ - -- ---------------------------------------------------------------- - · exact fun x hx ξ hξ => h_normal_V₁ x (hU_V₁ hx) ξ hξ - -- ---------------------------------------------------------------- - -- (b) Quadratic growth: f(x) - f⋆ ≥ (μ/8)·dist(x,S)² - -- ---------------------------------------------------------------- - · intro x hx - -- Define the fiber path φ(t) = f(π(x) + t·(x − π(x))) - set m := π x with hm_def - set e := x - m with he_def - set φ : ℝ → ℝ := fun t => f (m + t • e) with hφ_def - -- φ(0) = f(π(x)) = f⋆ since π(x) ∈ S = argmin f - have hφ0 : φ 0 = fStar f := by - simp only [hφ_def, zero_smul, add_zero] - have hxU : x ∈ U := hU_cl_U (subset_closure hx) - have hm_min : ∀ y, f m ≤ f y := by - have := (hπ_proj x hxU).1; rw [hM_argmin] at this; exact this - unfold fStar - exact le_antisymm (le_ciInf hm_min) - (ciInf_le ⟨f m, fun _ ⟨y, hy⟩ => hy ▸ hm_min y⟩ m) - -- φ(1) = f(m + 1·e) = f(m + (x − m)) = f(x) - have hφ1 : φ 1 = f x := by - simp only [hφ_def, one_smul, he_def]; congr 1; abel - -- φ'(0) = ⟨∇f(m), e⟩ = 0, since ∇f vanishes on S - have hxU : x ∈ U := hU_cl_U (subset_closure hx) - have hm_S : m ∈ S := (hπ_proj x hxU).1 - have hm_U : m ∈ U := hTub_sub.subset hm_S - have hf_diff_on : DifferentiableOn ℝ f U := - hf_C2.differentiableOn two_ne_zero - have hf_da : DifferentiableAt ℝ f m := - hf_diff_on.differentiableAt (hTub_sub.isOpen.mem_nhds hm_U) - have hφ'0 : deriv φ 0 = 0 := by - have hg : HasDerivAt (fun t : ℝ => m + t • e) e 0 := by - simpa [one_smul, zero_add] using ((hasDerivAt_id (0 : ℝ)).smul_const e).const_add m - have hf_da' : DifferentiableAt ℝ f (m + (0 : ℝ) • e) := by - simp only [zero_smul, add_zero]; exact hf_da - have key := hf_da'.hasFDerivAt.comp_hasDerivAt (0 : ℝ) hg - simp only [Function.comp_def] at key - rw [key.deriv, show m + (0 : ℝ) • e = m from by simp only [zero_smul, add_zero], - ← inner_gradient_left (𝕜 := ℝ) (f := f) (x := m) (y := e), - hgrad_zero m hm_S, inner_zero_left] - -- φ is C² at each point of [0,1] (fiber_path_C2at_on_segment) - have hseg_U : ∀ t : ℝ, t ∈ Set.Icc 0 1 → m + t • e ∈ U := by - intro t ⟨ht0, ht1⟩ - have : m + t • e = π x + t • (x - π x) := by simp only [hm_def, he_def] - rw [this] - exact hU_fiber_U x hx t ht0 ht1 - have hφ_C2at := fiber_path_C2at_on_segment f m e hU_is_open hf_C2 hseg_U - -- Derive local regularity from pointwise ContDiffAt ℝ 2 - have hφ_cont : ContinuousOn φ (Set.Icc 0 1) := - fun t ht => (hφ_C2at t ht).continuousAt.continuousWithinAt - have hφ_diffon : DifferentiableOn ℝ φ (Set.Ioo 0 1) := - fun t ht => ((hφ_C2at t (Set.Ioo_subset_Icc_self ht)).differentiableAt - (by norm_num : (2 : WithTop ℕ∞) ≠ 0)).differentiableWithinAt - have hφ'_cont : ContinuousOn (deriv φ) (Set.Icc 0 1) := by - intro t ht - have hfda := (hφ_C2at t ht).fderiv_right (show (1 : WithTop ℕ∞) + 1 ≤ 2 by norm_num) - have h_eq : deriv φ = fun s => fderiv ℝ φ s 1 := by - ext s; exact fderiv_apply_one_eq_deriv.symm - rw [h_eq]; exact (hfda.continuousAt.clm_apply continuousAt_const).continuousWithinAt - have hφ'_diffon : DifferentiableOn ℝ (deriv φ) (Set.Ioo 0 1) := by - intro t ht - have hfda := (hφ_C2at t (Set.Ioo_subset_Icc_self ht)).fderiv_right - (show (1 : WithTop ℕ∞) + 1 ≤ 2 by norm_num) - have hfda_diff := hfda.differentiableAt (show (1 : WithTop ℕ∞) ≠ 0 by norm_num) - have h_eq : deriv φ = fun s => fderiv ℝ φ s 1 := by - ext s; exact fderiv_apply_one_eq_deriv.symm - rw [h_eq]; exact (hfda_diff.clm_apply (differentiableAt_const _)).differentiableWithinAt - -- φ''(t) = eᵀ D²f(m+te) e ≥ (μ/4)‖e‖² (by normal Hessian bound on U₊, - -- since e = x − π(x) is a normal direction and m+te ∈ U₊ by fiber saturation) - have hφ''_lb : ∀ t, 0 ≤ t → t ≤ 1 → - deriv (deriv φ) t ≥ μ' * ‖e‖ ^ 2 := - fiber_path_hessian_lower_bound f μ' m e hU_is_open hf_C2 hseg_U - (fun t ht0 ht1 => by - exact h_normal_V₁ _ (hU_fiber_V₁ x hx t ht0 ht1) e (by - rw [hπ_fiber_const x hx t ht0 ht1] - exact hfderiv_normal x hx)) - -- By quadratic_growth_from_hessian: φ(1) − φ(0) ≥ ((μ/4)·‖e‖²)/2 - have hgrowth := quadratic_growth_from_hessian φ (μ' * ‖e‖ ^ 2) - hφ_cont hφ_diffon hφ'_cont hφ'_diffon hφ'0 hφ''_lb - rw [hφ1, hφ0] at hgrowth - -- dist(x, S) = ‖x − π(x)‖ = ‖e‖ by the projection property - have hdist : Metric.infDist x S = ‖e‖ := by - have hxU : x ∈ U := hU_cl_U (subset_closure hx) - rw [← (hπ_proj x hxU).2, dist_eq_norm] - rw [hdist] - have : μ' * ‖e‖ ^ 2 / 2 = μ' / 2 * ‖e‖ ^ 2 := by ring - linarith - -- ---------------------------------------------------------------- - -- (c) Strong aiming: ⟨∇f(x), x−π(x)⟩ ≥ f(x)−f⋆ + (μ/8)‖x−π(x)‖² - -- ---------------------------------------------------------------- + · exact fun x hx ξ hξ => h_normal_V₁ x (hU_cl_W (subset_closure hx)).1.1 ξ hξ + -- (b) Quadratic growth: dist(x, S) = ‖x − π(x)‖ by the projection property · intro x hx - -- Same fiber path as in (b) - set m := π x with hm_def - set e := x - m with he_def - set φ : ℝ → ℝ := fun t => f (m + t • e) with hφ_def - have hφ0 : φ 0 = fStar f := by - simp only [hφ_def, zero_smul, add_zero] - have hxU : x ∈ U := hU_cl_U (subset_closure hx) - have hm_min : ∀ y, f m ≤ f y := by - have := (hπ_proj x hxU).1; rw [hM_argmin] at this; exact this - unfold fStar - exact le_antisymm (le_ciInf hm_min) - (ciInf_le ⟨f m, fun _ ⟨y, hy⟩ => hy ▸ hm_min y⟩ m) - have hφ1 : φ 1 = f x := by - simp only [hφ_def, one_smul, he_def]; congr 1; abel have hxU : x ∈ U := hU_cl_U (subset_closure hx) - have hm_S : m ∈ S := (hπ_proj x hxU).1 - have hm_U : m ∈ U := hTub_sub.subset hm_S - have hf_diff_on : DifferentiableOn ℝ f U := - hf_C2.differentiableOn two_ne_zero - have hf_da_m : DifferentiableAt ℝ f m := - hf_diff_on.differentiableAt (hTub_sub.isOpen.mem_nhds hm_U) - have hf_da_x : DifferentiableAt ℝ f x := - hf_diff_on.differentiableAt (hTub_sub.isOpen.mem_nhds hxU) - have hφ'0 : deriv φ 0 = 0 := by - have hg : HasDerivAt (fun t : ℝ => m + t • e) e 0 := by - simpa [one_smul, zero_add] using ((hasDerivAt_id (0 : ℝ)).smul_const e).const_add m - have hf_da' : DifferentiableAt ℝ f (m + (0 : ℝ) • e) := by - simp only [zero_smul, add_zero]; exact hf_da_m - have key := hf_da'.hasFDerivAt.comp_hasDerivAt (0 : ℝ) hg - simp only [Function.comp_def] at key - rw [key.deriv, show m + (0 : ℝ) • e = m from by simp only [zero_smul, add_zero], - ← inner_gradient_left (𝕜 := ℝ) (f := f) (x := m) (y := e), - hgrad_zero m hm_S, inner_zero_left] - have hseg_U : ∀ t : ℝ, t ∈ Set.Icc 0 1 → m + t • e ∈ U := by - intro t ⟨ht0, ht1⟩ - have : m + t • e = π x + t • (x - π x) := by simp only [hm_def, he_def] - rw [this] - exact hU_fiber_U x hx t ht0 ht1 - have hφ_C2at := fiber_path_C2at_on_segment f m e hU_is_open hf_C2 hseg_U - have hφ_cont : ContinuousOn φ (Set.Icc 0 1) := - fun t ht => (hφ_C2at t ht).continuousAt.continuousWithinAt - have hφ_diffon : DifferentiableOn ℝ φ (Set.Ioo 0 1) := - fun t ht => ((hφ_C2at t (Set.Ioo_subset_Icc_self ht)).differentiableAt - (by norm_num : (2 : WithTop ℕ∞) ≠ 0)).differentiableWithinAt - have hφ'_cont : ContinuousOn (deriv φ) (Set.Icc 0 1) := by - intro t ht - have hfda := (hφ_C2at t ht).fderiv_right (show (1 : WithTop ℕ∞) + 1 ≤ 2 by norm_num) - have h_eq : deriv φ = fun s => fderiv ℝ φ s 1 := by - ext s; exact fderiv_apply_one_eq_deriv.symm - rw [h_eq]; exact (hfda.continuousAt.clm_apply continuousAt_const).continuousWithinAt - have hφ'_diffon : DifferentiableOn ℝ (deriv φ) (Set.Ioo 0 1) := by - intro t ht - have hfda := (hφ_C2at t (Set.Ioo_subset_Icc_self ht)).fderiv_right - (show (1 : WithTop ℕ∞) + 1 ≤ 2 by norm_num) - have hfda_diff := hfda.differentiableAt (show (1 : WithTop ℕ∞) ≠ 0 by norm_num) - have h_eq : deriv φ = fun s => fderiv ℝ φ s 1 := by - ext s; exact fderiv_apply_one_eq_deriv.symm - rw [h_eq]; exact (hfda_diff.clm_apply (differentiableAt_const _)).differentiableWithinAt - have hφ''_lb : ∀ t, 0 ≤ t → t ≤ 1 → - deriv (deriv φ) t ≥ μ' * ‖e‖ ^ 2 := - fiber_path_hessian_lower_bound f μ' m e hU_is_open hf_C2 hseg_U - (fun t ht0 ht1 => by - exact h_normal_V₁ _ (hU_fiber_V₁ x hx t ht0 ht1) e (by - rw [hπ_fiber_const x hx t ht0 ht1] - exact hfderiv_normal x hx)) - -- By strong_aiming_from_hessian: φ'(1) ≥ (φ(1)−φ(0)) + ((μ/4)·‖e‖²)/2 - have hsa := strong_aiming_from_hessian φ (μ' * ‖e‖ ^ 2) - hφ_cont hφ_diffon hφ'_cont hφ'_diffon hφ'0 hφ''_lb - -- φ'(1) = ⟨∇f(x), e⟩ by fiber_deriv - have hφ'1 : deriv φ 1 = @inner ℝ _ _ (gradient f x) e := by - have hg : HasDerivAt (fun t : ℝ => m + t • e) e 1 := by - simpa [one_smul] using ((hasDerivAt_id (1 : ℝ)).smul_const e).const_add m - have hme1 : m + (1 : ℝ) • e = x := by simp only [he_def, one_smul, add_sub_cancel] - have hf_da' : DifferentiableAt ℝ f (m + (1 : ℝ) • e) := by rw [hme1]; exact hf_da_x - have key := hf_da'.hasFDerivAt.comp_hasDerivAt (1 : ℝ) hg - simp only [Function.comp_def] at key - rw [key.deriv, hme1] - exact (inner_gradient_left (𝕜 := ℝ) (f := f) (x := x) (y := e)).symm - rw [hφ1, hφ0, hφ'1] at hsa - -- e = x − π(x), so the inner products match; convert (c/2) form - have : μ' * ‖e‖ ^ 2 / 2 = μ' / 2 * ‖e‖ ^ 2 := by ring - linarith - -- ---------------------------------------------------------------- + rw [← (hπ_proj x hxU).2, dist_eq_norm] + exact (hfiber x hx).1 + -- (c) Strong aiming + · exact fun x hx => (hfiber x hx).2 -- (d) Hessian lower bound D²f(x) ≽ −ε₀·I: inherited from V₂ - -- ---------------------------------------------------------------- - · exact fun x hx ξ => h_hess_V₂ x (hU_V₂ hx) ξ - -- ---------------------------------------------------------------- + · exact fun x hx ξ => h_hess_V₂ x (hU_cl_W (subset_closure hx)).1.2 ξ -- (e) Normal Hessian ≥ μ at m_star (from Step 1) - -- ---------------------------------------------------------------- · exact h_normal_hess_M m_star hm_star - -- ---------------------------------------------------------------- - -- (f) Fiber segments from U₊ stay in U - -- ---------------------------------------------------------------- - · exact hU_fiber_U /-- Public theorem wrapper for `localFiberwiseGeometryProof`. -/ diff --git a/LeanPool/PLAcceleratedNesterovLean/Convergence/LyapunovContraction/GenMain.lean b/LeanPool/PLAcceleratedNesterovLean/Convergence/LyapunovContraction/GenMain.lean index 7574f52e19..3547dbfe5a 100644 --- a/LeanPool/PLAcceleratedNesterovLean/Convergence/LyapunovContraction/GenMain.lean +++ b/LeanPool/PLAcceleratedNesterovLean/Convergence/LyapunovContraction/GenMain.lean @@ -32,8 +32,375 @@ open scoped Topology NNReal open Manifold -private abbrev lyapunovContractionGenProof - {d : ℕ} (_hd : 0 < d) +/-- Descent at the look-ahead point: a gradient step from a point well inside the ball +`B(m⋆, r₀) ⊆ U₊` decreases `f` by at least `(η/2)·‖∇f‖²`. -/ +private theorem descent_at_lookahead {d : ℕ} (f : E d → ℝ) + (L : ℝ≥0) (hL : 0 < (L : ℝ)) (η : ℝ) (hη : η = 1 / (L : ℝ)) + (U_plus : Set (E d)) (hU_open : IsOpen U_plus) + (hf_diff_on : DifferentiableOn ℝ f U_plus) + (hf_lip : LipschitzOnWith L (gradient f) U_plus) + (m_star : E d) (hm_star_Up : m_star ∈ U_plus) (hg_zero : gradient f m_star = 0) + (r₀ : ℝ) (hball_sub : Metric.ball m_star r₀ ⊆ U_plus) + (x'n : E d) (hx'_r09 : dist x'n m_star < r₀ / 9) : + f (x'n - η • gradient f x'n) ≤ f x'n - η / 2 * ‖gradient f x'n‖ ^ 2 := by + have hdist_nn := dist_nonneg (x := x'n) (y := m_star) + have hx'_Up : x'n ∈ U_plus := hball_sub (Metric.mem_ball.mpr (by linarith)) + have hgrad_lip' : ‖gradient f x'n‖ ≤ (↑L : ℝ) * dist x'n m_star := by + have h := hf_lip.dist_le_mul x'n hx'_Up m_star hm_star_Up + rwa [hg_zero, dist_zero_right] at h + have hseg_x'n : ∀ t : ℝ, 0 ≤ t → t ≤ 1 → + x'n + t • (-(((1 : ℝ) / (L : ℝ)) • gradient f x'n)) ∈ U_plus := by + intro t ht0 ht1 + apply hball_sub; rw [Metric.mem_ball] + have h_step_bound : dist (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gradient f x'n))) x'n ≤ + dist x'n m_star := by + rw [dist_eq_norm, + show (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gradient f x'n))) - x'n = + t • (-(((1 : ℝ) / (↑L : ℝ)) • gradient f x'n)) from by abel, + norm_smul, norm_neg, norm_smul, Real.norm_eq_abs, + abs_of_nonneg ht0, Real.norm_eq_abs, + abs_of_pos (div_pos one_pos hL)] + calc t * ((1 : ℝ) / (↑L : ℝ) * ‖gradient f x'n‖) + ≤ 1 * ((1 : ℝ) / (↑L : ℝ) * ((↑L : ℝ) * dist x'n m_star)) := + mul_le_mul ht1 + (mul_le_mul_of_nonneg_left hgrad_lip' + (le_of_lt (div_pos one_pos hL))) + (mul_nonneg (le_of_lt (div_pos one_pos hL)) (norm_nonneg _)) + one_pos.le + _ = dist x'n m_star := by + rw [one_mul, ← mul_assoc, one_div_mul_cancel (ne_of_gt hL), one_mul] + calc dist (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gradient f x'n))) m_star + ≤ dist (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gradient f x'n))) x'n + + dist x'n m_star := + dist_triangle _ _ _ + _ ≤ 2 * dist x'n m_star := by linarith [h_step_bound] + _ < 2 * (r₀ / 9) := by linarith [hx'_r09] + _ < r₀ := by linarith + exact lsmooth_descent_at f L hL hU_open hf_diff_on hf_lip x'n hx'_Up hseg_x'n η hη + +/-- The gradient step moves the position by at most the distance of the look-ahead point +to `m⋆`: `dist(x_{n+1}, m⋆) ≤ 2·dist(x'_n, m⋆)`. -/ +private theorem nesterovStep_dist_le_two_mul {d : ℕ} (f : E d → ℝ) + (L : ℝ≥0) (η ρ : ℝ) (hη_pos : 0 < η) (hηL : η * (L : ℝ) = 1) + (U_plus : Set (E d)) (hf_lip : LipschitzOnWith L (gradient f) U_plus) + (m_star : E d) (hm_star_Up : m_star ∈ U_plus) (hg_zero : gradient f m_star = 0) + (sn : NesterovState d) (hx'_Up : sn.lookahead η ∈ U_plus) : + dist (nesterovStep f η ρ sn).x m_star ≤ 2 * dist (sn.lookahead η) m_star := by + have h_sn1_x : (nesterovStep f η ρ sn).x = + sn.lookahead η - η • gradient f (sn.lookahead η) := rfl + rw [h_sn1_x] + generalize sn.lookahead η = x'n at hx'_Up ⊢ + have hgrad_lip : ‖gradient f x'n‖ ≤ (L : ℝ) * dist x'n m_star := by + have h := hf_lip.dist_le_mul x'n hx'_Up m_star hm_star_Up + rwa [hg_zero, dist_zero_right] at h + have h_step_dist : dist (x'n - η • gradient f x'n) x'n = η * ‖gradient f x'n‖ := by + rw [dist_eq_norm] + have : (x'n - η • gradient f x'n) - x'n = -(η • gradient f x'n) := by abel + rw [this, norm_neg, norm_smul, Real.norm_eq_abs, abs_of_pos hη_pos] + calc dist (x'n - η • gradient f x'n) m_star + ≤ dist (x'n - η • gradient f x'n) x'n + dist x'n m_star := dist_triangle _ _ _ + _ = η * ‖gradient f x'n‖ + dist x'n m_star := by rw [h_step_dist] + _ ≤ η * ((L : ℝ) * dist x'n m_star) + dist x'n m_star := by + linarith [mul_le_mul_of_nonneg_left hgrad_lip (le_of_lt hη_pos)] + _ = 2 * dist x'n m_star := by + have : η * ((L : ℝ) * dist x'n m_star) = dist x'n m_star := by + rw [← mul_assoc, hηL, one_mul] + linarith + +/-- Distance bound for the next look-ahead point. Uses the identity +`x'_{n+1} = (1+ρ)·x_{n+1} - ρ·x_n` and the triangle inequality: +`dist(x'_{n+1}, m⋆) ≤ (1+ρ)·dist(x_{n+1}, m⋆) + ρ·dist(x_n, m⋆) < (2 + 3ρ)·r < 5r`. -/ +private theorem nesterovStep_lookahead_dist_lt {d : ℕ} (f : E d → ℝ) + (η ρ : ℝ) (hη_pos : 0 < η) (hρ_pos : 0 < ρ) (hρ_lt1 : ρ < 1) + (m_star : E d) (r : ℝ) (sn : NesterovState d) + (hx : dist sn.x m_star < r) (hx1 : dist (nesterovStep f η ρ sn).x m_star < 2 * r) : + dist ((nesterovStep f η ρ sn).lookahead η) m_star < 5 * r := by + set sn1 := nesterovStep f η ρ sn with hsn1 + set x'n := sn.lookahead η with hx'n + set gn := gradient f x'n with hgn + have hr_pos : 0 < r := lt_of_le_of_lt dist_nonneg hx + -- Key identity: x'_{n+1} = (1+ρ)·x_{n+1} - ρ·x_n + have h_conv : sn1.lookahead η = (1 + ρ) • sn1.x - ρ • sn.x := by + change sn1.x + Real.sqrt η • sn1.v = (1 + ρ) • sn1.x - ρ • sn.x + have hsq : Real.sqrt η * Real.sqrt η = η := + Real.mul_self_sqrt (le_of_lt hη_pos) + have h5 : Real.sqrt η • (ρ • (sn.v - Real.sqrt η • gn)) = + ρ • (Real.sqrt η • sn.v - η • gn) := by + rw [smul_comm (Real.sqrt η) ρ, smul_sub, ← mul_smul, hsq] + change (x'n - η • gn) + Real.sqrt η • (ρ • (sn.v - Real.sqrt η • gn)) = + (1 + ρ) • (x'n - η • gn) - ρ • sn.x + rw [h5] + change (sn.x + Real.sqrt η • sn.v - η • gn) + + ρ • (Real.sqrt η • sn.v - η • gn) = + (1 + ρ) • (sn.x + Real.sqrt η • sn.v - η • gn) - ρ • sn.x + module + -- Subtract m_star using the convex combination identity + have h_sub : sn1.lookahead η - m_star = + (1 + ρ) • (sn1.x - m_star) - ρ • (sn.x - m_star) := by + rw [h_conv]; module + calc dist (sn1.lookahead η) m_star + = ‖sn1.lookahead η - m_star‖ := dist_eq_norm _ _ + _ = ‖(1 + ρ) • (sn1.x - m_star) - ρ • (sn.x - m_star)‖ := by + rw [h_sub] + _ ≤ ‖(1 + ρ) • (sn1.x - m_star)‖ + ‖ρ • (sn.x - m_star)‖ := + norm_sub_le _ _ + _ = (1 + ρ) * ‖sn1.x - m_star‖ + ρ * ‖sn.x - m_star‖ := by + rw [norm_smul, norm_smul, Real.norm_eq_abs, abs_of_pos (by linarith : (0:ℝ) < 1 + ρ), + Real.norm_eq_abs, abs_of_pos hρ_pos] + _ = (1 + ρ) * dist sn1.x m_star + ρ * dist sn.x m_star := by + simp only [dist_eq_norm] + _ < (1 + ρ) * (2 * r) + ρ * r := by + have h1 : (1 + ρ) * dist sn1.x m_star < (1 + ρ) * (2 * r) := + mul_lt_mul_of_pos_left hx1 (by linarith : (0:ℝ) < 1 + ρ) + have h2 : ρ * dist sn.x m_star < ρ * r := + mul_lt_mul_of_pos_left hx hρ_pos + linarith + _ < 5 * r := by + have h3 : ρ * r < r := mul_lt_of_lt_one_left hr_pos hρ_lt1 + linarith + +/-- **Flat-case assembly.** The heart of the Lyapunov contraction in the flat case: +with `w = (1-a)·P⊥v + √μ'·e - √η·P⊥g`, combining descent, aiming, the segment estimate +and the tangential identity yields +`F_{n+1} + ‖w‖²/2 + T_{n+1} ≤ (1-a)·(F_n + U_n/2 + T_n) + a·|⟨g, Pe⟩|`. -/ +private theorem flat_case_bound {d : ℕ} (P : E d →L[ℝ] E d) + (hP_self_adj : ∀ x y : E d, @inner ℝ _ _ (P x) y = @inner ℝ _ _ x (P y)) + (hP_idem : ∀ x : E d, P (P x) = P x) + (μ' η ε a : ℝ) (hμ' : 0 < μ') (hη_pos : 0 < η) (hε_pos : 0 < ε) + (hε_bound : ε * η ≤ a) (ha : a = Real.sqrt (μ' * η)) (ha_lt1 : a < 1) + (v g e w : E d) + (hwn_eq : w = (1 - a) • (v - P v) + Real.sqrt μ' • e - Real.sqrt η • (g - P g)) + (Fn Fn1 Fnprime : ℝ) (hgap_nn : 0 ≤ Fn) (hgap'_nn : 0 ≤ Fn1) (hFnprime_nn : 0 ≤ Fnprime) + (h_f_upper : Fn1 ≤ Fnprime - η / 2 * ‖g‖ ^ 2) + (h_aim : @inner ℝ _ _ g e ≥ Fnprime + μ' / 2 * ‖e‖ ^ 2) + (h_seg : @inner ℝ _ _ g (Real.sqrt η • v) ≥ + Fnprime - Fn - ε / 2 * ‖Real.sqrt η • v‖ ^ 2) : + Fn1 + ‖w‖ ^ 2 / 2 + (1 - a) / 2 * ‖P v - Real.sqrt η • P g‖ ^ 2 ≤ + (1 - a) * (Fn + ‖(v - P v) + Real.sqrt μ' • e‖ ^ 2 / 2 + + (1 + a) ^ 2 / (2 * (1 - a)) * ‖P v‖ ^ 2) + a * |@inner ℝ _ _ g (P e)| := by + have ha_pos : 0 < a := ha ▸ Real.sqrt_pos_of_pos (mul_pos hμ' hη_pos) + -- ═══ B: Projector-freezing decomposition ═══ + -- ⟨g, e⟩ = ⟨P⊥g, e⟩ + ⟨g, Pe⟩ (via self-adjointness of P) + have h_ipGE_decomp : @inner ℝ _ _ g e = + @inner ℝ _ _ (g - P g) e + @inner ℝ _ _ g (P e) := by + have hsplit : g = (g - P g) + P g := by abel + conv_lhs => rw [hsplit] + rw [inner_add_left, hP_self_adj g e] + have hG_pyth := pythagorean_proj P hP_self_adj hP_idem g + have hV_pyth := pythagorean_proj P hP_self_adj hP_idem v + have h_ip_decomp := inner_proj_decomp P hP_self_adj hP_idem g v + -- ═══ D: Norm expansions ═══ + have h_wn_sq : ‖w‖ ^ 2 = + (1 - a) ^ 2 * ‖v - P v‖ ^ 2 + μ' * ‖e‖ ^ 2 + + η * ‖g - P g‖ ^ 2 + + 2 * (1 - a) * Real.sqrt μ' * @inner ℝ _ _ (v - P v) e - + 2 * (1 - a) * Real.sqrt η * @inner ℝ _ _ (v - P v) (g - P g) - + 2 * Real.sqrt μ' * Real.sqrt η * @inner ℝ _ _ e (g - P g) := by + rw [hwn_eq] + exact norm_three_term_sq _ _ _ _ _ _ (le_of_lt hμ') (le_of_lt hη_pos) + have h_un_eq : ‖(v - P v) + Real.sqrt μ' • e‖ ^ 2 = ‖v - P v‖ ^ 2 + + 2 * Real.sqrt μ' * @inner ℝ _ _ (v - P v) e + μ' * ‖e‖ ^ 2 := by + rw [norm_two_term_sq _ _ _ (le_of_lt hμ')]; ring + have h_sqrt_prod : Real.sqrt μ' * Real.sqrt η = a := by + rw [ha, ← Real.sqrt_mul (le_of_lt hμ')] + -- Key coefficient identity: 2·√μ'·√η = 2·a (for norm simplification) + have h2a : 2 * Real.sqrt μ' * Real.sqrt η = 2 * a := by + have : (2 : ℝ) * Real.sqrt μ' * Real.sqrt η = + 2 * (Real.sqrt μ' * Real.sqrt η) := by ring + rw [this, h_sqrt_prod] + -- ═══ H: Apply flat_case_arithmetic ═══ + -- Descent bound: Fn1 ≤ Fnprime - η/2·(‖Pg‖² + ‖P⊥g‖²) + have hFn1_descent : Fn1 ≤ Fnprime - η / 2 * (‖P g‖ ^ 2 + ‖g - P g‖ ^ 2) := by + rw [← hG_pyth]; exact h_f_upper + -- Segment: √η·(⟨Pg,Pv⟩ + ⟨P⊥g,P⊥v⟩) ≥ Fnprime - Fn - εη/2·(‖Pv‖² + ‖P⊥v‖²) + have h_segment_arith : + Real.sqrt η * (@inner ℝ _ _ (P g) (P v) + + @inner ℝ _ _ (g - P g) (v - P v)) ≥ + Fnprime - Fn - ε * η / 2 * (‖P v‖ ^ 2 + ‖v - P v‖ ^ 2) := by + have h1 := h_seg + rw [inner_smul_right, norm_smul, Real.norm_eq_abs, + abs_of_nonneg (Real.sqrt_nonneg η), mul_pow, Real.sq_sqrt (le_of_lt hη_pos)] at h1 + rw [h_ip_decomp, hV_pyth] at h1 + linarith + -- Aiming: ⟨P⊥g, e⟩ ≥ Fnprime + μ'/2·‖e‖² − |⟨g, Pe⟩| (projector-freezing error) + have h_aiming_arith : @inner ℝ _ _ (g - P g) e ≥ + Fnprime + μ' / 2 * ‖e‖ ^ 2 - abs (@inner ℝ _ _ g (P e)) := by + have hle := le_abs_self (@inner ℝ _ _ g (P e)) + linarith [h_ipGE_decomp] + -- w norm identity (with √μ'·√η = a) + have hwn_sq_arith : ‖w‖ ^ 2 = + (1 - a) ^ 2 * ‖v - P v‖ ^ 2 + μ' * ‖e‖ ^ 2 + + η * ‖g - P g‖ ^ 2 + + 2 * (1 - a) * Real.sqrt μ' * @inner ℝ _ _ (v - P v) e - + 2 * (1 - a) * Real.sqrt η * @inner ℝ _ _ (g - P g) (v - P v) - + 2 * a * @inner ℝ _ _ (g - P g) e := by + rw [h_wn_sq, h2a, real_inner_comm (g - P g) e, real_inner_comm (g - P g) (v - P v)] + -- T_{n+1} identity (matching flat_case_arithmetic parameter order) + have hTn1_arith : (1 - a) / 2 * ‖P v - Real.sqrt η • P g‖ ^ 2 = + (1 - a) / 2 * ‖P v‖ ^ 2 - (1 - a) * Real.sqrt η * @inner ℝ _ _ (P g) (P v) + + (1 - a) * η / 2 * ‖P g‖ ^ 2 := by + rw [norm_sub_sq_real, inner_smul_right, norm_smul, Real.norm_eq_abs, + abs_of_nonneg (Real.sqrt_nonneg _), mul_pow, Real.sq_sqrt (le_of_lt hη_pos), + real_inner_comm (P g) (P v)] + ring + exact flat_case_arithmetic a ha_pos ha_lt1 + η μ' (Real.sqrt μ') (Real.sqrt η) + hη_pos hμ' (Real.sqrt_nonneg _) (Real.sqrt_nonneg _) + (Real.sq_sqrt (le_of_lt hμ')) (Real.sq_sqrt (le_of_lt hη_pos)) + h_sqrt_prod + (ε * η) (mul_nonneg (le_of_lt hε_pos) (le_of_lt hη_pos)) hε_bound + Fn Fn1 Fnprime hgap_nn hgap'_nn hFnprime_nn + (‖P v‖ ^ 2) (‖v - P v‖ ^ 2) (‖P g‖ ^ 2) (‖g - P g‖ ^ 2) (‖e‖ ^ 2) + (sq_nonneg _) (sq_nonneg _) (sq_nonneg _) (sq_nonneg _) (sq_nonneg _) + (@inner ℝ _ _ (g - P g) e) (@inner ℝ _ _ (P g) (P v)) + (@inner ℝ _ _ (g - P g) (v - P v)) (@inner ℝ _ _ (v - P v) e) + (abs (@inner ℝ _ _ g (P e))) (abs_nonneg _) + hFn1_descent h_segment_arith h_aiming_arith + (‖w‖ ^ 2) hwn_sq_arith + _ h_un_eq + _ hTn1_arith + _ rfl + +/-- **One-step contraction for a single state.** Given the descent, aiming and segment +estimates at the look-ahead point and the perturbation absorption bound for the state `sn`, +the Lyapunov function contracts: `L(s_{n+1}) ≤ (1 - (1-θ)·a)·L(sₙ)`. -/ +private theorem lyapunovOfState_step_le {d : ℕ} (f : E d → ℝ) + (μ' : ℝ) (hμ' : 0 < μ') (θ : ℝ) (hθ_pos : 0 < θ) (hθ_lt1 : θ < 1) + (η : ℝ) (hη_pos : 0 < η) (ha_lt1 : Real.sqrt (μ' * η) < 1) + (ρ : ℝ) (hρ : ρ = (1 - Real.sqrt (μ' * η)) / (1 + Real.sqrt (μ' * η))) + (π : E d → E d) (P : E d →L[ℝ] E d) + (hP_self_adj : ∀ x y : E d, @inner ℝ _ _ (P x) y = @inner ℝ _ _ x (P y)) + (hP_idem : ∀ x : E d, P (P x) = P x) + (ε : ℝ) (hε_pos : 0 < ε) (hε_bound : ε * η ≤ Real.sqrt (μ' * η)) + (hbdd : BddBelow (Set.range f)) (sn : NesterovState d) + (h_descent : f (nesterovStep f η ρ sn).x ≤ + f (sn.lookahead η) - η / 2 * ‖gradient f (sn.lookahead η)‖ ^ 2) + (h_aim : @inner ℝ _ _ (gradient f (sn.lookahead η)) (sn.lookahead η - π (sn.lookahead η)) ≥ + f (sn.lookahead η) - fStar f + μ' / 2 * ‖sn.lookahead η - π (sn.lookahead η)‖ ^ 2) + (h_seg : @inner ℝ _ _ (gradient f (sn.lookahead η)) (sn.lookahead η - sn.x) ≥ + f (sn.lookahead η) - f sn.x - ε / 2 * ‖sn.lookahead η - sn.x‖ ^ 2) + (h_absorb : + let gn := gradient f (sn.lookahead η) + let en := sn.lookahead η - π (sn.lookahead η) + let ξn := curvatureErrorOfState (↑P) π f η ρ sn + let wn := auxVarOfState P μ' π η (nesterovStep f η ρ sn) - Real.sqrt μ' • ξn + let a := Real.sqrt (μ' * η) + Real.sqrt μ' * @inner ℝ _ _ wn ξn + (Real.sqrt μ') ^ 2 / 2 * ‖ξn‖ ^ 2 + + a * |@inner ℝ _ _ gn (P en)| ≤ θ * a * lyapunovOfState P μ' π f η sn) : + let a := Real.sqrt (μ' * η) + lyapunovOfState P μ' π f η (nesterovStep f η ρ sn) ≤ + (1 - (1 - θ) * a) * lyapunovOfState P μ' π f η sn := by + intro a + set sn1 := nesterovStep f η ρ sn with hsn1 + set x'n := sn.lookahead η with hx'n + set gn := gradient f x'n with hgn + have ha_pos : 0 < a := Real.sqrt_pos_of_pos (mul_pos hμ' hη_pos) + have hρ_pos : 0 < ρ := by rw [hρ]; apply div_pos <;> linarith + have hgap_nn : 0 ≤ f sn.x - fStar f := + sub_nonneg.mpr (ciInf_le hbdd sn.x) + have hgap'_nn : 0 ≤ f sn1.x - fStar f := + sub_nonneg.mpr (ciInf_le hbdd sn1.x) + -- Parameter positivity + have h1a_pos : (0 : ℝ) < 1 + a := by linarith + have h1a_ne : (1 + a : ℝ) ≠ 0 := ne_of_gt h1a_pos + have h1ma_ne : (1 - a : ℝ) ≠ 0 := ne_of_gt (by linarith) + -- λ = (1+a)²/(2(1-a)) > 0 + have hlam_pos : (0 : ℝ) < (1 + a) ^ 2 / (2 * (1 - a)) := + div_pos (sq_pos_of_pos h1a_pos) (by linarith) + -- Ln ≥ 0 + have hLn_nn : 0 ≤ lyapunovOfState P μ' π f η sn := by + simp only [lyapunovOfState] + have hlam_nn : 0 ≤ (1 + Real.sqrt (μ' * η)) ^ 2 / (2 * (1 - Real.sqrt (μ' * η))) := + le_of_lt hlam_pos + have h1 := sq_nonneg ‖auxVarOfState P μ' π η sn‖ + have h2 := mul_nonneg hlam_nn (sq_nonneg ‖P sn.v‖) + linarith + -- ══════════════ Tangential velocity identity ══════════════ + -- P is a CLM, so P(sn1.v) = ρ • (P sn.v - √η • P gn) + have hPv1 : P sn1.v = ρ • (P sn.v - Real.sqrt η • P gn) := by + change P (ρ • (sn.v - Real.sqrt η • gn)) = ρ • (P sn.v - Real.sqrt η • P gn) + rw [map_smul, map_sub, map_smul] + -- λ‖P sn1.v‖² = ((1-a)/2) ‖P sn.v - √η • P gn‖² + have hTn1_eq : (1 + a) ^ 2 / (2 * (1 - a)) * ‖P sn1.v‖ ^ 2 = + (1 - a) / 2 * ‖P sn.v - Real.sqrt η • P gn‖ ^ 2 := by + rw [hPv1, norm_smul, Real.norm_eq_abs, abs_of_pos hρ_pos, mul_pow, ← mul_assoc] + congr 1 + exact lambda_rho_sq a ρ _ h1a_ne h1ma_ne hρ rfl + -- ══════════════ Lyapunov decomposition ══════════════ + -- Abbreviate the Lyapunov components at steps n and n+1. + set lam := (1 + a) ^ 2 / (2 * (1 - a)) with hlam_def + set Fn := f sn.x - fStar f with hFn_def + set Un := ‖auxVarOfState P μ' π η sn‖ ^ 2 with hUn_def + set Tn := lam * ‖P sn.v‖ ^ 2 with hTn_def + set un1 := auxVarOfState P μ' π η sn1 with hun1_def + set Fn1 := f sn1.x - fStar f with hFn1_def + set Un1 := ‖un1‖ ^ 2 with hUn1_def + set Tn1 := lam * ‖P sn1.v‖ ^ 2 with hTn1_def + -- Lyapunov decomposition identities + have hLn_eq : lyapunovOfState P μ' π f η sn = Fn + Un / 2 + Tn := by + unfold lyapunovOfState; rfl + have hLn'_eq : lyapunovOfState P μ' π f η sn1 = Fn1 + Un1 / 2 + Tn1 := by + unfold lyapunovOfState; rfl + -- ── Define intermediate quantities ── + let ξn := curvatureErrorOfState (↑P) π f η ρ sn + let wn := un1 - Real.sqrt μ' • ξn + -- ── AuxVar decomposition: u_{n+1} = w_n + √μ'·ξ_n ── + have h_un1_eq : un1 = wn + Real.sqrt μ' • ξn := by + change un1 = (un1 - Real.sqrt μ' • ξn) + Real.sqrt μ' • ξn + abel + -- ── Perturbation expansion ── + have h_Un1_expand : Un1 = + ‖wn‖ ^ 2 + 2 * Real.sqrt μ' * @inner ℝ _ _ wn ξn + + (Real.sqrt μ') ^ 2 * ‖ξn‖ ^ 2 := by + change ‖un1‖ ^ 2 = _ + rw [h_un1_eq] + exact perturbation_expansion wn ξn (Real.sqrt μ') + -- ── Curvature perturbation δ ── + set δ_curv := Real.sqrt μ' * @inner ℝ _ _ wn ξn + + (Real.sqrt μ') ^ 2 / 2 * ‖ξn‖ ^ 2 with hδ_def + -- ── Perturbation splitting: Un1/2 = ‖wn‖²/2 + δ_curv ── + have h_Un1_half : Un1 / 2 = ‖wn‖ ^ 2 / 2 + δ_curv := by + rw [h_Un1_expand]; ring + -- ── Flat-case assembly (Step A core) ── + have h_flat : Fn1 + ‖wn‖ ^ 2 / 2 + Tn1 ≤ + (1 - a) * (Fn + Un / 2 + Tn) + a * abs (@inner ℝ _ _ gn (P (x'n - π x'n))) := by + -- wn decomposition via the auxiliary-variable recursion + have hwn_eq : (wn : E d) = (1 - a) • (sn.v - P sn.v) + + Real.sqrt μ' • (x'n - π x'n) - Real.sqrt η • (gn - P gn) := by + change un1 - Real.sqrt μ' • ξn = _ + have h_av := auxVarOfState_step P μ' η ρ π f sn hρ ha_pos hη_pos hμ' + have : (un1 : E d) = ((1 - a) • (sn.v - P sn.v) + Real.sqrt μ' • (x'n - π x'n) - + Real.sqrt η • (gn - P gn)) + Real.sqrt μ' • ξn := by + change auxVarOfState P μ' π η (nesterovStep f η ρ sn) = _; exact h_av + rw [this]; abel + have h_diff_eq : x'n - sn.x = Real.sqrt η • sn.v := by + change sn.x + Real.sqrt η • sn.v - sn.x = _; abel + have hTn1_val : Tn1 = (1 - a) / 2 * ‖P sn.v - Real.sqrt η • P gn‖ ^ 2 := by + rw [hTn1_def]; exact hTn1_eq + rw [hTn1_val] + refine flat_case_bound P hP_self_adj hP_idem μ' η ε a hμ' hη_pos hε_pos hε_bound rfl + ha_lt1 sn.v gn (x'n - π x'n) wn hwn_eq Fn Fn1 (f x'n - fStar f) hgap_nn hgap'_nn + (sub_nonneg.mpr (ciInf_le hbdd x'n)) (by linarith [h_descent]) (by linarith [h_aim]) ?_ + rw [← h_diff_eq]; linarith [h_seg] + -- ── Final assembly ── + apply two_step_contraction_general a θ _ _ + (δ_curv + a * abs (@inner ℝ _ _ gn (P (x'n - π x'n)))) + ha_pos ha_lt1 hθ_pos hθ_lt1 hLn_nn + · -- Goal: Ln' ≤ (1-a) * Ln + (δ_curv + proj_err_n) + rw [hLn'_eq, hLn_eq] + linarith [h_Un1_half, h_flat] + · -- Goal: (δ_curv + proj_err_n) ≤ θ * a * Ln + exact h_absorb + +/-- **State-based Lyapunov contraction.** + +After shrinking Ω and R if necessary, for every state `sₙ` satisfying the perturbation +absorption bound, whenever xₙ, x'ₙ ∈ Ω and Lₙ ≤ R²: + L_{n+1} ≤ (1 - (1-θ)·a) · L_n +and x_{n+1}, x'_{n+1} ∈ Ω⁺. Both `lyapunov_contraction_gen` and `lyapunov_contraction` +are instances of this single-step statement. -/ +theorem lyapunov_contraction_of_state + {d : ℕ} -- The objective function (f : E d → ℝ) -- Parameters @@ -47,8 +414,6 @@ private abbrev lyapunovContractionGenProof (hM_argmin : S = argminSet f) -- Nearest-point projection (π : E d → E d) - (_hπ_in_S : ∀ x, π x ∈ S) - (_hπ_proj : ∀ x ∈ S, π x = x) -- Gradient vanishes on S (hgrad_zero : ∀ x ∈ S, gradient f x = 0) -- Tangent projector P = Dπ(m⋆) @@ -69,11 +434,8 @@ private abbrev lyapunovContractionGenProof @inner ℝ _ _ (gradient f x) (x - π x) ≥ f x - fStar f + μ' / 2 * ‖x - π x‖ ^ 2) -- Hessian lower bound on U₊ (from `local_fiberwise_geometry`) - (hHess_lower : ∀ x ∈ U_plus, ∀ ξ : E d, + (_hHess_lower : ∀ x ∈ U_plus, ∀ ξ : E d, hessianQuadForm f x ξ ≥ -ε * ‖ξ‖ ^ 2) - -- Normal Hessian on projection fibers: Dπ(π x) · e = 0 → e lies in normal space - (_hπ_kills_normal : ∀ x ∈ U_plus, - fderiv ℝ π (π x) (x - π x) = 0) -- P is self-adjoint (orthogonal projector property) (hP_self_adj : ∀ x y : E d, @inner ℝ _ _ (P x) y = @inner ℝ _ _ x (P y)) -- P is idempotent (orthogonal projector property) @@ -84,55 +446,30 @@ private abbrev lyapunovContractionGenProof (∀ t : ℝ, 0 ≤ t → t ≤ 1 → (1 - t) • z + t • x ∈ U_plus) → @inner ℝ _ _ (gradient f x) (x - z) ≥ f x - f z - ε / 2 * ‖x - z‖ ^ 2) - -- Total perturbation absorption (curvature + projector-freezing error) - -- δ_curv = curvature perturbation, proj_err = a·|⟨g, Pe⟩| from projector freezing - -- R_abs is the energy/spatial radius: iterates must be in B(m⋆, R_abs) with Ln ≤ R_abs². - (R_abs : ℝ) (hR_abs : 0 < R_abs) - (h_curv_absorb : ∀ (s₀ : NesterovState d) (n : ℕ), - (nesterovSeqGen f η ρ s₀ n).x ∈ Metric.ball m_star R_abs → - (nesterovSeqGen f η ρ s₀ n).lookahead η ∈ Metric.ball m_star R_abs → - lyapunovOfState P μ' π f η (nesterovSeqGen f η ρ s₀ n) ≤ R_abs ^ 2 → - let sn := nesterovSeqGen f η ρ s₀ n - let gn := gradient f (sn.lookahead η) - let en := sn.lookahead η - π (sn.lookahead η) - let ξn := curvatureErrorOfState (↑P) π f η ρ sn - let un1 := auxVarOfState P μ' π η (nesterovStep f η ρ sn) - let wn := un1 - Real.sqrt μ' • ξn - let δ_curv := Real.sqrt μ' * @inner ℝ _ _ wn ξn + - (Real.sqrt μ') ^ 2 / 2 * ‖ξn‖ ^ 2 - let a := Real.sqrt (μ' * η) - let Ln := lyapunovOfState P μ' π f η sn - let proj_err := a * |@inner ℝ _ _ gn (P en)| - δ_curv + proj_err ≤ θ * a * Ln) - : - -- Conclusion: ∃ Ω, R (independent of starting point) such that contraction holds + -- R_abs is the energy/spatial radius on which the absorption bound is available. + (R_abs : ℝ) (hR_abs : 0 < R_abs) : ∃ (Ω Ω_plus : Set (E d)) (R : ℝ), IsOpen Ω ∧ IsOpen Ω_plus ∧ 0 < R ∧ m_star ∈ Ω ∧ Ω ⊆ Ω_plus ∧ Ω_plus ⊆ U_plus ∧ - -- For all starting points and iterations with the right preconditions - ∀ (s₀ : NesterovState d) (n : ℕ), - let s := nesterovSeqGen f η ρ s₀ n - let s' := nesterovSeqGen f η ρ s₀ (n + 1) - let Ln := lyapunovOfState P μ' π f η s - let Ln' := lyapunovOfState P μ' π f η s' + ∀ (sn : NesterovState d), + let sn1 := nesterovStep f η ρ sn + let Ln := lyapunovOfState P μ' π f η sn + let Ln' := lyapunovOfState P μ' π f η sn1 let a := Real.sqrt (μ' * η) - s.x ∈ Ω → s.lookahead η ∈ Ω → Ln ≤ R ^ 2 → + -- Total perturbation absorption (curvature + projector-freezing error) at `sn` + (sn.x ∈ Metric.ball m_star R_abs → sn.lookahead η ∈ Metric.ball m_star R_abs → + Ln ≤ R_abs ^ 2 → + let gn := gradient f (sn.lookahead η) + let en := sn.lookahead η - π (sn.lookahead η) + let ξn := curvatureErrorOfState (↑P) π f η ρ sn + let wn := auxVarOfState P μ' π η sn1 - Real.sqrt μ' • ξn + Real.sqrt μ' * @inner ℝ _ _ wn ξn + (Real.sqrt μ') ^ 2 / 2 * ‖ξn‖ ^ 2 + + a * |@inner ℝ _ _ gn (P en)| ≤ θ * a * Ln) → + sn.x ∈ Ω → sn.lookahead η ∈ Ω → Ln ≤ R ^ 2 → -- Contraction Ln' ≤ (1 - (1 - θ) * a) * Ln ∧ -- Next iterates in Ω⁺ - s'.x ∈ Ω_plus ∧ s'.lookahead η ∈ Ω_plus := by - /- - Proof roadmap for the one-step contraction. - - Choose concentric neighborhoods Ω ⊂ Ω₊ ⊂ U₊ around m⋆ and an energy - radius R. For each state with xₙ, x'ₙ ∈ Ω and Lₙ ≤ R²: - * descent gives f(x_{n+1}) ≤ f(x'_n) − (η/2)‖gₙ‖²; - * the identity (1+a)ρ = 1−a rewrites the velocity update; - * the normal terms complete the square into (1−a)/2 · ‖uₙ‖²; - * the function values telescope to (1−a)(f(xₙ)−f⋆); - * curvature and projector-freezing errors are absorbed using the θ-budget, - producing Lₙ₊₁ ≤ (1 - (1-θ)a)Lₙ. - -/ + sn1.x ∈ Ω_plus ∧ sn1.lookahead η ∈ Ω_plus := by -- ═══════════════════════════════════════════════════════════════ -- Neighborhood construction -- ═══════════════════════════════════════════════════════════════ @@ -142,7 +479,7 @@ private abbrev lyapunovContractionGenProof -- Auxiliary inequalities for the chosen radii have hr₀9 : (0 : ℝ) < r₀ / 9 := by linarith have hR_min : (0 : ℝ) < min (r₀ / 9) R_abs := lt_min hr₀9 hR_abs - -- Ω = B(m⋆, min(r₀/9, R_abs)) — ensures iterates are in B(m⋆, R_abs) for h_curv_absorb + -- Ω = B(m⋆, min(r₀/9, R_abs)) — ensures iterates are in B(m⋆, R_abs) for the absorption have hΩ_sub_r09 : Metric.ball m_star (min (r₀ / 9) R_abs) ⊆ Metric.ball m_star (r₀ / 9) := Metric.ball_subset_ball (min_le_left _ _) @@ -172,531 +509,64 @@ private abbrev lyapunovContractionGenProof -- ═══════════════════════════════════════════════════════════════ -- Main contraction argument -- ═══════════════════════════════════════════════════════════════ - intro s₀ n sn sn1 Ln Ln' a hx_in hx'_in hLn_bound - -- Additional convenient abbreviations - let x'n := sn.lookahead η - let gn := gradient f x'n - let en := normalDispOfState π η sn - let un := auxVarOfState P μ' π η sn - -- ───────────────────────────────────────────────────────────── - -- Step 1 (Descent): f(x_{n+1}) ≤ f(x'_n) − (η/2)·‖g_n‖² - -- ───────────────────────────────────────────────────────────── - have h_descent : f sn1.x ≤ f x'n - η / 2 * ‖gn‖ ^ 2 := by - -- sn1.x = x'n - η • gn by definition of nesterovStep/nesterovSeq - have hx_eq : sn1.x = x'n - η • gn := rfl - rw [hx_eq] - have hx'_Up : x'n ∈ U_plus := hΩp_sub_Up (hΩ_sub_Ωp hx'_in) - have hx'_r09 : dist x'n m_star < r₀ / 9 := - Metric.mem_ball.mp (hΩ_sub_r09 hx'_in) - have hg_zero' : gradient f m_star = 0 := hgrad_zero m_star hm_star - have hgrad_lip' : ‖gn‖ ≤ (↑L : ℝ) * dist x'n m_star := by - have h := hf_lip.dist_le_mul x'n hx'_Up m_star hm_star_Up - rwa [hg_zero', dist_zero_right] at h - have hseg_x'n : ∀ t : ℝ, 0 ≤ t → t ≤ 1 → - x'n + t • (-(((1 : ℝ) / (L : ℝ)) • gradient f x'n)) ∈ U_plus := by - intro t ht0 ht1 - apply hball_sub; rw [Metric.mem_ball] - have h_step_bound : dist (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gn))) x'n ≤ - dist x'n m_star := by - rw [dist_eq_norm, - show (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gn))) - x'n = - t • (-(((1 : ℝ) / (↑L : ℝ)) • gn)) from by abel, - norm_smul, norm_neg, norm_smul, Real.norm_eq_abs, - abs_of_nonneg ht0, Real.norm_eq_abs, - abs_of_pos (div_pos one_pos hL)] - calc t * ((1 : ℝ) / (↑L : ℝ) * ‖gn‖) - ≤ 1 * ((1 : ℝ) / (↑L : ℝ) * ((↑L : ℝ) * dist x'n m_star)) := - mul_le_mul ht1 - (mul_le_mul_of_nonneg_left hgrad_lip' - (le_of_lt (div_pos one_pos hL))) - (mul_nonneg (le_of_lt (div_pos one_pos hL)) (norm_nonneg _)) - one_pos.le - _ = dist x'n m_star := by - rw [one_mul, ← mul_assoc, one_div_mul_cancel (ne_of_gt hL), one_mul] - calc dist (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gn))) m_star - ≤ dist (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gn))) x'n + dist x'n m_star := - dist_triangle _ _ _ - _ ≤ 2 * dist x'n m_star := by linarith [h_step_bound] - _ < 2 * (r₀ / 9) := by linarith [hx'_r09] - _ < r₀ := by linarith - exact lsmooth_descent_at f L hL hU_open hf_diff_on hf_lip x'n hx'_Up hseg_x'n η hη - -- ───────────────────────────────────────────────────────────── - -- Step 2 (Parameter identities) - -- ───────────────────────────────────────────────────────────── - have ha_pos : 0 < a := by - exact Real.sqrt_pos_of_pos (mul_pos hμ' hη_pos) + intro sn sn1 Ln Ln' a h_curv_absorb hx_in hx'_in hLn_bound + have hg_zero_mstar : gradient f m_star = 0 := hgrad_zero m_star hm_star + have hηL : η * (L : ℝ) = 1 := by rw [hη]; field_simp + have hx'_ball_r09 : dist (sn.lookahead η) m_star < r₀ / 9 := + lt_of_lt_of_le (Metric.mem_ball.mp hx'_in) (min_le_left _ _) + have hx_ball_r09 : dist sn.x m_star < r₀ / 9 := + lt_of_lt_of_le (Metric.mem_ball.mp hx_in) (min_le_left _ _) + have hx'n_Up : sn.lookahead η ∈ U_plus := hΩp_sub_Up (hΩ_sub_Ωp hx'_in) + have ha_pos : 0 < a := Real.sqrt_pos_of_pos (mul_pos hμ' hη_pos) have ha_lt1 : a < 1 := by have hle : (0 : ℝ) ≤ μ' * η := le_of_lt (mul_pos hμ' hη_pos) calc a = Real.sqrt (μ' * η) := rfl - _ < Real.sqrt 1 := Real.sqrt_lt_sqrt hle (by linarith) + _ < Real.sqrt 1 := Real.sqrt_lt_sqrt hle hμη_lt1 _ = 1 := Real.sqrt_one - have h_rho_id : (1 + a) * ρ = 1 - a := by - have h1a : (0 : ℝ) < 1 + a := by linarith - exact rho_identity a ρ h1a.ne' hρ - -- ───────────────────────────────────────────────────────────── - -- Step 3 (Complete the square for normal terms) - -- ((1-a)/2)·‖v‖² + (1-a)·√μ'·⟨v,e⟩ + ((1-a)·μ'/2)·‖e‖² - -- = ((1-a)/2)·‖v + √μ'·e‖² = ((1-a)/2)·‖uₙ‖² - -- ───────────────────────────────────────────────────────────── - have h_complete_sq : ∀ (v e : E d), - (1 - a) / 2 * ‖v‖ ^ 2 + - (1 - a) * Real.sqrt μ' * @inner ℝ _ _ v e + - (1 - a) * (Real.sqrt μ') ^ 2 / 2 * ‖e‖ ^ 2 = - (1 - a) / 2 * ‖v + Real.sqrt μ' • e‖ ^ 2 := by - intro v e - exact complete_square_normal v e (1 - a) (Real.sqrt μ') (by linarith) - -- ───────────────────────────────────────────────────────────── - -- Step 4 (Function-value telescoping) - -- (f'−f⋆) − (1−a)(f'−f) − a(f'−f⋆) = (1−a)(f−f⋆) - -- ───────────────────────────────────────────────────────────── - have h_func : ∀ f' fv : ℝ, - (f' - fStar f) - (1 - a) * (f' - fv) - a * (f' - fStar f) = - (1 - a) * (fv - fStar f) := - fun f' fv => function_value_collection f' fv (fStar f) a - -- ───────────────────────────────────────────────────────────── - -- Step 5 (Perturbation expansion + Cauchy–Schwarz) - -- ‖w + c·ξ‖² = ‖w‖² + 2c⟨w,ξ⟩ + c²‖ξ‖² - -- |⟨w,ξ⟩| ≤ ‖w‖·‖ξ‖ - -- ───────────────────────────────────────────────────────────── - have h_perturb : ∀ (w ξ : E d) (c : ℝ), - ‖w + c • ξ‖ ^ 2 = - ‖w‖ ^ 2 + 2 * c * @inner ℝ _ _ w ξ + c ^ 2 * ‖ξ‖ ^ 2 := - fun w ξ c => perturbation_expansion w ξ c - have h_cs : ∀ (w ξ : E d), - |@inner ℝ _ _ w ξ| ≤ ‖w‖ * ‖ξ‖ := - fun w ξ => inner_abs_le_norm_mul w ξ - -- ───────────────────────────────────────────────────────────── - -- Step 6 (Velocity coefficient bounds from Step 1 helpers) - -- ───────────────────────────────────────────────────────────── - have h_vel_coeff : ∀ (εη : ℝ), 0 ≤ εη → εη ≤ a → - (1 - a) ^ 2 + εη * (1 - a) ≤ 1 - a := - fun εη hεη hb => velocity_normal_coeff a εη (le_of_lt ha_pos) (le_of_lt ha_lt1) hεη hb - have h_tang_coeff : (1 - a) * (1 + a) ≤ (1 + a) ^ 2 := - tangential_coeff a (le_of_lt ha_pos) - -- ═══════════════════════════════════════════════════════════════ - -- Shared facts (used by multiple cases) - -- ═══════════════════════════════════════════════════════════════ - have hg_zero_mstar : gradient f m_star = 0 := hgrad_zero m_star hm_star - have hηL : η * (L : ℝ) = 1 := by rw [hη]; field_simp - have hx'_ball_r09 : dist x'n m_star < r₀ / 9 := - lt_of_lt_of_le (Metric.mem_ball.mp hx'_in) (min_le_left _ _) have hρ_pos : 0 < ρ := by rw [hρ]; apply div_pos <;> linarith - -- ═══════════════════════════════════════════════════════════════ - -- Assemble the three conclusions - -- ═══════════════════════════════════════════════════════════════ + -- Step 1 (Descent): f(x_{n+1}) ≤ f(x'_n) − (η/2)·‖g_n‖² + have h_descent := descent_at_lookahead f L hL η hη U_plus hU_open hf_diff_on hf_lip + m_star hm_star_Up hg_zero_mstar r₀ hball_sub (sn.lookahead η) hx'_ball_r09 + -- Distance bound on x_{n+1}: dist(x_{n+1}, m⋆) ≤ 2·dist(x'_n, m⋆) + have h_sn1_dist := nesterovStep_dist_le_two_mul f L η ρ hη_pos hηL U_plus hf_lip + m_star hm_star_Up hg_zero_mstar sn hx'n_Up refine ⟨?contraction, ?x_next_in, ?x'_next_in⟩ case contraction => - /- Combining Steps 1–6: - Descent (Step 1) bounds f(x_{n+1}). - The ρ-identity (Step 2) rewrites the velocity recursion. - Completing the square (Step 3) recombines normal terms → (1−a)/2·‖uₙ‖². - Function telescoping (Step 4) yields (1−a)(f(xₙ)−f⋆). - Perturbation + Cauchy–Schwarz (Step 5) absorb ξₙ when R is small. - Velocity bounds (Step 6) confirm coefficient contraction. - Together: L_{n+1} ≤ (1 − a/2) · Lₙ. -/ - -- Membership for applying strong aiming and Hessian bound - have hx'n_Up : x'n ∈ U_plus := hΩp_sub_Up (hΩ_sub_Ωp hx'_in) - -- Strong aiming: ⟨∇f(x'_n), e_n⟩ ≥ f(x'_n) - f⋆ + μ'/2 ‖e_n‖² - have h_aim : @inner ℝ _ _ (gradient f x'n) (x'n - π x'n) ≥ - f x'n - fStar f + μ' / 2 * ‖x'n - π x'n‖ ^ 2 := - hStrAim x'n hx'n_Up - -- f-value descent from Step 1 - have h_f_upper : f sn1.x - fStar f ≤ f x'n - fStar f - η / 2 * ‖gn‖ ^ 2 := by - linarith [h_descent] - -- Hessian perturbation control at x'_n - have h_hess_x' : ∀ ξ : E d, hessianQuadForm f x'n ξ ≥ -ε * ‖ξ‖ ^ 2 := - hHess_lower x'n hx'n_Up - -- ══════════════ Nonnegativity infrastructure ══════════════ -- BddBelow for fStar - have hmin : ∀ y, f m_star ≤ f y := by - intro y; exact (hM_argmin ▸ hm_star : m_star ∈ argminSet f) y have hbdd : BddBelow (Set.range f) := - ⟨f m_star, by rintro _ ⟨x, rfl⟩; exact hmin x⟩ - have hgap_nn : 0 ≤ f sn.x - fStar f := - sub_nonneg.mpr (ciInf_le hbdd sn.x) - have hgap'_nn : 0 ≤ f sn1.x - fStar f := - sub_nonneg.mpr (ciInf_le hbdd sn1.x) - -- Parameter positivity - have h1a_pos : (0 : ℝ) < 1 + a := by linarith - have h1a_ne : (1 + a : ℝ) ≠ 0 := ne_of_gt h1a_pos - have h1ma_pos : (0 : ℝ) < 1 - a := by linarith - have h1ma_ne : (1 - a : ℝ) ≠ 0 := ne_of_gt h1ma_pos - -- λ = (1+a)²/(2(1-a)) > 0 - have hlam_pos : (0 : ℝ) < (1 + a) ^ 2 / (2 * (1 - a)) := - div_pos (sq_pos_of_pos h1a_pos) (by linarith) - -- Ln ≥ 0 - have hLn_nn : 0 ≤ Ln := by - change 0 ≤ lyapunovOfState P μ' π f η sn - simp only [lyapunovOfState] - have hlam_nn : 0 ≤ (1 + Real.sqrt (μ' * η)) ^ 2 / (2 * (1 - Real.sqrt (μ' * η))) := - le_of_lt hlam_pos - have h1 := sq_nonneg ‖auxVarOfState P μ' π η sn‖ - have h2 := mul_nonneg hlam_nn (sq_nonneg ‖P sn.v‖) - linarith - -- ══════════════ Tangential velocity identity ══════════════ - -- P is a CLM, so P(sn1.v) = ρ • (P sn.v - √η • P gn) - have hPv1 : P sn1.v = ρ • (P sn.v - Real.sqrt η • P gn) := by - change P (ρ • (sn.v - Real.sqrt η • gn)) = ρ • (P sn.v - Real.sqrt η • P gn) - rw [map_smul, map_sub, map_smul] - -- λ‖P sn1.v‖² = ((1-a)/2) ‖P sn.v - √η • P gn‖² - have hTn1_eq : (1 + a) ^ 2 / (2 * (1 - a)) * ‖P sn1.v‖ ^ 2 = - (1 - a) / 2 * ‖P sn.v - Real.sqrt η • P gn‖ ^ 2 := by - rw [hPv1, norm_smul, Real.norm_eq_abs, abs_of_pos hρ_pos, mul_pow, ← mul_assoc] - congr 1 - exact lambda_rho_sq a ρ _ h1a_ne h1ma_ne hρ rfl - -- ══════════════ Aiming gives function descent bound ══════════════ - -- From descent + aiming: Fn' ≤ ⟨gn, en⟩ - μ'/2 ‖en‖² - η/2 ‖gn‖² - have hFn'_bound : f sn1.x - fStar f ≤ - @inner ℝ _ _ gn (x'n - π x'n) - μ' / 2 * ‖x'n - π x'n‖ ^ 2 - - η / 2 * ‖gn‖ ^ 2 := - function_descent_with_aiming _ _ _ _ _ _ _ h_f_upper h_aim - -- ══════════════ Lyapunov decomposition ══════════════ - -- Abbreviate the Lyapunov components at steps n and n+1. - set lam := (1 + a) ^ 2 / (2 * (1 - a)) with hlam_def - set Fn := f sn.x - fStar f with hFn_def - set Un := ‖un‖ ^ 2 with hUn_def - set Tn := lam * ‖P sn.v‖ ^ 2 with hTn_def - set un1 := auxVarOfState P μ' π η (nesterovStep f η ρ sn) with hun1_def - set Fn1 := f sn1.x - fStar f with hFn1_def - set Un1 := ‖un1‖ ^ 2 with hUn1_def - set Tn1 := lam * ‖P sn1.v‖ ^ 2 with hTn1_def - -- Lyapunov decomposition identities - have hLn_eq : Ln = Fn + Un / 2 + Tn := by - change lyapunovOfState P μ' π f η sn = Fn + Un / 2 + Tn - unfold lyapunovOfState; rfl - have hLn'_eq : Ln' = Fn1 + Un1 / 2 + Tn1 := by - change lyapunovOfState P μ' π f η (nesterovStep f η ρ sn) = Fn1 + Un1 / 2 + Tn1 - unfold lyapunovOfState; rfl - -- Nonnegativity - have hTn_nn : 0 ≤ Tn := mul_nonneg (le_of_lt hlam_pos) (sq_nonneg _) - have hTn1_nn : 0 ≤ Tn1 := mul_nonneg (le_of_lt hlam_pos) (sq_nonneg _) - -- ══════════════ Tangential energy identity ══════════════ - -- hTn1_eq: lam * ‖P sn1.v‖² = (1-a)/2 * ‖Pv - √η·Pg‖² - -- Restate in terms of Tn1: - have hTn1_val : Tn1 = (1 - a) / 2 * ‖P sn.v - Real.sqrt η • P gn‖ ^ 2 := by - rw [hTn1_def]; exact hTn1_eq - -- Expand ‖Pv - √η·Pg‖² for later use: - have h_expand : ‖P sn.v - Real.sqrt η • P gn‖ ^ 2 = - ‖P sn.v‖ ^ 2 - 2 * @inner ℝ _ _ (P sn.v) (Real.sqrt η • P gn) + - ‖Real.sqrt η • P gn‖ ^ 2 := by rw [norm_sub_sq_real] - have h_inner : @inner ℝ _ _ (P sn.v) (Real.sqrt η • P gn) = - Real.sqrt η * @inner ℝ _ _ (P sn.v) (P gn) := by rw [inner_smul_right] - have h_norm_smul : ‖Real.sqrt η • P gn‖ ^ 2 = η * ‖P gn‖ ^ 2 := by - rw [norm_smul, Real.norm_eq_abs, abs_of_nonneg (Real.sqrt_nonneg _), mul_pow, - Real.sq_sqrt (le_of_lt hη_pos)] - -- λ ≥ 1/2 (ensures ‖Pv‖² ≤ 2·Tn, used for coercivity bounds) - have hlam_ge_half : (1 : ℝ) / 2 ≤ lam := by - rw [hlam_def] - have h2ma : (0 : ℝ) < 2 * (1 - a) := by linarith - rw [div_le_div_iff₀ two_pos h2ma] - have h_asq := sq_nonneg a - linarith - -- ── Contraction assembly ── - -- Two-step: (A) L_{n+1} ≤ (1-a)·L_n + δ, (B) δ ≤ (a/2)·L_n → L_{n+1} ≤ (1-a/2)·L_n - - -- ── Define intermediate quantities ── - let ξn := curvatureErrorOfState (↑P) π f η ρ sn - let wn := un1 - Real.sqrt μ' • ξn - -- ── AuxVar decomposition: u_{n+1} = w_n + √μ'·ξ_n ── - have h_un1_eq : un1 = wn + Real.sqrt μ' • ξn := by - change un1 = (un1 - Real.sqrt μ' • ξn) + Real.sqrt μ' • ξn - abel - -- ── Perturbation expansion ── - have h_Un1_expand : Un1 = - ‖wn‖ ^ 2 + 2 * Real.sqrt μ' * @inner ℝ _ _ wn ξn + - (Real.sqrt μ') ^ 2 * ‖ξn‖ ^ 2 := by - change ‖un1‖ ^ 2 = _ - rw [h_un1_eq] - exact perturbation_expansion wn ξn (Real.sqrt μ') - -- ── Curvature perturbation δ ── - set δ_curv := Real.sqrt μ' * @inner ℝ _ _ wn ξn + - (Real.sqrt μ') ^ 2 / 2 * ‖ξn‖ ^ 2 with hδ_def - -- ── Perturbation splitting: Un1/2 = ‖wn‖²/2 + δ_curv ── - have h_Un1_half : Un1 / 2 = ‖wn‖ ^ 2 / 2 + δ_curv := by - rw [h_Un1_expand]; ring - -- ── Flat-case assembly (Step A core) ── - -- This is the heart of the Lyapunov contraction in the flat case. - -- Mathematically: the auxiliary variable recursion gives - -- w_n = (1-a)·P⊥v_n + √μ'·e_n - √η·P⊥g_n - -- and combining with descent, aiming, and the tangential identity yields - -- F_{n+1} + ‖w_n‖²/2 + T_{n+1} ≤ (1-a)·(F_n + U_n/2 + T_n) - have h_flat : Fn1 + ‖wn‖ ^ 2 / 2 + Tn1 ≤ - (1 - a) * (Fn + Un / 2 + Tn) + a * abs (@inner ℝ _ _ gn (P en)) := by - -- ═══ A: wn decomposition via auxVar_recursion ═══ - have hwn_eq : (wn : E d) = (1 - a) • (sn.v - P sn.v) + - Real.sqrt μ' • en - Real.sqrt η • (gn - P gn) := by - change un1 - Real.sqrt μ' • ξn = _ - have h_av := auxVarOfState_step P μ' η ρ π f sn hρ ha_pos hη_pos hμ' - have : (un1 : E d) = ((1 - a) • (sn.v - P sn.v) + Real.sqrt μ' • en - - Real.sqrt η • (gn - P gn)) + Real.sqrt μ' • ξn := by - change auxVarOfState P μ' π η (nesterovStep f η ρ sn) = _; exact h_av - rw [this]; abel - -- ═══ B: Projector-freezing decomposition ═══ - -- ⟨g, e⟩ = ⟨P⊥g, e⟩ + ⟨g, Pe⟩ (via self-adjointness of P) - have h_ipGE_decomp : @inner ℝ _ _ gn en = - @inner ℝ _ _ (gn - P gn) en + @inner ℝ _ _ gn (P en) := by - have hsplit : gn = (gn - P gn) + P gn := by abel - conv_lhs => rw [hsplit] - rw [inner_add_left, hP_self_adj gn en] - have hG_pyth := pythagorean_proj P hP_self_adj hP_idem gn - have hV_pyth := pythagorean_proj P hP_self_adj hP_idem sn.v - have h_ip_decomp := inner_proj_decomp P hP_self_adj hP_idem gn sn.v - -- ═══ C: Explicit conversion of hFn'_bound to use en ═══ - -- (en is definitionally x'n - π x'n, so this is just type-checking) - have hFn1_le : Fn1 ≤ - @inner ℝ _ _ gn en - μ' / 2 * ‖en‖ ^ 2 - - η / 2 * ‖gn‖ ^ 2 := hFn'_bound - -- ═══ D: Norm expansions ═══ - have h_wn_sq : ‖wn‖ ^ 2 = - (1 - a) ^ 2 * ‖sn.v - P sn.v‖ ^ 2 + μ' * ‖en‖ ^ 2 + - η * ‖gn - P gn‖ ^ 2 + - 2 * (1 - a) * Real.sqrt μ' * @inner ℝ _ _ (sn.v - P sn.v) en - - 2 * (1 - a) * Real.sqrt η * @inner ℝ _ _ (sn.v - P sn.v) (gn - P gn) - - 2 * Real.sqrt μ' * Real.sqrt η * @inner ℝ _ _ en (gn - P gn) := by - rw [hwn_eq] - exact norm_three_term_sq _ _ _ _ _ _ (le_of_lt hμ') (le_of_lt hη_pos) - have h_un_eq : Un = ‖sn.v - P sn.v‖ ^ 2 + μ' * ‖en‖ ^ 2 + - 2 * Real.sqrt μ' * @inner ℝ _ _ (sn.v - P sn.v) en := by - change ‖un‖ ^ 2 = _ - exact norm_two_term_sq _ _ _ (le_of_lt hμ') - have h_un_eq' : Un = ‖sn.v - P sn.v‖ ^ 2 + - 2 * Real.sqrt μ' * @inner ℝ _ _ (sn.v - P sn.v) en + μ' * ‖en‖ ^ 2 := by - linarith - have h_Tn1_exp : Tn1 = (1 - a) / 2 * ‖P sn.v‖ ^ 2 - - (1 - a) * Real.sqrt η * @inner ℝ _ _ (P sn.v) (P gn) + - (1 - a) / 2 * η * ‖P gn‖ ^ 2 := by - rw [hTn1_val, h_expand, h_inner, h_norm_smul]; ring - have h_sqrt_prod : Real.sqrt μ' * Real.sqrt η = a := by - change Real.sqrt μ' * Real.sqrt η = Real.sqrt (μ' * η) - rw [← Real.sqrt_mul (le_of_lt hμ')] - -- Key coefficient identity: 2·√μ'·√η = 2·a (for norm simplification) - have h2a : 2 * Real.sqrt μ' * Real.sqrt η = 2 * a := by - have : (2 : ℝ) * Real.sqrt μ' * Real.sqrt η = - 2 * (Real.sqrt μ' * Real.sqrt η) := by ring - rw [this, h_sqrt_prod] - -- ═══ E: ‖wn‖²/2 with √μ'·√η replaced by a ═══ - have h_wn_half : ‖wn‖ ^ 2 / 2 = - (1 - a) ^ 2 / 2 * ‖sn.v - P sn.v‖ ^ 2 + μ' / 2 * ‖en‖ ^ 2 + - η / 2 * ‖gn - P gn‖ ^ 2 + - (1 - a) * Real.sqrt μ' * @inner ℝ _ _ (sn.v - P sn.v) en - - (1 - a) * Real.sqrt η * @inner ℝ _ _ (sn.v - P sn.v) (gn - P gn) - - a * @inner ℝ _ _ en (gn - P gn) := by - rw [h_wn_sq, h2a]; ring - -- ═══ G: Segment estimate ═══ - have hxn_Up : sn.x ∈ U_plus := hΩp_sub_Up (hΩ_sub_Ωp hx_in) - have h_path : ∀ t : ℝ, 0 ≤ t → t ≤ 1 → - (1 - t) • sn.x + t • x'n ∈ U_plus := by - intro t ht0 ht1 - exact hΩp_sub_Up (hΩ_sub_Ωp - ((convex_ball m_star (min (r₀ / 9) R_abs)) hx_in hx'_in - (by linarith : (0 : ℝ) ≤ 1 - t) ht0 (by linarith : (1 : ℝ) - t + t = 1))) - have h_seg_raw := hSegment x'n sn.x hx'n_Up hxn_Up h_path - have h_diff_eq : x'n - sn.x = Real.sqrt η • sn.v := by - change sn.x + Real.sqrt η • sn.v - sn.x = _; abel - have h_diff_sq : ‖x'n - sn.x‖ ^ 2 = η * ‖sn.v‖ ^ 2 := by - rw [h_diff_eq, norm_smul, Real.norm_eq_abs, - abs_of_nonneg (Real.sqrt_nonneg η), mul_pow, - Real.sq_sqrt (le_of_lt hη_pos)] - have h_inner_diff : @inner ℝ _ _ gn (x'n - sn.x) = - Real.sqrt η * @inner ℝ _ _ gn sn.v := by - rw [h_diff_eq, inner_smul_right] - -- ═══ H: Apply flat_case_arithmetic ═══ - -- Set up intermediate quantities for the arithmetic lemma - set Fnprime := f x'n - fStar f with hFnprime_def - -- Descent bound: Fn1 ≤ Fnprime - η/2·(‖Pg‖² + ‖P⊥g‖²) - have hFn1_descent : Fn1 ≤ Fnprime - η / 2 * (‖P gn‖ ^ 2 + ‖gn - P gn‖ ^ 2) := by - have h_mid : Fn1 ≤ Fnprime - η / 2 * ‖gn‖ ^ 2 := by linarith [hFn'_bound, h_aim] - have h_eq : η / 2 * ‖gn‖ ^ 2 = η / 2 * (‖P gn‖ ^ 2 + ‖gn - P gn‖ ^ 2) := by - rw [hG_pyth] - linarith - -- Segment: √η·(⟨Pg,Pv⟩ + ⟨P⊥g,P⊥v⟩) ≥ Fnprime - Fn - εη/2·(‖Pv‖² + ‖P⊥v‖²) - have h_segment_arith : - Real.sqrt η * (@inner ℝ _ _ (P gn) (P sn.v) + - @inner ℝ _ _ (gn - P gn) (sn.v - P sn.v)) ≥ - Fnprime - Fn - ε * η / 2 * (‖P sn.v‖ ^ 2 + ‖sn.v - P sn.v‖ ^ 2) := by - -- From segment estimate: ⟨gn, x'n - sn.x⟩ ≥ f(x'n) - f(sn.x) - ε/2·‖x'n-sn.x‖² - have h1 := h_seg_raw - rw [h_inner_diff, h_diff_sq] at h1 - -- h1: √η·⟨gn,sn.v⟩ ≥ Fnprime - Fn - εη/2·‖sn.v‖² - -- Use ip_decomp and V_pyth to rewrite - rw [h_ip_decomp, hV_pyth] at h1 - linarith - -- Aiming: ⟨P⊥g, en⟩ ≥ Fnprime + μ'/2·‖en‖² − |⟨g, Pe⟩| (projector-freezing error) - have h_aiming_arith : @inner ℝ _ _ (gn - P gn) en ≥ - Fnprime + μ' / 2 * ‖en‖ ^ 2 - abs (@inner ℝ _ _ gn (P en)) := by - -- Convert h_aim to use set-abbreviations gn, en, Fnprime - have h_aim' : @inner ℝ _ _ gn en ≥ Fnprime + μ' / 2 * ‖en‖ ^ 2 := h_aim - have hle := le_abs_self (@inner ℝ _ _ gn (P en)) - linarith [h_ipGE_decomp] - -- wn norm identity (with √μ'·√η = a) - have h_inner_comm_en_ppg : @inner ℝ _ _ en (gn - P gn) = - @inner ℝ _ _ (gn - P gn) en := real_inner_comm _ _ - have hwn_sq_arith : ‖wn‖ ^ 2 = - (1 - a) ^ 2 * ‖sn.v - P sn.v‖ ^ 2 + μ' * ‖en‖ ^ 2 + - η * ‖gn - P gn‖ ^ 2 + - 2 * (1 - a) * Real.sqrt μ' * @inner ℝ _ _ (sn.v - P sn.v) en - - 2 * (1 - a) * Real.sqrt η * @inner ℝ _ _ (gn - P gn) (sn.v - P sn.v) - - 2 * a * @inner ℝ _ _ (gn - P gn) en := by - rw [h_wn_sq, h2a, h_inner_comm_en_ppg] - have h_ic3 : @inner ℝ _ _ (sn.v - P sn.v) (gn - P gn) = - @inner ℝ _ _ (gn - P gn) (sn.v - P sn.v) := real_inner_comm _ _ - rw [h_ic3] - -- Tn1 identity (matching flat_case_arithmetic parameter order) - have hTn1_arith : Tn1 = (1 - a) / 2 * ‖P sn.v‖ ^ 2 - - (1 - a) * Real.sqrt η * @inner ℝ _ _ (P gn) (P sn.v) + - (1 - a) * η / 2 * ‖P gn‖ ^ 2 := by - have h_PgPv_comm : @inner ℝ _ _ (P sn.v) (P gn) = - @inner ℝ _ _ (P gn) (P sn.v) := real_inner_comm _ _ - rw [h_Tn1_exp, h_PgPv_comm]; ring - -- Tn identity - have hTn_arith : Tn = (1 + a) ^ 2 / (2 * (1 - a)) * ‖P sn.v‖ ^ 2 := by - rw [hTn_def, hlam_def] - -- Fnprime ≥ 0 - have hFnprime_nn : 0 ≤ Fnprime := by - change 0 ≤ f x'n - fStar f - exact sub_nonneg.mpr (ciInf_le hbdd x'n) - -- Un nonnegativity - have hUn_nn : 0 ≤ Un := by - change 0 ≤ ‖un‖ ^ 2; exact sq_nonneg _ - -- Apply the arithmetic lemma - have hpe_abs_nn : (0 : ℝ) ≤ abs (@inner ℝ _ _ gn (P en)) := abs_nonneg _ - exact flat_case_arithmetic a ha_pos ha_lt1 - η μ' (Real.sqrt μ') (Real.sqrt η) - hη_pos hμ' (Real.sqrt_nonneg _) (Real.sqrt_nonneg _) - (Real.sq_sqrt (le_of_lt hμ')) (Real.sq_sqrt (le_of_lt hη_pos)) - h_sqrt_prod - (ε * η) (mul_nonneg (le_of_lt hε_pos) (le_of_lt hη_pos)) hε_bound - Fn Fn1 Fnprime hgap_nn hgap'_nn hFnprime_nn - (‖P sn.v‖ ^ 2) (‖sn.v - P sn.v‖ ^ 2) (‖P gn‖ ^ 2) (‖gn - P gn‖ ^ 2) (‖en‖ ^ 2) - (sq_nonneg _) (sq_nonneg _) (sq_nonneg _) (sq_nonneg _) (sq_nonneg _) - (@inner ℝ _ _ (gn - P gn) en) (@inner ℝ _ _ (P gn) (P sn.v)) - (@inner ℝ _ _ (gn - P gn) (sn.v - P sn.v)) (@inner ℝ _ _ (sn.v - P sn.v) en) - (abs (@inner ℝ _ _ gn (P en))) hpe_abs_nn - hFn1_descent h_segment_arith h_aiming_arith - (‖wn‖ ^ 2) hwn_sq_arith - Un h_un_eq' - Tn1 hTn1_arith - Tn hTn_arith - -- ── Total perturbation absorption (Step B) ── - -- Curvature (ξ_n) + projector-freezing (|⟨g, Pe⟩|) terms are absorbed - -- by shrinking Ω and R. The hypothesis h_curv_absorb provides this. + ⟨f m_star, by rintro _ ⟨x, rfl⟩; exact (hM_argmin ▸ hm_star : m_star ∈ argminSet f) x⟩ + -- Segment estimate along [xₙ, x'ₙ] ⊆ Ω ⊆ U₊ + have hxn_Up : sn.x ∈ U_plus := hΩp_sub_Up (hΩ_sub_Ωp hx_in) + have h_path : ∀ t : ℝ, 0 ≤ t → t ≤ 1 → + (1 - t) • sn.x + t • sn.lookahead η ∈ U_plus := by + intro t ht0 ht1 + exact hΩp_sub_Up (hΩ_sub_Ωp + ((convex_ball m_star (min (r₀ / 9) R_abs)) hx_in hx'_in + (by linarith : (0 : ℝ) ≤ 1 - t) ht0 (by linarith : (1 : ℝ) - t + t = 1))) -- Derive Ln ≤ R_abs² from Ln ≤ (min(r₀/9, R_abs))² ≤ R_abs² have hLn_le_Rabs : Ln ≤ R_abs ^ 2 := by calc Ln ≤ (min (r₀ / 9) R_abs) ^ 2 := hLn_bound _ ≤ R_abs ^ 2 := by apply pow_le_pow_left₀ (le_min (le_of_lt hr₀9) (le_of_lt hR_abs)) (min_le_right _ _) - set proj_err_n := a * abs (@inner ℝ _ _ gn (P en)) with hproj_err_def - have h_absorb : δ_curv + proj_err_n ≤ θ * a * Ln := - h_curv_absorb s₀ n (hΩ_sub_Rabs hx_in) (hΩ_sub_Rabs hx'_in) - hLn_le_Rabs - -- ── Final assembly ── - apply two_step_contraction_general a θ Ln Ln' (δ_curv + proj_err_n) - ha_pos ha_lt1 hθ_pos hθ_lt1 hLn_nn - · -- Goal: Ln' ≤ (1-a) * Ln + (δ_curv + proj_err_n) - rw [hLn'_eq, hLn_eq] - linarith [h_Un1_half, h_flat] - · -- Goal: (δ_curv + proj_err_n) ≤ θ * a * Ln - exact h_absorb + exact lyapunovOfState_step_le f μ' hμ' θ hθ_pos hθ_lt1 η hη_pos ha_lt1 ρ hρ π P + hP_self_adj hP_idem ε hε_pos hε_bound hbdd sn h_descent + (hStrAim _ hx'n_Up) (hSegment _ _ hx'n_Up hxn_Up h_path) + (h_curv_absorb (hΩ_sub_Rabs hx_in) (hΩ_sub_Rabs hx'_in) hLn_le_Rabs) case x_next_in => - /- Uses shared hηL and hg_zero_mstar. -/ rw [Metric.mem_ball] - have hgrad_lip : ‖gn‖ ≤ (L : ℝ) * dist x'n m_star := by - have h := hf_lip.dist_le_mul x'n (hΩp_sub_Up (hΩ_sub_Ωp hx'_in)) m_star hm_star_Up - rwa [hg_zero_mstar, dist_zero_right] at h - have h_sn1_x : sn1.x = x'n - η • gn := rfl - have h_step_dist : dist sn1.x x'n = η * ‖gn‖ := by - rw [h_sn1_x, dist_eq_norm] - have : (x'n - η • gn) - x'n = -(η • gn) := by abel - rw [this, norm_neg, norm_smul, Real.norm_eq_abs, abs_of_pos hη_pos] - calc dist sn1.x m_star - ≤ dist sn1.x x'n + dist x'n m_star := dist_triangle _ _ _ - _ = η * ‖gn‖ + dist x'n m_star := by rw [h_step_dist] - _ ≤ η * ((L : ℝ) * dist x'n m_star) + dist x'n m_star := by - linarith [mul_le_mul_of_nonneg_left hgrad_lip (le_of_lt hη_pos)] - _ = 2 * dist x'n m_star := by - have : η * ((L : ℝ) * dist x'n m_star) = dist x'n m_star := by - rw [← mul_assoc, hηL, one_mul] - linarith - _ < 2 * r₀ / 3 := by linarith [hx'_ball_r09] + exact h_sn1_dist.trans_lt (by linarith) case x'_next_in => - /- x'_{n+1} = (1+ρ)·x_{n+1} - ρ·x_n (convex-like combination). - Need: x'_{n+1} ∈ B(m⋆, 2r₀/3). - By triangle inequality via this identity: - dist(x'_{n+1}, m⋆) ≤ (1+ρ)·dist(x_{n+1}, m⋆) + ρ·dist(x_n, m⋆) - < (1+ρ)·2(r₀/9) + ρ·(r₀/9) - = (2+3ρ)/9 · r₀ < 5r₀/9 < 2r₀/3. -/ rw [Metric.mem_ball] - have hx_ball := Metric.mem_ball.mp hx_in - have hx_ball_r09 : dist sn.x m_star < r₀ / 9 := - lt_of_lt_of_le hx_ball (min_le_left _ _) - have hgrad_lip : ‖gn‖ ≤ (L : ℝ) * dist x'n m_star := by - have h := hf_lip.dist_le_mul x'n (hΩp_sub_Up (hΩ_sub_Ωp hx'_in)) m_star hm_star_Up - rwa [hg_zero_mstar, dist_zero_right] at h have hρ_lt1 : ρ < 1 := by rw [hρ]; rw [div_lt_one (by linarith : (0 : ℝ) < 1 + a)]; linarith - -- Key identity: x'_{n+1} = (1+ρ)·x_{n+1} - ρ·x_n - have h_conv : sn1.lookahead η = (1 + ρ) • sn1.x - ρ • sn.x := by - change sn1.x + Real.sqrt η • sn1.v = (1 + ρ) • sn1.x - ρ • sn.x - have hsq : Real.sqrt η * Real.sqrt η = η := - Real.mul_self_sqrt (le_of_lt hη_pos) - have h5 : Real.sqrt η • (ρ • (sn.v - Real.sqrt η • gn)) = - ρ • (Real.sqrt η • sn.v - η • gn) := by - rw [smul_comm (Real.sqrt η) ρ, smul_sub, ← mul_smul, hsq] - change (x'n - η • gn) + Real.sqrt η • (ρ • (sn.v - Real.sqrt η • gn)) = - (1 + ρ) • (x'n - η • gn) - ρ • sn.x - rw [h5] - change (sn.x + Real.sqrt η • sn.v - η • gn) + - ρ • (Real.sqrt η • sn.v - η • gn) = - (1 + ρ) • (sn.x + Real.sqrt η • sn.v - η • gn) - ρ • sn.x - module - -- Distance bound on x_{n+1}: dist(x_{n+1}, m⋆) < 2·(r₀/9) - have h_sn1_dist : dist sn1.x m_star < 2 * (r₀ / 9) := by - have h_sn1_x : sn1.x = x'n - η • gn := rfl - have h_step_dist : dist sn1.x x'n = η * ‖gn‖ := by - rw [h_sn1_x, dist_eq_norm] - have : (x'n - η • gn) - x'n = -(η • gn) := by abel - rw [this, norm_neg, norm_smul, Real.norm_eq_abs, abs_of_pos hη_pos] - calc dist sn1.x m_star - ≤ dist sn1.x x'n + dist x'n m_star := dist_triangle _ _ _ - _ = η * ‖gn‖ + dist x'n m_star := by rw [h_step_dist] - _ ≤ η * ((L : ℝ) * dist x'n m_star) + dist x'n m_star := by - linarith [mul_le_mul_of_nonneg_left hgrad_lip (le_of_lt hη_pos)] - _ = 2 * dist x'n m_star := by - have : η * ((L : ℝ) * dist x'n m_star) = dist x'n m_star := by - rw [← mul_assoc, hηL, one_mul] - linarith - _ < 2 * (r₀ / 9) := by linarith [hx'_ball_r09] - -- Subtract m_star using the convex combination identity - have h_sub : sn1.lookahead η - m_star = - (1 + ρ) • (sn1.x - m_star) - ρ • (sn.x - m_star) := by - rw [h_conv]; module - -- Main distance bound via triangle inequality - calc dist (sn1.lookahead η) m_star - = ‖sn1.lookahead η - m_star‖ := dist_eq_norm _ _ - _ = ‖(1 + ρ) • (sn1.x - m_star) - ρ • (sn.x - m_star)‖ := by - rw [h_sub] - _ ≤ ‖(1 + ρ) • (sn1.x - m_star)‖ + ‖ρ • (sn.x - m_star)‖ := - norm_sub_le _ _ - _ = (1 + ρ) * ‖sn1.x - m_star‖ + ρ * ‖sn.x - m_star‖ := by - rw [norm_smul, norm_smul, Real.norm_eq_abs, abs_of_pos (by linarith : (0:ℝ) < 1 + ρ), - Real.norm_eq_abs, abs_of_pos hρ_pos] - _ = (1 + ρ) * dist sn1.x m_star + ρ * dist sn.x m_star := by - simp only [dist_eq_norm] - _ < (1 + ρ) * (2 * (r₀ / 9)) + ρ * (r₀ / 9) := by - have h1 : (1 + ρ) * dist sn1.x m_star < (1 + ρ) * (2 * (r₀ / 9)) := - mul_lt_mul_of_pos_left h_sn1_dist (by linarith : (0:ℝ) < 1 + ρ) - have h2 : ρ * dist sn.x m_star < ρ * (r₀ / 9) := - mul_lt_mul_of_pos_left hx_ball_r09 hρ_pos - linarith - _ = (2 + 3 * ρ) / 9 * r₀ := by ring - _ < 2 / 3 * r₀ := by - have hcoef : (2 + 3 * ρ) / 9 < (2 : ℝ) / 3 := by linarith - exact mul_lt_mul_of_pos_right hcoef hr₀_pos - _ = 2 * r₀ / 3 := by ring + exact (nesterovStep_lookahead_dist_lt f η ρ hη_pos hρ_pos hρ_lt1 m_star (r₀ / 9) sn + hx_ball_r09 (h_sn1_dist.trans_lt (by linarith))).trans_le (by linarith) +/-- **State-based Lyapunov contraction along `nesterovSeqGen`.** -/-- Public theorem wrapper for `lyapunovContractionGenProof`. -/ +Generalization of `lyapunov_contraction` (Main.lean) to arbitrary initial +`NesterovState`, supporting nonzero initial velocity. -/ theorem lyapunov_contraction_gen {d : ℕ} (_hd : 0 < d) -- The objective function @@ -786,14 +656,11 @@ theorem lyapunov_contraction_gen Ln' ≤ (1 - (1 - θ) * a) * Ln ∧ -- Next iterates in Ω⁺ s'.x ∈ Ω_plus ∧ s'.lookahead η ∈ Ω_plus := by - exact lyapunovContractionGenProof (d := d) (_hd := _hd) (f := f) (L := L) (hL := hL) (μ' := μ') - (hμ' := hμ') (θ := θ) (hθ_pos := hθ_pos) (hθ_lt1 := hθ_lt1) (η := η) (hη := hη) - (hη_pos := hη_pos) (ρ := ρ) (hρ := hρ) (S := S) (hM_argmin := hM_argmin) (π := π) - (_hπ_in_S := _hπ_in_S) (_hπ_proj := _hπ_proj) (hgrad_zero := hgrad_zero) (P := P) - (m_star := m_star) (hm_star := hm_star) (ε := ε) (hε_pos := hε_pos) (hε_bound := hε_bound) - (hμη_lt1 := hμη_lt1) (U_plus := U_plus) (hU_open := hU_open) (hm_star_Up := hm_star_Up) - (hf_diff_on := hf_diff_on) (hf_lip := hf_lip) (hStrAim := hStrAim) (hHess_lower := hHess_lower) - (_hπ_kills_normal := _hπ_kills_normal) (hP_self_adj := hP_self_adj) (hP_idem := hP_idem) - (hSegment := hSegment) (R_abs := R_abs) (hR_abs := hR_abs) (h_curv_absorb := h_curv_absorb) + obtain ⟨Ω, Ω_plus, R, hΩ, hΩp, hR, hm, hsub, hsubp, h⟩ := + lyapunov_contraction_of_state f L hL μ' hμ' θ hθ_pos hθ_lt1 η hη hη_pos ρ hρ S hM_argmin + π hgrad_zero P m_star hm_star ε hε_pos hε_bound hμη_lt1 U_plus hU_open hm_star_Up + hf_diff_on hf_lip hStrAim hHess_lower hP_self_adj hP_idem hSegment R_abs hR_abs + exact ⟨Ω, Ω_plus, R, hΩ, hΩp, hR, hm, hsub, hsubp, + fun s₀ n => h (nesterovSeqGen f η ρ s₀ n) (h_curv_absorb s₀ n)⟩ end PLAcceleratedNesterovLean diff --git a/LeanPool/PLAcceleratedNesterovLean/Convergence/LyapunovContraction/Main.lean b/LeanPool/PLAcceleratedNesterovLean/Convergence/LyapunovContraction/Main.lean index bccc4aab65..94f9e47753 100644 --- a/LeanPool/PLAcceleratedNesterovLean/Convergence/LyapunovContraction/Main.lean +++ b/LeanPool/PLAcceleratedNesterovLean/Convergence/LyapunovContraction/Main.lean @@ -6,12 +6,7 @@ Authors: Max Obreiter, Tobias Steinbrecher, Robert Foerster module public import LeanPool.PLAcceleratedNesterovLean.Core.NesterovScheme -import LeanPool.PLAcceleratedNesterovLean.Convergence.LyapunovContraction.AuxVar -import LeanPool.PLAcceleratedNesterovLean.Convergence.LyapunovContraction.FlatCaseArithmetic -import LeanPool.PLAcceleratedNesterovLean.Convergence.LyapunovContraction.FlatCaseHelper -import LeanPool.PLAcceleratedNesterovLean.Convergence.LyapunovContraction.Step1 -import LeanPool.PLAcceleratedNesterovLean.Convergence.LyapunovContraction.Step2 -import LeanPool.PLAcceleratedNesterovLean.Convergence.LyapunovContraction.Step3 +import LeanPool.PLAcceleratedNesterovLean.Convergence.LyapunovContraction.GenMain /-! @@ -42,671 +37,6 @@ and x_{n+1}, x'_{n+1} ∈ Ω⁺. The budget-split parameter θ ∈ (0,1) controls what fraction of the contraction rate a is consumed by perturbation absorption. When θ = 1/2 this gives (1 - a/2). -/ -private abbrev lyapunovContractionProof - {d : ℕ} (_hd : 0 < d) - -- The objective function - (f : E d → ℝ) - -- Parameters - (L : ℝ≥0) (hL : 0 < (L : ℝ)) - (μ' : ℝ) (hμ' : 0 < μ') - (θ : ℝ) (hθ_pos : 0 < θ) (hθ_lt1 : θ < 1) - (η : ℝ) (hη : η = 1 / (L : ℝ)) (hη_pos : 0 < η) - (ρ : ℝ) (hρ : ρ = (1 - Real.sqrt (μ' * η)) / (1 + Real.sqrt (μ' * η))) - -- S = argmin set - (S : Set (E d)) - (hM_argmin : S = argminSet f) - -- Nearest-point projection - (π : E d → E d) - (_hπ_in_S : ∀ x, π x ∈ S) - (_hπ_proj : ∀ x ∈ S, π x = x) - -- Gradient vanishes on S - (hgrad_zero : ∀ x ∈ S, gradient f x = 0) - -- Tangent projector P = Dπ(m⋆) - (P : E d →L[ℝ] E d) - -- Base point - (m_star : E d) (hm_star : m_star ∈ S) - -- ε from `local_fiberwise_geometry` - (ε : ℝ) (hε_pos : 0 < ε) (hε_bound : ε * η ≤ Real.sqrt (μ' * η)) - (hμη_lt1 : μ' * η < 1) - -- Strong aiming on U₊ (from `local_fiberwise_geometry`) - (U_plus : Set (E d)) - (hU_open : IsOpen U_plus) - (hm_star_Up : m_star ∈ U_plus) - -- Local smoothness on U₊ - (hf_diff_on : DifferentiableOn ℝ f U_plus) - (hf_lip : LipschitzOnWith L (gradient f) U_plus) - (hStrAim : ∀ x ∈ U_plus, - @inner ℝ _ _ (gradient f x) (x - π x) ≥ - f x - fStar f + μ' / 2 * ‖x - π x‖ ^ 2) - -- Hessian lower bound on U₊ (from `local_fiberwise_geometry`) - (hHess_lower : ∀ x ∈ U_plus, ∀ ξ : E d, - hessianQuadForm f x ξ ≥ -ε * ‖ξ‖ ^ 2) - -- Normal Hessian on projection fibers: Dπ(π x) · e = 0 → e lies in normal space - (_hπ_kills_normal : ∀ x ∈ U_plus, - fderiv ℝ π (π x) (x - π x) = 0) - -- P is self-adjoint (orthogonal projector property) - (hP_self_adj : ∀ x y : E d, @inner ℝ _ _ (P x) y = @inner ℝ _ _ x (P y)) - -- P is idempotent (orthogonal projector property) - (hP_idem : ∀ x : E d, P (P x) = P x) - -- Segment estimate (from D²f ≽ -εI and C² regularity): - -- ⟨∇f(x), x - z⟩ ≥ f(x) - f(z) - ε/2 · ‖x - z‖² - (hSegment : ∀ x z : E d, x ∈ U_plus → z ∈ U_plus → - (∀ t : ℝ, 0 ≤ t → t ≤ 1 → (1 - t) • z + t • x ∈ U_plus) → - @inner ℝ _ _ (gradient f x) (x - z) ≥ - f x - f z - ε / 2 * ‖x - z‖ ^ 2) - -- Total perturbation absorption (curvature + projector-freezing error) - -- δ_curv = curvature perturbation, proj_err = a·|⟨g, Pe⟩| from projector freezing - -- R_abs is the energy/spatial radius: iterates must be in B(m⋆, R_abs) with Ln ≤ R_abs². - (R_abs : ℝ) (hR_abs : 0 < R_abs) - (h_curv_absorb : ∀ (x₁ : E d) (n : ℕ), - (nesterovSeq f η ρ x₁ n).x ∈ Metric.ball m_star R_abs → - (nesterovSeq f η ρ x₁ n).lookahead η ∈ Metric.ball m_star R_abs → - lyapunov P μ' π f η ρ x₁ n ≤ R_abs ^ 2 → - let sn := nesterovSeq f η ρ x₁ n - let gn := gradient f (sn.lookahead η) - let en := sn.lookahead η - π (sn.lookahead η) - let ξn := curvatureError (↑P) π f η ρ x₁ n - let un1 := auxVar P μ' π f η ρ x₁ (n + 1) - let wn := un1 - Real.sqrt μ' • ξn - let δ_curv := Real.sqrt μ' * @inner ℝ _ _ wn ξn + - (Real.sqrt μ') ^ 2 / 2 * ‖ξn‖ ^ 2 - let a := Real.sqrt (μ' * η) - let Ln := lyapunov P μ' π f η ρ x₁ n - let proj_err := a * |@inner ℝ _ _ gn (P en)| - δ_curv + proj_err ≤ θ * a * Ln) - : - -- Conclusion: ∃ Ω, R (independent of starting point) such that contraction holds - ∃ (Ω Ω_plus : Set (E d)) (R : ℝ), - IsOpen Ω ∧ IsOpen Ω_plus ∧ 0 < R ∧ - m_star ∈ Ω ∧ Ω ⊆ Ω_plus ∧ Ω_plus ⊆ U_plus ∧ - -- For all starting points and iterations with the right preconditions - ∀ (x₁ : E d) (n : ℕ), - let s := nesterovSeq f η ρ x₁ n - let s' := nesterovSeq f η ρ x₁ (n + 1) - let Ln := lyapunov P μ' π f η ρ x₁ n - let Ln' := lyapunov P μ' π f η ρ x₁ (n + 1) - let a := Real.sqrt (μ' * η) - s.x ∈ Ω → s.lookahead η ∈ Ω → Ln ≤ R ^ 2 → - -- Contraction - Ln' ≤ (1 - (1 - θ) * a) * Ln ∧ - -- Next iterates in Ω⁺ - s'.x ∈ Ω_plus ∧ s'.lookahead η ∈ Ω_plus := by - /- - Proof roadmap for the one-step contraction. - - Choose concentric neighborhoods Ω ⊂ Ω₊ ⊂ U₊ around m⋆ and an energy - radius R. For each iterate with xₙ, x'ₙ ∈ Ω and Lₙ ≤ R²: - * descent gives f(x_{n+1}) ≤ f(x'_n) − (η/2)‖gₙ‖²; - * the identity (1+a)ρ = 1−a rewrites the velocity update; - * the normal terms complete the square into (1−a)/2 · ‖uₙ‖²; - * the function values telescope to (1−a)(f(xₙ)−f⋆); - * curvature and projector-freezing errors are absorbed using the θ-budget, - producing Lₙ₊₁ ≤ (1 - (1-θ)a)Lₙ. - -/ - -- ═══════════════════════════════════════════════════════════════ - -- Neighborhood construction - -- ═══════════════════════════════════════════════════════════════ - -- Extract r₀ > 0 with B(m⋆, r₀) ⊆ U₊ - obtain ⟨r₀, hr₀_pos, hball_sub⟩ : ∃ r₀ > 0, Metric.ball m_star r₀ ⊆ U_plus := by - exact Metric.isOpen_iff.mp hU_open m_star hm_star_Up - -- Auxiliary inequalities for the chosen radii - have hr₀9 : (0 : ℝ) < r₀ / 9 := by linarith - have hR_min : (0 : ℝ) < min (r₀ / 9) R_abs := lt_min hr₀9 hR_abs - -- Ω = B(m⋆, min(r₀/9, R_abs)) — ensures iterates are in B(m⋆, R_abs) for h_curv_absorb - have hΩ_sub_r09 : Metric.ball m_star (min (r₀ / 9) R_abs) ⊆ - Metric.ball m_star (r₀ / 9) := - Metric.ball_subset_ball (min_le_left _ _) - have hΩ_sub_Rabs : Metric.ball m_star (min (r₀ / 9) R_abs) ⊆ - Metric.ball m_star R_abs := - Metric.ball_subset_ball (min_le_right _ _) - have hΩ_sub_Ωp : Metric.ball m_star (min (r₀ / 9) R_abs) ⊆ - Metric.ball m_star (2 * r₀ / 3) := - hΩ_sub_r09.trans (Metric.ball_subset_ball (by linarith)) - have h23_le : 2 * r₀ / 3 ≤ r₀ := by linarith - have hΩp_sub_Up : Metric.ball m_star (2 * r₀ / 3) ⊆ U_plus := - (Metric.ball_subset_ball h23_le).trans hball_sub - -- Provide the existential witnesses: - -- Ω := B(m⋆, min(r₀/9, R_abs)) - -- Ω₊ := B(m⋆, 2r₀/3) - -- R := min(r₀/9, R_abs) - refine ⟨Metric.ball m_star (min (r₀ / 9) R_abs), - Metric.ball m_star (2 * r₀ / 3), - min (r₀ / 9) R_abs, - Metric.isOpen_ball, - Metric.isOpen_ball, - hR_min, - Metric.mem_ball_self hR_min, - hΩ_sub_Ωp, - hΩp_sub_Up, - ?_⟩ - -- ═══════════════════════════════════════════════════════════════ - -- Main contraction argument - -- ═══════════════════════════════════════════════════════════════ - intro x₁ n sn sn1 Ln Ln' a hx_in hx'_in hLn_bound - -- Additional convenient abbreviations - let x'n := sn.lookahead η - let gn := gradient f x'n - let en := normalDisp π f η ρ x₁ n - let un := auxVar P μ' π f η ρ x₁ n - -- ───────────────────────────────────────────────────────────── - -- Step 1 (Descent): f(x_{n+1}) ≤ f(x'_n) − (η/2)·‖g_n‖² - -- ───────────────────────────────────────────────────────────── - have h_descent : f sn1.x ≤ f x'n - η / 2 * ‖gn‖ ^ 2 := by - -- sn1.x = x'n - η • gn by definition of nesterovStep/nesterovSeq - have hx_eq : sn1.x = x'n - η • gn := rfl - rw [hx_eq] - have hx'_Up : x'n ∈ U_plus := hΩp_sub_Up (hΩ_sub_Ωp hx'_in) - have hx'_r09 : dist x'n m_star < r₀ / 9 := - Metric.mem_ball.mp (hΩ_sub_r09 hx'_in) - have hg_zero' : gradient f m_star = 0 := hgrad_zero m_star hm_star - have hgrad_lip' : ‖gn‖ ≤ (↑L : ℝ) * dist x'n m_star := by - have h := hf_lip.dist_le_mul x'n hx'_Up m_star hm_star_Up - rwa [hg_zero', dist_zero_right] at h - have hseg_x'n : ∀ t : ℝ, 0 ≤ t → t ≤ 1 → - x'n + t • (-(((1 : ℝ) / (L : ℝ)) • gradient f x'n)) ∈ U_plus := by - intro t ht0 ht1 - apply hball_sub; rw [Metric.mem_ball] - have h_step_bound : dist (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gn))) x'n ≤ - dist x'n m_star := by - rw [dist_eq_norm, - show (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gn))) - x'n = - t • (-(((1 : ℝ) / (↑L : ℝ)) • gn)) from by abel, - norm_smul, norm_neg, norm_smul, Real.norm_eq_abs, - abs_of_nonneg ht0, Real.norm_eq_abs, - abs_of_pos (div_pos one_pos hL)] - calc t * ((1 : ℝ) / (↑L : ℝ) * ‖gn‖) - ≤ 1 * ((1 : ℝ) / (↑L : ℝ) * ((↑L : ℝ) * dist x'n m_star)) := - mul_le_mul ht1 - (mul_le_mul_of_nonneg_left hgrad_lip' - (le_of_lt (div_pos one_pos hL))) - (mul_nonneg (le_of_lt (div_pos one_pos hL)) (norm_nonneg _)) - one_pos.le - _ = dist x'n m_star := by - rw [one_mul, ← mul_assoc, one_div_mul_cancel (ne_of_gt hL), one_mul] - calc dist (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gn))) m_star - ≤ dist (x'n + t • (-(((1 : ℝ) / (↑L : ℝ)) • gn))) x'n + dist x'n m_star := - dist_triangle _ _ _ - _ ≤ 2 * dist x'n m_star := by linarith [h_step_bound] - _ < 2 * (r₀ / 9) := by linarith [hx'_r09] - _ < r₀ := by linarith - exact lsmooth_descent_at f L hL hU_open hf_diff_on hf_lip x'n hx'_Up hseg_x'n η hη - -- ───────────────────────────────────────────────────────────── - -- Step 2 (Parameter identities) - -- ───────────────────────────────────────────────────────────── - have ha_pos : 0 < a := by - exact Real.sqrt_pos_of_pos (mul_pos hμ' hη_pos) - have ha_lt1 : a < 1 := by - have hle : (0 : ℝ) ≤ μ' * η := le_of_lt (mul_pos hμ' hη_pos) - calc a = Real.sqrt (μ' * η) := rfl - _ < Real.sqrt 1 := Real.sqrt_lt_sqrt hle (by linarith) - _ = 1 := Real.sqrt_one - have h_rho_id : (1 + a) * ρ = 1 - a := by - have h1a : (0 : ℝ) < 1 + a := by linarith - exact rho_identity a ρ h1a.ne' hρ - -- ───────────────────────────────────────────────────────────── - -- Step 3 (Complete the square for normal terms) - -- ((1-a)/2)·‖v‖² + (1-a)·√μ'·⟨v,e⟩ + ((1-a)·μ'/2)·‖e‖² - -- = ((1-a)/2)·‖v + √μ'·e‖² = ((1-a)/2)·‖uₙ‖² - -- ───────────────────────────────────────────────────────────── - have h_complete_sq : ∀ (v e : E d), - (1 - a) / 2 * ‖v‖ ^ 2 + - (1 - a) * Real.sqrt μ' * @inner ℝ _ _ v e + - (1 - a) * (Real.sqrt μ') ^ 2 / 2 * ‖e‖ ^ 2 = - (1 - a) / 2 * ‖v + Real.sqrt μ' • e‖ ^ 2 := by - intro v e - exact complete_square_normal v e (1 - a) (Real.sqrt μ') (by linarith) - -- ───────────────────────────────────────────────────────────── - -- Step 4 (Function-value telescoping) - -- (f'−f⋆) − (1−a)(f'−f) − a(f'−f⋆) = (1−a)(f−f⋆) - -- ───────────────────────────────────────────────────────────── - have h_func : ∀ f' fv : ℝ, - (f' - fStar f) - (1 - a) * (f' - fv) - a * (f' - fStar f) = - (1 - a) * (fv - fStar f) := - fun f' fv => function_value_collection f' fv (fStar f) a - -- ───────────────────────────────────────────────────────────── - -- Step 5 (Perturbation expansion + Cauchy–Schwarz) - -- ‖w + c·ξ‖² = ‖w‖² + 2c⟨w,ξ⟩ + c²‖ξ‖² - -- |⟨w,ξ⟩| ≤ ‖w‖·‖ξ‖ - -- ───────────────────────────────────────────────────────────── - have h_perturb : ∀ (w ξ : E d) (c : ℝ), - ‖w + c • ξ‖ ^ 2 = - ‖w‖ ^ 2 + 2 * c * @inner ℝ _ _ w ξ + c ^ 2 * ‖ξ‖ ^ 2 := - fun w ξ c => perturbation_expansion w ξ c - have h_cs : ∀ (w ξ : E d), - |@inner ℝ _ _ w ξ| ≤ ‖w‖ * ‖ξ‖ := - fun w ξ => inner_abs_le_norm_mul w ξ - -- ───────────────────────────────────────────────────────────── - -- Step 6 (Velocity coefficient bounds from Step 1 helpers) - -- ───────────────────────────────────────────────────────────── - have h_vel_coeff : ∀ (εη : ℝ), 0 ≤ εη → εη ≤ a → - (1 - a) ^ 2 + εη * (1 - a) ≤ 1 - a := - fun εη hεη hb => velocity_normal_coeff a εη (le_of_lt ha_pos) (le_of_lt ha_lt1) hεη hb - have h_tang_coeff : (1 - a) * (1 + a) ≤ (1 + a) ^ 2 := - tangential_coeff a (le_of_lt ha_pos) - -- ═══════════════════════════════════════════════════════════════ - -- Shared facts (used by multiple cases) - -- ═══════════════════════════════════════════════════════════════ - have hg_zero_mstar : gradient f m_star = 0 := hgrad_zero m_star hm_star - have hηL : η * (L : ℝ) = 1 := by rw [hη]; field_simp - have hx'_ball_r09 : dist x'n m_star < r₀ / 9 := - lt_of_lt_of_le (Metric.mem_ball.mp hx'_in) (min_le_left _ _) - have hρ_pos : 0 < ρ := by rw [hρ]; apply div_pos <;> linarith - -- ═══════════════════════════════════════════════════════════════ - -- Assemble the three conclusions - -- ═══════════════════════════════════════════════════════════════ - refine ⟨?contraction, ?x_next_in, ?x'_next_in⟩ - case contraction => - /- Combining Steps 1–6: - Descent (Step 1) bounds f(x_{n+1}). - The ρ-identity (Step 2) rewrites the velocity recursion. - Completing the square (Step 3) recombines normal terms → (1−a)/2·‖uₙ‖². - Function telescoping (Step 4) yields (1−a)(f(xₙ)−f⋆). - Perturbation + Cauchy–Schwarz (Step 5) absorb ξₙ when R is small. - Velocity bounds (Step 6) confirm coefficient contraction. - Together: L_{n+1} ≤ (1 − a/2) · Lₙ. -/ - -- Membership for applying strong aiming and Hessian bound - have hx'n_Up : x'n ∈ U_plus := hΩp_sub_Up (hΩ_sub_Ωp hx'_in) - -- Strong aiming: ⟨∇f(x'_n), e_n⟩ ≥ f(x'_n) - f⋆ + μ'/2 ‖e_n‖² - have h_aim : @inner ℝ _ _ (gradient f x'n) (x'n - π x'n) ≥ - f x'n - fStar f + μ' / 2 * ‖x'n - π x'n‖ ^ 2 := - hStrAim x'n hx'n_Up - -- f-value descent from Step 1 - have h_f_upper : f sn1.x - fStar f ≤ f x'n - fStar f - η / 2 * ‖gn‖ ^ 2 := by - linarith [h_descent] - -- Hessian perturbation control at x'_n - have h_hess_x' : ∀ ξ : E d, hessianQuadForm f x'n ξ ≥ -ε * ‖ξ‖ ^ 2 := - hHess_lower x'n hx'n_Up - -- ══════════════ Nonnegativity infrastructure ══════════════ - -- BddBelow for fStar - have hmin : ∀ y, f m_star ≤ f y := by - intro y; exact (hM_argmin ▸ hm_star : m_star ∈ argminSet f) y - have hbdd : BddBelow (Set.range f) := - ⟨f m_star, by rintro _ ⟨x, rfl⟩; exact hmin x⟩ - have hgap_nn : 0 ≤ f sn.x - fStar f := - sub_nonneg.mpr (ciInf_le hbdd sn.x) - have hgap'_nn : 0 ≤ f sn1.x - fStar f := - sub_nonneg.mpr (ciInf_le hbdd sn1.x) - -- Parameter positivity - have h1a_pos : (0 : ℝ) < 1 + a := by linarith - have h1a_ne : (1 + a : ℝ) ≠ 0 := ne_of_gt h1a_pos - have h1ma_pos : (0 : ℝ) < 1 - a := by linarith - have h1ma_ne : (1 - a : ℝ) ≠ 0 := ne_of_gt h1ma_pos - -- λ = (1+a)²/(2(1-a)) > 0 - have hlam_pos : (0 : ℝ) < (1 + a) ^ 2 / (2 * (1 - a)) := - div_pos (sq_pos_of_pos h1a_pos) (by linarith) - -- Ln ≥ 0 - have hLn_nn : 0 ≤ Ln := by - change 0 ≤ lyapunov P μ' π f η ρ x₁ n - simp only [lyapunov] - have hlam_nn : 0 ≤ (1 + Real.sqrt (μ' * η)) ^ 2 / (2 * (1 - Real.sqrt (μ' * η))) := - le_of_lt hlam_pos - have h1 := sq_nonneg ‖auxVar P μ' π f η ρ x₁ n‖ - have h2 := mul_nonneg hlam_nn (sq_nonneg ‖P (nesterovSeq f η ρ x₁ n).v‖) - linarith - -- ══════════════ Tangential velocity identity ══════════════ - -- P is a CLM, so P(sn1.v) = ρ • (P sn.v - √η • P gn) - have hPv1 : P sn1.v = ρ • (P sn.v - Real.sqrt η • P gn) := by - change P (ρ • (sn.v - Real.sqrt η • gn)) = ρ • (P sn.v - Real.sqrt η • P gn) - rw [map_smul, map_sub, map_smul] - -- λ‖P sn1.v‖² = ((1-a)/2) ‖P sn.v - √η • P gn‖² - have hTn1_eq : (1 + a) ^ 2 / (2 * (1 - a)) * ‖P sn1.v‖ ^ 2 = - (1 - a) / 2 * ‖P sn.v - Real.sqrt η • P gn‖ ^ 2 := by - rw [hPv1, norm_smul, Real.norm_eq_abs, abs_of_pos hρ_pos, mul_pow, ← mul_assoc] - congr 1 - exact lambda_rho_sq a ρ _ h1a_ne h1ma_ne hρ rfl - -- ══════════════ Aiming gives function descent bound ══════════════ - -- From descent + aiming: Fn' ≤ ⟨gn, en⟩ - μ'/2 ‖en‖² - η/2 ‖gn‖² - have hFn'_bound : f sn1.x - fStar f ≤ - @inner ℝ _ _ gn (x'n - π x'n) - μ' / 2 * ‖x'n - π x'n‖ ^ 2 - - η / 2 * ‖gn‖ ^ 2 := - function_descent_with_aiming _ _ _ _ _ _ _ h_f_upper h_aim - -- ══════════════ Lyapunov decomposition ══════════════ - -- Abbreviate the Lyapunov components at steps n and n+1. - set lam := (1 + a) ^ 2 / (2 * (1 - a)) with hlam_def - set Fn := f sn.x - fStar f with hFn_def - set Un := ‖un‖ ^ 2 with hUn_def - set Tn := lam * ‖P sn.v‖ ^ 2 with hTn_def - set un1 := auxVar P μ' π f η ρ x₁ (n + 1) with hun1_def - set Fn1 := f sn1.x - fStar f with hFn1_def - set Un1 := ‖un1‖ ^ 2 with hUn1_def - set Tn1 := lam * ‖P sn1.v‖ ^ 2 with hTn1_def - -- Lyapunov decomposition identities - have hLn_eq : Ln = Fn + Un / 2 + Tn := by - change lyapunov P μ' π f η ρ x₁ n = Fn + Un / 2 + Tn - unfold lyapunov; rfl - have hLn'_eq : Ln' = Fn1 + Un1 / 2 + Tn1 := by - change lyapunov P μ' π f η ρ x₁ (n + 1) = Fn1 + Un1 / 2 + Tn1 - unfold lyapunov; rfl - -- Nonnegativity - have hTn_nn : 0 ≤ Tn := mul_nonneg (le_of_lt hlam_pos) (sq_nonneg _) - have hTn1_nn : 0 ≤ Tn1 := mul_nonneg (le_of_lt hlam_pos) (sq_nonneg _) - -- ══════════════ Tangential energy identity ══════════════ - -- hTn1_eq: lam * ‖P sn1.v‖² = (1-a)/2 * ‖Pv - √η·Pg‖² - -- Restate in terms of Tn1: - have hTn1_val : Tn1 = (1 - a) / 2 * ‖P sn.v - Real.sqrt η • P gn‖ ^ 2 := by - rw [hTn1_def]; exact hTn1_eq - -- Expand ‖Pv - √η·Pg‖² for later use: - have h_expand : ‖P sn.v - Real.sqrt η • P gn‖ ^ 2 = - ‖P sn.v‖ ^ 2 - 2 * @inner ℝ _ _ (P sn.v) (Real.sqrt η • P gn) + - ‖Real.sqrt η • P gn‖ ^ 2 := by rw [norm_sub_sq_real] - have h_inner : @inner ℝ _ _ (P sn.v) (Real.sqrt η • P gn) = - Real.sqrt η * @inner ℝ _ _ (P sn.v) (P gn) := by rw [inner_smul_right] - have h_norm_smul : ‖Real.sqrt η • P gn‖ ^ 2 = η * ‖P gn‖ ^ 2 := by - rw [norm_smul, Real.norm_eq_abs, abs_of_nonneg (Real.sqrt_nonneg _), mul_pow, - Real.sq_sqrt (le_of_lt hη_pos)] - -- λ ≥ 1/2 (ensures ‖Pv‖² ≤ 2·Tn, used for coercivity bounds) - have hlam_ge_half : (1 : ℝ) / 2 ≤ lam := by - rw [hlam_def] - have h2ma : (0 : ℝ) < 2 * (1 - a) := by linarith - rw [div_le_div_iff₀ two_pos h2ma] - have h_asq := sq_nonneg a - linarith - -- ── Contraction assembly ── - -- Two-step: (A) L_{n+1} ≤ (1-a)·L_n + δ, (B) δ ≤ (a/2)·L_n → L_{n+1} ≤ (1-a/2)·L_n - - -- ── Define intermediate quantities ── - let ξn := curvatureError (↑P) π f η ρ x₁ n - let wn := un1 - Real.sqrt μ' • ξn - -- ── AuxVar decomposition: u_{n+1} = w_n + √μ'·ξ_n ── - have h_un1_eq : un1 = wn + Real.sqrt μ' • ξn := by - change un1 = (un1 - Real.sqrt μ' • ξn) + Real.sqrt μ' • ξn - abel - -- ── Perturbation expansion ── - have h_Un1_expand : Un1 = - ‖wn‖ ^ 2 + 2 * Real.sqrt μ' * @inner ℝ _ _ wn ξn + - (Real.sqrt μ') ^ 2 * ‖ξn‖ ^ 2 := by - change ‖un1‖ ^ 2 = _ - rw [h_un1_eq] - exact perturbation_expansion wn ξn (Real.sqrt μ') - -- ── Curvature perturbation δ ── - set δ_curv := Real.sqrt μ' * @inner ℝ _ _ wn ξn + - (Real.sqrt μ') ^ 2 / 2 * ‖ξn‖ ^ 2 with hδ_def - -- ── Perturbation splitting: Un1/2 = ‖wn‖²/2 + δ_curv ── - have h_Un1_half : Un1 / 2 = ‖wn‖ ^ 2 / 2 + δ_curv := by - rw [h_Un1_expand]; ring - -- ── Flat-case assembly (Step A core) ── - -- This is the heart of the Lyapunov contraction in the flat case. - -- Mathematically: the auxiliary variable recursion gives - -- w_n = (1-a)·P⊥v_n + √μ'·e_n - √η·P⊥g_n - -- and combining with descent, aiming, and the tangential identity yields - -- F_{n+1} + ‖w_n‖²/2 + T_{n+1} ≤ (1-a)·(F_n + U_n/2 + T_n) - have h_flat : Fn1 + ‖wn‖ ^ 2 / 2 + Tn1 ≤ - (1 - a) * (Fn + Un / 2 + Tn) + a * abs (@inner ℝ _ _ gn (P en)) := by - -- ═══ A: wn decomposition via auxVar_recursion ═══ - have hwn_eq : (wn : E d) = (1 - a) • (sn.v - P sn.v) + - Real.sqrt μ' • en - Real.sqrt η • (gn - P gn) := by - change un1 - Real.sqrt μ' • ξn = _ - have h_av := auxVar_recursion P μ' η ρ π f x₁ n hρ ha_pos hη_pos hμ' - have : (un1 : E d) = ((1 - a) • (sn.v - P sn.v) + Real.sqrt μ' • en - - Real.sqrt η • (gn - P gn)) + Real.sqrt μ' • ξn := by - change auxVar P μ' π f η ρ x₁ (n + 1) = _; exact h_av - rw [this]; abel - -- ═══ B: Projector-freezing decomposition ═══ - -- ⟨g, e⟩ = ⟨P⊥g, e⟩ + ⟨g, Pe⟩ (via self-adjointness of P) - have h_ipGE_decomp : @inner ℝ _ _ gn en = - @inner ℝ _ _ (gn - P gn) en + @inner ℝ _ _ gn (P en) := by - have hsplit : gn = (gn - P gn) + P gn := by abel - conv_lhs => rw [hsplit] - rw [inner_add_left, hP_self_adj gn en] - have hG_pyth := pythagorean_proj P hP_self_adj hP_idem gn - have hV_pyth := pythagorean_proj P hP_self_adj hP_idem sn.v - have h_ip_decomp := inner_proj_decomp P hP_self_adj hP_idem gn sn.v - -- ═══ C: Explicit conversion of hFn'_bound to use en ═══ - -- (en is definitionally x'n - π x'n, so this is just type-checking) - have hFn1_le : Fn1 ≤ - @inner ℝ _ _ gn en - μ' / 2 * ‖en‖ ^ 2 - - η / 2 * ‖gn‖ ^ 2 := hFn'_bound - -- ═══ D: Norm expansions ═══ - have h_wn_sq : ‖wn‖ ^ 2 = - (1 - a) ^ 2 * ‖sn.v - P sn.v‖ ^ 2 + μ' * ‖en‖ ^ 2 + - η * ‖gn - P gn‖ ^ 2 + - 2 * (1 - a) * Real.sqrt μ' * @inner ℝ _ _ (sn.v - P sn.v) en - - 2 * (1 - a) * Real.sqrt η * @inner ℝ _ _ (sn.v - P sn.v) (gn - P gn) - - 2 * Real.sqrt μ' * Real.sqrt η * @inner ℝ _ _ en (gn - P gn) := by - rw [hwn_eq] - exact norm_three_term_sq _ _ _ _ _ _ (le_of_lt hμ') (le_of_lt hη_pos) - have h_un_eq : Un = ‖sn.v - P sn.v‖ ^ 2 + μ' * ‖en‖ ^ 2 + - 2 * Real.sqrt μ' * @inner ℝ _ _ (sn.v - P sn.v) en := by - change ‖un‖ ^ 2 = _ - exact norm_two_term_sq _ _ _ (le_of_lt hμ') - have h_un_eq' : Un = ‖sn.v - P sn.v‖ ^ 2 + - 2 * Real.sqrt μ' * @inner ℝ _ _ (sn.v - P sn.v) en + μ' * ‖en‖ ^ 2 := by - linarith - have h_Tn1_exp : Tn1 = (1 - a) / 2 * ‖P sn.v‖ ^ 2 - - (1 - a) * Real.sqrt η * @inner ℝ _ _ (P sn.v) (P gn) + - (1 - a) / 2 * η * ‖P gn‖ ^ 2 := by - rw [hTn1_val, h_expand, h_inner, h_norm_smul]; ring - have h_sqrt_prod : Real.sqrt μ' * Real.sqrt η = a := by - change Real.sqrt μ' * Real.sqrt η = Real.sqrt (μ' * η) - rw [← Real.sqrt_mul (le_of_lt hμ')] - -- Key coefficient identity: 2·√μ'·√η = 2·a (for norm simplification) - have h2a : 2 * Real.sqrt μ' * Real.sqrt η = 2 * a := by - have : (2 : ℝ) * Real.sqrt μ' * Real.sqrt η = - 2 * (Real.sqrt μ' * Real.sqrt η) := by ring - rw [this, h_sqrt_prod] - -- ═══ E: ‖wn‖²/2 with √μ'·√η replaced by a ═══ - have h_wn_half : ‖wn‖ ^ 2 / 2 = - (1 - a) ^ 2 / 2 * ‖sn.v - P sn.v‖ ^ 2 + μ' / 2 * ‖en‖ ^ 2 + - η / 2 * ‖gn - P gn‖ ^ 2 + - (1 - a) * Real.sqrt μ' * @inner ℝ _ _ (sn.v - P sn.v) en - - (1 - a) * Real.sqrt η * @inner ℝ _ _ (sn.v - P sn.v) (gn - P gn) - - a * @inner ℝ _ _ en (gn - P gn) := by - rw [h_wn_sq, h2a]; ring - -- ═══ G: Segment estimate ═══ - have hxn_Up : sn.x ∈ U_plus := hΩp_sub_Up (hΩ_sub_Ωp hx_in) - have h_path : ∀ t : ℝ, 0 ≤ t → t ≤ 1 → - (1 - t) • sn.x + t • x'n ∈ U_plus := by - intro t ht0 ht1 - exact hΩp_sub_Up (hΩ_sub_Ωp - ((convex_ball m_star (min (r₀ / 9) R_abs)) hx_in hx'_in - (by linarith : (0 : ℝ) ≤ 1 - t) ht0 (by linarith : (1 : ℝ) - t + t = 1))) - have h_seg_raw := hSegment x'n sn.x hx'n_Up hxn_Up h_path - have h_diff_eq : x'n - sn.x = Real.sqrt η • sn.v := by - change sn.x + Real.sqrt η • sn.v - sn.x = _; abel - have h_diff_sq : ‖x'n - sn.x‖ ^ 2 = η * ‖sn.v‖ ^ 2 := by - rw [h_diff_eq, norm_smul, Real.norm_eq_abs, - abs_of_nonneg (Real.sqrt_nonneg η), mul_pow, - Real.sq_sqrt (le_of_lt hη_pos)] - have h_inner_diff : @inner ℝ _ _ gn (x'n - sn.x) = - Real.sqrt η * @inner ℝ _ _ gn sn.v := by - rw [h_diff_eq, inner_smul_right] - -- ═══ H: Apply flat_case_arithmetic ═══ - -- Set up intermediate quantities for the arithmetic lemma - set Fnprime := f x'n - fStar f with hFnprime_def - -- Descent bound: Fn1 ≤ Fnprime - η/2·(‖Pg‖² + ‖P⊥g‖²) - have hFn1_descent : Fn1 ≤ Fnprime - η / 2 * (‖P gn‖ ^ 2 + ‖gn - P gn‖ ^ 2) := by - have h_mid : Fn1 ≤ Fnprime - η / 2 * ‖gn‖ ^ 2 := by linarith [hFn'_bound, h_aim] - have h_eq : η / 2 * ‖gn‖ ^ 2 = η / 2 * (‖P gn‖ ^ 2 + ‖gn - P gn‖ ^ 2) := by - rw [hG_pyth] - linarith - -- Segment: √η·(⟨Pg,Pv⟩ + ⟨P⊥g,P⊥v⟩) ≥ Fnprime - Fn - εη/2·(‖Pv‖² + ‖P⊥v‖²) - have h_segment_arith : - Real.sqrt η * (@inner ℝ _ _ (P gn) (P sn.v) + - @inner ℝ _ _ (gn - P gn) (sn.v - P sn.v)) ≥ - Fnprime - Fn - ε * η / 2 * (‖P sn.v‖ ^ 2 + ‖sn.v - P sn.v‖ ^ 2) := by - -- From segment estimate: ⟨gn, x'n - sn.x⟩ ≥ f(x'n) - f(sn.x) - ε/2·‖x'n-sn.x‖² - have h1 := h_seg_raw - rw [h_inner_diff, h_diff_sq] at h1 - -- h1: √η·⟨gn,sn.v⟩ ≥ Fnprime - Fn - εη/2·‖sn.v‖² - -- Use ip_decomp and V_pyth to rewrite - rw [h_ip_decomp, hV_pyth] at h1 - linarith - -- Aiming: ⟨P⊥g, en⟩ ≥ Fnprime + μ'/2·‖en‖² − |⟨g, Pe⟩| (projector-freezing error) - have h_aiming_arith : @inner ℝ _ _ (gn - P gn) en ≥ - Fnprime + μ' / 2 * ‖en‖ ^ 2 - abs (@inner ℝ _ _ gn (P en)) := by - -- Convert h_aim to use set-abbreviations gn, en, Fnprime - have h_aim' : @inner ℝ _ _ gn en ≥ Fnprime + μ' / 2 * ‖en‖ ^ 2 := h_aim - have hle := le_abs_self (@inner ℝ _ _ gn (P en)) - linarith [h_ipGE_decomp] - -- wn norm identity (with √μ'·√η = a) - have h_inner_comm_en_ppg : @inner ℝ _ _ en (gn - P gn) = - @inner ℝ _ _ (gn - P gn) en := real_inner_comm _ _ - have hwn_sq_arith : ‖wn‖ ^ 2 = - (1 - a) ^ 2 * ‖sn.v - P sn.v‖ ^ 2 + μ' * ‖en‖ ^ 2 + - η * ‖gn - P gn‖ ^ 2 + - 2 * (1 - a) * Real.sqrt μ' * @inner ℝ _ _ (sn.v - P sn.v) en - - 2 * (1 - a) * Real.sqrt η * @inner ℝ _ _ (gn - P gn) (sn.v - P sn.v) - - 2 * a * @inner ℝ _ _ (gn - P gn) en := by - rw [h_wn_sq, h2a, h_inner_comm_en_ppg] - have h_ic3 : @inner ℝ _ _ (sn.v - P sn.v) (gn - P gn) = - @inner ℝ _ _ (gn - P gn) (sn.v - P sn.v) := real_inner_comm _ _ - rw [h_ic3] - -- Tn1 identity (matching flat_case_arithmetic parameter order) - have hTn1_arith : Tn1 = (1 - a) / 2 * ‖P sn.v‖ ^ 2 - - (1 - a) * Real.sqrt η * @inner ℝ _ _ (P gn) (P sn.v) + - (1 - a) * η / 2 * ‖P gn‖ ^ 2 := by - have h_PgPv_comm : @inner ℝ _ _ (P sn.v) (P gn) = - @inner ℝ _ _ (P gn) (P sn.v) := real_inner_comm _ _ - rw [h_Tn1_exp, h_PgPv_comm]; ring - -- Tn identity - have hTn_arith : Tn = (1 + a) ^ 2 / (2 * (1 - a)) * ‖P sn.v‖ ^ 2 := by - rw [hTn_def, hlam_def] - -- Fnprime ≥ 0 - have hFnprime_nn : 0 ≤ Fnprime := by - change 0 ≤ f x'n - fStar f - exact sub_nonneg.mpr (ciInf_le hbdd x'n) - -- Un nonnegativity - have hUn_nn : 0 ≤ Un := by - change 0 ≤ ‖un‖ ^ 2; exact sq_nonneg _ - -- Apply the arithmetic lemma - have hpe_abs_nn : (0 : ℝ) ≤ abs (@inner ℝ _ _ gn (P en)) := abs_nonneg _ - exact flat_case_arithmetic a ha_pos ha_lt1 - η μ' (Real.sqrt μ') (Real.sqrt η) - hη_pos hμ' (Real.sqrt_nonneg _) (Real.sqrt_nonneg _) - (Real.sq_sqrt (le_of_lt hμ')) (Real.sq_sqrt (le_of_lt hη_pos)) - h_sqrt_prod - (ε * η) (mul_nonneg (le_of_lt hε_pos) (le_of_lt hη_pos)) hε_bound - Fn Fn1 Fnprime hgap_nn hgap'_nn hFnprime_nn - (‖P sn.v‖ ^ 2) (‖sn.v - P sn.v‖ ^ 2) (‖P gn‖ ^ 2) (‖gn - P gn‖ ^ 2) (‖en‖ ^ 2) - (sq_nonneg _) (sq_nonneg _) (sq_nonneg _) (sq_nonneg _) (sq_nonneg _) - (@inner ℝ _ _ (gn - P gn) en) (@inner ℝ _ _ (P gn) (P sn.v)) - (@inner ℝ _ _ (gn - P gn) (sn.v - P sn.v)) (@inner ℝ _ _ (sn.v - P sn.v) en) - (abs (@inner ℝ _ _ gn (P en))) hpe_abs_nn - hFn1_descent h_segment_arith h_aiming_arith - (‖wn‖ ^ 2) hwn_sq_arith - Un h_un_eq' - Tn1 hTn1_arith - Tn hTn_arith - -- ── Total perturbation absorption (Step B) ── - -- Curvature (ξ_n) + projector-freezing (|⟨g, Pe⟩|) terms are absorbed - -- by shrinking Ω and R. The hypothesis h_curv_absorb provides this. - -- Derive Ln ≤ R_abs² from Ln ≤ (min(r₀/9, R_abs))² ≤ R_abs² - have hLn_le_Rabs : Ln ≤ R_abs ^ 2 := by - calc Ln ≤ (min (r₀ / 9) R_abs) ^ 2 := hLn_bound - _ ≤ R_abs ^ 2 := by - apply pow_le_pow_left₀ (le_min (le_of_lt hr₀9) (le_of_lt hR_abs)) - (min_le_right _ _) - set proj_err_n := a * abs (@inner ℝ _ _ gn (P en)) with hproj_err_def - have h_absorb : δ_curv + proj_err_n ≤ θ * a * Ln := - h_curv_absorb x₁ n (hΩ_sub_Rabs hx_in) (hΩ_sub_Rabs hx'_in) - hLn_le_Rabs - -- ── Final assembly ── - apply two_step_contraction_general a θ Ln Ln' (δ_curv + proj_err_n) - ha_pos ha_lt1 hθ_pos hθ_lt1 hLn_nn - · -- Goal: Ln' ≤ (1-a) * Ln + (δ_curv + proj_err_n) - rw [hLn'_eq, hLn_eq] - linarith [h_Un1_half, h_flat] - · -- Goal: (δ_curv + proj_err_n) ≤ θ * a * Ln - exact h_absorb - case x_next_in => - /- Uses shared hηL and hg_zero_mstar. -/ - rw [Metric.mem_ball] - have hgrad_lip : ‖gn‖ ≤ (L : ℝ) * dist x'n m_star := by - have h := hf_lip.dist_le_mul x'n (hΩp_sub_Up (hΩ_sub_Ωp hx'_in)) m_star hm_star_Up - rwa [hg_zero_mstar, dist_zero_right] at h - have h_sn1_x : sn1.x = x'n - η • gn := rfl - have h_step_dist : dist sn1.x x'n = η * ‖gn‖ := by - rw [h_sn1_x, dist_eq_norm] - have : (x'n - η • gn) - x'n = -(η • gn) := by abel - rw [this, norm_neg, norm_smul, Real.norm_eq_abs, abs_of_pos hη_pos] - calc dist sn1.x m_star - ≤ dist sn1.x x'n + dist x'n m_star := dist_triangle _ _ _ - _ = η * ‖gn‖ + dist x'n m_star := by rw [h_step_dist] - _ ≤ η * ((L : ℝ) * dist x'n m_star) + dist x'n m_star := by - linarith [mul_le_mul_of_nonneg_left hgrad_lip (le_of_lt hη_pos)] - _ = 2 * dist x'n m_star := by - have : η * ((L : ℝ) * dist x'n m_star) = dist x'n m_star := by - rw [← mul_assoc, hηL, one_mul] - linarith - _ < 2 * r₀ / 3 := by linarith [hx'_ball_r09] - case x'_next_in => - /- x'_{n+1} = (1+ρ)·x_{n+1} - ρ·x_n (convex-like combination). - Need: x'_{n+1} ∈ B(m⋆, 2r₀/3). - By triangle inequality via this identity: - dist(x'_{n+1}, m⋆) ≤ (1+ρ)·dist(x_{n+1}, m⋆) + ρ·dist(x_n, m⋆) - < (1+ρ)·2(r₀/9) + ρ·(r₀/9) - = (2+3ρ)/9 · r₀ < 5r₀/9 < 2r₀/3. -/ - rw [Metric.mem_ball] - have hx_ball := Metric.mem_ball.mp hx_in - have hx_ball_r09 : dist sn.x m_star < r₀ / 9 := - lt_of_lt_of_le hx_ball (min_le_left _ _) - have hgrad_lip : ‖gn‖ ≤ (L : ℝ) * dist x'n m_star := by - have h := hf_lip.dist_le_mul x'n (hΩp_sub_Up (hΩ_sub_Ωp hx'_in)) m_star hm_star_Up - rwa [hg_zero_mstar, dist_zero_right] at h - have hρ_lt1 : ρ < 1 := by - rw [hρ]; rw [div_lt_one (by linarith : (0 : ℝ) < 1 + a)]; linarith - -- Key identity: x'_{n+1} = (1+ρ)·x_{n+1} - ρ·x_n - have h_conv : sn1.lookahead η = (1 + ρ) • sn1.x - ρ • sn.x := by - change sn1.x + Real.sqrt η • sn1.v = (1 + ρ) • sn1.x - ρ • sn.x - have hsq : Real.sqrt η * Real.sqrt η = η := - Real.mul_self_sqrt (le_of_lt hη_pos) - have h5 : Real.sqrt η • (ρ • (sn.v - Real.sqrt η • gn)) = - ρ • (Real.sqrt η • sn.v - η • gn) := by - rw [smul_comm (Real.sqrt η) ρ, smul_sub, ← mul_smul, hsq] - change (x'n - η • gn) + Real.sqrt η • (ρ • (sn.v - Real.sqrt η • gn)) = - (1 + ρ) • (x'n - η • gn) - ρ • sn.x - rw [h5] - change (sn.x + Real.sqrt η • sn.v - η • gn) + - ρ • (Real.sqrt η • sn.v - η • gn) = - (1 + ρ) • (sn.x + Real.sqrt η • sn.v - η • gn) - ρ • sn.x - module - -- Distance bound on x_{n+1}: dist(x_{n+1}, m⋆) < 2·(r₀/9) - have h_sn1_dist : dist sn1.x m_star < 2 * (r₀ / 9) := by - have h_sn1_x : sn1.x = x'n - η • gn := rfl - have h_step_dist : dist sn1.x x'n = η * ‖gn‖ := by - rw [h_sn1_x, dist_eq_norm] - have : (x'n - η • gn) - x'n = -(η • gn) := by abel - rw [this, norm_neg, norm_smul, Real.norm_eq_abs, abs_of_pos hη_pos] - calc dist sn1.x m_star - ≤ dist sn1.x x'n + dist x'n m_star := dist_triangle _ _ _ - _ = η * ‖gn‖ + dist x'n m_star := by rw [h_step_dist] - _ ≤ η * ((L : ℝ) * dist x'n m_star) + dist x'n m_star := by - linarith [mul_le_mul_of_nonneg_left hgrad_lip (le_of_lt hη_pos)] - _ = 2 * dist x'n m_star := by - have : η * ((L : ℝ) * dist x'n m_star) = dist x'n m_star := by - rw [← mul_assoc, hηL, one_mul] - linarith - _ < 2 * (r₀ / 9) := by linarith [hx'_ball_r09] - -- Subtract m_star using the convex combination identity - have h_sub : sn1.lookahead η - m_star = - (1 + ρ) • (sn1.x - m_star) - ρ • (sn.x - m_star) := by - rw [h_conv]; module - -- Main distance bound via triangle inequality - calc dist (sn1.lookahead η) m_star - = ‖sn1.lookahead η - m_star‖ := dist_eq_norm _ _ - _ = ‖(1 + ρ) • (sn1.x - m_star) - ρ • (sn.x - m_star)‖ := by - rw [h_sub] - _ ≤ ‖(1 + ρ) • (sn1.x - m_star)‖ + ‖ρ • (sn.x - m_star)‖ := - norm_sub_le _ _ - _ = (1 + ρ) * ‖sn1.x - m_star‖ + ρ * ‖sn.x - m_star‖ := by - rw [norm_smul, norm_smul, Real.norm_eq_abs, abs_of_pos (by linarith : (0:ℝ) < 1 + ρ), - Real.norm_eq_abs, abs_of_pos hρ_pos] - _ = (1 + ρ) * dist sn1.x m_star + ρ * dist sn.x m_star := by - simp only [dist_eq_norm] - _ < (1 + ρ) * (2 * (r₀ / 9)) + ρ * (r₀ / 9) := by - have h1 : (1 + ρ) * dist sn1.x m_star < (1 + ρ) * (2 * (r₀ / 9)) := - mul_lt_mul_of_pos_left h_sn1_dist (by linarith : (0:ℝ) < 1 + ρ) - have h2 : ρ * dist sn.x m_star < ρ * (r₀ / 9) := - mul_lt_mul_of_pos_left hx_ball_r09 hρ_pos - linarith - _ = (2 + 3 * ρ) / 9 * r₀ := by ring - _ < 2 / 3 * r₀ := by - have hcoef : (2 + 3 * ρ) / 9 < (2 : ℝ) / 3 := by linarith - exact mul_lt_mul_of_pos_right hcoef hr₀_pos - _ = 2 * r₀ / 3 := by ring - - -/-- Public theorem wrapper for `lyapunovContractionProof`. -/ theorem lyapunov_contraction {d : ℕ} (_hd : 0 < d) -- The objective function @@ -796,14 +126,11 @@ theorem lyapunov_contraction Ln' ≤ (1 - (1 - θ) * a) * Ln ∧ -- Next iterates in Ω⁺ s'.x ∈ Ω_plus ∧ s'.lookahead η ∈ Ω_plus := by - exact lyapunovContractionProof (d := d) (_hd := _hd) (f := f) (L := L) (hL := hL) (μ' := μ') - (hμ' := hμ') (θ := θ) (hθ_pos := hθ_pos) (hθ_lt1 := hθ_lt1) (η := η) (hη := hη) - (hη_pos := hη_pos) (ρ := ρ) (hρ := hρ) (S := S) (hM_argmin := hM_argmin) (π := π) - (_hπ_in_S := _hπ_in_S) (_hπ_proj := _hπ_proj) (hgrad_zero := hgrad_zero) (P := P) - (m_star := m_star) (hm_star := hm_star) (ε := ε) (hε_pos := hε_pos) (hε_bound := hε_bound) - (hμη_lt1 := hμη_lt1) (U_plus := U_plus) (hU_open := hU_open) (hm_star_Up := hm_star_Up) - (hf_diff_on := hf_diff_on) (hf_lip := hf_lip) (hStrAim := hStrAim) (hHess_lower := hHess_lower) - (_hπ_kills_normal := _hπ_kills_normal) (hP_self_adj := hP_self_adj) (hP_idem := hP_idem) - (hSegment := hSegment) (R_abs := R_abs) (hR_abs := hR_abs) (h_curv_absorb := h_curv_absorb) + obtain ⟨Ω, Ω_plus, R, hΩ, hΩp, hR, hm, hsub, hsubp, h⟩ := + lyapunov_contraction_of_state f L hL μ' hμ' θ hθ_pos hθ_lt1 η hη hη_pos ρ hρ S hM_argmin + π hgrad_zero P m_star hm_star ε hε_pos hε_bound hμη_lt1 U_plus hU_open hm_star_Up + hf_diff_on hf_lip hStrAim hHess_lower hP_self_adj hP_idem hSegment R_abs hR_abs + exact ⟨Ω, Ω_plus, R, hΩ, hΩp, hR, hm, hsub, hsubp, + fun x₁ n => h (nesterovSeq f η ρ x₁ n) (h_curv_absorb x₁ n)⟩ end PLAcceleratedNesterovLean diff --git a/LeanPool/PLAcceleratedNesterovLean/Core/EmbeddedManifold.lean b/LeanPool/PLAcceleratedNesterovLean/Core/EmbeddedManifold.lean index 02f503edcb..589ae8d21c 100644 --- a/LeanPool/PLAcceleratedNesterovLean/Core/EmbeddedManifold.lean +++ b/LeanPool/PLAcceleratedNesterovLean/Core/EmbeddedManifold.lean @@ -117,11 +117,195 @@ private abbrev isInvertible_of_bijective_finiteDimensional · ext x rfl --- IFT + chart argument: large because of manifold API elaboration +/-- An embedding written in the extended chart at `p` is `C²` at the chart image of `p`. -/ +private theorem contDiffAt_comp_extChartAt_symm_of_smoothEmbedding {d n : ℕ} + (M : Type*) [TopologicalSpace M] + [ChartedSpace (ManifoldModel n) M] + (ι : M → E d) + (hι : IsSmoothEmbedding (modelI n) (𝓘(ℝ, E d)) 2 ι) (p : M) : + ContDiffAt ℝ 2 (ι ∘ (extChartAt (modelI n) p).symm) (extChartAt (modelI n) p p) := by + let F := hι.isImmersion.complement + have hFp := hι.isImmersion.isImmersionOfComplement_complement p + have hp_ext_source : p ∈ (hFp.domChart.extend (modelI n)).source := by + rw [hFp.domChart.extend_source]; exact hFp.mem_domChart_source + have hp_inTarget := (hFp.domChart.extend (modelI n)).map_source hp_ext_source + have : (modelI n).Boundaryless := by unfold modelI; infer_instance + have htarget_open : IsOpen (hFp.domChart.extend (modelI n)).target := + hFp.domChart.isOpen_extend_target + have heq : (hFp.codChart.extend (𝓘(ℝ, E d)) ∘ ι ∘ (hFp.domChart.extend (modelI n)).symm) + =ᶠ[𝓝 (hFp.domChart.extend (modelI n) p)] + (↑hFp.equiv ∘ fun v => (v, (0 : F))) := + hFp.writtenInCharts.eventuallyEq_of_mem (htarget_open.mem_nhds hp_inTarget) + have hsmooth : ContDiffAt ℝ 2 (↑hFp.equiv ∘ fun v => (v, (0 : F))) + (hFp.domChart.extend (modelI n) p) := + (hFp.equiv.contDiff.comp (contDiff_prodMk_left 0)).contDiffAt + have hcoord_cda := hsmooth.congr_of_eventuallyEq heq + have hι_cont : ContinuousAt ι p := hι.isEmbedding.continuous.continuousAt + have hι_cmd : ContMDiffAt (modelI n) (𝓘(ℝ, E d)) 2 ι p := by + change ContMDiffWithinAt (modelI n) (𝓘(ℝ, E d)) 2 ι Set.univ p + rw [contMDiffWithinAt_iff_of_mem_maximalAtlas + hFp.domChart_mem_maximalAtlas hFp.codChart_mem_maximalAtlas + hFp.mem_domChart_source hFp.mem_codChart_source] + exact ⟨hι_cont.continuousWithinAt, hcoord_cda.contDiffWithinAt⟩ + rw [contMDiffAt_iff] at hι_cmd + simp only [modelI, extChartAt_model_space_eq_id, PartialEquiv.refl_coe, + modelWithCornersSelf_coe, Set.range_id, contDiffWithinAt_univ] at hι_cmd + exact hι_cmd.2 + +/-- An immersion written in the extended chart at `p` has injective derivative at the chart +image of `p`. -/ +private theorem injective_fderiv_comp_extChartAt_symm_of_smoothEmbedding {d n : ℕ} + (M : Type*) [TopologicalSpace M] + [ChartedSpace (ManifoldModel n) M] + [IsManifold (modelI n) 2 M] + (ι : M → E d) + (hι : IsSmoothEmbedding (modelI n) (𝓘(ℝ, E d)) 2 ι) (p : M) : + Function.Injective + (fderiv ℝ (ι ∘ (extChartAt (modelI n) p).symm) (extChartAt (modelI n) p p)) := by + let c := extChartAt (modelI n) p + let a := c p + let g : ManifoldModel n → E d := ι ∘ c.symm + have hp_source : p ∈ c.source := mem_extChartAt_source p + have hg_smooth : ContDiffAt ℝ 2 g a := + contDiffAt_comp_extChartAt_symm_of_smoothEmbedding M ι hι p + change Function.Injective (fderiv ℝ g a) + let F := hι.isImmersion.complement + have hFp := hι.isImmersion.isImmersionOfComplement_complement p + have : (modelI n).Boundaryless := by unfold modelI; infer_instance + have hg_diff' : DifferentiableAt ℝ g a := hg_smooth.differentiableAt (by norm_num) + have hp_ext_source : p ∈ (hFp.domChart.extend (modelI n)).source := by + rw [hFp.domChart.extend_source]; exact hFp.mem_domChart_source + set transition : ManifoldModel n → ManifoldModel n := + hFp.domChart.extend (modelI n) ∘ ↑c.symm with htrans_def + have hcsymm_mem : ∀ᶠ y in 𝓝 a, c.symm y ∈ hFp.domChart.source := by + have hcont := continuousAt_extChartAt_symm (I := modelI n) p + have h_mem : hFp.domChart.source ∈ 𝓝 (c.symm a) := by + rw [c.left_inv hp_source] + exact hFp.domChart.open_source.mem_nhds hFp.mem_domChart_source + exact hcont h_mem + have ha_target : a ∈ c.target := c.map_source hp_source + have htarget_mem := (isOpen_extChartAt_target (I := modelI n) p).mem_nhds ha_target + have htarget_open : IsOpen (hFp.domChart.extend (modelI n)).target := + hFp.domChart.isOpen_extend_target + have heq_comp : (↑(hFp.codChart.extend (𝓘(ℝ, E d))) ∘ g) + =ᶠ[𝓝 a] (↑hFp.equiv ∘ fun v => (v, (0 : F))) ∘ transition := by + filter_upwards [hcsymm_mem] with y hy + simp only [Function.comp] + have hy' : c.symm y ∈ (hFp.domChart.extend (modelI n)).source := by + rwa [OpenPartialHomeomorph.extend_source] + have hz := hFp.writtenInCharts ((hFp.domChart.extend (modelI n)).map_source hy') + simp only [Function.comp] at hz + rwa [(hFp.domChart.extend (modelI n)).left_inv hy'] at hz + have hfderiv_eq := heq_comp.fderiv_eq (𝕜 := ℝ) + have htrans_diff : DifferentiableAt ℝ transition a := by + have h := ModelWithCorners.contDiffWithinAt_extendCoordChange' (I := modelI n) + (IsManifold.chart_mem_maximalAtlas (I := modelI n) p) + hFp.domChart_mem_maximalAtlas + (mem_chart_source (ManifoldModel n) p) hFp.mem_domChart_source + simp only [modelI, modelWithCornersSelf_coe, Set.range_id, contDiffWithinAt_univ] at h + simpa [transition, htrans_def, a, c, extChartAt, modelI] using + h.differentiableAt (by norm_num) + have hinv_comp_eq : (↑c ∘ ↑(hFp.domChart.extend (modelI n)).symm) ∘ transition + =ᶠ[𝓝 a] id := by + filter_upwards [hcsymm_mem, htarget_mem] with y hy1 hy2 + simp only [Function.comp, id, htrans_def] + have hy1' : c.symm y ∈ (hFp.domChart.extend (modelI n)).source := by + rwa [OpenPartialHomeomorph.extend_source] + rw [(hFp.domChart.extend (modelI n)).left_inv hy1', c.right_inv hy2] + have htrans_a : transition a = hFp.domChart.extend (modelI n) p := by + change (hFp.domChart.extend (modelI n)) (c.symm (c p)) = _ + rw [c.left_inv hp_source] + have hinv_diff : DifferentiableAt ℝ (↑c ∘ ↑(hFp.domChart.extend (modelI n)).symm) + (transition a) := by + have h := ModelWithCorners.contDiffWithinAt_extendCoordChange' (I := modelI n) + hFp.domChart_mem_maximalAtlas + (IsManifold.chart_mem_maximalAtlas (I := modelI n) p) + hFp.mem_domChart_source (mem_chart_source (ManifoldModel n) p) + simp only [modelI, modelWithCornersSelf_coe, Set.range_id, contDiffWithinAt_univ] at h + simpa [htrans_a, c, extChartAt, modelI] using h.differentiableAt (by norm_num) + have hcomp_id : fderiv ℝ ((↑c ∘ ↑(hFp.domChart.extend (modelI n)).symm) ∘ transition) a = + ContinuousLinearMap.id ℝ _ := by + rw [hinv_comp_eq.fderiv_eq (𝕜 := ℝ), fderiv_id] + have hchain := fderiv_comp (x := a) hinv_diff htrans_diff + rw [hchain] at hcomp_id + have htrans_inj : Function.Injective (fderiv ℝ transition a) := + Function.HasLeftInverse.injective ⟨fderiv ℝ (↑c ∘ ↑(hFp.domChart.extend (modelI n)).symm) + (transition a), fun x => by + have := congr_fun (congr_arg DFunLike.coe hcomp_id) x + simp only [ContinuousLinearMap.comp_apply, ContinuousLinearMap.id_apply] at this + exact this⟩ + set equiv_inl : ManifoldModel n →L[ℝ] E d := + hFp.equiv.toContinuousLinearMap.comp (ContinuousLinearMap.inl ℝ _ F) with hequiv_inl_def + have hequiv_inl_eq : ↑hFp.equiv ∘ (fun v => (v, (0 : F))) = ⇑equiv_inl := by + ext v; simp [equiv_inl, ContinuousLinearMap.comp_apply, ContinuousLinearMap.inl_apply] + have hequiv_inl_inj : Function.Injective equiv_inl := + hFp.equiv.injective.comp (fun x y h => (Prod.mk.inj h).1) + have hrhs_inj : Function.Injective + (fderiv ℝ ((↑hFp.equiv ∘ fun v => (v, (0 : F))) ∘ transition) a) := by + rw [hequiv_inl_eq] + rw [fderiv_comp (x := a) equiv_inl.differentiableAt htrans_diff, + ContinuousLinearMap.fderiv] + exact hequiv_inl_inj.comp htrans_inj + rw [← hfderiv_eq] at hrhs_inj + have hcodchart_diff : DifferentiableAt ℝ (↑(hFp.codChart.extend (𝓘(ℝ, E d)))) (g a) := by + have hga : g a = ι p := by change ι (c.symm (c p)) = ι p; rw [c.left_inv hp_source] + rw [hga] + have h := ModelWithCorners.contDiffWithinAt_extendCoordChange' (I := 𝓘(ℝ, E d)) + (IsManifold.chart_mem_maximalAtlas (I := 𝓘(ℝ, E d)) (ι p)) + hFp.codChart_mem_maximalAtlas + (mem_chart_source (E d) (ι p)) hFp.mem_codChart_source + simp only [modelWithCornersSelf_coe, Set.range_id, contDiffWithinAt_univ] at h + simpa [chartAt_self_eq, extChartAt_model_space_eq_id, PartialEquiv.refl_coe] using + h.differentiableAt (by norm_num) + rw [fderiv_comp (x := a) hcodchart_diff hg_diff'] at hrhs_inj + intro x y hxy + apply hrhs_inj + simp only [ContinuousLinearMap.comp_apply, hxy] + +/-- A map that is `C²` at `0` agrees near `0` with a globally `C²` map, obtained by +multiplying with a smooth bump function. -/ +private theorem exists_contDiff_eventuallyEq_of_contDiffAt_zero + {V W : Type*} [NormedAddCommGroup V] [InnerProductSpace ℝ V] + [NormedAddCommGroup W] [NormedSpace ℝ W] {φ_raw : V → W} + (hφ_raw_smooth_at : ContDiffAt ℝ 2 φ_raw 0) : + ∃ φ : V → W, ContDiff ℝ 2 φ ∧ φ =ᶠ[𝓝 0] φ_raw := by + have hφ_raw_ev : ∀ᶠ v in 𝓝 (0 : V), ContDiffAt ℝ 2 φ_raw v := + hφ_raw_smooth_at.eventually (by norm_num) + obtain ⟨ε, hε_pos, hε_ball⟩ := Metric.eventually_nhds_iff.mp hφ_raw_ev + -- Construct smooth bump χ equal to 1 near 0 with support inside ball 0 ε + let bump : ContDiffBump (0 : V) := + { rIn := ε / 3 + rOut := ε / 2 + rIn_pos := by positivity + rIn_lt_rOut := by linarith } + -- Define bump-extended φ := bump • φ_raw, which is globally C² + set φ : V → W := fun v => bump v • φ_raw v + -- Near 0, bump = 1 so φ = φ_raw + have hφ_eq_raw_near : φ =ᶠ[𝓝 0] φ_raw := by + filter_upwards [bump.eventuallyEq_one] with v hv + change bump v • φ_raw v = φ_raw v + have hbv : (↑bump : V → ℝ) v = 1 := by simpa using hv + rw [hbv, one_smul] + have hφ_smooth : ContDiff ℝ 2 φ := by + rw [contDiff_iff_contDiffAt] + intro v + by_cases hv : v ∈ tsupport (↑bump : V → ℝ) + · have hv_dist : dist v 0 < ε := by + have hmem : v ∈ Metric.closedBall (0 : V) (ε / 2) := bump.tsupport_eq ▸ hv + exact lt_of_le_of_lt (Metric.mem_closedBall.mp hmem) (by linarith) + exact (bump.contDiff (n := 2)).contDiffAt.smul (hε_ball hv_dist) + · have hφ_eq_zero : φ =ᶠ[𝓝 v] (fun _ : V => (0 : W)) := by + filter_upwards [notMem_tsupport_iff_eventuallyEq.mp hv] with w hw + change bump w • φ_raw w = (0 : W) + have hbw : (↑bump : V → ℝ) w = 0 := by simpa using hw + rw [hbw, zero_smul] + exact contDiffAt_const.congr_of_eventuallyEq hφ_eq_zero + exact ⟨φ, hφ_smooth, hφ_eq_raw_near⟩ + /-- At each point of a C² smooth embedding, the image is locally a C² graph over an n-dimensional subspace, with φ(0) = 0, Dφ(0) = 0. (IFT applied to the embedding.) -/ -private abbrev smooth_embedding_local_graph {d n : ℕ} +private theorem smooth_embedding_local_graph {d n : ℕ} (M : Type*) [TopologicalSpace M] [ChartedSpace (ManifoldModel n) M] [IsManifold (modelI n) 2 M] @@ -144,130 +328,13 @@ private abbrev smooth_embedding_local_graph {d n : ℕ} let g : ManifoldModel n → E d := ι ∘ c.symm have hp_source : p ∈ c.source := mem_extChartAt_source p -- Step 3: Key analytic properties of g - have hg_smooth : ContDiffAt ℝ 2 g a := by - let F := hι.isImmersion.complement - have hFp := hι.isImmersion.isImmersionOfComplement_complement p - have hp_ext_source : p ∈ (hFp.domChart.extend (modelI n)).source := by - rw [hFp.domChart.extend_source]; exact hFp.mem_domChart_source - have hp_inTarget := (hFp.domChart.extend (modelI n)).map_source hp_ext_source - have : (modelI n).Boundaryless := by unfold modelI; infer_instance - have htarget_open : IsOpen (hFp.domChart.extend (modelI n)).target := - hFp.domChart.isOpen_extend_target - have heq : (hFp.codChart.extend (𝓘(ℝ, E d)) ∘ ι ∘ (hFp.domChart.extend (modelI n)).symm) - =ᶠ[𝓝 (hFp.domChart.extend (modelI n) p)] - (↑hFp.equiv ∘ fun v => (v, (0 : F))) := - hFp.writtenInCharts.eventuallyEq_of_mem (htarget_open.mem_nhds hp_inTarget) - have hsmooth : ContDiffAt ℝ 2 (↑hFp.equiv ∘ fun v => (v, (0 : F))) - (hFp.domChart.extend (modelI n) p) := - (hFp.equiv.contDiff.comp (contDiff_prodMk_left 0)).contDiffAt - have hcoord_cda := hsmooth.congr_of_eventuallyEq heq - have hι_cont : ContinuousAt ι p := hι.isEmbedding.continuous.continuousAt - have hι_cmd : ContMDiffAt (modelI n) (𝓘(ℝ, E d)) 2 ι p := by - change ContMDiffWithinAt (modelI n) (𝓘(ℝ, E d)) 2 ι Set.univ p - rw [contMDiffWithinAt_iff_of_mem_maximalAtlas - hFp.domChart_mem_maximalAtlas hFp.codChart_mem_maximalAtlas - hFp.mem_domChart_source hFp.mem_codChart_source] - exact ⟨hι_cont.continuousWithinAt, hcoord_cda.contDiffWithinAt⟩ - rw [contMDiffAt_iff] at hι_cmd - simp only [modelI, extChartAt_model_space_eq_id, PartialEquiv.refl_coe, - modelWithCornersSelf_coe, Set.range_id, contDiffWithinAt_univ] at hι_cmd - exact hι_cmd.2 + have hg_smooth : ContDiffAt ℝ 2 g a := + contDiffAt_comp_extChartAt_symm_of_smoothEmbedding M ι hι p have hg_a : g a = m := by change ι (c.symm (c p)) = m rw [PartialEquiv.left_inv c hp_source, hp] - have hg_inj : Function.Injective (fderiv ℝ g a) := by - let F := hι.isImmersion.complement - have hFp := hι.isImmersion.isImmersionOfComplement_complement p - have : (modelI n).Boundaryless := by unfold modelI; infer_instance - have hg_diff' : DifferentiableAt ℝ g a := hg_smooth.differentiableAt (by norm_num) - have hp_ext_source : p ∈ (hFp.domChart.extend (modelI n)).source := by - rw [hFp.domChart.extend_source]; exact hFp.mem_domChart_source - set transition : ManifoldModel n → ManifoldModel n := - hFp.domChart.extend (modelI n) ∘ ↑c.symm with htrans_def - have hcsymm_mem : ∀ᶠ y in 𝓝 a, c.symm y ∈ hFp.domChart.source := by - have hcont := continuousAt_extChartAt_symm (I := modelI n) p - have h_mem : hFp.domChart.source ∈ 𝓝 (c.symm a) := by - rw [c.left_inv hp_source] - exact hFp.domChart.open_source.mem_nhds hFp.mem_domChart_source - exact hcont h_mem - have ha_target : a ∈ c.target := c.map_source hp_source - have htarget_mem := (isOpen_extChartAt_target (I := modelI n) p).mem_nhds ha_target - have htarget_open : IsOpen (hFp.domChart.extend (modelI n)).target := - hFp.domChart.isOpen_extend_target - have heq_comp : (↑(hFp.codChart.extend (𝓘(ℝ, E d))) ∘ g) - =ᶠ[𝓝 a] (↑hFp.equiv ∘ fun v => (v, (0 : F))) ∘ transition := by - filter_upwards [hcsymm_mem] with y hy - simp only [Function.comp] - have hy' : c.symm y ∈ (hFp.domChart.extend (modelI n)).source := by - rwa [OpenPartialHomeomorph.extend_source] - have hz := hFp.writtenInCharts ((hFp.domChart.extend (modelI n)).map_source hy') - simp only [Function.comp] at hz - rwa [(hFp.domChart.extend (modelI n)).left_inv hy'] at hz - have hfderiv_eq := heq_comp.fderiv_eq (𝕜 := ℝ) - have htrans_diff : DifferentiableAt ℝ transition a := by - have h := ModelWithCorners.contDiffWithinAt_extendCoordChange' (I := modelI n) - (IsManifold.chart_mem_maximalAtlas (I := modelI n) p) - hFp.domChart_mem_maximalAtlas - (mem_chart_source (ManifoldModel n) p) hFp.mem_domChart_source - simp only [modelI, modelWithCornersSelf_coe, Set.range_id, contDiffWithinAt_univ] at h - simpa [transition, htrans_def, a, c, extChartAt, modelI] using - h.differentiableAt (by norm_num) - have hinv_comp_eq : (↑c ∘ ↑(hFp.domChart.extend (modelI n)).symm) ∘ transition - =ᶠ[𝓝 a] id := by - filter_upwards [hcsymm_mem, htarget_mem] with y hy1 hy2 - simp only [Function.comp, id, htrans_def] - have hy1' : c.symm y ∈ (hFp.domChart.extend (modelI n)).source := by - rwa [OpenPartialHomeomorph.extend_source] - rw [(hFp.domChart.extend (modelI n)).left_inv hy1', c.right_inv hy2] - have htrans_a : transition a = hFp.domChart.extend (modelI n) p := by - change (hFp.domChart.extend (modelI n)) (c.symm (c p)) = _ - rw [c.left_inv hp_source] - have hinv_diff : DifferentiableAt ℝ (↑c ∘ ↑(hFp.domChart.extend (modelI n)).symm) - (transition a) := by - have h := ModelWithCorners.contDiffWithinAt_extendCoordChange' (I := modelI n) - hFp.domChart_mem_maximalAtlas - (IsManifold.chart_mem_maximalAtlas (I := modelI n) p) - hFp.mem_domChart_source (mem_chart_source (ManifoldModel n) p) - simp only [modelI, modelWithCornersSelf_coe, Set.range_id, contDiffWithinAt_univ] at h - simpa [htrans_a, c, extChartAt, modelI] using h.differentiableAt (by norm_num) - have hcomp_id : fderiv ℝ ((↑c ∘ ↑(hFp.domChart.extend (modelI n)).symm) ∘ transition) a = - ContinuousLinearMap.id ℝ _ := by - rw [hinv_comp_eq.fderiv_eq (𝕜 := ℝ), fderiv_id] - have hchain := fderiv_comp (x := a) hinv_diff htrans_diff - rw [hchain] at hcomp_id - have htrans_inj : Function.Injective (fderiv ℝ transition a) := - Function.HasLeftInverse.injective ⟨fderiv ℝ (↑c ∘ ↑(hFp.domChart.extend (modelI n)).symm) - (transition a), fun x => by - have := congr_fun (congr_arg DFunLike.coe hcomp_id) x - simp only [ContinuousLinearMap.comp_apply, ContinuousLinearMap.id_apply] at this - exact this⟩ - set equiv_inl : ManifoldModel n →L[ℝ] E d := - hFp.equiv.toContinuousLinearMap.comp (ContinuousLinearMap.inl ℝ _ F) with hequiv_inl_def - have hequiv_inl_eq : ↑hFp.equiv ∘ (fun v => (v, (0 : F))) = ⇑equiv_inl := by - ext v; simp [equiv_inl, ContinuousLinearMap.comp_apply, ContinuousLinearMap.inl_apply] - have hequiv_inl_inj : Function.Injective equiv_inl := - hFp.equiv.injective.comp (fun x y h => (Prod.mk.inj h).1) - have hrhs_inj : Function.Injective - (fderiv ℝ ((↑hFp.equiv ∘ fun v => (v, (0 : F))) ∘ transition) a) := by - rw [hequiv_inl_eq] - rw [fderiv_comp (x := a) equiv_inl.differentiableAt htrans_diff, - ContinuousLinearMap.fderiv] - exact hequiv_inl_inj.comp htrans_inj - rw [← hfderiv_eq] at hrhs_inj - have hcodchart_diff : DifferentiableAt ℝ (↑(hFp.codChart.extend (𝓘(ℝ, E d)))) (g a) := by - have hga : g a = ι p := by change ι (c.symm (c p)) = ι p; rw [c.left_inv hp_source] - rw [hga] - have h := ModelWithCorners.contDiffWithinAt_extendCoordChange' (I := 𝓘(ℝ, E d)) - (IsManifold.chart_mem_maximalAtlas (I := 𝓘(ℝ, E d)) (ι p)) - hFp.codChart_mem_maximalAtlas - (mem_chart_source (E d) (ι p)) hFp.mem_codChart_source - simp only [modelWithCornersSelf_coe, Set.range_id, contDiffWithinAt_univ] at h - simpa [chartAt_self_eq, extChartAt_model_space_eq_id, PartialEquiv.refl_coe] using - h.differentiableAt (by norm_num) - rw [fderiv_comp (x := a) hcodchart_diff hg_diff'] at hrhs_inj - intro x y hxy - apply hrhs_inj - simp only [ContinuousLinearMap.comp_apply, hxy] + have hg_inj : Function.Injective (fderiv ℝ g a) := + injective_fderiv_comp_extChartAt_symm_of_smoothEmbedding M ι hι p have hg_diff : DifferentiableAt ℝ g a := hg_smooth.differentiableAt (by norm_num) -- Step 4: Define the tangent subspace V = range(Dg(a)) set L : ManifoldModel n →L[ℝ] E d := fderiv ℝ g a with hL_def @@ -336,41 +403,10 @@ private abbrev smooth_embedding_local_graph {d n : ℕ} (Vᗮ.orthogonalProjectionOnto.comp L).comp (fderiv ℝ ψ 0) by rw [hassoc, hperp, ContinuousLinearMap.zero_comp] ext1 v; simp only [ContinuousLinearMap.comp_apply] - -- Extract ball around 0 where φ_raw is C² - have hφ_raw_ev : ∀ᶠ v in 𝓝 (0 : ↥V), ContDiffAt ℝ 2 φ_raw v := - hφ_raw_smooth_at.eventually (by norm_num) - obtain ⟨ε, hε_pos, hε_ball⟩ := Metric.eventually_nhds_iff.mp hφ_raw_ev - -- Construct smooth bump χ equal to 1 near 0 with support inside ball 0 ε - let bump : ContDiffBump (0 : ↥V) := - { rIn := ε / 3 - rOut := ε / 2 - rIn_pos := by positivity - rIn_lt_rOut := by linarith } - -- Define bump-extended φ := bump • φ_raw, which is globally C² - set φ : ↥V → ↥(Vᗮ) := fun v => bump v • φ_raw v with hφ_def - -- Near 0, bump = 1 so φ = φ_raw - have hφ_eq_raw_near : φ =ᶠ[𝓝 0] φ_raw := by - filter_upwards [bump.eventuallyEq_one] with v hv - change bump v • φ_raw v = φ_raw v - have hbv : (↑bump : ↥V → ℝ) v = 1 := by simpa using hv - rw [hbv, one_smul] - have hφ_zero : φ 0 = 0 := by - change bump 0 • φ_raw 0 = 0 - rw [hφ_raw_zero, smul_zero] - have hφ_smooth : ContDiff ℝ 2 φ := by - rw [contDiff_iff_contDiffAt] - intro v - by_cases hv : v ∈ tsupport (↑bump : ↥V → ℝ) - · have hv_dist : dist v 0 < ε := by - have hmem : v ∈ Metric.closedBall (0 : ↥V) (ε / 2) := bump.tsupport_eq ▸ hv - exact lt_of_le_of_lt (Metric.mem_closedBall.mp hmem) (by linarith) - exact (bump.contDiff (n := 2)).contDiffAt.smul (hε_ball hv_dist) - · have hφ_eq_zero : φ =ᶠ[𝓝 v] (fun _ : ↥V => (0 : ↥(Vᗮ))) := by - filter_upwards [notMem_tsupport_iff_eventuallyEq.mp hv] with w hw - change bump w • φ_raw w = (0 : ↥(Vᗮ)) - have hbw : (↑bump : ↥V → ℝ) w = 0 := by simpa using hw - rw [hbw, zero_smul] - exact contDiffAt_const.congr_of_eventuallyEq hφ_eq_zero + -- Extend φ_raw globally via a bump function, keeping it unchanged near 0 + obtain ⟨φ, hφ_smooth, hφ_eq_raw_near⟩ := + exists_contDiff_eventuallyEq_of_contDiffAt_zero hφ_raw_smooth_at + have hφ_zero : φ 0 = 0 := by rw [hφ_eq_raw_near.eq_of_nhds, hφ_raw_zero] have hDφ_zero : fderiv ℝ φ 0 = 0 := by rw [hφ_eq_raw_near.fderiv_eq] exact hDφ_raw_zero diff --git a/LeanPool/PLAcceleratedNesterovLean/MorseBott/TubularProjection/Derivative.lean b/LeanPool/PLAcceleratedNesterovLean/MorseBott/TubularProjection/Derivative.lean index 8bd658ed16..959212b39f 100644 --- a/LeanPool/PLAcceleratedNesterovLean/MorseBott/TubularProjection/Derivative.lean +++ b/LeanPool/PLAcceleratedNesterovLean/MorseBott/TubularProjection/Derivative.lean @@ -38,7 +38,7 @@ omit [FiniteDimensional ℝ E] in /-- Transfer `HasFDerivAt` from `g` to `f` when `f − g = o(· − a)` and `f(a) = g(a)`. This is weaker than `EventuallyEq.hasFDerivAt_iff` but covers perturbation estimates on curved submanifolds where π ≠ χ exactly but π − χ = O(‖x−m‖²) = o(‖x−m‖). -/ -private abbrev hasFDerivAt_of_isLittleO_sub +private theorem hasFDerivAt_of_isLittleO_sub {F' : Type*} [NormedAddCommGroup F'] [NormedSpace ℝ F'] {f g : E → F'} {L : E →L[ℝ] F'} {a : E} (hg : HasFDerivAt g L a) (hfa : f a = g a) @@ -51,7 +51,7 @@ private abbrev hasFDerivAt_of_isLittleO_sub -- Needed: nlinarith/linarith proofs exceed default heartbeat limit omit [FiniteDimensional ℝ E] in /-- φ is ε-Lipschitz on a ball around 0 for any ε > 0, since Dφ(0) = 0 and φ is C². -/ -private abbrev phi_lipschitzOn_near_zero +private theorem phi_lipschitzOn_near_zero {V : Submodule ℝ E} {φ : V → V.orthogonal} (hφC2 : ContDiff ℝ 2 φ) (hDφ0 : fderiv ℝ φ 0 = 0) (ε : ℝ) (hε : 0 < ε) : @@ -92,6 +92,248 @@ private abbrev phi_lipschitzOn_near_zero (Metric.mem_closedBall.mpr (le_of_lt (Metric.mem_ball.mp ha))) -- Needed: nlinarith/linarith proofs exceed default heartbeat limit +/-- Algebraic core of the nearest-point estimate: if `a² + b² ≤ (b + εa)²` with + `0 < ε ≤ 1/4`, then `a ≤ 3bε`. -/ +private theorem nearest_point_core_bound {a b ε : ℝ} (ha_nn : 0 ≤ a) (hb_nn : 0 ≤ b) + (hε_pos : 0 < ε) (hε_le : ε ≤ 1 / 4) + (hcore : a * a + b * b ≤ (b + ε * a) * (b + ε * a)) : + a ≤ 3 * b * ε := by + have hcore2 : a * a * (1 - ε * ε) ≤ 2 * b * ε * a := by + have hexp : (b + ε * a) * (b + ε * a) = + b * b + 2 * b * (ε * a) + ε * a * (ε * a) := by ring + have key : a * a ≤ 2 * b * (ε * a) + ε * a * (ε * a) := by + have h_combined := le_trans hcore (le_of_eq hexp) + linarith + have factored : a * a * (1 - ε * ε) = a * a - ε * ε * (a * a) := by ring + have rearranged : ε * a * (ε * a) = ε * ε * (a * a) := by ring + linarith + have hε_sq : 1 - ε * ε ≥ 15 / 16 := by + have := mul_self_le_mul_self hε_pos.le hε_le + linarith + by_cases ha0 : a = 0 + · rw [ha0]; positivity + · have ha_pos : 0 < a := lt_of_le_of_ne ha_nn (Ne.symm ha0) + have h_cancel : a * (1 - ε * ε) ≤ 2 * b * ε := by + by_contra h; push Not at h + have h1 := mul_lt_mul_of_pos_right h ha_pos + have : a * (1 - ε * ε) * a = a * a * (1 - ε * ε) := by ring + linarith [hcore2] + have h_step : a * (15 / 16) ≤ 2 * b * ε := + le_trans (mul_le_mul_of_nonneg_left (by linarith : (15:ℝ)/16 ≤ 1 - ε * ε) ha_nn) + h_cancel + have h_bε_nn : 0 ≤ b * ε := mul_nonneg hb_nn hε_pos.le + linarith + +/-- Final arithmetic of the first-order estimate: `(1 + ε) · 3bε ≤ c · t` + whenever `b ≤ 2t` and `ε ≤ min (1/4) (c/12)`. -/ +private theorem chart_difference_final_bound {b c ε t d : ℝ} (hε_pos : 0 < ε) + (hε_le : ε ≤ 1 / 4) (hε_le_c : ε ≤ c / 12) (ht : 0 ≤ t) + (hb_bound : b ≤ 2 * t) (hd : d ≤ (1 + ε) * (3 * b * ε)) : + d ≤ c * t := by + have h2 : (1 + ε) * (3 * b * ε) ≤ (1 + ε) * (3 * (2 * t) * ε) := by + apply mul_le_mul_of_nonneg_left _ (by linarith : (0:ℝ) ≤ 1 + ε) + apply mul_le_mul_of_nonneg_right _ hε_pos.le + linarith + have h3 : (1 + ε) * (3 * (2 * t) * ε) = (1 + ε) * 6 * ε * t := by ring + have h4 : (1 + ε) * 6 * ε * t ≤ c * t := by + apply mul_le_mul_of_nonneg_right _ ht + have h_1e : (1 : ℝ) + ε ≤ 5 / 4 := by linarith + have h_6e : 6 * ε ≤ c / 2 := by linarith + calc (1 + ε) * 6 * ε = (1 + ε) * (6 * ε) := by ring + _ ≤ (5 / 4) * (c / 2) := + mul_le_mul h_1e h_6e (by positivity) (by positivity) + _ = 5 * c / 8 := by ring + _ ≤ c := by linarith + linarith + +omit [FiniteDimensional ℝ E] in +/-- Nearest-point comparison in a graph chart. Write `x − m = v + w` with `v ∈ V`, + `w ∈ V⊥`, and let `p = m + v⋆ + φ(v⋆)`, `q = m + v + φ(v)` be two points of the + graph with `p` at least as close to `x` as `q`. If `φ` is `ε`-Lipschitz between + `v` and `v⋆`, then Pythagoras on `V ⊕ V⊥` bounds `‖p − q‖` by + `(1 + ε) · 3ε · ‖w − φ(v⋆)‖`. -/ +private theorem chart_nearest_point_difference_le {V : Submodule ℝ E} {φ : V → V.orthogonal} + {ε : ℝ} {x m p q : E} {v v_star : V} {w : V.orthogonal} + (hε_pos : 0 < ε) (hε_le : ε ≤ 1 / 4) + (hLip_diff : ‖φ v_star - φ v‖ ≤ ε * ‖v_star - v‖) + (hxm_decomp : x - m = (v : E) + (w : E)) + (hp_sub : p - m = (v_star : E) + (φ v_star : E)) + (hq_sub : q - m = (v : E) + (φ v : E)) + (hopt : ‖x - p‖ ≤ ‖x - q‖) : + ‖p - q‖ ≤ (1 + ε) * (3 * ‖(w : E) - (φ v_star : E)‖ * ε) := by + -- Decompose x - p and x - q + have hxp_eq : x - p = ((v : E) - (v_star : E)) + ((w : E) - (φ v_star : E)) := by + have : x - p = (x - m) - (p - m) := by abel + rw [this, hxm_decomp, hp_sub]; abel + have hxq_eq : x - q = (w : E) - (φ v : E) := by + have : x - q = (x - m) - (q - m) := by abel + rw [this, hxm_decomp, hq_sub]; abel + -- Pythagorean theorem: V-component ⊥ V⊥-component of (x - p) + set a_vec := (v : E) - (v_star : E) with ha_def + set b_vec := (w : E) - (φ v_star : E) with hb_def + have ha_mem : a_vec ∈ V := V.sub_mem (Submodule.coe_mem v) (Submodule.coe_mem v_star) + have hb_mem : b_vec ∈ V.orthogonal := + V.orthogonal.sub_mem (Submodule.coe_mem w) (Submodule.coe_mem (φ v_star)) + have hortho : @inner ℝ E _ a_vec b_vec = 0 := + Submodule.inner_right_of_mem_orthogonal ha_mem hb_mem + -- ‖x - p‖² = ‖a_vec‖² + ‖b_vec‖² (Pythagoras) + have hpyth : ‖x - p‖ * ‖x - p‖ = ‖a_vec‖ * ‖a_vec‖ + ‖b_vec‖ * ‖b_vec‖ := by + rw [hxp_eq] + exact norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero a_vec b_vec hortho + -- From optimality: ‖a_vec‖² + ‖b_vec‖² ≤ ‖x - q‖² + have hopt_sq : ‖a_vec‖ * ‖a_vec‖ + ‖b_vec‖ * ‖b_vec‖ ≤ ‖x - q‖ * ‖x - q‖ := by + rw [← hpyth]; exact mul_self_le_mul_self (norm_nonneg _) hopt + -- Lipschitz bound in ambient norms + have h_lip_coe : ‖(φ v_star : E) - (φ v : E)‖ ≤ ε * ‖a_vec‖ := by + calc ‖(φ v_star : E) - (φ v : E)‖ + = ‖((φ v_star - φ v : V.orthogonal) : E)‖ := by rw [AddSubgroupClass.coe_sub] + _ = ‖φ v_star - φ v‖ := rfl + _ ≤ ε * ‖v_star - v‖ := hLip_diff + _ = ε * ‖((v_star - v : V) : E)‖ := by rfl + _ = ε * ‖(v_star : E) - (v : E)‖ := by rw [AddSubgroupClass.coe_sub] + _ = ε * ‖a_vec‖ := by congr 1; exact norm_sub_rev _ _ + -- Triangle: ‖w - φ(v)‖ ≤ ‖w - φ(v*)‖ + ‖φ(v*) - φ(v)‖ ≤ ‖b_vec‖ + ε‖v* - v‖ + have htri : ‖x - q‖ ≤ ‖b_vec‖ + ε * ‖a_vec‖ := by + rw [hxq_eq] + have hsplit : (w : E) - (φ v : E) = b_vec + ((φ v_star : E) - (φ v : E)) := by + rw [hb_def]; abel + rw [hsplit] + exact le_trans (norm_add_le _ _) (add_le_add le_rfl h_lip_coe) + -- Core algebraic bound: a² + b² ≤ (b + εa)² gives a ≤ 3bε + have ha_bound : ‖a_vec‖ ≤ 3 * ‖b_vec‖ * ε := + nearest_point_core_bound (norm_nonneg _) (norm_nonneg _) hε_pos hε_le + (le_trans hopt_sq (mul_self_le_mul_self (norm_nonneg _) htri)) + -- ‖p - q‖ ≤ (1 + ε) * a + have h_eq : p - q = ((v_star : E) - (v : E)) + ((φ v_star : E) - (φ v : E)) := by + have : p - q = (p - m) - (q - m) := by abel + rw [this, hp_sub, hq_sub]; abel + have h_vs_norm : ‖(v_star : E) - (v : E)‖ = ‖a_vec‖ := norm_sub_rev _ _ + calc ‖p - q‖ + = ‖((v_star : E) - (v : E)) + ((φ v_star : E) - (φ v : E))‖ := by rw [h_eq] + _ ≤ ‖(v_star : E) - (v : E)‖ + ‖(φ v_star : E) - (φ v : E)‖ := norm_add_le _ _ + _ ≤ ‖a_vec‖ + ε * ‖a_vec‖ := add_le_add (le_of_eq h_vs_norm) h_lip_coe + _ = (1 + ε) * ‖a_vec‖ := by ring + _ ≤ (1 + ε) * (3 * ‖b_vec‖ * ε) := + mul_le_mul_of_nonneg_left ha_bound (by linarith) + +/-- Pointwise first-order estimate: on a small ball around `m ∈ S`, the tubular + projection differs from the chart projection + `χ(x) = m + P_V(x − m) + φ(P_V(x − m))` by at most `c‖x − m‖`, provided `φ` is + `ε`-Lipschitz near `0` with `ε ≤ min (1/4) (c/12)`. -/ +private theorem tubularProj_sub_chart_le {S U : Set E} + (hTN : IsTubularNeighborhoodOfSubmanifold S U) (hne : S.Nonempty) + {m : E} (hm : m ∈ S) {V : Submodule ℝ E} {φ : V → V.orthogonal} {δ : ℝ} + (hφ0 : φ 0 = 0) + (hchart : ∀ x ∈ Metric.ball m δ, x ∈ S ↔ ∃ v : V, x = m + (v : E) + (φ v : E)) + {c ε r₁ : ℝ} (hε_pos : 0 < ε) (hε_le : ε ≤ 1 / 4) (hε_le_c : ε ≤ c / 12) + (hLip_on : ∀ a ∈ Metric.ball (0 : V) r₁, ∀ b ∈ Metric.ball (0 : V) r₁, + ‖φ a - φ b‖ ≤ ε * ‖a - b‖) + {x : E} (hx_U : x ∈ U) (hx_δ : ‖x - m‖ < δ / 3) (hx_r₁ : ‖x - m‖ < r₁ / 3) : + ‖tubularProj hTN hne x - + (m + (V.starProjection (x - m) : E) + ((φ (V.orthogonalProjectionOnto (x - m))) : E))‖ + ≤ c * ‖x - m‖ := by + set q : E := m + (V.starProjection (x - m) : E) + + ((φ (V.orthogonalProjectionOnto (x - m))) : E) with hq_def + set π_x := tubularProj hTN hne x with hπ_def + obtain ⟨hπ_S, hπ_dist⟩ := tubularProj_mem hTN hne x hx_U + -- ‖π(x) - m‖ ≤ 2‖x - m‖ (nearest point + triangle inequality) + have hπ_opt : ‖x - π_x‖ ≤ ‖x - m‖ := by + calc ‖x - π_x‖ = dist x π_x := (dist_eq_norm x π_x).symm + _ = Metric.infDist x S := hπ_dist + _ ≤ dist x m := Metric.infDist_le_dist_of_mem hm + _ = ‖x - m‖ := dist_eq_norm x m + have hπ_near : ‖π_x - m‖ ≤ 2 * ‖x - m‖ := by + have h2 : ‖π_x - m‖ ≤ ‖π_x - x‖ + ‖x - m‖ := by + calc ‖π_x - m‖ = ‖(π_x - x) + (x - m)‖ := by congr 1; abel + _ ≤ ‖π_x - x‖ + ‖x - m‖ := norm_add_le _ _ + have h3 : ‖π_x - x‖ = ‖x - π_x‖ := (norm_sub_rev x π_x).symm + linarith + -- π(x) ∈ ball(m, δ), so we can use the chart + have hπ_in_ball : π_x ∈ Metric.ball m δ := by + rw [Metric.mem_ball, dist_comm, dist_eq_norm, norm_sub_rev]; linarith [norm_nonneg (x - m)] + obtain ⟨v_star, hπ_eq⟩ := (hchart π_x hπ_in_ball).mp hπ_S + -- Define v = V-component of (x - m) + set v := V.orthogonalProjectionOnto (x - m) with hv_def + set w := V.orthogonal.orthogonalProjectionOnto (x - m) with hw_def + -- x - m = (v : E) + (w : E) (orthogonal decomposition) + have hxm_decomp : x - m = (v : E) + (w : E) := by + have h := (V.starProjection_add_starProjection_orthogonal (x - m)).symm + rwa [Submodule.starProjection_apply, Submodule.starProjection_apply] at h + -- π_x - m = (v_star : E) + (φ v_star : E) + have hπ_sub : π_x - m = (v_star : E) + (φ v_star : E) := by + rw [hπ_eq]; abel + -- V.orthogonalProjectionOnto(π_x - m) = v_star + have hπ_proj : V.orthogonalProjectionOnto (π_x - m) = v_star := by + have hφ_proj : V.orthogonalProjectionOnto (φ v_star : E) = 0 := + Submodule.orthogonalProjectionOnto_eq_zero_iff.mpr + (V.orthogonal.coe_mem (φ v_star)) + rw [hπ_sub, map_add, + Submodule.orthogonalProjectionOnto_mem_subspace_eq_self v_star, + hφ_proj, add_zero] + -- Norm bounds + have hv_norm : ‖(v : E)‖ ≤ ‖x - m‖ := + Submodule.norm_orthogonalProjectionOnto_apply_le V (x - m) + have hvs_norm : ‖(v_star : E)‖ ≤ 2 * ‖x - m‖ := by + have h := Submodule.norm_orthogonalProjectionOnto_apply_le V (π_x - m) + rw [hπ_proj] at h; exact le_trans h hπ_near + -- v, v_star and 0 are in the Lipschitz ball + have hv_ball : v ∈ Metric.ball (0 : V) r₁ := by + rw [Metric.mem_ball, dist_zero_right] + exact lt_of_le_of_lt hv_norm (by linarith [norm_nonneg (x - m)]) + have hvs_ball : v_star ∈ Metric.ball (0 : V) r₁ := by + rw [Metric.mem_ball, dist_zero_right] + exact lt_of_le_of_lt hvs_norm (by linarith [norm_nonneg (x - m)]) + have h0_ball : (0 : V) ∈ Metric.ball (0 : V) r₁ := + Metric.mem_ball_self (by linarith [norm_nonneg (x - m)]) + -- Lipschitz bounds (in subtype norms, which equal ambient norms) + have hLip_v : ‖φ v‖ ≤ ε * ‖v‖ := by + have h := hLip_on v hv_ball 0 h0_ball + simp only [sub_zero, hφ0] at h; exact h + have hLip_vs : ‖φ v_star‖ ≤ ε * ‖v_star‖ := by + have h := hLip_on v_star hvs_ball 0 h0_ball + simp only [sub_zero, hφ0] at h; exact h + -- χ(x) ∈ S: need m + v + φ(v) ∈ ball(m, δ) and use chart + have h_star_eq : V.starProjection (x - m) = (v : E) := + Submodule.starProjection_apply V (x - m) + have hχ_sub_m : q - m = (v : E) + (φ v : E) := by + rw [hq_def, h_star_eq]; abel + have hχ_in_ball : q ∈ Metric.ball m δ := by + rw [Metric.mem_ball, dist_comm, dist_eq_norm, norm_sub_rev, hχ_sub_m] + calc ‖(v : E) + (φ v : E)‖ ≤ ‖(v : E)‖ + ‖(φ v : E)‖ := norm_add_le _ _ + _ ≤ ‖x - m‖ + ε * ‖x - m‖ := by + have h1 : ‖(φ v : E)‖ ≤ ε * ‖(v : E)‖ := hLip_v + have h2 : ε * ‖(v : E)‖ ≤ ε * ‖x - m‖ := + mul_le_mul_of_nonneg_left hv_norm hε_pos.le + linarith + _ < δ := by + have h_eps_bound : ε * ‖x - m‖ ≤ (1 / 4) * ‖x - m‖ := + mul_le_mul_of_nonneg_right hε_le (norm_nonneg _) + linarith [norm_nonneg (x - m)] + have hχ_S : q ∈ S := + (hchart q hχ_in_ball).mpr ⟨v, by + have := sub_eq_iff_eq_add.mp hχ_sub_m; rw [this]; abel⟩ + -- Optimality: ‖x - π_x‖ ≤ ‖x - χ(x)‖ (nearest point) + have hopt : ‖x - π_x‖ ≤ ‖x - q‖ := by + calc ‖x - π_x‖ = dist x π_x := (dist_eq_norm x π_x).symm + _ = Metric.infDist x S := hπ_dist + _ ≤ dist x q := Metric.infDist_le_dist_of_mem hχ_S + _ = ‖x - q‖ := dist_eq_norm x q + have hdiff_bound := chart_nearest_point_difference_le hε_pos hε_le + (hLip_on v_star hvs_ball v hv_ball) hxm_decomp hπ_sub hχ_sub_m hopt + -- Bound ‖w - φ(v*)‖ ≤ 2‖x-m‖ + have hw_norm : ‖(w : E)‖ ≤ ‖x - m‖ := + Submodule.norm_orthogonalProjectionOnto_apply_le V.orthogonal (x - m) + have hb_bound : ‖(w : E) - (φ v_star : E)‖ ≤ 2 * ‖x - m‖ := by + have hφvs_coe : ‖(φ v_star : E)‖ ≤ ε * ‖(v_star : E)‖ := hLip_vs + calc ‖(w : E) - (φ v_star : E)‖ ≤ ‖(w : E)‖ + ‖(φ v_star : E)‖ := norm_sub_le _ _ + _ ≤ ‖x - m‖ + ε * ‖(v_star : E)‖ := by linarith + _ ≤ ‖x - m‖ + (1/4) * (2 * ‖x - m‖) := by + have := mul_le_mul hε_le hvs_norm (norm_nonneg _) (by positivity : (0:ℝ) ≤ 1/4) + linarith + _ ≤ 2 * ‖x - m‖ := by linarith [norm_nonneg (x - m)] + exact chart_difference_final_bound hε_pos hε_le hε_le_c (norm_nonneg _) hb_bound + hdiff_bound + /-- At each point `m ∈ S`, the Fréchet derivative of the tubular projection equals `V.starProjection` (the orthogonal projection `E → E` onto the tangent space `V`). @@ -102,7 +344,7 @@ private abbrev phi_lipschitzOn_near_zero 2. `h_chartHasFDeriv`: `χ` has Fréchet derivative `V.starProjection` at `m`, which follows from `φ 0 = 0`, `Dφ(0) = 0`, and the chain rule. These combine via `hasFDerivAt_of_isLittleO_sub`. -/ -private abbrev tubularProj_hasFDerivAt_starProjection {S U : Set E} +private theorem tubularProj_hasFDerivAt_starProjection {S U : Set E} (hTN : IsTubularNeighborhoodOfSubmanifold S U) (hne : S.Nonempty) (m : E) (hm : m ∈ S) : ∃ V : Submodule ℝ E, @@ -129,244 +371,26 @@ private abbrev tubularProj_hasFDerivAt_starProjection {S U : Set E} (fun x => x - m) := by rw [Asymptotics.isLittleO_iff] intro c hc - -- Step 1: Choose ε and get Lipschitz ball for φ near 0 + -- Choose ε and get Lipschitz ball for φ near 0 have hε_pos : (0 : ℝ) < min (1 / 4) (c / 12) := lt_min (by positivity) (by linarith) set ε := min (1 / 4 : ℝ) (c / 12) with hε_def - have hε_le : ε ≤ 1 / 4 := min_le_left _ _ - have hε_le_c : ε ≤ c / 12 := min_le_right _ _ obtain ⟨r₁, hr₁, hLip_on⟩ := phi_lipschitzOn_near_zero hφC2 hDφ0 ε hε_pos - -- Step 2: m ∈ U (since m ∈ S ⊆ U) - have hm_U : m ∈ U := hTN.subset hm - obtain ⟨r_U, hr_U, hball_U⟩ := isOpen_iff.mp (U_isOpen hTN) m hm_U - -- Step 3: Choose radius ensuring x ∈ U, π(x) in chart, v/v* in Lipschitz ball + -- m ∈ U (since m ∈ S ⊆ U) + obtain ⟨r_U, hr_U, hball_U⟩ := isOpen_iff.mp (U_isOpen hTN) m (hTN.subset hm) + -- Choose radius ensuring x ∈ U, π(x) in chart, v/v* in Lipschitz ball set r := min (min (δ / 3) (r₁ / 3)) r_U with hr_def have hr_pos : 0 < r := lt_min (lt_min (by linarith) (by linarith)) hr_U have hr_le_δ3 : r ≤ δ / 3 := le_trans (min_le_left _ _) (min_le_left _ _) have hr_le_r13 : r ≤ r₁ / 3 := le_trans (min_le_left _ _) (min_le_right _ _) - -- Step 4: Prove the bound on ball(m, r) + -- Prove the bound on ball(m, r) apply Metric.eventually_nhds_iff_ball.mpr refine ⟨r, hr_pos, fun x hx_ball => ?_⟩ have hx_norm : ‖x - m‖ < r := by rwa [mem_ball, dist_eq_norm] at hx_ball have hx_U : x ∈ U := hball_U (mem_ball.mpr (lt_of_lt_of_le (show dist x m < r by rwa [dist_eq_norm]) (min_le_right _ _))) - set π_x := tubularProj hTN hne x with hπ_def - obtain ⟨hπ_S, hπ_dist⟩ := tubularProj_mem hTN hne x hx_U - -- ‖π(x) - m‖ ≤ 2‖x - m‖ (nearest point + triangle inequality) - have hπ_opt : ‖x - π_x‖ ≤ ‖x - m‖ := by - calc ‖x - π_x‖ = dist x π_x := (dist_eq_norm x π_x).symm - _ = Metric.infDist x S := hπ_dist - _ ≤ dist x m := Metric.infDist_le_dist_of_mem hm - _ = ‖x - m‖ := dist_eq_norm x m - have hπ_near : ‖π_x - m‖ ≤ 2 * ‖x - m‖ := by - have h2 : ‖π_x - m‖ ≤ ‖π_x - x‖ + ‖x - m‖ := by - calc ‖π_x - m‖ = ‖(π_x - x) + (x - m)‖ := by congr 1; abel - _ ≤ ‖π_x - x‖ + ‖x - m‖ := norm_add_le _ _ - have h3 : ‖π_x - x‖ = ‖x - π_x‖ := (norm_sub_rev x π_x).symm - linarith - -- π(x) ∈ ball(m, δ), so we can use the chart - have hπ_in_ball : π_x ∈ ball m δ := by - rw [mem_ball, dist_comm, dist_eq_norm, norm_sub_rev]; linarith - obtain ⟨v_star, hπ_eq⟩ := (hchart π_x hπ_in_ball).mp hπ_S - -- Define v = V-component of (x - m) - set v := V.orthogonalProjectionOnto (x - m) with hv_def - set w := V.orthogonal.orthogonalProjectionOnto (x - m) with hw_def - -- x - m = (v : E) + (w : E) (orthogonal decomposition) - have hxm_decomp : x - m = (v : E) + (w : E) := by - have h := (V.starProjection_add_starProjection_orthogonal (x - m)).symm - rwa [Submodule.starProjection_apply, Submodule.starProjection_apply] at h - -- π_x - m = (v_star : E) + (φ v_star : E) - have hπ_sub : π_x - m = (v_star : E) + (φ v_star : E) := by - rw [hπ_eq]; abel - -- V.orthogonalProjectionOnto(π_x - m) = v_star - have hπ_proj : V.orthogonalProjectionOnto (π_x - m) = v_star := by - have hφ_proj : V.orthogonalProjectionOnto (φ v_star : E) = 0 := - Submodule.orthogonalProjectionOnto_eq_zero_iff.mpr - (V.orthogonal.coe_mem (φ v_star)) - rw [hπ_sub, map_add, - Submodule.orthogonalProjectionOnto_mem_subspace_eq_self v_star, - hφ_proj, add_zero] - -- Norm bounds - have hv_norm : ‖(v : E)‖ ≤ ‖x - m‖ := - Submodule.norm_orthogonalProjectionOnto_apply_le V (x - m) - have hvs_norm : ‖(v_star : E)‖ ≤ 2 * ‖x - m‖ := by - have h := Submodule.norm_orthogonalProjectionOnto_apply_le V (π_x - m) - rw [hπ_proj] at h; exact le_trans h hπ_near - -- v and v_star are in the Lipschitz ball - have hv_ball : v ∈ ball (0 : V) r₁ := by - rw [mem_ball, dist_zero_right]; exact lt_of_le_of_lt hv_norm (by linarith) - have hvs_ball : v_star ∈ ball (0 : V) r₁ := by - rw [mem_ball, dist_zero_right]; exact lt_of_le_of_lt hvs_norm (by linarith) - have h0_ball : (0 : V) ∈ ball (0 : V) r₁ := mem_ball_self hr₁ - -- Lipschitz bounds (in subtype norms, which equal ambient norms) - have hLip_diff : ‖φ v_star - φ v‖ ≤ ε * ‖v_star - v‖ := - hLip_on v_star hvs_ball v hv_ball - have hLip_v : ‖φ v‖ ≤ ε * ‖v‖ := by - have h := hLip_on v hv_ball 0 h0_ball - simp only [sub_zero, hφ0] at h; exact h - have hLip_vs : ‖φ v_star‖ ≤ ε * ‖v_star‖ := by - have h := hLip_on v_star hvs_ball 0 h0_ball - simp only [sub_zero, hφ0] at h; exact h - -- χ(x) ∈ S: need m + v + φ(v) ∈ ball(m, δ) and use chart - have h_star_eq : V.starProjection (x - m) = (v : E) := - Submodule.starProjection_apply V (x - m) - have hχ_sub_m : χ x - m = (v : E) + (φ v : E) := by - change m + V.starProjection (x - m) + (φ (V.orthogonalProjectionOnto (x - m)) : E) - m = - (v : E) + (φ v : E) - rw [h_star_eq]; abel - have hχ_in_ball : χ x ∈ ball m δ := by - rw [mem_ball, dist_comm, dist_eq_norm, norm_sub_rev, - show χ x - m = (v : E) + (φ v : E) from hχ_sub_m] - calc ‖(v : E) + (φ v : E)‖ ≤ ‖(v : E)‖ + ‖(φ v : E)‖ := norm_add_le _ _ - _ ≤ ‖x - m‖ + ε * ‖x - m‖ := by - have h1 : ‖(φ v : E)‖ ≤ ε * ‖(v : E)‖ := hLip_v - have h2 : ε * ‖(v : E)‖ ≤ ε * ‖x - m‖ := - mul_le_mul_of_nonneg_left hv_norm hε_pos.le - linarith - _ < δ := by - have h_xm_lt : ‖x - m‖ < δ / 3 := lt_of_lt_of_le hx_norm hr_le_δ3 - have h_eps_bound : ε * ‖x - m‖ ≤ (1 / 4) * ‖x - m‖ := - mul_le_mul_of_nonneg_right hε_le (norm_nonneg _) - linarith - have hχ_S : χ x ∈ S := - (hchart (χ x) hχ_in_ball).mpr ⟨v, by - have := sub_eq_iff_eq_add.mp hχ_sub_m; rw [this]; abel⟩ - -- Optimality: ‖x - π_x‖ ≤ ‖x - χ(x)‖ (nearest point) - have hopt : ‖x - π_x‖ ≤ ‖x - χ x‖ := by - calc ‖x - π_x‖ = dist x π_x := (dist_eq_norm x π_x).symm - _ = Metric.infDist x S := hπ_dist - _ ≤ dist x (χ x) := Metric.infDist_le_dist_of_mem hχ_S - _ = ‖x - χ x‖ := dist_eq_norm x (χ x) - -- Decompose x - π_x and x - χ(x) - have hxπ_eq : x - π_x = ((v : E) - (v_star : E)) + ((w : E) - (φ v_star : E)) := by - have : x - π_x = (x - m) - (π_x - m) := by abel - rw [this, hxm_decomp, hπ_sub]; abel - have hxχ_eq : x - χ x = (w : E) - (φ v : E) := by - have : x - χ x = (x - m) - (χ x - m) := by abel - rw [this, hxm_decomp, hχ_sub_m]; abel - -- Pythagorean theorem: V-component ⊥ V⊥-component of (x - π_x) - set a_vec := (v : E) - (v_star : E) with ha_def - set b_vec := (w : E) - (φ v_star : E) with hb_def - have ha_mem : a_vec ∈ V := V.sub_mem (Submodule.coe_mem v) (Submodule.coe_mem v_star) - have hb_mem : b_vec ∈ V.orthogonal := - V.orthogonal.sub_mem (Submodule.coe_mem w) (Submodule.coe_mem (φ v_star)) - have hortho : @inner ℝ E _ a_vec b_vec = 0 := - Submodule.inner_right_of_mem_orthogonal ha_mem hb_mem - -- ‖x - π_x‖² = ‖a_vec‖² + ‖b_vec‖² (Pythagoras) - have hpyth : ‖x - π_x‖ * ‖x - π_x‖ = ‖a_vec‖ * ‖a_vec‖ + ‖b_vec‖ * ‖b_vec‖ := by - rw [hxπ_eq] - exact norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero a_vec b_vec hortho - -- ‖x - χ(x)‖² = ‖w - φ(v)‖² (entirely in V⊥, no V-component) - -- From optimality: ‖a_vec‖² + ‖b_vec‖² ≤ ‖x - χ(x)‖² - have hopt_sq : ‖a_vec‖ * ‖a_vec‖ + ‖b_vec‖ * ‖b_vec‖ ≤ - ‖x - χ x‖ * ‖x - χ x‖ := by - rw [← hpyth]; exact mul_self_le_mul_self (norm_nonneg _) hopt - -- Triangle: ‖w - φ(v)‖ ≤ ‖w - φ(v*)‖ + ‖φ(v*) - φ(v)‖ ≤ ‖b_vec‖ + ε‖v* - v‖ - have coe_sub_W : ∀ a b : V.orthogonal, ((a - b : V.orthogonal) : E) = (a : E) - (b : E) := - fun a b => AddSubgroupClass.coe_sub a b - have coe_sub_V : ∀ a b : V, ((a - b : V) : E) = (a : E) - (b : E) := - fun a b => AddSubgroupClass.coe_sub a b - have htri : ‖x - χ x‖ ≤ ‖b_vec‖ + ε * ‖a_vec‖ := by - rw [hxχ_eq] - have hsplit : (w : E) - (φ v : E) = b_vec + ((φ v_star : E) - (φ v : E)) := by - rw [hb_def]; abel - rw [hsplit] - refine le_trans (norm_add_le _ _) (add_le_add le_rfl ?_) - calc ‖(φ v_star : E) - (φ v : E)‖ - = ‖((φ v_star - φ v : V.orthogonal) : E)‖ := by rw [coe_sub_W] - _ = ‖φ v_star - φ v‖ := rfl - _ ≤ ε * ‖v_star - v‖ := hLip_diff - _ = ε * ‖((v_star - v : V) : E)‖ := by rfl - _ = ε * ‖(v_star : E) - (v : E)‖ := by rw [coe_sub_V] - _ = ε * ‖a_vec‖ := by congr 1; exact norm_sub_rev _ _ - -- Core algebraic bound: a² + b² ≤ (b + εa)² gives a(1-ε²) ≤ 2bε - set a := ‖a_vec‖ with ha_norm_def - set b := ‖b_vec‖ with hb_norm_def - have ha_nn : 0 ≤ a := norm_nonneg _ - have hb_nn : 0 ≤ b := norm_nonneg _ - have hcore : a * a + b * b ≤ (b + ε * a) * (b + ε * a) := by - calc a * a + b * b ≤ ‖x - χ x‖ * ‖x - χ x‖ := hopt_sq - _ ≤ (b + ε * a) * (b + ε * a) := mul_self_le_mul_self (norm_nonneg _) htri - have hcore2 : a * a * (1 - ε * ε) ≤ 2 * b * ε * a := by - have hexp : (b + ε * a) * (b + ε * a) = - b * b + 2 * b * (ε * a) + ε * a * (ε * a) := by ring - have key : a * a ≤ 2 * b * (ε * a) + ε * a * (ε * a) := by - have h_combined := le_trans hcore (le_of_eq hexp) - linarith - have factored : a * a * (1 - ε * ε) = a * a - ε * ε * (a * a) := by ring - have rearranged : ε * a * (ε * a) = ε * ε * (a * a) := by ring - linarith - have hε_sq : 1 - ε * ε ≥ 15 / 16 := by - have := mul_self_le_mul_self hε_pos.le hε_le - linarith - have ha_bound : a ≤ 3 * b * ε := by - by_cases ha0 : a = 0 - · rw [ha0]; positivity - · have ha_pos : 0 < a := lt_of_le_of_ne ha_nn (Ne.symm ha0) - have h_cancel : a * (1 - ε * ε) ≤ 2 * b * ε := by - by_contra h; push Not at h - have h1 := mul_lt_mul_of_pos_right h ha_pos - have : a * (1 - ε * ε) * a = a * a * (1 - ε * ε) := by ring - linarith [hcore2] - have h_step : a * (15 / 16) ≤ 2 * b * ε := - le_trans (mul_le_mul_of_nonneg_left (by linarith : (15:ℝ)/16 ≤ 1 - ε * ε) ha_nn) - h_cancel - have h_bε_nn : 0 ≤ b * ε := mul_nonneg hb_nn hε_pos.le - linarith - -- Bound b ≤ 2‖x-m‖ - have hw_norm : ‖(w : E)‖ ≤ ‖x - m‖ := - Submodule.norm_orthogonalProjectionOnto_apply_le V.orthogonal (x - m) - have hb_bound : b ≤ 2 * ‖x - m‖ := by - have hφvs_coe : ‖(φ v_star : E)‖ ≤ ε * ‖(v_star : E)‖ := hLip_vs - have hvs_coe : ‖(v_star : E)‖ ≤ 2 * ‖x - m‖ := hvs_norm - calc b ≤ ‖(w : E)‖ + ‖(φ v_star : E)‖ := norm_sub_le _ _ - _ ≤ ‖x - m‖ + ε * ‖(v_star : E)‖ := by - have h5 := hw_norm; have h6 := hφvs_coe; linarith - _ ≤ ‖x - m‖ + (1/4) * (2 * ‖x - m‖) := by - have := mul_le_mul hε_le hvs_coe (norm_nonneg _) (by positivity : (0:ℝ) ≤ 1/4) - linarith - _ ≤ 2 * ‖x - m‖ := by linarith [norm_nonneg (x - m)] - -- ‖π(x) - χ(x)‖ ≤ (1 + ε) * a - have hdiff_bound : ‖tubularProj hTN hne x - χ x‖ ≤ (1 + ε) * a := by - have h_eq : π_x - χ x = ((v_star : E) - (v : E)) + ((φ v_star : E) - (φ v : E)) := by - have : π_x - χ x = (π_x - m) - (χ x - m) := by abel - rw [this, hπ_sub, hχ_sub_m]; abel - have h_lip_coe : ‖(φ v_star : E) - (φ v : E)‖ ≤ ε * a := by - calc ‖(φ v_star : E) - (φ v : E)‖ - = ‖((φ v_star - φ v : V.orthogonal) : E)‖ := by rw [coe_sub_W] - _ = ‖φ v_star - φ v‖ := rfl - _ ≤ ε * ‖v_star - v‖ := hLip_diff - _ = ε * ‖((v_star - v : V) : E)‖ := by rfl - _ = ε * ‖(v_star : E) - (v : E)‖ := by rw [coe_sub_V] - _ = ε * ‖a_vec‖ := by congr 1; exact norm_sub_rev _ _ - have h_vs_norm : ‖(v_star : E) - (v : E)‖ = a := by - change ‖(v_star : E) - (v : E)‖ = ‖a_vec‖ - exact norm_sub_rev _ _ - calc ‖tubularProj hTN hne x - χ x‖ = ‖π_x - χ x‖ := rfl - _ = ‖((v_star : E) - (v : E)) + ((φ v_star : E) - (φ v : E))‖ := by rw [h_eq] - _ ≤ ‖(v_star : E) - (v : E)‖ + ‖(φ v_star : E) - (φ v : E)‖ := norm_add_le _ _ - _ ≤ a + ε * a := add_le_add (le_of_eq h_vs_norm) h_lip_coe - _ = (1 + ε) * a := by ring - -- Final: (1+ε) * 3bε ≤ (5/4) * 6ε * ‖x-m‖ ≤ c * ‖x-m‖ - have hxm_nn : 0 ≤ ‖x - m‖ := norm_nonneg _ - have h1 : (1 + ε) * a ≤ (1 + ε) * (3 * b * ε) := - mul_le_mul_of_nonneg_left ha_bound (by linarith) - have h2 : (1 + ε) * (3 * b * ε) ≤ (1 + ε) * (3 * (2 * ‖x - m‖) * ε) := by - apply mul_le_mul_of_nonneg_left _ (by linarith : (0:ℝ) ≤ 1 + ε) - apply mul_le_mul_of_nonneg_right _ hε_pos.le - have h_bb := hb_bound - linarith - have h3 : (1 + ε) * (3 * (2 * ‖x - m‖) * ε) = (1 + ε) * 6 * ε * ‖x - m‖ := by ring - have h4 : (1 + ε) * 6 * ε * ‖x - m‖ ≤ c * ‖x - m‖ := by - apply mul_le_mul_of_nonneg_right _ hxm_nn - have h_1e : (1 : ℝ) + ε ≤ 5 / 4 := by linarith - have h_6e : 6 * ε ≤ c / 2 := by linarith - calc (1 + ε) * 6 * ε = (1 + ε) * (6 * ε) := by ring - _ ≤ (5 / 4) * (c / 2) := - mul_le_mul h_1e h_6e (by positivity) (by positivity) - _ = 5 * c / 8 := by ring - _ ≤ c := by linarith - have h5 := hdiff_bound - linarith + exact tubularProj_sub_chart_le hTN hne hm hφ0 hchart hε_pos (min_le_left _ _) + (min_le_right _ _) hLip_on hx_U (lt_of_lt_of_le hx_norm hr_le_δ3) + (lt_of_lt_of_le hx_norm hr_le_r13) -- Step 2: χ has Fréchet derivative V.starProjection at m -- (The φ-term vanishes because Dφ(0) = 0; the starProjection term is linear.) have h_chartHasFDeriv : HasFDerivAt χ V.starProjection m := by