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

Commit 790e98f

Browse files
committed
feat(linear_algebra/matrix/is_diag): add a file (#9010)
Co-authored-by: l534zhan <84618936+l534zhan@users.noreply.github.com>
1 parent 9af1db3 commit 790e98f

File tree

2 files changed

+260
-0
lines changed

2 files changed

+260
-0
lines changed
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/-
2+
Copyright (c) 2021 Lu-Ming Zhang. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Lu-Ming Zhang
5+
-/
6+
import linear_algebra.matrix.symmetric
7+
import linear_algebra.matrix.orthogonal
8+
import data.matrix.kronecker
9+
10+
/-!
11+
# Diagonal matrices
12+
13+
This file contains the definition and basic results about diagonal matrices.
14+
15+
## Main results
16+
17+
- `matrix.is_diag`: a proposition that states a given square matrix `A` is diagonal.
18+
19+
## Tags
20+
21+
diag, diagonal, matrix
22+
-/
23+
24+
namespace matrix
25+
26+
variables {α β R n m : Type*}
27+
28+
open function
29+
open_locale matrix kronecker
30+
31+
/-- `A.is_diag` means square matrix `A` is a diagonal matrix. -/
32+
def is_diag [has_zero α] (A : matrix n n α) : Prop := ∀ ⦃i j⦄, i ≠ j → A i j = 0
33+
34+
@[simp] lemma is_diag_diagonal [has_zero α] [decidable_eq n] (d : n → α) :
35+
(diagonal d).is_diag :=
36+
λ i j, matrix.diagonal_apply_ne
37+
38+
/-- Diagonal matrices are generated by `matrix.diagonal`. -/
39+
lemma is_diag.exists_diagonal [has_zero α] [decidable_eq n] {A : matrix n n α} (h : A.is_diag) :
40+
∃ d, diagonal d = A :=
41+
begin
42+
refine ⟨λ i, A i i, ext $ λ i j, _⟩,
43+
obtain rfl | hij := decidable.eq_or_ne i j,
44+
{ rw diagonal_apply_eq },
45+
{ rw [diagonal_apply_ne hij, h hij] },
46+
end
47+
48+
/-- `matrix.is_diag.exists_diagonal` as an iff. -/
49+
lemma is_diag_iff_exists_diagonal [has_zero α] [decidable_eq n] (A : matrix n n α) :
50+
A.is_diag ↔ (∃ d, diagonal d = A) :=
51+
⟨is_diag.exists_diagonal, λ ⟨d, hd⟩, hd ▸ is_diag_diagonal d⟩
52+
53+
/-- Every matrix indexed by a subsingleton is diagonal. -/
54+
lemma is_diag_of_subsingleton [has_zero α] [subsingleton n] (A : matrix n n α) : A.is_diag :=
55+
λ i j h, (h $ subsingleton.elim i j).elim
56+
57+
/-- Every zero matrix is diagonal. -/
58+
@[simp] lemma is_diag_zero [has_zero α] : (0 : matrix n n α).is_diag :=
59+
λ i j h, rfl
60+
61+
/-- Every identity matrix is diagonal. -/
62+
@[simp] lemma is_diag_one [decidable_eq n] [has_zero α] [has_one α] :
63+
(1 : matrix n n α).is_diag :=
64+
λ i j, one_apply_ne
65+
66+
lemma is_diag.map [has_zero α] [has_zero β]
67+
{A : matrix n n α} (ha : A.is_diag) {f : α → β} (hf : f 0 = 0) :
68+
(A.map f).is_diag :=
69+
by { intros i j h, simp [ha h, hf] }
70+
71+
lemma is_diag.neg [add_group α] {A : matrix n n α} (ha : A.is_diag) :
72+
(-A).is_diag :=
73+
by { intros i j h, simp [ha h] }
74+
75+
@[simp] lemma is_diag_neg_iff [add_group α] {A : matrix n n α} :
76+
(-A).is_diag ↔ A.is_diag :=
77+
⟨ λ ha i j h, neg_eq_zero.1 (ha h), is_diag.neg ⟩
78+
79+
lemma is_diag.add
80+
[add_zero_class α] {A B : matrix n n α} (ha : A.is_diag) (hb : B.is_diag) :
81+
(A + B).is_diag :=
82+
by { intros i j h, simp [ha h, hb h] }
83+
84+
lemma is_diag.sub [add_group α]
85+
{A B : matrix n n α} (ha : A.is_diag) (hb : B.is_diag) :
86+
(A - B).is_diag :=
87+
by { intros i j h, simp [ha h, hb h] }
88+
89+
lemma is_diag.smul [monoid R] [add_monoid α] [distrib_mul_action R α]
90+
(k : R) {A : matrix n n α} (ha : A.is_diag) :
91+
(k • A).is_diag :=
92+
by { intros i j h, simp [ha h] }
93+
94+
@[simp] lemma is_diag_smul_one (n) [semiring α] [decidable_eq n] (k : α) :
95+
(k • (1 : matrix n n α)).is_diag :=
96+
is_diag_one.smul k
97+
98+
lemma is_diag.transpose [has_zero α] {A : matrix n n α} (ha : A.is_diag) : Aᵀ.is_diag :=
99+
λ i j h, ha h.symm
100+
101+
@[simp] lemma is_diag_transpose_iff [has_zero α] {A : matrix n n α} :
102+
Aᵀ.is_diag ↔ A.is_diag :=
103+
⟨ is_diag.transpose, is_diag.transpose ⟩
104+
105+
lemma is_diag.conj_transpose
106+
[semiring α] [star_ring α] {A : matrix n n α} (ha : A.is_diag) :
107+
Aᴴ.is_diag :=
108+
ha.transpose.map (star_zero _)
109+
110+
@[simp] lemma is_diag_conj_transpose_iff [semiring α] [star_ring α] {A : matrix n n α} :
111+
Aᴴ.is_diag ↔ A.is_diag :=
112+
⟨ λ ha, by {convert ha.conj_transpose, simp}, is_diag.conj_transpose ⟩
113+
114+
lemma is_diag.minor [has_zero α]
115+
{A : matrix n n α} (ha : A.is_diag) {f : m → n} (hf : injective f) :
116+
(A.minor f f).is_diag :=
117+
λ i j h, ha (hf.ne h)
118+
119+
/-- `(A ⊗ B).is_diag` if both `A` and `B` are diagonal. -/
120+
lemma is_diag.kronecker [mul_zero_class α]
121+
{A : matrix m m α} {B : matrix n n α} (hA : A.is_diag) (hB : B.is_diag) :
122+
(A ⊗ₖ B).is_diag :=
123+
begin
124+
rintros ⟨a, b⟩ ⟨c, d⟩ h,
125+
simp only [prod.mk.inj_iff, ne.def, not_and_distrib] at h,
126+
cases h with hac hbd,
127+
{ simp [hA hac] },
128+
{ simp [hB hbd] },
129+
end
130+
131+
lemma is_diag.is_symm [has_zero α] {A : matrix n n α} (h : A.is_diag) :
132+
A.is_symm :=
133+
begin
134+
ext i j,
135+
by_cases g : i = j, { rw g },
136+
simp [h g, h (ne.symm g)],
137+
end
138+
139+
/-- The block matrix `A.from_blocks 0 0 D` is diagonal if `A` and `D` are diagonal. -/
140+
lemma is_diag.from_blocks [has_zero α]
141+
{A : matrix m m α} {D : matrix n n α}
142+
(ha : A.is_diag) (hd : D.is_diag) :
143+
(A.from_blocks 0 0 D).is_diag :=
144+
begin
145+
rintros (i | i) (j | j) hij,
146+
{ exact ha (ne_of_apply_ne _ hij) },
147+
{ refl },
148+
{ refl },
149+
{ exact hd (ne_of_apply_ne _ hij) },
150+
end
151+
152+
/-- This is the `iff` version of `matrix.is_diag.from_blocks`. -/
153+
lemma is_diag_from_blocks_iff [has_zero α]
154+
{A : matrix m m α} {B : matrix m n α} {C : matrix n m α} {D : matrix n n α} :
155+
(A.from_blocks B C D).is_diag ↔ A.is_diag ∧ B = 0 ∧ C = 0 ∧ D.is_diag :=
156+
begin
157+
split,
158+
{ intros h,
159+
refine ⟨λ i j hij, _, ext $ λ i j, _, ext $ λ i j, _, λ i j hij, _⟩,
160+
{ exact h (sum.inl_injective.ne hij), },
161+
{ exact h sum.inl_ne_inr, },
162+
{ exact h sum.inr_ne_inl, },
163+
{ exact h (sum.inr_injective.ne hij), }, },
164+
{ rintros ⟨ha, hb, hc, hd⟩,
165+
convert is_diag.from_blocks ha hd }
166+
end
167+
168+
/-- A symmetric block matrix `A.from_blocks B C D` is diagonal
169+
if `A` and `D` are diagonal and `B` is `0`. -/
170+
lemma is_diag.from_blocks_of_is_symm [has_zero α]
171+
{A : matrix m m α} {C : matrix n m α} {D : matrix n n α}
172+
(h : (A.from_blocks 0 C D).is_symm) (ha : A.is_diag) (hd : D.is_diag) :
173+
(A.from_blocks 0 C D).is_diag :=
174+
begin
175+
rw ←(is_symm_from_blocks_iff.1 h).2.1,
176+
exact ha.from_blocks hd,
177+
end
178+
179+
lemma mul_transpose_self_is_diag_iff_has_orthogonal_rows
180+
[fintype n] [has_mul α] [add_comm_monoid α] {A : matrix m n α} :
181+
(A ⬝ Aᵀ).is_diag ↔ A.has_orthogonal_rows :=
182+
iff.rfl
183+
184+
lemma transpose_mul_self_is_diag_iff_has_orthogonal_cols
185+
[fintype m] [has_mul α] [add_comm_monoid α] {A : matrix m n α} :
186+
(Aᵀ ⬝ A).is_diag ↔ A.has_orthogonal_cols :=
187+
iff.rfl
188+
189+
end matrix
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/-
2+
Copyright (c) 2021 Lu-Ming Zhang. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Lu-Ming Zhang
5+
-/
6+
import data.matrix.basic
7+
8+
/-!
9+
# Orthogonal
10+
11+
This file contains definitions and properties concerning orthogonality of rows and columns.
12+
13+
## Main results
14+
15+
- `matrix.has_orthogonal_rows`:
16+
`A.has_orthogonal_rows` means `A` has orthogonal (with respect to `dot_product`) rows.
17+
- `matrix.has_orthogonal_cols`:
18+
`A.has_orthogonal_cols` means `A` has orthogonal (with respect to `dot_product`) columns.
19+
20+
## Tags
21+
22+
orthogonal
23+
-/
24+
25+
namespace matrix
26+
27+
variables {α n m : Type*}
28+
variables [has_mul α] [add_comm_monoid α]
29+
variables (A : matrix m n α)
30+
31+
open_locale matrix
32+
33+
/-- `A.has_orthogonal_rows` means matrix `A` has orthogonal rows (with respect to
34+
`matrix.dot_product`). -/
35+
def has_orthogonal_rows [fintype n] : Prop :=
36+
∀ ⦃i₁ i₂⦄, i₁ ≠ i₂ → dot_product (A i₁) (A i₂) = 0
37+
38+
/-- `A.has_orthogonal_rows` means matrix `A` has orthogonal columns (with respect to
39+
`matrix.dot_product`). -/
40+
def has_orthogonal_cols [fintype m] : Prop :=
41+
has_orthogonal_rows Aᵀ
42+
43+
/-- `Aᵀ` has orthogonal rows iff `A` has orthogonal columns. -/
44+
@[simp] lemma transpose_has_orthogonal_rows_iff_has_orthogonal_cols [fintype m] :
45+
Aᵀ.has_orthogonal_rows ↔ A.has_orthogonal_cols :=
46+
iff.rfl
47+
48+
/-- `Aᵀ` has orthogonal columns iff `A` has orthogonal rows. -/
49+
@[simp] lemma transpose_has_orthogonal_cols_iff_has_orthogonal_rows [fintype n] :
50+
Aᵀ.has_orthogonal_cols ↔ A.has_orthogonal_rows :=
51+
iff.rfl
52+
53+
variables {A}
54+
55+
lemma has_orthogonal_rows.has_orthogonal_cols
56+
[fintype m] (h : Aᵀ.has_orthogonal_rows) :
57+
A.has_orthogonal_cols := h
58+
59+
lemma has_orthogonal_cols.transpose_has_orthogonal_rows
60+
[fintype m] (h : A.has_orthogonal_cols) :
61+
Aᵀ.has_orthogonal_rows := h
62+
63+
lemma has_orthogonal_cols.has_orthogonal_rows
64+
[fintype n] (h : Aᵀ.has_orthogonal_cols) :
65+
A.has_orthogonal_rows := h
66+
67+
lemma has_orthogonal_rows.transpose_has_orthogonal_cols
68+
[fintype n] (h : A.has_orthogonal_rows) :
69+
Aᵀ.has_orthogonal_cols := h
70+
71+
end matrix

0 commit comments

Comments
 (0)