File: Mathlib/LinearAlgebra/Matrix/Transvection.lean

full_name: Matrix.transvection
code: /-- The transvection matrix `transvection i j c` is equal to the identity plus `c` at position
`(i, j)`. Multiplying by it on the left (as in `transvection i j c * M`) corresponds to adding
`c` times the `j`-th row of `M` to its `i`-th row. Multiplying by it on the right corresponds
to adding `c` times the `i`-th column to the `j`-th column. -/
def transvection (c : R) : Matrix n n R 
goal: Matrix n n R

full_name: Matrix.transvection_zero
code: @[simp]
theorem transvection_zero : transvection i j (0 : R) = 1 
goal: Matrix.transvection i j 0 = 1

full_name: Matrix.updateRow_eq_transvection
code: /-- A transvection matrix is obtained from the identity by adding `c` times the `j`-th row to
the `i`-th row. -/
theorem updateRow_eq_transvection [Finite n] (c : R) :
    updateRow (1 : Matrix n n R) i ((1 : Matrix n n R) i + c • (1 : Matrix n n R) j) =
      transvection i j c 
goal: Matrix.updateRow 1 i (1 i + c • 1 j) = Matrix.transvection i j c

full_name: Matrix.transvection_mul_transvection_same
code: theorem transvection_mul_transvection_same (h : i ≠ j) (c d : R) :
    transvection i j c * transvection i j d = transvection i j (c + d) 
goal: Matrix.transvection i j c * Matrix.transvection i j d = Matrix.transvection i j (c + d)

full_name: Matrix.transvection_mul_apply_same
code: @[simp]
theorem transvection_mul_apply_same (b : n) (c : R) (M : Matrix n n R) :
    (transvection i j c * M) i b = M i b + c * M j b 
goal: (Matrix.transvection i j c * M) i b = M i b + c * M j b

full_name: Matrix.mul_transvection_apply_same
code: @[simp]
theorem mul_transvection_apply_same (a : n) (c : R) (M : Matrix n n R) :
    (M * transvection i j c) a j = M a j + c * M a i 
goal: (M * Matrix.transvection i j c) a j = M a j + c * M a i

full_name: Matrix.transvection_mul_apply_of_ne
code: @[simp]
theorem transvection_mul_apply_of_ne (a b : n) (ha : a ≠ i) (c : R) (M : Matrix n n R) :
    (transvection i j c * M) a b = M a b 
goal: (Matrix.transvection i j c * M) a b = M a b

full_name: Matrix.mul_transvection_apply_of_ne
code: @[simp]
theorem mul_transvection_apply_of_ne (a b : n) (hb : b ≠ j) (c : R) (M : Matrix n n R) :
    (M * transvection i j c) a b = M a b 
goal: (M * Matrix.transvection i j c) a b = M a b

full_name: Matrix.det_transvection_of_ne
code: @[simp]
theorem det_transvection_of_ne (h : i ≠ j) (c : R) : det (transvection i j c) = 1 
goal: (Matrix.transvection i j c).det = 1

full_name: Matrix.TransvectionStruct.c
code: /-- A structure containing all the information from which one can build a nontrivial transvection.
This structure is easier to manipulate than transvections as one has a direct access to all the
relevant fields. -/
-- porting note (#5171): removed @[nolint has_nonempty_instance]
structure TransvectionStruct where
  (i j : n)
  hij : i ≠ j
  c : R
goal: R

full_name: Matrix.TransvectionStruct.i
code: /-- A structure containing all the information from which one can build a nontrivial transvection.
This structure is easier to manipulate than transvections as one has a direct access to all the
relevant fields. -/
-- porting note (#5171): removed @[nolint has_nonempty_instance]
structure TransvectionStruct where
  (i j : n)
  hij : i ≠ j
  c : R
goal: n

full_name: Matrix.TransvectionStruct.j
code: /-- A structure containing all the information from which one can build a nontrivial transvection.
This structure is easier to manipulate than transvections as one has a direct access to all the
relevant fields. -/
-- porting note (#5171): removed @[nolint has_nonempty_instance]
structure TransvectionStruct where
  (i j : n)
  hij : i ≠ j
  c : R
goal: n

full_name: Matrix.TransvectionStruct.hij
code: /-- A structure containing all the information from which one can build a nontrivial transvection.
This structure is easier to manipulate than transvections as one has a direct access to all the
relevant fields. -/
-- porting note (#5171): removed @[nolint has_nonempty_instance]
structure TransvectionStruct where
  (i j : n)
  hij : i ≠ j
  c : R
goal: self.i ≠ self.j

full_name: Matrix.TransvectionStruct
code: /-- A structure containing all the information from which one can build a nontrivial transvection.
This structure is easier to manipulate than transvections as one has a direct access to all the
relevant fields. -/
-- porting note (#5171): removed @[nolint has_nonempty_instance]
structure TransvectionStruct where
  (i j : n)
  hij : i ≠ j
  c : R
goal: Type (max u_1 u₂)

full_name: Matrix.instNonemptyTransvectionStructOfNontrivial
code: instance [Nontrivial n] : Nonempty (TransvectionStruct n R) 
goal: Nonempty (Matrix.TransvectionStruct n R)

full_name: Matrix.TransvectionStruct.toMatrix
code: /-- Associating to a `transvection_struct` the corresponding transvection matrix. -/
def toMatrix (t : TransvectionStruct n R) : Matrix n n R 
goal: Matrix n n R

full_name: Matrix.TransvectionStruct.toMatrix_mk
code: @[simp]
theorem toMatrix_mk (i j : n) (hij : i ≠ j) (c : R) :
    TransvectionStruct.toMatrix ⟨i, j, hij, c⟩ = transvection i j c 
goal: { i := i, j := j, hij := hij, c := c }.toMatrix = Matrix.transvection i j c

full_name: Matrix.TransvectionStruct.det
code: @[simp]
protected theorem det [Fintype n] (t : TransvectionStruct n R) : det t.toMatrix = 1 
goal: t.toMatrix.det = 1

full_name: Matrix.TransvectionStruct.det_toMatrix_prod
code: @[simp]
theorem det_toMatrix_prod [Fintype n] (L : List (TransvectionStruct n 𝕜)) :
    det (L.map toMatrix).prod = 1 
goal: (List.map Matrix.TransvectionStruct.toMatrix L).prod.det = 1

full_name: Matrix.TransvectionStruct.inv_j
code: /-- The inverse of a `TransvectionStruct`, designed so that `t.inv.toMatrix` is the inverse of
`t.toMatrix`. -/
@[simps]
protected def inv (t : TransvectionStruct n R) : TransvectionStruct n R 
goal: t.inv.j = t.j

full_name: Matrix.TransvectionStruct.inv_i
code: /-- The inverse of a `TransvectionStruct`, designed so that `t.inv.toMatrix` is the inverse of
`t.toMatrix`. -/
@[simps]
protected def inv (t : TransvectionStruct n R) : TransvectionStruct n R 
goal: t.inv.i = t.i

full_name: Matrix.TransvectionStruct.inv
code: /-- The inverse of a `TransvectionStruct`, designed so that `t.inv.toMatrix` is the inverse of
`t.toMatrix`. -/
@[simps]
protected def inv (t : TransvectionStruct n R) : TransvectionStruct n R 
goal: Matrix.TransvectionStruct n R

full_name: Matrix.TransvectionStruct.inv_c
code: /-- The inverse of a `TransvectionStruct`, designed so that `t.inv.toMatrix` is the inverse of
`t.toMatrix`. -/
@[simps]
protected def inv (t : TransvectionStruct n R) : TransvectionStruct n R 
goal: t.inv.c = -t.c

full_name: Matrix.TransvectionStruct.inv_mul
code: theorem inv_mul (t : TransvectionStruct n R) : t.inv.toMatrix * t.toMatrix = 1 
goal: t.inv.toMatrix * t.toMatrix = 1

full_name: Matrix.TransvectionStruct.mul_inv
code: theorem mul_inv (t : TransvectionStruct n R) : t.toMatrix * t.inv.toMatrix = 1 
goal: t.toMatrix * t.inv.toMatrix = 1

full_name: Matrix.TransvectionStruct.reverse_inv_prod_mul_prod
code: theorem reverse_inv_prod_mul_prod (L : List (TransvectionStruct n R)) :
    (L.reverse.map (toMatrix ∘ TransvectionStruct.inv)).prod * (L.map toMatrix).prod = 1 
goal: (List.map (Matrix.TransvectionStruct.toMatrix ∘ Matrix.TransvectionStruct.inv) L.reverse).prod *
    (List.map Matrix.TransvectionStruct.toMatrix L).prod =
  1

full_name: Matrix.TransvectionStruct.prod_mul_reverse_inv_prod
code: theorem prod_mul_reverse_inv_prod (L : List (TransvectionStruct n R)) :
    (L.map toMatrix).prod * (L.reverse.map (toMatrix ∘ TransvectionStruct.inv)).prod = 1 
goal: (List.map Matrix.TransvectionStruct.toMatrix L).prod *
    (List.map (Matrix.TransvectionStruct.toMatrix ∘ Matrix.TransvectionStruct.inv) L.reverse).prod =
  1

full_name: Matrix.mem_range_scalar_of_commute_transvectionStruct
code: /-- `M` is a scalar matrix if it commutes with every nontrivial transvection (elementary matrix). -/
theorem _root_.Matrix.mem_range_scalar_of_commute_transvectionStruct {M : Matrix n n R}
    (hM : ∀ t : TransvectionStruct n R, Commute t.toMatrix M) :
    M ∈ Set.range (Matrix.scalar n) 
goal: M ∈ Set.range ⇑(Matrix.scalar n)

full_name: Matrix.mem_range_scalar_iff_commute_transvectionStruct
code: theorem _root_.Matrix.mem_range_scalar_iff_commute_transvectionStruct {M : Matrix n n R} :
    M ∈ Set.range (Matrix.scalar n) ↔ ∀ t : TransvectionStruct n R, Commute t.toMatrix M 
goal: M ∈ Set.range ⇑(Matrix.scalar n) ↔ ∀ (t : Matrix.TransvectionStruct n R), Commute t.toMatrix M

full_name: Matrix.TransvectionStruct.sumInl
code: /-- Given a `TransvectionStruct` on `n`, define the corresponding `TransvectionStruct` on `n ⊕ p`
using the identity on `p`. -/
def sumInl (t : TransvectionStruct n R) : TransvectionStruct (n ⊕ p) R 
goal: Matrix.TransvectionStruct (n ⊕ p) R

full_name: Matrix.TransvectionStruct.toMatrix_sumInl
code: theorem toMatrix_sumInl (t : TransvectionStruct n R) :
    (t.sumInl p).toMatrix = fromBlocks t.toMatrix 0 0 1 
goal: (Matrix.TransvectionStruct.sumInl p t).toMatrix = Matrix.fromBlocks t.toMatrix 0 0 1

full_name: Matrix.TransvectionStruct.sumInl_toMatrix_prod_mul
code: @[simp]
theorem sumInl_toMatrix_prod_mul [Fintype n] [Fintype p] (M : Matrix n n R)
    (L : List (TransvectionStruct n R)) (N : Matrix p p R) :
    (L.map (toMatrix ∘ sumInl p)).prod * fromBlocks M 0 0 N =
      fromBlocks ((L.map toMatrix).prod * M) 0 0 N 
goal: (List.map (Matrix.TransvectionStruct.toMatrix ∘ Matrix.TransvectionStruct.sumInl p) L).prod *
    Matrix.fromBlocks M 0 0 N =
  Matrix.fromBlocks ((List.map Matrix.TransvectionStruct.toMatrix L).prod * M) 0 0 N

full_name: Matrix.TransvectionStruct.mul_sumInl_toMatrix_prod
code: @[simp]
theorem mul_sumInl_toMatrix_prod [Fintype n] [Fintype p] (M : Matrix n n R)
    (L : List (TransvectionStruct n R)) (N : Matrix p p R) :
    fromBlocks M 0 0 N * (L.map (toMatrix ∘ sumInl p)).prod =
      fromBlocks (M * (L.map toMatrix).prod) 0 0 N 
goal: Matrix.fromBlocks M 0 0 N *
    (List.map (Matrix.TransvectionStruct.toMatrix ∘ Matrix.TransvectionStruct.sumInl p) L).prod =
  Matrix.fromBlocks (M * (List.map Matrix.TransvectionStruct.toMatrix L).prod) 0 0 N

full_name: Matrix.TransvectionStruct.reindexEquiv
code: /-- Given a `TransvectionStruct` on `n` and an equivalence between `n` and `p`, define the
corresponding `TransvectionStruct` on `p`. -/
def reindexEquiv (e : n ≃ p) (t : TransvectionStruct n R) : TransvectionStruct p R 
goal: Matrix.TransvectionStruct p R

full_name: Matrix.TransvectionStruct.toMatrix_reindexEquiv
code: theorem toMatrix_reindexEquiv (e : n ≃ p) (t : TransvectionStruct n R) :
    (t.reindexEquiv e).toMatrix = reindexAlgEquiv R _ e t.toMatrix 
goal: (Matrix.TransvectionStruct.reindexEquiv e t).toMatrix = (Matrix.reindexAlgEquiv R R e) t.toMatrix

full_name: Matrix.TransvectionStruct.toMatrix_reindexEquiv_prod
code: theorem toMatrix_reindexEquiv_prod (e : n ≃ p) (L : List (TransvectionStruct n R)) :
    (L.map (toMatrix ∘ reindexEquiv e)).prod = reindexAlgEquiv R _ e (L.map toMatrix).prod 
goal: (List.map (Matrix.TransvectionStruct.toMatrix ∘ Matrix.TransvectionStruct.reindexEquiv e) L).prod =
  (Matrix.reindexAlgEquiv R R e) (List.map Matrix.TransvectionStruct.toMatrix L).prod

full_name: Matrix.Pivot.listTransvecCol
code: /-- A list of transvections such that multiplying on the left with these transvections will replace
the last column with zeroes. -/
def listTransvecCol : List (Matrix (Fin r ⊕ Unit) (Fin r ⊕ Unit) 𝕜) 
goal: List (Matrix (Fin r ⊕ Unit) (Fin r ⊕ Unit) 𝕜)

full_name: Matrix.Pivot.listTransvecRow
code: /-- A list of transvections such that multiplying on the right with these transvections will replace
the last row with zeroes. -/
def listTransvecRow : List (Matrix (Fin r ⊕ Unit) (Fin r ⊕ Unit) 𝕜) 
goal: List (Matrix (Fin r ⊕ Unit) (Fin r ⊕ Unit) 𝕜)

full_name: Matrix.Pivot.length_listTransvecCol
code: @[simp]
theorem length_listTransvecCol : (listTransvecCol M).length = r 
goal: (Matrix.Pivot.listTransvecCol M).length = r

full_name: Matrix.Pivot.listTransvecCol_get
code: theorem listTransvecCol_get (i : Fin (listTransvecCol M).length) :
    (listTransvecCol M).get i =
      letI i' := Fin.cast (length_listTransvecCol M) i
      transvection (inl i') (inr unit) <| -M (inl i') (inr unit) / M (inr unit) (inr unit) 
goal: (Matrix.Pivot.listTransvecCol M).get i =
  Matrix.transvection (Sum.inl (Fin.cast ⋯ i)) (Sum.inr ())
    (-M (Sum.inl (Fin.cast ⋯ i)) (Sum.inr ()) / M (Sum.inr ()) (Sum.inr ()))

full_name: Matrix.Pivot.length_listTransvecRow
code: @[simp]
theorem length_listTransvecRow : (listTransvecRow M).length = r 
goal: (Matrix.Pivot.listTransvecRow M).length = r

full_name: Matrix.Pivot.listTransvecRow_get
code: theorem listTransvecRow_get (i : Fin (listTransvecRow M).length) :
    (listTransvecRow M).get i =
      letI i' := Fin.cast (length_listTransvecRow M) i
      transvection (inr unit) (inl i') <| -M (inr unit) (inl i') / M (inr unit) (inr unit) 
goal: (Matrix.Pivot.listTransvecRow M).get i =
  Matrix.transvection (Sum.inr ()) (Sum.inl (Fin.cast ⋯ i))
    (-M (Sum.inr ()) (Sum.inl (Fin.cast ⋯ i)) / M (Sum.inr ()) (Sum.inr ()))

full_name: Matrix.Pivot.listTransvecCol_mul_last_row_drop
code: /-- Multiplying by some of the matrices in `listTransvecCol M` does not change the last row. -/
theorem listTransvecCol_mul_last_row_drop (i : Fin r ⊕ Unit) {k : ℕ} (hk : k ≤ r) :
    (((listTransvecCol M).drop k).prod * M) (inr unit) i = M (inr unit) i 
goal: ((List.drop k (Matrix.Pivot.listTransvecCol M)).prod * M) (Sum.inr ()) i = M (Sum.inr ()) i

full_name: Matrix.Pivot.listTransvecCol_mul_last_row
code: /-- Multiplying by all the matrices in `listTransvecCol M` does not change the last row. -/
theorem listTransvecCol_mul_last_row (i : Fin r ⊕ Unit) :
    ((listTransvecCol M).prod * M) (inr unit) i = M (inr unit) i 
goal: ((Matrix.Pivot.listTransvecCol M).prod * M) (Sum.inr ()) i = M (Sum.inr ()) i

full_name: Matrix.Pivot.listTransvecCol_mul_last_col
code: /-- Multiplying by all the matrices in `listTransvecCol M` kills all the coefficients in the
last column but the last one. -/
theorem listTransvecCol_mul_last_col (hM : M (inr unit) (inr unit) ≠ 0) (i : Fin r) :
    ((listTransvecCol M).prod * M) (inl i) (inr unit) = 0 
goal: ((Matrix.Pivot.listTransvecCol M).prod * M) (Sum.inl i) (Sum.inr ()) = 0

full_name: Matrix.Pivot.mul_listTransvecRow_last_col_take
code: /-- Multiplying by some of the matrices in `listTransvecRow M` does not change the last column. -/
theorem mul_listTransvecRow_last_col_take (i : Fin r ⊕ Unit) {k : ℕ} (hk : k ≤ r) :
    (M * ((listTransvecRow M).take k).prod) i (inr unit) = M i (inr unit) 
goal: (M * (List.take k (Matrix.Pivot.listTransvecRow M)).prod) i (Sum.inr ()) = M i (Sum.inr ())

full_name: Matrix.Pivot.mul_listTransvecRow_last_col
code: /-- Multiplying by all the matrices in `listTransvecRow M` does not change the last column. -/
theorem mul_listTransvecRow_last_col (i : Fin r ⊕ Unit) :
    (M * (listTransvecRow M).prod) i (inr unit) = M i (inr unit) 
goal: (M * (Matrix.Pivot.listTransvecRow M).prod) i (Sum.inr ()) = M i (Sum.inr ())

full_name: Matrix.Pivot.mul_listTransvecRow_last_row
code: /-- Multiplying by all the matrices in `listTransvecRow M` kills all the coefficients in the
last row but the last one. -/
theorem mul_listTransvecRow_last_row (hM : M (inr unit) (inr unit) ≠ 0) (i : Fin r) :
    (M * (listTransvecRow M).prod) (inr unit) (inl i) = 0 
goal: (M * (Matrix.Pivot.listTransvecRow M).prod) (Sum.inr ()) (Sum.inl i) = 0

full_name: Matrix.Pivot.listTransvecCol_mul_mul_listTransvecRow_last_col
code: /-- Multiplying by all the matrices either in `listTransvecCol M` and `listTransvecRow M` kills
all the coefficients in the last row but the last one. -/
theorem listTransvecCol_mul_mul_listTransvecRow_last_col (hM : M (inr unit) (inr unit) ≠ 0)
    (i : Fin r) :
    ((listTransvecCol M).prod * M * (listTransvecRow M).prod) (inr unit) (inl i) = 0 
goal: ((Matrix.Pivot.listTransvecCol M).prod * M * (Matrix.Pivot.listTransvecRow M).prod) (Sum.inr ()) (Sum.inl i) = 0

full_name: Matrix.Pivot.listTransvecCol_mul_mul_listTransvecRow_last_row
code: /-- Multiplying by all the matrices either in `listTransvecCol M` and `listTransvecRow M` kills
all the coefficients in the last column but the last one. -/
theorem listTransvecCol_mul_mul_listTransvecRow_last_row (hM : M (inr unit) (inr unit) ≠ 0)
    (i : Fin r) :
    ((listTransvecCol M).prod * M * (listTransvecRow M).prod) (inl i) (inr unit) = 0 
goal: ((Matrix.Pivot.listTransvecCol M).prod * M * (Matrix.Pivot.listTransvecRow M).prod) (Sum.inl i) (Sum.inr ()) = 0

full_name: Matrix.Pivot.isTwoBlockDiagonal_listTransvecCol_mul_mul_listTransvecRow
code: /-- Multiplying by all the matrices either in `listTransvecCol M` and `listTransvecRow M` turns
the matrix in block-diagonal form. -/
theorem isTwoBlockDiagonal_listTransvecCol_mul_mul_listTransvecRow
    (hM : M (inr unit) (inr unit) ≠ 0) :
    IsTwoBlockDiagonal ((listTransvecCol M).prod * M * (listTransvecRow M).prod) 
goal: ((Matrix.Pivot.listTransvecCol M).prod * M * (Matrix.Pivot.listTransvecRow M).prod).IsTwoBlockDiagonal

full_name: Matrix.Pivot.exists_isTwoBlockDiagonal_of_ne_zero
code: /-- There exist two lists of `TransvectionStruct` such that multiplying by them on the left and
on the right makes a matrix block-diagonal, when the last coefficient is nonzero. -/
theorem exists_isTwoBlockDiagonal_of_ne_zero (hM : M (inr unit) (inr unit) ≠ 0) :
    ∃ L L' : List (TransvectionStruct (Fin r ⊕ Unit) 𝕜),
      IsTwoBlockDiagonal ((L.map toMatrix).prod * M * (L'.map toMatrix).prod) 
goal: ∃ L L',
  ((List.map Matrix.TransvectionStruct.toMatrix L).prod * M *
      (List.map Matrix.TransvectionStruct.toMatrix L').prod).IsTwoBlockDiagonal

full_name: Matrix.Pivot.exists_isTwoBlockDiagonal_list_transvec_mul_mul_list_transvec
code: /-- There exist two lists of `TransvectionStruct` such that multiplying by them on the left and
on the right makes a matrix block-diagonal. -/
theorem exists_isTwoBlockDiagonal_list_transvec_mul_mul_list_transvec
    (M : Matrix (Fin r ⊕ Unit) (Fin r ⊕ Unit) 𝕜) :
    ∃ L L' : List (TransvectionStruct (Fin r ⊕ Unit) 𝕜),
      IsTwoBlockDiagonal ((L.map toMatrix).prod * M * (L'.map toMatrix).prod) 
goal: ∃ L L',
  ((List.map Matrix.TransvectionStruct.toMatrix L).prod * M *
      (List.map Matrix.TransvectionStruct.toMatrix L').prod).IsTwoBlockDiagonal

full_name: Matrix.Pivot.exists_list_transvec_mul_mul_list_transvec_eq_diagonal_induction
code: /-- Inductive step for the reduction: if one knows that any size `r` matrix can be reduced to
diagonal form by elementary operations, then one deduces it for matrices over `Fin r ⊕ Unit`. -/
theorem exists_list_transvec_mul_mul_list_transvec_eq_diagonal_induction
    (IH :
      ∀ M : Matrix (Fin r) (Fin r) 𝕜,
        ∃ (L₀ L₀' : List (TransvectionStruct (Fin r) 𝕜)) (D₀ : Fin r → 𝕜),
          (L₀.map toMatrix).prod * M * (L₀'.map toMatrix).prod = diagonal D₀)
    (M : Matrix (Fin r ⊕ Unit) (Fin r ⊕ Unit) 𝕜) :
    ∃ (L L' : List (TransvectionStruct (Fin r ⊕ Unit) 𝕜)) (D : Fin r ⊕ Unit → 𝕜),
      (L.map toMatrix).prod * M * (L'.map toMatrix).prod = diagonal D 
goal: ∃ L L' D,
  (List.map Matrix.TransvectionStruct.toMatrix L).prod * M * (List.map Matrix.TransvectionStruct.toMatrix L').prod =
    Matrix.diagonal D

full_name: Matrix.Pivot.reindex_exists_list_transvec_mul_mul_list_transvec_eq_diagonal
code: /-- Reduction to diagonal form by elementary operations is invariant under reindexing. -/
theorem reindex_exists_list_transvec_mul_mul_list_transvec_eq_diagonal (M : Matrix p p 𝕜)
    (e : p ≃ n)
    (H :
      ∃ (L L' : List (TransvectionStruct n 𝕜)) (D : n → 𝕜),
        (L.map toMatrix).prod * Matrix.reindexAlgEquiv 𝕜 _ e M * (L'.map toMatrix).prod =
          diagonal D) :
    ∃ (L L' : List (TransvectionStruct p 𝕜)) (D : p → 𝕜),
      (L.map toMatrix).prod * M * (L'.map toMatrix).prod = diagonal D 
goal: ∃ L L' D,
  (List.map Matrix.TransvectionStruct.toMatrix L).prod * M * (List.map Matrix.TransvectionStruct.toMatrix L').prod =
    Matrix.diagonal D

full_name: Matrix.Pivot.exists_list_transvec_mul_mul_list_transvec_eq_diagonal_aux
code: /-- Any matrix can be reduced to diagonal form by elementary operations. Formulated here on `Type 0`
because we will make an induction using `Fin r`.
See `exists_list_transvec_mul_mul_list_transvec_eq_diagonal` for the general version (which follows
from this one and reindexing). -/
theorem exists_list_transvec_mul_mul_list_transvec_eq_diagonal_aux (n : Type) [Fintype n]
    [DecidableEq n] (M : Matrix n n 𝕜) :
    ∃ (L L' : List (TransvectionStruct n 𝕜)) (D : n → 𝕜),
      (L.map toMatrix).prod * M * (L'.map toMatrix).prod = diagonal D 
goal: ∃ L L' D,
  (List.map Matrix.TransvectionStruct.toMatrix L).prod * M * (List.map Matrix.TransvectionStruct.toMatrix L').prod =
    Matrix.diagonal D

full_name: Matrix.Pivot.exists_list_transvec_mul_mul_list_transvec_eq_diagonal
code: /-- Any matrix can be reduced to diagonal form by elementary operations. -/
theorem exists_list_transvec_mul_mul_list_transvec_eq_diagonal (M : Matrix n n 𝕜) :
    ∃ (L L' : List (TransvectionStruct n 𝕜)) (D : n → 𝕜),
      (L.map toMatrix).prod * M * (L'.map toMatrix).prod = diagonal D 
goal: ∃ L L' D,
  (List.map Matrix.TransvectionStruct.toMatrix L).prod * M * (List.map Matrix.TransvectionStruct.toMatrix L').prod =
    Matrix.diagonal D

full_name: Matrix.Pivot.exists_list_transvec_mul_diagonal_mul_list_transvec
code: /-- Any matrix can be written as the product of transvections, a diagonal matrix, and
transvections. -/
theorem exists_list_transvec_mul_diagonal_mul_list_transvec (M : Matrix n n 𝕜) :
    ∃ (L L' : List (TransvectionStruct n 𝕜)) (D : n → 𝕜),
      M = (L.map toMatrix).prod * diagonal D * (L'.map toMatrix).prod 
goal: ∃ L L' D,
  M =
    (List.map Matrix.TransvectionStruct.toMatrix L).prod * Matrix.diagonal D *
      (List.map Matrix.TransvectionStruct.toMatrix L').prod

full_name: Matrix.diagonal_transvection_induction
code: /-- Induction principle for matrices based on transvections: if a property is true for all diagonal
matrices, all transvections, and is stable under product, then it is true for all matrices. This is
the useful way to say that matrices are generated by diagonal matrices and transvections.

We state a slightly more general version: to prove a property for a matrix `M`, it suffices to
assume that the diagonal matrices we consider have the same determinant as `M`. This is useful to
obtain similar principles for `SLₙ` or `GLₙ`. -/
theorem diagonal_transvection_induction (P : Matrix n n 𝕜 → Prop) (M : Matrix n n 𝕜)
    (hdiag : ∀ D : n → 𝕜, det (diagonal D) = det M → P (diagonal D))
    (htransvec : ∀ t : TransvectionStruct n 𝕜, P t.toMatrix) (hmul : ∀ A B, P A → P B → P (A * B)) :
    P M 
goal: P M

full_name: Matrix.diagonal_transvection_induction_of_det_ne_zero
code: /-- Induction principle for invertible matrices based on transvections: if a property is true for
all invertible diagonal matrices, all transvections, and is stable under product of invertible
matrices, then it is true for all invertible matrices. This is the useful way to say that
invertible matrices are generated by invertible diagonal matrices and transvections. -/
theorem diagonal_transvection_induction_of_det_ne_zero (P : Matrix n n 𝕜 → Prop) (M : Matrix n n 𝕜)
    (hMdet : det M ≠ 0) (hdiag : ∀ D : n → 𝕜, det (diagonal D) ≠ 0 → P (diagonal D))
    (htransvec : ∀ t : TransvectionStruct n 𝕜, P t.toMatrix)
    (hmul : ∀ A B, det A ≠ 0 → det B ≠ 0 → P A → P B → P (A * B)) : P M 
goal: P M