l3lab/ntp-mathlib huggingface dataset:
/-- If a `Finset` of a subtype is converted to the main type with
`Embedding.subtype`, all elements of the result have the property of
the subtype. -/
theorem property_of_mem_map_subtype {p : α → Prop} (s : Finset { x // p x }) {a : α}
    (h : a ∈ s.map (Embedding.subtype _)) : p a := by
  rcases mem_map.1 h with ⟨x, _, rfl⟩
  

Proof state:
case intro.intro
α : Type u_1
β : Type u_2
γ : Type u_3
p : α → Prop
s : Finset { x // p x }
x : { x // p x }
left✝ : x ∈ s
h : (Embedding.subtype fun x => p x) x ∈ map (Embedding.subtype fun x => p x) s
⊢ p ((Embedding.subtype fun x => p x) x)

Next tactic:
exact x.2
/-- If a `Finset` of a subtype is converted to the main type with
`Embedding.subtype`, the result is a subset of the set giving the
subtype. -/
theorem map_subtype_subset {t : Set α} (s : Finset t) : ↑(s.map (Embedding.subtype _)) ⊆ t := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
t : Set α
s : Finset ↑t
⊢ ↑(map (Embedding.subtype fun x => x ∈ t) s) ⊆ t

Next tactic:
intro a ha
/-- If a `Finset` of a subtype is converted to the main type with
`Embedding.subtype`, the result is a subset of the set giving the
subtype. -/
theorem map_subtype_subset {t : Set α} (s : Finset t) : ↑(s.map (Embedding.subtype _)) ⊆ t := by
  intro a ha
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
t : Set α
s : Finset ↑t
a : α
ha : a ∈ ↑(map (Embedding.subtype fun x => x ∈ t) s)
⊢ a ∈ t

Next tactic:
rw [mem_coe] at ha
/-- If a `Finset` of a subtype is converted to the main type with
`Embedding.subtype`, the result is a subset of the set giving the
subtype. -/
theorem map_subtype_subset {t : Set α} (s : Finset t) : ↑(s.map (Embedding.subtype _)) ⊆ t := by
  intro a ha
  rw [mem_coe] at ha
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
t : Set α
s : Finset ↑t
a : α
ha : a ∈ map (Embedding.subtype fun x => x ∈ t) s
⊢ a ∈ t

Next tactic:
convert property_of_mem_map_subtype s ha
@[simp]
theorem mem_fin {n} {s : Finset ℕ} : ∀ a : Fin n, a ∈ s.fin n ↔ (a : ℕ) ∈ s
  | ⟨a, ha⟩ => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
n : ℕ
s : Finset ℕ
a : ℕ
ha : a < n
⊢ { val := a, isLt := ha } ∈ Finset.fin n s ↔ ↑{ val := a, isLt := ha } ∈ s

Next tactic:
simp [Finset.fin, ha, and_comm]
@[mono]
theorem fin_mono {n} : Monotone (Finset.fin n) := fun s t h x => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
n : ℕ
s t : Finset ℕ
h : s ≤ t
x : Fin n
⊢ x ∈ Finset.fin n s → x ∈ Finset.fin n t

Next tactic:
simpa using @h x
@[simp]
theorem fin_map {n} {s : Finset ℕ} : (s.fin n).map Fin.valEmbedding = s.filter (· < n) := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
n : ℕ
s : Finset ℕ
⊢ map Fin.valEmbedding (Finset.fin n s) = filter (fun x => x < n) s

Next tactic:
simp [Finset.fin, Finset.map_map]
theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
    ↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
t : Finset β
f : α → β
⊢ ↑t ⊆ f '' s ↔ ∃ s', ↑s' ⊆ s ∧ image f s' = t

Next tactic:
constructor
theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
    ↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
  constructor; 

Proof state:
case mp
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
t : Finset β
f : α → β
⊢ ↑t ⊆ f '' s → ∃ s', ↑s' ⊆ s ∧ image f s' = t
case mpr
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
t : Finset β
f : α → β
⊢ (∃ s', ↑s' ⊆ s ∧ image f s' = t) → ↑t ⊆ f '' s

Next tactic:
swap
theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
    ↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
  constructor; swap
  · 

Proof state:
case mpr
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
t : Finset β
f : α → β
⊢ (∃ s', ↑s' ⊆ s ∧ image f s' = t) → ↑t ⊆ f '' s

Next tactic:
rintro ⟨t, ht, rfl⟩
theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
    ↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
  constructor; swap
  · rintro ⟨t, ht, rfl⟩
    

Proof state:
case mpr.intro.intro
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
f : α → β
t : Finset α
ht : ↑t ⊆ s
⊢ ↑(image f t) ⊆ f '' s

Next tactic:
rw [coe_image]
theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
    ↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
  constructor; swap
  · rintro ⟨t, ht, rfl⟩
    rw [coe_image]
    

Proof state:
case mpr.intro.intro
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
f : α → β
t : Finset α
ht : ↑t ⊆ s
⊢ f '' ↑t ⊆ f '' s

Next tactic:
exact Set.image_subset f ht
theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
    ↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
  constructor; swap
  · rintro ⟨t, ht, rfl⟩
    rw [coe_image]
    exact Set.image_subset f ht
  

Proof state:
case mp
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
t : Finset β
f : α → β
⊢ ↑t ⊆ f '' s → ∃ s', ↑s' ⊆ s ∧ image f s' = t

Next tactic:
intro h
theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
    ↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
  constructor; swap
  · rintro ⟨t, ht, rfl⟩
    rw [coe_image]
    exact Set.image_subset f ht
  intro h
  

Proof state:
case mp
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
t : Finset β
f : α → β
h : ↑t ⊆ f '' s
⊢ ∃ s', ↑s' ⊆ s ∧ image f s' = t

Next tactic:
letI : CanLift β s (f ∘ (↑)) fun y => y ∈ f '' s := ⟨fun y ⟨x, hxt, hy⟩ => ⟨⟨x, hxt⟩, hy⟩⟩
theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
    ↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
  constructor; swap
  · rintro ⟨t, ht, rfl⟩
    rw [coe_image]
    exact Set.image_subset f ht
  intro h
  letI : CanLift β s (f ∘ (↑)) fun y => y ∈ f '' s := ⟨fun y ⟨x, hxt, hy⟩ => ⟨⟨x, hxt⟩, hy⟩⟩
  

Proof state:
case mp
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
t : Finset β
f : α → β
h : ↑t ⊆ f '' s
this : CanLift β (↑s) (f ∘ Subtype.val) fun y => y ∈ f '' s :=
  {
    prf := fun y x =>
      match x with
      | Exists.intro x { left := hxt, right := hy } => Exists.intro { val := x, property := hxt } hy }
⊢ ∃ s', ↑s' ⊆ s ∧ image f s' = t

Next tactic:
lift t to Finset s using h
theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
    ↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
  constructor; swap
  · rintro ⟨t, ht, rfl⟩
    rw [coe_image]
    exact Set.image_subset f ht
  intro h
  letI : CanLift β s (f ∘ (↑)) fun y => y ∈ f '' s := ⟨fun y ⟨x, hxt, hy⟩ => ⟨⟨x, hxt⟩, hy⟩⟩
  lift t to Finset s using h
  

Proof state:
case mp.intro
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
f : α → β
this : CanLift β (↑s) (f ∘ Subtype.val) fun y => y ∈ f '' s :=
  {
    prf := fun y x =>
      match x with
      | Exists.intro x { left := hxt, right := hy } => Exists.intro { val := x, property := hxt } hy }
t : Finset ↑s
⊢ ∃ s', ↑s' ⊆ s ∧ image f s' = image (f ∘ Subtype.val) t

Next tactic:
refine' ⟨t.map (Embedding.subtype _), map_subtype_subset _, _⟩
theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
    ↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
  constructor; swap
  · rintro ⟨t, ht, rfl⟩
    rw [coe_image]
    exact Set.image_subset f ht
  intro h
  letI : CanLift β s (f ∘ (↑)) fun y => y ∈ f '' s := ⟨fun y ⟨x, hxt, hy⟩ => ⟨⟨x, hxt⟩, hy⟩⟩
  lift t to Finset s using h
  refine' ⟨t.map (Embedding.subtype _), map_subtype_subset _, _⟩
  

Proof state:
case mp.intro
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
f : α → β
this : CanLift β (↑s) (f ∘ Subtype.val) fun y => y ∈ f '' s :=
  {
    prf := fun y x =>
      match x with
      | Exists.intro x { left := hxt, right := hy } => Exists.intro { val := x, property := hxt } hy }
t : Finset ↑s
⊢ image f (map (Embedding.subtype fun x => x ∈ s) t) = image (f ∘ Subtype.val) t

Next tactic:
ext y
theorem subset_image_iff [DecidableEq β] {s : Set α} {t : Finset β} {f : α → β} :
    ↑t ⊆ f '' s ↔ ∃ s' : Finset α, ↑s' ⊆ s ∧ s'.image f = t := by
  constructor; swap
  · rintro ⟨t, ht, rfl⟩
    rw [coe_image]
    exact Set.image_subset f ht
  intro h
  letI : CanLift β s (f ∘ (↑)) fun y => y ∈ f '' s := ⟨fun y ⟨x, hxt, hy⟩ => ⟨⟨x, hxt⟩, hy⟩⟩
  lift t to Finset s using h
  refine' ⟨t.map (Embedding.subtype _), map_subtype_subset _, _⟩
  ext y; 

Proof state:
case mp.intro.a
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : DecidableEq β
s : Set α
f : α → β
this : CanLift β (↑s) (f ∘ Subtype.val) fun y => y ∈ f '' s :=
  {
    prf := fun y x =>
      match x with
      | Exists.intro x { left := hxt, right := hy } => Exists.intro { val := x, property := hxt } hy }
t : Finset ↑s
y : β
⊢ y ∈ image f (map (Embedding.subtype fun x => x ∈ s) t) ↔ y ∈ image (f ∘ Subtype.val) t

Next tactic:
simp
theorem range_sdiff_zero {n : ℕ} : range (n + 1) \ {0} = (range n).image Nat.succ := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
n : ℕ
⊢ range (n + 1) \ {0} = image Nat.succ (range n)

Next tactic:
induction' n with k hk
theorem range_sdiff_zero {n : ℕ} : range (n + 1) \ {0} = (range n).image Nat.succ := by
  induction' n with k hk
  · 

Proof state:
case zero
α : Type u_1
β : Type u_2
γ : Type u_3
⊢ range (Nat.zero + 1) \ {0} = image Nat.succ (range Nat.zero)

Next tactic:
simp
theorem range_sdiff_zero {n : ℕ} : range (n + 1) \ {0} = (range n).image Nat.succ := by
  induction' n with k hk
  · simp
  

Proof state:
case succ
α : Type u_1
β : Type u_2
γ : Type u_3
k : ℕ
hk : range (k + 1) \ {0} = image Nat.succ (range k)
⊢ range (Nat.succ k + 1) \ {0} = image Nat.succ (range (Nat.succ k))

Next tactic:
conv_rhs => rw [range_succ]
theorem range_sdiff_zero {n : ℕ} : range (n + 1) \ {0} = (range n).image Nat.succ := by
  induction' n with k hk
  · simp
  conv_rhs => 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
k : ℕ
hk : range (k + 1) \ {0} = image Nat.succ (range k)
| image Nat.succ (range (Nat.succ k))

Next tactic:
rw [range_succ]
theorem range_sdiff_zero {n : ℕ} : range (n + 1) \ {0} = (range n).image Nat.succ := by
  induction' n with k hk
  · simp
  conv_rhs => rw [range_succ]
  

Proof state:
case succ
α : Type u_1
β : Type u_2
γ : Type u_3
k : ℕ
hk : range (k + 1) \ {0} = image Nat.succ (range k)
⊢ range (Nat.succ k + 1) \ {0} = image Nat.succ (insert k (range k))

Next tactic:
rw [range_succ, image_insert, ← hk, insert_sdiff_of_not_mem]
theorem range_sdiff_zero {n : ℕ} : range (n + 1) \ {0} = (range n).image Nat.succ := by
  induction' n with k hk
  · simp
  conv_rhs => rw [range_succ]
  rw [range_succ, image_insert, ← hk, insert_sdiff_of_not_mem]
  

Proof state:
case succ.h
α : Type u_1
β : Type u_2
γ : Type u_3
k : ℕ
hk : range (k + 1) \ {0} = image Nat.succ (range k)
⊢ k + 1 ∉ {0}

Next tactic:
simp
/-- Given an equivalence `α` to `β`, produce an equivalence between `Finset α` and `Finset β`. -/
protected def finsetCongr (e : α ≃ β) : Finset α ≃ Finset β where
  toFun s := s.map e.toEmbedding
  invFun s := s.map e.symm.toEmbedding
  left_inv s := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
e : α ≃ β
s : Finset α
⊢ (fun s => Finset.map (Equiv.toEmbedding e.symm) s) ((fun s => Finset.map (Equiv.toEmbedding e) s) s) = s

Next tactic:
simp [Finset.map_map]
/-- Given an equivalence `α` to `β`, produce an equivalence between `Finset α` and `Finset β`. -/
protected def finsetCongr (e : α ≃ β) : Finset α ≃ Finset β where
  toFun s := s.map e.toEmbedding
  invFun s := s.map e.symm.toEmbedding
  left_inv s := by simp [Finset.map_map]
  right_inv s := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
e : α ≃ β
s : Finset β
⊢ (fun s => Finset.map (Equiv.toEmbedding e) s) ((fun s => Finset.map (Equiv.toEmbedding e.symm) s) s) = s

Next tactic:
simp [Finset.map_map]
@[simp]
theorem finsetCongr_refl : (Equiv.refl α).finsetCongr = Equiv.refl _ := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
⊢ Equiv.finsetCongr (Equiv.refl α) = Equiv.refl (Finset α)

Next tactic:
ext
@[simp]
theorem finsetCongr_refl : (Equiv.refl α).finsetCongr = Equiv.refl _ := by
  ext
  

Proof state:
case H.a
α : Type u_1
β : Type u_2
γ : Type u_3
x✝ : Finset α
a✝ : α
⊢ a✝ ∈ (Equiv.finsetCongr (Equiv.refl α)) x✝ ↔ a✝ ∈ (Equiv.refl (Finset α)) x✝

Next tactic:
simp
@[simp]
theorem finsetCongr_trans (e : α ≃ β) (e' : β ≃ γ) :
    e.finsetCongr.trans e'.finsetCongr = (e.trans e').finsetCongr := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
e : α ≃ β
e' : β ≃ γ
⊢ (Equiv.finsetCongr e).trans (Equiv.finsetCongr e') = Equiv.finsetCongr (e.trans e')

Next tactic:
ext
@[simp]
theorem finsetCongr_trans (e : α ≃ β) (e' : β ≃ γ) :
    e.finsetCongr.trans e'.finsetCongr = (e.trans e').finsetCongr := by
  ext
  

Proof state:
case H.a
α : Type u_1
β : Type u_2
γ : Type u_3
e : α ≃ β
e' : β ≃ γ
x✝ : Finset α
a✝ : γ
⊢ a✝ ∈ ((Equiv.finsetCongr e).trans (Equiv.finsetCongr e')) x✝ ↔ a✝ ∈ (Equiv.finsetCongr (e.trans e')) x✝

Next tactic:
simp [-Finset.mem_map, -Equiv.trans_toEmbedding]
/-- The length of a list converted from a function is the size of the domain. -/
@[simp]
theorem length_ofFn {n} (f : Fin n → α) : length (ofFn f) = n := by
  

Proof state:
α : Type u
n : ℕ
f : Fin n → α
⊢ length (ofFn f) = n

Next tactic:
simp [ofFn]
@[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by 

Proof state:
α : Type u
n : ℕ
f : Fin n → α
i : Fin (length (ofFn f))
⊢ length (ofFn f) = n

Next tactic:
simp
@[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by simp) i) := by
  

Proof state:
α : Type u
n : ℕ
f : Fin n → α
i : Fin (length (ofFn f))
⊢ get (ofFn f) i = f (Fin.cast (_ : length (ofFn f) = n) i)

Next tactic:
have := Array.getElem_ofFn f i (by simpa using i.2)
@[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by simp) i) := by
  have := Array.getElem_ofFn f i (by 

Proof state:
α : Type u
n : ℕ
f : Fin n → α
i : Fin (length (ofFn f))
⊢ ↑i < Array.size (Array.ofFn f)

Next tactic:
simpa using i.2
@[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by simp) i) := by
  have := Array.getElem_ofFn f i (by simpa using i.2)
  

Proof state:
α : Type u
n : ℕ
f : Fin n → α
i : Fin (length (ofFn f))
this : (Array.ofFn f)[↑i] = f { val := ↑i, isLt := (_ : ↑i < n) }
⊢ get (ofFn f) i = f (Fin.cast (_ : length (ofFn f) = n) i)

Next tactic:
cases' i with i hi
@[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by simp) i) := by
  have := Array.getElem_ofFn f i (by simpa using i.2)
  cases' i with i hi
  

Proof state:
case mk
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
hi : i < length (ofFn f)
this :
  (Array.ofFn f)[↑{ val := i, isLt := hi }] =
    f { val := ↑{ val := i, isLt := hi }, isLt := (_ : ↑{ val := i, isLt := hi } < n) }
⊢ get (ofFn f) { val := i, isLt := hi } = f (Fin.cast (_ : length (ofFn f) = n) { val := i, isLt := hi })

Next tactic:
simp only [getElem, Array.get] at this
@[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by simp) i) := by
  have := Array.getElem_ofFn f i (by simpa using i.2)
  cases' i with i hi
  simp only [getElem, Array.get] at this
  

Proof state:
case mk
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
hi : i < length (ofFn f)
this :
  get (Array.ofFn f).data { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < Array.size (Array.ofFn f)) } =
    f { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < n) }
⊢ get (ofFn f) { val := i, isLt := hi } = f (Fin.cast (_ : length (ofFn f) = n) { val := i, isLt := hi })

Next tactic:
simp only [Fin.cast_mk]
@[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by simp) i) := by
  have := Array.getElem_ofFn f i (by simpa using i.2)
  cases' i with i hi
  simp only [getElem, Array.get] at this
  simp only [Fin.cast_mk]
  

Proof state:
case mk
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
hi : i < length (ofFn f)
this :
  get (Array.ofFn f).data { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < Array.size (Array.ofFn f)) } =
    f { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < n) }
⊢ get (ofFn f) { val := i, isLt := hi } = f { val := i, isLt := (_ : i < n) }

Next tactic:
rw [← this]
@[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by simp) i) := by
  have := Array.getElem_ofFn f i (by simpa using i.2)
  cases' i with i hi
  simp only [getElem, Array.get] at this
  simp only [Fin.cast_mk]
  rw [← this]
  

Proof state:
case mk
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
hi : i < length (ofFn f)
this :
  get (Array.ofFn f).data { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < Array.size (Array.ofFn f)) } =
    f { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < n) }
⊢ get (ofFn f) { val := i, isLt := hi } =
    get (Array.ofFn f).data { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < Array.size (Array.ofFn f)) }

Next tactic:
congr
@[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by simp) i) := by
  have := Array.getElem_ofFn f i (by simpa using i.2)
  cases' i with i hi
  simp only [getElem, Array.get] at this
  simp only [Fin.cast_mk]
  rw [← this]
  congr <;> 

Proof state:
case mk.h.e_2.h
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
hi : i < length (ofFn f)
this :
  get (Array.ofFn f).data { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < Array.size (Array.ofFn f)) } =
    f { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < n) }
⊢ ofFn f = (Array.ofFn f).data

Next tactic:
simp [ofFn]
@[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by simp) i) := by
  have := Array.getElem_ofFn f i (by simpa using i.2)
  cases' i with i hi
  simp only [getElem, Array.get] at this
  simp only [Fin.cast_mk]
  rw [← this]
  congr <;> 

Proof state:
case mk.h.e_3.e_1.e_a
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
hi : i < length (ofFn f)
this :
  get (Array.ofFn f).data { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < Array.size (Array.ofFn f)) } =
    f { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < n) }
⊢ ofFn f = (Array.ofFn f).data

Next tactic:
simp [ofFn]
@[simp]
theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by simp) i) := by
  have := Array.getElem_ofFn f i (by simpa using i.2)
  cases' i with i hi
  simp only [getElem, Array.get] at this
  simp only [Fin.cast_mk]
  rw [← this]
  congr <;> 

Proof state:
case mk.h.e_3.e_3
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
hi : i < length (ofFn f)
this :
  get (Array.ofFn f).data { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < Array.size (Array.ofFn f)) } =
    f { val := i, isLt := (_ : ↑{ val := i, isLt := hi } < n) }
⊢ HEq hi (_ : ↑{ val := i, isLt := hi } < Array.size (Array.ofFn f))

Next tactic:
simp [ofFn]
/-- The `n`th element of a list -/
@[simp]
theorem get?_ofFn {n} (f : Fin n → α) (i) : get? (ofFn f) i = ofFnNthVal f i :=
  if h : i < (ofFn f).length
  then by
    

Proof state:
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
h : i < length (ofFn f)
⊢ get? (ofFn f) i = ofFnNthVal f i

Next tactic:
rw [get?_eq_get h, get_ofFn]
/-- The `n`th element of a list -/
@[simp]
theorem get?_ofFn {n} (f : Fin n → α) (i) : get? (ofFn f) i = ofFnNthVal f i :=
  if h : i < (ofFn f).length
  then by
    rw [get?_eq_get h, get_ofFn]
    · 

Proof state:
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
h : i < length (ofFn f)
⊢ some (f (Fin.cast (_ : length (ofFn f) = n) { val := i, isLt := h })) = ofFnNthVal f i

Next tactic:
simp at h
/-- The `n`th element of a list -/
@[simp]
theorem get?_ofFn {n} (f : Fin n → α) (i) : get? (ofFn f) i = ofFnNthVal f i :=
  if h : i < (ofFn f).length
  then by
    rw [get?_eq_get h, get_ofFn]
    · simp at h; 

Proof state:
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
h✝ : i < length (ofFn f)
h : i < n
⊢ some (f (Fin.cast (_ : length (ofFn f) = n) { val := i, isLt := h✝ })) = ofFnNthVal f i

Next tactic:
simp [ofFnNthVal, h]
/-- The `n`th element of a list -/
@[simp]
theorem get?_ofFn {n} (f : Fin n → α) (i) : get? (ofFn f) i = ofFnNthVal f i :=
  if h : i < (ofFn f).length
  then by
    rw [get?_eq_get h, get_ofFn]
    · simp at h; simp [ofFnNthVal, h]
  else by
    

Proof state:
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
h : ¬i < length (ofFn f)
⊢ get? (ofFn f) i = ofFnNthVal f i

Next tactic:
rw [ofFnNthVal, dif_neg]
/-- The `n`th element of a list -/
@[simp]
theorem get?_ofFn {n} (f : Fin n → α) (i) : get? (ofFn f) i = ofFnNthVal f i :=
  if h : i < (ofFn f).length
  then by
    rw [get?_eq_get h, get_ofFn]
    · simp at h; simp [ofFnNthVal, h]
  else by
    rw [ofFnNthVal, dif_neg] <;>
    

Proof state:
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
h : ¬i < length (ofFn f)
⊢ get? (ofFn f) i = none

Next tactic:
simpa using h
/-- The `n`th element of a list -/
@[simp]
theorem get?_ofFn {n} (f : Fin n → α) (i) : get? (ofFn f) i = ofFnNthVal f i :=
  if h : i < (ofFn f).length
  then by
    rw [get?_eq_get h, get_ofFn]
    · simp at h; simp [ofFnNthVal, h]
  else by
    rw [ofFnNthVal, dif_neg] <;>
    

Proof state:
case hnc
α : Type u
n : ℕ
f : Fin n → α
i : ℕ
h : ¬i < length (ofFn f)
⊢ ¬i < n

Next tactic:
simpa using h
set_option linter.deprecated false in
@[deprecated get_ofFn]
theorem nthLe_ofFn {n} (f : Fin n → α) (i : Fin n) :
    nthLe (ofFn f) i ((length_ofFn f).symm ▸ i.2) = f i := by
  

Proof state:
α : Type u
n : ℕ
f : Fin n → α
i : Fin n
⊢ nthLe (ofFn f) ↑i (_ : ↑i < length (ofFn f)) = f i

Next tactic:
simp [nthLe]
@[simp]
theorem map_ofFn {β : Type*} {n : ℕ} (f : Fin n → α) (g : α → β) :
    map g (ofFn f) = ofFn (g ∘ f) :=
  ext_get (by 

Proof state:
α : Type u
β : Type u_1
n : ℕ
f : Fin n → α
g : α → β
⊢ length (map g (ofFn f)) = length (ofFn (g ∘ f))

Next tactic:
simp
@[simp]
theorem map_ofFn {β : Type*} {n : ℕ} (f : Fin n → α) (g : α → β) :
    map g (ofFn f) = ofFn (g ∘ f) :=
  ext_get (by simp) fun i h h' => by 

Proof state:
α : Type u
β : Type u_1
n : ℕ
f : Fin n → α
g : α → β
i : ℕ
h : i < length (map g (ofFn f))
h' : i < length (ofFn (g ∘ f))
⊢ get (map g (ofFn f)) { val := i, isLt := h } = get (ofFn (g ∘ f)) { val := i, isLt := h' }

Next tactic:
simp
@[congr]
theorem ofFn_congr {m n : ℕ} (h : m = n) (f : Fin m → α) :
    ofFn f = ofFn fun i : Fin n => f (Fin.cast h.symm i) := by
  

Proof state:
α : Type u
m n : ℕ
h : m = n
f : Fin m → α
⊢ ofFn f = ofFn fun i => f (Fin.cast (_ : n = m) i)

Next tactic:
subst h
@[congr]
theorem ofFn_congr {m n : ℕ} (h : m = n) (f : Fin m → α) :
    ofFn f = ofFn fun i : Fin n => f (Fin.cast h.symm i) := by
  subst h
  

Proof state:
α : Type u
m : ℕ
f : Fin m → α
⊢ ofFn f = ofFn fun i => f (Fin.cast (_ : m = m) i)

Next tactic:
simp_rw [Fin.cast_refl, id]
@[simp]
theorem ofFn_succ {n} (f : Fin (succ n) → α) : ofFn f = f 0 :: ofFn fun i => f i.succ :=
  ext_get (by 

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

Next tactic:
simp
@[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
    

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

Next tactic:
cases i
@[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
    · 

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

Next tactic:
simp