Skip to content

Commit d1c754c

Browse files
committed
feat(Combinatorics/SimpleGraph): introduce ConnectedComponent.toSimpleGraph (#22085)
1 parent b84acde commit d1c754c

File tree

3 files changed

+103
-62
lines changed

3 files changed

+103
-62
lines changed

Mathlib/Combinatorics/SimpleGraph/Matching.lean

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,14 +371,16 @@ lemma IsCycles.existsUnique_ne_adj (h : G.IsCycles) (hadj : G.Adj v w) :
371371
simp_rw [← SimpleGraph.mem_neighborSet] at *
372372
aesop
373373

374-
lemma IsCycles.induce_supp (c : G.ConnectedComponent) (h : G.IsCycles) :
375-
(G.induce c.supp).spanningCoe.IsCycles := by
374+
lemma IsCycles.toSimpleGraph (c : G.ConnectedComponent) (h : G.IsCycles) :
375+
c.toSimpleGraph.spanningCoe.IsCycles := by
376376
intro v ⟨w, hw⟩
377-
rw [mem_neighborSet, c.adj_spanningCoe_induce_supp] at hw
377+
rw [mem_neighborSet, c.adj_spanningCoe_toSimpleGraph] at hw
378378
rw [← h ⟨w, hw.2⟩]
379379
congr
380380
ext w'
381-
simp only [mem_neighborSet, c.adj_spanningCoe_induce_supp, hw, true_and]
381+
simp only [mem_neighborSet, c.adj_spanningCoe_toSimpleGraph, hw, true_and]
382+
383+
@[deprecated (since := "2025-06-08")] alias IsCycles.induce_supp := IsCycles.toSimpleGraph
382384

383385
lemma Walk.IsCycle.isCycles_spanningCoe_toSubgraph {u : V} {p : G.Walk u u} (hpc : p.IsCycle) :
384386
p.toSubgraph.spanningCoe.IsCycles := by

Mathlib/Combinatorics/SimpleGraph/Path.lean

Lines changed: 87 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,7 @@ lemma IsPath.getVert_eq_start_iff {i : ℕ} {p : G.Walk u w} (hp : p.IsPath) (hi
328328
lemma IsPath.getVert_eq_end_iff {i : ℕ} {p : G.Walk u w} (hp : p.IsPath) (hi : i ≤ p.length) :
329329
p.getVert i = w ↔ i = p.length := by
330330
have := hp.reverse.getVert_eq_start_iff (by omega : p.reverse.length - i ≤ p.reverse.length)
331-
simp only [length_reverse, getVert_reverse,
332-
show p.length - (p.length - i) = i from by omega] at this
331+
simp only [length_reverse, getVert_reverse, show p.length - (p.length - i) = i by omega] at this
333332
rw [this]
334333
omega
335334

@@ -893,7 +892,6 @@ lemma Reachable.mem_subgraphVerts {u v} {H : G.Subgraph} (hr : G.Reachable u v)
893892
exact aux (H.edge_vert (h _ hv' _ (Walk.adj_snd hnp)).symm) p.tail
894893
termination_by p.length
895894
decreasing_by {
896-
simp_wf
897895
rw [← Walk.length_tail_add_one hnp]
898896
omega
899897
}
@@ -1132,15 +1130,12 @@ theorem map_mk (φ : G →g G') (v : V) :
11321130
rfl
11331131

11341132
@[simp]
1135-
theorem map_id (C : ConnectedComponent G) : C.map Hom.id = C := by
1136-
refine C.ind ?_
1137-
exact fun _ => rfl
1133+
theorem map_id (C : ConnectedComponent G) : C.map Hom.id = C := C.ind (fun _ => rfl)
11381134

11391135
@[simp]
11401136
theorem map_comp (C : G.ConnectedComponent) (φ : G →g G') (ψ : G' →g G'') :
1141-
(C.map φ).map ψ = C.map (ψ.comp φ) := by
1142-
refine C.ind ?_
1143-
exact fun _ => rfl
1137+
(C.map φ).map ψ = C.map (ψ.comp φ) :=
1138+
C.ind (fun _ => rfl)
11441139

11451140
variable {φ : G ≃g G'} {v : V} {v' : V'}
11461141

@@ -1167,10 +1162,8 @@ namespace Iso
11671162
def connectedComponentEquiv (φ : G ≃g G') : G.ConnectedComponent ≃ G'.ConnectedComponent where
11681163
toFun := ConnectedComponent.map φ
11691164
invFun := ConnectedComponent.map φ.symm
1170-
left_inv C := ConnectedComponent.ind
1171-
(fun v => congr_arg G.connectedComponentMk (Equiv.left_inv φ.toEquiv v)) C
1172-
right_inv C := ConnectedComponent.ind
1173-
(fun v => congr_arg G'.connectedComponentMk (Equiv.right_inv φ.toEquiv v)) C
1165+
left_inv C := C.ind (fun v => congr_arg G.connectedComponentMk (Equiv.left_inv φ.toEquiv v))
1166+
right_inv C := C.ind (fun v => congr_arg G'.connectedComponentMk (Equiv.right_inv φ.toEquiv v))
11741167

11751168
@[simp]
11761169
theorem connectedComponentEquiv_refl :
@@ -1203,9 +1196,8 @@ def supp (C : G.ConnectedComponent) :=
12031196
theorem supp_injective :
12041197
Function.Injective (ConnectedComponent.supp : G.ConnectedComponent → Set V) := by
12051198
refine ConnectedComponent.ind₂ ?_
1206-
intro v w
12071199
simp only [ConnectedComponent.supp, Set.ext_iff, ConnectedComponent.eq, Set.mem_setOf_eq]
1208-
intro h
1200+
intro v w h
12091201
rw [reachable_comm, h]
12101202

12111203
@[simp]
@@ -1228,15 +1220,6 @@ lemma mem_supp_congr_adj {v w : V} (c : G.ConnectedComponent) (hadj : G.Adj v w)
12281220
· exact hadj.symm
12291221
· exact hadj
12301222

1231-
lemma adj_spanningCoe_induce_supp {v w : V} (c : G.ConnectedComponent) :
1232-
(G.induce c.supp).spanningCoe.Adj v w ↔ v ∈ c.supp ∧ G.Adj v w := by
1233-
by_cases h : v ∈ c.supp
1234-
· refine ⟨by aesop, ?_⟩
1235-
intro h'
1236-
have : w ∈ c.supp := by rwa [c.mem_supp_congr_adj h'.2] at h
1237-
aesop
1238-
· aesop
1239-
12401223
theorem connectedComponentMk_mem {v : V} : v ∈ G.connectedComponentMk v :=
12411224
rfl
12421225

@@ -1263,8 +1246,7 @@ lemma mem_coe_supp_of_adj {v w : V} {H : Subgraph G} {c : ConnectedComponent H.c
12631246
lemma eq_of_common_vertex {v : V} {c c' : ConnectedComponent G} (hc : v ∈ c.supp)
12641247
(hc' : v ∈ c'.supp) : c = c' := by
12651248
simp only [mem_supp_iff] at *
1266-
subst hc hc'
1267-
rfl
1249+
rw [← hc, ← hc']
12681250

12691251
lemma connectedComponentMk_supp_subset_supp {G'} {v : V} (h : G ≤ G') (c' : G'.ConnectedComponent)
12701252
(hc' : v ∈ c'.supp) : (G.connectedComponentMk v).supp ⊆ c'.supp := by
@@ -1288,28 +1270,84 @@ lemma top_supp_eq_univ (c : ConnectedComponent (⊤ : SimpleGraph V)) :
12881270
have ⟨w, hw⟩ := c.exists_rep
12891271
ext v
12901272
simp only [Set.mem_univ, iff_true, mem_supp_iff, ← hw]
1291-
apply SimpleGraph.ConnectedComponent.sound
1292-
exact (@SimpleGraph.top_connected V (Nonempty.intro v)).preconnected v w
1273+
apply ConnectedComponent.sound
1274+
exact (@top_connected V (Nonempty.intro v)).preconnected v w
1275+
1276+
lemma reachable_of_mem_supp {G : SimpleGraph V} (C : G.ConnectedComponent) {u v : V}
1277+
(hu : u ∈ C.supp) (hv : v ∈ C.supp) : G.Reachable u v := by
1278+
rw [mem_supp_iff] at hu hv
1279+
exact ConnectedComponent.exact (hv ▸ hu)
1280+
1281+
lemma mem_supp_of_adj_mem_supp {G : SimpleGraph V} (C : G.ConnectedComponent) {u v : V}
1282+
(hu : u ∈ C.supp) (hadj : G.Adj u v) : v ∈ C.supp := by
1283+
have hC : G.connectedComponentMk u = G.connectedComponentMk v :=
1284+
connectedComponentMk_eq_of_adj hadj
1285+
rw [hu] at hC
1286+
exact hC.symm
1287+
1288+
/--
1289+
Given a connected component `C` of a simple graph `G`, produce the induced graph on `C`.
1290+
The declaration `connected_toSimpleGraph` shows it is connected, and `toSimpleGraph_hom`
1291+
provides the homomorphism back to `G`.
1292+
-/
1293+
def toSimpleGraph {G : SimpleGraph V} (C : G.ConnectedComponent) : SimpleGraph C := G.induce C.supp
12931294

1294-
lemma reachable_induce_supp {v w} {c : ConnectedComponent G} (hv : v ∈ c.supp) (hw : w ∈ c.supp)
1295-
(p : G.Walk v w) : (G.induce c.supp).Reachable ⟨v, hv⟩ ⟨w, hw⟩ := by
1296-
induction p with
1297-
| nil => rfl
1298-
| @cons u v w h p ih =>
1299-
have : v ∈ c.supp := (c.mem_supp_congr_adj h).mp hv
1300-
obtain ⟨q⟩ := ih this hw
1301-
have hadj : (G.induce c.supp).Adj ⟨u, hv⟩ ⟨v, this⟩ := h
1302-
use q.cons hadj
1303-
1304-
lemma connected_induce_supp (c : ConnectedComponent G) : (G.induce c.supp).Connected := by
1305-
rw [connected_iff_exists_forall_reachable]
1306-
use ⟨c.out, c.out_eq⟩
1307-
intro w
1308-
have hwc := (c.mem_supp_iff w).mp (Subtype.coe_prop w)
1309-
obtain ⟨p⟩ := ConnectedComponent.exact
1310-
(show G.connectedComponentMk c.out = G.connectedComponentMk w by
1311-
simp [← hwc, connectedComponentMk])
1312-
exact c.reachable_induce_supp c.out_eq hwc p
1295+
/-- Homomorphism from a connected component graph to the original graph. -/
1296+
def toSimpleGraph_hom {G : SimpleGraph V} (C : G.ConnectedComponent) : C.toSimpleGraph →g G where
1297+
toFun u := u.val
1298+
map_rel' := id
1299+
1300+
lemma toSimpleGraph_hom_apply {G : SimpleGraph V} (C : G.ConnectedComponent) (u : C) :
1301+
C.toSimpleGraph_hom u = u.val := rfl
1302+
1303+
lemma toSimpleGraph_adj {G : SimpleGraph V} (C : G.ConnectedComponent) {u v : V} (hu : u ∈ C)
1304+
(hv : v ∈ C) : C.toSimpleGraph.Adj ⟨u, hu⟩ ⟨v, hv⟩ ↔ G.Adj u v := by
1305+
simp [toSimpleGraph]
1306+
1307+
lemma adj_spanningCoe_toSimpleGraph {v w : V} (C : G.ConnectedComponent) :
1308+
C.toSimpleGraph.spanningCoe.Adj v w ↔ v ∈ C.supp ∧ G.Adj v w := by
1309+
apply Iff.intro
1310+
· intro h
1311+
simp_all only [map_adj, SetLike.coe_sort_coe, Subtype.exists, mem_supp_iff]
1312+
obtain ⟨_, a, _, _, h₁, h₂, h₃⟩ := h
1313+
subst h₂ h₃
1314+
exact ⟨a, h₁⟩
1315+
· simp only [toSimpleGraph, map_adj, comap_adj, Embedding.subtype_apply, Subtype.exists,
1316+
exists_and_left, and_imp]
1317+
intro h hadj
1318+
exact ⟨v, h, w, hadj, rfl, (C.mem_supp_congr_adj hadj).mp h, rfl⟩
1319+
1320+
@[deprecated (since := "2025-05-08")]
1321+
alias adj_spanningCoe_induce_supp := adj_spanningCoe_toSimpleGraph
1322+
1323+
/-- Get the walk between two vertices in a connected component from a walk in the original graph. -/
1324+
private def walk_toSimpleGraph' {G : SimpleGraph V} (C : G.ConnectedComponent) {u v : V}
1325+
(hu : u ∈ C) (hv : v ∈ C) (p : G.Walk u v) : C.toSimpleGraph.Walk ⟨u, hu⟩ ⟨v, hv⟩ := by
1326+
cases p with
1327+
| nil => exact Walk.nil
1328+
| @cons v w u h p =>
1329+
have hw : w ∈ C := C.mem_supp_of_adj_mem_supp hu h
1330+
have h' : C.toSimpleGraph.Adj ⟨u, hu⟩ ⟨w, hw⟩ := h
1331+
exact Walk.cons h' (C.walk_toSimpleGraph' hw hv p)
1332+
1333+
@[deprecated (since := "2025-05-08")] alias reachable_induce_supp := walk_toSimpleGraph'
1334+
1335+
/-- There is a walk between every pair of vertices in a connected component. -/
1336+
noncomputable def walk_toSimpleGraph {G : SimpleGraph V} (C : G.ConnectedComponent) {u v : V}
1337+
(hu : u ∈ C) (hv : v ∈ C) : C.toSimpleGraph.Walk ⟨u, hu⟩ ⟨v, hv⟩ :=
1338+
C.walk_toSimpleGraph' hu hv (C.reachable_of_mem_supp hu hv).some
1339+
1340+
lemma reachable_toSimpleGraph {G : SimpleGraph V} (C : G.ConnectedComponent) {u v : V}
1341+
(hu : u ∈ C) (hv : v ∈ C) : C.toSimpleGraph.Reachable ⟨u, hu⟩ ⟨v, hv⟩ :=
1342+
Walk.reachable (C.walk_toSimpleGraph hu hv)
1343+
1344+
lemma connected_toSimpleGraph (C : ConnectedComponent G) : (C.toSimpleGraph).Connected where
1345+
preconnected := by
1346+
intro ⟨u, hu⟩ ⟨v, hv⟩
1347+
exact C.reachable_toSimpleGraph hu hv
1348+
nonempty := ⟨C.out, C.out_eq⟩
1349+
1350+
@[deprecated (since := "2025-05-08")] alias connected_induce_supp := connected_toSimpleGraph
13131351

13141352
end ConnectedComponent
13151353

@@ -1327,7 +1365,7 @@ lemma iUnion_connectedComponentSupp (G : SimpleGraph V) :
13271365
⋃ c : G.ConnectedComponent, c.supp = Set.univ := by
13281366
refine Set.eq_univ_of_forall fun v ↦ ⟨G.connectedComponentMk v, ?_⟩
13291367
simp only [Set.mem_range, SetLike.mem_coe]
1330-
exact ⟨by use G.connectedComponentMk v; exact rfl, rfl⟩
1368+
exact ⟨G.connectedComponentMk v, rfl, rfl⟩
13311369

13321370
theorem Preconnected.set_univ_walk_nonempty (hconn : G.Preconnected) (u v : V) :
13331371
(Set.univ : Set (G.Walk u v)).Nonempty := by
@@ -1361,8 +1399,7 @@ theorem reachable_delete_edges_iff_exists_walk {v w v' w' : V} :
13611399
simpa using p.edges_subset_edgeSet h
13621400
· rintro ⟨p, h⟩
13631401
refine ⟨p.transfer _ fun e ep => ?_⟩
1364-
simp only [edgeSet_sdiff, edgeSet_fromEdgeSet, edgeSet_sdiff_sdiff_isDiag, Set.mem_diff,
1365-
Set.mem_singleton_iff]
1402+
simp only [edgeSet_sdiff, edgeSet_fromEdgeSet, edgeSet_sdiff_sdiff_isDiag]
13661403
exact ⟨p.edges_subset_edgeSet ep, fun h' => h (h' ▸ ep)⟩
13671404

13681405
theorem isBridge_iff_adj_and_forall_walk_mem_edges {v w : V} :

Mathlib/Combinatorics/SimpleGraph/Tutte.lean

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -187,21 +187,22 @@ private theorem tutte_exists_isPerfectMatching_of_near_matchings {x a b c : V}
187187
have hM1sub := Subgraph.spanningCoe_le M1
188188
have hM2sub := Subgraph.spanningCoe_le M2
189189
-- We consider the cycle that contains the vertex `c`
190-
have induce_le : (induce (cycles.connectedComponentMk c).supp cycles).spanningCoe ≤
190+
have induce_le : ((cycles.connectedComponentMk c).toSimpleGraph).spanningCoe ≤
191191
(G ⊔ edge a c) ⊔ edge x b := by
192192
refine le_trans (spanningCoe_induce_le cycles (cycles.connectedComponentMk c).supp) ?_
193193
simp only [← hsupG, cycles]
194194
exact le_trans (by apply symmDiff_le_sup) (sup_le_sup hM1sub hM2sub)
195195
-- If that cycle does not contain the vertex `x`, we use it as an alternating cycle
196196
by_cases hxc : x ∉ (cycles.connectedComponentMk c).supp
197-
· use (cycles.induce (cycles.connectedComponentMk c).supp).spanningCoe
197+
· use (cycles.connectedComponentMk c).toSimpleGraph.spanningCoe
198198
refine ⟨hcalt.mono (spanningCoe_induce_le cycles (cycles.connectedComponentMk c).supp), ?_⟩
199-
simp only [ConnectedComponent.adj_spanningCoe_induce_supp, hxc, hcac, false_and,
199+
simp only [ConnectedComponent.adj_spanningCoe_toSimpleGraph, hxc, hcac, false_and,
200200
not_false_eq_true, ConnectedComponent.mem_supp_iff, ConnectedComponent.eq, and_true,
201201
true_and, hcac.reachable]
202-
refine ⟨hcycles.induce_supp (cycles.connectedComponentMk c),
202+
refine ⟨hcycles.toSimpleGraph (cycles.connectedComponentMk c),
203203
Disjoint.left_le_of_le_sup_right induce_le ?_⟩
204204
rw [disjoint_edge]
205+
rw [ConnectedComponent.adj_spanningCoe_toSimpleGraph]
205206
aesop
206207
push_neg at hxc
207208
have hacc := ((cycles.connectedComponentMk c).mem_supp_congr_adj hcac.symm).mp rfl
@@ -289,12 +290,13 @@ lemma exists_isTutteViolator (h : ∀ (M : G.Subgraph), ¬M.IsPerfectMatching)
289290
push_neg at h'
290291
obtain ⟨K, hK⟩ := h'
291292
obtain ⟨x, y, hxy⟩ := (not_isClique_iff _).mp hK
292-
obtain ⟨p , hp⟩ := Reachable.exists_path_of_dist (K.connected_induce_supp x y)
293+
obtain ⟨p , hp⟩ := Reachable.exists_path_of_dist (K.connected_toSimpleGraph x y)
293294
obtain ⟨x, a, b, hxa, hxb, hnadjxb, hnxb⟩ := Walk.exists_adj_adj_not_adj_ne hp.2
294295
(p.reachable.one_lt_dist_of_ne_of_not_adj hxy.1 hxy.2)
295-
simp only [deleteUniversalVerts, universalVerts, ne_eq, Subgraph.induce_verts,
296-
Subgraph.verts_top, comap_adj, Function.Embedding.coe_subtype, Subgraph.coe_adj,
297-
Subgraph.induce_adj, Subtype.coe_prop, Subgraph.top_adj, true_and] at hxa hxb hnadjxb
296+
simp only [ConnectedComponent.toSimpleGraph, deleteUniversalVerts, universalVerts, ne_eq,
297+
Subgraph.induce_verts, Subgraph.verts_top, comap_adj, Function.Embedding.coe_subtype,
298+
Subgraph.coe_adj, Subgraph.induce_adj, Subtype.coe_prop, Subgraph.top_adj, true_and
299+
] at hxa hxb hnadjxb
298300
obtain ⟨c, hc⟩ : ∃ (c : V), (a : V) ≠ c ∧ ¬ Gmax.Adj c a := by
299301
simpa [universalVerts] using a.1.2.2
300302
have hbnec : b.val.val ≠ c := by rintro rfl; exact hc.2 hxb.symm

0 commit comments

Comments
 (0)