l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem ofFn_succ {n} (f : Fin (succ n) → α) : ofFn f = f 0 :: ofFn fun i => f i.succ :=
  ext_get (by simp) (fun i hi₁ hi₂ => by
    cases i
    · simp
    · 

Proof state:
case succ
α : Type u
n : ℕ
f : Fin (succ n) → α
n✝ : ℕ
hi₁ : succ n✝ < length (ofFn f)
hi₂ : succ n✝ < length (f 0 :: ofFn fun i => f (Fin.succ i))
⊢ get (ofFn f) { val := succ n✝, isLt := hi₁ } =
    get (f 0 :: ofFn fun i => f (Fin.succ i)) { val := succ n✝, isLt := hi₂ }

Next tactic:
simp
theorem ofFn_succ' {n} (f : Fin (succ n) → α) :
    ofFn f = (ofFn fun i => f (Fin.castSucc i)).concat (f (Fin.last _)) := by
  

Proof state:
α : Type u
n : ℕ
f : Fin (succ n) → α
⊢ ofFn f = concat (ofFn fun i => f (Fin.castSucc i)) (f (Fin.last n))

Next tactic:
induction' n with n IH
theorem ofFn_succ' {n} (f : Fin (succ n) → α) :
    ofFn f = (ofFn fun i => f (Fin.castSucc i)).concat (f (Fin.last _)) := by
  induction' n with n IH
  · 

Proof state:
case zero
α : Type u
f : Fin (succ zero) → α
⊢ ofFn f = concat (ofFn fun i => f (Fin.castSucc i)) (f (Fin.last zero))

Next tactic:
rw [ofFn_zero, concat_nil, ofFn_succ, ofFn_zero]
theorem ofFn_succ' {n} (f : Fin (succ n) → α) :
    ofFn f = (ofFn fun i => f (Fin.castSucc i)).concat (f (Fin.last _)) := by
  induction' n with n IH
  · rw [ofFn_zero, concat_nil, ofFn_succ, ofFn_zero]
    

Proof state:
case zero
α : Type u
f : Fin (succ zero) → α
⊢ [f 0] = [f (Fin.last zero)]

Next tactic:
rfl
theorem ofFn_succ' {n} (f : Fin (succ n) → α) :
    ofFn f = (ofFn fun i => f (Fin.castSucc i)).concat (f (Fin.last _)) := by
  induction' n with n IH
  · rw [ofFn_zero, concat_nil, ofFn_succ, ofFn_zero]
    rfl
  · 

Proof state:
case succ
α : Type u
n : ℕ
IH : ∀ (f : Fin (succ n) → α), ofFn f = concat (ofFn fun i => f (Fin.castSucc i)) (f (Fin.last n))
f : Fin (succ (succ n)) → α
⊢ ofFn f = concat (ofFn fun i => f (Fin.castSucc i)) (f (Fin.last (succ n)))

Next tactic:
rw [ofFn_succ, IH, ofFn_succ, concat_cons, Fin.castSucc_zero]
theorem ofFn_succ' {n} (f : Fin (succ n) → α) :
    ofFn f = (ofFn fun i => f (Fin.castSucc i)).concat (f (Fin.last _)) := by
  induction' n with n IH
  · rw [ofFn_zero, concat_nil, ofFn_succ, ofFn_zero]
    rfl
  · rw [ofFn_succ, IH, ofFn_succ, concat_cons, Fin.castSucc_zero]
    

Proof state:
case succ
α : Type u
n : ℕ
IH : ∀ (f : Fin (succ n) → α), ofFn f = concat (ofFn fun i => f (Fin.castSucc i)) (f (Fin.last n))
f : Fin (succ (succ n)) → α
⊢ f 0 :: concat (ofFn fun i => f (Fin.succ (Fin.castSucc i))) (f (Fin.succ (Fin.last n))) =
    f 0 :: concat (ofFn fun i => f (Fin.castSucc (Fin.succ i))) (f (Fin.last (succ n)))

Next tactic:
congr
@[simp]
theorem ofFn_eq_nil_iff {n : ℕ} {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by
  

Proof state:
α : Type u
n : ℕ
f : Fin n → α
⊢ ofFn f = [] ↔ n = 0

Next tactic:
cases n
@[simp]
theorem ofFn_eq_nil_iff {n : ℕ} {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by
  cases n <;> 

Proof state:
case zero
α : Type u
f : Fin zero → α
⊢ ofFn f = [] ↔ zero = 0

Next tactic:
simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero]
@[simp]
theorem ofFn_eq_nil_iff {n : ℕ} {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by
  cases n <;> 

Proof state:
case succ
α : Type u
n✝ : ℕ
f : Fin (succ n✝) → α
⊢ ofFn f = [] ↔ succ n✝ = 0

Next tactic:
simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero]
theorem last_ofFn {n : ℕ} (f : Fin n → α) (h : ofFn f ≠ [])
    (hn : n - 1 < n := Nat.pred_lt <| ofFn_eq_nil_iff.not.mp h) :
    getLast (ofFn f) h = f ⟨n - 1, hn⟩ := by 

Proof state:
α : Type u
n : ℕ
f : Fin n → α
h : ofFn f ≠ []
hn : optParam (n - 1 < n) (_ : pred (Nat.sub n 0) < Nat.sub n 0)
⊢ getLast (ofFn f) h = f { val := n - 1, isLt := hn }

Next tactic:
simp [getLast_eq_get]
/-- Note this matches the convention of `List.ofFn_succ'`, putting the `Fin m` elements first. -/
theorem ofFn_add {m n} (f : Fin (m + n) → α) :
    List.ofFn f =
      (List.ofFn fun i => f (Fin.castAdd n i)) ++ List.ofFn fun j => f (Fin.natAdd m j) := by
  

Proof state:
α : Type u
m n : ℕ
f : Fin (m + n) → α
⊢ ofFn f = (ofFn fun i => f (Fin.castAdd n i)) ++ ofFn fun j => f (Fin.natAdd m j)

Next tactic:
induction' n with n IH
/-- Note this matches the convention of `List.ofFn_succ'`, putting the `Fin m` elements first. -/
theorem ofFn_add {m n} (f : Fin (m + n) → α) :
    List.ofFn f =
      (List.ofFn fun i => f (Fin.castAdd n i)) ++ List.ofFn fun j => f (Fin.natAdd m j) := by
  induction' n with n IH
  · 

Proof state:
case zero
α : Type u
m : ℕ
f : Fin (m + zero) → α
⊢ ofFn f = (ofFn fun i => f (Fin.castAdd zero i)) ++ ofFn fun j => f (Fin.natAdd m j)

Next tactic:
rw [ofFn_zero, append_nil, Fin.castAdd_zero, Fin.cast_refl]
/-- Note this matches the convention of `List.ofFn_succ'`, putting the `Fin m` elements first. -/
theorem ofFn_add {m n} (f : Fin (m + n) → α) :
    List.ofFn f =
      (List.ofFn fun i => f (Fin.castAdd n i)) ++ List.ofFn fun j => f (Fin.natAdd m j) := by
  induction' n with n IH
  · rw [ofFn_zero, append_nil, Fin.castAdd_zero, Fin.cast_refl]
    

Proof state:
case zero
α : Type u
m : ℕ
f : Fin (m + zero) → α
⊢ ofFn f = ofFn fun i => f (id i)

Next tactic:
rfl
/-- Note this matches the convention of `List.ofFn_succ'`, putting the `Fin m` elements first. -/
theorem ofFn_add {m n} (f : Fin (m + n) → α) :
    List.ofFn f =
      (List.ofFn fun i => f (Fin.castAdd n i)) ++ List.ofFn fun j => f (Fin.natAdd m j) := by
  induction' n with n IH
  · rw [ofFn_zero, append_nil, Fin.castAdd_zero, Fin.cast_refl]
    rfl
  · 

Proof state:
case succ
α : Type u
m n : ℕ
IH : ∀ (f : Fin (m + n) → α), ofFn f = (ofFn fun i => f (Fin.castAdd n i)) ++ ofFn fun j => f (Fin.natAdd m j)
f : Fin (m + succ n) → α
⊢ ofFn f = (ofFn fun i => f (Fin.castAdd (succ n) i)) ++ ofFn fun j => f (Fin.natAdd m j)

Next tactic:
rw [ofFn_succ', ofFn_succ', IH, append_concat]
/-- Note this matches the convention of `List.ofFn_succ'`, putting the `Fin m` elements first. -/
theorem ofFn_add {m n} (f : Fin (m + n) → α) :
    List.ofFn f =
      (List.ofFn fun i => f (Fin.castAdd n i)) ++ List.ofFn fun j => f (Fin.natAdd m j) := by
  induction' n with n IH
  · rw [ofFn_zero, append_nil, Fin.castAdd_zero, Fin.cast_refl]
    rfl
  · rw [ofFn_succ', ofFn_succ', IH, append_concat]
    

Proof state:
case succ
α : Type u
m n : ℕ
IH : ∀ (f : Fin (m + n) → α), ofFn f = (ofFn fun i => f (Fin.castAdd n i)) ++ ofFn fun j => f (Fin.natAdd m j)
f : Fin (m + succ n) → α
⊢ concat ((ofFn fun i => f (Fin.castSucc (Fin.castAdd n i))) ++ ofFn fun j => f (Fin.castSucc (Fin.natAdd m j)))
      (f (Fin.last (Nat.add m n))) =
    concat ((ofFn fun i => f (Fin.castAdd (succ n) i)) ++ ofFn fun i => f (Fin.natAdd m (Fin.castSucc i)))
      (f (Fin.natAdd m (Fin.last n)))

Next tactic:
rfl
@[simp]
theorem ofFn_fin_append {m n} (a : Fin m → α) (b : Fin n → α) :
    List.ofFn (Fin.append a b) = List.ofFn a ++ List.ofFn b := by
  

Proof state:
α : Type u
m n : ℕ
a : Fin m → α
b : Fin n → α
⊢ ofFn (Fin.append a b) = ofFn a ++ ofFn b

Next tactic:
simp_rw [ofFn_add, Fin.append_left, Fin.append_right]
/-- This breaks a list of `m*n` items into `m` groups each containing `n` elements. -/
theorem ofFn_mul {m n} (f : Fin (m * n) → α) :
    List.ofFn f = List.join (List.ofFn fun i : Fin m => List.ofFn fun j : Fin n => f ⟨i * n + j,
    calc
      ↑i * n + j < (i + 1) * n := (add_lt_add_left j.prop _).trans_eq (add_one_mul (_ : ℕ) _).symm
      _ ≤ _ := Nat.mul_le_mul_right _ i.prop⟩) := by
  

Proof state:
α : Type u
m n : ℕ
f : Fin (m * n) → α
⊢ ofFn f = join (ofFn fun i => ofFn fun j => f { val := ↑i * n + ↑j, isLt := (_ : ↑i * n + ↑j < m * n) })

Next tactic:
induction' m with m IH
/-- This breaks a list of `m*n` items into `m` groups each containing `n` elements. -/
theorem ofFn_mul {m n} (f : Fin (m * n) → α) :
    List.ofFn f = List.join (List.ofFn fun i : Fin m => List.ofFn fun j : Fin n => f ⟨i * n + j,
    calc
      ↑i * n + j < (i + 1) * n := (add_lt_add_left j.prop _).trans_eq (add_one_mul (_ : ℕ) _).symm
      _ ≤ _ := Nat.mul_le_mul_right _ i.prop⟩) := by
  induction' m with m IH
  · 

Proof state:
case zero
α : Type u
n : ℕ
f : Fin (zero * n) → α
⊢ ofFn f = join (ofFn fun i => ofFn fun j => f { val := ↑i * n + ↑j, isLt := (_ : ↑i * n + ↑j < zero * n) })

Next tactic:
simp [ofFn_zero, zero_mul, ofFn_zero, join]
/-- This breaks a list of `m*n` items into `m` groups each containing `n` elements. -/
theorem ofFn_mul {m n} (f : Fin (m * n) → α) :
    List.ofFn f = List.join (List.ofFn fun i : Fin m => List.ofFn fun j : Fin n => f ⟨i * n + j,
    calc
      ↑i * n + j < (i + 1) * n := (add_lt_add_left j.prop _).trans_eq (add_one_mul (_ : ℕ) _).symm
      _ ≤ _ := Nat.mul_le_mul_right _ i.prop⟩) := by
  induction' m with m IH
  · simp [ofFn_zero, zero_mul, ofFn_zero, join]
  · 

Proof state:
case succ
α : Type u
n m : ℕ
IH :
  ∀ (f : Fin (m * n) → α),
    ofFn f = join (ofFn fun i => ofFn fun j => f { val := ↑i * n + ↑j, isLt := (_ : ↑i * n + ↑j < m * n) })
f : Fin (succ m * n) → α
⊢ ofFn f = join (ofFn fun i => ofFn fun j => f { val := ↑i * n + ↑j, isLt := (_ : ↑i * n + ↑j < succ m * n) })

Next tactic:
simp_rw [ofFn_succ', succ_mul, join_concat, ofFn_add, IH]
/-- This breaks a list of `m*n` items into `m` groups each containing `n` elements. -/
theorem ofFn_mul {m n} (f : Fin (m * n) → α) :
    List.ofFn f = List.join (List.ofFn fun i : Fin m => List.ofFn fun j : Fin n => f ⟨i * n + j,
    calc
      ↑i * n + j < (i + 1) * n := (add_lt_add_left j.prop _).trans_eq (add_one_mul (_ : ℕ) _).symm
      _ ≤ _ := Nat.mul_le_mul_right _ i.prop⟩) := by
  induction' m with m IH
  · simp [ofFn_zero, zero_mul, ofFn_zero, join]
  · simp_rw [ofFn_succ', succ_mul, join_concat, ofFn_add, IH]
    

Proof state:
case succ
α : Type u
n m : ℕ
IH :
  ∀ (f : Fin (m * n) → α),
    ofFn f = join (ofFn fun i => ofFn fun j => f { val := ↑i * n + ↑j, isLt := (_ : ↑i * n + ↑j < m * n) })
f : Fin (succ m * n) → α
⊢ (join
        (ofFn fun i =>
          ofFn fun j =>
            f
              (Fin.cast (_ : m * n + n = succ m * n)
                (Fin.castAdd n { val := ↑i * n + ↑j, isLt := (_ : ↑i * n + ↑j < m * n) }))) ++
      ofFn fun j => f (Fin.cast (_ : m * n + n = succ m * n) (Fin.natAdd (m * n) j))) =
    join
        (ofFn fun i =>
          ofFn fun j =>
            f { val := ↑(Fin.castSucc i) * n + ↑j, isLt := (_ : ↑(Fin.castSucc i) * n + ↑j < succ m * n) }) ++
      ofFn fun j => f { val := ↑(Fin.last m) * n + ↑j, isLt := (_ : ↑(Fin.last m) * n + ↑j < succ m * n) }

Next tactic:
rfl
/-- This breaks a list of `m*n` items into `n` groups each containing `m` elements. -/
theorem ofFn_mul' {m n} (f : Fin (m * n) → α) :
    List.ofFn f = List.join (List.ofFn fun i : Fin n => List.ofFn fun j : Fin m => f ⟨m * i + j,
    calc
      m * i + j < m * (i + 1) := (add_lt_add_left j.prop _).trans_eq (mul_add_one (_ : ℕ) _).symm
      _ ≤ _ := Nat.mul_le_mul_left _ i.prop⟩) := by
  

Proof state:
α : Type u
m n : ℕ
f : Fin (m * n) → α
⊢ ofFn f = join (ofFn fun i => ofFn fun j => f { val := m * ↑i + ↑j, isLt := (_ : m * ↑i + ↑j < m * n) })

Next tactic:
simp_rw [mul_comm m n, mul_comm m, ofFn_mul, Fin.cast_mk]
theorem ofFn_get : ∀ l : List α, (ofFn (get l)) = l
  | [] => rfl
  | a :: l => by
    

Proof state:
α : Type u
a : α
l : List α
⊢ ofFn (get (a :: l)) = a :: l

Next tactic:
rw [ofFn_succ]
theorem ofFn_get : ∀ l : List α, (ofFn (get l)) = l
  | [] => rfl
  | a :: l => by
    rw [ofFn_succ]
    

Proof state:
α : Type u
a : α
l : List α
⊢ (get (a :: l) 0 :: ofFn fun i => get (a :: l) (Fin.succ i)) = a :: l

Next tactic:
congr
theorem ofFn_get : ∀ l : List α, (ofFn (get l)) = l
  | [] => rfl
  | a :: l => by
    rw [ofFn_succ]
    congr
    

Proof state:
case e_tail
α : Type u
a : α
l : List α
⊢ (ofFn fun i => get (a :: l) (Fin.succ i)) = l

Next tactic:
exact ofFn_get l
theorem mem_ofFn {n} (f : Fin n → α) (a : α) : a ∈ ofFn f ↔ a ∈ Set.range f := by
  

Proof state:
α : Type u
n : ℕ
f : Fin n → α
a : α
⊢ a ∈ ofFn f ↔ a ∈ Set.range f

Next tactic:
simp only [mem_iff_get, Set.mem_range, get_ofFn]
theorem mem_ofFn {n} (f : Fin n → α) (a : α) : a ∈ ofFn f ↔ a ∈ Set.range f := by
  simp only [mem_iff_get, Set.mem_range, get_ofFn]
  

Proof state:
α : Type u
n : ℕ
f : Fin n → α
a : α
⊢ (∃ n_1, f (Fin.cast (_ : length (ofFn f) = n) n_1) = a) ↔ ∃ y, f y = a

Next tactic:
exact ⟨fun ⟨i, hi⟩ => ⟨Fin.cast (by simp) i, hi⟩, fun ⟨i, hi⟩ => ⟨Fin.cast (by simp) i, hi⟩⟩
theorem mem_ofFn {n} (f : Fin n → α) (a : α) : a ∈ ofFn f ↔ a ∈ Set.range f := by
  simp only [mem_iff_get, Set.mem_range, get_ofFn]
  exact ⟨fun ⟨i, hi⟩ => ⟨Fin.cast (by 

Proof state:
α : Type u
n : ℕ
f : Fin n → α
a : α
x✝ : ∃ n_1, f (Fin.cast (_ : length (ofFn f) = n) n_1) = a
i : Fin (length (ofFn f))
hi : f (Fin.cast (_ : length (ofFn f) = n) i) = a
⊢ length (ofFn f) = n

Next tactic:
simp
theorem mem_ofFn {n} (f : Fin n → α) (a : α) : a ∈ ofFn f ↔ a ∈ Set.range f := by
  simp only [mem_iff_get, Set.mem_range, get_ofFn]
  exact ⟨fun ⟨i, hi⟩ => ⟨Fin.cast (by simp) i, hi⟩, fun ⟨i, hi⟩ => ⟨Fin.cast (by 

Proof state:
α : Type u
n : ℕ
f : Fin n → α
a : α
x✝ : ∃ y, f y = a
i : Fin n
hi : f i = a
⊢ n = length (ofFn f)

Next tactic:
simp
@[simp]
theorem forall_mem_ofFn_iff {n : ℕ} {f : Fin n → α} {P : α → Prop} :
    (∀ i ∈ ofFn f, P i) ↔ ∀ j : Fin n, P (f j) := by 

Proof state:
α : Type u
n : ℕ
f : Fin n → α
P : α → Prop
⊢ (∀ i ∈ ofFn f, P i) ↔ ∀ (j : Fin n), P (f j)

Next tactic:
simp only [mem_ofFn, Set.forall_range_iff]
@[simp]
theorem ofFn_const : ∀ (n : ℕ) (c : α), (ofFn fun _ : Fin n => c) = replicate n c
  | 0, c => rfl
  | n+1, c => by 

Proof state:
α : Type u
n : ℕ
c : α
⊢ (ofFn fun x => c) = replicate (n + 1) c

Next tactic:
rw [replicate, ← ofFn_const n]
@[simp]
theorem ofFn_const : ∀ (n : ℕ) (c : α), (ofFn fun _ : Fin n => c) = replicate n c
  | 0, c => rfl
  | n+1, c => by rw [replicate, ← ofFn_const n]; 

Proof state:
α : Type u
n : ℕ
c : α
⊢ (ofFn fun x => c) = c :: ofFn fun x => c

Next tactic:
simp
@[simp]
theorem ofFn_fin_repeat {m} (a : Fin m → α) (n : ℕ) :
    List.ofFn (Fin.repeat n a) = (List.replicate n (List.ofFn a)).join := by
  

Proof state:
α : Type u
m : ℕ
a : Fin m → α
n : ℕ
⊢ ofFn (Fin.repeat n a) = join (replicate n (ofFn a))

Next tactic:
simp_rw [ofFn_mul, ← ofFn_const, Fin.repeat, Fin.modNat, add_comm,
    Nat.add_mul_mod_self_right, Nat.mod_eq_of_lt (Fin.is_lt _)]
@[simp]
theorem pairwise_ofFn {R : α → α → Prop} {n} {f : Fin n → α} :
    (ofFn f).Pairwise R ↔ ∀ ⦃i j⦄, i < j → R (f i) (f j) := by
  

Proof state:
α : Type u
R : α → α → Prop
n : ℕ
f : Fin n → α
⊢ Pairwise R (ofFn f) ↔ ∀ ⦃i j : Fin n⦄, i < j → R (f i) (f j)

Next tactic:
simp only [pairwise_iff_get, (Fin.rightInverse_cast (length_ofFn f)).surjective.forall, get_ofFn,
    lt_iff_not_le, Fin.cast_le_cast]
@[simp]
theorem ofFnRec_ofFn {C : List α → Sort*} (h : ∀ (n) (f : Fin n → α), C (List.ofFn f)) {n : ℕ}
    (f : Fin n → α) : @ofFnRec _ C h (List.ofFn f) = h _ f := by
  --Porting note: Old proof was
  -- equivSigmaTuple.rightInverse_symm.cast_eq (fun s => h s.1 s.2) ⟨n, f⟩
  

Proof state:
α : Type u
C : List α → Sort u_1
h : (n : ℕ) → (f : Fin n → α) → C (ofFn f)
n : ℕ
f : Fin n → α
⊢ ofFnRec h (ofFn f) = h n f

Next tactic:
have := (@equivSigmaTuple α).rightInverse_symm
@[simp]
theorem ofFnRec_ofFn {C : List α → Sort*} (h : ∀ (n) (f : Fin n → α), C (List.ofFn f)) {n : ℕ}
    (f : Fin n → α) : @ofFnRec _ C h (List.ofFn f) = h _ f := by
  --Porting note: Old proof was
  -- equivSigmaTuple.rightInverse_symm.cast_eq (fun s => h s.1 s.2) ⟨n, f⟩
  have := (@equivSigmaTuple α).rightInverse_symm
  

Proof state:
α : Type u
C : List α → Sort u_1
h : (n : ℕ) → (f : Fin n → α) → C (ofFn f)
n : ℕ
f : Fin n → α
this : Function.RightInverse ⇑equivSigmaTuple.symm ⇑equivSigmaTuple
⊢ ofFnRec h (ofFn f) = h n f

Next tactic:
dsimp [equivSigmaTuple] at this
@[simp]
theorem ofFnRec_ofFn {C : List α → Sort*} (h : ∀ (n) (f : Fin n → α), C (List.ofFn f)) {n : ℕ}
    (f : Fin n → α) : @ofFnRec _ C h (List.ofFn f) = h _ f := by
  --Porting note: Old proof was
  -- equivSigmaTuple.rightInverse_symm.cast_eq (fun s => h s.1 s.2) ⟨n, f⟩
  have := (@equivSigmaTuple α).rightInverse_symm
  dsimp [equivSigmaTuple] at this
  

Proof state:
α : Type u
C : List α → Sort u_1
h : (n : ℕ) → (f : Fin n → α) → C (ofFn f)
n : ℕ
f : Fin n → α
this : Function.RightInverse (fun f => ofFn f.snd) fun l => { fst := length l, snd := get l }
⊢ ofFnRec h (ofFn f) = h n f

Next tactic:
have := this.cast_eq (fun s => h s.1 s.2) ⟨n, f⟩
@[simp]
theorem ofFnRec_ofFn {C : List α → Sort*} (h : ∀ (n) (f : Fin n → α), C (List.ofFn f)) {n : ℕ}
    (f : Fin n → α) : @ofFnRec _ C h (List.ofFn f) = h _ f := by
  --Porting note: Old proof was
  -- equivSigmaTuple.rightInverse_symm.cast_eq (fun s => h s.1 s.2) ⟨n, f⟩
  have := (@equivSigmaTuple α).rightInverse_symm
  dsimp [equivSigmaTuple] at this
  have := this.cast_eq (fun s => h s.1 s.2) ⟨n, f⟩
  

Proof state:
α : Type u
C : List α → Sort u_1
h : (n : ℕ) → (f : Fin n → α) → C (ofFn f)
n : ℕ
f : Fin n → α
this✝ : Function.RightInverse (fun f => ofFn f.snd) fun l => { fst := length l, snd := get l }
this :
  cast
      (_ :
        C (ofFn { fst := length (ofFn { fst := n, snd := f }.snd), snd := get (ofFn { fst := n, snd := f }.snd) }.snd) =
          C (ofFn { fst := n, snd := f }.snd))
      (h { fst := length (ofFn { fst := n, snd := f }.snd), snd := get (ofFn { fst := n, snd := f }.snd) }.fst
        { fst := length (ofFn { fst := n, snd := f }.snd), snd := get (ofFn { fst := n, snd := f }.snd) }.snd) =
    h { fst := n, snd := f }.fst { fst := n, snd := f }.snd
⊢ ofFnRec h (ofFn f) = h n f

Next tactic:
dsimp only at this
@[simp]
theorem ofFnRec_ofFn {C : List α → Sort*} (h : ∀ (n) (f : Fin n → α), C (List.ofFn f)) {n : ℕ}
    (f : Fin n → α) : @ofFnRec _ C h (List.ofFn f) = h _ f := by
  --Porting note: Old proof was
  -- equivSigmaTuple.rightInverse_symm.cast_eq (fun s => h s.1 s.2) ⟨n, f⟩
  have := (@equivSigmaTuple α).rightInverse_symm
  dsimp [equivSigmaTuple] at this
  have := this.cast_eq (fun s => h s.1 s.2) ⟨n, f⟩
  dsimp only at this
  

Proof state:
α : Type u
C : List α → Sort u_1
h : (n : ℕ) → (f : Fin n → α) → C (ofFn f)
n : ℕ
f : Fin n → α
this✝ : Function.RightInverse (fun f => ofFn f.snd) fun l => { fst := length l, snd := get l }
this :
  cast (_ : C (ofFn { fst := length (ofFn f), snd := get (ofFn f) }.snd) = C (ofFn { fst := n, snd := f }.snd))
      (h (length (ofFn f)) (get (ofFn f))) =
    h n f
⊢ ofFnRec h (ofFn f) = h n f

Next tactic:
rw [ofFnRec, ← this]
/-- Note we can only state this when the two functions are indexed by defeq `n`. -/
theorem ofFn_injective {n : ℕ} : Function.Injective (ofFn : (Fin n → α) → List α) := fun f g h =>
  eq_of_heq $ by 

Proof state:
α : Type u
n : ℕ
f g : Fin n → α
h : ofFn f = ofFn g
⊢ HEq f g

Next tactic:
rw [ofFn_inj'] at h
/-- Note we can only state this when the two functions are indexed by defeq `n`. -/
theorem ofFn_injective {n : ℕ} : Function.Injective (ofFn : (Fin n → α) → List α) := fun f g h =>
  eq_of_heq $ by rw [ofFn_inj'] at h; 

Proof state:
α : Type u
n : ℕ
f g : Fin n → α
h : { fst := n, snd := f } = { fst := n, snd := g }
⊢ HEq f g

Next tactic:
cases h
/-- Note we can only state this when the two functions are indexed by defeq `n`. -/
theorem ofFn_injective {n : ℕ} : Function.Injective (ofFn : (Fin n → α) → List α) := fun f g h =>
  eq_of_heq $ by rw [ofFn_inj'] at h; cases h; 

Proof state:
case refl
α : Type u
n : ℕ
f : Fin n → α
⊢ HEq f f

Next tactic:
rfl
/-- The exponential in a Banach algebra `𝔸` over a normed field `𝕂` has strict Fréchet derivative
`1 : 𝔸 →L[𝕂] 𝔸` at zero, as long as it converges on a neighborhood of zero. -/
theorem hasStrictFDerivAt_exp_zero_of_radius_pos (h : 0 < (expSeries 𝕂 𝔸).radius) :
    HasStrictFDerivAt (exp 𝕂) (1 : 𝔸 →L[𝕂] 𝔸) 0 := by
  

Proof state:
𝕂 : Type u_1
𝔸 : Type u_2
inst✝³ : NontriviallyNormedField 𝕂
inst✝² : NormedRing 𝔸
inst✝¹ : NormedAlgebra 𝕂 𝔸
inst✝ : CompleteSpace 𝔸
h : 0 < FormalMultilinearSeries.radius (expSeries 𝕂 𝔸)
⊢ HasStrictFDerivAt (exp 𝕂) 1 0

Next tactic:
convert (hasFPowerSeriesAt_exp_zero_of_radius_pos h).hasStrictFDerivAt
/-- The exponential in a Banach algebra `𝔸` over a normed field `𝕂` has strict Fréchet derivative
`1 : 𝔸 →L[𝕂] 𝔸` at zero, as long as it converges on a neighborhood of zero. -/
theorem hasStrictFDerivAt_exp_zero_of_radius_pos (h : 0 < (expSeries 𝕂 𝔸).radius) :
    HasStrictFDerivAt (exp 𝕂) (1 : 𝔸 →L[𝕂] 𝔸) 0 := by
  convert (hasFPowerSeriesAt_exp_zero_of_radius_pos h).hasStrictFDerivAt
  

Proof state:
case h.e'_10
𝕂 : Type u_1
𝔸 : Type u_2
inst✝³ : NontriviallyNormedField 𝕂
inst✝² : NormedRing 𝔸
inst✝¹ : NormedAlgebra 𝕂 𝔸
inst✝ : CompleteSpace 𝔸
h : 0 < FormalMultilinearSeries.radius (expSeries 𝕂 𝔸)
⊢ 1 = (continuousMultilinearCurryFin1 𝕂 𝔸 𝔸) (expSeries 𝕂 𝔸 1)

Next tactic:
ext x
/-- The exponential in a Banach algebra `𝔸` over a normed field `𝕂` has strict Fréchet derivative
`1 : 𝔸 →L[𝕂] 𝔸` at zero, as long as it converges on a neighborhood of zero. -/
theorem hasStrictFDerivAt_exp_zero_of_radius_pos (h : 0 < (expSeries 𝕂 𝔸).radius) :
    HasStrictFDerivAt (exp 𝕂) (1 : 𝔸 →L[𝕂] 𝔸) 0 := by
  convert (hasFPowerSeriesAt_exp_zero_of_radius_pos h).hasStrictFDerivAt
  ext x
  

Proof state:
case h.e'_10.h
𝕂 : Type u_1
𝔸 : Type u_2
inst✝³ : NontriviallyNormedField 𝕂
inst✝² : NormedRing 𝔸
inst✝¹ : NormedAlgebra 𝕂 𝔸
inst✝ : CompleteSpace 𝔸
h : 0 < FormalMultilinearSeries.radius (expSeries 𝕂 𝔸)
x : 𝔸
⊢ 1 x = ((continuousMultilinearCurryFin1 𝕂 𝔸 𝔸) (expSeries 𝕂 𝔸 1)) x

Next tactic:
change x = expSeries 𝕂 𝔸 1 fun _ => x
/-- The exponential in a Banach algebra `𝔸` over a normed field `𝕂` has strict Fréchet derivative
`1 : 𝔸 →L[𝕂] 𝔸` at zero, as long as it converges on a neighborhood of zero. -/
theorem hasStrictFDerivAt_exp_zero_of_radius_pos (h : 0 < (expSeries 𝕂 𝔸).radius) :
    HasStrictFDerivAt (exp 𝕂) (1 : 𝔸 →L[𝕂] 𝔸) 0 := by
  convert (hasFPowerSeriesAt_exp_zero_of_radius_pos h).hasStrictFDerivAt
  ext x
  change x = expSeries 𝕂 𝔸 1 fun _ => x
  

Proof state:
case h.e'_10.h
𝕂 : Type u_1
𝔸 : Type u_2
inst✝³ : NontriviallyNormedField 𝕂
inst✝² : NormedRing 𝔸
inst✝¹ : NormedAlgebra 𝕂 𝔸
inst✝ : CompleteSpace 𝔸
h : 0 < FormalMultilinearSeries.radius (expSeries 𝕂 𝔸)
x : 𝔸
⊢ x = (expSeries 𝕂 𝔸 1) fun x_1 => x

Next tactic:
simp [expSeries_apply_eq, Nat.factorial]
/-- The exponential map in a commutative Banach algebra `𝔸` over a normed field `𝕂` of
characteristic zero has Fréchet derivative `exp 𝕂 x • 1 : 𝔸 →L[𝕂] 𝔸` at any point `x` in the
disk of convergence. -/
theorem hasFDerivAt_exp_of_mem_ball [CharZero 𝕂] {x : 𝔸}
    (hx : x ∈ EMetric.ball (0 : 𝔸) (expSeries 𝕂 𝔸).radius) :
    HasFDerivAt (exp 𝕂) (exp 𝕂 x • (1 : 𝔸 →L[𝕂] 𝔸)) x := by
  

Proof state:
𝕂 : Type u_1
𝔸 : Type u_2
inst✝⁴ : NontriviallyNormedField 𝕂
inst✝³ : NormedCommRing 𝔸
inst✝² : NormedAlgebra 𝕂 𝔸
inst✝¹ : CompleteSpace 𝔸
inst✝ : CharZero 𝕂
x : 𝔸
hx : x ∈ EMetric.ball 0 (FormalMultilinearSeries.radius (expSeries 𝕂 𝔸))
⊢ HasFDerivAt (exp 𝕂) (exp 𝕂 x • 1) x

Next tactic:
have hpos : 0 < (expSeries 𝕂 𝔸).radius := (zero_le _).trans_lt hx
/-- The exponential map in a commutative Banach algebra `𝔸` over a normed field `𝕂` of
characteristic zero has Fréchet derivative `exp 𝕂 x • 1 : 𝔸 →L[𝕂] 𝔸` at any point `x` in the
disk of convergence. -/
theorem hasFDerivAt_exp_of_mem_ball [CharZero 𝕂] {x : 𝔸}
    (hx : x ∈ EMetric.ball (0 : 𝔸) (expSeries 𝕂 𝔸).radius) :
    HasFDerivAt (exp 𝕂) (exp 𝕂 x • (1 : 𝔸 →L[𝕂] 𝔸)) x := by
  have hpos : 0 < (expSeries 𝕂 𝔸).radius := (zero_le _).trans_lt hx
  

Proof state:
𝕂 : Type u_1
𝔸 : Type u_2
inst✝⁴ : NontriviallyNormedField 𝕂
inst✝³ : NormedCommRing 𝔸
inst✝² : NormedAlgebra 𝕂 𝔸
inst✝¹ : CompleteSpace 𝔸
inst✝ : CharZero 𝕂
x : 𝔸
hx : x ∈ EMetric.ball 0 (FormalMultilinearSeries.radius (expSeries 𝕂 𝔸))
hpos : 0 < FormalMultilinearSeries.radius (expSeries 𝕂 𝔸)
⊢ HasFDerivAt (exp 𝕂) (exp 𝕂 x • 1) x

Next tactic:
rw [hasFDerivAt_iff_isLittleO_nhds_zero]