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

Commit b0f585c

Browse files
YaelDillieskmill
andcommitted
feat(combinatorics/simple_graph/inc_matrix): Incidence matrix (#10867)
Define the incidence matrix of a simple graph and prove the basics, including some stuff about matrix multiplication. Co-authored-by: Gabriel Moise <gabriel.moise@stcatz.ox.ac.uk> Co-authored-by: Kyle Miller <kmill31415@gmail.com> Co-authored-by: Kyle Miller <kmill31415@gmail.com>
1 parent 01eb653 commit b0f585c

File tree

6 files changed

+220
-6
lines changed

6 files changed

+220
-6
lines changed

src/algebra/ring/basic.lean

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ lemma ite_mul_zero_right {α : Type*} [mul_zero_class α] (P : Prop) [decidable
269269
ite P (a * b) 0 = a * ite P b 0 :=
270270
by { by_cases h : P; simp [h], }
271271

272+
lemma ite_and_mul_zero {α : Type*} [mul_zero_class α]
273+
(P Q : Prop) [decidable P] [decidable Q] (a b : α) :
274+
ite (P ∧ Q) (a * b) 0 = ite P a 0 * ite Q b 0 :=
275+
by simp only [←ite_and, ite_mul, mul_ite, mul_zero, zero_mul, and_comm]
276+
272277
/-- An element `a` of a semiring is even if there exists `k` such `a = 2*k`. -/
273278
def even (a : α) : Prop := ∃ k, a = 2*k
274279

src/combinatorics/simple_graph/basic.lean

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ lemma incidence_set_inter_incidence_set_subset (h : a ≠ b) :
428428
G.incidence_set a ∩ G.incidence_set b ⊆ {⟦(a, b)⟧} :=
429429
λ e he, (sym2.mem_and_mem_iff h).1 ⟨he.1.2, he.2.2
430430

431-
lemma incidence_set_inter_incidence_set (h : G.adj a b) :
431+
lemma incidence_set_inter_incidence_set_of_adj (h : G.adj a b) :
432432
G.incidence_set a ∩ G.incidence_set b = {⟦(a, b)⟧} :=
433433
begin
434434
refine (G.incidence_set_inter_incidence_set_subset $ h.ne).antisymm _,
@@ -442,6 +442,14 @@ lemma adj_of_mem_incidence_set (h : a ≠ b) (ha : e ∈ G.incidence_set a)
442442
by rwa [←mk_mem_incidence_set_left_iff,
443443
←set.mem_singleton_iff.1 $ G.incidence_set_inter_incidence_set_subset h ⟨ha, hb⟩]
444444

445+
lemma incidence_set_inter_incidence_set_of_not_adj (h : ¬ G.adj a b) (hn : a ≠ b) :
446+
G.incidence_set a ∩ G.incidence_set b = ∅ :=
447+
begin
448+
simp_rw [set.eq_empty_iff_forall_not_mem, set.mem_inter_eq, not_and],
449+
intros u ha hb,
450+
exact h (G.adj_of_mem_incidence_set hn ha hb),
451+
end
452+
445453
instance decidable_mem_incidence_set [decidable_eq V] [decidable_rel G.adj] (v : V) :
446454
decidable_pred (∈ G.incidence_set v) := λ e, and.decidable
447455

@@ -687,6 +695,11 @@ lemma card_incidence_set_eq_degree [decidable_eq V] :
687695
fintype.card (G.incidence_set v) = G.degree v :=
688696
by { rw fintype.card_congr (G.incidence_set_equiv_neighbor_set v), simp }
689697

698+
@[simp]
699+
lemma card_incidence_finset_eq_degree [decidable_eq V] :
700+
(G.incidence_finset v).card = G.degree v :=
701+
by { rw ← G.card_incidence_set_eq_degree, apply set.to_finset_card }
702+
690703
@[simp]
691704
lemma mem_incidence_finset [decidable_eq V] (e : sym2 V) :
692705
e ∈ G.incidence_finset v ↔ e ∈ G.incidence_set v :=
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/-
2+
Copyright (c) 2021 Gabriel Moise. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Gabriel Moise, Yaël Dillies, Kyle Miller
5+
-/
6+
import combinatorics.simple_graph.basic
7+
import data.matrix.basic
8+
9+
/-!
10+
# Incidence matrix of a simple graph
11+
12+
This file defines the unoriented incidence matrix of a simple graph.
13+
14+
## Main definitions
15+
16+
* `simple_graph.inc_matrix`: `G.inc_matrix R` is the incidence matrix of `G` over the ring `R`.
17+
18+
## Main results
19+
20+
* `simple_graph.inc_matrix_mul_transpose_diag`: The diagonal entries of the product of
21+
`G.inc_matrix R` and its transpose are the degrees of the vertices.
22+
* `simple_graph.inc_matrix_mul_transpose`: Gives a complete description of the product of
23+
`G.inc_matrix R` and its transpose; the diagonal is the degrees of each vertex, and the
24+
off-diagonals are 1 or 0 depending on whether or not the vertices are adjacent.
25+
* `simple_graph.inc_matrix_transpose_mul_diag`: The diagonal entries of the product of the
26+
transpose of `G.inc_matrix R` and `G.inc_matrix R` are `2` or `0` depending on whether or
27+
not the unordered pair is an edge of `G`.
28+
29+
## Implementation notes
30+
31+
The usual definition of an incidence matrix has one row per vertex and one column per edge.
32+
However, this definition has columns indexed by all of `sym2 α`, where `α` is the vertex type.
33+
This appears not to change the theory, and for simple graphs it has the nice effect that every
34+
incidence matrix for each `simple_graph α` has the same type.
35+
36+
## TODO
37+
38+
* Define the oriented incidence matrices for oriented graphs.
39+
* Define the graph Laplacian of a simple graph using the oriented incidence matrix from an
40+
arbitrary orientation of a simple graph.
41+
-/
42+
43+
noncomputable theory
44+
45+
open finset matrix simple_graph sym2
46+
open_locale big_operators matrix
47+
48+
namespace simple_graph
49+
variables (R : Type*) {α : Type*} (G : simple_graph α)
50+
51+
/-- `G.inc_matrix R` is the `α × sym2 α` matrix whose `(a, e)`-entry is `1` if `e` is incident to
52+
`a` and `0` otherwise. -/
53+
def inc_matrix [has_zero R] [has_one R] : matrix α (sym2 α) R :=
54+
λ a, (G.incidence_set a).indicator 1
55+
56+
variables {R}
57+
58+
lemma inc_matrix_apply [has_zero R] [has_one R] {a : α} {e : sym2 α} :
59+
G.inc_matrix R a e = (G.incidence_set a).indicator 1 e := rfl
60+
61+
/-- Entries of the incidence matrix can be computed given additional decidable instances. -/
62+
lemma inc_matrix_apply' [has_zero R] [has_one R] [decidable_eq α] [decidable_rel G.adj]
63+
{a : α} {e : sym2 α} :
64+
G.inc_matrix R a e = if e ∈ G.incidence_set a then 1 else 0 :=
65+
by convert rfl
66+
67+
section mul_zero_one_class
68+
variables [mul_zero_one_class R] {a b : α} {e : sym2 α}
69+
70+
lemma inc_matrix_apply_mul_inc_matrix_apply :
71+
G.inc_matrix R a e * G.inc_matrix R b e = (G.incidence_set a ∩ G.incidence_set b).indicator 1 e :=
72+
begin
73+
simp only [inc_matrix, set.indicator_apply, ←ite_and_mul_zero,
74+
pi.one_apply, mul_one, set.mem_inter_eq],
75+
congr,
76+
end
77+
78+
lemma inc_matrix_apply_mul_inc_matrix_apply_of_not_adj (hab : a ≠ b) (h : ¬ G.adj a b) :
79+
G.inc_matrix R a e * G.inc_matrix R b e = 0 :=
80+
begin
81+
rw [inc_matrix_apply_mul_inc_matrix_apply, set.indicator_of_not_mem],
82+
rw [G.incidence_set_inter_incidence_set_of_not_adj h hab],
83+
exact set.not_mem_empty e,
84+
end
85+
86+
lemma inc_matrix_of_not_mem_incidence_set (h : e ∉ G.incidence_set a) :
87+
G.inc_matrix R a e = 0 :=
88+
by rw [inc_matrix_apply, set.indicator_of_not_mem h]
89+
90+
lemma inc_matrix_of_mem_incidence_set (h : e ∈ G.incidence_set a) : G.inc_matrix R a e = 1 :=
91+
by rw [inc_matrix_apply, set.indicator_of_mem h, pi.one_apply]
92+
93+
variables [nontrivial R]
94+
95+
lemma inc_matrix_apply_eq_zero_iff : G.inc_matrix R a e = 0 ↔ e ∉ G.incidence_set a :=
96+
begin
97+
simp only [inc_matrix_apply, set.indicator_apply_eq_zero, pi.one_apply, one_ne_zero],
98+
exact iff.rfl,
99+
end
100+
101+
lemma inc_matrix_apply_eq_one_iff : G.inc_matrix R a e = 1 ↔ e ∈ G.incidence_set a :=
102+
by { convert one_ne_zero.ite_eq_left_iff, assumption }
103+
104+
end mul_zero_one_class
105+
106+
section non_assoc_semiring
107+
variables [fintype α] [non_assoc_semiring R] {a b : α} {e : sym2 α}
108+
109+
lemma sum_inc_matrix_apply [decidable_eq α] [decidable_rel G.adj] :
110+
∑ e, G.inc_matrix R a e = G.degree a :=
111+
by simp [inc_matrix_apply', sum_boole, set.filter_mem_univ_eq_to_finset]
112+
113+
lemma inc_matrix_mul_transpose_diag [decidable_eq α] [decidable_rel G.adj] :
114+
(G.inc_matrix R ⬝ (G.inc_matrix R)ᵀ) a a = G.degree a :=
115+
begin
116+
rw ←sum_inc_matrix_apply,
117+
simp [matrix.mul_apply, inc_matrix_apply', ←ite_and_mul_zero],
118+
end
119+
120+
lemma sum_inc_matrix_apply_of_mem_edge_set : e ∈ G.edge_set → ∑ a, G.inc_matrix R a e = 2 :=
121+
begin
122+
classical,
123+
refine e.ind _,
124+
intros a b h,
125+
rw mem_edge_set at h,
126+
rw [←nat.cast_two, ←card_doubleton h.ne],
127+
simp only [inc_matrix_apply', sum_boole, mk_mem_incidence_set_iff, h, true_and],
128+
congr' 2,
129+
ext e,
130+
simp only [mem_filter, mem_univ, true_and, mem_insert, mem_singleton],
131+
end
132+
133+
lemma sum_inc_matrix_apply_of_not_mem_edge_set (h : e ∉ G.edge_set) : ∑ a, G.inc_matrix R a e = 0 :=
134+
sum_eq_zero $ λ a _, G.inc_matrix_of_not_mem_incidence_set $ λ he, h he.1
135+
136+
lemma inc_matrix_transpose_mul_diag [decidable_rel G.adj] :
137+
((G.inc_matrix R)ᵀ ⬝ G.inc_matrix R) e e = if e ∈ G.edge_set then 2 else 0 :=
138+
begin
139+
classical,
140+
simp only [matrix.mul_apply, inc_matrix_apply', transpose_apply, ←ite_and_mul_zero,
141+
one_mul, sum_boole, and_self],
142+
split_ifs with h,
143+
{ revert h,
144+
refine e.ind _,
145+
intros v w h,
146+
rw [←nat.cast_two, ←card_doubleton (G.ne_of_adj h)],
147+
simp [mk_mem_incidence_set_iff, G.mem_edge_set.mp h],
148+
congr' 2,
149+
ext u,
150+
simp, },
151+
{ revert h,
152+
refine e.ind _,
153+
intros v w h,
154+
simp [mk_mem_incidence_set_iff, G.mem_edge_set.not.mp h], },
155+
end
156+
157+
end non_assoc_semiring
158+
159+
section semiring
160+
variables [fintype (sym2 α)] [semiring R] {a b : α} {e : sym2 α}
161+
162+
lemma inc_matrix_mul_transpose_apply_of_adj (h : G.adj a b) :
163+
(G.inc_matrix R ⬝ (G.inc_matrix R)ᵀ) a b = (1 : R) :=
164+
begin
165+
simp_rw [matrix.mul_apply, matrix.transpose_apply, inc_matrix_apply_mul_inc_matrix_apply,
166+
set.indicator_apply, pi.one_apply, sum_boole],
167+
convert nat.cast_one,
168+
convert card_singleton ⟦(a, b)⟧,
169+
rw [←coe_eq_singleton, coe_filter_univ],
170+
exact G.incidence_set_inter_incidence_set_of_adj h,
171+
end
172+
173+
lemma inc_matrix_mul_transpose [fintype α] [decidable_eq α] [decidable_rel G.adj] :
174+
G.inc_matrix R ⬝ (G.inc_matrix R)ᵀ = λ a b,
175+
if a = b then G.degree a else if G.adj a b then 1 else 0 :=
176+
begin
177+
ext a b,
178+
split_ifs with h h',
179+
{ subst b,
180+
convert G.inc_matrix_mul_transpose_diag },
181+
{ exact G.inc_matrix_mul_transpose_apply_of_adj h' },
182+
{ simp only [matrix.mul_apply, matrix.transpose_apply,
183+
G.inc_matrix_apply_mul_inc_matrix_apply_of_not_adj h h', sum_const_zero] }
184+
end
185+
186+
end semiring
187+
end simple_graph

src/data/finset/card.lean

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ open function multiset nat
3333
variables {α β : Type*}
3434

3535
namespace finset
36-
variables {s t : finset α} {a : α}
36+
variables {s t : finset α} {a b : α}
3737

3838
/-- `s.card` is the number of elements of `s`, aka its cardinality. -/
3939
def card (s : finset α) : ℕ := s.1.card
@@ -88,6 +88,9 @@ begin
8888
{ rw [card_insert_of_not_mem h, if_neg h] }
8989
end
9090

91+
@[simp] lemma card_doubleton (h : a ≠ b) : ({a, b} : finset α).card = 2 :=
92+
by rw [card_insert_of_not_mem (not_mem_singleton.2 h), card_singleton]
93+
9194
@[simp] lemma card_erase_of_mem : a ∈ s → (s.erase a).card = s.card - 1 := card_erase_of_mem
9295
@[simp] lemma card_erase_add_one : a ∈ s → (s.erase a).card + 1 = s.card := card_erase_add_one
9396

@@ -463,8 +466,8 @@ begin
463466
simp_rw [card_eq_one],
464467
rintro ⟨a, _, hab, rfl, b, rfl⟩,
465468
exact ⟨a, b, not_mem_singleton.1 hab, rfl⟩ },
466-
{ rintro ⟨x, y, hxy, rfl⟩,
467-
simp only [hxy, card_insert_of_not_mem, not_false_iff, mem_singleton, card_singleton] }
469+
{ rintro ⟨x, y, h, rfl⟩,
470+
exact card_doubleton h }
468471
end
469472

470473
lemma card_eq_three [decidable_eq α] :

src/data/fintype/basic.lean

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ lemma univ_filter_mem_range (f : α → β) [fintype β]
209209
finset.univ.filter (λ y, y ∈ set.range f) = finset.univ.image f :=
210210
univ_filter_exists f
211211

212+
lemma coe_filter_univ (p : α → Prop) [decidable_pred p] : (univ.filter p : set α) = {x | p x} :=
213+
by rw [coe_filter, coe_univ, set.sep_univ]
214+
212215
/-- A special case of `finset.sup_eq_supr` that omits the useless `x ∈ univ` binder. -/
213216
lemma sup_univ_eq_supr [complete_lattice β] (f : α → β) : finset.univ.sup f = supr f :=
214217
(sup_eq_supr _ f).trans $ congr_arg _ $ funext $ λ a, supr_pos (mem_univ _)
@@ -668,6 +671,10 @@ end
668671
disjoint s.to_finset t.to_finset ↔ disjoint s t :=
669672
⟨λ h x hx, h (by simpa using hx), λ h x hx, h (by simpa using hx)⟩
670673

674+
lemma filter_mem_univ_eq_to_finset [fintype α] (s : set α) [fintype s] [decidable_pred (∈ s)] :
675+
finset.univ.filter (∈ s) = s.to_finset :=
676+
by { ext, simp only [mem_filter, finset.mem_univ, true_and, mem_to_finset] }
677+
671678
end set
672679

673680
lemma finset.card_univ [fintype α] : (finset.univ : finset α).card = fintype.card α :=

src/linear_algebra/affine_space/combination.lean

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -543,8 +543,7 @@ begin
543543
rw [centroid_def,
544544
affine_combination_eq_weighted_vsub_of_point_vadd_of_sum_eq_one _ _ _
545545
(sum_centroid_weights_eq_one_of_cast_card_ne_zero _ hc) (p i₁)],
546-
simp [h],
547-
norm_num }
546+
simp [h] }
548547
end
549548

550549
/-- The centroid of two points indexed by `fin 2`, expressed directly

0 commit comments

Comments
 (0)