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

Commit 3d58fce

Browse files
committed
feat(linear_algebra): determinant of matrix.block_diagonal (#4300)
This PR shows the determinant of `matrix.block_diagonal` is the product of the determinant of each subblock. The only contributing permutations in the expansion of the determinant are those which map each block to the same block. Each of those permutations has the form `equiv.prod_congr_left σ`. Using `equiv.perm.extend` and `equiv.prod_congr_right`, we can compute the sign of `equiv.prod_congr_left σ`, and with a bit of algebraic manipulation we reach the conclusion.
1 parent 13e9cc4 commit 3d58fce

File tree

5 files changed

+253
-8
lines changed

5 files changed

+253
-8
lines changed

src/algebra/big_operators/basic.lean

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,16 @@ end comm_group_with_zero
10341034

10351035
end finset
10361036

1037+
namespace list
1038+
1039+
@[to_additive] lemma prod_to_finset {M : Type*} [decidable_eq α] [comm_monoid M]
1040+
(f : α → M) : ∀ {l : list α} (hl : l.nodup), l.to_finset.prod f = (l.map f).prod
1041+
| [] _ := by simp
1042+
| (a :: l) hl := let ⟨not_mem, hl⟩ := list.nodup_cons.mp hl in
1043+
by simp [finset.prod_insert (mt list.mem_to_finset.mp not_mem), prod_to_finset hl]
1044+
1045+
end list
1046+
10371047
namespace multiset
10381048
variables [decidable_eq α]
10391049

@@ -1090,3 +1100,15 @@ begin
10901100
end
10911101

10921102
end multiset
1103+
1104+
@[simp, norm_cast] lemma nat.coe_prod {R : Type*} [comm_semiring R]
1105+
(f : α → ℕ) (s : finset α) : (↑∏ i in s, f i : R) = ∏ i in s, f i :=
1106+
(nat.cast_ring_hom R).map_prod _ _
1107+
1108+
@[simp, norm_cast] lemma int.coe_prod {R : Type*} [comm_ring R]
1109+
(f : α → ℤ) (s : finset α) : (↑∏ i in s, f i : R) = ∏ i in s, f i :=
1110+
(int.cast_ring_hom R).map_prod _ _
1111+
1112+
@[simp, norm_cast] lemma units.coe_prod {M : Type*} [comm_monoid M]
1113+
(f : α → units M) (s : finset α) : (↑∏ i in s, f i : M) = ∏ i in s, f i :=
1114+
(units.coe_hom M).map_prod _ _

src/data/equiv/basic.lean

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,93 @@ def sigma_equiv_prod_of_equiv {α β} {β₁ : α → Sort*} (F : Π a, β₁ a
758758

759759
end
760760

761+
section prod_congr
762+
763+
variables {α₁ β₁ β₂ : Type*} (e : α₁ → β₁ ≃ β₂)
764+
765+
/-- A family of equivalences `Π (a : α₁), β₁ ≃ β₂` generates an equivalence
766+
between `β₁ × α₁` and `β₂ × α₁`. -/
767+
def prod_congr_left : β₁ × α₁ ≃ β₂ × α₁ :=
768+
{ to_fun := λ ab, ⟨e ab.2 ab.1, ab.2⟩,
769+
inv_fun := λ ab, ⟨(e ab.2).symm ab.1, ab.2⟩,
770+
left_inv := by { rintros ⟨a, b⟩, simp },
771+
right_inv := by { rintros ⟨a, b⟩, simp } }
772+
773+
@[simp] lemma prod_congr_left_apply (b : β₁) (a : α₁) :
774+
prod_congr_left e (b, a) = (e a b, a) := rfl
775+
776+
lemma prod_congr_refl_right (e : β₁ ≃ β₂) :
777+
prod_congr e (equiv.refl α₁) = prod_congr_left (λ _, e) :=
778+
by { ext ⟨a, b⟩ : 1, simp }
779+
780+
/-- A family of equivalences `Π (a : α₁), β₁ ≃ β₂` generates an equivalence
781+
between `α₁ × β₁` and `α₁ × β₂`. -/
782+
def prod_congr_right : α₁ × β₁ ≃ α₁ × β₂ :=
783+
{ to_fun := λ ab, ⟨ab.1, e ab.1 ab.2⟩,
784+
inv_fun := λ ab, ⟨ab.1, (e ab.1).symm ab.2⟩,
785+
left_inv := by { rintros ⟨a, b⟩, simp },
786+
right_inv := by { rintros ⟨a, b⟩, simp } }
787+
788+
@[simp] lemma prod_congr_right_apply (a : α₁) (b : β₁) :
789+
prod_congr_right e (a, b) = (a, e a b) := rfl
790+
791+
lemma prod_congr_refl_left (e : β₁ ≃ β₂) :
792+
prod_congr (equiv.refl α₁) e = prod_congr_right (λ _, e) :=
793+
by { ext ⟨a, b⟩ : 1, simp }
794+
795+
@[simp] lemma prod_congr_left_trans_prod_comm :
796+
(prod_congr_left e).trans (prod_comm _ _) = (prod_comm _ _).trans (prod_congr_right e) :=
797+
by { ext ⟨a, b⟩ : 1, simp }
798+
799+
@[simp] lemma prod_congr_right_trans_prod_comm :
800+
(prod_congr_right e).trans (prod_comm _ _) = (prod_comm _ _).trans (prod_congr_left e) :=
801+
by { ext ⟨a, b⟩ : 1, simp }
802+
803+
lemma sigma_congr_right_sigma_equiv_prod :
804+
(sigma_congr_right e).trans (sigma_equiv_prod α₁ β₂) =
805+
(sigma_equiv_prod α₁ β₁).trans (prod_congr_right e) :=
806+
by { ext ⟨a, b⟩ : 1, simp }
807+
808+
lemma sigma_equiv_prod_sigma_congr_right :
809+
(sigma_equiv_prod α₁ β₁).symm.trans (sigma_congr_right e) =
810+
(prod_congr_right e).trans (sigma_equiv_prod α₁ β₂).symm :=
811+
by { ext ⟨a, b⟩ : 1, simp }
812+
813+
end prod_congr
814+
815+
namespace perm
816+
817+
variables {α₁ β₁ β₂ : Type*} [decidable_eq α₁] (a : α₁) (e : perm β₁)
818+
819+
/-- `prod_extend_right a e` extends `e : perm β` to `perm (α × β)` by sending `(a, b)` to
820+
`(a, e b)` and keeping the other `(a', b)` fixed. -/
821+
def prod_extend_right : perm (α₁ × β₁) :=
822+
{ to_fun := λ ab, if ab.fst = a then (a, e ab.snd) else ab,
823+
inv_fun := λ ab, if ab.fst = a then (a, e⁻¹ ab.snd) else ab,
824+
left_inv := by { rintros ⟨k', x⟩, simp only, split_ifs with h; simp [h] },
825+
right_inv := by { rintros ⟨k', x⟩, simp only, split_ifs with h; simp [h] } }
826+
827+
@[simp] lemma prod_extend_right_apply_eq (b : β₁) :
828+
prod_extend_right a e (a, b) = (a, e b) := if_pos rfl
829+
830+
lemma prod_extend_right_apply_ne {a a' : α₁} (h : a' ≠ a) (b : β₁) :
831+
prod_extend_right a e (a', b) = (a', b) := if_neg h
832+
833+
lemma eq_of_prod_extend_right_ne {e : perm β₁} {a a' : α₁} {b : β₁}
834+
(h : prod_extend_right a e (a', b) ≠ (a', b)) : a' = a :=
835+
by { contrapose! h, exact prod_extend_right_apply_ne _ h _ }
836+
837+
@[simp] lemma fst_prod_extend_right (ab : α₁ × β₁) :
838+
(prod_extend_right a e ab).fst = ab.fst :=
839+
begin
840+
rw [prod_extend_right, coe_fn_mk],
841+
split_ifs with h,
842+
{ rw h },
843+
{ refl }
844+
end
845+
846+
end perm
847+
761848
section
762849
/-- The type of functions to a product `α × β` is equivalent to the type of pairs of functions
763850
`γ → α` and `γ → β`. -/

src/data/fintype/basic.lean

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,11 @@ instance pfun_fintype (p : Prop) [decidable p] (α : p → Type*)
783783
if hp : p then fintype.of_equiv (α hp) ⟨λ a _, a, λ f, f hp, λ _, rfl, λ _, rfl⟩
784784
else ⟨singleton (λ h, (hp h).elim), by simp [hp, function.funext_iff]⟩
785785

786+
@[simp] lemma finset.univ_pi_univ {α : Type*} {β : α → Type*}
787+
[decidable_eq α] [fintype α] [∀a, fintype (β a)] :
788+
finset.univ.pi (λ a : α, (finset.univ : finset (β a))) = finset.univ :=
789+
by { ext, simp }
790+
786791
lemma mem_image_univ_iff_mem_range
787792
{α β : Type*} [fintype α] [decidable_eq β] {f : α → β} {b : β} :
788793
b ∈ univ.image f ↔ b ∈ set.range f :=

src/group_theory/perm/sign.lean

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ calc sign f = sign (@subtype_perm _ f (λ x, f x ≠ x) (by simp)) :
576576

577577
def is_cycle (f : perm β) := ∃ x, f x ≠ x ∧ ∀ y, f y ≠ y → ∃ i : ℤ, (f ^ i) x = y
578578

579-
lemma is_cycle_swap {x y : α} (hxy : x ≠ y) : is_cycle (swap x y) :=
579+
lemma is_cycle_swap {α : Type*} [decidable_eq α] {x y : α} (hxy : x ≠ y) : is_cycle (swap x y) :=
580580
⟨y, by rwa swap_apply_right,
581581
λ a (ha : ite (a = x) y (ite (a = y) x a) ≠ a),
582582
if hya : y = a then0, hya⟩
@@ -595,7 +595,7 @@ let ⟨a, ha⟩ := hg.2 x hx in
595595
let ⟨b, hb⟩ := hg.2 y hy in
596596
⟨b - a, by rw [← ha, ← mul_apply, ← gpow_add, sub_add_cancel, hb]⟩
597597

598-
lemma is_cycle_swap_mul_aux₁ : ∀ (n : ℕ) {b x : α} {f : perm α}
598+
lemma is_cycle_swap_mul_aux₁ {α : Type*} [decidable_eq α] : ∀ (n : ℕ) {b x : α} {f : perm α}
599599
(hb : (swap x (f x) * f) b ≠ b) (h : (f ^ n) (f x) = b),
600600
∃ i : ℤ, ((swap x (f x) * f) ^ i) (f x) = b
601601
| 0 := λ b x f hb h, ⟨0, h⟩
@@ -614,7 +614,7 @@ lemma is_cycle_swap_mul_aux₁ : ∀ (n : ℕ) {b x : α} {f : perm α}
614614
⟨i + 1, by rw [add_comm, gpow_add, mul_apply, hi, gpow_one, mul_apply, apply_inv_self,
615615
swap_apply_of_ne_of_ne (ne_and_ne_of_swap_mul_apply_ne_self hb).2 (ne.symm hfbx)]⟩
616616

617-
lemma is_cycle_swap_mul_aux₂ : ∀ (n : ℤ) {b x : α} {f : perm α}
617+
lemma is_cycle_swap_mul_aux₂ {α : Type*} [decidable_eq α] : ∀ (n : ℤ) {b x : α} {f : perm α}
618618
(hb : (swap x (f x) * f) b ≠ b) (h : (f ^ n) (f x) = b),
619619
∃ i : ℤ, ((swap x (f x) * f) ^ i) (f x) = b
620620
| (n : ℕ) := λ b x f, is_cycle_swap_mul_aux₁ n
@@ -636,7 +636,8 @@ lemma is_cycle_swap_mul_aux₂ : ∀ (n : ℤ) {b x : α} {f : perm α}
636636
mul_inv_rev, swap_inv, mul_swap_eq_swap_mul, inv_apply_self, swap_comm _ x, gpow_add, gpow_one,
637637
mul_apply, mul_apply (_ ^ i), h, hi, mul_apply, apply_inv_self, swap_apply_of_ne_of_ne this.2 (ne.symm hfbx')]⟩
638638

639-
lemma eq_swap_of_is_cycle_of_apply_apply_eq_self {f : perm α} (hf : is_cycle f) {x : α}
639+
lemma eq_swap_of_is_cycle_of_apply_apply_eq_self {α : Type*} [decidable_eq α]
640+
{f : perm α} (hf : is_cycle f) {x : α}
640641
(hfx : f x ≠ x) (hffx : f (f x) = x) : f = swap x (f x) :=
641642
equiv.ext $ λ y,
642643
let ⟨z, hz⟩ := hf in
@@ -653,7 +654,7 @@ else begin
653654
{ rw [← hj, hji] at hfyx, cc }
654655
end
655656

656-
lemma is_cycle_swap_mul {f : perm α} (hf : is_cycle f) {x : α}
657+
lemma is_cycle_swap_mul {α : Type*} [decidable_eq α] {f : perm α} (hf : is_cycle f) {x : α}
657658
(hx : f x ≠ x) (hffx : f (f x) ≠ x) : is_cycle (swap x (f x) * f) :=
658659
⟨f x, by simp only [swap_apply_def, mul_apply];
659660
split_ifs; simp [injective.eq_iff f.injective] at *; cc,
@@ -664,14 +665,14 @@ lemma is_cycle_swap_mul {f : perm α} (hf : is_cycle f) {x : α}
664665
... = y : by rwa [← gpow_add, sub_add_cancel],
665666
is_cycle_swap_mul_aux₂ (i - 1) hy hi⟩
666667

667-
@[simp] lemma support_swap [fintype α] {x y : α} (hxy : x ≠ y) : (swap x y).support = {x, y} :=
668+
@[simp] lemma support_swap {x y : α} (hxy : x ≠ y) : (swap x y).support = {x, y} :=
668669
finset.ext $ λ a, by simp [swap_apply_def]; split_ifs; cc
669670

670-
lemma card_support_swap [fintype α] {x y : α} (hxy : x ≠ y) : (swap x y).support.card = 2 :=
671+
lemma card_support_swap {x y : α} (hxy : x ≠ y) : (swap x y).support.card = 2 :=
671672
show (swap x y).support.card = finset.card ⟨x::y::0, by simp [hxy]⟩,
672673
from congr_arg card $ by rw [support_swap hxy]; simp [*, finset.ext_iff]; cc
673674

674-
lemma sign_cycle [fintype α] : ∀ {f : perm α} (hf : is_cycle f),
675+
lemma sign_cycle : ∀ {f : perm α} (hf : is_cycle f),
675676
sign f = -(-1) ^ f.support.card
676677
| f := λ hf,
677678
let ⟨x, hx⟩ := hf in
@@ -698,6 +699,72 @@ calc sign f = sign (swap x (f x) * (swap x (f x) * f)) :
698699
pow_one, units.neg_mul_neg]
699700
using_well_founded {rel_tac := λ _ _, `[exact ⟨_, measure_wf (λ f, f.support.card)⟩]}
700701

702+
/-- If we apply `prod_extend_right a (σ a)` for all `a : α` in turn,
703+
we get `prod_congr_right σ`. -/
704+
lemma prod_prod_extend_right {α : Type*} [decidable_eq α] (σ : α → perm β)
705+
{l : list α} (hl : l.nodup) (mem_l : ∀ a, a ∈ l) :
706+
(l.map (λ a, prod_extend_right a (σ a))).prod = prod_congr_right σ :=
707+
begin
708+
ext ⟨a, b⟩ : 1,
709+
-- We'll use induction on the list of elements,
710+
-- but we have to keep track of whether we already passed `a` in the list.
711+
suffices : (a ∈ l ∧ (l.map (λ a, prod_extend_right a (σ a))).prod (a, b) = (a, σ a b)) ∨
712+
(a ∉ l ∧ (l.map (λ a, prod_extend_right a (σ a))).prod (a, b) = (a, b)),
713+
{ obtain ⟨_, prod_eq⟩ := or.resolve_right this (not_and.mpr (λ h _, h (mem_l a))),
714+
rw [prod_eq, prod_congr_right_apply] },
715+
clear mem_l,
716+
717+
induction l with a' l ih,
718+
{ refine or.inr ⟨list.not_mem_nil _, _⟩,
719+
rw [list.map_nil, list.prod_nil, one_apply] },
720+
721+
rw [list.map_cons, list.prod_cons, mul_apply],
722+
rcases ih (list.nodup_cons.mp hl).2 with ⟨mem_l, prod_eq⟩ | ⟨not_mem_l, prod_eq⟩; rw prod_eq,
723+
{ refine or.inl ⟨list.mem_cons_of_mem _ mem_l, _⟩,
724+
rw prod_extend_right_apply_ne _ (λ (h : a = a'), (list.nodup_cons.mp hl).1 (h ▸ mem_l)) },
725+
by_cases ha' : a = a',
726+
{ rw ← ha' at *,
727+
refine or.inl ⟨l.mem_cons_self a, _⟩,
728+
rw prod_extend_right_apply_eq },
729+
{ refine or.inr ⟨λ h, not_or ha' not_mem_l ((list.mem_cons_iff _ _ _).mp h), _⟩,
730+
rw prod_extend_right_apply_ne _ ha' },
731+
end
732+
733+
section
734+
735+
open_locale classical
736+
737+
lemma sign_prod_extend_right [fintype β] (a : α) (σ : perm β) :
738+
(prod_extend_right a σ).sign = σ.sign :=
739+
sign_bij (λ (ab : α × β) _, ab.snd)
740+
(λ ⟨a', b⟩ hab hab', by simp [eq_of_prod_extend_right_ne hab])
741+
(λ ⟨a₁, b₁⟩ ⟨a₂, b₂⟩ hab₁ hab₂ h,
742+
by simpa [eq_of_prod_extend_right_ne hab₁, eq_of_prod_extend_right_ne hab₂] using h)
743+
(λ y hy, ⟨(a, y), by simpa, by simp⟩)
744+
745+
lemma sign_prod_congr_right [fintype β] (σ : α → perm β) :
746+
sign (prod_congr_right σ) = ∏ k, (σ k).sign :=
747+
begin
748+
obtain ⟨l, hl, mem_l⟩ := fintype.exists_univ_list α,
749+
have l_to_finset : l.to_finset = finset.univ,
750+
{ apply eq_top_iff.mpr,
751+
intros b _,
752+
exact list.mem_to_finset.mpr (mem_l b) },
753+
rw [← prod_prod_extend_right σ hl mem_l, sign.map_list_prod,
754+
list.map_map, ← l_to_finset, list.prod_to_finset _ hl],
755+
simp_rw ← λ a, sign_prod_extend_right a (σ a)
756+
end
757+
758+
lemma sign_prod_congr_left [fintype β] (σ : α → perm β) :
759+
sign (prod_congr_left σ) = ∏ k, (σ k).sign :=
760+
begin
761+
refine (sign_eq_sign_of_equiv _ _ (prod_comm β α) _).trans (sign_prod_congr_right σ),
762+
rintro ⟨b, α⟩,
763+
refl
764+
end
765+
766+
end
767+
701768
end sign
702769

703770
end equiv.perm

src/linear_algebra/determinant.lean

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,68 @@ begin
269269
simp [update_column_transpose, det_transpose]
270270
end
271271

272+
@[simp] lemma det_block_diagonal {o : Type*} [fintype o] [decidable_eq o] (M : o → matrix n n R) :
273+
(block_diagonal M).det = ∏ k, (M k).det :=
274+
begin
275+
-- Rewrite the determinants as a sum over permutations.
276+
unfold det,
277+
-- The right hand side is a product of sums, rewrite it as a sum of products.
278+
rw finset.prod_sum,
279+
simp_rw [finset.mem_univ, finset.prod_attach_univ, finset.univ_pi_univ],
280+
-- We claim that the only permutations contributing to the sum are those that
281+
-- preserve their second component.
282+
let preserving_snd : finset (equiv.perm (n × o)) :=
283+
finset.univ.filter (λ σ, ∀ x, (σ x).snd = x.snd),
284+
have mem_preserving_snd : ∀ {σ : equiv.perm (n × o)},
285+
σ ∈ preserving_snd ↔ ∀ x, (σ x).snd = x.snd :=
286+
λ σ, finset.mem_filter.trans ⟨λ h, h.2, λ h, ⟨finset.mem_univ _, h⟩⟩,
287+
rw ← finset.sum_subset (finset.subset_univ preserving_snd) _,
288+
-- And that these are in bijection with `o → equiv.perm m`.
289+
rw (finset.sum_bij (λ (σ : ∀ (k : o), k ∈ finset.univ → equiv.perm n) _,
290+
prod_congr_left (λ k, σ k (finset.mem_univ k))) _ _ _ _).symm,
291+
{ intros σ _,
292+
rw mem_preserving_snd,
293+
rintros ⟨k, x⟩,
294+
simp },
295+
{ intros σ _,
296+
rw finset.prod_mul_distrib,
297+
congr,
298+
{ convert congr_arg (λ (x : units ℤ), (↑x : R)) (sign_prod_congr_left (λ k, σ k _)).symm,
299+
simp, congr, ext, congr },
300+
rw [← finset.univ_product_univ, finset.prod_product, finset.prod_comm],
301+
simp },
302+
{ intros σ σ' _ _ eq,
303+
ext x hx k,
304+
simp only at eq,
305+
have : ∀ k x, prod_congr_left (λ k, σ k (finset.mem_univ _)) (k, x) =
306+
prod_congr_left (λ k, σ' k (finset.mem_univ _)) (k, x) :=
307+
λ k x, by rw eq,
308+
simp only [prod_congr_left_apply, prod.mk.inj_iff] at this,
309+
exact (this k x).1 },
310+
{ intros σ hσ,
311+
rw mem_preserving_snd at hσ,
312+
have hσ' : ∀ x, (σ⁻¹ x).snd = x.snd,
313+
{ intro x, conv_rhs { rw [← perm.apply_inv_self σ x, hσ] } },
314+
have mk_apply_eq : ∀ k x, ((σ (x, k)).fst, k) = σ (x, k),
315+
{ intros k x,
316+
ext; simp [hσ] },
317+
have mk_inv_apply_eq : ∀ k x, ((σ⁻¹ (x, k)).fst, k) = σ⁻¹ (x, k),
318+
{ intros k x,
319+
conv_lhs { rw ← perm.apply_inv_self σ (x, k) },
320+
ext; simp [hσ'] },
321+
refine ⟨λ k _, ⟨λ x, (σ (x, k)).fst, λ x, (σ⁻¹ (x, k)).fst, _, _⟩, _, _⟩,
322+
{ intro x,
323+
simp [mk_apply_eq, mk_inv_apply_eq] },
324+
{ intro x,
325+
simp [mk_apply_eq, mk_inv_apply_eq] },
326+
{ apply finset.mem_univ },
327+
{ ext ⟨k, x⟩; simp [hσ] } },
328+
{ intros σ _ hσ,
329+
rw mem_preserving_snd at hσ,
330+
obtain ⟨⟨k, x⟩, hkx⟩ := not_forall.mp hσ,
331+
rw [finset.prod_eq_zero (finset.mem_univ (k, x)), mul_zero],
332+
rw [← @prod.mk.eta _ _ (σ (k, x)), block_diagonal_apply_ne],
333+
exact hkx }
334+
end
335+
272336
end matrix

0 commit comments

Comments
 (0)