l3lab/ntp-mathlib huggingface dataset:
/-- Equivalence between `∀ i : Fin m, Fin (n i)` and `Fin (∏ i : Fin m, n i)`. -/
def finPiFinEquiv {m : ℕ} {n : Fin m → ℕ} : (∀ i : Fin m, Fin (n i)) ≃ Fin (∏ i : Fin m, n i) :=
  Equiv.ofRightInverseOfCardLE (le_of_eq <| by simp_rw [Fintype.card_pi, Fintype.card_fin])
    (fun f => ⟨∑ i, f i * ∏ j, n (Fin.castLE i.is_lt.le j), by
      induction' m with m ih
      · simp
      rw [Fin.prod_univ_castSucc, Fin.sum_univ_castSucc]
      suffices
        ∀ (n : Fin m → ℕ) (nn : ℕ) (f : ∀ i : Fin m, Fin (n i)) (fn : Fin nn),
          ((∑ i : Fin m, ↑(f i) * ∏ j : Fin i, n (Fin.castLE i.prop.le j)) + ↑fn * ∏ j, n j) <
            (∏ i : Fin m, n i) * nn by
        replace := this (Fin.init n) (n (Fin.last _)) (Fin.init f) (f (Fin.last _))
        rw [← Fin.snoc_init_self f]
        simp (config := { singlePass := true }) only [← Fin.snoc_init_self n]
        simp_rw [Fin.snoc_castSucc, Fin.snoc_last, Fin.snoc_init_self n]
        exact this
      intro n nn f fn
      cases nn
      · dsimp only [Nat.zero_eq] at fn -- porting note: added, wrong zero
        exact isEmptyElim fn
      refine' (add_lt_add_of_lt_of_le (ih _) <| mul_le_mul_right' (Fin.is_le _) _).trans_eq _
      rw [← one_add_mul (_ : ℕ), mul_comm, add_comm]
      -- porting note: added, wrong `succ`
      rfl⟩)
    (fun a b => ⟨(a / ∏ j : Fin b, n (Fin.castLE b.is_lt.le j)) % n b, by
      cases m
      · exact b.elim0
      cases' h : n b with nb
      · rw [prod_eq_zero (Finset.mem_univ _) h] at a
        exact isEmptyElim a
      exact Nat.mod_lt _ nb.succ_pos⟩)
    (by
      intro a; revert a; dsimp only [Fin.val_mk]
      refine' Fin.consInduction _ _ n
      · intro a
        haveI : Subsingleton (Fin (∏ i : Fin 0, i.elim0)) :=
          (Fin.castIso <| prod_empty).toEquiv.subsingleton
        exact Subsingleton.elim _ _
      · intro n x xs ih a
        simp_rw [Fin.forall_iff, Fin.ext_iff] at ih
        ext
        

Proof state:
case refine'_2.h
α : Type u_1
β : Type u_2
m : ℕ
n✝ : Fin m → ℕ
n x : ℕ
xs : Fin n → ℕ
a : Fin (∏ i : Fin (n + 1), Fin.cons x xs i)
ih :
  ∀ i < ∏ i : Fin n, xs i,
    ∑ x : Fin n,
        (i / ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j)) % xs x * ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j) =
      i
⊢ ↑{
        val :=
          ∑ i : Fin (n + 1),
            (↑a / ∏ j : Fin ↑i, Fin.cons x xs (Fin.castLE (_ : ↑i ≤ n + 1) j)) % Fin.cons x xs i *
              ∏ j : Fin ↑i, Fin.cons x xs (Fin.castLE (_ : ↑i ≤ n + 1) j),
        isLt :=
          (_ :
            ∑ i : Fin (n + 1),
                ↑{ val := (↑a / ∏ j : Fin ↑i, Fin.cons x xs (Fin.castLE (_ : ↑i ≤ n + 1) j)) % Fin.cons x xs i,
                      isLt :=
                        (_ :
                          (↑a / ∏ j : Fin ↑i, Fin.cons x xs (Fin.castLE (_ : ↑i ≤ n + 1) j)) % Fin.cons x xs i <
                            Fin.cons x xs i) } *
                  ∏ j : Fin ↑i, Fin.cons x xs (Fin.castLE (_ : ↑i ≤ n + 1) j) <
              ∏ i : Fin (n + 1), Fin.cons x xs i) } =
    ↑a

Next tactic:
simp_rw [Fin.sum_univ_succ, Fin.cons_succ]
/-- Equivalence between `∀ i : Fin m, Fin (n i)` and `Fin (∏ i : Fin m, n i)`. -/
def finPiFinEquiv {m : ℕ} {n : Fin m → ℕ} : (∀ i : Fin m, Fin (n i)) ≃ Fin (∏ i : Fin m, n i) :=
  Equiv.ofRightInverseOfCardLE (le_of_eq <| by simp_rw [Fintype.card_pi, Fintype.card_fin])
    (fun f => ⟨∑ i, f i * ∏ j, n (Fin.castLE i.is_lt.le j), by
      induction' m with m ih
      · simp
      rw [Fin.prod_univ_castSucc, Fin.sum_univ_castSucc]
      suffices
        ∀ (n : Fin m → ℕ) (nn : ℕ) (f : ∀ i : Fin m, Fin (n i)) (fn : Fin nn),
          ((∑ i : Fin m, ↑(f i) * ∏ j : Fin i, n (Fin.castLE i.prop.le j)) + ↑fn * ∏ j, n j) <
            (∏ i : Fin m, n i) * nn by
        replace := this (Fin.init n) (n (Fin.last _)) (Fin.init f) (f (Fin.last _))
        rw [← Fin.snoc_init_self f]
        simp (config := { singlePass := true }) only [← Fin.snoc_init_self n]
        simp_rw [Fin.snoc_castSucc, Fin.snoc_last, Fin.snoc_init_self n]
        exact this
      intro n nn f fn
      cases nn
      · dsimp only [Nat.zero_eq] at fn -- porting note: added, wrong zero
        exact isEmptyElim fn
      refine' (add_lt_add_of_lt_of_le (ih _) <| mul_le_mul_right' (Fin.is_le _) _).trans_eq _
      rw [← one_add_mul (_ : ℕ), mul_comm, add_comm]
      -- porting note: added, wrong `succ`
      rfl⟩)
    (fun a b => ⟨(a / ∏ j : Fin b, n (Fin.castLE b.is_lt.le j)) % n b, by
      cases m
      · exact b.elim0
      cases' h : n b with nb
      · rw [prod_eq_zero (Finset.mem_univ _) h] at a
        exact isEmptyElim a
      exact Nat.mod_lt _ nb.succ_pos⟩)
    (by
      intro a; revert a; dsimp only [Fin.val_mk]
      refine' Fin.consInduction _ _ n
      · intro a
        haveI : Subsingleton (Fin (∏ i : Fin 0, i.elim0)) :=
          (Fin.castIso <| prod_empty).toEquiv.subsingleton
        exact Subsingleton.elim _ _
      · intro n x xs ih a
        simp_rw [Fin.forall_iff, Fin.ext_iff] at ih
        ext
        simp_rw [Fin.sum_univ_succ, Fin.cons_succ]
        

Proof state:
case refine'_2.h
α : Type u_1
β : Type u_2
m : ℕ
n✝ : Fin m → ℕ
n x : ℕ
xs : Fin n → ℕ
a : Fin (∏ i : Fin (n + 1), Fin.cons x xs i)
ih :
  ∀ i < ∏ i : Fin n, xs i,
    ∑ x : Fin n,
        (i / ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j)) % xs x * ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j) =
      i
⊢ (↑a / ∏ j : Fin ↑0, Fin.cons x xs (Fin.castLE (_ : ↑0 ≤ n + 1) j)) % Fin.cons x xs 0 *
        ∏ j : Fin ↑0, Fin.cons x xs (Fin.castLE (_ : ↑0 ≤ n + 1) j) +
      ∑ x_1 : Fin n,
        (↑a / ∏ j : Fin ↑(Fin.succ x_1), Fin.cons x xs (Fin.castLE (_ : ↑(Fin.succ x_1) ≤ n + 1) j)) % xs x_1 *
          ∏ j : Fin ↑(Fin.succ x_1), Fin.cons x xs (Fin.castLE (_ : ↑(Fin.succ x_1) ≤ n + 1) j) =
    ↑a

Next tactic:
have := fun i : Fin n =>
          Fintype.prod_equiv (Fin.castIso <| Fin.val_succ i).toEquiv
            (fun j => (Fin.cons x xs : _ → ℕ) (Fin.castLE (Fin.is_lt _).le j))
            (fun j => (Fin.cons x xs : _ → ℕ) (Fin.castLE (Nat.succ_le_succ (Fin.is_lt _).le) j))
            fun j => rfl
/-- Equivalence between `∀ i : Fin m, Fin (n i)` and `Fin (∏ i : Fin m, n i)`. -/
def finPiFinEquiv {m : ℕ} {n : Fin m → ℕ} : (∀ i : Fin m, Fin (n i)) ≃ Fin (∏ i : Fin m, n i) :=
  Equiv.ofRightInverseOfCardLE (le_of_eq <| by simp_rw [Fintype.card_pi, Fintype.card_fin])
    (fun f => ⟨∑ i, f i * ∏ j, n (Fin.castLE i.is_lt.le j), by
      induction' m with m ih
      · simp
      rw [Fin.prod_univ_castSucc, Fin.sum_univ_castSucc]
      suffices
        ∀ (n : Fin m → ℕ) (nn : ℕ) (f : ∀ i : Fin m, Fin (n i)) (fn : Fin nn),
          ((∑ i : Fin m, ↑(f i) * ∏ j : Fin i, n (Fin.castLE i.prop.le j)) + ↑fn * ∏ j, n j) <
            (∏ i : Fin m, n i) * nn by
        replace := this (Fin.init n) (n (Fin.last _)) (Fin.init f) (f (Fin.last _))
        rw [← Fin.snoc_init_self f]
        simp (config := { singlePass := true }) only [← Fin.snoc_init_self n]
        simp_rw [Fin.snoc_castSucc, Fin.snoc_last, Fin.snoc_init_self n]
        exact this
      intro n nn f fn
      cases nn
      · dsimp only [Nat.zero_eq] at fn -- porting note: added, wrong zero
        exact isEmptyElim fn
      refine' (add_lt_add_of_lt_of_le (ih _) <| mul_le_mul_right' (Fin.is_le _) _).trans_eq _
      rw [← one_add_mul (_ : ℕ), mul_comm, add_comm]
      -- porting note: added, wrong `succ`
      rfl⟩)
    (fun a b => ⟨(a / ∏ j : Fin b, n (Fin.castLE b.is_lt.le j)) % n b, by
      cases m
      · exact b.elim0
      cases' h : n b with nb
      · rw [prod_eq_zero (Finset.mem_univ _) h] at a
        exact isEmptyElim a
      exact Nat.mod_lt _ nb.succ_pos⟩)
    (by
      intro a; revert a; dsimp only [Fin.val_mk]
      refine' Fin.consInduction _ _ n
      · intro a
        haveI : Subsingleton (Fin (∏ i : Fin 0, i.elim0)) :=
          (Fin.castIso <| prod_empty).toEquiv.subsingleton
        exact Subsingleton.elim _ _
      · intro n x xs ih a
        simp_rw [Fin.forall_iff, Fin.ext_iff] at ih
        ext
        simp_rw [Fin.sum_univ_succ, Fin.cons_succ]
        have := fun i : Fin n =>
          Fintype.prod_equiv (Fin.castIso <| Fin.val_succ i).toEquiv
            (fun j => (Fin.cons x xs : _ → ℕ) (Fin.castLE (Fin.is_lt _).le j))
            (fun j => (Fin.cons x xs : _ → ℕ) (Fin.castLE (Nat.succ_le_succ (Fin.is_lt _).le) j))
            fun j => rfl
        simp_rw [this]
        clear this
        

Proof state:
case refine'_2.h
α : Type u_1
β : Type u_2
m : ℕ
n✝ : Fin m → ℕ
n x : ℕ
xs : Fin n → ℕ
a : Fin (∏ i : Fin (n + 1), Fin.cons x xs i)
ih :
  ∀ i < ∏ i : Fin n, xs i,
    ∑ x : Fin n,
        (i / ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j)) % xs x * ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j) =
      i
⊢ (↑a / ∏ j : Fin ↑0, Fin.cons x xs (Fin.castLE (_ : ↑0 ≤ n + 1) j)) % Fin.cons x xs 0 *
        ∏ j : Fin ↑0, Fin.cons x xs (Fin.castLE (_ : ↑0 ≤ n + 1) j) +
      ∑ x_1 : Fin n,
        (↑a / ∏ x_2 : Fin (↑x_1 + 1), Fin.cons x xs (Fin.castLE (_ : Nat.succ ↑x_1 ≤ Nat.succ n) x_2)) % xs x_1 *
          ∏ x_2 : Fin (↑x_1 + 1), Fin.cons x xs (Fin.castLE (_ : Nat.succ ↑x_1 ≤ Nat.succ n) x_2) =
    ↑a

Next tactic:
dsimp only [Fin.val_zero]
/-- Equivalence between `∀ i : Fin m, Fin (n i)` and `Fin (∏ i : Fin m, n i)`. -/
def finPiFinEquiv {m : ℕ} {n : Fin m → ℕ} : (∀ i : Fin m, Fin (n i)) ≃ Fin (∏ i : Fin m, n i) :=
  Equiv.ofRightInverseOfCardLE (le_of_eq <| by simp_rw [Fintype.card_pi, Fintype.card_fin])
    (fun f => ⟨∑ i, f i * ∏ j, n (Fin.castLE i.is_lt.le j), by
      induction' m with m ih
      · simp
      rw [Fin.prod_univ_castSucc, Fin.sum_univ_castSucc]
      suffices
        ∀ (n : Fin m → ℕ) (nn : ℕ) (f : ∀ i : Fin m, Fin (n i)) (fn : Fin nn),
          ((∑ i : Fin m, ↑(f i) * ∏ j : Fin i, n (Fin.castLE i.prop.le j)) + ↑fn * ∏ j, n j) <
            (∏ i : Fin m, n i) * nn by
        replace := this (Fin.init n) (n (Fin.last _)) (Fin.init f) (f (Fin.last _))
        rw [← Fin.snoc_init_self f]
        simp (config := { singlePass := true }) only [← Fin.snoc_init_self n]
        simp_rw [Fin.snoc_castSucc, Fin.snoc_last, Fin.snoc_init_self n]
        exact this
      intro n nn f fn
      cases nn
      · dsimp only [Nat.zero_eq] at fn -- porting note: added, wrong zero
        exact isEmptyElim fn
      refine' (add_lt_add_of_lt_of_le (ih _) <| mul_le_mul_right' (Fin.is_le _) _).trans_eq _
      rw [← one_add_mul (_ : ℕ), mul_comm, add_comm]
      -- porting note: added, wrong `succ`
      rfl⟩)
    (fun a b => ⟨(a / ∏ j : Fin b, n (Fin.castLE b.is_lt.le j)) % n b, by
      cases m
      · exact b.elim0
      cases' h : n b with nb
      · rw [prod_eq_zero (Finset.mem_univ _) h] at a
        exact isEmptyElim a
      exact Nat.mod_lt _ nb.succ_pos⟩)
    (by
      intro a; revert a; dsimp only [Fin.val_mk]
      refine' Fin.consInduction _ _ n
      · intro a
        haveI : Subsingleton (Fin (∏ i : Fin 0, i.elim0)) :=
          (Fin.castIso <| prod_empty).toEquiv.subsingleton
        exact Subsingleton.elim _ _
      · intro n x xs ih a
        simp_rw [Fin.forall_iff, Fin.ext_iff] at ih
        ext
        simp_rw [Fin.sum_univ_succ, Fin.cons_succ]
        have := fun i : Fin n =>
          Fintype.prod_equiv (Fin.castIso <| Fin.val_succ i).toEquiv
            (fun j => (Fin.cons x xs : _ → ℕ) (Fin.castLE (Fin.is_lt _).le j))
            (fun j => (Fin.cons x xs : _ → ℕ) (Fin.castLE (Nat.succ_le_succ (Fin.is_lt _).le) j))
            fun j => rfl
        simp_rw [this]
        clear this
        dsimp only [Fin.val_zero]
        

Proof state:
case refine'_2.h
α : Type u_1
β : Type u_2
m : ℕ
n✝ : Fin m → ℕ
n x : ℕ
xs : Fin n → ℕ
a : Fin (∏ i : Fin (n + 1), Fin.cons x xs i)
ih :
  ∀ i < ∏ i : Fin n, xs i,
    ∑ x : Fin n,
        (i / ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j)) % xs x * ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j) =
      i
⊢ (↑a / ∏ j : Fin 0, Fin.cons x xs (Fin.castLE (_ : 0 ≤ n + 1) j)) % Fin.cons x xs 0 *
        ∏ j : Fin 0, Fin.cons x xs (Fin.castLE (_ : 0 ≤ n + 1) j) +
      ∑ x_1 : Fin n,
        (↑a / ∏ x_2 : Fin (↑x_1 + 1), Fin.cons x xs (Fin.castLE (_ : Nat.succ ↑x_1 ≤ Nat.succ n) x_2)) % xs x_1 *
          ∏ x_2 : Fin (↑x_1 + 1), Fin.cons x xs (Fin.castLE (_ : Nat.succ ↑x_1 ≤ Nat.succ n) x_2) =
    ↑a

Next tactic:
simp_rw [Fintype.prod_empty, Nat.div_one, mul_one, Fin.cons_zero, Fin.prod_univ_succ]
/-- Equivalence between `∀ i : Fin m, Fin (n i)` and `Fin (∏ i : Fin m, n i)`. -/
def finPiFinEquiv {m : ℕ} {n : Fin m → ℕ} : (∀ i : Fin m, Fin (n i)) ≃ Fin (∏ i : Fin m, n i) :=
  Equiv.ofRightInverseOfCardLE (le_of_eq <| by simp_rw [Fintype.card_pi, Fintype.card_fin])
    (fun f => ⟨∑ i, f i * ∏ j, n (Fin.castLE i.is_lt.le j), by
      induction' m with m ih
      · simp
      rw [Fin.prod_univ_castSucc, Fin.sum_univ_castSucc]
      suffices
        ∀ (n : Fin m → ℕ) (nn : ℕ) (f : ∀ i : Fin m, Fin (n i)) (fn : Fin nn),
          ((∑ i : Fin m, ↑(f i) * ∏ j : Fin i, n (Fin.castLE i.prop.le j)) + ↑fn * ∏ j, n j) <
            (∏ i : Fin m, n i) * nn by
        replace := this (Fin.init n) (n (Fin.last _)) (Fin.init f) (f (Fin.last _))
        rw [← Fin.snoc_init_self f]
        simp (config := { singlePass := true }) only [← Fin.snoc_init_self n]
        simp_rw [Fin.snoc_castSucc, Fin.snoc_last, Fin.snoc_init_self n]
        exact this
      intro n nn f fn
      cases nn
      · dsimp only [Nat.zero_eq] at fn -- porting note: added, wrong zero
        exact isEmptyElim fn
      refine' (add_lt_add_of_lt_of_le (ih _) <| mul_le_mul_right' (Fin.is_le _) _).trans_eq _
      rw [← one_add_mul (_ : ℕ), mul_comm, add_comm]
      -- porting note: added, wrong `succ`
      rfl⟩)
    (fun a b => ⟨(a / ∏ j : Fin b, n (Fin.castLE b.is_lt.le j)) % n b, by
      cases m
      · exact b.elim0
      cases' h : n b with nb
      · rw [prod_eq_zero (Finset.mem_univ _) h] at a
        exact isEmptyElim a
      exact Nat.mod_lt _ nb.succ_pos⟩)
    (by
      intro a; revert a; dsimp only [Fin.val_mk]
      refine' Fin.consInduction _ _ n
      · intro a
        haveI : Subsingleton (Fin (∏ i : Fin 0, i.elim0)) :=
          (Fin.castIso <| prod_empty).toEquiv.subsingleton
        exact Subsingleton.elim _ _
      · intro n x xs ih a
        simp_rw [Fin.forall_iff, Fin.ext_iff] at ih
        ext
        simp_rw [Fin.sum_univ_succ, Fin.cons_succ]
        have := fun i : Fin n =>
          Fintype.prod_equiv (Fin.castIso <| Fin.val_succ i).toEquiv
            (fun j => (Fin.cons x xs : _ → ℕ) (Fin.castLE (Fin.is_lt _).le j))
            (fun j => (Fin.cons x xs : _ → ℕ) (Fin.castLE (Nat.succ_le_succ (Fin.is_lt _).le) j))
            fun j => rfl
        simp_rw [this]
        clear this
        dsimp only [Fin.val_zero]
        simp_rw [Fintype.prod_empty, Nat.div_one, mul_one, Fin.cons_zero, Fin.prod_univ_succ]
        change (_ + ∑ y : _, _ / (x * _) % _ * (x * _)) = _
        

Proof state:
case refine'_2.h
α : Type u_1
β : Type u_2
m : ℕ
n✝ : Fin m → ℕ
n x : ℕ
xs : Fin n → ℕ
a : Fin (∏ i : Fin (n + 1), Fin.cons x xs i)
ih :
  ∀ i < ∏ i : Fin n, xs i,
    ∑ x : Fin n,
        (i / ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j)) % xs x * ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j) =
      i
⊢ ↑a % x +
      ∑ y : Fin n,
        ↑a / (x * ∏ i : Fin ↑y, Fin.cons x xs (Fin.castLE (_ : Nat.succ ↑y ≤ Nat.succ n) (Fin.succ i))) % xs y *
          (x * ∏ i : Fin ↑y, Fin.cons x xs (Fin.castLE (_ : Nat.succ ↑y ≤ Nat.succ n) (Fin.succ i))) =
    ↑a

Next tactic:
simp_rw [← Nat.div_div_eq_div_mul, mul_left_comm (_ % _ : ℕ), ← mul_sum]
/-- Equivalence between `∀ i : Fin m, Fin (n i)` and `Fin (∏ i : Fin m, n i)`. -/
def finPiFinEquiv {m : ℕ} {n : Fin m → ℕ} : (∀ i : Fin m, Fin (n i)) ≃ Fin (∏ i : Fin m, n i) :=
  Equiv.ofRightInverseOfCardLE (le_of_eq <| by simp_rw [Fintype.card_pi, Fintype.card_fin])
    (fun f => ⟨∑ i, f i * ∏ j, n (Fin.castLE i.is_lt.le j), by
      induction' m with m ih
      · simp
      rw [Fin.prod_univ_castSucc, Fin.sum_univ_castSucc]
      suffices
        ∀ (n : Fin m → ℕ) (nn : ℕ) (f : ∀ i : Fin m, Fin (n i)) (fn : Fin nn),
          ((∑ i : Fin m, ↑(f i) * ∏ j : Fin i, n (Fin.castLE i.prop.le j)) + ↑fn * ∏ j, n j) <
            (∏ i : Fin m, n i) * nn by
        replace := this (Fin.init n) (n (Fin.last _)) (Fin.init f) (f (Fin.last _))
        rw [← Fin.snoc_init_self f]
        simp (config := { singlePass := true }) only [← Fin.snoc_init_self n]
        simp_rw [Fin.snoc_castSucc, Fin.snoc_last, Fin.snoc_init_self n]
        exact this
      intro n nn f fn
      cases nn
      · dsimp only [Nat.zero_eq] at fn -- porting note: added, wrong zero
        exact isEmptyElim fn
      refine' (add_lt_add_of_lt_of_le (ih _) <| mul_le_mul_right' (Fin.is_le _) _).trans_eq _
      rw [← one_add_mul (_ : ℕ), mul_comm, add_comm]
      -- porting note: added, wrong `succ`
      rfl⟩)
    (fun a b => ⟨(a / ∏ j : Fin b, n (Fin.castLE b.is_lt.le j)) % n b, by
      cases m
      · exact b.elim0
      cases' h : n b with nb
      · rw [prod_eq_zero (Finset.mem_univ _) h] at a
        exact isEmptyElim a
      exact Nat.mod_lt _ nb.succ_pos⟩)
    (by
      intro a; revert a; dsimp only [Fin.val_mk]
      refine' Fin.consInduction _ _ n
      · intro a
        haveI : Subsingleton (Fin (∏ i : Fin 0, i.elim0)) :=
          (Fin.castIso <| prod_empty).toEquiv.subsingleton
        exact Subsingleton.elim _ _
      · intro n x xs ih a
        simp_rw [Fin.forall_iff, Fin.ext_iff] at ih
        ext
        simp_rw [Fin.sum_univ_succ, Fin.cons_succ]
        have := fun i : Fin n =>
          Fintype.prod_equiv (Fin.castIso <| Fin.val_succ i).toEquiv
            (fun j => (Fin.cons x xs : _ → ℕ) (Fin.castLE (Fin.is_lt _).le j))
            (fun j => (Fin.cons x xs : _ → ℕ) (Fin.castLE (Nat.succ_le_succ (Fin.is_lt _).le) j))
            fun j => rfl
        simp_rw [this]
        clear this
        dsimp only [Fin.val_zero]
        simp_rw [Fintype.prod_empty, Nat.div_one, mul_one, Fin.cons_zero, Fin.prod_univ_succ]
        change (_ + ∑ y : _, _ / (x * _) % _ * (x * _)) = _
        simp_rw [← Nat.div_div_eq_div_mul, mul_left_comm (_ % _ : ℕ), ← mul_sum]
        convert Nat.mod_add_div _ _
        -- porting note: new
        refine (ih (a / x) (Nat.div_lt_of_lt_mul <| a.is_lt.trans_eq ?_))
        

Proof state:
case h.e'_2.h.e'_6.h.e'_6
α : Type u_1
β : Type u_2
m : ℕ
n✝ : Fin m → ℕ
n x : ℕ
xs : Fin n → ℕ
a : Fin (∏ i : Fin (n + 1), Fin.cons x xs i)
ih :
  ∀ i < ∏ i : Fin n, xs i,
    ∑ x : Fin n,
        (i / ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j)) % xs x * ∏ j : Fin ↑x, xs (Fin.castLE (_ : ↑x ≤ n) j) =
      i
⊢ ∏ i : Fin (n + 1), Fin.cons x xs i = x * ∏ i : Fin n, xs i

Next tactic:
exact Fin.prod_univ_succ _
theorem finPiFinEquiv_single {m : ℕ} {n : Fin m → ℕ} [∀ i, NeZero (n i)] (i : Fin m)
    (j : Fin (n i)) :
    (finPiFinEquiv (Pi.single i j : ∀ i : Fin m, Fin (n i)) : ℕ) =
      j * ∏ j, n (Fin.castLE i.is_lt.le j) := by
  

Proof state:
α : Type u_1
β : Type u_2
m : ℕ
n : Fin m → ℕ
inst✝ : ∀ (i : Fin m), NeZero (n i)
i : Fin m
j : Fin (n i)
⊢ ↑(finPiFinEquiv (Pi.single i j)) = ↑j * ∏ j : Fin ↑i, n (Fin.castLE (_ : ↑i ≤ m) j)

Next tactic:
rw [finPiFinEquiv_apply, Fintype.sum_eq_single i, Pi.single_eq_same]
theorem finPiFinEquiv_single {m : ℕ} {n : Fin m → ℕ} [∀ i, NeZero (n i)] (i : Fin m)
    (j : Fin (n i)) :
    (finPiFinEquiv (Pi.single i j : ∀ i : Fin m, Fin (n i)) : ℕ) =
      j * ∏ j, n (Fin.castLE i.is_lt.le j) := by
  rw [finPiFinEquiv_apply, Fintype.sum_eq_single i, Pi.single_eq_same]
  

Proof state:
α : Type u_1
β : Type u_2
m : ℕ
n : Fin m → ℕ
inst✝ : ∀ (i : Fin m), NeZero (n i)
i : Fin m
j : Fin (n i)
⊢ ∀ (x : Fin m), x ≠ i → ↑(Pi.single i j x) * ∏ j : Fin ↑x, n (Fin.castLE (_ : ↑x ≤ m) j) = 0

Next tactic:
rintro x hx
theorem finPiFinEquiv_single {m : ℕ} {n : Fin m → ℕ} [∀ i, NeZero (n i)] (i : Fin m)
    (j : Fin (n i)) :
    (finPiFinEquiv (Pi.single i j : ∀ i : Fin m, Fin (n i)) : ℕ) =
      j * ∏ j, n (Fin.castLE i.is_lt.le j) := by
  rw [finPiFinEquiv_apply, Fintype.sum_eq_single i, Pi.single_eq_same]
  rintro x hx
  

Proof state:
α : Type u_1
β : Type u_2
m : ℕ
n : Fin m → ℕ
inst✝ : ∀ (i : Fin m), NeZero (n i)
i : Fin m
j : Fin (n i)
x : Fin m
hx : x ≠ i
⊢ ↑(Pi.single i j x) * ∏ j : Fin ↑x, n (Fin.castLE (_ : ↑x ≤ m) j) = 0

Next tactic:
rw [Pi.single_eq_of_ne hx, Fin.val_zero', zero_mul]
@[to_additive]
theorem prod_take_ofFn {n : ℕ} (f : Fin n → α) (i : ℕ) :
    ((ofFn f).take i).prod = ∏ j in Finset.univ.filter fun j : Fin n => j.val < i, f j := by
  

Proof state:
α : Type u_1
β : Type u_2
inst✝ : CommMonoid α
n : ℕ
f : Fin n → α
i : ℕ
⊢ prod (take i (ofFn f)) = ∏ j in Finset.filter (fun j => ↑j < i) univ, f j

Next tactic:
induction i with
  | zero =>
    simp
  | succ i IH =>
    by_cases h : i < n
    · have : i < length (ofFn f) := by rwa [length_ofFn f]
      rw [prod_take_succ _ _ this]
      have A : ((Finset.univ : Finset (Fin n)).filter fun j => j.val < i + 1) =
          ((Finset.univ : Finset (Fin n)).filter fun j => j.val < i) ∪ {(⟨i, h⟩ : Fin n)} := by
        ext ⟨_, _⟩
        simp [Nat.lt_succ_iff_lt_or_eq]
      have B : _root_.Disjoint (Finset.filter (fun j : Fin n => j.val < i) Finset.univ)
          (singleton (⟨i, h⟩ : Fin n)) := by simp
      rw [A, Finset.prod_union B, IH]
      simp
    · have A : (ofFn f).take i = (ofFn f).take i.succ := by
        rw [← length_ofFn f] at h
        have : length (ofFn f) ≤ i := not_lt.mp h
        rw [take_all_of_le this, take_all_of_le (le_trans this (Nat.le_succ _))]
      have B : ∀ j : Fin n, ((j : ℕ) < i.succ) = ((j : ℕ) < i) := by
        intro j
        have : (j : ℕ) < i := lt_of_lt_of_le j.2 (not_lt.mp h)
        simp [this, lt_trans this (Nat.lt_succ_self _)]
      simp [← A, B, IH]
@[to_additive]
theorem prod_take_ofFn {n : ℕ} (f : Fin n → α) (i : ℕ) :
    ((ofFn f).take i).prod = ∏ j in Finset.univ.filter fun j : Fin n => j.val < i, f j := by
  induction i with
  

Proof state:
case zero
α : Type u_1
β : Type u_2
inst✝ : CommMonoid α
n : ℕ
f : Fin n → α
⊢ prod (take Nat.zero (ofFn f)) = ∏ j in Finset.filter (fun j => ↑j < Nat.zero) univ, f j

Next tactic:
| zero =>
    simp
@[to_additive]
theorem prod_take_ofFn {n : ℕ} (f : Fin n → α) (i : ℕ) :
    ((ofFn f).take i).prod = ∏ j in Finset.univ.filter fun j : Fin n => j.val < i, f j := by
  induction i with
  | zero =>
    

Proof state:
case zero
α : Type u_1
β : Type u_2
inst✝ : CommMonoid α
n : ℕ
f : Fin n → α
⊢ prod (take Nat.zero (ofFn f)) = ∏ j in Finset.filter (fun j => ↑j < Nat.zero) univ, f j

Next tactic:
simp
@[to_additive]
theorem prod_take_ofFn {n : ℕ} (f : Fin n → α) (i : ℕ) :
    ((ofFn f).take i).prod = ∏ j in Finset.univ.filter fun j : Fin n => j.val < i, f j := by
  induction i with
  | zero =>
    simp
  

Proof state:
case succ
α : Type u_1
β : Type u_2
inst✝ : CommMonoid α
n : ℕ
f : Fin n → α
i : ℕ
IH : prod (take i (ofFn f)) = ∏ j in Finset.filter (fun j => ↑j < i) univ, f j
⊢ prod (take (Nat.succ i) (ofFn f)) = ∏ j in Finset.filter (fun j => ↑j < Nat.succ i) univ, f j

Next tactic:
| succ i IH =>
    by_cases h : i < n
    · have : i < length (ofFn f) := by rwa [length_ofFn f]
      rw [prod_take_succ _ _ this]
      have A : ((Finset.univ : Finset (Fin n)).filter fun j => j.val < i + 1) =
          ((Finset.univ : Finset (Fin n)).filter fun j => j.val < i) ∪ {(⟨i, h⟩ : Fin n)} := by
        ext ⟨_, _⟩
        simp [Nat.lt_succ_iff_lt_or_eq]
      have B : _root_.Disjoint (Finset.filter (fun j : Fin n => j.val < i) Finset.univ)
          (singleton (⟨i, h⟩ : Fin n)) := by simp
      rw [A, Finset.prod_union B, IH]
      simp
    · have A : (ofFn f).take i = (ofFn f).take i.succ := by
        rw [← length_ofFn f] at h
        have : length (ofFn f) ≤ i := not_lt.mp h
        rw [take_all_of_le this, take_all_of_le (le_trans this (Nat.le_succ _))]
      have B : ∀ j : Fin n, ((j : ℕ) < i.succ) = ((j : ℕ) < i) := by
        intro j
        have : (j : ℕ) < i := lt_of_lt_of_le j.2 (not_lt.mp h)
        simp [this, lt_trans this (Nat.lt_succ_self _)]
      simp [← A, B, IH]
@[to_additive]
theorem prod_take_ofFn {n : ℕ} (f : Fin n → α) (i : ℕ) :
    ((ofFn f).take i).prod = ∏ j in Finset.univ.filter fun j : Fin n => j.val < i, f j := by
  induction i with
  | zero =>
    simp
  | succ i IH =>
    

Proof state:
case succ
α : Type u_1
β : Type u_2
inst✝ : CommMonoid α
n : ℕ
f : Fin n → α
i : ℕ
IH : prod (take i (ofFn f)) = ∏ j in Finset.filter (fun j => ↑j < i) univ, f j
⊢ prod (take (Nat.succ i) (ofFn f)) = ∏ j in Finset.filter (fun j => ↑j < Nat.succ i) univ, f j

Next tactic:
by_cases h : i < n