Skip to content

Commit 38084fa

Browse files
committed
refactor(SimpleGraph): make triangleRemovalBound positive more often (#29540)
It wasn't positive when `ε > 4`, but that is a junk value anyway, so we change the junk value to a positive one. See #29496 for more context.
1 parent c9a2a18 commit 38084fa

File tree

6 files changed

+66
-40
lines changed

6 files changed

+66
-40
lines changed

Mathlib/Combinatorics/Additive/Corner/Roth.lean

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,7 @@ theorem corners_theorem (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound ε
8787
rwa [mul_le_iff_le_one_left] at this
8888
positivity
8989
have := noAccidental hA
90-
rw [Nat.floor_lt' (by positivity), inv_lt_iff_one_lt_mul₀'] at hG
91-
swap
92-
· have := triangleRemovalBound_pos (ε := ε / 9) (by linarith) (by linarith)
93-
linarith
90+
rw [Nat.floor_lt' (by positivity), inv_lt_iff_one_lt_mul₀' (by positivity)] at hG
9491
refine hG.not_ge (le_of_mul_le_mul_right ?_ (by positivity : (0 : ℝ) < card G ^ 2))
9592
classical
9693
have h₁ := (farFromTriangleFree_graph hAε).le_card_cliqueFinset

Mathlib/Combinatorics/SimpleGraph/DeleteEdges.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ alias ⟨DeleteFar.le_card_sub_card, _⟩ := deleteFar_iff
221221
theorem DeleteFar.mono (h : G.DeleteFar p r₂) (hr : r₁ ≤ r₂) : G.DeleteFar p r₁ := fun _ hs hG =>
222222
hr.trans <| h hs hG
223223

224+
lemma DeleteFar.le_card_edgeFinset (h : G.DeleteFar p r) (hp : p ⊥) : r ≤ #G.edgeFinset :=
225+
h subset_rfl (by simpa)
226+
224227
end DeleteFar
225228

226229
end SimpleGraph

Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Mathlib.Algebra.Order.Ring.Abs
88
import Mathlib.Combinatorics.Enumerative.DoubleCounting
99
import Mathlib.Combinatorics.SimpleGraph.Clique
1010
import Mathlib.Data.Finset.Sym
11+
import Mathlib.Data.Nat.Choose.Bounds
1112
import Mathlib.Tactic.GCongr
1213
import Mathlib.Tactic.Positivity
1314

@@ -252,29 +253,14 @@ end DecidableEq
252253

253254
variable [Nonempty α]
254255

255-
lemma FarFromTriangleFree.lt_half (hG : G.FarFromTriangleFree ε) : ε < 2⁻¹ := by
256-
classical
257-
by_contra! hε
258-
refine lt_irrefl (ε * card α ^ 2) ?_
259-
have hε₀ : 0 < ε := hε.trans_lt' (by simp)
260-
rw [inv_le_iff_one_le_mul₀ (zero_lt_two' 𝕜)] at hε
261-
calc
262-
_ ≤ (#G.edgeFinset : 𝕜) := by
263-
simpa using hG.le_card_sub_card bot_le (cliqueFree_bot (le_succ _))
264-
_ ≤ ε * 2 * #G.edgeFinset := le_mul_of_one_le_left (by positivity) (by assumption)
265-
_ < ε * card α ^ 2 := ?_
266-
rw [mul_assoc, mul_lt_mul_left hε₀]
267-
norm_cast
256+
lemma FarFromTriangleFree.lt_half (hε : G.FarFromTriangleFree ε) : ε < 2⁻¹ := by
257+
refine lt_of_mul_lt_mul_right (α := 𝕜) (a := Fintype.card α ^ 2) ?_ (by positivity)
268258
calc
269-
_ ≤ 2 * (completeGraph α).edgeFinset.card := by gcongr; exact le_top
270-
_ < card α ^ 2 := ?_
271-
rw [edgeFinset_top, filter_not, card_sdiff_of_subset (subset_univ _), Finset.card_univ, Sym2.card]
272-
simp_rw [choose_two_right, Nat.add_sub_cancel, Nat.mul_comm _ (card α),
273-
funext (propext <| Sym2.isDiag_iff_mem_range_diag ·), univ_filter_mem_range, mul_tsub,
274-
Nat.mul_div_cancel' (card α).even_mul_succ_self.two_dvd]
275-
rw [card_image_of_injective _ Sym2.diag_injective, Finset.card_univ, mul_add_one (α := ℕ),
276-
two_mul, sq, add_tsub_add_eq_tsub_right]
277-
apply tsub_lt_self <;> positivity
259+
ε * Fintype.card α ^ 2
260+
_ ≤ #G.edgeFinset := by simpa using hε.le_card_edgeFinset (by simp)
261+
_ ≤ (Fintype.card α).choose 2 := by gcongr; exact card_edgeFinset_le_card_choose_two
262+
_ < 2⁻¹ * Fintype.card α ^ 2 := by
263+
simpa [← div_eq_inv_mul] using Nat.choose_lt_pow_div (by positivity) le_rfl
278264

279265
lemma FarFromTriangleFree.lt_one (hG : G.FarFromTriangleFree ε) : ε < 1 :=
280266
hG.lt_half.trans two_inv_lt_one

Mathlib/Combinatorics/SimpleGraph/Triangle/Removal.lean

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,16 @@ namespace SimpleGraph
2929
/-- An explicit form for the constant in the triangle removal lemma.
3030
3131
Note that this depends on `SzemerediRegularity.bound`, which is a tower-type exponential. This means
32-
`triangleRemovalBound` is in practice absolutely tiny. -/
32+
`triangleRemovalBound` is in practice absolutely tiny.
33+
34+
This definition is meant to be used for small values of `ε`, and in particular is junk for values
35+
of `ε` greater than or equal to `1`. The junk value is chosen to be positive, so that
36+
`0 < ε → 0 < triangleRemovalBound ε` regardless of whether `ε < 1` or not. -/
3337
noncomputable def triangleRemovalBound (ε : ℝ) : ℝ :=
34-
min (2 * ⌈4/ε⌉₊^3)⁻¹ ((1 - ε/4) * (ε/(16 * bound (ε/8) ⌈4/ε⌉₊))^3)
38+
min (2 * ⌈4/ε⌉₊^3)⁻¹ ((1 - min 1 ε/4) * (ε/(16 * bound (ε/8) ⌈4/ε⌉₊))^3)
3539

36-
lemma triangleRemovalBound_pos (hε : 0 < ε) (hε₁ : ε ≤ 1) : 0 < triangleRemovalBound ε := by
37-
have : 0 < 1 - ε / 4 := by linarith
40+
lemma triangleRemovalBound_pos (hε : 0 < ε) : 0 < triangleRemovalBound ε := by
41+
have : 0 < 1 - min 1 ε/4 := by have := min_le_left 1 ε; linarith
3842
unfold triangleRemovalBound
3943
positivity
4044

@@ -48,6 +52,10 @@ lemma triangleRemovalBound_mul_cube_lt (hε : 0 < ε) :
4852
_ = 2⁻¹ := by rw [mul_inv, inv_mul_cancel_right₀]; positivity
4953
_ < 1 := by norm_num
5054

55+
lemma triangleRemovalBound_le (hε₁ : ε ≤ 1) :
56+
triangleRemovalBound ε ≤ (1 - ε/4) * (ε/(16 * bound (ε/8) ⌈4/ε⌉₊)) ^ 3 := by
57+
simp [triangleRemovalBound, hε₁]
58+
5159
private lemma aux {n k : ℕ} (hk : 0 < k) (hn : k ≤ n) : n < 2 * k * (n / k) := by
5260
rw [mul_assoc, two_mul, ← add_lt_add_iff_right (n % k), add_right_comm, add_assoc,
5361
mod_add_div n k, add_comm, add_lt_add_iff_right]
@@ -65,7 +73,7 @@ private lemma card_bound (hP₁ : P.IsEquipartition) (hP₃ : #P.parts ≤ bound
6573
(div_le_iff₀' (by positivity)).2 <| mod_cast (aux ‹_› P.card_parts_le_card).le
6674
_ ≤ (#s : ℝ) := mod_cast hP₁.average_le_card_part hX
6775

68-
private lemma triangle_removal_aux (hε : 0 < ε) (hP₁ : P.IsEquipartition)
76+
private lemma triangle_removal_aux (hε : 0 < ε) (hε₁ : ε ≤ 1) (hP₁ : P.IsEquipartition)
6977
(hP₃ : #P.parts ≤ bound (ε / 8) ⌈4 / ε⌉₊)
7078
(ht : t ∈ (G.regularityReduced P (ε / 8) (ε / 4)).cliqueFinset 3) :
7179
triangleRemovalBound ε * card α ^ 3 ≤ #(G.cliqueFinset 3) := by
@@ -84,7 +92,7 @@ private lemma triangle_removal_aux (hε : 0 < ε) (hP₁ : P.IsEquipartition)
8492
have : ε / 41 := ‹ε / 4 ≤ _›.trans (by exact mod_cast G.edgeDensity_le_one _ _); linarith
8593
calc
8694
_ ≤ (1 - ε/4) * (ε/(16 * bound (ε/8) ⌈4/ε⌉₊))^3 * card α ^ 3 := by
87-
gcongr; exact min_le_right _ _
95+
gcongr; exact triangleRemovalBound_le hε₁
8896
_ = (1 - 2 * (ε / 8)) * (ε / 8) ^ 3 * (card α / (2 * bound (ε / 8) ⌈4 / ε⌉₊)) *
8997
(card α / (2 * bound (ε / 8) ⌈4 / ε⌉₊)) * (card α / (2 * bound (ε / 8) ⌈4 / ε⌉₊)) := by
9098
ring
@@ -132,7 +140,7 @@ lemma FarFromTriangleFree.le_card_cliqueFinset (hG : G.FarFromTriangleFree ε) :
132140
rcases le_total (card α) l with hl' | hl'
133141
· calc
134142
_ ≤ triangleRemovalBound ε * ↑l ^ 3 := by
135-
gcongr; exact (triangleRemovalBound_pos hε hG.lt_one.le).le
143+
gcongr; exact (triangleRemovalBound_pos hε).le
136144
_ ≤ (1 : ℝ) := (triangleRemovalBound_mul_cube_lt hε).le
137145
_ ≤ _ := by simpa [one_le_iff_ne_zero] using (hG.cliqueFinset_nonempty hε).card_pos.ne'
138146
obtain ⟨P, hP₁, hP₂, hP₃, hP₄⟩ := szemeredi_regularity G (by positivity : 0 < ε / 8) hl'
@@ -141,7 +149,7 @@ lemma FarFromTriangleFree.le_card_cliqueFinset (hG : G.FarFromTriangleFree ε) :
141149
rw [mul_assoc] at k
142150
replace k := lt_of_mul_lt_mul_left k zero_le_two
143151
obtain ⟨t, ht⟩ := hG.cliqueFinset_nonempty' regularityReduced_le k
144-
exact triangle_removal_aux hε hP₁ hP₃ ht
152+
exact triangle_removal_aux hε hG.lt_one.le hP₁ hP₃ ht
145153

146154
/-- **Triangle Removal Lemma**. If there are not too many triangles (on the order of `(card α)^3`)
147155
then they can all be removed by removing a few edges (on the order of `(card α)^2`). -/
@@ -154,3 +162,23 @@ lemma triangle_removal (hG : #(G.cliqueFinset 3) < triangleRemovalBound ε * car
154162
exact le_of_not_gt fun i ↦ h G' hG _ i hG'
155163

156164
end SimpleGraph
165+
166+
namespace Mathlib.Meta.Positivity
167+
open Lean.Meta Qq SimpleGraph
168+
169+
/-- Extension for the `positivity` tactic: `SimpleGraph.triangleRemovalBound ε` is positive
170+
if `ε` is.
171+
172+
This exploits the positivity of the junk value of `triangleRemovalBound ε` for `ε ≥ 1`. -/
173+
@[positivity triangleRemovalBound _]
174+
def evalTriangleRemovalBound : PositivityExt where eval {u α} _zα _pα e := do
175+
match u, α, e with
176+
| 0, ~q(ℝ), ~q(triangleRemovalBound $ε) =>
177+
let .positive hε ← core q(inferInstance) q(inferInstance) ε | failure
178+
assertInstancesCommute
179+
pure (.positive q(triangleRemovalBound_pos $hε))
180+
| _, _, _ => throwError "failed to match on Int.ceil application"
181+
182+
example (ε : ℝ) (hε : 0 < ε) : 0 < triangleRemovalBound ε := by positivity
183+
184+
end Mathlib.Meta.Positivity

Mathlib/Data/Nat/Choose/Bounds.lean

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ bounds `n^r/r^r ≤ n.choose r ≤ e^r n^r/r^r` in the future.
2323

2424
open Nat
2525

26-
variable {α : Type*} [Semifield α] [LinearOrder α] [IsStrictOrderedRing α]
26+
variable {α : Type*} [Semifield α] [LinearOrder α] [IsStrictOrderedRing α] {n k : ℕ}
2727

2828
namespace Nat
2929

@@ -34,15 +34,25 @@ theorem choose_le_pow_div (r n : ℕ) : (n.choose r : α) ≤ (n ^ r : α) / r !
3434
exact n.descFactorial_le_pow r
3535
exact mod_cast r.factorial_pos
3636

37+
lemma choose_lt_pow_div (hn : n ≠ 0) (hk : 2 ≤ k) : (n.choose k : α) < (n ^ k : α) / k ! := by
38+
rw [lt_div_iff₀' (mod_cast k.factorial_pos)]
39+
norm_cast
40+
rw [← Nat.descFactorial_eq_factorial_mul_choose]
41+
exact descFactorial_lt_pow hn hk
42+
3743
lemma choose_le_descFactorial (n k : ℕ) : n.choose k ≤ n.descFactorial k := by
3844
rw [choose_eq_descFactorial_div_factorial]
3945
exact Nat.div_le_self _ _
4046

41-
/-- This lemma was changed on 2024/08/29, the old statement is available
42-
in `Nat.choose_le_pow_div`. -/
47+
lemma choose_lt_descFactorial (hk : 2 ≤ k) (hkn : k ≤ n) : n.choose k < n.descFactorial k := by
48+
rw [choose_eq_descFactorial_div_factorial]; exact Nat.div_lt_self (by simpa) (by simpa)
49+
4350
lemma choose_le_pow (n k : ℕ) : n.choose k ≤ n ^ k :=
4451
(choose_le_descFactorial n k).trans (descFactorial_le_pow n k)
4552

53+
lemma choose_lt_pow (hn : n ≠ 0) (hk : 2 ≤ k) : n.choose k < n ^ k :=
54+
(choose_le_descFactorial n k).trans_lt (descFactorial_lt_pow hn hk)
55+
4656
-- horrific casting is due to ℕ-subtraction
4757
theorem pow_le_choose (r n : ℕ) : ((n + 1 - r : ℕ) ^ r : α) / r ! ≤ n.choose r := by
4858
rw [div_le_iff₀']

Mathlib/Data/Nat/Factorial/Basic.lean

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@ theorem descFactorial_eq_zero_iff_lt {n : ℕ} : ∀ {k : ℕ}, n.descFactorial
346346
Nat.sub_eq_zero_iff_le, Nat.lt_iff_le_and_ne, or_iff_left_iff_imp, and_imp]
347347
exact fun h _ => h
348348

349+
@[simp]
350+
lemma descFactorial_pos {n k : ℕ} : 0 < n.descFactorial k ↔ k ≤ n := by simp [Nat.pos_iff_ne_zero]
351+
349352
alias ⟨_, descFactorial_of_lt⟩ := descFactorial_eq_zero_iff_lt
350353

351354
theorem add_descFactorial_eq_ascFactorial (n : ℕ) : ∀ k : ℕ,
@@ -434,13 +437,12 @@ theorem descFactorial_le_pow (n : ℕ) : ∀ k : ℕ, n.descFactorial k ≤ n ^
434437
rw [descFactorial_succ, Nat.pow_succ, Nat.mul_comm _ n]
435438
exact Nat.mul_le_mul (Nat.sub_le _ _) (descFactorial_le_pow _ k)
436439

437-
theorem descFactorial_lt_pow {n : ℕ} (hn : 1 ≤ n) : ∀ {k : ℕ}, 2 ≤ k → n.descFactorial k < n ^ k
440+
theorem descFactorial_lt_pow {n : ℕ} (hn : n ≠ 0) : ∀ {k : ℕ}, 2 ≤ k → n.descFactorial k < n ^ k
438441
| 0 => by rintro ⟨⟩
439442
| 1 => by intro; contradiction
440443
| k + 2 => fun _ => by
441444
rw [descFactorial_succ, pow_succ', Nat.mul_comm, Nat.mul_comm n]
442-
exact Nat.mul_lt_mul_of_le_of_lt (descFactorial_le_pow _ _) (Nat.sub_lt hn k.zero_lt_succ)
443-
(Nat.pow_pos (Nat.lt_of_succ_le hn))
445+
exact Nat.mul_lt_mul_of_le_of_lt (descFactorial_le_pow _ _) (by omega) (Nat.pow_pos <| by omega)
444446

445447
end DescFactorial
446448

0 commit comments

Comments
 (0)