Skip to content
Closed
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8622346
Work in progress
pimotte Feb 19, 2025
e6d8b3e
Prepping PR
pimotte Feb 20, 2025
4adc803
Refactoring
pimotte Feb 20, 2025
d80f82a
Merge remote-tracking branch 'origin/master' into PO_tutte_pt1
pimotte Feb 20, 2025
6552a11
Move off inlined lemma
pimotte Feb 20, 2025
7aeb75d
Refactoring
pimotte Feb 20, 2025
d020260
Polishing
pimotte Feb 20, 2025
730107a
Fixes
pimotte Feb 20, 2025
0097b68
Import order
pimotte Feb 20, 2025
fe630fb
Namespacing
pimotte Feb 20, 2025
7416cbf
Documentation
pimotte Feb 20, 2025
47b698b
Apply suggestions from code review
pimotte Feb 20, 2025
fe83cf9
Post-review patches
pimotte Feb 20, 2025
83c6162
Apply suggestions from code review
pimotte Mar 22, 2025
44b9735
Merge remote-tracking branch 'origin/master' into PO_tutte_pt1
pimotte Mar 22, 2025
58676c7
Patches
pimotte Mar 22, 2025
6d0f1b7
Cosmetic changes
pimotte Mar 22, 2025
b69047e
Apply suggestions from code review
pimotte Mar 31, 2025
bde854c
Fixes
pimotte Mar 31, 2025
dc17aaa
Apply suggestions from code review
pimotte Mar 31, 2025
18fc7d2
Update Mathlib/Combinatorics/SimpleGraph/Tutte.lean
pimotte Mar 31, 2025
782fbc9
Ugly thing
pimotte Mar 31, 2025
4c5ce7e
Unsqueezed simp and other small tweaks
pimotte Mar 31, 2025
a5b612e
golf
YaelDillies Apr 2, 2025
68f755b
Update Mathlib/Combinatorics/SimpleGraph/UniversalVerts.lean
pimotte Apr 3, 2025
0e73fb1
Lint fix
pimotte Apr 3, 2025
d992a7b
Update Mathlib/Combinatorics/SimpleGraph/Tutte.lean
pimotte Apr 18, 2025
b30b3a4
Update Mathlib/Combinatorics/SimpleGraph/Tutte.lean
pimotte Apr 18, 2025
9e03067
golf using `choose`
YaelDillies Apr 18, 2025
dea4153
Fix types
pimotte Apr 30, 2025
8628440
Merge branch 'PO_tutte_pt1' of github.com:leanprover-community/mathli…
pimotte Apr 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Mathlib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -2588,6 +2588,7 @@ import Mathlib.Combinatorics.SimpleGraph.Triangle.Counting
import Mathlib.Combinatorics.SimpleGraph.Triangle.Removal
import Mathlib.Combinatorics.SimpleGraph.Triangle.Tripartite
import Mathlib.Combinatorics.SimpleGraph.Turan
import Mathlib.Combinatorics.SimpleGraph.Tutte
import Mathlib.Combinatorics.SimpleGraph.UniversalVerts
import Mathlib.Combinatorics.SimpleGraph.Walk
import Mathlib.Combinatorics.Young.SemistandardTableau
Expand Down
19 changes: 17 additions & 2 deletions Mathlib/Combinatorics/SimpleGraph/Connectivity/Represents.lean
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Pim Otte
-/

import Mathlib.Combinatorics.SimpleGraph.Path
import Mathlib.Combinatorics.SimpleGraph.Connectivity.WalkCounting
import Mathlib.Data.Set.Card

/-!
Expand Down Expand Up @@ -60,6 +60,9 @@ lemma ncard_inter (hrep : Represents s C) (h : c ∈ C) : (s ∩ c.supp).ncard =
rw [Set.ncard_eq_one]
exact exists_inter_eq_singleton hrep h

lemma ncard_eq (hrep : Represents s C) : s.ncard = C.ncard :=
hrep.image_eq ▸ (Set.ncard_image_of_injOn hrep.injOn).symm

lemma ncard_sdiff_of_mem (hrep : Represents s C) (h : c ∈ C) :
(c.supp \ s).ncard = c.supp.ncard - 1 := by
obtain ⟨a, ha⟩ := exists_inter_eq_singleton hrep h
Expand All @@ -70,4 +73,16 @@ lemma ncard_sdiff_of_not_mem (hrep : Represents s C) (h : c ∉ C) :
(c.supp \ s).ncard = c.supp.ncard := by
rw [(disjoint_supp_of_not_mem hrep h).sdiff_eq_right]

end SimpleGraph.ConnectedComponent.Represents
end ConnectedComponent.Represents

lemma ConnectedComponent.even_ncard_supp_sdiff_rep {s : Set V} (K : G.ConnectedComponent)
(hrep : ConnectedComponent.Represents s G.oddComponents) :
Even (K.supp \ s).ncard := by
by_cases h : Even K.supp.ncard
· simpa [hrep.ncard_sdiff_of_not_mem
(by simpa [Set.ncard_image_of_injective, ← Nat.not_odd_iff_even] using h)] using h
· have : K.supp.ncard ≠ 0 := Nat.ne_of_odd_add (Nat.not_even_iff_odd.mp h)
rw [hrep.ncard_sdiff_of_mem (Nat.not_even_iff_odd.mp h), Nat.even_sub (by omega)]
simpa [Nat.even_sub] using Nat.not_even_iff_odd.mp h

end SimpleGraph
16 changes: 16 additions & 0 deletions Mathlib/Combinatorics/SimpleGraph/Matching.lean
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ Copyright (c) 2020 Alena Gusakov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Alena Gusakov, Arthur Paulino, Kyle Miller, Pim Otte
-/
import Mathlib.Combinatorics.SimpleGraph.Clique
import Mathlib.Combinatorics.SimpleGraph.Connectivity.Subgraph
import Mathlib.Combinatorics.SimpleGraph.Connectivity.WalkCounting
import Mathlib.Combinatorics.SimpleGraph.DegreeSum
import Mathlib.Combinatorics.SimpleGraph.Operations
import Mathlib.Data.Fintype.Order
import Mathlib.Data.Set.Card.Arithmetic
import Mathlib.Data.Set.Functor

/-!
Expand Down Expand Up @@ -260,6 +262,20 @@ lemma IsPerfectMatching.toSubgraph_iff (h : M.spanningCoe ≤ G') :

end Subgraph

lemma IsClique.even_iff_exists_isMatching {u : Set V} (hc : G.IsClique u)
(hu : u.Finite) : Even u.ncard ↔ ∃ (M : Subgraph G), M.verts = u ∧ M.IsMatching := by
refine ⟨fun h ↦ ?_, by
rintro ⟨M, rfl, hMr⟩
simpa [Set.ncard_eq_toFinset_card _ hu, Set.toFinite_toFinset,
← Set.toFinset_card] using @hMr.even_card _ _ _ hu.fintype⟩
obtain ⟨t, u, rfl, hd, hcard⟩ := Set.exists_union_disjoint_ncard_eq_of_even h
obtain ⟨f⟩ : Nonempty (t ≃ u) := by
rw [← Cardinal.eq, ← t.cast_ncard (Set.finite_union.mp hu).1,
← u.cast_ncard (Set.finite_union.mp hu).2]
exact congrArg Nat.cast hcard
exact Subgraph.IsMatching.exists_of_disjoint_sets_of_equiv hd f
fun v ↦ hc (by simp) (by simp) <| hd.ne_of_mem (by simp) (by simp)

namespace ConnectedComponent

section Finite
Expand Down
124 changes: 124 additions & 0 deletions Mathlib/Combinatorics/SimpleGraph/Tutte.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/-
Copyright (c) 2024 Pim Otte. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Pim Otte
-/

import Mathlib.Combinatorics.SimpleGraph.Matching
import Mathlib.Combinatorics.SimpleGraph.Operations
import Mathlib.Combinatorics.SimpleGraph.UniversalVerts
import Mathlib.Data.Fintype.Card

/-!
# Tutte's theorem (work in progress)

## Main definitions
* `SimpleGraph.TutteViolator G u` is a set of vertices `u` which certifies non-existence of a
perfect matching.
-/

namespace SimpleGraph
Comment thread
pimotte marked this conversation as resolved.

universe u
variable {V : Type u} {G G' : SimpleGraph V} {u x v' w : V} [Fintype V]

/-- A set certifying non-existence of a perfect matching. -/
def IsTutteViolator (G : SimpleGraph V) (u : Set V) : Prop :=
u.ncard < ((⊤ : G.Subgraph).deleteVerts u).coe.oddComponents.ncard

/-- Given a graph in which the universal vertices do not violate Tutte's condition,
if the graph decomposes into cliques, there exists a matching that covers
everything except some universal vertices.

This lemma is marked private, because
it is strictly weaker than `IsPerfectMatching.exists_of_isClique_supp` -/
Comment thread
pimotte marked this conversation as resolved.
Outdated
private lemma Subgraph.IsMatching.exists_verts_compl_subset_universalVerts
(h : ¬IsTutteViolator G G.universalVerts)
(h' : ∀ (K : G.deleteUniversalVerts.coe.ConnectedComponent),
G.deleteUniversalVerts.coe.IsClique K.supp) :
∃ M : Subgraph G, M.IsMatching ∧ M.vertsᶜ ⊆ G.universalVerts := by
classical
have hrep := ConnectedComponent.Represents.image_out
G.deleteUniversalVerts.coe.oddComponents
-- First we match one node from each odd component to a universal vertex
obtain ⟨t, ht, M1, hM1⟩ := Subgraph.IsMatching.exists_of_universalVerts
(disjoint_image_val_universalVerts _).symm (by
simp only [IsTutteViolator, not_lt] at h
rwa [Set.ncard_image_of_injective _ Subtype.val_injective, hrep.ncard_eq])
-- Then we match all other nodes in components internally
have compMatching (K : G.deleteUniversalVerts.coe.ConnectedComponent) :
∃ M : Subgraph G, M.verts = Subtype.val '' K.supp \ M1.verts ∧ M.IsMatching := by
have : G.IsClique (Subtype.val '' K.supp \ M1.verts) :=
((h' K).of_induce).subset Set.diff_subset
rw [← this.even_iff_exists_isMatching (Set.toFinite _), hM1.1]
exact even_ncard_image_val_supp_sdiff_image_val_rep_union _ ht hrep
let M2 : Subgraph G := ⨆ (K : G.deleteUniversalVerts.coe.ConnectedComponent),
(compMatching K).choose
have hM2 : M2.IsMatching := by
apply Subgraph.IsMatching.iSup (fun c ↦ (compMatching c).choose_spec.2) (fun i j hij ↦ ?_)
rw [(compMatching i).choose_spec.2.support_eq_verts,
(compMatching j).choose_spec.2.support_eq_verts,
(compMatching i).choose_spec.1, (compMatching j).choose_spec.1]
exact Set.disjoint_of_subset Set.diff_subset Set.diff_subset <|
Set.disjoint_image_of_injective Subtype.val_injective <|
SimpleGraph.pairwise_disjoint_supp_connectedComponent _ hij
Comment thread
pimotte marked this conversation as resolved.
Outdated
have disjointM12 : Disjoint M1.support M2.support := by
rw [hM1.2.support_eq_verts, hM2.support_eq_verts, Subgraph.verts_iSup,
Set.disjoint_iUnion_right]
exact fun K ↦ (compMatching K).choose_spec.1.symm ▸ Set.disjoint_sdiff_right
-- The only vertices left are indeed contained in universalVerts
have : (M1.verts ∪ M2.verts)ᶜ ⊆ G.universalVerts := by
rw [Set.compl_subset_comm, Set.compl_eq_univ_diff]
intro v hv
by_cases h : v ∈ M1.verts
· exact M1.verts.mem_union_left _ h
right
simp only [deleteUniversalVerts_verts, Subgraph.verts_iSup, Set.mem_iUnion, M2,
(compMatching _).choose_spec.1]
use (G.deleteUniversalVerts.coe.connectedComponentMk ⟨v, hv⟩)
aesop
exact ⟨M1 ⊔ M2, hM1.2.sup hM2 disjointM12, this⟩

/-- Given a graph in which the universal vertices do not violate Tutte's condition,
if the graph decomposes into cliques, it has a perfect matching. -/
theorem Subgraph.IsPerfectMatching.exists_of_isClique_supp
(hveven : Even (Fintype.card V)) (h : ¬G.IsTutteViolator G.universalVerts)
(h' : ∀ (K : G.deleteUniversalVerts.coe.ConnectedComponent),
G.deleteUniversalVerts.coe.IsClique K.supp) : ∃ (M : Subgraph G), M.IsPerfectMatching := by
classical
obtain ⟨M, ⟨hM, hsub⟩⟩ := IsMatching.exists_verts_compl_subset_universalVerts h h'
Comment thread
pimotte marked this conversation as resolved.
Outdated
obtain ⟨M', hM'⟩ := ((G.isClique_universalVerts.subset hsub).even_iff_exists_isMatching
(Set.toFinite _)).mp (by simpa [Set.even_ncard_compl_iff hveven, -Set.toFinset_card,
← Set.ncard_eq_toFinset_card'] using hM.even_card)
use M ⊔ M'
have hspan : (M ⊔ M').IsSpanning := by
rw [Subgraph.isSpanning_iff, Subgraph.verts_sup, hM'.1]
exact M.verts.union_compl_self
exact ⟨hM.sup hM'.2 (by
simp only [hM.support_eq_verts, hM'.2.support_eq_verts, hM'.1, Subgraph.verts_sup]
exact (Set.disjoint_compl_left_iff_subset.mpr fun ⦃a⦄ a ↦ a).symm), hspan⟩

theorem IsTutteViolator.empty (hodd : Odd (Fintype.card V)) : G.IsTutteViolator ∅ := by
have c :=
Finite.card_pos_iff.mp
((odd_ncard_oddComponents ((⊤ : Subgraph G).deleteVerts ∅).coe).mpr (by
simpa [Fintype.card_congr (Equiv.Set.univ V)] using hodd)).pos
rw [IsTutteViolator, Set.ncard_empty, Set.ncard_pos]
exact Set.Nonempty.of_subtype

/-- Proves the necessity part of Tutte's theorem -/
lemma not_isTutteViolator_of_isPerfectMatching {M : Subgraph G} (hM : M.IsPerfectMatching)
(u : Set V) :
¬G.IsTutteViolator u := by
simpa [IsTutteViolator, Set.Nat.card_coe_set_eq] using Finite.card_le_of_injective
(fun c => ⟨(ConnectedComponent.odd_matches_node_outside hM c).choose,
(ConnectedComponent.odd_matches_node_outside hM c).choose_spec.1⟩) (by
intro x y hxy
obtain ⟨v, hv⟩ := (ConnectedComponent.odd_matches_node_outside hM x).choose_spec.2
obtain ⟨w, hw⟩ := (ConnectedComponent.odd_matches_node_outside hM y).choose_spec.2
obtain ⟨v', hv'⟩ := Iff.mp (M.isPerfectMatching_iff) hM _
rw [Subtype.mk_eq_mk.mp hxy,
(Subtype.val_injective (hv'.2 _ hw.1.symm ▸ hv'.2 _ hv.1.symm) : v = w)] at hv
exact Subtype.mk_eq_mk.mpr <| ConnectedComponent.eq_of_common_vertex hv.2 hw.2)

end SimpleGraph
21 changes: 21 additions & 0 deletions Mathlib/Combinatorics/SimpleGraph/UniversalVerts.lean
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Pim Otte
-/
import Mathlib.Combinatorics.SimpleGraph.Clique
import Mathlib.Combinatorics.SimpleGraph.Connectivity.Represents
import Mathlib.Combinatorics.SimpleGraph.Matching

/-!
Expand Down Expand Up @@ -51,4 +52,24 @@ lemma Subgraph.IsMatching.exists_of_universalVerts [Finite V] {s : Set V}
have hadj (v : s) : G.Adj v (f v) := ht.1 (f v).2 (hd.ne_of_mem (f v).2 v.2)
exact Subgraph.IsMatching.exists_of_disjoint_sets_of_equiv hd.symm f hadj

lemma disjoint_image_val_universalVerts (s : Set G.deleteUniversalVerts.verts) :
Disjoint (Subtype.val '' s) G.universalVerts := by
simpa [deleteUniversalVerts, Subgraph.deleteVerts_verts, ← Set.disjoint_compl_right_iff_subset,
Set.compl_eq_univ_diff] using Subtype.coe_image_subset _ s
Comment thread
pimotte marked this conversation as resolved.
Outdated

/-- A component of the graph with universal vertices is even if we remove a set of representatives
of odd components and a subset of universal vertices.

This is because the number of vertices in the even components is not affected, and from odd
components exactly one vertex is removed. -/
lemma even_ncard_image_val_supp_sdiff_image_val_rep_union {t : Set V}
{s : Set G.deleteUniversalVerts.verts} (K : G.deleteUniversalVerts.coe.ConnectedComponent)
(h : t ⊆ G.universalVerts)
(hrep : ConnectedComponent.Represents s G.deleteUniversalVerts.coe.oddComponents) :
Even (Subtype.val '' K.supp \ (Subtype.val '' s ∪ t)).ncard := by
simp [-deleteUniversalVerts_verts, ← Set.diff_inter_diff, ← Set.image_diff Subtype.val_injective,
sdiff_eq_left.mpr <| Set.disjoint_of_subset_right h (disjoint_image_val_universalVerts _),
Set.inter_diff_distrib_right, ← Set.image_inter Subtype.val_injective,
Set.ncard_image_of_injective _ Subtype.val_injective, K.even_ncard_supp_sdiff_rep hrep]

end SimpleGraph
10 changes: 10 additions & 0 deletions Mathlib/Data/Set/Card.lean
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,16 @@ theorem eq_univ_iff_ncard [Finite α] (s : Set α) :
s = univ ↔ ncard s = Nat.card α := by
rw [← compl_empty_iff, ← ncard_eq_zero, ← ncard_add_ncard_compl s, left_eq_add]

lemma even_ncard_compl_iff [Fintype α] (heven : Even (Fintype.card α)) (s : Set α) :
Even sᶜ.ncard ↔ Even s.ncard := by
Comment thread
b-mehta marked this conversation as resolved.
Outdated
simp [compl_eq_univ_diff, ncard_diff (subset_univ _ : s ⊆ Set.univ),
Nat.even_sub (ncard_le_ncard (subset_univ _ : s ⊆ Set.univ)),
(ncard_univ _).symm ▸ (Fintype.card_eq_nat_card ▸ heven)]

lemma odd_ncard_compl_iff [Fintype α] (heven : Even (Fintype.card α)) (s : Set α) :
Odd sᶜ.ncard ↔ Odd s.ncard := by
rw [← Nat.not_even_iff_odd, even_ncard_compl_iff heven, Nat.not_even_iff_odd]

end Lattice

/-- Given a subset `s` of a set `t`, of sizes at most and at least `n` respectively, there exists a
Expand Down