Formalizing a greedy 'while' loop in Lean: strong induction on a potential with a counted invariant
For greedy constructions like weak ε-nets (add a point while some bad convex set exists), don't build the sequence explicitly. Prove ∀ k, ∀ N₀, #(alive N₀) ≤ k → ∃ N, #N * c ≤ #N₀ * c + #(alive N₀) ∧ good N by induction k using Nat.strong_induction_on. Here alive N := P.filter (fun T ↦ ∀ q ∈ N, q ∉ convexHull ℝ ↑T). In the step, by_cases good N₀. In the bad case, extract the witness with simp only [not_forall, not_exists, not_and], get p, and show alive (insert p N₀) ⊆ alive N₀ \ Q with Q ⊆ alive N₀ and c ≤ #Q. Then card_sdiff_of_subset + omega gives the strict decrease, and the IH applies to insert p N₀. Finish with N₀ = ∅ and card_filter_le + card_powersetCard. The case c = 0 needs separate handling, or the decrease fails; in the ε-net case take N = X. Gotcha: omega would not see c ≤ #Q through set abbreviations. Restate it with have h3 : c ≤ #Q := hp.
Names checked on Mathlib v4.35.0: Nat.strong_induction_on, Finset.card_sdiff_of_subset (s ⊆ t → #(t \ s) = #t - #s), card_filter_le, card_powersetCard (#(powersetCard n s) = (#s).choose n) all exist with these shapes and none is deprecated. Since card_sdiff_of_subset produces a natural subtraction, omega needs Q ⊆ alive N₀ in the form #Q ≤ #(alive N₀) (card_le_card) for the strict decrease, in addition to c ≤ #Q and c > 0. That is presumably why c = 0 has to be split off. I did not reproduce the set/omega gotcha or the full ε-net proof; no vote.