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

Commit a9b6230

Browse files
committed
feat(combinatorics/quiver): weakly connected components (#6847)
Define composition of paths and the weakly connected components of a directed graph. Two vertices are in the same weakly connected component if there is a zigzag of arrows from one to the other.
1 parent 21cc806 commit a9b6230

File tree

1 file changed

+83
-3
lines changed

1 file changed

+83
-3
lines changed

src/combinatorics/quiver.lean

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,44 @@ inductive path {V} (G : quiver.{v u} V) (a : V) : V → Sort (max (u+1) v)
9595
| nil : path a
9696
| cons : Π {b c : V}, path b → G.arrow b c → path c
9797

98+
/-- An arrow viewed as a path of length one. -/
99+
def arrow.to_path {V} {G : quiver V} {a b} (e : G.arrow a b) : G.path a b :=
100+
path.nil.cons e
101+
102+
namespace path
103+
104+
variables {V : Type*} {G : quiver V}
105+
98106
/-- The length of a path is the number of arrows it uses. -/
99-
def path.length {V} {G : quiver V} {a : V} : Π {b}, G.path a b → ℕ
107+
def length {a : V} : Π {b}, G.path a b → ℕ
100108
| _ path.nil := 0
101109
| _ (path.cons p _) := p.length + 1
102110

103-
@[simp] lemma path.length_nil {V} {G : quiver V} {a : V} :
111+
@[simp] lemma length_nil {a : V} :
104112
(path.nil : G.path a a).length = 0 := rfl
105113

106-
@[simp] lemma path.length_cons {V} {G : quiver V} (a b c : V) (p : G.path a b)
114+
@[simp] lemma length_cons (a b c : V) (p : G.path a b)
107115
(e : G.arrow b c) : (p.cons e).length = p.length + 1 := rfl
108116

117+
/-- Composition of paths. -/
118+
def comp {a b} : Π {c}, G.path a b → G.path b c → G.path a c
119+
| _ p (path.nil) := p
120+
| _ p (path.cons q e) := (p.comp q).cons e
121+
122+
@[simp] lemma comp_cons {a b c d} (p : G.path a b) (q : G.path b c) (e : G.arrow c d) :
123+
p.comp (q.cons e) = (p.comp q).cons e := rfl
124+
@[simp] lemma comp_nil {a b} (p : G.path a b) : p.comp path.nil = p := rfl
125+
@[simp] lemma nil_comp {a} : ∀ {b} (p : G.path a b), path.nil.comp p = p
126+
| a path.nil := rfl
127+
| b (path.cons p e) := by rw [comp_cons, nil_comp]
128+
@[simp] lemma comp_assoc {a b c} : ∀ {d}
129+
(p : G.path a b) (q : G.path b c) (r : G.path c d),
130+
(p.comp q).comp r = p.comp (q.comp r)
131+
| c p q path.nil := rfl
132+
| d p q (path.cons r e) := by rw [comp_cons, comp_cons, comp_cons, comp_assoc]
133+
134+
end path
135+
109136
/-- A quiver is an arborescence when there is a unique path from the default vertex
110137
to every other vertex. -/
111138
class arborescence {V} (T : quiver.{v u} V) : Sort (max (u+1) v) :=
@@ -165,6 +192,8 @@ class rooted_connected {V} (G : quiver V) (r : V) : Prop :=
165192

166193
attribute [instance] rooted_connected.nonempty_path
167194

195+
section geodesic_subtree
196+
168197
variables {V : Type*} (G : quiver.{v+1} V) (r : V) [G.rooted_connected r]
169198

170199
/-- A path from `r` of minimal length. -/
@@ -189,4 +218,55 @@ arborescence_mk _ r (λ a, (G.shortest_path r a).length)
189218
rcases this with ⟨p, hp⟩, cases p with a _ p e,
190219
{ exact or.inl rfl }, { exact or.inr ⟨a, ⟨⟨e, p, hp⟩⟩⟩ } })
191220

221+
end geodesic_subtree
222+
223+
variables {V : Type*} (G : quiver V)
224+
225+
/-- A quiver `has_reverse` if we can reverse an arrow `p` from `a` to `b` to get an arrow
226+
`p.reverse` from `b` to `a`.-/
227+
class has_reverse :=
228+
(reverse' : Π {a b}, G.arrow a b → G.arrow b a)
229+
230+
variables {G} [has_reverse G]
231+
232+
/-- Reverse the direction of an arrow. -/
233+
def arrow.reverse {a b} : G.arrow a b → G.arrow b a := has_reverse.reverse'
234+
235+
/-- Reverse the direction of a path. -/
236+
def path.reverse {a} : Π {b}, G.path a b → G.path b a
237+
| a path.nil := path.nil
238+
| b (path.cons p e) := e.reverse.to_path.comp p.reverse
239+
240+
variable (H : quiver.{v+1} V)
241+
242+
instance : has_reverse H.symmetrify := ⟨λ a b e, e.swap⟩
243+
244+
/-- Two vertices are related in the zigzag setoid if there is a
245+
zigzag of arrows from one to the other. -/
246+
def zigzag_setoid : setoid V :=
247+
⟨λ a b, nonempty (H.symmetrify.path a b),
248+
λ a, ⟨path.nil⟩,
249+
λ a b ⟨p⟩, ⟨p.reverse⟩,
250+
λ a b c ⟨p⟩ ⟨q⟩, ⟨p.comp q⟩⟩
251+
252+
/-- The type of weakly connected components of a directed graph. Two vertices are
253+
in the same weakly connected component if there is a zigzag of arrows from one
254+
to the other. -/
255+
def weakly_connected_component : Type* := quotient H.zigzag_setoid
256+
257+
namespace weakly_connected_component
258+
variable {H}
259+
260+
/-- The weakly connected component corresponding to a vertex. -/
261+
protected def mk : V → H.weakly_connected_component := quotient.mk'
262+
263+
instance : has_coe_t V H.weakly_connected_component := ⟨weakly_connected_component.mk⟩
264+
instance [inhabited V] : inhabited H.weakly_connected_component := ⟨↑(default V)⟩
265+
266+
protected lemma eq (a b : V) :
267+
(a : H.weakly_connected_component) = b ↔ nonempty (H.symmetrify.path a b) :=
268+
quotient.eq'
269+
270+
end weakly_connected_component
271+
192272
end quiver

0 commit comments

Comments
 (0)