This repository was archived by the owner on Jul 24, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 292
feat(combinatorics/simple_graph): Construct a tripartite graph from its triangles #19202
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,10 @@ Copyright (c) 2022 Yaël Dillies, Bhavik Mehta. All rights reserved. | |
Released under Apache 2.0 license as described in the file LICENSE. | ||
Authors: Yaël Dillies, Bhavik Mehta | ||
-/ | ||
import combinatorics.double_counting | ||
import combinatorics.simple_graph.clique | ||
import data.nat.parity | ||
import data.sym.card | ||
|
||
/-! | ||
# Triangles in graphs | ||
|
@@ -18,6 +21,8 @@ This module defines and proves properties about triangles in simple graphs. | |
|
||
## Main declarations | ||
|
||
* `simple_graph.edge_disjoint_triangles`: Predicate for a graph whose triangles are edge-disjoint. | ||
* `simple_graph.locally_linear`: Predicate for each edge in a graph to be in a unique triangle. | ||
* `simple_graph.far_from_triangle_free`: Predicate for a graph to have enough triangles that, to | ||
remove all of them, one must one must remove a lot of edges. This is the crux of the Triangle | ||
Removal lemma. | ||
|
@@ -28,21 +33,183 @@ This module defines and proves properties about triangles in simple graphs. | |
* Find a better name for `far_from_triangle_free`. Added 4/26/2022. Remove this TODO if it gets old. | ||
-/ | ||
|
||
open finset fintype nat | ||
open_locale classical | ||
namespace finset | ||
variables {α : Type*} [decidable_eq α] | ||
|
||
lemma insert_comm (a b : α) (s : finset α) : insert a (insert b s) = insert b (insert a s) := | ||
coe_injective $ by { push_cast, exact set.insert_comm _ _ _ } | ||
|
||
end finset | ||
|
||
namespace simple_graph | ||
variables {V : Type*} | ||
|
||
@[simp] lemma edge_set_top : (⊤ : simple_graph V).edge_set = {e : sym2 V | ¬ e.is_diag} := | ||
by ext x; induction x using sym2.ind; simp | ||
|
||
@[simp] lemma edge_finset_top [fintype V] [decidable_eq V] [fintype (⊤ : simple_graph V).edge_set] : | ||
(⊤ : simple_graph V).edge_finset = finset.univ.filter (λ e, ¬ e.is_diag) := | ||
by ext x; induction x using sym2.ind; simp | ||
|
||
end simple_graph | ||
YaelDillies marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
open finset fintype (card) nat | ||
|
||
namespace simple_graph | ||
variables {α 𝕜 : Type*} [fintype α] [linear_ordered_field 𝕜] {G H : simple_graph α} {ε δ : 𝕜} | ||
{n : ℕ} {s : finset α} | ||
variables {α β 𝕜 : Type*} [linear_ordered_field 𝕜] {G H : simple_graph α} {ε δ : 𝕜} {n : ℕ} | ||
{s : finset α} | ||
|
||
section locally_linear | ||
|
||
/-- A graph has edge-disjoint triangles if each edge belongs to at most one triangle. -/ | ||
def edge_disjoint_triangles (G : simple_graph α) : Prop := | ||
(G.clique_set 3).pairwise $ λ x y, (x ∩ y : set α).subsingleton | ||
YaelDillies marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/-- A graph is locally linear if each edge belongs to exactly one triangle. -/ | ||
def locally_linear (G : simple_graph α) : Prop := | ||
G.edge_disjoint_triangles ∧ ∀ ⦃x y⦄, G.adj x y → ∃ s, G.is_n_clique 3 s ∧ x ∈ s ∧ y ∈ s | ||
|
||
protected lemma locally_linear.edge_disjoint_triangles : | ||
G.locally_linear → G.edge_disjoint_triangles := | ||
and.left | ||
|
||
lemma edge_disjoint_triangles.mono (h : G ≤ H) (hH : H.edge_disjoint_triangles) : | ||
G.edge_disjoint_triangles := | ||
hH.mono $ clique_set_mono h | ||
|
||
@[simp] lemma edge_disjoint_triangles_bot : (⊥ : simple_graph α).edge_disjoint_triangles := | ||
by simp [edge_disjoint_triangles] | ||
|
||
@[simp] lemma locally_linear_bot : (⊥ : simple_graph α).locally_linear := by simp [locally_linear] | ||
|
||
lemma edge_disjoint_triangles.map (f : α ↪ β) (hG : G.edge_disjoint_triangles) : | ||
(G.map f).edge_disjoint_triangles := | ||
begin | ||
rw [edge_disjoint_triangles, clique_set_map (bit1_lt_bit1.2 zero_lt_one), | ||
((finset.map_injective f).inj_on _).pairwise_image], | ||
classical, | ||
rintro s hs t ht hst, | ||
dsimp [function.on_fun], | ||
rw [←coe_inter, ←map_inter, coe_map, coe_inter], | ||
exact (hG hs ht hst).image _, | ||
end | ||
|
||
lemma locally_linear.map (f : α ↪ β) (hG : G.locally_linear) : (G.map f).locally_linear := | ||
begin | ||
refine ⟨hG.1.map _, _⟩, | ||
rintro _ _ ⟨a, b, h, rfl, rfl⟩, | ||
obtain ⟨s, hs, ha, hb⟩ := hG.2 h, | ||
exact ⟨s.map f, hs.map, mem_map_of_mem _ ha, mem_map_of_mem _ hb⟩, | ||
end | ||
|
||
@[simp] lemma locally_linear_comap {G : simple_graph β} {e : α ≃ β} : | ||
(G.comap e).locally_linear ↔ G.locally_linear := | ||
begin | ||
refine ⟨λ h, _, _⟩, | ||
{ rw [←comap_map_eq e.symm.to_embedding G, comap_symm, map_symm], | ||
exact h.map _ }, | ||
{ rw [←equiv.coe_to_embedding, ←map_symm], | ||
exact locally_linear.map _ } | ||
end | ||
Comment on lines
+105
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is one direction of this true for embeddings? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
variables [decidable_eq α] | ||
|
||
lemma edge_disjoint_triangles_iff_mem_sym2_subsingleton : | ||
G.edge_disjoint_triangles ↔ | ||
∀ ⦃e : sym2 α⦄, ¬e.is_diag → {s ∈ G.clique_set 3 | e ∈ (s : finset α).sym2}.subsingleton := | ||
begin | ||
have : ∀ a b, a ≠ b → {s ∈ (G.clique_set 3 : set (finset α)) | ⟦(a, b)⟧ ∈ (s : finset α).sym2} | ||
= {s | G.adj a b ∧ ∃ c, G.adj a c ∧ G.adj b c ∧ s = {a, b, c}}, | ||
{ rintro a b hab, | ||
ext s, | ||
simp only [mem_sym2_iff, sym2.mem_iff, forall_eq_or_imp, forall_eq, set.sep_and, | ||
set.mem_inter_iff, set.mem_sep_iff, mem_clique_set_iff, set.mem_set_of_eq, | ||
and_and_and_comm _ (_ ∈ _), and_self, is_3_clique_iff], | ||
split, | ||
{ rintro ⟨⟨c, d, e, hcd, hce, hde, rfl⟩, hab⟩, | ||
simp only [mem_insert, mem_singleton] at hab, | ||
obtain ⟨rfl | rfl | rfl, rfl | rfl | rfl⟩ := hab; | ||
simp only [*, adj_comm, true_and, ne.def, eq_self_iff_true, not_true] at *; | ||
refine ⟨c, _⟩ <|> refine ⟨d, _⟩ <|> refine ⟨e, _⟩; simp [*, pair_comm, insert_comm] }, | ||
{ rintro ⟨hab, c, hac, hbc, rfl⟩, | ||
refine ⟨⟨a, b, c, _⟩, _⟩; simp [*] } }, | ||
split, | ||
{ rw sym2.forall, | ||
rintro hG a b hab, | ||
simp only [sym2.is_diag_iff_proj_eq] at hab, | ||
rw this _ _ (sym2.mk_is_diag_iff.not.2 hab), | ||
rintro _ ⟨hab, c, hac, hbc, rfl⟩ _ ⟨-, d, had, hbd, rfl⟩, | ||
refine hG.eq _ _ (set.nontrivial.not_subsingleton ⟨a, _, b, _, hab.ne⟩); | ||
simp [is_3_clique_triple_iff, *] }, | ||
{ simp only [edge_disjoint_triangles, is_3_clique_iff, set.pairwise, mem_clique_set_iff, ne.def, | ||
forall_exists_index, and_imp, ←@set.not_nontrivial_iff _ (_ ∩ _), not_imp_not, set.nontrivial, | ||
set.mem_inter_iff, mem_coe], | ||
rintro hG _ a b c hab hac hbc rfl _ d e f hde hdf hef rfl g hg₁ hg₂ h hh₁ hh₂ hgh, | ||
refine hG (sym2.mk_is_diag_iff.not.2 hgh)_ _; simp [is_3_clique_triple_iff, *] } | ||
end | ||
|
||
alias edge_disjoint_triangles_iff_mem_sym2_subsingleton ↔ | ||
edge_disjoint_triangles.mem_sym2_subsingleton _ | ||
|
||
variables [fintype α] [decidable_rel G.adj] | ||
|
||
instance : decidable G.edge_disjoint_triangles := | ||
decidable_of_iff ((G.clique_finset 3 : set (finset α)).pairwise $ λ x y, (x ∩ y).card ≤ 1) $ | ||
by simpa only [coe_clique_finset, edge_disjoint_triangles, finset.card_le_one, ←coe_inter] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be worth extracting as a lemma. |
||
|
||
instance : decidable G.locally_linear := and.decidable | ||
|
||
lemma edge_disjoint_triangles.card_edge_finset_le (hG : G.edge_disjoint_triangles) : | ||
3 * (G.clique_finset 3).card ≤ G.edge_finset.card := | ||
begin | ||
rw [mul_comm, ←mul_one G.edge_finset.card], | ||
refine card_mul_le_card_mul (λ s e, e ∈ s.sym2) _ (λ e he, _), | ||
{ simp only [is_3_clique_iff, mem_clique_finset_iff, mem_sym2_iff, | ||
forall_exists_index, and_imp], | ||
rintro _ a b c hab hac hbc rfl, | ||
have : finset.card ({⟦(a, b)⟧, ⟦(a, c)⟧, ⟦(b, c)⟧} : finset $ sym2 α) = 3, | ||
{ refine card_eq_three.2 ⟨_, _, _, _, _, _, rfl⟩; simp [hab.ne, hac.ne, hbc.ne] }, | ||
rw ←this, | ||
refine card_mono _, | ||
simp [insert_subset, *] }, | ||
{ simpa only [card_le_one, mem_bipartite_below, and_imp, set.subsingleton, set.mem_sep_iff, | ||
mem_clique_finset_iff, mem_clique_set_iff] | ||
using hG.mem_sym2_subsingleton (G.not_is_diag_of_mem_edge_set $ mem_edge_finset.1 he) } | ||
end | ||
|
||
lemma locally_linear.card_edge_finset (hG : G.locally_linear) : | ||
G.edge_finset.card = 3 * (G.clique_finset 3).card := | ||
begin | ||
refine hG.edge_disjoint_triangles.card_edge_finset_le.antisymm' _, | ||
rw [←mul_comm, ←mul_one (finset.card _)], | ||
refine card_mul_le_card_mul (λ e s, e ∈ s.sym2) _ _, | ||
{ simpa [sym2.forall, nat.succ_le_iff, card_pos, finset.nonempty] using hG.2 }, | ||
simp only [mem_clique_finset_iff, is_3_clique_iff, forall_exists_index, and_imp], | ||
rintro _ a b c hab hac hbc rfl, | ||
refine (card_mono _).trans _, | ||
{ exact {⟦(a, b)⟧, ⟦(a, c)⟧, ⟦(b, c)⟧} }, | ||
{ simp only [subset_iff, sym2.forall, mem_sym2_iff, le_eq_subset, mem_bipartite_below, mem_insert, | ||
mem_edge_finset, mem_singleton, and_imp, mem_edge_set, sym2.mem_iff, forall_eq_or_imp, | ||
forall_eq, quotient.eq, sym2.rel_iff], | ||
rintro d e hde (rfl | rfl | rfl) (rfl | rfl | rfl); simp [*] at * }, | ||
{ exact (card_insert_le _ _).trans (succ_le_succ $ (card_insert_le _ _).trans_eq $ | ||
by rw card_singleton) } | ||
end | ||
|
||
end locally_linear | ||
|
||
variables (G ε) [fintype α] [decidable_eq α] [decidable_rel G.adj] [decidable_rel H.adj] | ||
|
||
/-- A simple graph is *`ε`-triangle-free far* if one must remove at least `ε * (card α)^2` edges to | ||
make it triangle-free. -/ | ||
def far_from_triangle_free (G : simple_graph α) (ε : 𝕜) : Prop := | ||
G.delete_far (λ H, H.clique_free 3) $ ε * (card α^2 : ℕ) | ||
def far_from_triangle_free : Prop := G.delete_far (λ H, H.clique_free 3) $ ε * (card α^2 : ℕ) | ||
|
||
variables {G ε} | ||
|
||
lemma far_from_triangle_free_iff : | ||
G.far_from_triangle_free ε ↔ | ||
∀ ⦃H⦄, H ≤ G → H.clique_free 3 → ε * (card α^2 : ℕ) ≤ G.edge_finset.card - H.edge_finset.card := | ||
∀ ⦃H : simple_graph _⦄ [decidable_rel H.adj], by exactI | ||
H ≤ G → H.clique_free 3 → ε * (card α^2 : ℕ) ≤ G.edge_finset.card - H.edge_finset.card := | ||
delete_far_iff | ||
|
||
alias far_from_triangle_free_iff ↔ far_from_triangle_free.le_card_sub_card _ | ||
|
@@ -51,14 +218,87 @@ lemma far_from_triangle_free.mono (hε : G.far_from_triangle_free ε) (h : δ | |
G.far_from_triangle_free δ := | ||
hε.mono $ mul_le_mul_of_nonneg_right h $ cast_nonneg _ | ||
|
||
@[simp] lemma far_from_triangle_free_of_nonpos (hε : ε ≤ 0) : G.far_from_triangle_free ε := | ||
λ H _ _, (mul_nonpos_of_nonpos_of_nonneg hε $ nat.cast_nonneg _).trans $ nat.cast_nonneg _ | ||
|
||
lemma far_from_triangle_free.clique_finset_nonempty' (hH : H ≤ G) (hG : G.far_from_triangle_free ε) | ||
(hcard : (G.edge_finset.card - H.edge_finset.card : 𝕜) < ε * (card α ^ 2 : ℕ)) : | ||
(H.clique_finset 3).nonempty := | ||
nonempty_of_ne_empty $ H.clique_finset_eq_empty_iff.not.2 $ λ hH', | ||
(hG.le_card_sub_card hH hH').not_lt hcard | ||
|
||
private lemma far_from_triangle_free_of_disjoint_triangles_aux {tris : finset (finset α)} | ||
(htris : tris ⊆ G.clique_finset 3) | ||
(pd : (tris : set (finset α)).pairwise (λ x y, (x ∩ y : set α).subsingleton)) (hHG : H ≤ G) | ||
(hH : H.clique_free 3) : tris.card ≤ G.edge_finset.card - H.edge_finset.card := | ||
begin | ||
rw [←card_sdiff (edge_finset_mono hHG), ←card_attach], | ||
by_contra' hG, | ||
have : ∀ ⦃t⦄, t ∈ tris → ∃ x y, x ∈ t ∧ y ∈ t ∧ x ≠ y ∧ ⟦(x, y)⟧ ∈ G.edge_finset \ H.edge_finset, | ||
{ intros t ht, | ||
by_contra' h, | ||
refine hH t _, | ||
simp only [not_and, mem_sdiff, not_not, mem_edge_finset, mem_edge_set] at h, | ||
obtain ⟨x, y, z, xy, xz, yz, rfl⟩ := is_3_clique_iff.1 (G.mem_clique_finset_iff.1 $ htris ht), | ||
rw is_3_clique_triple_iff, | ||
refine ⟨h _ _ _ _ xy.ne xy, h _ _ _ _ xz.ne xz, h _ _ _ _ yz.ne yz⟩; simp }, | ||
choose fx fy hfx hfy hfne fmem using this, | ||
let f : {x // x ∈ tris} → sym2 α := λ t, ⟦(fx t.2, fy t.2)⟧, | ||
have hf : ∀ x, x ∈ tris.attach → f x ∈ G.edge_finset \ H.edge_finset := λ x hx, fmem _, | ||
obtain ⟨⟨t₁, ht₁⟩, -, ⟨t₂, ht₂⟩, -, tne, t : ⟦_⟧ = ⟦_⟧⟩ := | ||
exists_ne_map_eq_of_card_lt_of_maps_to hG hf, | ||
dsimp at t, | ||
have i := pd ht₁ ht₂ (subtype.val_injective.ne tne), | ||
rw sym2.eq_iff at t, | ||
cases t, | ||
{ exact hfne _ (i ⟨hfx ht₁, t.1.symm ▸ hfx ht₂⟩ ⟨hfy ht₁, t.2.symm ▸ hfy ht₂⟩) }, | ||
{ exact hfne _ (i ⟨hfx ht₁, t.1.symm ▸ hfy ht₂⟩ ⟨hfy ht₁, t.2.symm ▸ hfx ht₂⟩) } | ||
end | ||
|
||
/-- If there are `ε * (card α)^2` disjoint triangles, then the graph is `ε`-far from being | ||
triangle-free. -/ | ||
lemma far_from_triangle_free_of_disjoint_triangles (tris : finset (finset α)) | ||
(htris : tris ⊆ G.clique_finset 3) | ||
(pd : (tris : set (finset α)).pairwise (λ x y, (x ∩ y : set α).subsingleton)) | ||
(tris_big : ε * (card α ^ 2 : ℕ) ≤ tris.card) : | ||
G.far_from_triangle_free ε := | ||
begin | ||
rw far_from_triangle_free_iff, | ||
introsI H _ hG hH, | ||
rw ←nat.cast_sub (card_le_of_subset $ edge_finset_mono hG), | ||
exact tris_big.trans | ||
(nat.cast_le.2 $ far_from_triangle_free_of_disjoint_triangles_aux htris pd hG hH), | ||
end | ||
|
||
protected lemma edge_disjoint_triangles.far_from_triangle_free (hG : G.edge_disjoint_triangles) | ||
(tris_big : ε * (card α ^ 2 : ℕ) ≤ (G.clique_finset 3).card) : G.far_from_triangle_free ε := | ||
far_from_triangle_free_of_disjoint_triangles _ subset.rfl (by simpa using hG) tris_big | ||
|
||
variables [nonempty α] | ||
|
||
lemma far_from_triangle_free.lt_half (hG : G.far_from_triangle_free ε) : ε < 2⁻¹ := | ||
begin | ||
by_contra' hε, | ||
have := hG.le_card_sub_card bot_le (clique_free_bot $ by norm_num), | ||
simp only [set.to_finset_card (edge_set ⊥), fintype.card_of_finset, edge_set_bot, cast_zero, | ||
finset.card_empty, tsub_zero] at this, | ||
have hε₀ : 0 < ε := hε.trans_lt' (by norm_num), | ||
rw inv_pos_le_iff_one_le_mul (zero_lt_two' 𝕜) at hε, | ||
refine (this.trans $ le_mul_of_one_le_left (by positivity) hε).not_lt _, | ||
rw [mul_assoc, mul_lt_mul_left hε₀], | ||
norm_cast, | ||
refine (mul_le_mul_left' (card_mono $ edge_finset_mono le_top) _).trans_lt _, | ||
rw [edge_finset_top, filter_not, card_sdiff (subset_univ _), card_univ, sym2.card], | ||
simp_rw [sym2.is_diag_iff_mem_range_diag, univ_filter_mem_range, mul_tsub, | ||
nat.mul_div_cancel' (card α).even_mul_succ_self.two_dvd], | ||
rw [card_image_of_injective _ sym2.diag_injective, card_univ, mul_add_one, two_mul, sq, | ||
add_tsub_add_eq_tsub_right], | ||
exact tsub_lt_self (mul_pos fintype.card_pos fintype.card_pos) fintype.card_pos, | ||
end | ||
|
||
lemma far_from_triangle_free.lt_one (hG : G.far_from_triangle_free ε) : ε < 1 := | ||
hG.lt_half.trans $ by norm_num | ||
|
||
lemma far_from_triangle_free.nonpos (h₀ : G.far_from_triangle_free ε) (h₁ : G.clique_free 3) : | ||
ε ≤ 0 := | ||
begin | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.