|
| 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 |
0 commit comments