Skip to content

Commit 6895836

Browse files
Parcly-Taxelyuanyi-350
authored andcommitted
feat: number of edges in the Turán graph (leanprover-community#25788)
We provide two theorems, the first `card_edgeFinset_turanGraph` providing the exact number of edges and the other `mul_card_edgeFinset_turanGraph_le` providing a (slightly) looser bound whose main advantage is its lack of division/modulus operations. The bound in `mul_card_edgeFinset_turanGraph_le` is also the bound provided in [Motzkin and Straus (1965)](https://doi.org/10.4153%2FCJM-1965-053-6). Co-authored-by: Parcly Taxel <reddeloostw@gmail.com>
1 parent 36eb7b7 commit 6895836

File tree

2 files changed

+116
-2
lines changed

2 files changed

+116
-2
lines changed

Mathlib/Combinatorics/SimpleGraph/Extremal/Turan.lean

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Jeremy Tan
55
-/
66
import Mathlib.Combinatorics.SimpleGraph.Clique
7+
import Mathlib.Combinatorics.SimpleGraph.DegreeSum
78
import Mathlib.Order.Partition.Equipartition
89

910
/-!
@@ -255,8 +256,7 @@ theorem card_parts [DecidableEq V] : #h.finpartition.parts = min (Fintype.card V
255256
have cf : G.CliqueFree r := by
256257
simp_rw [← cliqueFinset_eq_empty_iff, cliqueFinset, filter_eq_empty_iff, mem_univ,
257258
forall_true_left, isNClique_iff, and_comm, not_and, isClique_iff, Set.Pairwise]
258-
#adaptation_note /-- 2025-07-19 added `-congrConsts` -/
259-
intro z zc; push_neg; simp_rw -congrConsts [h.not_adj_iff_part_eq]
259+
intro z zc; push_neg; simp_rw [h.not_adj_iff_part_eq]
260260
exact exists_ne_map_eq_of_card_lt_of_maps_to (zc.symm ▸ l.2) fun a _ ↦
261261
fp.part_mem.2 (mem_univ a)
262262
use G ⊔ edge x y, inferInstance, cf.sup_edge x y
@@ -310,4 +310,110 @@ theorem isTuranMaximal_iff_nonempty_iso_turanGraph (hr : 0 < r) :
310310
G.IsTuranMaximal r ↔ Nonempty (G ≃g turanGraph (Fintype.card V) r) :=
311311
fun h ↦ h.nonempty_iso_turanGraph, fun h ↦ isTuranMaximal_of_iso h.some hr⟩
312312

313+
/-! ### Number of edges in the Turán graph -/
314+
315+
private lemma sum_ne_add_mod_eq_sub_one {c : ℕ} :
316+
∑ w ∈ range r, (if c % r ≠ (n + w) % r then 1 else 0) = r - 1 := by
317+
rcases r.eq_zero_or_pos with rfl | hr; · simp
318+
suffices #{i ∈ range r | c % r = (n + i) % r} = 1 by
319+
rw [← card_filter, ← this]; apply Nat.eq_sub_of_add_eq'
320+
rw [filter_card_add_filter_neg_card_eq_card, card_range]
321+
apply le_antisymm
322+
· change #{i ∈ range r | _ ≡ _ [MOD r]} ≤ 1
323+
rw [card_le_one_iff]; intro w x mw mx
324+
simp only [mem_filter, mem_range] at mw mx
325+
have := mw.2.symm.trans mx.2
326+
rw [Nat.ModEq.add_iff_left rfl] at this
327+
change w % r = x % r at this
328+
rwa [Nat.mod_eq_of_lt mw.1, Nat.mod_eq_of_lt mx.1] at this
329+
· rw [one_le_card]; use ((r - 1) * n + c) % r
330+
simp only [mem_filter, mem_range]; refine ⟨Nat.mod_lt _ hr, ?_⟩
331+
rw [Nat.add_mod_mod, ← add_assoc, ← one_add_mul, show 1 + (r - 1) = r by omega,
332+
Nat.mul_add_mod_self_left]
333+
334+
lemma card_edgeFinset_turanGraph_add :
335+
#(turanGraph (n + r) r).edgeFinset =
336+
#(turanGraph n r).edgeFinset + n * (r - 1) + r.choose 2 := by
337+
rw [← mul_right_inj' two_ne_zero]
338+
simp_rw [mul_add, ← sum_degrees_eq_twice_card_edges,
339+
degree, neighborFinset_eq_filter, turanGraph, card_filter]
340+
conv_lhs =>
341+
enter [2, v]
342+
rw [Fin.sum_univ_eq_sum_range fun w ↦ if v % r ≠ w % r then 1 else 0, sum_range_add]
343+
rw [sum_add_distrib,
344+
Fin.sum_univ_eq_sum_range fun v ↦ ∑ w ∈ range n, if v % r ≠ w % r then 1 else 0,
345+
Fin.sum_univ_eq_sum_range fun v ↦ ∑ w ∈ range r, if v % r ≠ (n + w) % r then 1 else 0,
346+
sum_range_add, sum_range_add, add_assoc, add_assoc]
347+
congr 1; · simp [← Fin.sum_univ_eq_sum_range]
348+
rw [← add_assoc, sum_comm]; simp_rw [ne_comm, ← two_mul]; congr
349+
· conv_rhs => rw [← card_range n, ← smul_eq_mul, ← sum_const]
350+
congr!; exact sum_ne_add_mod_eq_sub_one
351+
· rw [mul_comm 2, Nat.choose_two_right, Nat.div_two_mul_two_of_even (Nat.even_mul_pred_self r)]
352+
conv_rhs => enter [1]; rw [← card_range r]
353+
rw [← smul_eq_mul, ← sum_const]
354+
congr!; exact sum_ne_add_mod_eq_sub_one
355+
356+
/-- The exact formula for the number of edges in `turanGraph n r`. -/
357+
theorem card_edgeFinset_turanGraph {n r : ℕ} :
358+
#(turanGraph n r).edgeFinset =
359+
(n ^ 2 - (n % r) ^ 2) * (r - 1) / (2 * r) + (n % r).choose 2 := by
360+
rcases r.eq_zero_or_pos with rfl | hr
361+
· rw [Nat.mod_zero, tsub_self, zero_mul, Nat.zero_div, zero_add]
362+
have := card_edgeFinset_top_eq_card_choose_two (V := Fin n)
363+
rw [Fintype.card_fin] at this; convert this; exact turanGraph_zero
364+
· have ring₁ (n) : (n ^ 2 - (n % r) ^ 2) * (r - 1) / (2 * r) =
365+
n % r * (n / r) * (r - 1) + r * (r - 1) * (n / r) ^ 2 / 2 := by
366+
nth_rw 1 [← Nat.mod_add_div n r, Nat.sq_sub_sq, add_tsub_cancel_left,
367+
show (n % r + r * (n / r) + n % r) * (r * (n / r)) * (r - 1) =
368+
(2 * ((n % r) * (n / r) * (r - 1)) + r * (r - 1) * (n / r) ^ 2) * r by grind]
369+
rw [Nat.mul_div_mul_right _ _ hr, Nat.mul_add_div zero_lt_two]
370+
rcases lt_or_ge n r with h | h
371+
· rw [Nat.mod_eq_of_lt h, tsub_self, zero_mul, Nat.zero_div, zero_add]
372+
have := card_edgeFinset_top_eq_card_choose_two (V := Fin n)
373+
rw [Fintype.card_fin] at this; convert this
374+
rw [turanGraph_eq_top]; exact .inr h.le
375+
· let n' := n - r
376+
have n'r : n = n' + r := by omega
377+
rw [n'r, card_edgeFinset_turanGraph_add, card_edgeFinset_turanGraph, ring₁, ring₁,
378+
add_rotate, ← add_assoc, Nat.add_mod_right, Nat.add_div_right _ hr]
379+
congr 1
380+
have rd : 2 ∣ r * (r - 1) := (Nat.even_mul_pred_self _).two_dvd
381+
rw [← Nat.div_mul_right_comm rd, ← Nat.div_mul_right_comm rd, ← Nat.choose_two_right]
382+
have ring₂ : n' % r * (n' / r + 1) * (r - 1) + r.choose 2 * (n' / r + 1) ^ 2 =
383+
n' % r * (n' / r + 1) * (r - 1) + r.choose 2 +
384+
r.choose 2 * 2 * (n' / r) + r.choose 2 * (n' / r) ^ 2 := by grind
385+
rw [ring₂, ← add_assoc]; congr 1
386+
rw [← add_rotate, ← add_rotate _ _ (r.choose 2)]; congr 1
387+
rw [Nat.choose_two_right, Nat.div_mul_cancel rd, mul_add_one, add_mul, ← add_assoc,
388+
← add_rotate, add_comm _ (_ *_)]; congr 1
389+
rw [← mul_rotate, ← add_mul, add_comm, mul_comm _ r, Nat.div_add_mod n' r]
390+
391+
/-- A looser (but simpler than `card_edgeFinset_turanGraph`) bound on the number of edges in
392+
`turanGraph n r`. -/
393+
theorem mul_card_edgeFinset_turanGraph_le :
394+
2 * r * #(turanGraph n r).edgeFinset ≤ (r - 1) * n ^ 2 := by
395+
rw [card_edgeFinset_turanGraph, mul_add]
396+
apply (Nat.add_le_add_right (Nat.mul_div_le ..) _).trans
397+
rw [tsub_mul, ← Nat.sub_add_comm]; swap
398+
· exact mul_le_mul_right' (pow_le_pow_left' (Nat.mod_le ..) _) _
399+
rw [Nat.sub_le_iff_le_add, mul_comm, Nat.add_le_add_iff_left, Nat.choose_two_right,
400+
← Nat.mul_div_assoc _ (Nat.even_mul_pred_self _).two_dvd, mul_assoc,
401+
mul_div_cancel_left₀ _ two_ne_zero, ← mul_assoc, ← mul_rotate, sq, ← mul_rotate (r - 1)]
402+
refine mul_le_mul_right' ?_ _
403+
rcases r.eq_zero_or_pos with rfl | hr; · omega
404+
rw [Nat.sub_one_mul, Nat.sub_one_mul, mul_comm]
405+
exact Nat.sub_le_sub_left (Nat.mod_lt _ hr).le _
406+
407+
theorem CliqueFree.card_edgeFinset_le (cf : G.CliqueFree (r + 1)) :
408+
let n := Fintype.card V;
409+
#G.edgeFinset ≤ (n ^ 2 - (n % r) ^ 2) * (r - 1) / (2 * r) + (n % r).choose 2 := by
410+
rcases r.eq_zero_or_pos with rfl | hr
411+
· rw [cliqueFree_one, ← Fintype.card_eq_zero_iff] at cf
412+
simp_rw [zero_tsub, mul_zero, Nat.mod_zero, Nat.div_zero, zero_add]
413+
exact card_edgeFinset_le_card_choose_two
414+
· obtain ⟨H, _, maxH⟩ := exists_isTuranMaximal (V := V) hr
415+
convert maxH.2 _ cf
416+
rw [((isTuranMaximal_iff_nonempty_iso_turanGraph hr).mp maxH).some.card_edgeFinset_eq,
417+
card_edgeFinset_turanGraph]
418+
313419
end SimpleGraph

Mathlib/Data/Nat/ModEq.lean

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ protected theorem add_left_cancel (h₁ : a ≡ b [MOD n]) (h₂ : a + c ≡ b +
141141
protected theorem add_left_cancel' (c : ℕ) (h : c + a ≡ c + b [MOD n]) : a ≡ b [MOD n] :=
142142
ModEq.rfl.add_left_cancel h
143143

144+
@[simp]
145+
protected theorem add_iff_left (h : a ≡ b [MOD n]) : a + c ≡ b + d [MOD n] ↔ c ≡ d [MOD n] :=
146+
⟨h.add_left_cancel, h.add⟩
147+
144148
protected theorem add_right_cancel (h₁ : c ≡ d [MOD n]) (h₂ : a + c ≡ b + d [MOD n]) :
145149
a ≡ b [MOD n] := by
146150
rw [add_comm a, add_comm b] at h₂
@@ -149,6 +153,10 @@ protected theorem add_right_cancel (h₁ : c ≡ d [MOD n]) (h₂ : a + c ≡ b
149153
protected theorem add_right_cancel' (c : ℕ) (h : a + c ≡ b + c [MOD n]) : a ≡ b [MOD n] :=
150154
ModEq.rfl.add_right_cancel h
151155

156+
@[simp]
157+
protected theorem add_iff_right (h : c ≡ d [MOD n]) : a + c ≡ b + d [MOD n] ↔ a ≡ b [MOD n] :=
158+
⟨h.add_right_cancel, (.add · h)⟩
159+
152160
protected lemma sub' (h : c ≤ a ↔ d ≤ b) (hab : a ≡ b [MOD n]) (hcd : c ≡ d [MOD n]) :
153161
a - c ≡ b - d [MOD n] := by
154162
obtain hac | hca := lt_or_ge a c

0 commit comments

Comments
 (0)