l3lab/ntp-mathlib huggingface dataset:
protected theorem eq_zero_or_eq_zero_of_mul_eq_zero {a b : ℤ} (h : a * b = 0) : a = 0 ∨ b = 0 :=
  match lt_trichotomy 0 a with
  | Or.inl hlt₁ =>
    match lt_trichotomy 0 b with
    | Or.inl hlt₂ => by
      have : 0 < a * b := Int.mul_pos hlt₁ hlt₂
      rw [h] at this
      exact absurd this (lt_irrefl _)
    | Or.inr (Or.inl heq₂) => Or.inr heq₂.symm
    | Or.inr (Or.inr hgt₂) => by
      have : 0 > a * b := Int.mul_neg_of_pos_of_neg hlt₁ hgt₂
      rw [h] at this
      exact absurd this (lt_irrefl _)
  | Or.inr (Or.inl heq₁) => Or.inl heq₁.symm
  | Or.inr (Or.inr hgt₁) =>
    match lt_trichotomy 0 b with
    | Or.inl hlt₂ => by
      have : 0 > a * b := Int.mul_neg_of_neg_of_pos hgt₁ hlt₂
      rw [h] at this
      exact absurd this (lt_irrefl _)
    | Or.inr (Or.inl heq₂) => Or.inr heq₂.symm
    | Or.inr (Or.inr hgt₂) => by
      have : 0 < a * b := Int.mul_pos_of_neg_of_neg hgt₁ hgt₂
      rw [h] at this
      

Proof state:
a b : ℤ
h : a * b = 0
hgt₁ : a < 0
hgt₂ : b < 0
this : 0 < 0
⊢ a = 0 ∨ b = 0

Next tactic:
exact absurd this (lt_irrefl _)
/-- If a linear map `f : M₁ → M₂` respects direct sum decompositions of `M₁` and `M₂`, then it has a
block diagonal matrix with respect to bases compatible with the direct sum decompositions. -/
lemma toMatrix_directSum_collectedBasis_eq_blockDiagonal' {R M₁ M₂ : Type*} [CommSemiring R]
    [AddCommMonoid M₁] [Module R M₁] {N₁ : ι → Submodule R M₁} (h₁ : IsInternal N₁)
    [AddCommMonoid M₂] [Module R M₂] {N₂ : ι → Submodule R M₂} (h₂ : IsInternal N₂)
    {κ₁ κ₂ : ι → Type*} [∀ i, Fintype (κ₁ i)] [∀ i, Fintype (κ₂ i)] [∀ i, DecidableEq (κ₁ i)]
    [Fintype ι] (b₁ : (i : ι) → Basis (κ₁ i) R (N₁ i)) (b₂ : (i : ι) → Basis (κ₂ i) R (N₂ i))
    {f : M₁ →ₗ[R] M₂} (hf : ∀ i, MapsTo f (N₁ i) (N₂ i)) :
    toMatrix (h₁.collectedBasis b₁) (h₂.collectedBasis b₂) f =
    Matrix.blockDiagonal' fun i ↦ toMatrix (b₁ i) (b₂ i) (f.restrict (hf i)) := by
  

Proof state:
ι : Type u_1
R✝ : Type u_2
M : Type u_3
inst✝¹² : CommRing R✝
inst✝¹¹ : AddCommGroup M
inst✝¹⁰ : Module R✝ M
N : ι → Submodule R✝ M
inst✝⁹ : DecidableEq ι
h : IsInternal N
R : Type u_4
M₁ : Type u_5
M₂ : Type u_6
inst✝⁸ : CommSemiring R
inst✝⁷ : AddCommMonoid M₁
inst✝⁶ : Module R M₁
N₁ : ι → Submodule R M₁
h₁ : IsInternal N₁
inst✝⁵ : AddCommMonoid M₂
inst✝⁴ : Module R M₂
N₂ : ι → Submodule R M₂
h₂ : IsInternal N₂
κ₁ : ι → Type u_7
κ₂ : ι → Type u_8
inst✝³ : (i : ι) → Fintype (κ₁ i)
inst✝² : (i : ι) → Fintype (κ₂ i)
inst✝¹ : (i : ι) → DecidableEq (κ₁ i)
inst✝ : Fintype ι
b₁ : (i : ι) → Basis (κ₁ i) R ↥(N₁ i)
b₂ : (i : ι) → Basis (κ₂ i) R ↥(N₂ i)
f : M₁ →ₗ[R] M₂
hf : ∀ (i : ι), MapsTo ⇑f ↑(N₁ i) ↑(N₂ i)
⊢ (toMatrix (IsInternal.collectedBasis h₁ b₁) (IsInternal.collectedBasis h₂ b₂)) f =
    Matrix.blockDiagonal' fun i => (toMatrix (b₁ i) (b₂ i)) (restrict f (_ : MapsTo ⇑f ↑(N₁ i) ↑(N₂ i)))

Next tactic:
ext ⟨i, _⟩ ⟨j, _⟩
/-- If a linear map `f : M₁ → M₂` respects direct sum decompositions of `M₁` and `M₂`, then it has a
block diagonal matrix with respect to bases compatible with the direct sum decompositions. -/
lemma toMatrix_directSum_collectedBasis_eq_blockDiagonal' {R M₁ M₂ : Type*} [CommSemiring R]
    [AddCommMonoid M₁] [Module R M₁] {N₁ : ι → Submodule R M₁} (h₁ : IsInternal N₁)
    [AddCommMonoid M₂] [Module R M₂] {N₂ : ι → Submodule R M₂} (h₂ : IsInternal N₂)
    {κ₁ κ₂ : ι → Type*} [∀ i, Fintype (κ₁ i)] [∀ i, Fintype (κ₂ i)] [∀ i, DecidableEq (κ₁ i)]
    [Fintype ι] (b₁ : (i : ι) → Basis (κ₁ i) R (N₁ i)) (b₂ : (i : ι) → Basis (κ₂ i) R (N₂ i))
    {f : M₁ →ₗ[R] M₂} (hf : ∀ i, MapsTo f (N₁ i) (N₂ i)) :
    toMatrix (h₁.collectedBasis b₁) (h₂.collectedBasis b₂) f =
    Matrix.blockDiagonal' fun i ↦ toMatrix (b₁ i) (b₂ i) (f.restrict (hf i)) := by
  ext ⟨i, _⟩ ⟨j, _⟩
  

Proof state:
case a.mk.h.mk
ι : Type u_1
R✝ : Type u_2
M : Type u_3
inst✝¹² : CommRing R✝
inst✝¹¹ : AddCommGroup M
inst✝¹⁰ : Module R✝ M
N : ι → Submodule R✝ M
inst✝⁹ : DecidableEq ι
h : IsInternal N
R : Type u_4
M₁ : Type u_5
M₂ : Type u_6
inst✝⁸ : CommSemiring R
inst✝⁷ : AddCommMonoid M₁
inst✝⁶ : Module R M₁
N₁ : ι → Submodule R M₁
h₁ : IsInternal N₁
inst✝⁵ : AddCommMonoid M₂
inst✝⁴ : Module R M₂
N₂ : ι → Submodule R M₂
h₂ : IsInternal N₂
κ₁ : ι → Type u_7
κ₂ : ι → Type u_8
inst✝³ : (i : ι) → Fintype (κ₁ i)
inst✝² : (i : ι) → Fintype (κ₂ i)
inst✝¹ : (i : ι) → DecidableEq (κ₁ i)
inst✝ : Fintype ι
b₁ : (i : ι) → Basis (κ₁ i) R ↥(N₁ i)
b₂ : (i : ι) → Basis (κ₂ i) R ↥(N₂ i)
f : M₁ →ₗ[R] M₂
hf : ∀ (i : ι), MapsTo ⇑f ↑(N₁ i) ↑(N₂ i)
i : ι
snd✝¹ : κ₂ i
j : ι
snd✝ : κ₁ j
⊢ (toMatrix (IsInternal.collectedBasis h₁ b₁) (IsInternal.collectedBasis h₂ b₂)) f { fst := i, snd := snd✝¹ }
      { fst := j, snd := snd✝ } =
    Matrix.blockDiagonal' (fun i => (toMatrix (b₁ i) (b₂ i)) (restrict f (_ : MapsTo ⇑f ↑(N₁ i) ↑(N₂ i))))
      { fst := i, snd := snd✝¹ } { fst := j, snd := snd✝ }

Next tactic:
simp only [toMatrix_apply, Matrix.blockDiagonal'_apply]
/-- If a linear map `f : M₁ → M₂` respects direct sum decompositions of `M₁` and `M₂`, then it has a
block diagonal matrix with respect to bases compatible with the direct sum decompositions. -/
lemma toMatrix_directSum_collectedBasis_eq_blockDiagonal' {R M₁ M₂ : Type*} [CommSemiring R]
    [AddCommMonoid M₁] [Module R M₁] {N₁ : ι → Submodule R M₁} (h₁ : IsInternal N₁)
    [AddCommMonoid M₂] [Module R M₂] {N₂ : ι → Submodule R M₂} (h₂ : IsInternal N₂)
    {κ₁ κ₂ : ι → Type*} [∀ i, Fintype (κ₁ i)] [∀ i, Fintype (κ₂ i)] [∀ i, DecidableEq (κ₁ i)]
    [Fintype ι] (b₁ : (i : ι) → Basis (κ₁ i) R (N₁ i)) (b₂ : (i : ι) → Basis (κ₂ i) R (N₂ i))
    {f : M₁ →ₗ[R] M₂} (hf : ∀ i, MapsTo f (N₁ i) (N₂ i)) :
    toMatrix (h₁.collectedBasis b₁) (h₂.collectedBasis b₂) f =
    Matrix.blockDiagonal' fun i ↦ toMatrix (b₁ i) (b₂ i) (f.restrict (hf i)) := by
  ext ⟨i, _⟩ ⟨j, _⟩
  simp only [toMatrix_apply, Matrix.blockDiagonal'_apply]
  

Proof state:
case a.mk.h.mk
ι : Type u_1
R✝ : Type u_2
M : Type u_3
inst✝¹² : CommRing R✝
inst✝¹¹ : AddCommGroup M
inst✝¹⁰ : Module R✝ M
N : ι → Submodule R✝ M
inst✝⁹ : DecidableEq ι
h : IsInternal N
R : Type u_4
M₁ : Type u_5
M₂ : Type u_6
inst✝⁸ : CommSemiring R
inst✝⁷ : AddCommMonoid M₁
inst✝⁶ : Module R M₁
N₁ : ι → Submodule R M₁
h₁ : IsInternal N₁
inst✝⁵ : AddCommMonoid M₂
inst✝⁴ : Module R M₂
N₂ : ι → Submodule R M₂
h₂ : IsInternal N₂
κ₁ : ι → Type u_7
κ₂ : ι → Type u_8
inst✝³ : (i : ι) → Fintype (κ₁ i)
inst✝² : (i : ι) → Fintype (κ₂ i)
inst✝¹ : (i : ι) → DecidableEq (κ₁ i)
inst✝ : Fintype ι
b₁ : (i : ι) → Basis (κ₁ i) R ↥(N₁ i)
b₂ : (i : ι) → Basis (κ₂ i) R ↥(N₂ i)
f : M₁ →ₗ[R] M₂
hf : ∀ (i : ι), MapsTo ⇑f ↑(N₁ i) ↑(N₂ i)
i : ι
snd✝¹ : κ₂ i
j : ι
snd✝ : κ₁ j
⊢ ((IsInternal.collectedBasis h₂ b₂).repr (f ((IsInternal.collectedBasis h₁ b₁) { fst := j, snd := snd✝ })))
      { fst := i, snd := snd✝¹ } =
    if h : i = j then
      ((b₂ i).repr
          ((restrict f (_ : MapsTo ⇑f ↑(N₁ { fst := i, snd := snd✝¹ }.fst) ↑(N₂ { fst := i, snd := snd✝¹ }.fst)))
            ((b₁ i) (cast (_ : κ₁ { fst := j, snd := snd✝ }.fst = κ₁ { fst := i, snd := snd✝¹ }.fst) snd✝))))
        snd✝¹
    else 0

Next tactic:
rcases eq_or_ne i j with rfl | hij
/-- If a linear map `f : M₁ → M₂` respects direct sum decompositions of `M₁` and `M₂`, then it has a
block diagonal matrix with respect to bases compatible with the direct sum decompositions. -/
lemma toMatrix_directSum_collectedBasis_eq_blockDiagonal' {R M₁ M₂ : Type*} [CommSemiring R]
    [AddCommMonoid M₁] [Module R M₁] {N₁ : ι → Submodule R M₁} (h₁ : IsInternal N₁)
    [AddCommMonoid M₂] [Module R M₂] {N₂ : ι → Submodule R M₂} (h₂ : IsInternal N₂)
    {κ₁ κ₂ : ι → Type*} [∀ i, Fintype (κ₁ i)] [∀ i, Fintype (κ₂ i)] [∀ i, DecidableEq (κ₁ i)]
    [Fintype ι] (b₁ : (i : ι) → Basis (κ₁ i) R (N₁ i)) (b₂ : (i : ι) → Basis (κ₂ i) R (N₂ i))
    {f : M₁ →ₗ[R] M₂} (hf : ∀ i, MapsTo f (N₁ i) (N₂ i)) :
    toMatrix (h₁.collectedBasis b₁) (h₂.collectedBasis b₂) f =
    Matrix.blockDiagonal' fun i ↦ toMatrix (b₁ i) (b₂ i) (f.restrict (hf i)) := by
  ext ⟨i, _⟩ ⟨j, _⟩
  simp only [toMatrix_apply, Matrix.blockDiagonal'_apply]
  rcases eq_or_ne i j with rfl | hij
  · 

Proof state:
case a.mk.h.mk.inl
ι : Type u_1
R✝ : Type u_2
M : Type u_3
inst✝¹² : CommRing R✝
inst✝¹¹ : AddCommGroup M
inst✝¹⁰ : Module R✝ M
N : ι → Submodule R✝ M
inst✝⁹ : DecidableEq ι
h : IsInternal N
R : Type u_4
M₁ : Type u_5
M₂ : Type u_6
inst✝⁸ : CommSemiring R
inst✝⁷ : AddCommMonoid M₁
inst✝⁶ : Module R M₁
N₁ : ι → Submodule R M₁
h₁ : IsInternal N₁
inst✝⁵ : AddCommMonoid M₂
inst✝⁴ : Module R M₂
N₂ : ι → Submodule R M₂
h₂ : IsInternal N₂
κ₁ : ι → Type u_7
κ₂ : ι → Type u_8
inst✝³ : (i : ι) → Fintype (κ₁ i)
inst✝² : (i : ι) → Fintype (κ₂ i)
inst✝¹ : (i : ι) → DecidableEq (κ₁ i)
inst✝ : Fintype ι
b₁ : (i : ι) → Basis (κ₁ i) R ↥(N₁ i)
b₂ : (i : ι) → Basis (κ₂ i) R ↥(N₂ i)
f : M₁ →ₗ[R] M₂
hf : ∀ (i : ι), MapsTo ⇑f ↑(N₁ i) ↑(N₂ i)
i : ι
snd✝¹ : κ₂ i
snd✝ : κ₁ i
⊢ ((IsInternal.collectedBasis h₂ b₂).repr (f ((IsInternal.collectedBasis h₁ b₁) { fst := i, snd := snd✝ })))
      { fst := i, snd := snd✝¹ } =
    if h : i = i then
      ((b₂ i).repr
          ((restrict f (_ : MapsTo ⇑f ↑(N₁ { fst := i, snd := snd✝¹ }.fst) ↑(N₂ { fst := i, snd := snd✝¹ }.fst)))
            ((b₁ i) (cast (_ : κ₁ { fst := i, snd := snd✝ }.fst = κ₁ { fst := i, snd := snd✝¹ }.fst) snd✝))))
        snd✝¹
    else 0

Next tactic:
simp [h₂.collectedBasis_repr_of_mem _ (hf _ (Subtype.mem _)), restrict_apply]
/-- If a linear map `f : M₁ → M₂` respects direct sum decompositions of `M₁` and `M₂`, then it has a
block diagonal matrix with respect to bases compatible with the direct sum decompositions. -/
lemma toMatrix_directSum_collectedBasis_eq_blockDiagonal' {R M₁ M₂ : Type*} [CommSemiring R]
    [AddCommMonoid M₁] [Module R M₁] {N₁ : ι → Submodule R M₁} (h₁ : IsInternal N₁)
    [AddCommMonoid M₂] [Module R M₂] {N₂ : ι → Submodule R M₂} (h₂ : IsInternal N₂)
    {κ₁ κ₂ : ι → Type*} [∀ i, Fintype (κ₁ i)] [∀ i, Fintype (κ₂ i)] [∀ i, DecidableEq (κ₁ i)]
    [Fintype ι] (b₁ : (i : ι) → Basis (κ₁ i) R (N₁ i)) (b₂ : (i : ι) → Basis (κ₂ i) R (N₂ i))
    {f : M₁ →ₗ[R] M₂} (hf : ∀ i, MapsTo f (N₁ i) (N₂ i)) :
    toMatrix (h₁.collectedBasis b₁) (h₂.collectedBasis b₂) f =
    Matrix.blockDiagonal' fun i ↦ toMatrix (b₁ i) (b₂ i) (f.restrict (hf i)) := by
  ext ⟨i, _⟩ ⟨j, _⟩
  simp only [toMatrix_apply, Matrix.blockDiagonal'_apply]
  rcases eq_or_ne i j with rfl | hij
  · simp [h₂.collectedBasis_repr_of_mem _ (hf _ (Subtype.mem _)), restrict_apply]
  · 

Proof state:
case a.mk.h.mk.inr
ι : Type u_1
R✝ : Type u_2
M : Type u_3
inst✝¹² : CommRing R✝
inst✝¹¹ : AddCommGroup M
inst✝¹⁰ : Module R✝ M
N : ι → Submodule R✝ M
inst✝⁹ : DecidableEq ι
h : IsInternal N
R : Type u_4
M₁ : Type u_5
M₂ : Type u_6
inst✝⁸ : CommSemiring R
inst✝⁷ : AddCommMonoid M₁
inst✝⁶ : Module R M₁
N₁ : ι → Submodule R M₁
h₁ : IsInternal N₁
inst✝⁵ : AddCommMonoid M₂
inst✝⁴ : Module R M₂
N₂ : ι → Submodule R M₂
h₂ : IsInternal N₂
κ₁ : ι → Type u_7
κ₂ : ι → Type u_8
inst✝³ : (i : ι) → Fintype (κ₁ i)
inst✝² : (i : ι) → Fintype (κ₂ i)
inst✝¹ : (i : ι) → DecidableEq (κ₁ i)
inst✝ : Fintype ι
b₁ : (i : ι) → Basis (κ₁ i) R ↥(N₁ i)
b₂ : (i : ι) → Basis (κ₂ i) R ↥(N₂ i)
f : M₁ →ₗ[R] M₂
hf : ∀ (i : ι), MapsTo ⇑f ↑(N₁ i) ↑(N₂ i)
i : ι
snd✝¹ : κ₂ i
j : ι
snd✝ : κ₁ j
hij : i ≠ j
⊢ ((IsInternal.collectedBasis h₂ b₂).repr (f ((IsInternal.collectedBasis h₁ b₁) { fst := j, snd := snd✝ })))
      { fst := i, snd := snd✝¹ } =
    if h : i = j then
      ((b₂ i).repr
          ((restrict f (_ : MapsTo ⇑f ↑(N₁ { fst := i, snd := snd✝¹ }.fst) ↑(N₂ { fst := i, snd := snd✝¹ }.fst)))
            ((b₁ i) (cast (_ : κ₁ { fst := j, snd := snd✝ }.fst = κ₁ { fst := i, snd := snd✝¹ }.fst) snd✝))))
        snd✝¹
    else 0

Next tactic:
simp [hij, h₂.collectedBasis_repr_of_mem_ne _ hij.symm (hf _ (Subtype.mem _))]
lemma trace_eq_sum_trace_restrict [Fintype ι]
    {f : M →ₗ[R] M} (hf : ∀ i, MapsTo f (N i) (N i)) :
    trace R M f = ∑ i, trace R (N i) (f.restrict (hf i)) := by
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁶ : CommRing R
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
N : ι → Submodule R M
inst✝³ : DecidableEq ι
h : IsInternal N
inst✝² : ∀ (i : ι), Module.Finite R ↥(N i)
inst✝¹ : ∀ (i : ι), Module.Free R ↥(N i)
inst✝ : Fintype ι
f : M →ₗ[R] M
hf : ∀ (i : ι), MapsTo ⇑f ↑(N i) ↑(N i)
⊢ (trace R M) f = ∑ i : ι, (trace R ↥(N i)) (restrict f (_ : MapsTo ⇑f ↑(N i) ↑(N i)))

Next tactic:
let b : (i : ι) → Basis _ R (N i) := fun i ↦ Module.Free.chooseBasis R (N i)
lemma trace_eq_sum_trace_restrict [Fintype ι]
    {f : M →ₗ[R] M} (hf : ∀ i, MapsTo f (N i) (N i)) :
    trace R M f = ∑ i, trace R (N i) (f.restrict (hf i)) := by
  let b : (i : ι) → Basis _ R (N i) := fun i ↦ Module.Free.chooseBasis R (N i)
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁶ : CommRing R
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
N : ι → Submodule R M
inst✝³ : DecidableEq ι
h : IsInternal N
inst✝² : ∀ (i : ι), Module.Finite R ↥(N i)
inst✝¹ : ∀ (i : ι), Module.Free R ↥(N i)
inst✝ : Fintype ι
f : M →ₗ[R] M
hf : ∀ (i : ι), MapsTo ⇑f ↑(N i) ↑(N i)
b : (i : ι) → Basis (Module.Free.ChooseBasisIndex R ↥(N i)) R ↥(N i) := fun i => Module.Free.chooseBasis R ↥(N i)
⊢ (trace R M) f = ∑ i : ι, (trace R ↥(N i)) (restrict f (_ : MapsTo ⇑f ↑(N i) ↑(N i)))

Next tactic:
simp_rw [trace_eq_matrix_trace R (h.collectedBasis b),
    toMatrix_directSum_collectedBasis_eq_blockDiagonal' h h b b hf, Matrix.trace_blockDiagonal',
    ← trace_eq_matrix_trace]
lemma trace_eq_sum_trace_restrict' (hN : {i | N i ≠ ⊥}.Finite)
    {f : M →ₗ[R] M} (hf : ∀ i, MapsTo f (N i) (N i)) :
    trace R M f = ∑ i in hN.toFinset, trace R (N i) (f.restrict (hf i)) := by
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
N : ι → Submodule R M
inst✝² : DecidableEq ι
h : IsInternal N
inst✝¹ : ∀ (i : ι), Module.Finite R ↥(N i)
inst✝ : ∀ (i : ι), Module.Free R ↥(N i)
hN : Set.Finite {i | N i ≠ ⊥}
f : M →ₗ[R] M
hf : ∀ (i : ι), MapsTo ⇑f ↑(N i) ↑(N i)
⊢ (trace R M) f = ∑ i in Finite.toFinset hN, (trace R ↥(N i)) (restrict f (_ : MapsTo ⇑f ↑(N i) ↑(N i)))

Next tactic:
let _ : Fintype {i // N i ≠ ⊥} := hN.fintype
lemma trace_eq_sum_trace_restrict' (hN : {i | N i ≠ ⊥}.Finite)
    {f : M →ₗ[R] M} (hf : ∀ i, MapsTo f (N i) (N i)) :
    trace R M f = ∑ i in hN.toFinset, trace R (N i) (f.restrict (hf i)) := by
  let _ : Fintype {i // N i ≠ ⊥} := hN.fintype
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
N : ι → Submodule R M
inst✝² : DecidableEq ι
h : IsInternal N
inst✝¹ : ∀ (i : ι), Module.Finite R ↥(N i)
inst✝ : ∀ (i : ι), Module.Free R ↥(N i)
hN : Set.Finite {i | N i ≠ ⊥}
f : M →ₗ[R] M
hf : ∀ (i : ι), MapsTo ⇑f ↑(N i) ↑(N i)
x✝ : Fintype { i // N i ≠ ⊥ } := Finite.fintype hN
⊢ (trace R M) f = ∑ i in Finite.toFinset hN, (trace R ↥(N i)) (restrict f (_ : MapsTo ⇑f ↑(N i) ↑(N i)))

Next tactic:
let _ : Fintype {i | N i ≠ ⊥} := hN.fintype
lemma trace_eq_sum_trace_restrict' (hN : {i | N i ≠ ⊥}.Finite)
    {f : M →ₗ[R] M} (hf : ∀ i, MapsTo f (N i) (N i)) :
    trace R M f = ∑ i in hN.toFinset, trace R (N i) (f.restrict (hf i)) := by
  let _ : Fintype {i // N i ≠ ⊥} := hN.fintype
  let _ : Fintype {i | N i ≠ ⊥} := hN.fintype
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
N : ι → Submodule R M
inst✝² : DecidableEq ι
h : IsInternal N
inst✝¹ : ∀ (i : ι), Module.Finite R ↥(N i)
inst✝ : ∀ (i : ι), Module.Free R ↥(N i)
hN : Set.Finite {i | N i ≠ ⊥}
f : M →ₗ[R] M
hf : ∀ (i : ι), MapsTo ⇑f ↑(N i) ↑(N i)
x✝¹ : Fintype { i // N i ≠ ⊥ } := Finite.fintype hN
x✝ : Fintype ↑{i | N i ≠ ⊥} := Finite.fintype hN
⊢ (trace R M) f = ∑ i in Finite.toFinset hN, (trace R ↥(N i)) (restrict f (_ : MapsTo ⇑f ↑(N i) ↑(N i)))

Next tactic:
rw [← Finset.sum_coe_sort, trace_eq_sum_trace_restrict (isInternal_ne_bot_iff.mpr h) _]
lemma trace_eq_sum_trace_restrict' (hN : {i | N i ≠ ⊥}.Finite)
    {f : M →ₗ[R] M} (hf : ∀ i, MapsTo f (N i) (N i)) :
    trace R M f = ∑ i in hN.toFinset, trace R (N i) (f.restrict (hf i)) := by
  let _ : Fintype {i // N i ≠ ⊥} := hN.fintype
  let _ : Fintype {i | N i ≠ ⊥} := hN.fintype
  rw [← Finset.sum_coe_sort, trace_eq_sum_trace_restrict (isInternal_ne_bot_iff.mpr h) _]
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
N : ι → Submodule R M
inst✝² : DecidableEq ι
h : IsInternal N
inst✝¹ : ∀ (i : ι), Module.Finite R ↥(N i)
inst✝ : ∀ (i : ι), Module.Free R ↥(N i)
hN : Set.Finite {i | N i ≠ ⊥}
f : M →ₗ[R] M
hf : ∀ (i : ι), MapsTo ⇑f ↑(N i) ↑(N i)
x✝¹ : Fintype { i // N i ≠ ⊥ } := Finite.fintype hN
x✝ : Fintype ↑{i | N i ≠ ⊥} := Finite.fintype hN
⊢ ∑ i : { i // N i ≠ ⊥ }, (trace R ↥(N ↑i)) (restrict f (_ : MapsTo ⇑?m.101369 ↑(?m.100714 i) ↑(?m.100714 i))) =
    ∑ i : { x // x ∈ Finite.toFinset hN }, (trace R ↥(N ↑i)) (restrict f (_ : MapsTo ⇑f ↑(N ↑i) ↑(N ↑i)))
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁵ : CommRing R
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
N : ι → Submodule R M
inst✝² : DecidableEq ι
h : IsInternal N
inst✝¹ : ∀ (i : ι), Module.Finite R ↥(N i)
inst✝ : ∀ (i : ι), Module.Free R ↥(N i)
hN : Set.Finite {i | N i ≠ ⊥}
f : M →ₗ[R] M
hf : ∀ (i : ι), MapsTo ⇑f ↑(N i) ↑(N i)
x✝¹ : Fintype { i // N i ≠ ⊥ } := Finite.fintype hN
x✝ : Fintype ↑{i | N i ≠ ⊥} := Finite.fintype hN
⊢ ∀ (i : { i // N i ≠ ⊥ }), MapsTo ⇑f ↑(N ↑i) ↑(N ↑i)

Next tactic:
exact Fintype.sum_equiv hN.subtypeEquivToFinset _ _ (fun i ↦ rfl)
/-- If `f` and `g` are commuting endomorphisms of a finite, free `R`-module `M`, such that `f`
is triangularizable, then to prove that the trace of `g ∘ f` vanishes, it is sufficient to prove
that the trace of `g` vanishes on each generalized eigenspace of `f`. -/
lemma trace_comp_eq_zero_of_commute_of_trace_restrict_eq_zero
    [IsDomain R] [IsPrincipalIdealRing R] [Module.Free R M] [Module.Finite R M]
    {f g : Module.End R M}
    (h_comm : Commute f g)
    (hf : ⨆ μ, ⨆ k, f.generalizedEigenspace μ k = ⊤)
    (hg : ∀ μ, trace R _ (g.restrict (f.mapsTo_iSup_generalizedEigenspace_of_comm h_comm μ)) = 0) :
    trace R _ (g ∘ₗ f) = 0 := by
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁹ : CommRing R
inst✝⁸ : AddCommGroup M
inst✝⁷ : Module R M
N : ι → Submodule R M
inst✝⁶ : DecidableEq ι
h : IsInternal N
inst✝⁵ : ∀ (i : ι), Module.Finite R ↥(N i)
inst✝⁴ : ∀ (i : ι), Module.Free R ↥(N i)
inst✝³ : IsDomain R
inst✝² : IsPrincipalIdealRing R
inst✝¹ : Module.Free R M
inst✝ : Module.Finite R M
f g : Module.End R M
h_comm : Commute f g
hf : ⨆ μ, ⨆ k, (Module.End.generalizedEigenspace f μ) k = ⊤
hg :
  ∀ (μ : R),
    (trace R ↥(⨆ k, (Module.End.generalizedEigenspace f μ) k))
        (restrict g
          (_ :
            MapsTo ⇑g ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k)
              ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k))) =
      0
⊢ (trace R M) (g ∘ₗ f) = 0

Next tactic:
have hfg : ∀ μ,
      MapsTo (g ∘ₗ f) ↑(⨆ k, f.generalizedEigenspace μ k) ↑(⨆ k, f.generalizedEigenspace μ k) :=
    fun μ ↦ (f.mapsTo_iSup_generalizedEigenspace_of_comm h_comm μ).comp
      (f.mapsTo_iSup_generalizedEigenspace_of_comm rfl μ)
/-- If `f` and `g` are commuting endomorphisms of a finite, free `R`-module `M`, such that `f`
is triangularizable, then to prove that the trace of `g ∘ f` vanishes, it is sufficient to prove
that the trace of `g` vanishes on each generalized eigenspace of `f`. -/
lemma trace_comp_eq_zero_of_commute_of_trace_restrict_eq_zero
    [IsDomain R] [IsPrincipalIdealRing R] [Module.Free R M] [Module.Finite R M]
    {f g : Module.End R M}
    (h_comm : Commute f g)
    (hf : ⨆ μ, ⨆ k, f.generalizedEigenspace μ k = ⊤)
    (hg : ∀ μ, trace R _ (g.restrict (f.mapsTo_iSup_generalizedEigenspace_of_comm h_comm μ)) = 0) :
    trace R _ (g ∘ₗ f) = 0 := by
  have hfg : ∀ μ,
      MapsTo (g ∘ₗ f) ↑(⨆ k, f.generalizedEigenspace μ k) ↑(⨆ k, f.generalizedEigenspace μ k) :=
    fun μ ↦ (f.mapsTo_iSup_generalizedEigenspace_of_comm h_comm μ).comp
      (f.mapsTo_iSup_generalizedEigenspace_of_comm rfl μ)
  

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁹ : CommRing R
inst✝⁸ : AddCommGroup M
inst✝⁷ : Module R M
N : ι → Submodule R M
inst✝⁶ : DecidableEq ι
h : IsInternal N
inst✝⁵ : ∀ (i : ι), Module.Finite R ↥(N i)
inst✝⁴ : ∀ (i : ι), Module.Free R ↥(N i)
inst✝³ : IsDomain R
inst✝² : IsPrincipalIdealRing R
inst✝¹ : Module.Free R M
inst✝ : Module.Finite R M
f g : Module.End R M
h_comm : Commute f g
hf : ⨆ μ, ⨆ k, (Module.End.generalizedEigenspace f μ) k = ⊤
hg :
  ∀ (μ : R),
    (trace R ↥(⨆ k, (Module.End.generalizedEigenspace f μ) k))
        (restrict g
          (_ :
            MapsTo ⇑g ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k)
              ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k))) =
      0
hfg :
  ∀ (μ : R),
    MapsTo ⇑(g ∘ₗ f) ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k) ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k)
⊢ (trace R M) (g ∘ₗ f) = 0

Next tactic:
suffices ∀ μ, trace R _ ((g ∘ₗ f).restrict (hfg μ)) = 0 by
    classical
    have hds := DirectSum.isInternal_submodule_of_independent_of_iSup_eq_top
      f.independent_generalizedEigenspace hf
    have h_fin : {μ | ⨆ k, f.generalizedEigenspace μ k ≠ ⊥}.Finite :=
      CompleteLattice.WellFounded.finite_ne_bot_of_independent
        (isNoetherian_iff_wellFounded.mp inferInstance) f.independent_generalizedEigenspace
    simp [trace_eq_sum_trace_restrict' hds h_fin hfg, this]
/-- If `f` and `g` are commuting endomorphisms of a finite, free `R`-module `M`, such that `f`
is triangularizable, then to prove that the trace of `g ∘ f` vanishes, it is sufficient to prove
that the trace of `g` vanishes on each generalized eigenspace of `f`. -/
lemma trace_comp_eq_zero_of_commute_of_trace_restrict_eq_zero
    [IsDomain R] [IsPrincipalIdealRing R] [Module.Free R M] [Module.Finite R M]
    {f g : Module.End R M}
    (h_comm : Commute f g)
    (hf : ⨆ μ, ⨆ k, f.generalizedEigenspace μ k = ⊤)
    (hg : ∀ μ, trace R _ (g.restrict (f.mapsTo_iSup_generalizedEigenspace_of_comm h_comm μ)) = 0) :
    trace R _ (g ∘ₗ f) = 0 := by
  have hfg : ∀ μ,
      MapsTo (g ∘ₗ f) ↑(⨆ k, f.generalizedEigenspace μ k) ↑(⨆ k, f.generalizedEigenspace μ k) :=
    fun μ ↦ (f.mapsTo_iSup_generalizedEigenspace_of_comm h_comm μ).comp
      (f.mapsTo_iSup_generalizedEigenspace_of_comm rfl μ)
  suffices ∀ μ, trace R _ ((g ∘ₗ f).restrict (hfg μ)) = 0 by
    

Proof state:
ι : Type u_1
R : Type u_2
M : Type u_3
inst✝⁹ : CommRing R
inst✝⁸ : AddCommGroup M
inst✝⁷ : Module R M
N : ι → Submodule R M
inst✝⁶ : DecidableEq ι
h : IsInternal N
inst✝⁵ : ∀ (i : ι), Module.Finite R ↥(N i)
inst✝⁴ : ∀ (i : ι), Module.Free R ↥(N i)
inst✝³ : IsDomain R
inst✝² : IsPrincipalIdealRing R
inst✝¹ : Module.Free R M
inst✝ : Module.Finite R M
f g : Module.End R M
h_comm : Commute f g
hf : ⨆ μ, ⨆ k, (Module.End.generalizedEigenspace f μ) k = ⊤
hg :
  ∀ (μ : R),
    (trace R ↥(⨆ k, (Module.End.generalizedEigenspace f μ) k))
        (restrict g
          (_ :
            MapsTo ⇑g ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k)
              ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k))) =
      0
hfg :
  ∀ (μ : R),
    MapsTo ⇑(g ∘ₗ f) ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k) ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k)
this :
  ∀ (μ : R),
    (trace R ↥(⨆ k, (Module.End.generalizedEigenspace f μ) k))
        (restrict (g ∘ₗ f)
          (_ :
            MapsTo ⇑(g ∘ₗ f) ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k)
              ↑(⨆ k, (Module.End.generalizedEigenspace f μ) k))) =
      0
⊢ (trace R M) (g ∘ₗ f) = 0

Next tactic:
classical
    have hds := DirectSum.isInternal_submodule_of_independent_of_iSup_eq_top
      f.independent_generalizedEigenspace hf
    have h_fin : {μ | ⨆ k, f.generalizedEigenspace μ k ≠ ⊥}.Finite :=
      CompleteLattice.WellFounded.finite_ne_bot_of_independent
        (isNoetherian_iff_wellFounded.mp inferInstance) f.independent_generalizedEigenspace
    simp [trace_eq_sum_trace_restrict' hds h_fin hfg, this]