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

Commit bba8473

Browse files
VierkantorChrisHughes24sgouezelmergify[bot]
committed
feat(linear_algebra): Matrix inverses for square nonsingular matrices (#1816)
* Prove that some matrices have inverses * Finish the proof: show that the determinant is 0 if a column is repeated * Show that nonsingular_inv is also a right inverse * Cleanup and code movement * Small lemmata on transpose * WIP: some work on inverse matrices * Code cleanup and documentation * More cleanup and documentation * Generalize det_zero_of_column_eq to remove the linear order assumption * Fix linting issues. * Unneeded import can be removed * A little bit more cleanup * Generalize nonsing_inv to any ring with inverse * Improve comments for `nonsingular_inverse` * Remove the less general `det_zero_of_column_eq_of_char_ne_two` proof * Rename `cramer_map_val` -> `cramer_map_def` Co-Authored-By: Chris Hughes <33847686+ChrisHughes24@users.noreply.github.com> * whitespace Co-Authored-By: Chris Hughes <33847686+ChrisHughes24@users.noreply.github.com> * whitespace: indent tactic proofs * More renaming `cramer_map_val` -> `cramer_map_def` * `swap_mul_self_mul` can be a `simp` lemma * Make parameter σ to `swap_mul_eq_iff` implicit * Update usage of `function.update_same` and `function.update_noteq` * Replace `det_permute` with `det_permutation` Although the statement now gives the determinant of a permutation matrix, the proof is easier if we write it as a permuted identity matrix. Thus the proof is basically the same, except a different line showing that the entries are the same. * Re-introduce `matrix.det_permute` (now based on `matrix.det_permutation`) * Delete `cramer_at` and clean up the proofs depending on it * Replace `cramer_map` with `cramer` after defining `cramer` * Apply suggestions from code review Co-Authored-By: sgouezel <sebastien.gouezel@univ-rennes1.fr> * Clean up imports * Formatting: move } to previous lines * Move assumptions of `det_zero_of_repeated_column` from variable to argument * whitespace Insert space between `finset.filter` and the filter condition. Co-Authored-By: sgouezel <sebastien.gouezel@univ-rennes1.fr> * Improve docstrings * Make argument to `prod_cancels_of_partition_cancels` explicit * Rename `replace_column` and `replace_row` to `update_column` and `update_row` * Replace `update_column_eq` with `update_column_self` + rewriting step * whitespace Newlines between all lemmas * whitespace Newline before 'begin' * Fix conflicts with latest mathlib * Remove unnecessary explicitification of arguments Co-authored-by: Chris Hughes <33847686+ChrisHughes24@users.noreply.github.com> Co-authored-by: sgouezel <sebastien.gouezel@univ-rennes1.fr> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent 5f01591 commit bba8473

File tree

8 files changed

+508
-9
lines changed

8 files changed

+508
-9
lines changed

src/algebra/big_operators.lean

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,28 @@ calc s.prod (λ x, h (if p x then f x else g x))
229229
(prod_congr rfl (by simp {contextual := tt}))
230230
(prod_congr rfl (by simp {contextual := tt}))
231231

232-
@[simp, to_additive] lemma prod_ite_eq [decidable_eq α] (s : finset α) (a : α) (b : β) :
233-
s.prod (λ x, (ite (a = x) b 1)) = ite (a ∈ s) b 1 :=
232+
@[simp, to_additive] lemma prod_ite_eq [decidable_eq α] (s : finset α) (a : α) (b : α → β) :
233+
s.prod (λ x, (ite (a = x) (b x) 1)) = ite (a ∈ s) (b a) 1 :=
234234
begin
235235
rw ←finset.prod_filter,
236236
split_ifs;
237237
simp only [filter_eq, if_true, if_false, h, prod_empty, prod_singleton, insert_empty_eq_singleton],
238238
end
239239

240+
/--
241+
When a product is taken over a conditional whose condition is an equality test on the index
242+
and whose alternative is 1, then the product's value is either the term at that index or `1`.
243+
244+
The difference with `prod_ite_eq` is that the arguments to `eq` are swapped.
245+
-/
246+
@[simp, to_additive] lemma prod_ite_eq' [decidable_eq α] (s : finset α) (a : α) (b : α → β) :
247+
s.prod (λ x, (ite (x = a) (b x) 1)) = ite (a ∈ s) (b a) 1 :=
248+
begin
249+
rw ←prod_ite_eq,
250+
congr, ext x,
251+
by_cases x = a; finish
252+
end
253+
240254
@[to_additive]
241255
lemma prod_attach {f : α → β} : s.attach.prod (λx, f x.val) = s.prod f :=
242256
by haveI := classical.dec_eq α; exact
@@ -458,6 +472,22 @@ begin
458472
congr' 1,
459473
rw mul_comm }
460474
end
475+
476+
/-- If we can partition a product into subsets that cancel out, then the whole product cancels. -/
477+
@[to_additive]
478+
lemma prod_cancels_of_partition_cancels (R : setoid α) [decidable_rel R.r]
479+
(h : ∀ x ∈ s, (s.filter (λy, y ≈ x)).prod f = 1) : s.prod f = 1 :=
480+
begin
481+
suffices : (s.image quotient.mk).prod (λ xbar, (s.filter (λ y, ⟦y⟧ = xbar)).prod f) = s.prod f,
482+
{ rw [←this, ←finset.prod_eq_one],
483+
intros xbar xbar_in_s,
484+
rcases (mem_image).mp xbar_in_s with ⟨x, x_in_s, xbar_eq_x⟩,
485+
rw [←xbar_eq_x, filter_congr (λ y _, @quotient.eq _ R y x)],
486+
apply h x x_in_s },
487+
apply finset.prod_image' f,
488+
intros,
489+
refl
490+
end
461491

462492
end comm_monoid
463493

@@ -574,14 +604,14 @@ lemma mul_sum : b * s.sum f = s.sum (λx, b * f x) :=
574604
@[simp] lemma sum_mul_boole [decidable_eq α] (s : finset α) (f : α → β) (a : α) :
575605
s.sum (λ x, (f x * ite (a = x) 1 0)) = ite (a ∈ s) (f a) 0 :=
576606
begin
577-
convert sum_ite_eq s a (f a),
607+
convert sum_ite_eq s a f,
578608
funext,
579609
split_ifs with h; simp [h],
580610
end
581611
@[simp] lemma sum_boole_mul [decidable_eq α] (s : finset α) (f : α → β) (a : α) :
582612
s.sum (λ x, (ite (a = x) 1 0) * f x) = ite (a ∈ s) (f a) 0 :=
583613
begin
584-
convert sum_ite_eq s a (f a),
614+
convert sum_ite_eq s a f,
585615
funext,
586616
split_ifs with h; simp [h],
587617
end

src/data/finset.lean

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,11 @@ noncomputable instance {α : Type*} : has_sep α (finset α) := ⟨λ p x, x.fil
791791

792792
end classical
793793

794+
/--
795+
After filtering out everything that does not equal a given value, at most that value remains.
796+
797+
This is equivalent to `filter_eq'` with the equality the other way.
798+
-/
794799
-- This is not a good simp lemma, as it would prevent `finset.mem_filter` from firing
795800
-- on, e.g. `x ∈ s.filter(eq b)`.
796801
lemma filter_eq [decidable_eq β] (s : finset β) (b : β) :
@@ -805,6 +810,15 @@ begin
805810
rintros m ⟨e⟩, exact h m, }
806811
end
807812

813+
/--
814+
After filtering out everything that does not equal a given value, at most that value remains.
815+
816+
This is equivalent to `filter_eq` with the equality the other way.
817+
-/
818+
lemma filter_eq' [decidable_eq β] (s : finset β) (b : β) :
819+
s.filter (λ a, a = b) = ite (b ∈ s) {b} ∅ :=
820+
trans (filter_congr (λ _ _, ⟨eq.symm, eq.symm⟩)) (filter_eq s b)
821+
808822
end filter
809823

810824
/-! ### range -/

src/data/matrix/basic.lean

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,21 +293,33 @@ section transpose
293293

294294
open_locale matrix
295295

296+
/--
297+
Tell `simp` what the entries are in a transposed matrix.
298+
299+
Compare with `mul_val`, `diagonal_val_eq`, etc.
300+
-/
301+
@[simp] lemma transpose_val (M : matrix m n α) (i j) : M.transpose j i = M i j := rfl
302+
296303
@[simp] lemma transpose_transpose (M : matrix m n α) :
297304
Mᵀᵀ = M :=
298305
by ext; refl
299306

300307
@[simp] lemma transpose_zero [has_zero α] : (0 : matrix m n α)ᵀ = 0 :=
301308
by ext i j; refl
302309

303-
@[simp] lemma transpose_add [has_add α] (M : matrix m n α) (N : matrix m n α) :
304-
(M + N)ᵀ = Mᵀ + Nᵀ :=
310+
@[simp] lemma transpose_one [decidable_eq n] [has_zero α] [has_one α] : (1 : matrix n n α)ᵀ = 1 :=
305311
begin
306312
ext i j,
307-
dsimp [transpose],
308-
refl
313+
unfold has_one.one transpose,
314+
by_cases i = j,
315+
{ simp only [h, diagonal_val_eq] },
316+
{ simp only [diagonal_val_ne h, diagonal_val_ne (λ p, h (symm p))] }
309317
end
310318

319+
@[simp] lemma transpose_add [has_add α] (M : matrix m n α) (N : matrix m n α) :
320+
(M + N)ᵀ = Mᵀ + Nᵀ :=
321+
by { ext i j, simp }
322+
311323
@[simp] lemma transpose_mul [comm_ring α] (M : matrix m n α) (N : matrix n l α) :
312324
(M ⬝ N)ᵀ = Nᵀ ⬝ Mᵀ :=
313325
begin
@@ -318,6 +330,10 @@ begin
318330
ac_refl
319331
end
320332

333+
@[simp] lemma transpose_smul [comm_ring α] (c : α)(M : matrix m n α) :
334+
(c • M)ᵀ = c • Mᵀ :=
335+
by { ext i j, refl }
336+
321337
@[simp] lemma transpose_neg [comm_ring α] (M : matrix m n α) :
322338
(- M)ᵀ = - Mᵀ :=
323339
by ext i j; refl

src/data/matrix/pequiv.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ begin
7676
simp [h, eq_comm] {contextual := tt} }
7777
end
7878

79+
lemma to_pequiv_mul_matrix [semiring α] (f : n ≃ n) (M : matrix n n α) :
80+
(f.to_pequiv.to_matrix * M) = λ i, M (f i) :=
81+
by { ext i j, rw [mul_eq_mul, mul_matrix_apply, equiv.to_pequiv_apply] }
82+
7983
lemma to_matrix_trans [semiring α] (f : l ≃. m) (g : m ≃. n) :
8084
((f.trans g).to_matrix : matrix l n α) = f.to_matrix ⬝ g.to_matrix :=
8185
begin
@@ -128,4 +132,9 @@ by rw [← to_matrix_trans, single_trans_single_of_ne hb, to_matrix_bot]
128132
(single a c).to_matrix ⬝ M :=
129133
by rw [← matrix.mul_assoc, single_mul_single]
130134

135+
/-- We can also define permutation matrices by permuting the rows of the identity matrix. -/
136+
lemma equiv_to_pequiv_to_matrix [has_one α] [has_zero α] (σ : equiv n n) (i j : n) :
137+
σ.to_pequiv.to_matrix i j = (1 : matrix n n α) (σ i) j :=
138+
if_congr option.some_inj rfl rfl
139+
131140
end pequiv

src/data/pequiv.lean

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,4 +326,6 @@ lemma to_pequiv_trans (f : α ≃ β) (g : β ≃ γ) : (f.trans g).to_pequiv =
326326

327327
lemma to_pequiv_symm (f : α ≃ β) : f.symm.to_pequiv = f.to_pequiv.symm := rfl
328328

329+
lemma to_pequiv_apply (f : α ≃ β) (x : α) : f.to_pequiv x = some (f x) := rfl
330+
329331
end equiv

src/group_theory/perm/sign.lean

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,19 @@ by rw [swap_mul_eq_mul_swap, inv_apply_self, inv_apply_self]
161161
@[simp] lemma swap_mul_self (i j : α) : equiv.swap i j * equiv.swap i j = 1 :=
162162
equiv.swap_swap i j
163163

164+
/-- Multiplying a permutation with `swap i j` twice gives the original permutation.
165+
166+
This specialization of `swap_mul_self` is useful when using cosets of permutations.
167+
-/
168+
@[simp]
169+
lemma swap_mul_self_mul (i j : α) (σ : perm α) : equiv.swap i j * (equiv.swap i j * σ) = σ :=
170+
by rw [←mul_assoc (swap i j) (swap i j) σ, equiv.perm.swap_mul_self, one_mul]
171+
172+
lemma swap_mul_eq_iff {i j : α} {σ : perm α} : swap i j * σ = σ ↔ i = j :=
173+
⟨(assume h, have swap_id : swap i j = 1 := mul_right_cancel (trans h (one_mul σ).symm),
174+
by {rw [←swap_apply_right i j, swap_id], refl}),
175+
(assume h, by erw [h, swap_self, one_mul])⟩
176+
164177
@[simp] lemma swap_swap_apply (i j k : α) : equiv.swap i j (equiv.swap i j k) = k :=
165178
equiv.swap_core_swap_core k i j
166179

src/linear_algebra/determinant.lean

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/-
22
Copyright (c) 2018 Kenny Lau. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
4-
Authors: Kenny Lau, Chris Hughes
4+
Authors: Kenny Lau, Chris Hughes, Tim Baanen
55
-/
66
import data.matrix.basic
7+
import data.matrix.pequiv
78
import group_theory.perm.sign
89

910
universes u v
@@ -15,6 +16,7 @@ variables {n : Type u} [fintype n] [decidable_eq n] {R : Type v} [comm_ring R]
1516

1617
local notation ` σ:max := ((sign σ : ℤ ) : R)
1718

19+
/-- The determinant of a matrix given by the Leibniz formula. -/
1820
definition det (M : matrix n n R) : R :=
1921
univ.sum (λ (σ : perm n), ε σ * univ.prod (λ i, M (σ i) i))
2022

@@ -103,4 +105,95 @@ instance : is_monoid_hom (det : matrix n n R → R) :=
103105
{ map_one := det_one,
104106
map_mul := det_mul }
105107

108+
/-- Transposing a matrix preserves the determinant. -/
109+
@[simp] lemma det_transpose (M : matrix n n R) : M.transpose.det = M.det :=
110+
begin
111+
apply sum_bij (λ σ _, σ⁻¹),
112+
{ intros σ _, apply mem_univ },
113+
{ intros σ _,
114+
rw [sign_inv],
115+
congr' 1,
116+
apply prod_bij (λ i _, σ i),
117+
{ intros i _, apply mem_univ },
118+
{ intros i _, simp },
119+
{ intros i j _ _ h, simp at h, assumption },
120+
{ intros i _, use σ⁻¹ i, finish } },
121+
{ intros σ σ' _ _ h, simp at h, assumption },
122+
{ intros σ _, use σ⁻¹, finish }
123+
end
124+
125+
/-- The determinant of a permutation matrix equals its sign. -/
126+
@[simp] lemma det_permutation (σ : perm n) :
127+
matrix.det (σ.to_pequiv.to_matrix : matrix n n R) = σ.sign := begin
128+
suffices : matrix.det (σ.to_pequiv.to_matrix) = ↑σ.sign * det (1 : matrix n n R), { simp [this] },
129+
unfold det,
130+
rw mul_sum,
131+
apply sum_bij (λ τ _, σ * τ),
132+
{ intros τ _, apply mem_univ },
133+
{ intros τ _,
134+
conv_lhs { rw [←one_mul (sign τ), ←int.units_pow_two (sign σ)] },
135+
conv_rhs { rw [←mul_assoc, coe_coe, sign_mul, units.coe_mul, int.cast_mul, ←mul_assoc] },
136+
congr,
137+
{ norm_num },
138+
{ ext i, apply pequiv.equiv_to_pequiv_to_matrix } },
139+
{ intros τ τ' _ _, exact (mul_left_inj σ).mp },
140+
{ intros τ _, use σ⁻¹ * τ, use (mem_univ _), exact (mul_inv_cancel_left _ _).symm }
141+
end
142+
143+
/-- Permuting the columns changes the sign of the determinant. -/
144+
lemma det_permute (σ : perm n) (M : matrix n n R) : matrix.det (λ i, M (σ i)) = σ.sign * M.det :=
145+
by rw [←det_permutation, ←det_mul, pequiv.to_pequiv_mul_matrix]
146+
147+
section det_zero
148+
/-! ### `det_zero` section
149+
150+
Prove that a matrix with a repeated column has determinant equal to zero.
151+
-/
152+
153+
/--
154+
`mod_swap i j` contains permutations up to swapping `i` and `j`.
155+
156+
We use this to partition permutations in the expression for the determinant,
157+
such that each partitions sums up to `0`.
158+
-/
159+
def mod_swap {n : Type u} [decidable_eq n] (i j : n) : setoid (perm n) :=
160+
⟨ λ σ τ, σ = τ ∨ σ = swap i j * τ,
161+
λ σ, or.inl (refl σ),
162+
λ σ τ h, or.cases_on h (λ h, or.inl h.symm) (λ h, or.inr (by rw [h, swap_mul_self_mul])),
163+
λ σ τ υ hστ hτυ, by cases hστ; cases hτυ; try {rw [hστ, hτυ, swap_mul_self_mul]}; finish⟩
164+
165+
instance (i j : n) : decidable_rel (mod_swap i j).r := λ σ τ, or.decidable
166+
167+
variables {M : matrix n n R} {i j : n}
168+
169+
/-- If a matrix has a repeated column, the determinant will be zero. -/
170+
theorem det_zero_of_column_eq (i_ne_j : i ≠ j) (hij : M i = M j) : M.det = 0 :=
171+
begin
172+
have swap_invariant : ∀ k, M (swap i j k) = M k,
173+
{ intros k,
174+
rw [swap_apply_def],
175+
by_cases k = i, { rw [if_pos h, h, ←hij] },
176+
rw [if_neg h],
177+
by_cases k = j, { rw [if_pos h, h, hij] },
178+
rw [if_neg h] },
179+
180+
have : ∀ σ, _root_.disjoint (_root_.singleton σ) (_root_.singleton (swap i j * σ)),
181+
{ intros σ,
182+
rw [finset.singleton_eq_singleton, finset.singleton_eq_singleton, disjoint_singleton],
183+
apply (not_congr mem_singleton).mpr,
184+
exact (not_congr swap_mul_eq_iff).mpr i_ne_j },
185+
186+
apply finset.sum_cancels_of_partition_cancels (mod_swap i j),
187+
intros σ _,
188+
erw [filter_or, filter_eq', filter_eq', if_pos (mem_univ σ), if_pos (mem_univ (swap i j * σ)),
189+
sum_union (this σ), sum_singleton, sum_singleton],
190+
convert add_right_neg (↑↑(sign σ) * finset.prod univ (λ (i : n), M (σ i) i)),
191+
rw [neg_mul_eq_neg_mul],
192+
congr,
193+
{ rw [sign_mul, sign_swap i_ne_j], norm_num },
194+
ext j, rw [mul_apply, swap_invariant]
195+
end
196+
197+
end det_zero
198+
106199
end matrix

0 commit comments

Comments
 (0)