Skip to content

Commit 2ee17ff

Browse files
committed
feat(Combinatorics/SimpleGraphs): various path and edge lemmas (#22034)
Adds a number of miscellaneous lemmas, mostly on paths and edges, in preparation for Tutte's theorem. Co-authored-by: Pim Otte <otte.pim@gmail.com>
1 parent cba55ba commit 2ee17ff

File tree

5 files changed

+150
-0
lines changed

5 files changed

+150
-0
lines changed

Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ theorem mem_verts_toSubgraph (p : G.Walk u v) : w ∈ p.toSubgraph.verts ↔ w
145145
by rintro (rfl | h) <;> simp [*], by simp (config := { contextual := true })⟩
146146
simp [ih, or_assoc, this]
147147

148+
lemma not_nil_of_adj_toSubgraph {u v} {x : V} {p : G.Walk u v} (hadj : p.toSubgraph.Adj w x) :
149+
¬p.Nil := by
150+
cases p <;> simp_all
151+
148152
lemma start_mem_verts_toSubgraph (p : G.Walk u v) : u ∈ p.toSubgraph.verts := by
149153
simp [mem_verts_toSubgraph]
150154

@@ -185,6 +189,13 @@ theorem toSubgraph_rotate [DecidableEq V] (c : G.Walk v v) (h : u ∈ c.support)
185189
theorem toSubgraph_map (f : G →g G') (p : G.Walk u v) :
186190
(p.map f).toSubgraph = p.toSubgraph.map f := by induction p <;> simp [*, Subgraph.map_sup]
187191

192+
lemma adj_toSubgraph_mapLe {G' : SimpleGraph V} {w x : V} {p : G.Walk u v} (h : G ≤ G') :
193+
(p.mapLe h).toSubgraph.Adj w x ↔ p.toSubgraph.Adj w x := by
194+
simp only [toSubgraph_map, Subgraph.map_adj]
195+
nth_rewrite 1 [← Hom.mapSpanningSubgraphs_apply h w, ← Hom.mapSpanningSubgraphs_apply h x]
196+
rw [Relation.map_apply_apply (Hom.mapSpanningSubgraphs_injective h)
197+
(Hom.mapSpanningSubgraphs_injective h)]
198+
188199
@[simp]
189200
theorem finite_neighborSet_toSubgraph (p : G.Walk u v) : (p.toSubgraph.neighborSet w).Finite := by
190201
induction p with
@@ -370,6 +381,17 @@ lemma ncard_neighborSet_toSubgraph_eq_two {u v} {p : G.Walk u u} (hpc : p.IsCycl
370381
rw [← hi.1, hpc.neighborSet_toSubgraph_internal he.1 (by omega)]
371382
exact Set.ncard_pair (hpc.getVert_sub_one_neq_getVert_add_one (by omega))
372383

384+
lemma exists_isCycle_snd_verts_eq {p : G.Walk v v} (h : p.IsCycle) (hadj : p.toSubgraph.Adj v w) :
385+
∃ (p' : G.Walk v v), p'.IsCycle ∧ p'.snd = w ∧ p'.toSubgraph.verts = p.toSubgraph.verts := by
386+
have : w ∈ p.toSubgraph.neighborSet v := hadj
387+
rw [h.neighborSet_toSubgraph_endpoint] at this
388+
simp only [Set.mem_insert_iff, Set.mem_singleton_iff] at this
389+
obtain hl | hr := this
390+
· exact ⟨p, ⟨h, hl.symm, rfl⟩⟩
391+
· use p.reverse
392+
rw [penultimate, ← getVert_reverse] at hr
393+
exact ⟨h.reverse, hr.symm, by rw [toSubgraph_reverse _]⟩
394+
373395
end IsCycle
374396

375397
end Walk

Mathlib/Combinatorics/SimpleGraph/Maps.lean

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,13 @@ def mapSpanningSubgraphs {G G' : SimpleGraph V} (h : G ≤ G') : G →g G' where
272272
toFun x := x
273273
map_rel' ha := h ha
274274

275+
lemma mapSpanningSubgraphs_inj {G G' : SimpleGraph V} {v w : V} (h : G ≤ G') :
276+
mapSpanningSubgraphs h v = mapSpanningSubgraphs h w ↔ v = w := by simp
277+
278+
lemma mapSpanningSubgraphs_injective {G G' : SimpleGraph V} (h : G ≤ G') :
279+
Injective (mapSpanningSubgraphs h) :=
280+
fun v w hvw ↦ by simpa [mapSpanningSubgraphs_apply] using hvw
281+
275282
theorem mapEdgeSet.injective (hinj : Function.Injective f) : Function.Injective f.mapEdgeSet := by
276283
rintro ⟨e₁, h₁⟩ ⟨e₂, h₂⟩
277284
dsimp [Hom.mapEdgeSet]

Mathlib/Combinatorics/SimpleGraph/Matching.lean

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Authors: Alena Gusakov, Arthur Paulino, Kyle Miller, Pim Otte
66
import Mathlib.Combinatorics.SimpleGraph.Connectivity.Subgraph
77
import Mathlib.Combinatorics.SimpleGraph.Connectivity.WalkCounting
88
import Mathlib.Combinatorics.SimpleGraph.DegreeSum
9+
import Mathlib.Combinatorics.SimpleGraph.Operations
910
import Mathlib.Data.Fintype.Order
1011
import Mathlib.Data.Set.Functor
1112

@@ -89,6 +90,16 @@ lemma IsMatching.map_ofLE (h : M.IsMatching) (hGG' : G ≤ G') :
8990
use w
9091
simpa using hv' ▸ hw
9192

93+
lemma IsMatching.not_adj_left_of_ne {M : Subgraph G} {u v w : V} (hM : M.IsMatching) (huv : v ≠ w)
94+
(hadj : M.Adj u v) : ¬M.Adj u w := by
95+
intro hadj'
96+
obtain ⟨x, hx⟩ := hM (M.edge_vert hadj)
97+
exact huv (hx.2 _ hadj ▸ (hx.2 _ hadj').symm)
98+
99+
lemma IsMatching.not_adj_right_of_ne {M : Subgraph G} {u v w : V} (hM : M.IsMatching) (huw : u ≠ w)
100+
(hadj : M.Adj u v) : ¬M.Adj w v :=
101+
fun hadj' ↦ hM.not_adj_left_of_ne huw hadj.symm hadj'.symm
102+
92103
lemma IsMatching.sup (hM : M.IsMatching) (hM' : M'.IsMatching)
93104
(hd : Disjoint M.support M'.support) : (M ⊔ M').IsMatching := by
94105
intro v hv
@@ -354,6 +365,35 @@ lemma IsCycles.induce_supp (c : G.ConnectedComponent) (h : G.IsCycles) :
354365
ext w'
355366
simp only [mem_neighborSet, c.adj_spanningCoe_induce_supp, hw, true_and]
356367

368+
lemma Walk.IsCycle.isCycles_spanningCoe_toSubgraph {u : V} {p : G.Walk u u} (hpc : p.IsCycle) :
369+
p.toSubgraph.spanningCoe.IsCycles := by
370+
intro v hv
371+
apply hpc.ncard_neighborSet_toSubgraph_eq_two
372+
obtain ⟨_, hw⟩ := hv
373+
exact p.mem_verts_toSubgraph.mp <| p.toSubgraph.edge_vert hw
374+
375+
lemma Walk.IsPath.isCycles_spanningCoe_toSubgraph_sup_edge {u v} {p : G.Walk u v} (hp : p.IsPath)
376+
(h : u ≠ v) (hs : s(v, u) ∉ p.edges) : (p.toSubgraph.spanningCoe ⊔ edge v u).IsCycles := by
377+
let c := (p.mapLe (OrderTop.le_top G)).cons (by simp [h.symm] : (completeGraph V).Adj v u)
378+
have : p.toSubgraph.spanningCoe ⊔ edge v u = c.toSubgraph.spanningCoe := by
379+
ext w x
380+
simp only [sup_adj, Subgraph.spanningCoe_adj, completeGraph_eq_top, edge_adj, c,
381+
Walk.toSubgraph, Subgraph.sup_adj, subgraphOfAdj_adj, adj_toSubgraph_mapLe]
382+
aesop
383+
exact this ▸ IsCycle.isCycles_spanningCoe_toSubgraph (by simp [Walk.cons_isCycle_iff, c, hp, hs])
384+
385+
lemma Walk.IsCycle.adj_toSubgraph_iff_of_isCycles [LocallyFinite G] {u} {p : G.Walk u u}
386+
(hp : p.IsCycle) (hcyc : G.IsCycles) (hv : v ∈ p.toSubgraph.verts) :
387+
∀ w, p.toSubgraph.Adj v w ↔ G.Adj v w := by
388+
refine fun w ↦ Subgraph.adj_iff_of_neighborSet_equiv (?_ : Inhabited _).default (Set.toFinite _)
389+
apply Classical.inhabited_of_nonempty
390+
rw [← Cardinal.eq, ← Set.cast_ncard (Set.toFinite _),
391+
← Set.cast_ncard (finite_neighborSet_toSubgraph p), hcyc
392+
(Set.Nonempty.mono (p.toSubgraph.neighborSet_subset v) <|
393+
Set.nonempty_of_ncard_ne_zero <| by simp [Set.Nonempty.mono,
394+
hp.ncard_neighborSet_toSubgraph_eq_two (by aesop), Set.nonempty_of_ncard_ne_zero]),
395+
hp.ncard_neighborSet_toSubgraph_eq_two (by aesop)]
396+
357397
open scoped symmDiff
358398

359399
lemma Subgraph.IsPerfectMatching.symmDiff_isCycles
@@ -490,6 +530,35 @@ def IsAlternating (G G' : SimpleGraph V) :=
490530
lemma IsAlternating.mono {G'' : SimpleGraph V} (halt : G.IsAlternating G') (h : G'' ≤ G) :
491531
G''.IsAlternating G' := fun _ _ _ hww' hvw hvw' ↦ halt hww' (h hvw) (h hvw')
492532

533+
lemma IsAlternating.spanningCoe (halt : G.IsAlternating G') (H : Subgraph G) :
534+
H.spanningCoe.IsAlternating G' := by
535+
intro v w w' hww' hvw hvv'
536+
simp only [Subgraph.spanningCoe_adj] at hvw hvv'
537+
exact halt hww' hvw.adj_sub hvv'.adj_sub
538+
539+
lemma IsAlternating.sup_edge {u x : V} (halt : G.IsAlternating G') (hnadj : ¬G'.Adj u x)
540+
(hu' : ∀ u', u' ≠ u → G.Adj x u' → G'.Adj x u')
541+
(hx' : ∀ x', x' ≠ x → G.Adj x' u → G'.Adj x' u) : (G ⊔ edge u x).IsAlternating G' := by
542+
by_cases hadj : G.Adj u x
543+
· rwa [sup_edge_of_adj G hadj]
544+
intro v w w' hww' hvw hvv'
545+
simp only [sup_adj, edge_adj] at hvw hvv'
546+
obtain hl | hr := hvw <;> obtain h1 | h2 := hvv'
547+
· exact halt hww' hl h1
548+
· rw [G'.adj_congr_of_sym2 (by aesop : s(v, w') = s(u, x))]
549+
simp only [hnadj, not_false_eq_true, iff_true]
550+
rcases h2.1 with ⟨h2l1, h2l2⟩ | ⟨h2r1,h2r2⟩
551+
· subst h2l1 h2l2
552+
exact (hx' _ hww' hl.symm).symm
553+
· aesop
554+
· rw [G'.adj_congr_of_sym2 (by aesop : s(v, w) = s(u, x))]
555+
simp only [hnadj, false_iff, not_not]
556+
rcases hr.1 with ⟨hrl1, hrl2⟩ | ⟨hrr1, hrr2⟩
557+
· subst hrl1 hrl2
558+
exact (hx' _ hww'.symm h1.symm).symm
559+
· aesop
560+
· aesop
561+
493562
lemma IsPerfectMatching.symmDiff_of_isAlternating (hM : M.IsPerfectMatching)
494563
(hG' : G'.IsAlternating M.spanningCoe) (hG'cyc : G'.IsCycles) :
495564
(⊤ : Subgraph (M.spanningCoe ∆ G')).IsPerfectMatching := by

Mathlib/Combinatorics/SimpleGraph/Operations.lean

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ def edge : SimpleGraph V := fromEdgeSet {s(s, t)}
148148
lemma edge_adj (v w : V) : (edge s t).Adj v w ↔ (v = s ∧ w = t ∨ v = t ∧ w = s) ∧ v ≠ w := by
149149
rw [edge, fromEdgeSet_adj, Set.mem_singleton_iff, Sym2.eq_iff]
150150

151+
lemma adj_edge {v w : V} : (edge s t).Adj v w ↔ s(s, t) = s(v, w) ∧ v ≠ w := by
152+
simp only [edge_adj, ne_eq, Sym2.eq, Sym2.rel_iff', Prod.mk.injEq, Prod.swap_prod_mk,
153+
and_congr_left_iff]
154+
tauto
155+
151156
lemma edge_comm : edge s t = edge t s := by
152157
rw [edge, edge, Sym2.eq_swap]
153158

@@ -175,6 +180,15 @@ lemma sup_edge_of_adj (h : G.Adj s t) : G ⊔ edge s t = G := by
175180
rwa [sup_eq_left, ← edgeSet_subset_edgeSet, edge_edgeSet_of_ne h.ne, Set.singleton_subset_iff,
176181
mem_edgeSet]
177182

183+
lemma disjoint_edge {u v : V} : Disjoint G (edge u v) ↔ ¬G.Adj u v := by
184+
by_cases h : u = v
185+
· subst h
186+
simp [edge_self_eq_bot]
187+
simp [← disjoint_edgeSet, edge_edgeSet_of_ne h]
188+
189+
lemma sdiff_edge {u v : V} (h : ¬G.Adj u v) : G \ edge u v = G := by
190+
simp [disjoint_edge, h]
191+
178192
theorem Subgraph.spanningCoe_sup_edge_le {H : Subgraph (G ⊔ edge s t)} (h : ¬ H.Adj s t) :
179193
H.spanningCoe ≤ G := by
180194
intro v w hvw

Mathlib/Combinatorics/SimpleGraph/Path.lean

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,44 @@ lemma IsPath.getVert_injOn {p : G.Walk u v} (hp : p.IsPath) :
304304
(by omega : (m - 1) ≤ p.length) hnm
305305
omega
306306

307+
lemma IsPath.getVert_eq_start_iff {i : ℕ} {p : G.Walk u w} (hp : p.IsPath) (hi : i ≤ p.length) :
308+
p.getVert i = u ↔ i = 0 := by
309+
refine ⟨?_, by aesop⟩
310+
intro h
311+
by_cases hi : i = 0
312+
· exact hi
313+
· apply hp.getVert_injOn (by rw [Set.mem_setOf]; omega) (by rw [Set.mem_setOf]; omega)
314+
simp [h]
315+
316+
lemma IsPath.getVert_eq_end_iff {i : ℕ} {p : G.Walk u w} (hp : p.IsPath) (hi : i ≤ p.length) :
317+
p.getVert i = w ↔ i = p.length := by
318+
have := hp.reverse.getVert_eq_start_iff (by omega : p.reverse.length - i ≤ p.reverse.length)
319+
simp only [length_reverse, getVert_reverse,
320+
show p.length - (p.length - i) = i from by omega] at this
321+
rw [this]
322+
omega
323+
324+
lemma IsPath.getVert_injOn_iff (p : G.Walk u v) : Set.InjOn p.getVert {i | i ≤ p.length} ↔
325+
p.IsPath := by
326+
refine ⟨?_, fun a => a.getVert_injOn⟩
327+
induction p with
328+
| nil => simp
329+
| cons h q ih =>
330+
intro hinj
331+
rw [cons_isPath_iff]
332+
refine ⟨ih (by
333+
intro n hn m hm hnm
334+
simp only [Set.mem_setOf_eq] at hn hm
335+
have := hinj (by rw [length_cons]; omega : n + 1 ≤ (q.cons h).length)
336+
(by rw [length_cons]; omega : m + 1 ≤ (q.cons h).length)
337+
(by simpa [getVert_cons] using hnm)
338+
omega), fun h' => ?_⟩
339+
obtain ⟨n, ⟨hn, hnl⟩⟩ := mem_support_iff_exists_getVert.mp h'
340+
have := hinj (by rw [length_cons]; omega : (n + 1) ≤ (q.cons h).length)
341+
(by omega : 0 ≤ (q.cons h).length) (show (q.cons h).getVert (n + 1) = (q.cons h).getVert 0
342+
from by rwa [getVert_cons _ _ (by omega : n + 10), getVert_zero])
343+
omega
344+
307345
/-! ### About cycles -/
308346

309347
-- TODO: These results could possibly be less laborious with a periodic function getCycleVert

0 commit comments

Comments
 (0)