Skip to content

Commit 4e83c73

Browse files
committed
refactor(Combinatorics/SimpleGraph): use edge and deleteEdges more (#36804)
Alternatively, we should make them `abbrev`s.
1 parent 31138aa commit 4e83c73

File tree

5 files changed

+78
-38
lines changed

5 files changed

+78
-38
lines changed

Mathlib/Combinatorics/SimpleGraph/Acyclic.lean

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -366,30 +366,33 @@ lemma isTree_iff_minimal_connected : IsTree G ↔ Minimal Connected G := by
366366
simp [this, p.adj_of_mem_edges]
367367

368368
/-- Connecting two unreachable vertices by an edge preserves acyclicity. -/
369-
theorem IsAcyclic.isAcyclic_sup_fromEdgeSet_of_not_reachable {u v : V} (hnreach : ¬G.Reachable u v)
370-
(hacyc : G.IsAcyclic) : (G ⊔ fromEdgeSet {s(u, v)}).IsAcyclic := by
371-
grind [isAcyclic_iff_forall_edge_isBridge, IsBridge.sup_fromEdgeSet_of_not_reachable,
372-
edgeSet_sup, IsBridge.sup_fromEdgeSet_of_not_reachable_of_isBridge, edgeSet_fromEdgeSet]
369+
theorem IsAcyclic.sup_edge_of_not_reachable {u v : V} (hnreach : ¬G.Reachable u v)
370+
(hacyc : G.IsAcyclic) : (G ⊔ edge u v).IsAcyclic := by
371+
grind [isAcyclic_iff_forall_edge_isBridge, IsBridge.sup_edge_of_not_reachable,
372+
IsBridge.sup_edge_of_not_reachable_of_isBridge,
373+
edgeSet_sup, edgeSet_edge, IsBridge.of_not_reachable]
374+
375+
@[deprecated (since := "2026-03-18")]
376+
alias IsAcyclic.isAcyclic_sup_fromEdgeSet_of_not_reachable := IsAcyclic.sup_edge_of_not_reachable
373377

374378
theorem isAcyclic_add_edge_iff_of_not_reachable (x y : V) (hxy : ¬ G.Reachable x y) :
375-
(G ⊔ fromEdgeSet {s(x, y)}).IsAcyclic ↔ IsAcyclic G :=
376-
⟨.anti le_sup_left, .isAcyclic_sup_fromEdgeSet_of_not_reachable hxy⟩
379+
(G ⊔ edge x y).IsAcyclic ↔ IsAcyclic G :=
380+
⟨.anti le_sup_left, .sup_edge_of_not_reachable hxy⟩
377381

378382
/-- Adding an edge results in an acyclic graph iff the original graph was acyclic and
379383
the edge connects vertices that previously had no path between them. -/
380384
theorem isAcyclic_sup_fromEdgeSet_iff {u v : V} :
381-
(G ⊔ fromEdgeSet {s(u, v)}).IsAcyclic ↔
385+
(G ⊔ edge u v).IsAcyclic ↔
382386
G.IsAcyclic ∧ (G.Reachable u v → u = v ∨ G.Adj u v) := by
383387
by_cases huv : u = v
384-
· grind [sup_eq_left, fromEdgeSet_le, Sym2.mem_diagSet, Sym2.mk_isDiag_iff]
388+
· grind [sup_eq_left, edge_le, Sym2.mem_diagSet, Sym2.mk_isDiag_iff]
385389
by_cases hadj : G.Adj u v
386-
· grind [sup_eq_left, fromEdgeSet_le, mem_edgeSet]
387-
refine ⟨?_, fun ⟨hacyc, hreach⟩ ↦ hacyc.isAcyclic_sup_fromEdgeSet_of_not_reachable <| by grind⟩
390+
· grind [sup_eq_left, edge_le, mem_edgeSet]
391+
refine ⟨?_, fun ⟨hacyc, hreach⟩ ↦ hacyc.sup_edge_of_not_reachable <| by grind⟩
388392
refine fun hacyc ↦ ⟨hacyc.anti le_sup_left, fun hreach ↦ False.elim ?_⟩
389-
have := isAcyclic_iff_forall_edge_isBridge.mp (e := s(u, v)) hacyc <| by simp [huv]
390-
refine isBridge_iff.mp this |>.right <| hreach.mono <| Eq.le <| Eq.symm ?_
391-
rw [sup_sdiff_right_self]
392-
exact deleteEdges_eq_self.mpr <| Set.disjoint_singleton_right.mpr hadj
393+
refine (isAcyclic_iff_forall_edge_isBridge.mp (e := s(u, v)) hacyc <| by simp [huv]).right ?_
394+
convert hreach
395+
simpa [deleteEdges_sup]
393396

394397
/--
395398
The reachability relation of a maximal acyclic subgraph agrees with that of the larger graph.
@@ -404,10 +407,10 @@ lemma reachable_eq_of_maximal_isAcyclic (F : SimpleGraph V)
404407
have : ∃ d ∈ p.darts, d.fst ∈ s ∧ d.snd ∉ s := p.exists_boundary_dart s rfl this
405408
rcases this with ⟨⟨⟨u', v'⟩, huv⟩, _, hu, hv⟩
406409
have : ¬F.Reachable v' u' := mt ConnectedComponent.sound <| s.mem_supp_iff u' |>.mp hu ▸ hv
407-
suffices F ⊔ fromEdgeSet {s(v', u')} ≤ F by
408-
grind [Adj.reachable, sup_le_iff, le_iff_adj, fromEdgeSet_adj]
409-
refine h.le_of_ge ⟨?_, h.prop.right.isAcyclic_sup_fromEdgeSet_of_not_reachable this⟩ le_sup_left
410-
grind [Maximal, sup_le, le_iff_adj, fromEdgeSet_adj, huv.symm]
410+
suffices F ⊔ edge v' u' ≤ F by
411+
grind [Adj.reachable, sup_le_iff, le_iff_adj, edge_adj]
412+
refine h.le_of_ge ⟨?_, h.prop.right.sup_edge_of_not_reachable this⟩ le_sup_left
413+
grind [Maximal, sup_le, le_iff_adj, edge_adj, huv.symm]
411414

412415
/-- A subgraph is maximal acyclic iff its reachability relation agrees with the larger graph. -/
413416
theorem maximal_isAcyclic_iff_reachable_eq {F : SimpleGraph V} (hle : F ≤ G) (hF : F.IsAcyclic) :
@@ -419,7 +422,7 @@ theorem maximal_isAcyclic_iff_reachable_eq {F : SimpleGraph V} (hle : F ≤ G) (
419422
have h_bridge : (F ⊔ fromEdgeSet {e}).IsBridge e := by
420423
refine isAcyclic_iff_forall_edge_isBridge.mp ?_ <| by simp [H.not_isDiag_of_mem_edgeSet heH]
421424
exact hH.anti <| sup_le_iff.mpr ⟨hFH.le, H.fromEdgeSet_le.mpr <| by grind⟩
422-
have : (F ⊔ fromEdgeSet {e}) \ fromEdgeSet {e} = F := by simpa using heF
425+
have : (F ⊔ fromEdgeSet {e}).deleteEdges {e} = F := by simpa using heF
423426
cases e
424427
rw [isBridge_iff, this, h] at h_bridge
425428
exact h_bridge.right <| hHG heH |>.reachable

Mathlib/Combinatorics/SimpleGraph/Basic.lean

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,9 @@ theorem fromEdgeSet_edgeSet : fromEdgeSet G.edgeSet = G := by
619619
ext v w
620620
exact ⟨fun h => h.1, fun h => ⟨h, G.ne_of_adj h⟩⟩
621621

622+
@[simp] lemma le_fromEdgeSet_iff : G ≤ fromEdgeSet s ↔ G.edgeSet ⊆ s := by
623+
simp [← edgeSet_subset_edgeSet, Set.subset_def]; grind [not_isDiag_of_mem_edgeSet]
624+
622625
@[simp] lemma fromEdgeSet_le {s : Set (Sym2 V)} :
623626
fromEdgeSet s ≤ G ↔ s \ Sym2.diagSet ⊆ G.edgeSet := by simp [← edgeSet_subset_edgeSet]
624627

@@ -659,7 +662,7 @@ theorem fromEdgeSet_sdiff (s t : Set (Sym2 V)) :
659662

660663
@[gcongr, mono]
661664
theorem fromEdgeSet_mono {s t : Set (Sym2 V)} (h : s ⊆ t) : fromEdgeSet s ≤ fromEdgeSet t := by
662-
simpa using Set.diff_subset_diff h fun _ a ↦ a
665+
simp only [le_fromEdgeSet_iff, edgeSet_fromEdgeSet]; grw [h]; exact sdiff_le
663666

664667
@[simp] lemma disjoint_fromEdgeSet : Disjoint G (fromEdgeSet s) ↔ Disjoint G.edgeSet s := by
665668
conv_rhs => rw [← Set.diff_union_inter s Sym2.diagSet]

Mathlib/Combinatorics/SimpleGraph/Connectivity/Connected.lean

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module
77

88
public import Mathlib.Combinatorics.SimpleGraph.Paths
99
public import Mathlib.Combinatorics.SimpleGraph.Subgraph
10+
public import Mathlib.Combinatorics.SimpleGraph.Operations
1011

1112
/-!
1213
## Main definitions
@@ -740,19 +741,23 @@ lemma Preconnected.exists_adj_of_nontrivial [Nontrivial V] {G : SimpleGraph V} (
740741
/-! ### Bridge edges -/
741742

742743
section BridgeEdges
744+
variable {u v : V}
743745

744746
/-- An edge of a graph is a *bridge* if, after removing it, its incident vertices
745747
are no longer reachable from one another. -/
746748
def IsBridge (G : SimpleGraph V) (e : Sym2 V) : Prop :=
747749
e ∈ G.edgeSet ∧
748-
Sym2.lift ⟨fun v w => ¬(G \ fromEdgeSet {e}).Reachable v w, by simp [reachable_comm]⟩ e
750+
Sym2.lift ⟨fun v w => ¬(G.deleteEdges {e}).Reachable v w, by simp [reachable_comm]⟩ e
749751

750752
theorem isBridge_iff {u v : V} :
751-
G.IsBridge s(u, v) ↔ G.Adj u v ∧ ¬(G \ fromEdgeSet {s(u, v)}).Reachable u v := Iff.rfl
753+
G.IsBridge s(u, v) ↔ G.Adj u v ∧ ¬(G.deleteEdges {s(u, v)}).Reachable u v := Iff.rfl
754+
755+
@[simp] lemma IsBridge.of_not_reachable (huv : ¬ G.Reachable u v) (h : G.Adj u v) :
756+
G.IsBridge s(u, v) := ⟨h, fun h ↦ huv <| h.mono <| deleteEdges_le _⟩
752757

753758
set_option backward.isDefEq.respectTransparency false in
754-
theorem reachable_delete_edges_iff_exists_walk {v w v' w' : V} :
755-
(G \ fromEdgeSet {s(v, w)}).Reachable v' w' ↔ ∃ p : G.Walk v' w', s(v, w) ∉ p.edges := by
759+
theorem reachable_deleteEdges_iff_exists_walk {v w v' w' : V} :
760+
(G.deleteEdges {s(v, w)}).Reachable v' w' ↔ ∃ p : G.Walk v' w', s(v, w) ∉ p.edges := by
756761
constructor
757762
· rintro ⟨p⟩
758763
use p.map (.ofLE (by simp))
@@ -761,13 +766,16 @@ theorem reachable_delete_edges_iff_exists_walk {v w v' w' : V} :
761766
simpa using p.edges_subset_edgeSet h
762767
· rintro ⟨p, h⟩
763768
refine ⟨p.transfer _ fun e ep => ?_⟩
764-
simp only [edgeSet_sdiff, edgeSet_fromEdgeSet, edgeSet_sdiff_sdiff_isDiag]
769+
rw [edgeSet_deleteEdges]
765770
exact ⟨p.edges_subset_edgeSet ep, fun h' => h (h' ▸ ep)⟩
766771

772+
@[deprecated (since := "2026-03-18")]
773+
alias reachable_delete_edges_iff_exists_walk := reachable_deleteEdges_iff_exists_walk
774+
767775
theorem isBridge_iff_adj_and_forall_walk_mem_edges {v w : V} :
768776
G.IsBridge s(v, w) ↔ G.Adj v w ∧ ∀ p : G.Walk v w, s(v, w) ∈ p.edges := by
769777
rw [isBridge_iff, and_congr_right']
770-
rw [reachable_delete_edges_iff_exists_walk, not_exists_not]
778+
rw [reachable_deleteEdges_iff_exists_walk, not_exists_not]
771779

772780
theorem reachable_deleteEdges_iff_exists_cycle.aux [DecidableEq V] {u v w : V}
773781
(hb : ∀ p : G.Walk v w, s(v, w) ∈ p.edges) (c : G.Walk u u) (hc : c.IsTrail)
@@ -796,10 +804,10 @@ theorem reachable_deleteEdges_iff_exists_cycle.aux [DecidableEq V] {u v w : V}
796804
exact List.disjoint_of_nodup_append hc hbq hpq'
797805

798806
theorem adj_and_reachable_delete_edges_iff_exists_cycle {v w : V} :
799-
G.Adj v w ∧ (G \ fromEdgeSet {s(v, w)}).Reachable v w ↔
807+
G.Adj v w ∧ (G.deleteEdges {s(v, w)}).Reachable v w ↔
800808
∃ (u : V) (p : G.Walk u u), p.IsCycle ∧ s(v, w) ∈ p.edges := by
801809
classical
802-
rw [reachable_delete_edges_iff_exists_walk]
810+
rw [reachable_deleteEdges_iff_exists_walk]
803811
constructor
804812
· rintro ⟨h, p, hp⟩
805813
refine ⟨w, Walk.cons h.symm p.toPath, ?_, ?_⟩
@@ -856,20 +864,27 @@ theorem IsBridge.anti_of_mem_edgeSet {G' : SimpleGraph V} {e : Sym2 V} (hle : G
856864
(p.mapLe hle) (Walk.IsCycle.mapLe hle hp) (p.edges_mapLe_eq_edges hle ▸ hpe)⟩
857865

858866
/-- Connecting two unreachable vertices by an edge creates a bridge. -/
859-
theorem IsBridge.sup_fromEdgeSet_of_not_reachable {u v : V} (h : ¬G.Reachable u v) :
860-
(G ⊔ fromEdgeSet {s(u, v)}).IsBridge s(u, v) := by
867+
theorem IsBridge.sup_edge_of_not_reachable {u v : V} (h : ¬G.Reachable u v) :
868+
(G ⊔ edge u v).IsBridge s(u, v) := by
861869
refine isBridge_iff.mpr ⟨.inr ⟨Set.mem_singleton _, mt (· ▸ .rfl) h⟩, ?_⟩
862870
exact fun h' ↦ h <| .mono (sdiff_le_iff'.mpr <| refl _) h'
863871

872+
@[deprecated (since := "2026-03-18")]
873+
alias IsBridge.sup_fromEdgeSet_of_not_reachable := IsBridge.sup_edge_of_not_reachable
874+
864875
/-- Connecting two unreachable vertices by an edge preserves existing bridges. -/
865-
theorem IsBridge.sup_fromEdgeSet_of_not_reachable_of_isBridge {u v : V} {e : Sym2 V}
866-
(h : ¬G.Reachable u v) (h' : G.IsBridge e) : (G ⊔ fromEdgeSet {s(u, v)}).IsBridge e := by
876+
theorem IsBridge.sup_edge_of_not_reachable_of_isBridge {u v : V} {e : Sym2 V}
877+
(h : ¬G.Reachable u v) (h' : G.IsBridge e) : (G ⊔ edge u v).IsBridge e := by
867878
refine isBridge_iff_mem_and_forall_cycle_notMem.mpr ⟨edgeSet_mono le_sup_left h'.left, ?_⟩
868879
refine fun _ p hp hpe ↦ isBridge_iff_mem_and_forall_cycle_notMem.mp h' |>.right
869880
(p.transfer G fun e' he' ↦ ?_) (hp.transfer _) (Walk.edges_transfer p _ ▸ hpe)
870881
refine edgeSet_sup .. ▸ Walk.edges_subset_edgeSet _ he' |>.elim id fun h' ↦ h ?_ |>.elim
871-
exact .mono (sdiff_le_iff'.mpr <| refl _) <|
872-
adj_and_reachable_delete_edges_iff_exists_cycle.mpr (by grind [edgeSet_fromEdgeSet]) |>.right
882+
exact .mono (sdiff_le_iff'.mpr le_rfl) <|
883+
adj_and_reachable_delete_edges_iff_exists_cycle.mpr ⟨_, p, by simp_all⟩ |>.right
884+
885+
@[deprecated (since := "2026-03-18")]
886+
alias IsBridge.sup_fromEdgeSet_of_not_reachable_of_isBridge :=
887+
IsBridge.sup_edge_of_not_reachable_of_isBridge
873888

874889
end BridgeEdges
875890

Mathlib/Combinatorics/SimpleGraph/DeleteEdges.lean

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ theorem deleteEdges_deleteEdges (s s' : Set (Sym2 V)) :
6565
lemma deleteEdges_empty : G.deleteEdges ∅ = G := by simp [deleteEdges]
6666
@[simp] lemma deleteEdges_univ : G.deleteEdges Set.univ = ⊥ := by simp [deleteEdges]
6767

68+
@[simp]
69+
theorem deleteEdges_le_iff (s : Set (Sym2 V)) (G' : SimpleGraph V) :
70+
G.deleteEdges s ≤ G' ↔ G ≤ fromEdgeSet s ⊔ G' := by
71+
rw [deleteEdges, sdiff_le_iff]
72+
6873
lemma deleteEdges_le (s : Set (Sym2 V)) : G.deleteEdges s ≤ G := sdiff_le
6974

7075
lemma deleteEdges_anti (h : s₁ ⊆ s₂) : G.deleteEdges s₂ ≤ G.deleteEdges s₁ :=
@@ -103,6 +108,8 @@ theorem edgeSet_deleteEdges (s : Set (Sym2 V)) : (G.deleteEdges s).edgeSet = G.e
103108
@[simp] lemma deleteEdges_fromEdgeSet (s t : Set (Sym2 V)) :
104109
(fromEdgeSet s).deleteEdges t = fromEdgeSet (s \ t) := by ext; simp +contextual
105110

111+
@[simp] lemma deleteEdges_eq_bot : G.deleteEdges s = ⊥ ↔ G.edgeSet ⊆ s := by simp [deleteEdges]
112+
106113
end DeleteEdges
107114

108115
section DeleteIncidenceSet

Mathlib/Combinatorics/SimpleGraph/Operations.lean

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ lemma adj_edge {v w : V} : (edge s t).Adj v w ↔ s(s, t) = s(v, w) ∧ v ≠ w
147147
lemma edge_comm : edge s t = edge t s := by
148148
rw [edge, edge, Sym2.eq_swap]
149149

150+
@[simp] lemma edge_le : edge s t ≤ G ↔ {s(s, t)} \ Sym2.diagSet ⊆ G.edgeSet := by simp [edge]
151+
150152
variable [DecidableEq V] in
151153
instance : DecidableRel (edge s t).Adj := fun _ _ ↦ by
152154
rw [edge_adj]; infer_instance
@@ -166,19 +168,29 @@ lemma edge_le_iff {v w : V} : edge v w ≤ G ↔ v = w ∨ G.Adj v w := by
166168
· refine ⟨fun h ↦ .inr <| h (by simp_all [edge_adj]), fun hadj v' w' hvw' ↦ ?_⟩
167169
aesop (add simp [edge_adj, adj_symm])
168170

171+
@[simp]
172+
lemma edgeSet_edge (v w : V) : (edge v w).edgeSet = {s(v, w)} \ Sym2.diagSet := by simp [edge]
173+
174+
lemma edgeSet_edge_subset {v w : V} : (edge v w).edgeSet ⊆ {s(v, w)} := by simp [edge]
175+
169176
variable {s t}
170177

171-
lemma edge_edgeSet_of_ne (h : s ≠ t) : (edge s t).edgeSet = {s(s, t)} := by simpa [edge]
178+
lemma edgeSet_edge_of_ne (h : s ≠ t) : (edge s t).edgeSet = {s(s, t)} := by simpa [edge]
179+
180+
@[deprecated (since := "2026-03-18")] alias edge_edgeSet_of_ne := edgeSet_edge_of_ne
172181

173182
lemma sup_edge_of_adj (h : G.Adj s t) : G ⊔ edge s t = G := by
174-
rwa [sup_eq_left, ← edgeSet_subset_edgeSet, edge_edgeSet_of_ne h.ne, Set.singleton_subset_iff,
183+
rwa [sup_eq_left, ← edgeSet_subset_edgeSet, edgeSet_edge_of_ne h.ne, Set.singleton_subset_iff,
175184
mem_edgeSet]
176185

186+
@[simp] lemma deleteEdges_edge {u v : V} {s : Set (Sym2 V)} (h : s(u, v) ∈ s) :
187+
(edge u v).deleteEdges s = ⊥ := by simp [edge, Set.diff_subset_iff, h]
188+
177189
lemma disjoint_edge {u v : V} : Disjoint G (edge u v) ↔ ¬G.Adj u v := by
178190
by_cases h : u = v
179191
· subst h
180192
simp [edge_self_eq_bot]
181-
simp [← disjoint_edgeSet, edge_edgeSet_of_ne h]
193+
simp [← disjoint_edgeSet, edgeSet_edge_of_ne h]
182194

183195
lemma sdiff_edge {u v : V} (h : ¬G.Adj u v) : G \ edge u v = G := by
184196
simp [disjoint_edge, h]
@@ -201,7 +213,7 @@ theorem edgeFinset_sup_edge [Fintype (edgeSet (G ⊔ edge s t))] (hn : ¬G.Adj s
201213
(G ⊔ edge s t).edgeFinset = G.edgeFinset.cons s(s, t) (by simp_all) := by
202214
letI := Classical.decEq V
203215
rw [edgeFinset_sup, cons_eq_insert, insert_eq, union_comm]
204-
simp_rw [edgeFinset, edge_edgeSet_of_ne h]; rfl
216+
simp_rw [edgeFinset, edgeSet_edge_of_ne h]; rfl
205217

206218
theorem card_edgeFinset_sup_edge [Fintype (edgeSet (G ⊔ edge s t))] (hn : ¬G.Adj s t) (h : s ≠ t) :
207219
#(G ⊔ edge s t).edgeFinset = #G.edgeFinset + 1 := by

0 commit comments

Comments
 (0)