Skip to content

Commit 99a7dcf

Browse files
SnirBroshijoelriou
authored andcommitted
feat(LinearAlgebra/Matrix/Nondegenerate): more API and generalize to non-domains (leanprover-community#39634)
- Syntactically generalize the bilinear form identities to non-square matrices - Prove iff and transpose theorems for `SeparatingLeft`/`SeparatingRight`/`Nondegenerate` - Prove `M *ᵥ v = 0 → v = 0` and `v ᵥ* M = 0 → v = 0` given `Nondegenerate` (extracted from the existing `eq_zero_of_*_eq_zero`) - Generalize `M.det ≠ 0 → M.Nondegenerate` to `M.det ∈ R⁰ → M.Nondegenerate` (over any `CommRing`) - Add `M *ᵥ v = 0 → v = 0` and `v ᵥ* M = 0 → v = 0` theorems given `M.det ∈ R⁰` - Allow `NonUnitalNonAssocSemiring`s in the `def`s
1 parent ed84fd3 commit 99a7dcf

3 files changed

Lines changed: 139 additions & 65 deletions

File tree

Mathlib/Data/Matrix/Mul.lean

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,13 +1093,13 @@ theorem vecMul_transpose [Fintype n] (A : Matrix m n α) (x : n → α) : x ᵥ*
10931093
apply dotProduct_comm
10941094

10951095
/-- Bilinear form identity: `x ⬝ᵥ Aᵀ *ᵥ y = y ⬝ᵥ A *ᵥ x` for commutative semirings. -/
1096-
theorem dotProduct_transpose_mulVec [Fintype m] (A : Matrix m m α) (x y : m → α) :
1097-
x ⬝ᵥ Aᵀ *ᵥ y = y ⬝ᵥ A *ᵥ x := by
1096+
theorem dotProduct_transpose_mulVec [Fintype m] [Fintype n] (A : Matrix m n α) (x : n → α)
1097+
(y : m → α) : x ⬝ᵥ Aᵀ *ᵥ y = y ⬝ᵥ A *ᵥ x := by
10981098
rw [dotProduct_mulVec, dotProduct_comm, vecMul_transpose]
10991099

11001100
/-- Bilinear form identity: `(x ᵥ* Aᵀ) ⬝ᵥ y = (y ᵥ* A) ⬝ᵥ x` for commutative semirings. -/
1101-
theorem dotProduct_vecMul_transpose [Fintype m] (A : Matrix m m α) (x y : m → α) :
1102-
(x ᵥ* Aᵀ) ⬝ᵥ y = (y ᵥ* A) ⬝ᵥ x := by
1101+
theorem dotProduct_vecMul_transpose [Fintype m] [Fintype n] (A : Matrix m n α) (x : n → α)
1102+
(y : m → α) : (x ᵥ* Aᵀ) ⬝ᵥ y = (y ᵥ* A) ⬝ᵥ x := by
11031103
simpa [dotProduct_mulVec] using dotProduct_transpose_mulVec (A := A) (x := x) (y := y)
11041104

11051105
theorem mulVec_vecMul [Fintype n] [Fintype o] (A : Matrix m n α) (B : Matrix o n α) (x : o → α) :

Mathlib/LinearAlgebra/Matrix/Nondegenerate.lean

Lines changed: 95 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace Matrix
2626

2727
section Finite
2828

29-
variable {m n R A : Type*} [CommRing R] [Finite m] [Finite n] (M : Matrix m n R)
29+
variable {m n R A : Type*} [NonUnitalNonAssocSemiring R] [Finite m] [Finite n] (M : Matrix m n R)
3030

3131
attribute [local instance] Fintype.ofFinite
3232

@@ -39,29 +39,87 @@ def SeparatingLeft : Prop :=
3939
(∀ v, (∀ w, v ⬝ᵥ M *ᵥ w = 0) → v = 0)
4040

4141
/-- A matrix `M` is nondegenerate if it is both left-separating and right-separating. -/
42+
@[mk_iff]
4243
structure Nondegenerate (M : Matrix m n R) : Prop where
4344
separatingLeft : SeparatingLeft M
4445
separatingRight : SeparatingRight M
4546

4647
end Finite
4748

48-
variable {m n R A : Type*} [CommRing R] [Fintype m] [Fintype n] [CommRing A] [IsDomain A]
49-
{M : Matrix m n R}
49+
variable {m n R : Type*} [CommRing R] {M : Matrix m n R}
5050

51-
lemma separatingRight_def : M.SeparatingRight ↔ (∀ w, (∀ v, v ⬝ᵥ M *ᵥ w = 0) → w = 0) := by
51+
lemma separatingRight_def [Fintype m] [Fintype n] :
52+
M.SeparatingRight ↔ (∀ w, (∀ v, v ⬝ᵥ M *ᵥ w = 0) → w = 0) := by
5253
refine forall_congr' fun w ↦ ⟨fun hM hw ↦ hM ?_, fun hM hw ↦ hM ?_⟩ <;>
5354
convert! hw
5455

55-
lemma separatingLeft_def : M.SeparatingLeft ↔ (∀ v, (∀ w, v ⬝ᵥ M *ᵥ w = 0) → v = 0) := by
56+
lemma separatingLeft_def [Fintype m] [Fintype n] :
57+
M.SeparatingLeft ↔ (∀ v, (∀ w, v ⬝ᵥ M *ᵥ w = 0) → v = 0) := by
5658
refine forall_congr' fun v ↦ ⟨fun hM hv ↦ hM ?_, fun hM hv ↦ hM ?_⟩ <;>
5759
convert! hv
5860

59-
lemma nondegenerate_def : M.Nondegenerate ↔
60-
(∀ v, (∀ w, v ⬝ᵥ M *ᵥ w = 0) → v = 0) ∧ (∀ w, (∀ v, v ⬝ᵥ M *ᵥ w = 0) → w = 0) := by
61+
lemma nondegenerate_def [Fintype m] [Fintype n] :
62+
M.Nondegenerate ↔
63+
(∀ v, (∀ w, v ⬝ᵥ M *ᵥ w = 0) → v = 0) ∧ (∀ w, (∀ v, v ⬝ᵥ M *ᵥ w = 0) → w = 0) := by
6164
constructor
6265
· exact fun h ↦ ⟨separatingLeft_def.mp h.1, separatingRight_def.mp h.2
6366
· exact fun h ↦ ⟨separatingLeft_def.mpr h.1, separatingRight_def.mpr h.2
6467

68+
theorem separatingLeft_iff_forall_vecMul_eq_zero [Fintype m] [Finite n] :
69+
M.SeparatingLeft ↔ ∀ v, v ᵥ* M = 0 → v = 0 := by
70+
have := Fintype.ofFinite n
71+
rw [separatingLeft_def]
72+
refine ⟨fun h v hv ↦ h v fun w ↦ ?_, fun h w hw ↦ h w <| funext fun i ↦ ?_⟩
73+
· simp [dotProduct_mulVec, hv]
74+
· classical simpa using! hw <| Pi.single i 1
75+
76+
theorem separatingRight_iff_forall_mulVec_eq_zero [Finite m] [Fintype n] :
77+
M.SeparatingRight ↔ ∀ v, M *ᵥ v = 0 → v = 0 := by
78+
have := Fintype.ofFinite m
79+
rw [separatingRight_def]
80+
refine ⟨fun h v hv ↦ h v fun w ↦ ?_, fun h w hw ↦ h w <| funext fun i ↦ ?_⟩
81+
· simp [hv]
82+
· classical simpa using hw <| Pi.single i 1
83+
84+
theorem SeparatingLeft.eq_zero_of_vecMul_eq_zero [Fintype m] [Finite n] (hM : M.SeparatingLeft)
85+
{v : m → R} (hv : v ᵥ* M = 0) : v = 0 :=
86+
separatingLeft_iff_forall_vecMul_eq_zero.mp hM v hv
87+
88+
theorem SeparatingRight.eq_zero_of_mulVec_eq_zero [Finite m] [Fintype n] (hM : M.SeparatingRight)
89+
{v : n → R} (hv : M *ᵥ v = 0) : v = 0 :=
90+
separatingRight_iff_forall_mulVec_eq_zero.mp hM v hv
91+
92+
theorem nondegenerate_iff_forall_vecMul_and_mulVec_eq_zero [Fintype m] [Fintype n] :
93+
M.Nondegenerate ↔ (∀ v, v ᵥ* M = 0 → v = 0) ∧ (∀ v, M *ᵥ v = 0 → v = 0) := by
94+
rw [nondegenerate_iff, separatingLeft_iff_forall_vecMul_eq_zero,
95+
separatingRight_iff_forall_mulVec_eq_zero]
96+
97+
@[simp]
98+
theorem separatingLeft_transpose_iff [Finite m] [Finite n] :
99+
Mᵀ.SeparatingLeft ↔ M.SeparatingRight := by
100+
have := Fintype.ofFinite m
101+
have := Fintype.ofFinite n
102+
simp_rw [separatingLeft_def, separatingRight_def, dotProduct_transpose_mulVec]
103+
104+
alias ⟨_, SeparatingRight.separatingLeft_transpose⟩ := separatingLeft_transpose_iff
105+
106+
@[simp]
107+
theorem separatingRight_transpose_iff [Finite m] [Finite n] :
108+
Mᵀ.SeparatingRight ↔ M.SeparatingLeft := by
109+
have := Fintype.ofFinite m
110+
have := Fintype.ofFinite n
111+
simp_rw [separatingRight_def, separatingLeft_def, dotProduct_transpose_mulVec]
112+
113+
alias ⟨_, SeparatingLeft.separatingRight_transpose⟩ := separatingRight_transpose_iff
114+
115+
@[simp]
116+
theorem nondegenerate_transpose_iff [Finite m] [Finite n] : Mᵀ.Nondegenerate ↔ M.Nondegenerate := by
117+
simp [nondegenerate_iff, and_comm]
118+
119+
alias ⟨_, Nondegenerate.transpose⟩ := nondegenerate_transpose_iff
120+
121+
variable [Fintype m] [Fintype n]
122+
65123
/-- If `M` is nondegenerate and `w * M * v = 0` for all `w`, then `v = 0`. -/
66124
theorem Nondegenerate.eq_zero_of_ortho (hM : Nondegenerate M) {v : m → R}
67125
(hv : ∀ w, v ⬝ᵥ M *ᵥ w = 0) : v = 0 :=
@@ -73,42 +131,51 @@ theorem Nondegenerate.exists_not_ortho_of_ne_zero (hM : Nondegenerate M)
73131
not_forall.mp (mt hM.eq_zero_of_ortho hv)
74132

75133
/-- If `M` is nondegenerate and `w * M * v = 0` for all `v`, then `w = 0`. -/
76-
theorem Nondegenerate.eq_zero_of_ortho' {M : Matrix m n R} (hM : Nondegenerate M) {w : n → R}
134+
theorem Nondegenerate.eq_zero_of_ortho' (hM : Nondegenerate M) {w : n → R}
77135
(hw : ∀ v, v ⬝ᵥ M *ᵥ w = 0) : w = 0 :=
78136
(nondegenerate_def.mp hM).2 w hw
79137

80138
/-- If `M` is nondegenerate and `w ≠ 0`, then there is some `v` such that `v * M * w ≠ 0`. -/
81-
theorem Nondegenerate.exists_not_ortho_of_ne_zero' {M : Matrix m n R} (hM : Nondegenerate M)
82-
{w : n → R} (hw : w ≠ 0) : ∃ v, v ⬝ᵥ M *ᵥ w ≠ 0 :=
139+
theorem Nondegenerate.exists_not_ortho_of_ne_zero' (hM : Nondegenerate M) {w : n → R} (hw : w ≠ 0) :
140+
∃ v, v ⬝ᵥ M *ᵥ w ≠ 0 :=
83141
not_forall.mp (mt hM.eq_zero_of_ortho' hw)
84142

85143
section Determinant
86-
variable [DecidableEq m] {M : Matrix m m A}
144+
variable [DecidableEq m] {M : Matrix m m R}
145+
146+
open scoped nonZeroDivisors
147+
148+
private theorem SeparatingLeft.of_det_mem_nonZeroDivisors (hM : M.det ∈ R⁰) : M.SeparatingLeft := by
149+
refine separatingLeft_def.mpr fun v h ↦ funext fun i ↦ mem_nonZeroDivisors_iff_left.mp hM _ ?_
150+
simpa using h <| M.cramer <| Pi.single i 1
151+
152+
theorem Nondegenerate.of_det_mem_nonZeroDivisors (hM : M.det ∈ R⁰) : M.Nondegenerate where
153+
separatingLeft := .of_det_mem_nonZeroDivisors hM
154+
separatingRight := separatingLeft_transpose_iff.mp <| .of_det_mem_nonZeroDivisors <| by simpa
87155

88-
/-- If `M` is square and has nonzero determinant, then `M` as a bilinear form on `n → A` is
156+
/-- If `M` is square and has nonzero determinant, then `M` as a bilinear form on `n → R` is
89157
nondegenerate. The "iff" implication, `nondegenerate_iff_det_ne_zero`, is proved in a later file.
90158
91159
See also `BilinForm.nondegenerateOfDetNeZero'` and `BilinForm.nondegenerateOfDetNeZero`.
92160
-/
93-
theorem nondegenerate_of_det_ne_zero (hM : M.det ≠ 0) : Nondegenerate M := by
94-
refine nondegenerate_def.mpr ⟨fun v h ↦ ?_, fun w h ↦ ?_⟩
95-
· ext i
96-
specialize h (M.cramer (Pi.single i 1))
97-
simp_all
98-
· ext i
99-
contrapose! h
100-
use Pi.single i 1 ᵥ* M.adjugate
101-
rw [dotProduct_mulVec, vecMul_vecMul, adjugate_mul]
102-
simp_all [dotProduct, smul_apply, smul_eq_mul, Matrix.one_apply]
103-
104-
theorem eq_zero_of_vecMul_eq_zero (hM : M.det ≠ 0) {v : m → A}
161+
theorem nondegenerate_of_det_ne_zero [NoZeroDivisors R] (hM : M.det ≠ 0) : M.Nondegenerate :=
162+
.of_det_mem_nonZeroDivisors <| mem_nonZeroDivisors_of_ne_zero hM
163+
164+
theorem eq_zero_of_det_mem_nonZeroDivisors_of_vecMul_eq_zero (hM : M.det ∈ R⁰)
165+
{v : m → R} (hv : v ᵥ* M = 0) : v = 0 :=
166+
Nondegenerate.of_det_mem_nonZeroDivisors hM |>.separatingLeft.eq_zero_of_vecMul_eq_zero hv
167+
168+
theorem eq_zero_of_vecMul_eq_zero [NoZeroDivisors R] (hM : M.det ≠ 0) {v : m → R}
105169
(hv : v ᵥ* M = 0) : v = 0 :=
106-
(nondegenerate_of_det_ne_zero hM).eq_zero_of_ortho fun w => by
107-
rw [dotProduct_mulVec, hv, zero_dotProduct]
170+
nondegenerate_of_det_ne_zero hM |>.separatingLeft.eq_zero_of_vecMul_eq_zero hv
171+
172+
theorem eq_zero_of_det_mem_nonZeroDivisors_of_mulVec_eq_zero (hM : M.det ∈ R⁰)
173+
{v : m → R} (hv : M *ᵥ v = 0) : v = 0 :=
174+
Nondegenerate.of_det_mem_nonZeroDivisors hM |>.separatingRight.eq_zero_of_mulVec_eq_zero hv
108175

109-
theorem eq_zero_of_mulVec_eq_zero (hM : M.det ≠ 0) {v : m → A}
176+
theorem eq_zero_of_mulVec_eq_zero [NoZeroDivisors R] (hM : M.det ≠ 0) {v : m → R}
110177
(hv : M *ᵥ v = 0) : v = 0 :=
111-
eq_zero_of_vecMul_eq_zero (by rwa [det_transpose]) ((vecMul_transpose M v).trans hv)
178+
nondegenerate_of_det_ne_zero hM |>.separatingRight.eq_zero_of_mulVec_eq_zero hv
112179

113180
end Determinant
114181

Mathlib/LinearAlgebra/Matrix/ToLinearEquiv.lean

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -158,54 +158,61 @@ private theorem exists_mulVec_eq_zero_iff' {A : Type*} (K : Type*) [DecidableEq
158158
RingHom.mapMatrix_apply, Pi.smul_apply, smul_eq_mul, Algebra.smul_def]
159159
· rw [mulVec_smul, mul_eq, Pi.smul_apply, Pi.zero_apply, smul_zero]
160160

161-
theorem exists_mulVec_eq_zero_iff {A : Type*} [DecidableEq n] [CommRing A] [IsDomain A]
162-
{M : Matrix n n A} : (∃ v ≠ 0, M *ᵥ v = 0) ↔ M.det = 0 :=
161+
variable {A : Type*} [CommRing A] [IsDomain A] {M N : Matrix n n A}
162+
163+
theorem exists_mulVec_eq_zero_iff [DecidableEq n] : (∃ v ≠ 0, M *ᵥ v = 0) ↔ M.det = 0 :=
163164
exists_mulVec_eq_zero_iff' (FractionRing A)
164165

165-
theorem exists_vecMul_eq_zero_iff {A : Type*} [DecidableEq n] [CommRing A] [IsDomain A]
166-
{M : Matrix n n A} : (∃ v ≠ 0, v ᵥ* M = 0) ↔ M.det = 0 := by
166+
theorem exists_vecMul_eq_zero_iff [DecidableEq n] : (∃ v ≠ 0, v ᵥ* M = 0) ↔ M.det = 0 := by
167167
simpa only [← M.det_transpose, ← mulVec_transpose] using exists_mulVec_eq_zero_iff
168168

169-
theorem nondegenerate_iff_det_ne_zero {A : Type*} [DecidableEq n] [CommRing A] [IsDomain A]
170-
{M : Matrix n n A} : Nondegenerate M ↔ M.det ≠ 0 := by
171-
refine ⟨?_, nondegenerate_of_det_ne_zero⟩
172-
rw [ne_eq, ← exists_vecMul_eq_zero_iff]
173-
push Not
174-
intro hM v hv hMv
175-
obtain ⟨w, hwMv⟩ := hM.exists_not_ortho_of_ne_zero hv
176-
simp [dotProduct_mulVec, hMv, zero_dotProduct, ne_eq] at hwMv
177-
178-
lemma separatingLeft_iff_det_ne_zero {A : Type*} [DecidableEq n] [CommRing A] [IsDomain A]
179-
{M : Matrix n n A} : SeparatingLeft M ↔ M.det ≠ 0 := by
180-
refine ⟨fun h hc ↦ ?_, fun h ↦ (nondegenerate_of_det_ne_zero h).1
181-
obtain ⟨v, hvne, hv⟩ := exists_vecMul_eq_zero_iff.mpr hc
182-
refine hvne (separatingLeft_def.mp h v ?_)
183-
simp [dotProduct_mulVec, hv]
184-
185-
lemma separatingRight_iff_det_ne_zero {A : Type*} [DecidableEq n] [CommRing A] [IsDomain A]
186-
{M : Matrix n n A} : SeparatingRight M ↔ M.det ≠ 0 := by
187-
refine ⟨fun h hc ↦ ?_, fun h ↦ (nondegenerate_of_det_ne_zero h).2
188-
obtain ⟨v, hvne, hv⟩ := exists_mulVec_eq_zero_iff.mpr hc
189-
refine hvne (separatingRight_def.mp h v ?_)
190-
simp [hv]
191-
192-
theorem Nondegenerate.mul_iff_right {A : Type*} [CommRing A] [IsDomain A]
193-
{M N : Matrix n n A} (h : N.Nondegenerate) :
169+
theorem nondegenerate_iff_det_ne_zero [DecidableEq n] : Nondegenerate M ↔ M.det ≠ 0 := by
170+
grind [nondegenerate_iff_forall_vecMul_and_mulVec_eq_zero, exists_mulVec_eq_zero_iff,
171+
exists_vecMul_eq_zero_iff]
172+
173+
lemma separatingLeft_iff_det_ne_zero [DecidableEq n] : SeparatingLeft M ↔ M.det ≠ 0 := by
174+
grind [separatingLeft_iff_forall_vecMul_eq_zero, exists_vecMul_eq_zero_iff]
175+
176+
lemma separatingRight_iff_det_ne_zero [DecidableEq n] : SeparatingRight M ↔ M.det ≠ 0 := by
177+
grind [separatingRight_iff_forall_mulVec_eq_zero, exists_mulVec_eq_zero_iff]
178+
179+
omit [Fintype n] in
180+
theorem nondegenerate_iff_separatingLeft [Finite n] : M.Nondegenerate ↔ M.SeparatingLeft := by
181+
classical
182+
have := Fintype.ofFinite n
183+
rw [nondegenerate_iff_det_ne_zero, separatingLeft_iff_det_ne_zero]
184+
185+
alias ⟨_, SeparatingLeft.nondegenerate⟩ := nondegenerate_iff_separatingLeft
186+
187+
omit [Fintype n] in
188+
theorem nondegenerate_iff_separatingRight [Finite n] : M.Nondegenerate ↔ M.SeparatingRight := by
189+
classical
190+
have := Fintype.ofFinite n
191+
rw [nondegenerate_iff_det_ne_zero, separatingRight_iff_det_ne_zero]
192+
193+
alias ⟨_, SeparatingRight.nondegenerate⟩ := nondegenerate_iff_separatingRight
194+
195+
omit [Fintype n] in
196+
theorem separatingLeft_iff_separatingRight [Finite n] : M.SeparatingLeft ↔ M.SeparatingRight :=
197+
nondegenerate_iff_separatingLeft.symm.trans nondegenerate_iff_separatingRight
198+
199+
alias ⟨SeparatingLeft.separatingRight, SeparatingRight.separatingLeft⟩ :=
200+
separatingLeft_iff_separatingRight
201+
202+
theorem Nondegenerate.mul_iff_right (h : N.Nondegenerate) :
194203
(M * N).Nondegenerate ↔ M.Nondegenerate := by
195204
classical
196205
simp only [nondegenerate_iff_det_ne_zero, det_mul] at h ⊢
197206
exact mul_ne_zero_iff_right h
198207

199-
theorem Nondegenerate.mul_iff_left {A : Type*} [CommRing A] [IsDomain A]
200-
{M N : Matrix n n A} (h : M.Nondegenerate) :
208+
theorem Nondegenerate.mul_iff_left (h : M.Nondegenerate) :
201209
(M * N).Nondegenerate ↔ N.Nondegenerate := by
202210
classical
203211
simp only [nondegenerate_iff_det_ne_zero, det_mul] at h ⊢
204212
exact mul_ne_zero_iff_left h
205213

206214
omit [Fintype n] in
207-
theorem Nondegenerate.smul_iff [Finite n] {A : Type*} [CommRing A] [IsDomain A]
208-
{M : Matrix n n A} {t : A} (h : t ≠ 0) :
215+
theorem Nondegenerate.smul_iff [Finite n] {t : A} (h : t ≠ 0) :
209216
(t • M).Nondegenerate ↔ M.Nondegenerate := by
210217
have := Fintype.ofFinite
211218
rw [nondegenerate_def, nondegenerate_def]

0 commit comments

Comments
 (0)