l3lab/ntp-mathlib huggingface dataset:
@[to_additive]
theorem prod_univ_add {M : Type*} [CommMonoid M] {a b : ℕ} (f : Fin (a + b) → M) :
    (∏ i : Fin (a + b), f i) = (∏ i : Fin a, f (castAdd b i)) * ∏ i : Fin b, f (natAdd a i) := by
  

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
inst✝ : CommMonoid M
a b : ℕ
f : Fin (a + b) → M
⊢ ∏ i : Fin (a + b), f i = (∏ i : Fin a, f (castAdd b i)) * ∏ i : Fin b, f (natAdd a i)

Next tactic:
rw [Fintype.prod_equiv finSumFinEquiv.symm f fun i => f (finSumFinEquiv.toFun i)]
@[to_additive]
theorem prod_univ_add {M : Type*} [CommMonoid M] {a b : ℕ} (f : Fin (a + b) → M) :
    (∏ i : Fin (a + b), f i) = (∏ i : Fin a, f (castAdd b i)) * ∏ i : Fin b, f (natAdd a i) := by
  rw [Fintype.prod_equiv finSumFinEquiv.symm f fun i => f (finSumFinEquiv.toFun i)]
  · 

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
inst✝ : CommMonoid M
a b : ℕ
f : Fin (a + b) → M
⊢ ∏ x : Fin a ⊕ Fin b, f (Equiv.toFun finSumFinEquiv x) = (∏ i : Fin a, f (castAdd b i)) * ∏ i : Fin b, f (natAdd a i)

Next tactic:
apply Fintype.prod_sum_type
@[to_additive]
theorem prod_univ_add {M : Type*} [CommMonoid M] {a b : ℕ} (f : Fin (a + b) → M) :
    (∏ i : Fin (a + b), f i) = (∏ i : Fin a, f (castAdd b i)) * ∏ i : Fin b, f (natAdd a i) := by
  rw [Fintype.prod_equiv finSumFinEquiv.symm f fun i => f (finSumFinEquiv.toFun i)]
  · apply Fintype.prod_sum_type
  · 

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
inst✝ : CommMonoid M
a b : ℕ
f : Fin (a + b) → M
⊢ ∀ (x : Fin (a + b)), f x = f (Equiv.toFun finSumFinEquiv (finSumFinEquiv.symm x))

Next tactic:
intro x
@[to_additive]
theorem prod_univ_add {M : Type*} [CommMonoid M] {a b : ℕ} (f : Fin (a + b) → M) :
    (∏ i : Fin (a + b), f i) = (∏ i : Fin a, f (castAdd b i)) * ∏ i : Fin b, f (natAdd a i) := by
  rw [Fintype.prod_equiv finSumFinEquiv.symm f fun i => f (finSumFinEquiv.toFun i)]
  · apply Fintype.prod_sum_type
  · intro x
    

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
inst✝ : CommMonoid M
a b : ℕ
f : Fin (a + b) → M
x : Fin (a + b)
⊢ f x = f (Equiv.toFun finSumFinEquiv (finSumFinEquiv.symm x))

Next tactic:
simp only [Equiv.toFun_as_coe, Equiv.apply_symm_apply]
@[to_additive]
theorem prod_trunc {M : Type*} [CommMonoid M] {a b : ℕ} (f : Fin (a + b) → M)
    (hf : ∀ j : Fin b, f (natAdd a j) = 1) :
    (∏ i : Fin (a + b), f i) = ∏ i : Fin a, f (castLE (Nat.le.intro rfl) i) := by
  

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
inst✝ : CommMonoid M
a b : ℕ
f : Fin (a + b) → M
hf : ∀ (j : Fin b), f (natAdd a j) = 1
⊢ ∏ i : Fin (a + b), f i = ∏ i : Fin a, f (castLE (_ : a ≤ a + b) i)

Next tactic:
rw [prod_univ_add, Fintype.prod_eq_one _ hf, mul_one]
@[to_additive]
theorem prod_trunc {M : Type*} [CommMonoid M] {a b : ℕ} (f : Fin (a + b) → M)
    (hf : ∀ j : Fin b, f (natAdd a j) = 1) :
    (∏ i : Fin (a + b), f i) = ∏ i : Fin a, f (castLE (Nat.le.intro rfl) i) := by
  rw [prod_univ_add, Fintype.prod_eq_one _ hf, mul_one]
  

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
inst✝ : CommMonoid M
a b : ℕ
f : Fin (a + b) → M
hf : ∀ (j : Fin b), f (natAdd a j) = 1
⊢ ∏ i : Fin a, f (castAdd b i) = ∏ i : Fin a, f (castLE (_ : a ≤ a + b) i)

Next tactic:
rfl
@[to_additive (attr := simp)]
theorem partialProd_zero (f : Fin n → α) : partialProd f 0 = 1 := by 

Proof state:
α : Type u_1
β : Type u_2
inst✝ : Monoid α
n : ℕ
f : Fin n → α
⊢ partialProd f 0 = 1

Next tactic:
simp [partialProd]
@[to_additive]
theorem partialProd_succ (f : Fin n → α) (j : Fin n) :
    partialProd f j.succ = partialProd f (Fin.castSucc j) * f j := by
  

Proof state:
α : Type u_1
β : Type u_2
inst✝ : Monoid α
n : ℕ
f : Fin n → α
j : Fin n
⊢ partialProd f (succ j) = partialProd f (castSucc j) * f j

Next tactic:
simp [partialProd, List.take_succ, List.ofFnNthVal, dif_pos j.is_lt, ← Option.coe_def]
@[to_additive]
theorem partialProd_succ' (f : Fin (n + 1) → α) (j : Fin (n + 1)) :
    partialProd f j.succ = f 0 * partialProd (Fin.tail f) j := by
  

Proof state:
α : Type u_1
β : Type u_2
inst✝ : Monoid α
n : ℕ
f : Fin (n + 1) → α
j : Fin (n + 1)
⊢ partialProd f (succ j) = f 0 * partialProd (tail f) j

Next tactic:
simp [partialProd]
@[to_additive]
theorem partialProd_succ' (f : Fin (n + 1) → α) (j : Fin (n + 1)) :
    partialProd f j.succ = f 0 * partialProd (Fin.tail f) j := by
  simp [partialProd]
  

Proof state:
α : Type u_1
β : Type u_2
inst✝ : Monoid α
n : ℕ
f : Fin (n + 1) → α
j : Fin (n + 1)
⊢ f 0 * List.prod (List.take (↑j) (List.ofFn fun i => f (succ i))) =
    f 0 * List.prod (List.take (↑j) (List.ofFn (tail f)))

Next tactic:
rfl
@[to_additive]
theorem partialProd_left_inv {G : Type*} [Group G] (f : Fin (n + 1) → G) :
    (f 0 • partialProd fun i : Fin n => (f i)⁻¹ * f i.succ) = f :=
  funext fun x => Fin.inductionOn x (by 

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin (n + 1) → G
x : Fin (n + 1)
⊢ (f 0 • partialProd fun i => (f ↑↑i)⁻¹ * f (succ i)) 0 = f 0

Next tactic:
simp
@[to_additive]
theorem partialProd_left_inv {G : Type*} [Group G] (f : Fin (n + 1) → G) :
    (f 0 • partialProd fun i : Fin n => (f i)⁻¹ * f i.succ) = f :=
  funext fun x => Fin.inductionOn x (by simp) fun x hx => by
    

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin (n + 1) → G
x✝ : Fin (n + 1)
x : Fin n
hx : (f 0 • partialProd fun i => (f ↑↑i)⁻¹ * f (succ i)) (castSucc x) = f (castSucc x)
⊢ (f 0 • partialProd fun i => (f ↑↑i)⁻¹ * f (succ i)) (succ x) = f (succ x)

Next tactic:
simp only [coe_eq_castSucc, Pi.smul_apply, smul_eq_mul] at hx ⊢
@[to_additive]
theorem partialProd_left_inv {G : Type*} [Group G] (f : Fin (n + 1) → G) :
    (f 0 • partialProd fun i : Fin n => (f i)⁻¹ * f i.succ) = f :=
  funext fun x => Fin.inductionOn x (by simp) fun x hx => by
    simp only [coe_eq_castSucc, Pi.smul_apply, smul_eq_mul] at hx ⊢
    

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin (n + 1) → G
x✝ : Fin (n + 1)
x : Fin n
hx : f 0 * partialProd (fun i => (f (castSucc i))⁻¹ * f (succ i)) (castSucc x) = f (castSucc x)
⊢ f 0 * partialProd (fun i => (f (castSucc i))⁻¹ * f (succ i)) (succ x) = f (succ x)

Next tactic:
rw [partialProd_succ, ← mul_assoc, hx, mul_inv_cancel_left]
@[to_additive]
theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) :
    (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by
  

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
i : Fin n
⊢ (partialProd f (castSucc i))⁻¹ * partialProd f (succ i) = f i

Next tactic:
cases' i with i hn
@[to_additive]
theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) :
    (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by
  cases' i with i hn
  

Proof state:
case mk
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
i : ℕ
hn : i < n
⊢ (partialProd f (castSucc { val := i, isLt := hn }))⁻¹ * partialProd f (succ { val := i, isLt := hn }) =
    f { val := i, isLt := hn }

Next tactic:
induction i with
  | zero => simp [-Fin.succ_mk, partialProd_succ]
  | succ i hi =>
    specialize hi (lt_trans (Nat.lt_succ_self i) hn)
    simp only [Fin.coe_eq_castSucc, Fin.succ_mk, Fin.castSucc_mk] at hi ⊢
    rw [← Fin.succ_mk _ _ (lt_trans (Nat.lt_succ_self _) hn), ← Fin.succ_mk]
    rw [Nat.succ_eq_add_one] at hn
    simp only [partialProd_succ, mul_inv_rev, Fin.castSucc_mk]
    -- Porting note: was
    -- assoc_rw [hi, inv_mul_cancel_left]
    rw [← mul_assoc, mul_left_eq_self, mul_assoc, hi, mul_left_inv]
@[to_additive]
theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) :
    (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by
  cases' i with i hn
  induction i with
  

Proof state:
case mk.zero
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
hn : Nat.zero < n
⊢ (partialProd f (castSucc { val := Nat.zero, isLt := hn }))⁻¹ * partialProd f (succ { val := Nat.zero, isLt := hn }) =
    f { val := Nat.zero, isLt := hn }

Next tactic:
| zero => simp [-Fin.succ_mk, partialProd_succ]
@[to_additive]
theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) :
    (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by
  cases' i with i hn
  induction i with
  | zero => 

Proof state:
case mk.zero
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
hn : Nat.zero < n
⊢ (partialProd f (castSucc { val := Nat.zero, isLt := hn }))⁻¹ * partialProd f (succ { val := Nat.zero, isLt := hn }) =
    f { val := Nat.zero, isLt := hn }

Next tactic:
simp [-Fin.succ_mk, partialProd_succ]
@[to_additive]
theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) :
    (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by
  cases' i with i hn
  induction i with
  | zero => simp [-Fin.succ_mk, partialProd_succ]
  

Proof state:
case mk.succ
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
i : ℕ
hi :
  ∀ (hn : i < n),
    (partialProd f (castSucc { val := i, isLt := hn }))⁻¹ * partialProd f (succ { val := i, isLt := hn }) =
      f { val := i, isLt := hn }
hn : Nat.succ i < n
⊢ (partialProd f (castSucc { val := Nat.succ i, isLt := hn }))⁻¹ *
      partialProd f (succ { val := Nat.succ i, isLt := hn }) =
    f { val := Nat.succ i, isLt := hn }

Next tactic:
| succ i hi =>
    specialize hi (lt_trans (Nat.lt_succ_self i) hn)
    simp only [Fin.coe_eq_castSucc, Fin.succ_mk, Fin.castSucc_mk] at hi ⊢
    rw [← Fin.succ_mk _ _ (lt_trans (Nat.lt_succ_self _) hn), ← Fin.succ_mk]
    rw [Nat.succ_eq_add_one] at hn
    simp only [partialProd_succ, mul_inv_rev, Fin.castSucc_mk]
    -- Porting note: was
    -- assoc_rw [hi, inv_mul_cancel_left]
    rw [← mul_assoc, mul_left_eq_self, mul_assoc, hi, mul_left_inv]
@[to_additive]
theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) :
    (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by
  cases' i with i hn
  induction i with
  | zero => simp [-Fin.succ_mk, partialProd_succ]
  | succ i hi =>
    

Proof state:
case mk.succ
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
i : ℕ
hi :
  ∀ (hn : i < n),
    (partialProd f (castSucc { val := i, isLt := hn }))⁻¹ * partialProd f (succ { val := i, isLt := hn }) =
      f { val := i, isLt := hn }
hn : Nat.succ i < n
⊢ (partialProd f (castSucc { val := Nat.succ i, isLt := hn }))⁻¹ *
      partialProd f (succ { val := Nat.succ i, isLt := hn }) =
    f { val := Nat.succ i, isLt := hn }

Next tactic:
specialize hi (lt_trans (Nat.lt_succ_self i) hn)
@[to_additive]
theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) :
    (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by
  cases' i with i hn
  induction i with
  | zero => simp [-Fin.succ_mk, partialProd_succ]
  | succ i hi =>
    specialize hi (lt_trans (Nat.lt_succ_self i) hn)
    

Proof state:
case mk.succ
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
i : ℕ
hn : Nat.succ i < n
hi :
  (partialProd f (castSucc { val := i, isLt := (_ : i < n) }))⁻¹ *
      partialProd f (succ { val := i, isLt := (_ : i < n) }) =
    f { val := i, isLt := (_ : i < n) }
⊢ (partialProd f (castSucc { val := Nat.succ i, isLt := hn }))⁻¹ *
      partialProd f (succ { val := Nat.succ i, isLt := hn }) =
    f { val := Nat.succ i, isLt := hn }

Next tactic:
simp only [Fin.coe_eq_castSucc, Fin.succ_mk, Fin.castSucc_mk] at hi ⊢
@[to_additive]
theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) :
    (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by
  cases' i with i hn
  induction i with
  | zero => simp [-Fin.succ_mk, partialProd_succ]
  | succ i hi =>
    specialize hi (lt_trans (Nat.lt_succ_self i) hn)
    simp only [Fin.coe_eq_castSucc, Fin.succ_mk, Fin.castSucc_mk] at hi ⊢
    

Proof state:
case mk.succ
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
i : ℕ
hn : Nat.succ i < n
hi :
  (partialProd f { val := i, isLt := (_ : i < Nat.succ n) })⁻¹ *
      partialProd f { val := i + 1, isLt := (_ : Nat.succ i < Nat.succ n) } =
    f { val := i, isLt := (_ : i < n) }
⊢ (partialProd f { val := Nat.succ i, isLt := (_ : Nat.succ i < Nat.succ n) })⁻¹ *
      partialProd f { val := Nat.succ i + 1, isLt := (_ : Nat.succ (Nat.succ i) < Nat.succ n) } =
    f { val := Nat.succ i, isLt := hn }

Next tactic:
rw [← Fin.succ_mk _ _ (lt_trans (Nat.lt_succ_self _) hn), ← Fin.succ_mk]
@[to_additive]
theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) :
    (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by
  cases' i with i hn
  induction i with
  | zero => simp [-Fin.succ_mk, partialProd_succ]
  | succ i hi =>
    specialize hi (lt_trans (Nat.lt_succ_self i) hn)
    simp only [Fin.coe_eq_castSucc, Fin.succ_mk, Fin.castSucc_mk] at hi ⊢
    rw [← Fin.succ_mk _ _ (lt_trans (Nat.lt_succ_self _) hn), ← Fin.succ_mk]
    

Proof state:
case mk.succ
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
i : ℕ
hn : Nat.succ i < n
hi :
  (partialProd f { val := i, isLt := (_ : i < Nat.succ n) })⁻¹ *
      partialProd f { val := i + 1, isLt := (_ : Nat.succ i < Nat.succ n) } =
    f { val := i, isLt := (_ : i < n) }
⊢ (partialProd f (succ { val := i, isLt := (_ : i < n) }))⁻¹ *
      partialProd f (succ { val := i + 1, isLt := ?mk.succ.h }) =
    f { val := Nat.succ i, isLt := hn }
case mk.succ.h
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
i : ℕ
hn : Nat.succ i < n
hi :
  (partialProd f { val := i, isLt := (_ : i < Nat.succ n) })⁻¹ *
      partialProd f { val := i + 1, isLt := (_ : Nat.succ i < Nat.succ n) } =
    f { val := i, isLt := (_ : i < n) }
⊢ i + 1 < n

Next tactic:
rw [Nat.succ_eq_add_one] at hn
@[to_additive]
theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) :
    (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by
  cases' i with i hn
  induction i with
  | zero => simp [-Fin.succ_mk, partialProd_succ]
  | succ i hi =>
    specialize hi (lt_trans (Nat.lt_succ_self i) hn)
    simp only [Fin.coe_eq_castSucc, Fin.succ_mk, Fin.castSucc_mk] at hi ⊢
    rw [← Fin.succ_mk _ _ (lt_trans (Nat.lt_succ_self _) hn), ← Fin.succ_mk]
    rw [Nat.succ_eq_add_one] at hn
    

Proof state:
case mk.succ
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
i : ℕ
hn✝ : Nat.succ i < n
hn : i + 1 < n
hi :
  (partialProd f { val := i, isLt := (_ : i < Nat.succ n) })⁻¹ *
      partialProd f { val := i + 1, isLt := (_ : Nat.succ i < Nat.succ n) } =
    f { val := i, isLt := (_ : i < n) }
⊢ (partialProd f (succ { val := i, isLt := (_ : i < n) }))⁻¹ *
      partialProd f (succ { val := i + 1, isLt := (_ : i + 1 < n) }) =
    f { val := Nat.succ i, isLt := hn✝ }

Next tactic:
simp only [partialProd_succ, mul_inv_rev, Fin.castSucc_mk]
@[to_additive]
theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) :
    (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by
  cases' i with i hn
  induction i with
  | zero => simp [-Fin.succ_mk, partialProd_succ]
  | succ i hi =>
    specialize hi (lt_trans (Nat.lt_succ_self i) hn)
    simp only [Fin.coe_eq_castSucc, Fin.succ_mk, Fin.castSucc_mk] at hi ⊢
    rw [← Fin.succ_mk _ _ (lt_trans (Nat.lt_succ_self _) hn), ← Fin.succ_mk]
    rw [Nat.succ_eq_add_one] at hn
    simp only [partialProd_succ, mul_inv_rev, Fin.castSucc_mk]
    -- Porting note: was
    -- assoc_rw [hi, inv_mul_cancel_left]
    

Proof state:
case mk.succ
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
f : Fin n → G
i : ℕ
hn✝ : Nat.succ i < n
hn : i + 1 < n
hi :
  (partialProd f { val := i, isLt := (_ : i < Nat.succ n) })⁻¹ *
      partialProd f { val := i + 1, isLt := (_ : Nat.succ i < Nat.succ n) } =
    f { val := i, isLt := (_ : i < n) }
⊢ (f { val := i, isLt := (_ : i < n) })⁻¹ * (partialProd f { val := i, isLt := (_ : i < Nat.succ n) })⁻¹ *
      (partialProd f { val := i + 1, isLt := (_ : i + 1 < Nat.succ n) } * f { val := i + 1, isLt := (_ : i + 1 < n) }) =
    f { val := Nat.succ i, isLt := hn✝ }

Next tactic:
rw [← mul_assoc, mul_left_eq_self, mul_assoc, hi, mul_left_inv]
/-- Let `(g₀, g₁, ..., gₙ)` be a tuple of elements in `Gⁿ⁺¹`.
Then if `k < j`, this says `(g₀g₁...gₖ₋₁)⁻¹ * g₀g₁...gₖ = gₖ`.
If `k = j`, it says `(g₀g₁...gₖ₋₁)⁻¹ * g₀g₁...gₖ₊₁ = gₖgₖ₊₁`.
If `k > j`, it says `(g₀g₁...gₖ)⁻¹ * g₀g₁...gₖ₊₁ = gₖ₊₁.`
Useful for defining group cohomology. -/
@[to_additive
      "Let `(g₀, g₁, ..., gₙ)` be a tuple of elements in `Gⁿ⁺¹`.
      Then if `k < j`, this says `-(g₀ + g₁ + ... + gₖ₋₁) + (g₀ + g₁ + ... + gₖ) = gₖ`.
      If `k = j`, it says `-(g₀ + g₁ + ... + gₖ₋₁) + (g₀ + g₁ + ... + gₖ₊₁) = gₖ + gₖ₊₁`.
      If `k > j`, it says `-(g₀ + g₁ + ... + gₖ) + (g₀ + g₁ + ... + gₖ₊₁) = gₖ₊₁.`
      Useful for defining group cohomology."]
theorem inv_partialProd_mul_eq_contractNth {G : Type*} [Group G] (g : Fin (n + 1) → G)
    (j : Fin (n + 1)) (k : Fin n) :
    (partialProd g (j.succ.succAbove (Fin.castSucc k)))⁻¹ * partialProd g (j.succAbove k).succ =
      j.contractNth (· * ·) g k := by
  

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
g : Fin (n + 1) → G
j : Fin (n + 1)
k : Fin n
⊢ (partialProd g (succAbove (succ j) (castSucc k)))⁻¹ * partialProd g (succ (succAbove j k)) =
    contractNth j (fun x x_1 => x * x_1) g k

Next tactic:
rcases lt_trichotomy (k : ℕ) j with (h | h | h)
/-- Let `(g₀, g₁, ..., gₙ)` be a tuple of elements in `Gⁿ⁺¹`.
Then if `k < j`, this says `(g₀g₁...gₖ₋₁)⁻¹ * g₀g₁...gₖ = gₖ`.
If `k = j`, it says `(g₀g₁...gₖ₋₁)⁻¹ * g₀g₁...gₖ₊₁ = gₖgₖ₊₁`.
If `k > j`, it says `(g₀g₁...gₖ)⁻¹ * g₀g₁...gₖ₊₁ = gₖ₊₁.`
Useful for defining group cohomology. -/
@[to_additive
      "Let `(g₀, g₁, ..., gₙ)` be a tuple of elements in `Gⁿ⁺¹`.
      Then if `k < j`, this says `-(g₀ + g₁ + ... + gₖ₋₁) + (g₀ + g₁ + ... + gₖ) = gₖ`.
      If `k = j`, it says `-(g₀ + g₁ + ... + gₖ₋₁) + (g₀ + g₁ + ... + gₖ₊₁) = gₖ + gₖ₊₁`.
      If `k > j`, it says `-(g₀ + g₁ + ... + gₖ) + (g₀ + g₁ + ... + gₖ₊₁) = gₖ₊₁.`
      Useful for defining group cohomology."]
theorem inv_partialProd_mul_eq_contractNth {G : Type*} [Group G] (g : Fin (n + 1) → G)
    (j : Fin (n + 1)) (k : Fin n) :
    (partialProd g (j.succ.succAbove (Fin.castSucc k)))⁻¹ * partialProd g (j.succAbove k).succ =
      j.contractNth (· * ·) g k := by
  rcases lt_trichotomy (k : ℕ) j with (h | h | h)
  · 

Proof state:
case inl
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
g : Fin (n + 1) → G
j : Fin (n + 1)
k : Fin n
h : ↑k < ↑j
⊢ (partialProd g (succAbove (succ j) (castSucc k)))⁻¹ * partialProd g (succ (succAbove j k)) =
    contractNth j (fun x x_1 => x * x_1) g k

Next tactic:
rwa [succAbove_below, succAbove_below, partialProd_right_inv, contractNth_apply_of_lt]
/-- Let `(g₀, g₁, ..., gₙ)` be a tuple of elements in `Gⁿ⁺¹`.
Then if `k < j`, this says `(g₀g₁...gₖ₋₁)⁻¹ * g₀g₁...gₖ = gₖ`.
If `k = j`, it says `(g₀g₁...gₖ₋₁)⁻¹ * g₀g₁...gₖ₊₁ = gₖgₖ₊₁`.
If `k > j`, it says `(g₀g₁...gₖ)⁻¹ * g₀g₁...gₖ₊₁ = gₖ₊₁.`
Useful for defining group cohomology. -/
@[to_additive
      "Let `(g₀, g₁, ..., gₙ)` be a tuple of elements in `Gⁿ⁺¹`.
      Then if `k < j`, this says `-(g₀ + g₁ + ... + gₖ₋₁) + (g₀ + g₁ + ... + gₖ) = gₖ`.
      If `k = j`, it says `-(g₀ + g₁ + ... + gₖ₋₁) + (g₀ + g₁ + ... + gₖ₊₁) = gₖ + gₖ₊₁`.
      If `k > j`, it says `-(g₀ + g₁ + ... + gₖ) + (g₀ + g₁ + ... + gₖ₊₁) = gₖ₊₁.`
      Useful for defining group cohomology."]
theorem inv_partialProd_mul_eq_contractNth {G : Type*} [Group G] (g : Fin (n + 1) → G)
    (j : Fin (n + 1)) (k : Fin n) :
    (partialProd g (j.succ.succAbove (Fin.castSucc k)))⁻¹ * partialProd g (j.succAbove k).succ =
      j.contractNth (· * ·) g k := by
  rcases lt_trichotomy (k : ℕ) j with (h | h | h)
  · rwa [succAbove_below, succAbove_below, partialProd_right_inv, contractNth_apply_of_lt]
    · 

Proof state:
case inl.h
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
g : Fin (n + 1) → G
j : Fin (n + 1)
k : Fin n
h : ↑k < ↑j
⊢ castSucc k < j

Next tactic:
assumption
/-- Let `(g₀, g₁, ..., gₙ)` be a tuple of elements in `Gⁿ⁺¹`.
Then if `k < j`, this says `(g₀g₁...gₖ₋₁)⁻¹ * g₀g₁...gₖ = gₖ`.
If `k = j`, it says `(g₀g₁...gₖ₋₁)⁻¹ * g₀g₁...gₖ₊₁ = gₖgₖ₊₁`.
If `k > j`, it says `(g₀g₁...gₖ)⁻¹ * g₀g₁...gₖ₊₁ = gₖ₊₁.`
Useful for defining group cohomology. -/
@[to_additive
      "Let `(g₀, g₁, ..., gₙ)` be a tuple of elements in `Gⁿ⁺¹`.
      Then if `k < j`, this says `-(g₀ + g₁ + ... + gₖ₋₁) + (g₀ + g₁ + ... + gₖ) = gₖ`.
      If `k = j`, it says `-(g₀ + g₁ + ... + gₖ₋₁) + (g₀ + g₁ + ... + gₖ₊₁) = gₖ + gₖ₊₁`.
      If `k > j`, it says `-(g₀ + g₁ + ... + gₖ) + (g₀ + g₁ + ... + gₖ₊₁) = gₖ₊₁.`
      Useful for defining group cohomology."]
theorem inv_partialProd_mul_eq_contractNth {G : Type*} [Group G] (g : Fin (n + 1) → G)
    (j : Fin (n + 1)) (k : Fin n) :
    (partialProd g (j.succ.succAbove (Fin.castSucc k)))⁻¹ * partialProd g (j.succAbove k).succ =
      j.contractNth (· * ·) g k := by
  rcases lt_trichotomy (k : ℕ) j with (h | h | h)
  · rwa [succAbove_below, succAbove_below, partialProd_right_inv, contractNth_apply_of_lt]
    · assumption
    · 

Proof state:
case inl.h
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
g : Fin (n + 1) → G
j : Fin (n + 1)
k : Fin n
h : ↑k < ↑j
⊢ castSucc (castSucc k) < succ j

Next tactic:
rw [castSucc_lt_iff_succ_le, succ_le_succ_iff, le_iff_val_le_val]
/-- Let `(g₀, g₁, ..., gₙ)` be a tuple of elements in `Gⁿ⁺¹`.
Then if `k < j`, this says `(g₀g₁...gₖ₋₁)⁻¹ * g₀g₁...gₖ = gₖ`.
If `k = j`, it says `(g₀g₁...gₖ₋₁)⁻¹ * g₀g₁...gₖ₊₁ = gₖgₖ₊₁`.
If `k > j`, it says `(g₀g₁...gₖ)⁻¹ * g₀g₁...gₖ₊₁ = gₖ₊₁.`
Useful for defining group cohomology. -/
@[to_additive
      "Let `(g₀, g₁, ..., gₙ)` be a tuple of elements in `Gⁿ⁺¹`.
      Then if `k < j`, this says `-(g₀ + g₁ + ... + gₖ₋₁) + (g₀ + g₁ + ... + gₖ) = gₖ`.
      If `k = j`, it says `-(g₀ + g₁ + ... + gₖ₋₁) + (g₀ + g₁ + ... + gₖ₊₁) = gₖ + gₖ₊₁`.
      If `k > j`, it says `-(g₀ + g₁ + ... + gₖ) + (g₀ + g₁ + ... + gₖ₊₁) = gₖ₊₁.`
      Useful for defining group cohomology."]
theorem inv_partialProd_mul_eq_contractNth {G : Type*} [Group G] (g : Fin (n + 1) → G)
    (j : Fin (n + 1)) (k : Fin n) :
    (partialProd g (j.succ.succAbove (Fin.castSucc k)))⁻¹ * partialProd g (j.succAbove k).succ =
      j.contractNth (· * ·) g k := by
  rcases lt_trichotomy (k : ℕ) j with (h | h | h)
  · rwa [succAbove_below, succAbove_below, partialProd_right_inv, contractNth_apply_of_lt]
    · assumption
    · rw [castSucc_lt_iff_succ_le, succ_le_succ_iff, le_iff_val_le_val]
      

Proof state:
case inl.h
α : Type u_1
β : Type u_2
inst✝¹ : Monoid α
n : ℕ
G : Type u_3
inst✝ : Group G
g : Fin (n + 1) → G
j : Fin (n + 1)
k : Fin n
h : ↑k < ↑j
⊢ ↑(castSucc k) ≤ ↑j

Next tactic:
exact le_of_lt h