Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit db09163

Browse files
committed
feat(combinatorics/simple_graph/subgraph): single-vertex and single-edge subgraphs (#16435)
Constructors for single-vertex and single-edge subgraphs along with some associated properties. Also includes dot notation improvements for `simple_graph.subgraph.adj`. Co-authored-by: Joanna Choules <joannachoules+lean@googlemail.com>
1 parent 5b294cf commit db09163

File tree

4 files changed

+234
-5
lines changed

4 files changed

+234
-5
lines changed

src/combinatorics/simple_graph/connectivity.lean

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ attribute [refl] walk.nil
8585

8686
@[simps] instance walk.inhabited (v : V) : inhabited (G.walk v v) := ⟨walk.nil⟩
8787

88+
/-- The one-edge walk associated to a pair of adjacent vertices. -/
89+
@[pattern, reducible] def adj.to_walk {G : simple_graph V} {u v : V} (h : G.adj u v) :
90+
G.walk u v := walk.cons h walk.nil
91+
8892
namespace walk
8993
variables {G}
9094

@@ -1176,6 +1180,12 @@ begin
11761180
exact h.elim (λ q, hp q.to_path),
11771181
end
11781182

1183+
protected lemma walk.reachable {G : simple_graph V} {u v : V} (p : G.walk u v) :
1184+
G.reachable u v := ⟨p⟩
1185+
1186+
protected lemma adj.reachable {u v : V} (h : G.adj u v) :
1187+
G.reachable u v := h.to_walk.reachable
1188+
11791189
@[refl] protected lemma reachable.refl (u : V) : G.reachable u u := by { fsplit, refl }
11801190
protected lemma reachable.rfl {u : V} : G.reachable u u := reachable.refl _
11811191

@@ -1201,6 +1211,10 @@ begin
12011211
{ exact reachable.trans hr ⟨walk.cons ha walk.nil⟩, }, },
12021212
end
12031213

1214+
protected lemma reachable.map {G : simple_graph V} {G' : simple_graph V'}
1215+
(f : G →g G') {u v : V} (h : G.reachable u v) : G'.reachable (f u) (f v) :=
1216+
h.elim (λ p, ⟨p.map f⟩)
1217+
12041218
variables (G)
12051219

12061220
lemma reachable_is_equivalence : equivalence G.reachable :=
@@ -1214,7 +1228,7 @@ def preconnected : Prop := ∀ (u v : V), G.reachable u v
12141228

12151229
lemma preconnected.map {G : simple_graph V} {H : simple_graph V'} (f : G →g H) (hf : surjective f)
12161230
(hG : G.preconnected) : H.preconnected :=
1217-
hf.forall₂.2 $ λ a b, (hG _ _).map $ walk.map _
1231+
hf.forall₂.2 $ λ a b, nonempty.map (walk.map _) $ hG _ _
12181232

12191233
lemma iso.preconnected_iff {G : simple_graph V} {H : simple_graph V'} (e : G ≃g H) :
12201234
G.preconnected ↔ H.preconnected :=
@@ -1308,6 +1322,24 @@ variables {G}
13081322
/-- A subgraph is connected if it is connected as a simple graph. -/
13091323
abbreviation subgraph.connected (H : G.subgraph) : Prop := H.coe.connected
13101324

1325+
lemma singleton_subgraph_connected {v : V} : (G.singleton_subgraph v).connected :=
1326+
begin
1327+
split,
1328+
rintros ⟨a, ha⟩ ⟨b, hb⟩,
1329+
simp only [singleton_subgraph_verts, set.mem_singleton_iff] at ha hb,
1330+
subst_vars
1331+
end
1332+
1333+
@[simp] lemma subgraph_of_adj_connected {v w : V} (hvw : G.adj v w) :
1334+
(G.subgraph_of_adj hvw).connected :=
1335+
begin
1336+
split,
1337+
rintro ⟨a, ha⟩ ⟨b, hb⟩,
1338+
simp only [subgraph_of_adj_verts, set.mem_insert_iff, set.mem_singleton_iff] at ha hb,
1339+
obtain (rfl|rfl) := ha; obtain (rfl|rfl) := hb;
1340+
refl <|> { apply adj.reachable, simp },
1341+
end
1342+
13111343
lemma preconnected.set_univ_walk_nonempty (hconn : G.preconnected) (u v : V) :
13121344
(set.univ : set (G.walk u v)).nonempty :=
13131345
by { rw ← set.nonempty_iff_univ_nonempty, exact hconn u v }

src/combinatorics/simple_graph/subgraph.lean

Lines changed: 183 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,27 @@ structure subgraph {V : Type u} (G : simple_graph V) :=
6161
(edge_vert : ∀ {v w : V}, adj v w → v ∈ verts)
6262
(symm : symmetric adj . obviously)
6363

64+
variables {V : Type u} {W : Type v}
65+
66+
/-- The one-vertex subgraph. -/
67+
@[simps]
68+
protected def singleton_subgraph (G : simple_graph V) (v : V) : G.subgraph :=
69+
{ verts := {v},
70+
adj := ⊥,
71+
adj_sub := by simp [-set.bot_eq_empty],
72+
edge_vert := by simp [-set.bot_eq_empty] }
73+
74+
/-- The one-edge subgraph. -/
75+
@[simps]
76+
def subgraph_of_adj (G : simple_graph V) {v w : V} (hvw : G.adj v w) : G.subgraph :=
77+
{ verts := {v, w},
78+
adj := λ a b, ⟦(v, w)⟧ = ⟦(a, b)⟧,
79+
adj_sub := λ a b h, by { rw [← G.mem_edge_set, ← h], exact hvw },
80+
edge_vert := λ a b h, by { apply_fun (λ e, a ∈ e) at h, simpa using h } }
81+
6482
namespace subgraph
6583

66-
variables {V : Type u} {W : Type v} {G : simple_graph V}
84+
variables {G : simple_graph V}
6785

6886
protected lemma loopless (G' : subgraph G) : irreflexive G'.adj :=
6987
λ v h, G.loopless v (G'.adj_sub h)
@@ -75,6 +93,16 @@ lemma adj_comm (G' : subgraph G) (v w : V) : G'.adj v w ↔ G'.adj w v :=
7593

7694
protected lemma adj.symm {G' : subgraph G} {u v : V} (h : G'.adj u v) : G'.adj v u := G'.symm h
7795

96+
protected lemma adj.adj_sub {H : G.subgraph} {u v : V} (h : H.adj u v) : G.adj u v := H.adj_sub h
97+
98+
protected lemma adj.fst_mem {H : G.subgraph} {u v : V} (h : H.adj u v) : u ∈ H.verts :=
99+
H.edge_vert h
100+
101+
protected lemma adj.snd_mem {H : G.subgraph} {u v : V} (h : H.adj u v) : v ∈ H.verts :=
102+
h.symm.fst_mem
103+
104+
protected lemma adj.ne {H : G.subgraph} {u v : V} (h : H.adj u v) : u ≠ v := h.adj_sub.ne
105+
78106
/-- Coercion from `G' : subgraph G` to a `simple_graph ↥G'.verts`. -/
79107
@[simps] protected def coe (G' : subgraph G) : simple_graph G'.verts :=
80108
{ adj := λ v w, G'.adj v w,
@@ -84,6 +112,10 @@ protected lemma adj.symm {G' : subgraph G} {u v : V} (h : G'.adj u v) : G'.adj v
84112
@[simp] lemma coe_adj_sub (G' : subgraph G) (u v : G'.verts) (h : G'.coe.adj u v) : G.adj u v :=
85113
G'.adj_sub h
86114

115+
/- Given `h : H.adj u v`, then `h.coe : H.coe.adj ⟨u, _⟩ ⟨v, _⟩`. -/
116+
protected lemma adj.coe {H : G.subgraph} {u v : V} (h : H.adj u v) :
117+
H.coe.adj ⟨u, H.edge_vert h⟩ ⟨v, H.edge_vert h.symm⟩ := h
118+
87119
/-- A subgraph is called a *spanning subgraph* if it contains all the vertices of `G`. --/
88120
def is_spanning (G' : subgraph G) : Prop := ∀ (v : V), v ∈ G'.verts
89121

@@ -493,7 +525,135 @@ begin
493525
simp only [set.mem_to_finset, mem_neighbor_set],
494526
end
495527

496-
/-! ## Subgraphs of subgraphs -/
528+
end subgraph
529+
530+
section mk_properties
531+
/-! ### Properties of `singleton_subgraph` and `subgraph_of_adj` -/
532+
533+
variables {G : simple_graph V} {G' : simple_graph W}
534+
535+
instance nonempty_singleton_subgraph_verts (v : V) : nonempty (G.singleton_subgraph v).verts :=
536+
⟨⟨v, set.mem_singleton v⟩⟩
537+
538+
@[simp] lemma singleton_subgraph_le_iff (v : V) (H : G.subgraph) :
539+
G.singleton_subgraph v ≤ H ↔ v ∈ H.verts :=
540+
begin
541+
refine ⟨λ h, h.1 (set.mem_singleton v), _⟩,
542+
intro h,
543+
split,
544+
{ simp [h] },
545+
{ simp [-set.bot_eq_empty] }
546+
end
547+
548+
@[simp] lemma map_singleton_subgraph (f : G →g G') {v : V} :
549+
subgraph.map f (G.singleton_subgraph v) = G'.singleton_subgraph (f v) :=
550+
by ext; simp only [relation.map, subgraph.map_adj, singleton_subgraph_adj, pi.bot_apply,
551+
exists_and_distrib_left, and_iff_left_iff_imp, is_empty.forall_iff, subgraph.map_verts,
552+
singleton_subgraph_verts, set.image_singleton]
553+
554+
@[simp] lemma neighbor_set_singleton_subgraph (v w : V) :
555+
(G.singleton_subgraph v).neighbor_set w = ∅ :=
556+
by { ext u, refl }
557+
558+
@[simp] lemma edge_set_singleton_subgraph (v : V) :
559+
(G.singleton_subgraph v).edge_set = ∅ :=
560+
sym2.from_rel_bot
561+
562+
lemma eq_singleton_subgraph_iff_verts_eq (H : G.subgraph) {v : V} :
563+
H = G.singleton_subgraph v ↔ H.verts = {v} :=
564+
begin
565+
refine ⟨λ h, by simp [h], λ h, _⟩,
566+
ext,
567+
{ rw [h, singleton_subgraph_verts] },
568+
{ simp only [Prop.bot_eq_false, singleton_subgraph_adj, pi.bot_apply, iff_false],
569+
intro ha,
570+
have ha1 := ha.fst_mem,
571+
have ha2 := ha.snd_mem,
572+
rw [h, set.mem_singleton_iff] at ha1 ha2,
573+
subst_vars,
574+
exact ha.ne rfl },
575+
end
576+
577+
instance nonempty_subgraph_of_adj_verts {v w : V} (hvw : G.adj v w) :
578+
nonempty (G.subgraph_of_adj hvw).verts := ⟨⟨v, by simp⟩⟩
579+
580+
@[simp] lemma edge_set_subgraph_of_adj {v w : V} (hvw : G.adj v w) :
581+
(G.subgraph_of_adj hvw).edge_set = {⟦(v, w)⟧} :=
582+
begin
583+
ext e,
584+
refine e.ind _,
585+
simp only [eq_comm, set.mem_singleton_iff, subgraph.mem_edge_set, subgraph_of_adj_adj,
586+
iff_self, forall_2_true_iff],
587+
end
588+
589+
lemma subgraph_of_adj_symm {v w : V} (hvw : G.adj v w) :
590+
G.subgraph_of_adj hvw.symm = G.subgraph_of_adj hvw :=
591+
by ext; simp [or_comm, and_comm]
592+
593+
@[simp] lemma map_subgraph_of_adj (f : G →g G')
594+
{v w : V} (hvw : G.adj v w) :
595+
subgraph.map f (G.subgraph_of_adj hvw) = G'.subgraph_of_adj (f.map_adj hvw) :=
596+
begin
597+
ext,
598+
{ simp only [subgraph.map_verts, subgraph_of_adj_verts, set.mem_image,
599+
set.mem_insert_iff, set.mem_singleton_iff],
600+
split,
601+
{ rintro ⟨u, rfl|rfl, rfl⟩; simp },
602+
{ rintro (rfl|rfl),
603+
{ use v, simp },
604+
{ use w, simp } } },
605+
{ simp only [relation.map, subgraph.map_adj, subgraph_of_adj_adj, quotient.eq, sym2.rel_iff],
606+
split,
607+
{ rintro ⟨a, b, (⟨rfl,rfl⟩|⟨rfl,rfl⟩), rfl, rfl⟩; simp },
608+
{ rintro (⟨rfl,rfl⟩|⟨rfl,rfl⟩),
609+
{ use [v, w], simp },
610+
{ use [w, v], simp } } }
611+
end
612+
613+
lemma neighbor_set_subgraph_of_adj_subset {u v w : V} (hvw : G.adj v w) :
614+
(G.subgraph_of_adj hvw).neighbor_set u ⊆ {v, w} :=
615+
(G.subgraph_of_adj hvw).neighbor_set_subset_verts _
616+
617+
@[simp] lemma neighbor_set_fst_subgraph_of_adj {v w : V} (hvw : G.adj v w) :
618+
(G.subgraph_of_adj hvw).neighbor_set v = {w} :=
619+
begin
620+
ext u,
621+
suffices : w = u ↔ u = w, by simpa [hvw.ne.symm] using this,
622+
rw eq_comm,
623+
end
624+
625+
@[simp] lemma neighbor_set_snd_subgraph_of_adj {v w : V} (hvw : G.adj v w) :
626+
(G.subgraph_of_adj hvw).neighbor_set w = {v} :=
627+
begin
628+
rw subgraph_of_adj_symm hvw.symm,
629+
exact neighbor_set_fst_subgraph_of_adj hvw.symm,
630+
end
631+
632+
@[simp] lemma neighbor_set_subgraph_of_adj_of_ne_of_ne {u v w : V} (hvw : G.adj v w)
633+
(hv : u ≠ v) (hw : u ≠ w) :
634+
(G.subgraph_of_adj hvw).neighbor_set u = ∅ :=
635+
by { ext, simp [hv.symm, hw.symm] }
636+
637+
lemma neighbor_set_subgraph_of_adj [decidable_eq V] {u v w : V} (hvw : G.adj v w) :
638+
(G.subgraph_of_adj hvw).neighbor_set u =
639+
(if u = v then {w} else ∅) ∪ (if u = w then {v} else ∅) :=
640+
by split_ifs; subst_vars; simp [*]
641+
642+
lemma singleton_subgraph_fst_le_subgraph_of_adj {u v : V} {h : G.adj u v} :
643+
G.singleton_subgraph u ≤ G.subgraph_of_adj h :=
644+
by split; simp [-set.bot_eq_empty]
645+
646+
lemma singleton_subgraph_snd_le_subgraph_of_adj {u v : V} {h : G.adj u v} :
647+
G.singleton_subgraph v ≤ G.subgraph_of_adj h :=
648+
by split; simp [-set.bot_eq_empty]
649+
650+
end mk_properties
651+
652+
namespace subgraph
653+
654+
variables {G : simple_graph V}
655+
656+
/-! ### Subgraphs of subgraphs -/
497657

498658
/-- Given a subgraph of a subgraph of `G`, construct a subgraph of `G`. -/
499659
@[reducible]
@@ -519,7 +679,7 @@ lemma coe_subgraph_injective (G' : G.subgraph) :
519679
function.injective (subgraph.coe_subgraph : G'.coe.subgraph → G.subgraph) :=
520680
function.left_inverse.injective restrict_coe_subgraph
521681

522-
/-! ## Edge deletion -/
682+
/-! ### Edge deletion -/
523683

524684
/-- Given a subgraph `G'` and a set of vertex pairs, remove all of the corresponding edges
525685
from its edge set, if present.
@@ -602,7 +762,7 @@ spanning_coe_le_of_le (delete_edges_le s)
602762

603763
end delete_edges
604764

605-
/-! ## Induced subgraphs -/
765+
/-! ### Induced subgraphs -/
606766

607767
/- Given a subgraph, we can change its vertex set while removing any invalid edges, which
608768
gives induced subgraphs. See also `simple_graph.induce` for the `simple_graph` version, which,
@@ -652,6 +812,25 @@ begin
652812
exact λ ha, ⟨G'.edge_vert ha, G'.edge_vert ha.symm⟩ }
653813
end
654814

815+
lemma singleton_subgraph_eq_induce {v : V} :
816+
G.singleton_subgraph v = (⊤ : G.subgraph).induce {v} :=
817+
by ext; simp [-set.bot_eq_empty, Prop.bot_eq_false] { contextual := tt }
818+
819+
lemma subgraph_of_adj_eq_induce {v w : V} (hvw : G.adj v w) :
820+
G.subgraph_of_adj hvw = (⊤ : G.subgraph).induce {v, w} :=
821+
begin
822+
ext,
823+
{ simp },
824+
{ split,
825+
{ intro h,
826+
simp only [subgraph_of_adj_adj, quotient.eq, sym2.rel_iff] at h,
827+
obtain ⟨rfl, rfl⟩|⟨rfl, rfl⟩ := h; simp [hvw, hvw.symm], },
828+
{ intro h,
829+
simp only [induce_adj, set.mem_insert_iff, set.mem_singleton_iff, top_adj_iff] at h,
830+
obtain ⟨rfl|rfl, rfl|rfl, ha⟩ := h;
831+
exact (ha.ne rfl).elim <|> simp } }
832+
end
833+
655834
end induce
656835

657836
/-- Given a subgraph and a set of vertices, delete all the vertices from the subgraph,

src/data/sym/sym2.lean

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,20 @@ lemma from_rel_proj_prop {sym : symmetric r} {z : α × α} : ⟦z⟧ ∈ from_r
363363
@[simp]
364364
lemma from_rel_prop {sym : symmetric r} {a b : α} : ⟦(a, b)⟧ ∈ from_rel sym ↔ r a b := iff.rfl
365365

366+
lemma from_rel_bot : from_rel (λ (x y : α) z, z : symmetric ⊥) = ∅ :=
367+
begin
368+
apply set.eq_empty_of_forall_not_mem (λ e, _),
369+
refine e.ind _,
370+
simp [-set.bot_eq_empty, Prop.bot_eq_false],
371+
end
372+
373+
lemma from_rel_top : from_rel (λ (x y : α) z, z : symmetric ⊤) = set.univ :=
374+
begin
375+
apply set.eq_univ_of_forall (λ e, _),
376+
refine e.ind _,
377+
simp [-set.top_eq_univ, Prop.top_eq_true],
378+
end
379+
366380
lemma from_rel_irreflexive {sym : symmetric r} :
367381
irreflexive r ↔ ∀ {z}, z ∈ from_rel sym → ¬is_diag z :=
368382
{ mp := λ h, sym2.ind $ by { rintros a b hr (rfl : a = b), exact h _ hr },

src/order/bounded_order.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ instance Prop.bounded_order : bounded_order Prop :=
362362
bot := false,
363363
bot_le := @false.elim }
364364

365+
lemma Prop.bot_eq_false : (⊥ : Prop) = false := rfl
366+
367+
lemma Prop.top_eq_true : (⊤ : Prop) = true := rfl
368+
365369
instance Prop.le_is_total : is_total Prop (≤) :=
366370
⟨λ p q, by { change (p → q) ∨ (q → p), tauto! }⟩
367371

0 commit comments

Comments
 (0)