l3lab/ntp-mathlib huggingface dataset:
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  

Proof state:
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
⊢ a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰

Next tactic:
constructor
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · 

Proof state:
case mp
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
⊢ a * b ∈ M₁⁰ → a ∈ M₁⁰ ∧ b ∈ M₁⁰

Next tactic:
intro h
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · intro h
    

Proof state:
case mp
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
h : a * b ∈ M₁⁰
⊢ a ∈ M₁⁰ ∧ b ∈ M₁⁰

Next tactic:
constructor
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · intro h
    constructor <;> 

Proof state:
case mp.left
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
h : a * b ∈ M₁⁰
⊢ a ∈ M₁⁰

Next tactic:
intro x h'
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · intro h
    constructor <;> 

Proof state:
case mp.right
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
h : a * b ∈ M₁⁰
⊢ b ∈ M₁⁰

Next tactic:
intro x h'
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · intro h
    constructor <;> intro x h' <;> 

Proof state:
case mp.left
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
h : a * b ∈ M₁⁰
x : M₁
h' : x * a = 0
⊢ x = 0

Next tactic:
apply h
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · intro h
    constructor <;> intro x h' <;> 

Proof state:
case mp.right
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
h : a * b ∈ M₁⁰
x : M₁
h' : x * b = 0
⊢ x = 0

Next tactic:
apply h
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · intro h
    constructor <;> intro x h' <;> apply h
    · 

Proof state:
case mp.left.a
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
h : a * b ∈ M₁⁰
x : M₁
h' : x * a = 0
⊢ x * (a * b) = 0

Next tactic:
rw [← mul_assoc, h', zero_mul]
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · intro h
    constructor <;> intro x h' <;> apply h
    · rw [← mul_assoc, h', zero_mul]
    · 

Proof state:
case mp.right.a
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
h : a * b ∈ M₁⁰
x : M₁
h' : x * b = 0
⊢ x * (a * b) = 0

Next tactic:
rw [mul_comm a b, ← mul_assoc, h', zero_mul]
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · intro h
    constructor <;> intro x h' <;> apply h
    · rw [← mul_assoc, h', zero_mul]
    · rw [mul_comm a b, ← mul_assoc, h', zero_mul]
  · 

Proof state:
case mpr
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
⊢ a ∈ M₁⁰ ∧ b ∈ M₁⁰ → a * b ∈ M₁⁰

Next tactic:
rintro ⟨ha, hb⟩ x hx
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · intro h
    constructor <;> intro x h' <;> apply h
    · rw [← mul_assoc, h', zero_mul]
    · rw [mul_comm a b, ← mul_assoc, h', zero_mul]
  · rintro ⟨ha, hb⟩ x hx
    

Proof state:
case mpr.intro
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
ha : a ∈ M₁⁰
hb : b ∈ M₁⁰
x : M₁
hx : x * (a * b) = 0
⊢ x = 0

Next tactic:
apply ha
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · intro h
    constructor <;> intro x h' <;> apply h
    · rw [← mul_assoc, h', zero_mul]
    · rw [mul_comm a b, ← mul_assoc, h', zero_mul]
  · rintro ⟨ha, hb⟩ x hx
    apply ha
    

Proof state:
case mpr.intro.a
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
ha : a ∈ M₁⁰
hb : b ∈ M₁⁰
x : M₁
hx : x * (a * b) = 0
⊢ x * a = 0

Next tactic:
apply hb
theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁⁰ ∧ b ∈ M₁⁰ := by
  constructor
  · intro h
    constructor <;> intro x h' <;> apply h
    · rw [← mul_assoc, h', zero_mul]
    · rw [mul_comm a b, ← mul_assoc, h', zero_mul]
  · rintro ⟨ha, hb⟩ x hx
    apply ha
    apply hb
    

Proof state:
case mpr.intro.a.a
M₀ : Type u_1
inst✝⁵ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁴ : MonoidWithZero M
inst✝³ : MonoidWithZero M'
inst✝² : CommMonoidWithZero M₁
inst✝¹ : Ring R
inst✝ : CommRing R'
a b : M₁
ha : a ∈ M₁⁰
hb : b ∈ M₁⁰
x : M₁
hx : x * (a * b) = 0
⊢ x * a * b = 0

Next tactic:
rw [mul_assoc, hx]
theorem map_le_nonZeroDivisors_of_injective [NoZeroDivisors M'] [MonoidWithZeroHomClass F M M']
    (f : F) (hf : Function.Injective f) {S : Submonoid M} (hS : S ≤ M⁰) : S.map f ≤ M'⁰ := by
  

Proof state:
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M'
inst✝ : MonoidWithZeroHomClass F M M'
f : F
hf : Function.Injective ⇑f
S : Submonoid M
hS : S ≤ M⁰
⊢ Submonoid.map f S ≤ M'⁰

Next tactic:
cases subsingleton_or_nontrivial M
theorem map_le_nonZeroDivisors_of_injective [NoZeroDivisors M'] [MonoidWithZeroHomClass F M M']
    (f : F) (hf : Function.Injective f) {S : Submonoid M} (hS : S ≤ M⁰) : S.map f ≤ M'⁰ := by
  cases subsingleton_or_nontrivial M
  · 

Proof state:
case inl
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M'
inst✝ : MonoidWithZeroHomClass F M M'
f : F
hf : Function.Injective ⇑f
S : Submonoid M
hS : S ≤ M⁰
h✝ : Subsingleton M
⊢ Submonoid.map f S ≤ M'⁰

Next tactic:
simp [Subsingleton.elim S ⊥]
theorem map_le_nonZeroDivisors_of_injective [NoZeroDivisors M'] [MonoidWithZeroHomClass F M M']
    (f : F) (hf : Function.Injective f) {S : Submonoid M} (hS : S ≤ M⁰) : S.map f ≤ M'⁰ := by
  cases subsingleton_or_nontrivial M
  · simp [Subsingleton.elim S ⊥]
  · 

Proof state:
case inr
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M'
inst✝ : MonoidWithZeroHomClass F M M'
f : F
hf : Function.Injective ⇑f
S : Submonoid M
hS : S ≤ M⁰
h✝ : Nontrivial M
⊢ Submonoid.map f S ≤ M'⁰

Next tactic:
exact le_nonZeroDivisors_of_noZeroDivisors fun h ↦
      let ⟨x, hx, hx0⟩ := h
      zero_ne_one (hS (hf (hx0.trans (map_zero f).symm) ▸ hx : 0 ∈ S) 1 (mul_zero 1)).symm
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  

Proof state:
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
s : Multiset M₁
⊢ Multiset.prod s = 0 ↔ ∃ r, ∃ (_ : r ∈ s), r = 0

Next tactic:
constructor
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; 

Proof state:
case mp
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
s : Multiset M₁
⊢ Multiset.prod s = 0 → ∃ r, ∃ (_ : r ∈ s), r = 0
case mpr
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
s : Multiset M₁
⊢ (∃ r, ∃ (_ : r ∈ s), r = 0) → Multiset.prod s = 0

Next tactic:
swap
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · 

Proof state:
case mpr
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
s : Multiset M₁
⊢ (∃ r, ∃ (_ : r ∈ s), r = 0) → Multiset.prod s = 0

Next tactic:
rintro ⟨r, hrs, rfl⟩
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    

Proof state:
case mpr.intro.intro
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
s : Multiset M₁
hrs : 0 ∈ s
⊢ Multiset.prod s = 0

Next tactic:
exact Multiset.prod_eq_zero hrs
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    exact Multiset.prod_eq_zero hrs
  

Proof state:
case mp
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
s : Multiset M₁
⊢ Multiset.prod s = 0 → ∃ r, ∃ (_ : r ∈ s), r = 0

Next tactic:
induction' s using Multiset.induction_on with a s ih
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    exact Multiset.prod_eq_zero hrs
  induction' s using Multiset.induction_on with a s ih
  · 

Proof state:
case mp.empty
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
⊢ Multiset.prod 0 = 0 → ∃ r, ∃ (_ : r ∈ 0), r = 0

Next tactic:
intro habs
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    exact Multiset.prod_eq_zero hrs
  induction' s using Multiset.induction_on with a s ih
  · intro habs
    

Proof state:
case mp.empty
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
habs : Multiset.prod 0 = 0
⊢ ∃ r, ∃ (_ : r ∈ 0), r = 0

Next tactic:
simp at habs
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    exact Multiset.prod_eq_zero hrs
  induction' s using Multiset.induction_on with a s ih
  · intro habs
    simp at habs
  · 

Proof state:
case mp.cons
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
a : M₁
s : Multiset M₁
ih : Multiset.prod s = 0 → ∃ r, ∃ (_ : r ∈ s), r = 0
⊢ Multiset.prod (a ::ₘ s) = 0 → ∃ r, ∃ (_ : r ∈ a ::ₘ s), r = 0

Next tactic:
rw [Multiset.prod_cons]
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    exact Multiset.prod_eq_zero hrs
  induction' s using Multiset.induction_on with a s ih
  · intro habs
    simp at habs
  · rw [Multiset.prod_cons]
    

Proof state:
case mp.cons
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
a : M₁
s : Multiset M₁
ih : Multiset.prod s = 0 → ∃ r, ∃ (_ : r ∈ s), r = 0
⊢ a * Multiset.prod s = 0 → ∃ r, ∃ (_ : r ∈ a ::ₘ s), r = 0

Next tactic:
intro hprod
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    exact Multiset.prod_eq_zero hrs
  induction' s using Multiset.induction_on with a s ih
  · intro habs
    simp at habs
  · rw [Multiset.prod_cons]
    intro hprod
    

Proof state:
case mp.cons
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
a : M₁
s : Multiset M₁
ih : Multiset.prod s = 0 → ∃ r, ∃ (_ : r ∈ s), r = 0
hprod : a * Multiset.prod s = 0
⊢ ∃ r, ∃ (_ : r ∈ a ::ₘ s), r = 0

Next tactic:
replace hprod := eq_zero_or_eq_zero_of_mul_eq_zero hprod
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    exact Multiset.prod_eq_zero hrs
  induction' s using Multiset.induction_on with a s ih
  · intro habs
    simp at habs
  · rw [Multiset.prod_cons]
    intro hprod
    replace hprod := eq_zero_or_eq_zero_of_mul_eq_zero hprod
    

Proof state:
case mp.cons
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
a : M₁
s : Multiset M₁
ih : Multiset.prod s = 0 → ∃ r, ∃ (_ : r ∈ s), r = 0
hprod : a = 0 ∨ Multiset.prod s = 0
⊢ ∃ r, ∃ (_ : r ∈ a ::ₘ s), r = 0

Next tactic:
cases' hprod with ha hb
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    exact Multiset.prod_eq_zero hrs
  induction' s using Multiset.induction_on with a s ih
  · intro habs
    simp at habs
  · rw [Multiset.prod_cons]
    intro hprod
    replace hprod := eq_zero_or_eq_zero_of_mul_eq_zero hprod
    cases' hprod with ha hb
    · 

Proof state:
case mp.cons.inl
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
a : M₁
s : Multiset M₁
ih : Multiset.prod s = 0 → ∃ r, ∃ (_ : r ∈ s), r = 0
ha : a = 0
⊢ ∃ r, ∃ (_ : r ∈ a ::ₘ s), r = 0

Next tactic:
exact ⟨a, Multiset.mem_cons_self a s, ha⟩
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    exact Multiset.prod_eq_zero hrs
  induction' s using Multiset.induction_on with a s ih
  · intro habs
    simp at habs
  · rw [Multiset.prod_cons]
    intro hprod
    replace hprod := eq_zero_or_eq_zero_of_mul_eq_zero hprod
    cases' hprod with ha hb
    · exact ⟨a, Multiset.mem_cons_self a s, ha⟩
    · 

Proof state:
case mp.cons.inr
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
a : M₁
s : Multiset M₁
ih : Multiset.prod s = 0 → ∃ r, ∃ (_ : r ∈ s), r = 0
hb : Multiset.prod s = 0
⊢ ∃ r, ∃ (_ : r ∈ a ::ₘ s), r = 0

Next tactic:
apply (ih hb).imp _
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    exact Multiset.prod_eq_zero hrs
  induction' s using Multiset.induction_on with a s ih
  · intro habs
    simp at habs
  · rw [Multiset.prod_cons]
    intro hprod
    replace hprod := eq_zero_or_eq_zero_of_mul_eq_zero hprod
    cases' hprod with ha hb
    · exact ⟨a, Multiset.mem_cons_self a s, ha⟩
    · apply (ih hb).imp _
      

Proof state:
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
a : M₁
s : Multiset M₁
ih : Multiset.prod s = 0 → ∃ r, ∃ (_ : r ∈ s), r = 0
hb : Multiset.prod s = 0
⊢ ∀ (a_1 : M₁), (∃ (_ : a_1 ∈ s), a_1 = 0) → ∃ (_ : a_1 ∈ a ::ₘ s), a_1 = 0

Next tactic:
rintro b ⟨hb₁, hb₂⟩
theorem prod_zero_iff_exists_zero [NoZeroDivisors M₁] [Nontrivial M₁] {s : Multiset M₁} :
    s.prod = 0 ↔ ∃ (r : M₁) (_ : r ∈ s), r = 0 := by
  constructor; swap
  · rintro ⟨r, hrs, rfl⟩
    exact Multiset.prod_eq_zero hrs
  induction' s using Multiset.induction_on with a s ih
  · intro habs
    simp at habs
  · rw [Multiset.prod_cons]
    intro hprod
    replace hprod := eq_zero_or_eq_zero_of_mul_eq_zero hprod
    cases' hprod with ha hb
    · exact ⟨a, Multiset.mem_cons_self a s, ha⟩
    · apply (ih hb).imp _
      rintro b ⟨hb₁, hb₂⟩
      

Proof state:
case intro
M₀ : Type u_1
inst✝⁷ : MonoidWithZero M₀
M : Type u_2
M' : Type u_3
M₁ : Type u_4
R : Type u_5
R' : Type u_6
F : Type u_7
inst✝⁶ : MonoidWithZero M
inst✝⁵ : MonoidWithZero M'
inst✝⁴ : CommMonoidWithZero M₁
inst✝³ : Ring R
inst✝² : CommRing R'
inst✝¹ : NoZeroDivisors M₁
inst✝ : Nontrivial M₁
a : M₁
s : Multiset M₁
ih : Multiset.prod s = 0 → ∃ r, ∃ (_ : r ∈ s), r = 0
hb : Multiset.prod s = 0
b : M₁
hb₁ : b ∈ s
hb₂ : b = 0
⊢ ∃ (_ : b ∈ a ::ₘ s), b = 0

Next tactic:
exact ⟨Multiset.mem_cons_of_mem hb₁, hb₂⟩
lemma trace_diagonal {o} [Fintype o] [DecidableEq o] (d : o → R) :
    trace (diagonal d) = ∑ i, d i := by
  

Proof state:
ι : Type u_1
m : Type u_2
n : Type u_3
p : Type u_4
α : Type u_5
R : Type u_6
S : Type u_7
inst✝⁵ : Fintype m
inst✝⁴ : Fintype n
inst✝³ : Fintype p
inst✝² : AddCommMonoid R
o : Type u_8
inst✝¹ : Fintype o
inst✝ : DecidableEq o
d : o → R
⊢ trace (diagonal d) = ∑ i : o, d i

Next tactic:
simp only [trace, diag_apply, diagonal_apply_eq]
@[simp]
lemma trace_eq_zero_of_isEmpty [IsEmpty n] (A : Matrix n n R) : trace A = 0 := by 

Proof state:
ι : Type u_1
m : Type u_2
n : Type u_3
p : Type u_4
α : Type u_5
R : Type u_6
S : Type u_7
inst✝⁴ : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype p
inst✝¹ : AddCommMonoid R
inst✝ : IsEmpty n
A : Matrix n n R
⊢ trace A = 0

Next tactic:
simp [trace]
lemma trace_blockDiagonal [DecidableEq p] (M : p → Matrix n n R) :
    trace (blockDiagonal M) = ∑ i, trace (M i) := by
  

Proof state:
ι : Type u_1
m : Type u_2
n : Type u_3
p : Type u_4
α : Type u_5
R : Type u_6
S : Type u_7
inst✝⁴ : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype p
inst✝¹ : AddCommMonoid R
inst✝ : DecidableEq p
M : p → Matrix n n R
⊢ trace (blockDiagonal M) = ∑ i : p, trace (M i)

Next tactic:
simp [blockDiagonal, trace, Finset.sum_comm (γ := n)]
lemma trace_blockDiagonal' [DecidableEq p] {m : p → Type*} [∀ i, Fintype (m i)]
    (M : ∀ i, Matrix (m i) (m i) R) :
    trace (blockDiagonal' M) = ∑ i, trace (M i) := by
  

Proof state:
ι : Type u_1
m✝ : Type u_2
n : Type u_3
p : Type u_4
α : Type u_5
R : Type u_6
S : Type u_7
inst✝⁵ : Fintype m✝
inst✝⁴ : Fintype n
inst✝³ : Fintype p
inst✝² : AddCommMonoid R
inst✝¹ : DecidableEq p
m : p → Type u_8
inst✝ : (i : p) → Fintype (m i)
M : (i : p) → Matrix (m i) (m i) R
⊢ trace (blockDiagonal' M) = ∑ i : p, trace (M i)

Next tactic:
simp [blockDiagonal', trace, Finset.sum_sigma']
@[simp]
theorem trace_one : trace (1 : Matrix n n R) = Fintype.card n := by
  

Proof state:
ι : Type u_1
m : Type u_2
n : Type u_3
p : Type u_4
α : Type u_5
R : Type u_6
S : Type u_7
inst✝⁴ : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype p
inst✝¹ : DecidableEq n
inst✝ : AddCommMonoidWithOne R
⊢ trace 1 = ↑(Fintype.card n)

Next tactic:
simp_rw [trace, diag_one, Pi.one_def, Finset.sum_const, nsmul_one, Finset.card_univ]
theorem trace_mul_comm [AddCommMonoid R] [CommSemigroup R] (A : Matrix m n R) (B : Matrix n m R) :
    trace (A * B) = trace (B * A) := by 

Proof state:
ι : Type u_1
m : Type u_2
n : Type u_3
p : Type u_4
α : Type u_5
R : Type u_6
S : Type u_7
inst✝⁴ : Fintype m
inst✝³ : Fintype n
inst✝² : Fintype p
inst✝¹ : AddCommMonoid R
inst✝ : CommSemigroup R
A : Matrix m n R
B : Matrix n m R
⊢ trace (A * B) = trace (B * A)

Next tactic:
rw [← trace_transpose, ← trace_transpose_mul, transpose_mul]