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

Commit d4d33de

Browse files
feat(combinatorics): define simple graphs (#3458)
adds basic definition of `simple_graph`s Co-authored-by: Aaron Anderson <awainverse@gmail.com>
1 parent 8af1579 commit d4d33de

File tree

2 files changed

+268
-8
lines changed

2 files changed

+268
-8
lines changed
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/-
2+
Copyright (c) 2020 Aaron Anderson, Jalex Stark, Kyle Miller. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: Aaron Anderson, Jalex Stark, Kyle Miller.
5+
-/
6+
import data.fintype.basic
7+
import data.sym2
8+
/-!
9+
# Simple graphs
10+
11+
This module defines simple graphs on a vertex type `V` as an
12+
irreflexive symmetric relation.
13+
14+
There is a basic API for locally finite graphs and for graphs with
15+
finitely many vertices.
16+
17+
## Main definitions
18+
19+
* `simple_graph` is a structure for symmetric, irreflexive relations
20+
21+
* `neighbor_set` is the `set` of vertices adjacent to a given vertex
22+
23+
* `neighbor_finset` is the `finset` of vertices adjacent to a given vertex,
24+
if `neighbor_set` is finite
25+
26+
## Implementation notes
27+
28+
* A locally finite graph is one with instances `∀ v, fintype (G.neighbor_set v)`.
29+
30+
* Given instances `decidable_rel G.adj` and `fintype V`, then the graph
31+
is locally finite, too.
32+
33+
TODO: This is the simplest notion of an unoriented graph. This should
34+
eventually fit into a more complete combinatorics hierarchy which
35+
includes multigraphs and directed graphs. We begin with simple graphs
36+
in order to start learning what the combinatorics hierarchy should
37+
look like.
38+
39+
TODO: Part of this would include defining, for example, subgraphs of a
40+
simple graph.
41+
42+
-/
43+
open finset
44+
universe u
45+
46+
/--
47+
A simple graph is an irreflexive symmetric relation `adj` on a vertex type `V`.
48+
The relation describes which pairs of vertices are adjacent.
49+
There is exactly one edge for every pair of adjacent edges;
50+
see `simple_graph.edge_set` for the corresponding edge set.
51+
-/
52+
structure simple_graph (V : Type u) :=
53+
(adj : V → V → Prop)
54+
(sym : symmetric adj . obviously)
55+
(loopless : irreflexive adj . obviously)
56+
57+
/--
58+
The complete graph on a type `V` is the simple graph with all pairs of distinct vertices adjacent.
59+
-/
60+
def complete_graph (V : Type u) : simple_graph V :=
61+
{ adj := ne }
62+
63+
instance (V : Type u) : inhabited (simple_graph V) :=
64+
⟨complete_graph V⟩
65+
66+
instance complete_graph_adj_decidable (V : Type u) [decidable_eq V] :
67+
decidable_rel (complete_graph V).adj :=
68+
by { dsimp [complete_graph], apply_instance }
69+
70+
namespace simple_graph
71+
variables {V : Type u} (G : simple_graph V)
72+
73+
/-- `G.neighbor_set v` is the set of vertices adjacent to `v` in `G`. -/
74+
def neighbor_set (v : V) : set V := set_of (G.adj v)
75+
76+
lemma ne_of_adj {a b : V} (hab : G.adj a b) : a ≠ b :=
77+
by { rintro rfl, exact G.loopless a hab }
78+
79+
/--
80+
The edges of G consist of the unordered pairs of vertices related by
81+
`G.adj`.
82+
-/
83+
def edge_set : set (sym2 V) := sym2.from_rel G.sym
84+
85+
@[simp]
86+
lemma mem_edge_set {v w : V} : ⟦(v, w)⟧ ∈ G.edge_set ↔ G.adj v w :=
87+
by refl
88+
89+
/--
90+
Two vertices are adjacent iff there is an edge between them. The
91+
condition `v ≠ w` ensures they are different endpoints of the edge,
92+
which is necessary since when `v = w` the existential
93+
`∃ (e ∈ G.edge_set), v ∈ e ∧ w ∈ e` is satisfied by every edge
94+
incident to `v`.
95+
-/
96+
lemma adj_iff_exists_edge {v w : V} :
97+
G.adj v w ↔ v ≠ w ∧ ∃ (e ∈ G.edge_set), v ∈ e ∧ w ∈ e :=
98+
begin
99+
split, { intro, split, { exact G.ne_of_adj a, }, {use ⟦(v,w)⟧, simpa} },
100+
{ rintro ⟨hne, e, he, hv⟩,
101+
rw sym2.elems_iff_eq hne at hv,
102+
subst e,
103+
rwa mem_edge_set at he, }
104+
end
105+
106+
lemma edge_other_ne {e : sym2 V} (he : e ∈ G.edge_set) {v : V} (h : v ∈ e) : h.other ≠ v :=
107+
begin
108+
erw [← sym2.mem_other_spec h, sym2.eq_swap] at he,
109+
exact G.ne_of_adj he,
110+
end
111+
112+
instance edges_fintype [decidable_eq V] [fintype V] [decidable_rel G.adj] :
113+
fintype G.edge_set := by { dunfold edge_set, exact subtype.fintype _ }
114+
115+
/--
116+
The `edge_set` of the graph as a `finset`.
117+
-/
118+
def edge_finset [decidable_eq V] [fintype V] [decidable_rel G.adj] : finset (sym2 V) :=
119+
set.to_finset G.edge_set
120+
121+
@[simp] lemma mem_edge_finset [decidable_eq V] [fintype V] [decidable_rel G.adj] (e : sym2 V) :
122+
e ∈ G.edge_finset ↔ e ∈ G.edge_set :=
123+
by { dunfold edge_finset, simp }
124+
125+
@[simp] lemma irrefl {v : V} : ¬G.adj v v := G.loopless v
126+
127+
@[symm] lemma edge_symm (u v : V) : G.adj u v ↔ G.adj v u := ⟨λ x, G.sym x, λ x, G.sym x⟩
128+
129+
@[simp] lemma mem_neighbor_set (v w : V) : w ∈ G.neighbor_set v ↔ G.adj v w :=
130+
by tauto
131+
132+
section finite_at
133+
134+
/-!
135+
## Finiteness at a vertex
136+
137+
This section contains definitions and lemmas concerning vertices that
138+
have finitely many adjacent vertices. We denote this condition by
139+
`fintype (G.neighbor_set v)`.
140+
141+
We define `G.neighbor_finset v` to be the `finset` version of `G.neighbor_set v`.
142+
Use `neighbor_finset_eq_filter` to rewrite this definition as a `filter`.
143+
-/
144+
145+
variables (v : V) [fintype (G.neighbor_set v)]
146+
/--
147+
`G.neighbors v` is the `finset` version of `G.adj v` in case `G` is
148+
locally finite at `v`.
149+
-/
150+
def neighbor_finset : finset V := (G.neighbor_set v).to_finset
151+
152+
@[simp] lemma mem_neighbor_finset (w : V) :
153+
w ∈ G.neighbor_finset v ↔ G.adj v w :=
154+
by simp [neighbor_finset]
155+
156+
/--
157+
`G.degree v` is the number of vertices adjacent to `v`.
158+
-/
159+
def degree : ℕ := (G.neighbor_finset v).card
160+
161+
@[simp]
162+
lemma card_neighbor_set_eq_degree : fintype.card (G.neighbor_set v) = G.degree v :=
163+
by simp [degree, neighbor_finset]
164+
165+
end finite_at
166+
167+
section locally_finite
168+
169+
/--
170+
A graph is locally finite if every vertex has a finite neighbor set.
171+
-/
172+
@[reducible]
173+
def locally_finite := Π (v : V), fintype (G.neighbor_set v)
174+
175+
variable [locally_finite G]
176+
177+
/--
178+
A locally finite simple graph is regular of degree `d` if every vertex has degree `d`.
179+
-/
180+
def is_regular_of_degree (d : ℕ) : Prop := ∀ (v : V), G.degree v = d
181+
182+
end locally_finite
183+
184+
section finite
185+
186+
variables [fintype V]
187+
188+
instance neighbor_set_fintype [decidable_rel G.adj] (v : V) : fintype (G.neighbor_set v) :=
189+
@subtype.fintype _ _ (by { simp_rw mem_neighbor_set, apply_instance }) _
190+
191+
lemma neighbor_finset_eq_filter {v : V} [decidable_rel G.adj] :
192+
G.neighbor_finset v = finset.univ.filter (G.adj v) :=
193+
by { ext, simp }
194+
195+
@[simp]
196+
lemma complete_graph_degree [decidable_eq V] (v : V) :
197+
(complete_graph V).degree v = fintype.card V - 1 :=
198+
begin
199+
convert univ.card.pred_eq_sub_one,
200+
erw [degree, neighbor_finset_eq_filter, filter_ne, card_erase_of_mem (mem_univ v)],
201+
end
202+
203+
lemma complete_graph_is_regular [decidable_eq V] :
204+
(complete_graph V).is_regular_of_degree (fintype.card V - 1) :=
205+
by { intro v, simp }
206+
207+
end finite
208+
209+
end simple_graph

src/data/sym2.lean

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,14 @@ term of the symmetric square.
4141
symmetric square, unordered pairs, symmetric powers
4242
-/
4343

44+
universe u
45+
variables {α : Type u}
4446
namespace sym2
45-
variables {α : Type*}
4647

4748
/--
4849
This is the relation capturing the notion of pairs equivalent up to permutations.
4950
-/
50-
inductive rel (α : Type*) : (α × α) → (α × α) → Prop
51+
inductive rel (α : Type u) : (α × α) → (α × α) → Prop
5152
| refl (x y : α) : rel (x, y) (x, y)
5253
| swap (x y : α) : rel (x, y) (y, x)
5354

@@ -61,7 +62,7 @@ by { intros a b, cases_matching* rel _ _ _; apply rel.refl <|> apply rel.swap }
6162

6263
lemma rel.is_equivalence : equivalence (rel α) := by tidy; apply rel.trans; assumption
6364

64-
instance rel.setoid (α : Type*) : setoid (α × α) := ⟨rel α, rel.is_equivalence⟩
65+
instance rel.setoid (α : Type u) : setoid (α × α) := ⟨rel α, rel.is_equivalence⟩
6566

6667
end sym2
6768

@@ -73,11 +74,9 @@ It is equivalent in a natural way to multisets of cardinality 2 (see
7374
`sym2.equiv_multiset`).
7475
-/
7576
@[reducible]
76-
def sym2 (α : Type*) := quotient (sym2.rel.setoid α)
77+
def sym2 (α : Type u) := quotient (sym2.rel.setoid α)
7778

7879
namespace sym2
79-
universe u
80-
variables {α : Type u}
8180

8281
lemma eq_swap {a b : α} : ⟦(a, b)⟧ = ⟦(b, a)⟧ :=
8382
by { rw quotient.eq, apply rel.swap }
@@ -114,6 +113,7 @@ def mem (x : α) (z : sym2 α) : Prop :=
114113
instance : has_mem α (sym2 α) := ⟨mem⟩
115114

116115
lemma mk_has_mem (x y : α) : x ∈ ⟦(x, y)⟧ := ⟨y, rfl⟩
116+
lemma mk_has_mem_right (x y : α) : y ∈ ⟦(x, y)⟧ := by { rw eq_swap, apply mk_has_mem }
117117

118118
/--
119119
This is a type-valued version of the membership predicate `mem` that contains the other
@@ -167,9 +167,21 @@ begin
167167
{ cases h; rw [h.1, h.2], rw eq_swap }
168168
end
169169

170-
lemma mem_iff {a b c : α} : a ∈ ⟦(b, c)⟧ ↔ a = b ∨ a = c :=
170+
@[simp] lemma mem_iff {a b c : α} : a ∈ ⟦(b, c)⟧ ↔ a = b ∨ a = c :=
171171
{ mp := by { rintro ⟨_, h⟩, rw eq_iff at h, tidy },
172-
mpr := by { rintro ⟨_⟩; subst a, { apply mk_has_mem }, rw eq_swap, apply mk_has_mem } }
172+
mpr := by { rintro ⟨_⟩; subst a, { apply mk_has_mem }, apply mk_has_mem_right } }
173+
174+
lemma elems_iff_eq {x y : α} {z : sym2 α} (hne : x ≠ y) :
175+
x ∈ z ∧ y ∈ z ↔ z = ⟦(x, y)⟧ :=
176+
begin
177+
split,
178+
{ rintros ⟨hx, hy⟩,
179+
induction z, cases z with z₁ z₂,
180+
apply eq_iff.mpr,
181+
cases mem_iff.mp hx with hx hx; cases mem_iff.mp hy with hy hy; cc,
182+
refl },
183+
{ rintro rfl, simp },
184+
end
173185

174186
end membership
175187

@@ -221,6 +233,16 @@ lemma from_rel_irreflexive {sym : symmetric r} :
221233
erw is_diag_iff_proj_eq at hd, erw from_rel_proj_prop at hr, tidy },
222234
mpr := by { intros h x hr, rw ← @from_rel_prop _ _ sym at hr, exact h hr ⟨x, rfl⟩ }}
223235

236+
instance from_rel.decidable_as_set (sym : symmetric r) [h : decidable_rel r] :
237+
decidable_pred (λ x, x ∈ sym2.from_rel sym) :=
238+
λ (x : sym2 α), quotient.rec_on x
239+
(λ x', by { simp_rw from_rel_proj_prop, apply_instance })
240+
(by tidy)
241+
242+
instance from_rel.decidable_pred (sym : symmetric r) [h : decidable_rel r] :
243+
decidable_pred (sym2.from_rel sym) :=
244+
by { change decidable_pred (λ x, x ∈ sym2.from_rel sym), apply_instance }
245+
224246
end relations
225247

226248
section sym_equiv
@@ -282,4 +304,33 @@ equiv_sym α
282304

283305
end sym_equiv
284306

307+
section fintype
308+
309+
/--
310+
An algorithm for computing `sym2.rel`.
311+
-/
312+
def rel_bool [decidable_eq α] (x y : α × α) : bool :=
313+
if x.1 = y.1 then x.2 = y.2 else
314+
if x.1 = y.2 then x.2 = y.1 else ff
315+
316+
lemma rel_bool_spec [decidable_eq α] (x y : α × α) :
317+
↥(rel_bool x y) ↔ rel α x y :=
318+
begin
319+
cases x with x₁ x₂, cases y with y₁ y₂,
320+
dsimp [rel_bool], split_ifs;
321+
simp only [false_iff, bool.coe_sort_ff, bool.of_to_bool_iff],
322+
rotate 2, { contrapose! h, cases h; cc },
323+
all_goals { subst x₁, split; intro h1,
324+
{ subst h1; apply sym2.rel.swap },
325+
{ cases h1; cc } }
326+
end
327+
328+
/--
329+
Given `[decidable_eq α]` and `[fintype α]`, the following instance gives `fintype (sym2 α)`.
330+
-/
331+
instance (α : Type*) [decidable_eq α] : decidable_rel (sym2.rel α) :=
332+
λ x y, decidable_of_bool (rel_bool x y) (rel_bool_spec x y)
333+
334+
end fintype
335+
285336
end sym2

0 commit comments

Comments
 (0)