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

Commit c3c7c34

Browse files
committed
feat(data/matrix/basic): dependently-typed block diagonal (#7068)
This allows constructing block diagonal matrices whose blocks are different sizes. A notable example of such a matrix is the one from the Jordan Normal Form. This duplicates all of the API for `block_diagonal` from this file. Most of the proofs copy across cleanly, but the proof for `block_diagonal_mul'` required lots of hand-holding that `simp` could solve by itself for the non-dependent case.
1 parent 8459d0a commit c3c7c34

File tree

1 file changed

+122
-9
lines changed

1 file changed

+122
-9
lines changed

src/data/matrix/basic.lean

Lines changed: 122 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ def matrix (m : Type u) (n : Type u') [fintype m] [fintype n] (α : Type v) : Ty
2525
m → n → α
2626

2727
variables {l m n o : Type*} [fintype l] [fintype m] [fintype n] [fintype o]
28+
variables {m' : o → Type*} [∀ i, fintype (m' i)]
29+
variables {n' : o → Type*} [∀ i, fintype (n' i)]
2830
variables {α : Type v}
2931

3032
namespace matrix
@@ -1123,9 +1125,12 @@ section has_zero
11231125

11241126
variables [has_zero α]
11251127

1126-
/-- `matrix.block_diagonal M` turns `M : o → matrix m n α'` into a
1127-
`m × o`-by`n × o` block matrix which has the entries of `M` along the diagonal
1128-
and zero elsewhere. -/
1128+
/-- `matrix.block_diagonal M` turns a homogenously-indexed collection of matrices
1129+
`M : o → matrix m n α'` into a `m × o`-by-`n × o` block matrix which has the entries of `M` along
1130+
the diagonal and zero elsewhere.
1131+
1132+
See also `matrix.block_diagonal'` if the matrices may not have the same size everywhere.
1133+
-/
11291134
def block_diagonal : matrix (m × o) (n × o) α
11301135
| ⟨i, k⟩ ⟨j, k'⟩ := if k = k' then M k i j else 0
11311136

@@ -1143,7 +1148,7 @@ lemma block_diagonal_apply_ne (i j) {k k'} (h : k ≠ k') :
11431148
if_neg h
11441149

11451150
@[simp] lemma block_diagonal_transpose :
1146-
(block_diagonal M)ᵀ = (block_diagonal (λ k, (M k)ᵀ)) :=
1151+
(block_diagonal M)ᵀ = block_diagonal (λ k, (M k)ᵀ) :=
11471152
begin
11481153
ext,
11491154
simp only [transpose_apply, block_diagonal_apply, eq_comm],
@@ -1157,16 +1162,16 @@ end
11571162
by { ext, simp [block_diagonal_apply] }
11581163

11591164
@[simp] lemma block_diagonal_diagonal [decidable_eq m] (d : o → m → α) :
1160-
(block_diagonal (λ k, diagonal (d k))) = diagonal (λ ik, d ik.2 ik.1) :=
1165+
block_diagonal (λ k, diagonal (d k)) = diagonal (λ ik, d ik.2 ik.1) :=
11611166
begin
11621167
ext ⟨i, k⟩ ⟨j, k'⟩,
11631168
simp only [block_diagonal_apply, diagonal],
11641169
split_ifs; finish
11651170
end
11661171

11671172
@[simp] lemma block_diagonal_one [decidable_eq m] [has_one α] :
1168-
(block_diagonal (1 : o → matrix m m α)) = 1 :=
1169-
show (block_diagonal (λ (_ : o), diagonal (λ (_ : m), (1 : α)))) = diagonal (λ _, 1),
1173+
block_diagonal (1 : o → matrix m m α) = 1 :=
1174+
show block_diagonal (λ (_ : o), diagonal (λ (_ : m), (1 : α))) = diagonal (λ _, 1),
11701175
by rw [block_diagonal_diagonal]
11711176

11721177
end has_zero
@@ -1191,8 +1196,8 @@ end
11911196
block_diagonal (M - N) = block_diagonal M - block_diagonal N :=
11921197
by simp [sub_eq_add_neg]
11931198

1194-
@[simp] lemma block_diagonal_mul {p : Type*} [fintype p] [semiring α]
1195-
(N : o → matrix n p α) : block_diagonal (λ k, M k ⬝ N k) = block_diagonal M ⬝ block_diagonal N :=
1199+
@[simp] lemma block_diagonal_mul {p : Type*} [fintype p] [semiring α] (N : o → matrix n p α) :
1200+
block_diagonal (λ k, M k ⬝ N k) = block_diagonal M ⬝ block_diagonal N :=
11961201
begin
11971202
ext ⟨i, k⟩ ⟨j, k'⟩,
11981203
simp only [block_diagonal_apply, mul_apply, ← finset.univ_product_univ, finset.sum_product],
@@ -1205,6 +1210,114 @@ by { ext, simp only [block_diagonal_apply, pi.smul_apply, smul_apply], split_ifs
12051210

12061211
end block_diagonal
12071212

1213+
section block_diagonal'
1214+
1215+
variables (M N : Π i, matrix (m' i) (n' i) α) [decidable_eq o]
1216+
1217+
section has_zero
1218+
1219+
variables [has_zero α]
1220+
1221+
/-- `matrix.block_diagonal' M` turns `M : Π i, matrix (m i) (n i) α` into a
1222+
`Σ i, m i`-by-`Σ i, n i` block matrix which has the entries of `M` along the diagonal
1223+
and zero elsewhere.
1224+
1225+
This is the dependently-typed version of `matrix.block_diagonal`. -/
1226+
def block_diagonal' : matrix (Σ i, m' i) (Σ i, n' i) α
1227+
| ⟨k, i⟩ ⟨k', j⟩ := if h : k = k' then M k i (cast (congr_arg n' h.symm) j) else 0
1228+
1229+
lemma block_diagonal'_eq_block_diagonal (M : o → matrix m n α) {k k'} (i j) :
1230+
block_diagonal M (i, k) (j, k') = block_diagonal' M ⟨k, i⟩ ⟨k', j⟩ :=
1231+
rfl
1232+
1233+
lemma block_diagonal'_minor_eq_block_diagonal (M : o → matrix m n α) :
1234+
(block_diagonal' M).minor (prod.to_sigma ∘ prod.swap) (prod.to_sigma ∘ prod.swap) =
1235+
block_diagonal M :=
1236+
matrix.ext $ λ ⟨k, i⟩ ⟨k', j⟩, rfl
1237+
1238+
lemma block_diagonal'_apply (ik jk) :
1239+
block_diagonal' M ik jk = if h : ik.1 = jk.1 then
1240+
M ik.1 ik.2 (cast (congr_arg n' h.symm) jk.2) else 0 :=
1241+
by { cases ik, cases jk, refl }
1242+
1243+
@[simp]
1244+
lemma block_diagonal'_apply_eq (k i j) :
1245+
block_diagonal' M ⟨k, i⟩ ⟨k, j⟩ = M k i j :=
1246+
dif_pos rfl
1247+
1248+
lemma block_diagonal'_apply_ne {k k'} (i j) (h : k ≠ k') :
1249+
block_diagonal' M ⟨k, i⟩ ⟨k', j⟩ = 0 :=
1250+
dif_neg h
1251+
1252+
@[simp] lemma block_diagonal'_transpose :
1253+
(block_diagonal' M)ᵀ = block_diagonal' (λ k, (M k)ᵀ) :=
1254+
begin
1255+
ext ⟨ii, ix⟩ ⟨ji, jx⟩,
1256+
simp only [transpose_apply, block_diagonal'_apply, eq_comm],
1257+
dsimp only,
1258+
split_ifs with h₁ h₂ h₂,
1259+
{ subst h₁, refl, },
1260+
{ exact (h₂ h₁.symm).elim },
1261+
{ exact (h₁ h₂.symm).elim },
1262+
{ refl }
1263+
end
1264+
1265+
@[simp] lemma block_diagonal'_zero :
1266+
block_diagonal' (0 : Π i, matrix (m' i) (n' i) α) = 0 :=
1267+
by { ext, simp [block_diagonal'_apply] }
1268+
1269+
@[simp] lemma block_diagonal'_diagonal [∀ i, decidable_eq (m' i)] (d : Π i, m' i → α) :
1270+
block_diagonal' (λ k, diagonal (d k)) = diagonal (λ ik, d ik.1 ik.2) :=
1271+
begin
1272+
ext ⟨i, k⟩ ⟨j, k'⟩,
1273+
simp only [block_diagonal'_apply, diagonal],
1274+
split_ifs; finish
1275+
end
1276+
1277+
@[simp] lemma block_diagonal'_one [∀ i, decidable_eq (m' i)] [has_one α] :
1278+
block_diagonal' (1 : Π i, matrix (m' i) (m' i) α) = 1 :=
1279+
show block_diagonal' (λ (i : o), diagonal (λ (_ : m' i), (1 : α))) = diagonal (λ _, 1),
1280+
by rw [block_diagonal'_diagonal]
1281+
1282+
end has_zero
1283+
1284+
@[simp] lemma block_diagonal'_add [add_monoid α] :
1285+
block_diagonal' (M + N) = block_diagonal' M + block_diagonal' N :=
1286+
begin
1287+
ext,
1288+
simp only [block_diagonal'_apply, add_apply],
1289+
split_ifs; simp
1290+
end
1291+
1292+
@[simp] lemma block_diagonal'_neg [add_group α] :
1293+
block_diagonal' (-M) = - block_diagonal' M :=
1294+
begin
1295+
ext,
1296+
simp only [block_diagonal'_apply, neg_apply],
1297+
split_ifs; simp
1298+
end
1299+
1300+
@[simp] lemma block_diagonal'_sub [add_group α] :
1301+
block_diagonal' (M - N) = block_diagonal' M - block_diagonal' N :=
1302+
by simp [sub_eq_add_neg]
1303+
1304+
@[simp] lemma block_diagonal'_mul {p : o → Type*} [Π i, fintype (p i)] [semiring α]
1305+
(N : Π i, matrix (n' i) (p i) α) :
1306+
block_diagonal' (λ k, M k ⬝ N k) = block_diagonal' M ⬝ block_diagonal' N :=
1307+
begin
1308+
ext ⟨k, i⟩ ⟨k', j⟩,
1309+
simp only [block_diagonal'_apply, mul_apply, ← finset.univ_sigma_univ, finset.sum_sigma],
1310+
rw fintype.sum_eq_single k,
1311+
{ split_ifs; simp },
1312+
{ intros j' hj', exact finset.sum_eq_zero (λ _ _, by rw [dif_neg hj'.symm, zero_mul]) },
1313+
end
1314+
1315+
@[simp] lemma block_diagonal'_smul {R : Type*} [semiring R] [add_comm_monoid α] [semimodule R α]
1316+
(x : R) : block_diagonal' (x • M) = x • block_diagonal' M :=
1317+
by { ext, simp only [block_diagonal'_apply, pi.smul_apply, smul_apply], split_ifs; simp }
1318+
1319+
end block_diagonal'
1320+
12081321
end matrix
12091322

12101323
namespace ring_hom

0 commit comments

Comments
 (0)