l3lab/ntp-mathlib huggingface dataset:
def setParentBump {n} (m : UFModel n) (x y : Fin n)
    (H : m.rank x ≤ m.rank y) (hroot : (m.parent y).1 = y) : UFModel n where
  parent i := if x.1 = i then y else m.parent i
  rank i := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
  rank_lt i := by
    simp; split <;>
      (rename_i h₁; (try simp [h₁]); split <;> rename_i h₂ <;>
        (intro h; try simp [h] at h₂ <;> simp [h₁, h₂, h]))
    · simp [← h₁]; split <;> rename_i h₃
      · rw [h₃]; apply Nat.lt_succ_self
      · exact lt_of_le_of_ne H h₃
    · have := Fin.eq_of_val_eq h₂.1; subst this
      simp [hroot] at h
    · have := m.rank_lt i h
      split <;> 

Proof state:
case inr.inr.inl
n : ℕ
m : UFModel n
x y : Fin n
H : rank m ↑x ≤ rank m ↑y
hroot : ↑(parent m y) = ↑y
i : Fin n
h₁ : ¬↑x = ↑i
h₂ : ¬(↑y = ↑i ∧ rank m ↑x = rank m ↑y)
h : ¬↑(parent m i) = ↑i
this : rank m ↑i < rank m ↑(parent m i)
h✝ : ↑y = ↑(parent m i) ∧ rank m ↑x = rank m ↑y
⊢ rank m ↑i < rank m ↑y + 1

Next tactic:
rename_i h₃
def setParentBump {n} (m : UFModel n) (x y : Fin n)
    (H : m.rank x ≤ m.rank y) (hroot : (m.parent y).1 = y) : UFModel n where
  parent i := if x.1 = i then y else m.parent i
  rank i := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
  rank_lt i := by
    simp; split <;>
      (rename_i h₁; (try simp [h₁]); split <;> rename_i h₂ <;>
        (intro h; try simp [h] at h₂ <;> simp [h₁, h₂, h]))
    · simp [← h₁]; split <;> rename_i h₃
      · rw [h₃]; apply Nat.lt_succ_self
      · exact lt_of_le_of_ne H h₃
    · have := Fin.eq_of_val_eq h₂.1; subst this
      simp [hroot] at h
    · have := m.rank_lt i h
      split <;> 

Proof state:
case inr.inr.inr
n : ℕ
m : UFModel n
x y : Fin n
H : rank m ↑x ≤ rank m ↑y
hroot : ↑(parent m y) = ↑y
i : Fin n
h₁ : ¬↑x = ↑i
h₂ : ¬(↑y = ↑i ∧ rank m ↑x = rank m ↑y)
h : ¬↑(parent m i) = ↑i
this : rank m ↑i < rank m ↑(parent m i)
h✝ : ¬(↑y = ↑(parent m i) ∧ rank m ↑x = rank m ↑y)
⊢ rank m ↑i < rank m ↑(parent m i)

Next tactic:
rename_i h₃
def setParentBump {n} (m : UFModel n) (x y : Fin n)
    (H : m.rank x ≤ m.rank y) (hroot : (m.parent y).1 = y) : UFModel n where
  parent i := if x.1 = i then y else m.parent i
  rank i := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
  rank_lt i := by
    simp; split <;>
      (rename_i h₁; (try simp [h₁]); split <;> rename_i h₂ <;>
        (intro h; try simp [h] at h₂ <;> simp [h₁, h₂, h]))
    · simp [← h₁]; split <;> rename_i h₃
      · rw [h₃]; apply Nat.lt_succ_self
      · exact lt_of_le_of_ne H h₃
    · have := Fin.eq_of_val_eq h₂.1; subst this
      simp [hroot] at h
    · have := m.rank_lt i h
      split <;> rename_i h₃
      · 

Proof state:
case inr.inr.inl
n : ℕ
m : UFModel n
x y : Fin n
H : rank m ↑x ≤ rank m ↑y
hroot : ↑(parent m y) = ↑y
i : Fin n
h₁ : ¬↑x = ↑i
h₂ : ¬(↑y = ↑i ∧ rank m ↑x = rank m ↑y)
h : ¬↑(parent m i) = ↑i
this : rank m ↑i < rank m ↑(parent m i)
h₃ : ↑y = ↑(parent m i) ∧ rank m ↑x = rank m ↑y
⊢ rank m ↑i < rank m ↑y + 1

Next tactic:
rw [h₃.1]
def setParentBump {n} (m : UFModel n) (x y : Fin n)
    (H : m.rank x ≤ m.rank y) (hroot : (m.parent y).1 = y) : UFModel n where
  parent i := if x.1 = i then y else m.parent i
  rank i := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
  rank_lt i := by
    simp; split <;>
      (rename_i h₁; (try simp [h₁]); split <;> rename_i h₂ <;>
        (intro h; try simp [h] at h₂ <;> simp [h₁, h₂, h]))
    · simp [← h₁]; split <;> rename_i h₃
      · rw [h₃]; apply Nat.lt_succ_self
      · exact lt_of_le_of_ne H h₃
    · have := Fin.eq_of_val_eq h₂.1; subst this
      simp [hroot] at h
    · have := m.rank_lt i h
      split <;> rename_i h₃
      · rw [h₃.1]; 

Proof state:
case inr.inr.inl
n : ℕ
m : UFModel n
x y : Fin n
H : rank m ↑x ≤ rank m ↑y
hroot : ↑(parent m y) = ↑y
i : Fin n
h₁ : ¬↑x = ↑i
h₂ : ¬(↑y = ↑i ∧ rank m ↑x = rank m ↑y)
h : ¬↑(parent m i) = ↑i
this : rank m ↑i < rank m ↑(parent m i)
h₃ : ↑y = ↑(parent m i) ∧ rank m ↑x = rank m ↑y
⊢ rank m ↑i < rank m ↑(parent m i) + 1

Next tactic:
exact Nat.lt_succ_of_lt this
def setParentBump {n} (m : UFModel n) (x y : Fin n)
    (H : m.rank x ≤ m.rank y) (hroot : (m.parent y).1 = y) : UFModel n where
  parent i := if x.1 = i then y else m.parent i
  rank i := if y.1 = i ∧ m.rank x = m.rank y then m.rank y + 1 else m.rank i
  rank_lt i := by
    simp; split <;>
      (rename_i h₁; (try simp [h₁]); split <;> rename_i h₂ <;>
        (intro h; try simp [h] at h₂ <;> simp [h₁, h₂, h]))
    · simp [← h₁]; split <;> rename_i h₃
      · rw [h₃]; apply Nat.lt_succ_self
      · exact lt_of_le_of_ne H h₃
    · have := Fin.eq_of_val_eq h₂.1; subst this
      simp [hroot] at h
    · have := m.rank_lt i h
      split <;> rename_i h₃
      · rw [h₃.1]; exact Nat.lt_succ_of_lt this
      · 

Proof state:
case inr.inr.inr
n : ℕ
m : UFModel n
x y : Fin n
H : rank m ↑x ≤ rank m ↑y
hroot : ↑(parent m y) = ↑y
i : Fin n
h₁ : ¬↑x = ↑i
h₂ : ¬(↑y = ↑i ∧ rank m ↑x = rank m ↑y)
h : ¬↑(parent m i) = ↑i
this : rank m ↑i < rank m ↑(parent m i)
h₃ : ¬(↑y = ↑(parent m i) ∧ rank m ↑x = rank m ↑y)
⊢ rank m ↑i < rank m ↑(parent m i)

Next tactic:
exact this
theorem mk' {arr : Array α} {f : α → β} {n} {g : Fin n → β} (e : n = arr.size)
    (H : ∀ i h₁ h₂, f (arr.get ⟨i, h₁⟩) = g ⟨i, h₂⟩) : Agrees arr f g := by
  

Proof state:
α : Type u_1
β : Sort u_2
arr : Array α
f : α → β
n : ℕ
g : Fin n → β
e : n = Array.size arr
H :
  ∀ (i : ℕ) (h₁ : i < Array.size arr) (h₂ : i < n),
    f (Array.get arr { val := i, isLt := h₁ }) = g { val := i, isLt := h₂ }
⊢ Agrees arr f g

Next tactic:
cases e
theorem mk' {arr : Array α} {f : α → β} {n} {g : Fin n → β} (e : n = arr.size)
    (H : ∀ i h₁ h₂, f (arr.get ⟨i, h₁⟩) = g ⟨i, h₂⟩) : Agrees arr f g := by
  cases e
  

Proof state:
case refl
α : Type u_1
β : Sort u_2
arr : Array α
f : α → β
g : Fin (Array.size arr) → β
H : ∀ (i : ℕ) (h₁ h₂ : i < Array.size arr), f (Array.get arr { val := i, isLt := h₁ }) = g { val := i, isLt := h₂ }
⊢ Agrees arr f g

Next tactic:
have : (fun i ↦ f (arr.get i)) = g := by funext ⟨i, h⟩; apply H
theorem mk' {arr : Array α} {f : α → β} {n} {g : Fin n → β} (e : n = arr.size)
    (H : ∀ i h₁ h₂, f (arr.get ⟨i, h₁⟩) = g ⟨i, h₂⟩) : Agrees arr f g := by
  cases e
  have : (fun i ↦ f (arr.get i)) = g := by 

Proof state:
α : Type u_1
β : Sort u_2
arr : Array α
f : α → β
g : Fin (Array.size arr) → β
H : ∀ (i : ℕ) (h₁ h₂ : i < Array.size arr), f (Array.get arr { val := i, isLt := h₁ }) = g { val := i, isLt := h₂ }
⊢ (fun i => f (Array.get arr i)) = g

Next tactic:
funext ⟨i, h⟩
theorem mk' {arr : Array α} {f : α → β} {n} {g : Fin n → β} (e : n = arr.size)
    (H : ∀ i h₁ h₂, f (arr.get ⟨i, h₁⟩) = g ⟨i, h₂⟩) : Agrees arr f g := by
  cases e
  have : (fun i ↦ f (arr.get i)) = g := by funext ⟨i, h⟩; 

Proof state:
case h
α : Type u_1
β : Sort u_2
arr : Array α
f : α → β
g : Fin (Array.size arr) → β
H : ∀ (i : ℕ) (h₁ h₂ : i < Array.size arr), f (Array.get arr { val := i, isLt := h₁ }) = g { val := i, isLt := h₂ }
i : ℕ
h : i < Array.size arr
⊢ f (Array.get arr { val := i, isLt := h }) = g { val := i, isLt := h }

Next tactic:
apply H
theorem mk' {arr : Array α} {f : α → β} {n} {g : Fin n → β} (e : n = arr.size)
    (H : ∀ i h₁ h₂, f (arr.get ⟨i, h₁⟩) = g ⟨i, h₂⟩) : Agrees arr f g := by
  cases e
  have : (fun i ↦ f (arr.get i)) = g := by funext ⟨i, h⟩; apply H
  

Proof state:
case refl
α : Type u_1
β : Sort u_2
arr : Array α
f : α → β
g : Fin (Array.size arr) → β
H : ∀ (i : ℕ) (h₁ h₂ : i < Array.size arr), f (Array.get arr { val := i, isLt := h₁ }) = g { val := i, isLt := h₂ }
this : (fun i => f (Array.get arr i)) = g
⊢ Agrees arr f g

Next tactic:
cases this
theorem mk' {arr : Array α} {f : α → β} {n} {g : Fin n → β} (e : n = arr.size)
    (H : ∀ i h₁ h₂, f (arr.get ⟨i, h₁⟩) = g ⟨i, h₂⟩) : Agrees arr f g := by
  cases e
  have : (fun i ↦ f (arr.get i)) = g := by funext ⟨i, h⟩; apply H
  cases this; 

Proof state:
case refl.refl
α : Type u_1
β : Sort u_2
arr : Array α
f : α → β
H :
  ∀ (i : ℕ) (h₁ h₂ : i < Array.size arr),
    f (Array.get arr { val := i, isLt := h₁ }) = (fun i => f (Array.get arr i)) { val := i, isLt := h₂ }
⊢ Agrees arr f fun i => f (Array.get arr i)

Next tactic:
constructor
theorem size_eq {arr : Array α} {m : Fin n → β} (H : Agrees arr f m) : n = arr.size := by
  

Proof state:
α : Type u_1
n : ℕ
β : Sort u_2
f : α → β
arr : Array α
m : Fin n → β
H : Agrees arr f m
⊢ n = Array.size arr

Next tactic:
cases H
theorem size_eq {arr : Array α} {m : Fin n → β} (H : Agrees arr f m) : n = arr.size := by
  cases H; 

Proof state:
case mk
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
⊢ Array.size arr = Array.size arr

Next tactic:
rfl
theorem get_eq {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m) :
    ∀ i h₁ h₂, f (arr.get ⟨i, h₁⟩) = m ⟨i, h₂⟩ := by
  

Proof state:
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
n : ℕ
m : Fin n → β
H : Agrees arr f m
⊢ ∀ (i : ℕ) (h₁ : i < Array.size arr) (h₂ : i < n),
    f (Array.get arr { val := i, isLt := h₁ }) = m { val := i, isLt := h₂ }

Next tactic:
cases H
theorem get_eq {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m) :
    ∀ i h₁ h₂, f (arr.get ⟨i, h₁⟩) = m ⟨i, h₂⟩ := by
  cases H; 

Proof state:
case mk
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
⊢ ∀ (i : ℕ) (h₁ h₂ : i < Array.size arr),
    f (Array.get arr { val := i, isLt := h₁ }) = (fun i => f (Array.get arr i)) { val := i, isLt := h₂ }

Next tactic:
exact fun i h _ ↦ rfl
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  

Proof state:
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
n : ℕ
m : Fin n → β
H : Agrees arr f m
k : ℕ
hk : k = n + 1
x : α
m' : Fin k → β
hm₁ : ∀ (i : Fin k) (h : ↑i < n), m' i = m { val := ↑i, isLt := h }
hm₂ : ∀ (h : n < k), f x = m' { val := n, isLt := h }
⊢ Agrees (Array.push arr x) f m'

Next tactic:
cases H
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  

Proof state:
case mk
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = (fun i => f (Array.get arr i)) { val := ↑i, isLt := h }
⊢ Agrees (Array.push arr x) f m'

Next tactic:
have : k = (arr.push x).size := by simp [hk]
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by 

Proof state:
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = (fun i => f (Array.get arr i)) { val := ↑i, isLt := h }
⊢ k = Array.size (Array.push arr x)

Next tactic:
simp [hk]
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  

Proof state:
case mk
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = (fun i => f (Array.get arr i)) { val := ↑i, isLt := h }
this : k = Array.size (Array.push arr x)
⊢ Agrees (Array.push arr x) f m'

Next tactic:
refine mk' this fun i h₁ h₂ ↦ ?_
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  

Proof state:
case mk
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = (fun i => f (Array.get arr i)) { val := ↑i, isLt := h }
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
⊢ f (Array.get (Array.push arr x) { val := i, isLt := h₁ }) = m' { val := i, isLt := h₂ }

Next tactic:
simp [Array.get_push]
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; 

Proof state:
case mk
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = (fun i => f (Array.get arr i)) { val := ↑i, isLt := h }
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
⊢ f (if h : i < Array.size arr then arr[i] else x) = m' { val := i, isLt := h₂ }

Next tactic:
split
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; split <;> (

Proof state:
case mk.inl
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = (fun i => f (Array.get arr i)) { val := ↑i, isLt := h }
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
h✝ : i < Array.size arr
⊢ f arr[i] = m' { val := i, isLt := h₂ }

Next tactic:
rename_i h
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; split <;> (rename_i h; 

Proof state:
case mk.inl
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = (fun i => f (Array.get arr i)) { val := ↑i, isLt := h }
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
h : i < Array.size arr
⊢ f arr[i] = m' { val := i, isLt := h₂ }

Next tactic:
simp at hm₁ ⊢
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; split <;> (

Proof state:
case mk.inr
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = (fun i => f (Array.get arr i)) { val := ↑i, isLt := h }
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
h✝ : ¬i < Array.size arr
⊢ f x = m' { val := i, isLt := h₂ }

Next tactic:
rename_i h
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; split <;> (rename_i h; 

Proof state:
case mk.inr
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = (fun i => f (Array.get arr i)) { val := ↑i, isLt := h }
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
h : ¬i < Array.size arr
⊢ f x = m' { val := i, isLt := h₂ }

Next tactic:
simp at hm₁ ⊢
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; split <;> (rename_i h; simp at hm₁ ⊢)
  · 

Proof state:
case mk.inl
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = f arr[↑i]
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
h : i < Array.size arr
⊢ f arr[i] = m' { val := i, isLt := h₂ }

Next tactic:
rw [← hm₁ ⟨i, h₂⟩]
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; split <;> (rename_i h; simp at hm₁ ⊢)
  · rw [← hm₁ ⟨i, h₂⟩]; 

Proof state:
case mk.inl
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = f arr[↑i]
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
h : i < Array.size arr
⊢ ↑{ val := i, isLt := h₂ } < Array.size arr

Next tactic:
assumption
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; split <;> (rename_i h; simp at hm₁ ⊢)
  · rw [← hm₁ ⟨i, h₂⟩]; assumption
  · 

Proof state:
case mk.inr
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = f arr[↑i]
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
h : ¬i < Array.size arr
⊢ f x = m' { val := i, isLt := h₂ }

Next tactic:
cases show i = arr.size by apply le_antisymm <;> simp_all [Nat.lt_succ]
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; split <;> (rename_i h; simp at hm₁ ⊢)
  · rw [← hm₁ ⟨i, h₂⟩]; assumption
  · cases show i = arr.size by 

Proof state:
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = f arr[↑i]
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
h : ¬i < Array.size arr
⊢ i = Array.size arr

Next tactic:
apply le_antisymm
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; split <;> (rename_i h; simp at hm₁ ⊢)
  · rw [← hm₁ ⟨i, h₂⟩]; assumption
  · cases show i = arr.size by apply le_antisymm <;> 

Proof state:
case a
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = f arr[↑i]
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
h : ¬i < Array.size arr
⊢ i ≤ Array.size arr

Next tactic:
simp_all [Nat.lt_succ]
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; split <;> (rename_i h; simp at hm₁ ⊢)
  · rw [← hm₁ ⟨i, h₂⟩]; assumption
  · cases show i = arr.size by apply le_antisymm <;> 

Proof state:
case a
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = f arr[↑i]
this : k = Array.size (Array.push arr x)
i : ℕ
h₁ : i < Array.size (Array.push arr x)
h₂ : i < k
h : ¬i < Array.size arr
⊢ Array.size arr ≤ i

Next tactic:
simp_all [Nat.lt_succ]
theorem push {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    (k) (hk : k = n + 1) (x) (m' : Fin k → β)
    (hm₁ : ∀ (i : Fin k) (h : i < n), m' i = m ⟨i, h⟩)
    (hm₂ : ∀ (h : n < k), f x = m' ⟨n, h⟩) : Agrees (arr.push x) f m' := by
  cases H
  have : k = (arr.push x).size := by simp [hk]
  refine mk' this fun i h₁ h₂ ↦ ?_
  simp [Array.get_push]; split <;> (rename_i h; simp at hm₁ ⊢)
  · rw [← hm₁ ⟨i, h₂⟩]; assumption
  · cases show i = arr.size by apply le_antisymm <;> simp_all [Nat.lt_succ]
    

Proof state:
case mk.inr.refl
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
k : ℕ
x : α
m' : Fin k → β
hk : k = Array.size arr + 1
hm₂ : ∀ (h : Array.size arr < k), f x = m' { val := Array.size arr, isLt := h }
hm₁ : ∀ (i : Fin k) (h : ↑i < Array.size arr), m' i = f arr[↑i]
this : k = Array.size (Array.push arr x)
h₁ : Array.size arr < Array.size (Array.push arr x)
h₂ : Array.size arr < k
h : ¬Array.size arr < Array.size arr
⊢ f x = m' { val := Array.size arr, isLt := h₂ }

Next tactic:
rw [hm₂]
theorem set {arr : Array α} {n} {m : Fin n → β} (H : Agrees arr f m)
    {i : Fin arr.size} {x} {m' : Fin n → β}
  (hm₁ : ∀ (j : Fin n), j.1 ≠ i → m' j = m j)
  (hm₂ : ∀ (h : i < n), f x = m' ⟨i, h⟩) : Agrees (arr.set i x) f m' := by
  

Proof state:
α : Type u_1
β : Sort u_2
f : α → β
arr : Array α
n : ℕ
m : Fin n → β
H : Agrees arr f m
i : Fin (Array.size arr)
x : α
m' : Fin n → β
hm₁ : ∀ (j : Fin n), ↑j ≠ ↑i → m' j = m j
hm₂ : ∀ (h : ↑i < n), f x = m' { val := ↑i, isLt := h }
⊢ Agrees (Array.set arr i x) f m'

Next tactic:
cases H