Skip to content

Commit 9cb18fd

Browse files
Ruben-VandeVeldeParcly-Taxelkmill
committed
feat: port Combinatorics.SimpleGraph.Regularity.Bound (#4409)
Co-authored-by: Parcly Taxel <reddeloostw@gmail.com> Co-authored-by: Kyle Miller <kmill31415@gmail.com>
1 parent 37805e2 commit 9cb18fd

File tree

2 files changed

+295
-0
lines changed

2 files changed

+295
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,7 @@ import Mathlib.Combinatorics.SimpleGraph.Matching
11671167
import Mathlib.Combinatorics.SimpleGraph.Metric
11681168
import Mathlib.Combinatorics.SimpleGraph.Partition
11691169
import Mathlib.Combinatorics.SimpleGraph.Prod
1170+
import Mathlib.Combinatorics.SimpleGraph.Regularity.Bound
11701171
import Mathlib.Combinatorics.SimpleGraph.Regularity.Energy
11711172
import Mathlib.Combinatorics.SimpleGraph.Regularity.Equitabilise
11721173
import Mathlib.Combinatorics.SimpleGraph.Regularity.Uniform
Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
/-
2+
Copyright (c) 2022 Yaël Dillies, Bhavik Mehta. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Yaël Dillies, Bhavik Mehta
5+
6+
! This file was ported from Lean 3 source module combinatorics.simple_graph.regularity.bound
7+
! leanprover-community/mathlib commit bf7ef0e83e5b7e6c1169e97f055e58a2e4e9d52d
8+
! Please do not edit these lines, except to modify the commit id
9+
! if you have ported upstream changes.
10+
-/
11+
import Mathlib.Algebra.Order.Chebyshev
12+
import Mathlib.Analysis.SpecialFunctions.Pow.Real
13+
import Mathlib.Order.Partition.Equipartition
14+
15+
/-!
16+
# Numerical bounds for Szemerédi Regularity Lemma
17+
18+
This file gathers the numerical facts required by the proof of Szemerédi's regularity lemma.
19+
20+
This entire file is internal to the proof of Szemerédi Regularity Lemma.
21+
22+
## Main declarations
23+
24+
* `SzemerediRegularity.stepBound`: During the inductive step, a partition of size `n` is blown to
25+
size at most `stepBound n`.
26+
* `SzemerediRegularity.initialBound`: The size of the partition we start the induction with.
27+
* `SzemerediRegularity.bound`: The upper bound on the size of the partition produced by our version
28+
of Szemerédi's regularity lemma.
29+
30+
## References
31+
32+
[Yaël Dillies, Bhavik Mehta, *Formalising Szemerédi’s Regularity Lemma in Lean*][srl_itp]
33+
-/
34+
35+
36+
open Finset Fintype Function Real
37+
38+
local macro_rules | `($x ^ $y) => `(HPow.hPow $x $y) -- Porting note: See issue #2220
39+
40+
open BigOperators
41+
42+
namespace SzemerediRegularity
43+
44+
/-- Auxiliary function for Szemerédi's regularity lemma. Blowing up a partition of size `n` during
45+
the induction results in a partition of size at most `stepBound n`. -/
46+
def stepBound (n : ℕ) : ℕ :=
47+
n * 4 ^ n
48+
#align szemeredi_regularity.step_bound SzemerediRegularity.stepBound
49+
50+
theorem le_stepBound : id ≤ stepBound := fun n => Nat.le_mul_of_pos_right <| pow_pos (by norm_num) n
51+
#align szemeredi_regularity.le_step_bound SzemerediRegularity.le_stepBound
52+
53+
theorem stepBound_mono : Monotone stepBound := fun a b h =>
54+
Nat.mul_le_mul h <| Nat.pow_le_pow_of_le_right (by norm_num) h
55+
#align szemeredi_regularity.step_bound_mono SzemerediRegularity.stepBound_mono
56+
57+
theorem stepBound_pos_iff {n : ℕ} : 0 < stepBound n ↔ 0 < n :=
58+
zero_lt_mul_right <| by positivity
59+
#align szemeredi_regularity.step_bound_pos_iff SzemerediRegularity.stepBound_pos_iff
60+
61+
alias stepBound_pos_iff ↔ _ stepBound_pos
62+
#align szemeredi_regularity.step_bound_pos SzemerediRegularity.stepBound_pos
63+
64+
end SzemerediRegularity
65+
66+
open SzemerediRegularity
67+
68+
variable {α : Type _} [DecidableEq α] [Fintype α] {P : Finpartition (univ : Finset α)}
69+
{u : Finset α} {ε : ℝ}
70+
71+
local notation3 (prettyPrint := false)
72+
"m" => (card α / stepBound P.parts.card : ℕ)
73+
74+
local notation3 (prettyPrint := false)
75+
"a" => (card α / P.parts.card - m * 4 ^ P.parts.card : ℕ)
76+
77+
namespace SzemerediRegularity.Positivity
78+
79+
private theorem eps_pos {ε : ℝ} {n : ℕ} (h : 100 ≤ (4 : ℝ) ^ n * ε ^ 5) : 0 < ε :=
80+
(Odd.pow_pos_iff (by norm_num)).mp
81+
(pos_of_mul_pos_right ((show 0 < (100 : ℝ) by norm_num).trans_le h) (by positivity))
82+
83+
private theorem m_pos [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) : 0 < m :=
84+
Nat.div_pos ((Nat.mul_le_mul_left _ <| Nat.pow_le_pow_of_le_left (by norm_num) _).trans hPα) <|
85+
stepBound_pos (P.parts_nonempty <| univ_nonempty.ne_empty).card_pos
86+
87+
/-- Local extension for the `positivity` tactic: A few facts that are needed many times for the
88+
proof of Szemerédi's regularity lemma. -/
89+
-- Porting note: positivity extensions must now be global, and this did not seem like a good
90+
-- match for positivity anymore, so I wrote a new tactic (kmill)
91+
scoped macro "sz_positivity" : tactic =>
92+
`(tactic|
93+
{ try have := m_pos ‹_›
94+
try have := eps_pos ‹_›
95+
positivity })
96+
97+
-- Original meta code
98+
/- meta def positivity_szemeredi_regularity : expr → tactic strictness
99+
| `(%%n / step_bound (finpartition.parts %%P).card) := do
100+
p ← to_expr
101+
``((finpartition.parts %%P).card * 16^(finpartition.parts %%P).card ≤ %%n)
102+
>>= find_assumption,
103+
positive <$> mk_app ``m_pos [p]
104+
| ε := do
105+
typ ← infer_type ε,
106+
unify typ `(ℝ),
107+
p ← to_expr ``(100 ≤ 4 ^ _ * %%ε ^ 5) >>= find_assumption,
108+
positive <$> mk_app ``eps_pos [p] -/
109+
110+
end SzemerediRegularity.Positivity
111+
112+
namespace SzemerediRegularity
113+
114+
open scoped SzemerediRegularity.Positivity
115+
116+
theorem m_pos [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) : 0 < m := by
117+
sz_positivity
118+
#align szemeredi_regularity.m_pos SzemerediRegularity.m_pos
119+
120+
theorem coe_m_add_one_pos : 0 < (m : ℝ) + 1 := by positivity
121+
#align szemeredi_regularity.coe_m_add_one_pos SzemerediRegularity.coe_m_add_one_pos
122+
123+
theorem one_le_m_coe [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α) : (1 : ℝ) ≤ m :=
124+
Nat.one_le_cast.2 <| m_pos hPα
125+
#align szemeredi_regularity.one_le_m_coe SzemerediRegularity.one_le_m_coe
126+
127+
theorem eps_pow_five_pos (hPε : 100 ≤ (4 : ℝ) ^ P.parts.card * ε ^ 5) : ↑0 < ε ^ 5 :=
128+
pos_of_mul_pos_right ((by norm_num : (0 : ℝ) < 100).trans_le hPε) <| pow_nonneg (by norm_num) _
129+
#align szemeredi_regularity.eps_pow_five_pos SzemerediRegularity.eps_pow_five_pos
130+
131+
theorem eps_pos (hPε : 100 ≤ (4 : ℝ) ^ P.parts.card * ε ^ 5) : 0 < ε :=
132+
(Odd.pow_pos_iff (by norm_num)).mp (eps_pow_five_pos hPε)
133+
#align szemeredi_regularity.eps_pos SzemerediRegularity.eps_pos
134+
135+
theorem hundred_div_ε_pow_five_le_m [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α)
136+
(hPε : 100 ≤ (4 : ℝ) ^ P.parts.card * ε ^ 5) : 100 / ε ^ 5 ≤ m :=
137+
(div_le_of_nonneg_of_le_mul (eps_pow_five_pos hPε).le (by positivity) hPε).trans
138+
(by
139+
norm_cast
140+
rwa [Nat.le_div_iff_mul_le' (stepBound_pos (P.parts_nonempty <|
141+
univ_nonempty.ne_empty).card_pos), stepBound, mul_left_comm, ← mul_pow])
142+
#align szemeredi_regularity.hundred_div_ε_pow_five_le_m SzemerediRegularity.hundred_div_ε_pow_five_le_m
143+
144+
theorem hundred_le_m [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ card α)
145+
(hPε : 100 ≤ (4 : ℝ) ^ P.parts.card * ε ^ 5) (hε : ε ≤ 1) : 100 ≤ m := by
146+
exact_mod_cast
147+
(hundred_div_ε_pow_five_le_m hPα hPε).trans'
148+
(le_div_self (by norm_num) (by sz_positivity) <| pow_le_one _ (by sz_positivity) hε)
149+
#align szemeredi_regularity.hundred_le_m SzemerediRegularity.hundred_le_m
150+
151+
theorem a_add_one_le_four_pow_parts_card : a + 14 ^ P.parts.card := by
152+
have h : 14 ^ P.parts.card := one_le_pow_of_one_le (by norm_num) _
153+
rw [stepBound, ← Nat.div_div_eq_div_mul]
154+
conv_rhs => rw [← Nat.sub_add_cancel h]
155+
rw [add_le_add_iff_right, tsub_le_iff_left, ← Nat.add_sub_assoc h]
156+
exact Nat.le_pred_of_lt (Nat.lt_div_mul_add h)
157+
#align szemeredi_regularity.a_add_one_le_four_pow_parts_card SzemerediRegularity.a_add_one_le_four_pow_parts_card
158+
159+
theorem card_aux₁ (hucard : u.card = m * 4 ^ P.parts.card + a) :
160+
(4 ^ P.parts.card - a) * m + a * (m + 1) = u.card := by
161+
rw [hucard, mul_add, mul_one, ← add_assoc, ← add_mul,
162+
Nat.sub_add_cancel ((Nat.le_succ _).trans a_add_one_le_four_pow_parts_card), mul_comm]
163+
#align szemeredi_regularity.card_aux₁ SzemerediRegularity.card_aux₁
164+
165+
theorem card_aux₂ (hP : P.IsEquipartition) (hu : u ∈ P.parts)
166+
(hucard : ¬u.card = m * 4 ^ P.parts.card + a) :
167+
(4 ^ P.parts.card - (a + 1)) * m + (a + 1) * (m + 1) = u.card := by
168+
have : m * 4 ^ P.parts.card ≤ card α / P.parts.card := by
169+
rw [stepBound, ← Nat.div_div_eq_div_mul]
170+
exact Nat.div_mul_le_self _ _
171+
rw [Nat.add_sub_of_le this] at hucard
172+
rw [(hP.card_parts_eq_average hu).resolve_left hucard, mul_add, mul_one, ← add_assoc, ← add_mul,
173+
Nat.sub_add_cancel a_add_one_le_four_pow_parts_card, ← add_assoc, mul_comm,
174+
Nat.add_sub_of_le this, card_univ]
175+
#align szemeredi_regularity.card_aux₂ SzemerediRegularity.card_aux₂
176+
177+
theorem pow_mul_m_le_card_part (hP : P.IsEquipartition) (hu : u ∈ P.parts) :
178+
(4 : ℝ) ^ P.parts.card * m ≤ u.card := by
179+
norm_cast
180+
rw [stepBound, ← Nat.div_div_eq_div_mul]
181+
exact (Nat.mul_div_le _ _).trans (hP.average_le_card_part hu)
182+
#align szemeredi_regularity.pow_mul_m_le_card_part SzemerediRegularity.pow_mul_m_le_card_part
183+
184+
variable (P ε) (l : ℕ)
185+
186+
/-- Auxiliary function for Szemerédi's regularity lemma. The size of the partition by which we start
187+
blowing. -/
188+
noncomputable def initialBound : ℕ :=
189+
max 7 <| max l <| ⌊log (100 / ε ^ 5) / log 4⌋₊ + 1
190+
#align szemeredi_regularity.initial_bound SzemerediRegularity.initialBound
191+
192+
theorem le_initialBound : l ≤ initialBound ε l :=
193+
(le_max_left _ _).trans <| le_max_right _ _
194+
#align szemeredi_regularity.le_initial_bound SzemerediRegularity.le_initialBound
195+
196+
theorem seven_le_initialBound : 7 ≤ initialBound ε l :=
197+
le_max_left _ _
198+
#align szemeredi_regularity.seven_le_initial_bound SzemerediRegularity.seven_le_initialBound
199+
200+
theorem initialBound_pos : 0 < initialBound ε l :=
201+
Nat.succ_pos'.trans_le <| seven_le_initialBound _ _
202+
#align szemeredi_regularity.initial_bound_pos SzemerediRegularity.initialBound_pos
203+
204+
theorem hundred_lt_pow_initialBound_mul {ε : ℝ} (hε : 0 < ε) (l : ℕ) :
205+
100 < ↑4 ^ initialBound ε l * ε ^ 5 := by
206+
rw [← rpow_nat_cast 4, ← div_lt_iff (pow_pos hε 5), lt_rpow_iff_log_lt _ zero_lt_four, ←
207+
div_lt_iff, initialBound, Nat.cast_max, Nat.cast_max]
208+
· push_cast
209+
exact lt_max_of_lt_right (lt_max_of_lt_right <| Nat.lt_floor_add_one _)
210+
· exact log_pos (by norm_num)
211+
· exact div_pos (by norm_num) (pow_pos hε 5)
212+
#align szemeredi_regularity.hundred_lt_pow_initial_bound_mul SzemerediRegularity.hundred_lt_pow_initialBound_mul
213+
214+
/-- An explicit bound on the size of the equipartition whose existence is given by Szemerédi's
215+
regularity lemma. -/
216+
noncomputable def bound : ℕ :=
217+
(stepBound^[⌊4 / ε ^ 5⌋₊] <| initialBound ε l) *
218+
16 ^ (stepBound^[⌊4 / ε ^ 5⌋₊] <| initialBound ε l)
219+
#align szemeredi_regularity.bound SzemerediRegularity.bound
220+
221+
theorem initialBound_le_bound : initialBound ε l ≤ bound ε l :=
222+
(id_le_iterate_of_id_le le_stepBound _ _).trans <| Nat.le_mul_of_pos_right <| by positivity
223+
#align szemeredi_regularity.initial_bound_le_bound SzemerediRegularity.initialBound_le_bound
224+
225+
theorem le_bound : l ≤ bound ε l :=
226+
(le_initialBound ε l).trans <| initialBound_le_bound ε l
227+
#align szemeredi_regularity.le_bound SzemerediRegularity.le_bound
228+
229+
theorem bound_pos : 0 < bound ε l :=
230+
(initialBound_pos ε l).trans_le <| initialBound_le_bound ε l
231+
#align szemeredi_regularity.bound_pos SzemerediRegularity.bound_pos
232+
233+
variable {ι 𝕜 : Type _} [LinearOrderedField 𝕜] (r : ι → ι → Prop) [DecidableRel r] {s t : Finset ι}
234+
{x : 𝕜}
235+
236+
theorem mul_sq_le_sum_sq (hst : s ⊆ t) (f : ι → 𝕜) (hs : x ^ 2 ≤ ((∑ i in s, f i) / s.card) ^ 2)
237+
(hs' : (s.card : 𝕜) ≠ 0) : (s.card : 𝕜) * x ^ 2 ≤ ∑ i in t, f i ^ 2 :=
238+
(mul_le_mul_of_nonneg_left (hs.trans sum_div_card_sq_le_sum_sq_div_card) <|
239+
Nat.cast_nonneg _).trans <| (mul_div_cancel' _ hs').le.trans <|
240+
sum_le_sum_of_subset_of_nonneg hst fun _ _ _ => sq_nonneg _
241+
#align szemeredi_regularity.mul_sq_le_sum_sq SzemerediRegularity.mul_sq_le_sum_sq
242+
243+
theorem add_div_le_sum_sq_div_card (hst : s ⊆ t) (f : ι → 𝕜) (d : 𝕜) (hx : 0 ≤ x)
244+
(hs : x ≤ |(∑ i in s, f i) / s.card - (∑ i in t, f i) / t.card|)
245+
(ht : d ≤ ((∑ i in t, f i) / t.card) ^ 2) :
246+
d + s.card / t.card * x ^ 2 ≤ (∑ i in t, f i ^ 2) / t.card := by
247+
obtain hscard | hscard := (s.card.cast_nonneg : (0 : 𝕜) ≤ s.card).eq_or_lt
248+
· simpa [← hscard] using ht.trans sum_div_card_sq_le_sum_sq_div_card
249+
have htcard : (0 : 𝕜) < t.card := hscard.trans_le (Nat.cast_le.2 (card_le_of_subset hst))
250+
have h₁ : x ^ 2 ≤ ((∑ i in s, f i) / s.card - (∑ i in t, f i) / t.card) ^ 2 :=
251+
sq_le_sq.2 (by rwa [abs_of_nonneg hx])
252+
have h₂ : x ^ 2 ≤ ((∑ i in s, (f i - (∑ j in t, f j) / t.card)) / s.card) ^ 2 := by
253+
apply h₁.trans
254+
rw [sum_sub_distrib, sum_const, nsmul_eq_mul, sub_div, mul_div_cancel_left _ hscard.ne']
255+
apply (add_le_add_right ht _).trans
256+
rw [← mul_div_right_comm, le_div_iff htcard, add_mul, div_mul_cancel _ htcard.ne']
257+
have h₃ := mul_sq_le_sum_sq hst (fun i => (f i - (∑ j in t, f j) / t.card)) h₂ hscard.ne'
258+
apply (add_le_add_left h₃ _).trans
259+
-- Porting note: was
260+
-- `simp [← mul_div_right_comm _ (t.card : 𝕜), sub_div' _ _ _ htcard.ne', ← sum_div, ← add_div,`
261+
-- ` mul_pow, div_le_iff (sq_pos_of_ne_zero _ htcard.ne'), sub_sq, sum_add_distrib, ← sum_mul, ←`
262+
-- ` mul_sum]`
263+
simp_rw [sub_div' _ _ _ htcard.ne']
264+
conv_lhs => enter [2, 2, x]; rw [div_pow]
265+
rw [div_pow, ← sum_div, ← mul_div_right_comm _ (t.card : 𝕜), ← add_div,
266+
div_le_iff (sq_pos_of_ne_zero _ htcard.ne')]
267+
simp_rw [sub_sq, sum_add_distrib, sum_const, nsmul_eq_mul, sum_sub_distrib, mul_pow, ← sum_mul,
268+
← mul_sum, ← sum_mul]
269+
ring_nf; rfl
270+
#align szemeredi_regularity.add_div_le_sum_sq_div_card SzemerediRegularity.add_div_le_sum_sq_div_card
271+
272+
end SzemerediRegularity
273+
274+
namespace Tactic
275+
276+
open Lean.Meta Qq
277+
278+
/-- Extension for the `positivity` tactic: `SzemerediRegularity.initialBound` is always positive. -/
279+
@[positivity SzemerediRegularity.initialBound _ _]
280+
def evalInitialBound : Mathlib.Meta.Positivity.PositivityExt where eval {_ _} _ _ e := do
281+
let (.app (.app _ (ε : Q(ℝ))) (l : Q(ℕ))) ← whnfR e | throwError "not initialBound"
282+
pure (.positive (q(SzemerediRegularity.initialBound_pos $ε $l) : Lean.Expr))
283+
284+
example (ε : ℝ) (l : ℕ) : 0 < SzemerediRegularity.initialBound ε l := by positivity
285+
286+
/-- Extension for the `positivity` tactic: `SzemerediRegularity.bound` is always positive. -/
287+
@[positivity SzemerediRegularity.bound _ _]
288+
def evalBound : Mathlib.Meta.Positivity.PositivityExt where eval {_ _} _ _ e := do
289+
let (.app (.app _ (ε : Q(ℝ))) (l : Q(ℕ))) ← whnfR e | throwError "not bound"
290+
pure (.positive (q(SzemerediRegularity.bound_pos $ε $l) : Lean.Expr))
291+
292+
example (ε : ℝ) (l : ℕ) : 0 < SzemerediRegularity.bound ε l := by positivity
293+
294+
end Tactic

0 commit comments

Comments
 (0)