l3lab/ntp-mathlib huggingface dataset:
/-- The injection into a pi group at different indices commutes.

For injections of commuting elements at the same index, see `Commute.map` -/
@[to_additive
      "The injection into an additive pi group at different indices commutes.

      For injections of commuting elements at the same index, see `AddCommute.map`"]
theorem Pi.mulSingle_commute [∀ i, MulOneClass <| f i] :
    Pairwise fun i j => ∀ (x : f i) (y : f j), Commute (mulSingle i x) (mulSingle j y) := by
  intro i j hij x y; 

Proof state:
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y✝ : (i : I) → f i
i✝ j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → MulOneClass (f i)
i j : I
hij : i ≠ j
x : f i
y : f j
⊢ Commute (mulSingle i x) (mulSingle j y)

Next tactic:
ext k
/-- The injection into a pi group at different indices commutes.

For injections of commuting elements at the same index, see `Commute.map` -/
@[to_additive
      "The injection into an additive pi group at different indices commutes.

      For injections of commuting elements at the same index, see `AddCommute.map`"]
theorem Pi.mulSingle_commute [∀ i, MulOneClass <| f i] :
    Pairwise fun i j => ∀ (x : f i) (y : f j), Commute (mulSingle i x) (mulSingle j y) := by
  intro i j hij x y; ext k
  

Proof state:
case h
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y✝ : (i : I) → f i
i✝ j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → MulOneClass (f i)
i j : I
hij : i ≠ j
x : f i
y : f j
k : I
⊢ (mulSingle i x * mulSingle j y) k = (mulSingle j y * mulSingle i x) k

Next tactic:
by_cases h1 : i = k
/-- The injection into a pi group at different indices commutes.

For injections of commuting elements at the same index, see `Commute.map` -/
@[to_additive
      "The injection into an additive pi group at different indices commutes.

      For injections of commuting elements at the same index, see `AddCommute.map`"]
theorem Pi.mulSingle_commute [∀ i, MulOneClass <| f i] :
    Pairwise fun i j => ∀ (x : f i) (y : f j), Commute (mulSingle i x) (mulSingle j y) := by
  intro i j hij x y; ext k
  by_cases h1 : i = k;
  · 

Proof state:
case pos
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y✝ : (i : I) → f i
i✝ j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → MulOneClass (f i)
i j : I
hij : i ≠ j
x : f i
y : f j
k : I
h1 : i = k
⊢ (mulSingle i x * mulSingle j y) k = (mulSingle j y * mulSingle i x) k

Next tactic:
subst h1
/-- The injection into a pi group at different indices commutes.

For injections of commuting elements at the same index, see `Commute.map` -/
@[to_additive
      "The injection into an additive pi group at different indices commutes.

      For injections of commuting elements at the same index, see `AddCommute.map`"]
theorem Pi.mulSingle_commute [∀ i, MulOneClass <| f i] :
    Pairwise fun i j => ∀ (x : f i) (y : f j), Commute (mulSingle i x) (mulSingle j y) := by
  intro i j hij x y; ext k
  by_cases h1 : i = k;
  · subst h1
    

Proof state:
case pos
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y✝ : (i : I) → f i
i✝ j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → MulOneClass (f i)
i j : I
hij : i ≠ j
x : f i
y : f j
⊢ (mulSingle i x * mulSingle j y) i = (mulSingle j y * mulSingle i x) i

Next tactic:
simp [hij]
/-- The injection into a pi group at different indices commutes.

For injections of commuting elements at the same index, see `Commute.map` -/
@[to_additive
      "The injection into an additive pi group at different indices commutes.

      For injections of commuting elements at the same index, see `AddCommute.map`"]
theorem Pi.mulSingle_commute [∀ i, MulOneClass <| f i] :
    Pairwise fun i j => ∀ (x : f i) (y : f j), Commute (mulSingle i x) (mulSingle j y) := by
  intro i j hij x y; ext k
  by_cases h1 : i = k;
  · subst h1
    simp [hij]
  

Proof state:
case neg
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y✝ : (i : I) → f i
i✝ j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → MulOneClass (f i)
i j : I
hij : i ≠ j
x : f i
y : f j
k : I
h1 : ¬i = k
⊢ (mulSingle i x * mulSingle j y) k = (mulSingle j y * mulSingle i x) k

Next tactic:
by_cases h2 : j = k
/-- The injection into a pi group at different indices commutes.

For injections of commuting elements at the same index, see `Commute.map` -/
@[to_additive
      "The injection into an additive pi group at different indices commutes.

      For injections of commuting elements at the same index, see `AddCommute.map`"]
theorem Pi.mulSingle_commute [∀ i, MulOneClass <| f i] :
    Pairwise fun i j => ∀ (x : f i) (y : f j), Commute (mulSingle i x) (mulSingle j y) := by
  intro i j hij x y; ext k
  by_cases h1 : i = k;
  · subst h1
    simp [hij]
  by_cases h2 : j = k;
  · 

Proof state:
case pos
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y✝ : (i : I) → f i
i✝ j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → MulOneClass (f i)
i j : I
hij : i ≠ j
x : f i
y : f j
k : I
h1 : ¬i = k
h2 : j = k
⊢ (mulSingle i x * mulSingle j y) k = (mulSingle j y * mulSingle i x) k

Next tactic:
subst h2
/-- The injection into a pi group at different indices commutes.

For injections of commuting elements at the same index, see `Commute.map` -/
@[to_additive
      "The injection into an additive pi group at different indices commutes.

      For injections of commuting elements at the same index, see `AddCommute.map`"]
theorem Pi.mulSingle_commute [∀ i, MulOneClass <| f i] :
    Pairwise fun i j => ∀ (x : f i) (y : f j), Commute (mulSingle i x) (mulSingle j y) := by
  intro i j hij x y; ext k
  by_cases h1 : i = k;
  · subst h1
    simp [hij]
  by_cases h2 : j = k;
  · subst h2
    

Proof state:
case pos
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y✝ : (i : I) → f i
i✝ j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → MulOneClass (f i)
i j : I
hij : i ≠ j
x : f i
y : f j
h1 : ¬i = j
⊢ (mulSingle i x * mulSingle j y) j = (mulSingle j y * mulSingle i x) j

Next tactic:
simp [hij]
/-- The injection into a pi group at different indices commutes.

For injections of commuting elements at the same index, see `Commute.map` -/
@[to_additive
      "The injection into an additive pi group at different indices commutes.

      For injections of commuting elements at the same index, see `AddCommute.map`"]
theorem Pi.mulSingle_commute [∀ i, MulOneClass <| f i] :
    Pairwise fun i j => ∀ (x : f i) (y : f j), Commute (mulSingle i x) (mulSingle j y) := by
  intro i j hij x y; ext k
  by_cases h1 : i = k;
  · subst h1
    simp [hij]
  by_cases h2 : j = k;
  · subst h2
    simp [hij]
  

Proof state:
case neg
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y✝ : (i : I) → f i
i✝ j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → MulOneClass (f i)
i j : I
hij : i ≠ j
x : f i
y : f j
k : I
h1 : ¬i = k
h2 : ¬j = k
⊢ (mulSingle i x * mulSingle j y) k = (mulSingle j y * mulSingle i x) k

Next tactic:
simp [h1, h2]
/-- The injection into a pi group with the same values commutes. -/
@[to_additive "The injection into an additive pi group with the same values commutes."]
theorem Pi.mulSingle_apply_commute [∀ i, MulOneClass <| f i] (x : ∀ i, f i) (i j : I) :
    Commute (mulSingle i (x i)) (mulSingle j (x j)) := by
  

Proof state:
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y : (i : I) → f i
i✝ j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → MulOneClass (f i)
x : (i : I) → f i
i j : I
⊢ Commute (mulSingle i (x i)) (mulSingle j (x j))

Next tactic:
obtain rfl | hij := Decidable.eq_or_ne i j
/-- The injection into a pi group with the same values commutes. -/
@[to_additive "The injection into an additive pi group with the same values commutes."]
theorem Pi.mulSingle_apply_commute [∀ i, MulOneClass <| f i] (x : ∀ i, f i) (i j : I) :
    Commute (mulSingle i (x i)) (mulSingle j (x j)) := by
  obtain rfl | hij := Decidable.eq_or_ne i j
  · 

Proof state:
case inl
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y : (i : I) → f i
i✝ j : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → MulOneClass (f i)
x : (i : I) → f i
i : I
⊢ Commute (mulSingle i (x i)) (mulSingle i (x i))

Next tactic:
rfl
/-- The injection into a pi group with the same values commutes. -/
@[to_additive "The injection into an additive pi group with the same values commutes."]
theorem Pi.mulSingle_apply_commute [∀ i, MulOneClass <| f i] (x : ∀ i, f i) (i j : I) :
    Commute (mulSingle i (x i)) (mulSingle j (x j)) := by
  obtain rfl | hij := Decidable.eq_or_ne i j
  · rfl
  · 

Proof state:
case inr
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y : (i : I) → f i
i✝ j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → MulOneClass (f i)
x : (i : I) → f i
i j : I
hij : i ≠ j
⊢ Commute (mulSingle i (x i)) (mulSingle j (x j))

Next tactic:
exact Pi.mulSingle_commute hij _ _
@[to_additive]
theorem Pi.update_eq_div_mul_mulSingle [∀ i, Group <| f i] (g : ∀ i : I, f i) (x : f i) :
    Function.update g i x = g / mulSingle i (g i) * mulSingle i x := by
  

Proof state:
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → Group (f i)
g : (i : I) → f i
x : f i
⊢ Function.update g i x = g / mulSingle i (g i) * mulSingle i x

Next tactic:
ext j
@[to_additive]
theorem Pi.update_eq_div_mul_mulSingle [∀ i, Group <| f i] (g : ∀ i : I, f i) (x : f i) :
    Function.update g i x = g / mulSingle i (g i) * mulSingle i x := by
  ext j
  

Proof state:
case h
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y : (i : I) → f i
i j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → Group (f i)
g : (i : I) → f i
x : f i
j : I
⊢ Function.update g i x j = (g / mulSingle i (g i) * mulSingle i x) j

Next tactic:
rcases eq_or_ne i j with (rfl | h)
@[to_additive]
theorem Pi.update_eq_div_mul_mulSingle [∀ i, Group <| f i] (g : ∀ i : I, f i) (x : f i) :
    Function.update g i x = g / mulSingle i (g i) * mulSingle i x := by
  ext j
  rcases eq_or_ne i j with (rfl | h)
  · 

Proof state:
case h.inl
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → Group (f i)
g : (i : I) → f i
x : f i
⊢ Function.update g i x i = (g / mulSingle i (g i) * mulSingle i x) i

Next tactic:
simp
@[to_additive]
theorem Pi.update_eq_div_mul_mulSingle [∀ i, Group <| f i] (g : ∀ i : I, f i) (x : f i) :
    Function.update g i x = g / mulSingle i (g i) * mulSingle i x := by
  ext j
  rcases eq_or_ne i j with (rfl | h)
  · simp
  · 

Proof state:
case h.inr
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x✝ y : (i : I) → f i
i j✝ : I
inst✝¹ : DecidableEq I
inst✝ : (i : I) → Group (f i)
g : (i : I) → f i
x : f i
j : I
h : i ≠ j
⊢ Function.update g i x j = (g / mulSingle i (g i) * mulSingle i x) j

Next tactic:
simp [Function.update_noteq h.symm, h]
@[to_additive]
theorem Pi.mulSingle_mul_mulSingle_eq_mulSingle_mul_mulSingle {M : Type*} [CommMonoid M]
    {k l m n : I} {u v : M} (hu : u ≠ 1) (hv : v ≠ 1) :
    (mulSingle k u : I → M) * mulSingle l v = mulSingle m u * mulSingle n v ↔
      k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n := by
  

Proof state:
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
M : Type u_3
inst✝ : CommMonoid M
k l m n : I
u v : M
hu : u ≠ 1
hv : v ≠ 1
⊢ mulSingle k u * mulSingle l v = mulSingle m u * mulSingle n v ↔
    k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n

Next tactic:
refine' ⟨fun h => _, _⟩
@[to_additive]
theorem Pi.mulSingle_mul_mulSingle_eq_mulSingle_mul_mulSingle {M : Type*} [CommMonoid M]
    {k l m n : I} {u v : M} (hu : u ≠ 1) (hv : v ≠ 1) :
    (mulSingle k u : I → M) * mulSingle l v = mulSingle m u * mulSingle n v ↔
      k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n := by
  refine' ⟨fun h => _, _⟩
  · 

Proof state:
case refine'_1
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
M : Type u_3
inst✝ : CommMonoid M
k l m n : I
u v : M
hu : u ≠ 1
hv : v ≠ 1
h : mulSingle k u * mulSingle l v = mulSingle m u * mulSingle n v
⊢ k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n

Next tactic:
have hk := congr_fun h k
@[to_additive]
theorem Pi.mulSingle_mul_mulSingle_eq_mulSingle_mul_mulSingle {M : Type*} [CommMonoid M]
    {k l m n : I} {u v : M} (hu : u ≠ 1) (hv : v ≠ 1) :
    (mulSingle k u : I → M) * mulSingle l v = mulSingle m u * mulSingle n v ↔
      k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n := by
  refine' ⟨fun h => _, _⟩
  · have hk := congr_fun h k
    

Proof state:
case refine'_1
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
M : Type u_3
inst✝ : CommMonoid M
k l m n : I
u v : M
hu : u ≠ 1
hv : v ≠ 1
h : mulSingle k u * mulSingle l v = mulSingle m u * mulSingle n v
hk : (mulSingle k u * mulSingle l v) k = (mulSingle m u * mulSingle n v) k
⊢ k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n

Next tactic:
have hl := congr_fun h l
@[to_additive]
theorem Pi.mulSingle_mul_mulSingle_eq_mulSingle_mul_mulSingle {M : Type*} [CommMonoid M]
    {k l m n : I} {u v : M} (hu : u ≠ 1) (hv : v ≠ 1) :
    (mulSingle k u : I → M) * mulSingle l v = mulSingle m u * mulSingle n v ↔
      k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n := by
  refine' ⟨fun h => _, _⟩
  · have hk := congr_fun h k
    have hl := congr_fun h l
    

Proof state:
case refine'_1
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
M : Type u_3
inst✝ : CommMonoid M
k l m n : I
u v : M
hu : u ≠ 1
hv : v ≠ 1
h : mulSingle k u * mulSingle l v = mulSingle m u * mulSingle n v
hk : (mulSingle k u * mulSingle l v) k = (mulSingle m u * mulSingle n v) k
hl : (mulSingle k u * mulSingle l v) l = (mulSingle m u * mulSingle n v) l
⊢ k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n

Next tactic:
have hm := (congr_fun h m).symm
@[to_additive]
theorem Pi.mulSingle_mul_mulSingle_eq_mulSingle_mul_mulSingle {M : Type*} [CommMonoid M]
    {k l m n : I} {u v : M} (hu : u ≠ 1) (hv : v ≠ 1) :
    (mulSingle k u : I → M) * mulSingle l v = mulSingle m u * mulSingle n v ↔
      k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n := by
  refine' ⟨fun h => _, _⟩
  · have hk := congr_fun h k
    have hl := congr_fun h l
    have hm := (congr_fun h m).symm
    

Proof state:
case refine'_1
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
M : Type u_3
inst✝ : CommMonoid M
k l m n : I
u v : M
hu : u ≠ 1
hv : v ≠ 1
h : mulSingle k u * mulSingle l v = mulSingle m u * mulSingle n v
hk : (mulSingle k u * mulSingle l v) k = (mulSingle m u * mulSingle n v) k
hl : (mulSingle k u * mulSingle l v) l = (mulSingle m u * mulSingle n v) l
hm : (mulSingle m u * mulSingle n v) m = (mulSingle k u * mulSingle l v) m
⊢ k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n

Next tactic:
have hn := (congr_fun h n).symm
@[to_additive]
theorem Pi.mulSingle_mul_mulSingle_eq_mulSingle_mul_mulSingle {M : Type*} [CommMonoid M]
    {k l m n : I} {u v : M} (hu : u ≠ 1) (hv : v ≠ 1) :
    (mulSingle k u : I → M) * mulSingle l v = mulSingle m u * mulSingle n v ↔
      k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n := by
  refine' ⟨fun h => _, _⟩
  · have hk := congr_fun h k
    have hl := congr_fun h l
    have hm := (congr_fun h m).symm
    have hn := (congr_fun h n).symm
    

Proof state:
case refine'_1
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
M : Type u_3
inst✝ : CommMonoid M
k l m n : I
u v : M
hu : u ≠ 1
hv : v ≠ 1
h : mulSingle k u * mulSingle l v = mulSingle m u * mulSingle n v
hk : (mulSingle k u * mulSingle l v) k = (mulSingle m u * mulSingle n v) k
hl : (mulSingle k u * mulSingle l v) l = (mulSingle m u * mulSingle n v) l
hm : (mulSingle m u * mulSingle n v) m = (mulSingle k u * mulSingle l v) m
hn : (mulSingle m u * mulSingle n v) n = (mulSingle k u * mulSingle l v) n
⊢ k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n

Next tactic:
simp only [mul_apply, mulSingle_apply, if_pos rfl] at hk hl hm hn
@[to_additive]
theorem Pi.mulSingle_mul_mulSingle_eq_mulSingle_mul_mulSingle {M : Type*} [CommMonoid M]
    {k l m n : I} {u v : M} (hu : u ≠ 1) (hv : v ≠ 1) :
    (mulSingle k u : I → M) * mulSingle l v = mulSingle m u * mulSingle n v ↔
      k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n := by
  refine' ⟨fun h => _, _⟩
  · have hk := congr_fun h k
    have hl := congr_fun h l
    have hm := (congr_fun h m).symm
    have hn := (congr_fun h n).symm
    simp only [mul_apply, mulSingle_apply, if_pos rfl] at hk hl hm hn
    

Proof state:
case refine'_1
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
M : Type u_3
inst✝ : CommMonoid M
k l m n : I
u v : M
hu : u ≠ 1
hv : v ≠ 1
h : mulSingle k u * mulSingle l v = mulSingle m u * mulSingle n v
hk : ((if True then u else 1) * if k = l then v else 1) = (if k = m then u else 1) * if k = n then v else 1
hl : ((if l = k then u else 1) * if True then v else 1) = (if l = m then u else 1) * if l = n then v else 1
hm : ((if True then u else 1) * if m = n then v else 1) = (if m = k then u else 1) * if m = l then v else 1
hn : ((if n = m then u else 1) * if True then v else 1) = (if n = k then u else 1) * if n = l then v else 1
⊢ k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n

Next tactic:
rcases eq_or_ne k m with (rfl | hkm)
@[to_additive]
theorem Pi.mulSingle_mul_mulSingle_eq_mulSingle_mul_mulSingle {M : Type*} [CommMonoid M]
    {k l m n : I} {u v : M} (hu : u ≠ 1) (hv : v ≠ 1) :
    (mulSingle k u : I → M) * mulSingle l v = mulSingle m u * mulSingle n v ↔
      k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n := by
  refine' ⟨fun h => _, _⟩
  · have hk := congr_fun h k
    have hl := congr_fun h l
    have hm := (congr_fun h m).symm
    have hn := (congr_fun h n).symm
    simp only [mul_apply, mulSingle_apply, if_pos rfl] at hk hl hm hn
    rcases eq_or_ne k m with (rfl | hkm)
    · 

Proof state:
case refine'_1.inl
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
M : Type u_3
inst✝ : CommMonoid M
k l n : I
u v : M
hu : u ≠ 1
hv : v ≠ 1
h : mulSingle k u * mulSingle l v = mulSingle k u * mulSingle n v
hk : ((if True then u else 1) * if k = l then v else 1) = (if k = k then u else 1) * if k = n then v else 1
hl : ((if l = k then u else 1) * if True then v else 1) = (if l = k then u else 1) * if l = n then v else 1
hm : ((if True then u else 1) * if k = n then v else 1) = (if k = k then u else 1) * if k = l then v else 1
hn : ((if n = k then u else 1) * if True then v else 1) = (if n = k then u else 1) * if n = l then v else 1
⊢ k = k ∧ l = n ∨ u = v ∧ k = n ∧ l = k ∨ u * v = 1 ∧ k = l ∧ k = n

Next tactic:
refine' Or.inl ⟨rfl, not_ne_iff.mp fun hln => (hv _).elim⟩
@[to_additive]
theorem Pi.mulSingle_mul_mulSingle_eq_mulSingle_mul_mulSingle {M : Type*} [CommMonoid M]
    {k l m n : I} {u v : M} (hu : u ≠ 1) (hv : v ≠ 1) :
    (mulSingle k u : I → M) * mulSingle l v = mulSingle m u * mulSingle n v ↔
      k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n := by
  refine' ⟨fun h => _, _⟩
  · have hk := congr_fun h k
    have hl := congr_fun h l
    have hm := (congr_fun h m).symm
    have hn := (congr_fun h n).symm
    simp only [mul_apply, mulSingle_apply, if_pos rfl] at hk hl hm hn
    rcases eq_or_ne k m with (rfl | hkm)
    · refine' Or.inl ⟨rfl, not_ne_iff.mp fun hln => (hv _).elim⟩
      

Proof state:
case refine'_1.inl
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
M : Type u_3
inst✝ : CommMonoid M
k l n : I
u v : M
hu : u ≠ 1
hv : v ≠ 1
h : mulSingle k u * mulSingle l v = mulSingle k u * mulSingle n v
hk : ((if True then u else 1) * if k = l then v else 1) = (if k = k then u else 1) * if k = n then v else 1
hl : ((if l = k then u else 1) * if True then v else 1) = (if l = k then u else 1) * if l = n then v else 1
hm : ((if True then u else 1) * if k = n then v else 1) = (if k = k then u else 1) * if k = l then v else 1
hn : ((if n = k then u else 1) * if True then v else 1) = (if n = k then u else 1) * if n = l then v else 1
hln : l ≠ n
⊢ v = 1

Next tactic:
rcases eq_or_ne k l with (rfl | hkl)
@[to_additive]
theorem Pi.mulSingle_mul_mulSingle_eq_mulSingle_mul_mulSingle {M : Type*} [CommMonoid M]
    {k l m n : I} {u v : M} (hu : u ≠ 1) (hv : v ≠ 1) :
    (mulSingle k u : I → M) * mulSingle l v = mulSingle m u * mulSingle n v ↔
      k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n := by
  refine' ⟨fun h => _, _⟩
  · have hk := congr_fun h k
    have hl := congr_fun h l
    have hm := (congr_fun h m).symm
    have hn := (congr_fun h n).symm
    simp only [mul_apply, mulSingle_apply, if_pos rfl] at hk hl hm hn
    rcases eq_or_ne k m with (rfl | hkm)
    · refine' Or.inl ⟨rfl, not_ne_iff.mp fun hln => (hv _).elim⟩
      rcases eq_or_ne k l with (rfl | hkl)
      · 

Proof state:
case refine'_1.inl.inl
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
M : Type u_3
inst✝ : CommMonoid M
k n : I
u v : M
hu : u ≠ 1
hv : v ≠ 1
h : mulSingle k u * mulSingle k v = mulSingle k u * mulSingle n v
hk : ((if True then u else 1) * if k = k then v else 1) = (if k = k then u else 1) * if k = n then v else 1
hl : ((if k = k then u else 1) * if True then v else 1) = (if k = k then u else 1) * if k = n then v else 1
hm : ((if True then u else 1) * if k = n then v else 1) = (if k = k then u else 1) * if k = k then v else 1
hn : ((if n = k then u else 1) * if True then v else 1) = (if n = k then u else 1) * if n = k then v else 1
hln : k ≠ n
⊢ v = 1

Next tactic:
rwa [if_neg hln.symm, if_neg hln.symm, one_mul, one_mul] at hn
@[to_additive]
theorem Pi.mulSingle_mul_mulSingle_eq_mulSingle_mul_mulSingle {M : Type*} [CommMonoid M]
    {k l m n : I} {u v : M} (hu : u ≠ 1) (hv : v ≠ 1) :
    (mulSingle k u : I → M) * mulSingle l v = mulSingle m u * mulSingle n v ↔
      k = m ∧ l = n ∨ u = v ∧ k = n ∧ l = m ∨ u * v = 1 ∧ k = l ∧ m = n := by
  refine' ⟨fun h => _, _⟩
  · have hk := congr_fun h k
    have hl := congr_fun h l
    have hm := (congr_fun h m).symm
    have hn := (congr_fun h n).symm
    simp only [mul_apply, mulSingle_apply, if_pos rfl] at hk hl hm hn
    rcases eq_or_ne k m with (rfl | hkm)
    · refine' Or.inl ⟨rfl, not_ne_iff.mp fun hln => (hv _).elim⟩
      rcases eq_or_ne k l with (rfl | hkl)
      · rwa [if_neg hln.symm, if_neg hln.symm, one_mul, one_mul] at hn
      · 

Proof state:
case refine'_1.inl.inr
ι : Type u_1
α : Type u_2
I : Type u
f : I → Type v
x y : (i : I) → f i
i j : I
inst✝¹ : DecidableEq I
M : Type u_3
inst✝ : CommMonoid M
k l n : I
u v : M
hu : u ≠ 1
hv : v ≠ 1
h : mulSingle k u * mulSingle l v = mulSingle k u * mulSingle n v
hk : ((if True then u else 1) * if k = l then v else 1) = (if k = k then u else 1) * if k = n then v else 1
hl : ((if l = k then u else 1) * if True then v else 1) = (if l = k then u else 1) * if l = n then v else 1
hm : ((if True then u else 1) * if k = n then v else 1) = (if k = k then u else 1) * if k = l then v else 1
hn : ((if n = k then u else 1) * if True then v else 1) = (if n = k then u else 1) * if n = l then v else 1
hln : l ≠ n
hkl : k ≠ l
⊢ v = 1

Next tactic:
rwa [if_neg hkl.symm, if_neg hln, one_mul, one_mul] at hl