l3lab/ntp-mathlib huggingface dataset:
@[simp] theorem map_replicate (f : α → β) (n) (a : α) :
    map f (replicate n a) = replicate n (f a) := by
  induction n <;> [rfl; 

Proof state:
case succ
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
f : α → β
a : α
n✝ : ℕ
n_ih✝ : map f (replicate n✝ a) = replicate n✝ (f a)
⊢ map f (replicate (succ n✝) a) = replicate (succ n✝) (f a)

Next tactic:
simp only [*, replicate, map]
@[simp] theorem tail_replicate (a : α) (n) :
    tail (replicate n a) = replicate (n - 1) a := by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
n : ℕ
⊢ tail (replicate n a) = replicate (n - 1) a

Next tactic:
cases n
@[simp] theorem tail_replicate (a : α) (n) :
    tail (replicate n a) = replicate (n - 1) a := by cases n <;> 

Proof state:
case zero
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
⊢ tail (replicate zero a) = replicate (zero - 1) a

Next tactic:
rfl
@[simp] theorem tail_replicate (a : α) (n) :
    tail (replicate n a) = replicate (n - 1) a := by cases n <;> 

Proof state:
case succ
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
n✝ : ℕ
⊢ tail (replicate (succ n✝) a) = replicate (succ n✝ - 1) a

Next tactic:
rfl
@[simp] theorem join_replicate_nil (n : ℕ) : join (replicate n []) = @nil α := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
n : ℕ
⊢ join (replicate n []) = []

Next tactic:
induction n <;> [rfl; simp only [*, replicate, join, append_nil]]
@[simp] theorem join_replicate_nil (n : ℕ) : join (replicate n []) = @nil α := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
n : ℕ
⊢ join (replicate n []) = []

Next tactic:
induction n
@[simp] theorem join_replicate_nil (n : ℕ) : join (replicate n []) = @nil α := by
  induction n <;> [

Proof state:
case zero
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
⊢ join (replicate zero []) = []

Next tactic:
rfl
@[simp] theorem join_replicate_nil (n : ℕ) : join (replicate n []) = @nil α := by
  induction n <;> [rfl; 

Proof state:
case succ
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
n✝ : ℕ
n_ih✝ : join (replicate n✝ []) = []
⊢ join (replicate (succ n✝) []) = []

Next tactic:
simp only [*, replicate, join, append_nil]
@[simp] theorem replicate_right_inj' {a b : α} : ∀ {n},
    replicate n a = replicate n b ↔ n = 0 ∨ a = b
  | 0 => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
⊢ replicate 0 a = replicate 0 b ↔ 0 = 0 ∨ a = b

Next tactic:
simp
@[simp] theorem replicate_right_inj' {a b : α} : ∀ {n},
    replicate n a = replicate n b ↔ n = 0 ∨ a = b
  | 0 => by simp
  | n + 1 => (replicate_right_inj n.succ_ne_zero).trans <| by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
n : ℕ
⊢ a = b ↔ n + 1 = 0 ∨ a = b

Next tactic:
simp only [n.succ_ne_zero, false_or]
@[simp]
theorem mem_pure {α} (x y : α) : x ∈ (pure y : List α) ↔ x = y :=
  show x ∈ [y] ↔ x = y by 

Proof state:
ι : Type u_1
α✝ : Type u
β : Type v
γ : Type w
l₁ l₂ : List α✝
α : Type u_2
x y : α
⊢ x ∈ [y] ↔ x = y

Next tactic:
simp
theorem init_eq_of_concat_eq {a : α} {l₁ l₂ : List α} : concat l₁ a = concat l₂ a → l₁ = l₂ := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ : List α
a : α
l₁ l₂ : List α
⊢ concat l₁ a = concat l₂ a → l₁ = l₂

Next tactic:
intro h
theorem init_eq_of_concat_eq {a : α} {l₁ l₂ : List α} : concat l₁ a = concat l₂ a → l₁ = l₂ := by
  intro h
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ : List α
a : α
l₁ l₂ : List α
h : concat l₁ a = concat l₂ a
⊢ l₁ = l₂

Next tactic:
rw [concat_eq_append, concat_eq_append] at h
theorem init_eq_of_concat_eq {a : α} {l₁ l₂ : List α} : concat l₁ a = concat l₂ a → l₁ = l₂ := by
  intro h
  rw [concat_eq_append, concat_eq_append] at h
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ : List α
a : α
l₁ l₂ : List α
h : l₁ ++ [a] = l₂ ++ [a]
⊢ l₁ = l₂

Next tactic:
exact append_right_cancel h
theorem last_eq_of_concat_eq {a b : α} {l : List α} : concat l a = concat l b → a = b := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
⊢ concat l a = concat l b → a = b

Next tactic:
intro h
theorem last_eq_of_concat_eq {a b : α} {l : List α} : concat l a = concat l b → a = b := by
  intro h
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
h : concat l a = concat l b
⊢ a = b

Next tactic:
rw [concat_eq_append, concat_eq_append] at h
theorem last_eq_of_concat_eq {a b : α} {l : List α} : concat l a = concat l b → a = b := by
  intro h
  rw [concat_eq_append, concat_eq_append] at h
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
h : l ++ [a] = l ++ [b]
⊢ a = b

Next tactic:
exact head_eq_of_cons_eq (append_left_cancel h)
theorem concat_ne_nil (a : α) (l : List α) : concat l a ≠ [] := by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
l : List α
⊢ concat l a ≠ []

Next tactic:
simp
theorem concat_append (a : α) (l₁ l₂ : List α) : concat l₁ a ++ l₂ = l₁ ++ a :: l₂ := by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ : List α
a : α
l₁ l₂ : List α
⊢ concat l₁ a ++ l₂ = l₁ ++ a :: l₂

Next tactic:
simp
@[deprecated length_concat]
theorem length_concat' (a : α) (l : List α) : length (concat l a) = succ (length l) := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
l : List α
⊢ length (concat l a) = succ (length l)

Next tactic:
simp only [concat_eq_append, length_append, length]
theorem append_concat (a : α) (l₁ l₂ : List α) : l₁ ++ concat l₂ a = concat (l₁ ++ l₂) a := by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ : List α
a : α
l₁ l₂ : List α
⊢ l₁ ++ concat l₂ a = concat (l₁ ++ l₂) a

Next tactic:
simp
theorem reverse_cons' (a : α) (l : List α) : reverse (a :: l) = concat (reverse l) a := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
l : List α
⊢ reverse (a :: l) = concat (reverse l) a

Next tactic:
simp only [reverse_cons, concat_eq_append]
theorem concat_eq_reverse_cons (a : α) (l : List α) : concat l a = reverse (a :: reverse l) := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
l : List α
⊢ concat l a = reverse (a :: reverse l)

Next tactic:
simp only [concat_eq_append, reverse_cons, reverse_reverse]
theorem map_reverseAux (f : α → β) (l₁ l₂ : List α) :
    map f (reverseAux l₁ l₂) = reverseAux (map f l₁) (map f l₂) := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ : List α
f : α → β
l₁ l₂ : List α
⊢ map f (reverseAux l₁ l₂) = reverseAux (map f l₁) (map f l₂)

Next tactic:
simp only [reverseAux_eq, map_append, map_reverse]
@[simp] theorem reverse_replicate (n) (a : α) : reverse (replicate n a) = replicate n a :=
  eq_replicate.2
    ⟨by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
n : ℕ
a : α
⊢ length (reverse (replicate n a)) = n

Next tactic:
rw [length_reverse, length_replicate]
theorem isEmpty_iff_eq_nil {l : List α} : l.isEmpty ↔ l = [] := by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
⊢ isEmpty l = true ↔ l = []

Next tactic:
cases l
theorem isEmpty_iff_eq_nil {l : List α} : l.isEmpty ↔ l = [] := by cases l <;> 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
⊢ isEmpty [] = true ↔ [] = []

Next tactic:
simp [isEmpty]
theorem isEmpty_iff_eq_nil {l : List α} : l.isEmpty ↔ l = [] := by cases l <;> 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
head✝ : α
tail✝ : List α
⊢ isEmpty (head✝ :: tail✝) = true ↔ head✝ :: tail✝ = []

Next tactic:
simp [isEmpty]
@[simp]
theorem getLast_cons {a : α} {l : List α} :
    ∀ h : l ≠ nil, getLast (a :: l) (cons_ne_nil a l) = getLast l h := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
l : List α
⊢ ∀ (h : l ≠ []), getLast (a :: l) (_ : a :: l ≠ []) = getLast l h

Next tactic:
induction l
@[simp]
theorem getLast_cons {a : α} {l : List α} :
    ∀ h : l ≠ nil, getLast (a :: l) (cons_ne_nil a l) = getLast l h := by
  induction l <;> 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
⊢ ∀ (h : [] ≠ []), getLast [a] (_ : [a] ≠ []) = getLast [] h

Next tactic:
intros
@[simp]
theorem getLast_cons {a : α} {l : List α} :
    ∀ h : l ≠ nil, getLast (a :: l) (cons_ne_nil a l) = getLast l h := by
  induction l <;> 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a head✝ : α
tail✝ : List α
tail_ih✝ : ∀ (h : tail✝ ≠ []), getLast (a :: tail✝) (_ : a :: tail✝ ≠ []) = getLast tail✝ h
⊢ ∀ (h : head✝ :: tail✝ ≠ []), getLast (a :: head✝ :: tail✝) (_ : a :: head✝ :: tail✝ ≠ []) = getLast (head✝ :: tail✝) h

Next tactic:
intros
@[simp]
theorem getLast_cons {a : α} {l : List α} :
    ∀ h : l ≠ nil, getLast (a :: l) (cons_ne_nil a l) = getLast l h := by
  induction l <;> intros
  

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
h✝ : [] ≠ []
⊢ getLast [a] (_ : [a] ≠ []) = getLast [] h✝
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a head✝ : α
tail✝ : List α
tail_ih✝ : ∀ (h : tail✝ ≠ []), getLast (a :: tail✝) (_ : a :: tail✝ ≠ []) = getLast tail✝ h
h✝ : head✝ :: tail✝ ≠ []
⊢ getLast (a :: head✝ :: tail✝) (_ : a :: head✝ :: tail✝ ≠ []) = getLast (head✝ :: tail✝) h✝

Next tactic:
contradiction
@[simp]
theorem getLast_cons {a : α} {l : List α} :
    ∀ h : l ≠ nil, getLast (a :: l) (cons_ne_nil a l) = getLast l h := by
  induction l <;> intros
  contradiction
  

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a head✝ : α
tail✝ : List α
tail_ih✝ : ∀ (h : tail✝ ≠ []), getLast (a :: tail✝) (_ : a :: tail✝ ≠ []) = getLast tail✝ h
h✝ : head✝ :: tail✝ ≠ []
⊢ getLast (a :: head✝ :: tail✝) (_ : a :: head✝ :: tail✝ ≠ []) = getLast (head✝ :: tail✝) h✝

Next tactic:
rfl
theorem getLast_append_singleton {a : α} (l : List α) :
    getLast (l ++ [a]) (append_ne_nil_of_ne_nil_right l _ (cons_ne_nil a _)) = a := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
l : List α
⊢ getLast (l ++ [a]) (_ : l ++ [a] ≠ []) = a

Next tactic:
simp only [getLast_append]
theorem getLast_append' (l₁ l₂ : List α) (h : l₂ ≠ []) :
    getLast (l₁ ++ l₂) (append_ne_nil_of_ne_nil_right l₁ l₂ h) = getLast l₂ h := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ l₁ l₂ : List α
h : l₂ ≠ []
⊢ getLast (l₁ ++ l₂) (_ : l₁ ++ l₂ ≠ []) = getLast l₂ h

Next tactic:
induction' l₁ with _ _ ih
theorem getLast_append' (l₁ l₂ : List α) (h : l₂ ≠ []) :
    getLast (l₁ ++ l₂) (append_ne_nil_of_ne_nil_right l₁ l₂ h) = getLast l₂ h := by
  induction' l₁ with _ _ ih
  · 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂✝ l₂ : List α
h : l₂ ≠ []
⊢ getLast ([] ++ l₂) (_ : [] ++ l₂ ≠ []) = getLast l₂ h

Next tactic:
simp
theorem getLast_append' (l₁ l₂ : List α) (h : l₂ ≠ []) :
    getLast (l₁ ++ l₂) (append_ne_nil_of_ne_nil_right l₁ l₂ h) = getLast l₂ h := by
  induction' l₁ with _ _ ih
  · simp
  · 

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂✝ l₂ : List α
h : l₂ ≠ []
head✝ : α
tail✝ : List α
ih : getLast (tail✝ ++ l₂) (_ : tail✝ ++ l₂ ≠ []) = getLast l₂ h
⊢ getLast (head✝ :: tail✝ ++ l₂) (_ : head✝ :: tail✝ ++ l₂ ≠ []) = getLast l₂ h

Next tactic:
simp only [cons_append]
theorem getLast_append' (l₁ l₂ : List α) (h : l₂ ≠ []) :
    getLast (l₁ ++ l₂) (append_ne_nil_of_ne_nil_right l₁ l₂ h) = getLast l₂ h := by
  induction' l₁ with _ _ ih
  · simp
  · simp only [cons_append]
    

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂✝ l₂ : List α
h : l₂ ≠ []
head✝ : α
tail✝ : List α
ih : getLast (tail✝ ++ l₂) (_ : tail✝ ++ l₂ ≠ []) = getLast l₂ h
⊢ getLast (head✝ :: (tail✝ ++ l₂)) (_ : head✝ :: (tail✝ ++ l₂) ≠ []) = getLast l₂ h

Next tactic:
rw [List.getLast_cons]
theorem getLast_append' (l₁ l₂ : List α) (h : l₂ ≠ []) :
    getLast (l₁ ++ l₂) (append_ne_nil_of_ne_nil_right l₁ l₂ h) = getLast l₂ h := by
  induction' l₁ with _ _ ih
  · simp
  · simp only [cons_append]
    rw [List.getLast_cons]
    

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂✝ l₂ : List α
h : l₂ ≠ []
head✝ : α
tail✝ : List α
ih : getLast (tail✝ ++ l₂) (_ : tail✝ ++ l₂ ≠ []) = getLast l₂ h
⊢ getLast (tail✝ ++ l₂) ?cons = getLast l₂ h
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂✝ l₂ : List α
h : l₂ ≠ []
head✝ : α
tail✝ : List α
ih : getLast (tail✝ ++ l₂) (_ : tail✝ ++ l₂ ≠ []) = getLast l₂ h
⊢ tail✝ ++ l₂ ≠ []

Next tactic:
exact ih
theorem dropLast_append_getLast : ∀ {l : List α} (h : l ≠ []), dropLast l ++ [getLast l h] = l
  | [], h => absurd rfl h
  | [a], h => rfl
  | a :: b :: l, h => by
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
h : a :: b :: l ≠ []
⊢ dropLast (a :: b :: l) ++ [getLast (a :: b :: l) h] = a :: b :: l

Next tactic:
rw [dropLast_cons₂, cons_append, getLast_cons (cons_ne_nil _ _)]
theorem dropLast_append_getLast : ∀ {l : List α} (h : l ≠ []), dropLast l ++ [getLast l h] = l
  | [], h => absurd rfl h
  | [a], h => rfl
  | a :: b :: l, h => by
    rw [dropLast_cons₂, cons_append, getLast_cons (cons_ne_nil _ _)]
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
h : a :: b :: l ≠ []
⊢ a :: (dropLast (b :: l) ++ [getLast (b :: l) (_ : b :: l ≠ [])]) = a :: b :: l

Next tactic:
congr
theorem dropLast_append_getLast : ∀ {l : List α} (h : l ≠ []), dropLast l ++ [getLast l h] = l
  | [], h => absurd rfl h
  | [a], h => rfl
  | a :: b :: l, h => by
    rw [dropLast_cons₂, cons_append, getLast_cons (cons_ne_nil _ _)]
    congr
    

Proof state:
case e_tail
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
h : a :: b :: l ≠ []
⊢ dropLast (b :: l) ++ [getLast (b :: l) (_ : b :: l ≠ [])] = b :: l

Next tactic:
exact dropLast_append_getLast (cons_ne_nil b l)
theorem getLast_congr {l₁ l₂ : List α} (h₁ : l₁ ≠ []) (h₂ : l₂ ≠ []) (h₃ : l₁ = l₂) :
    getLast l₁ h₁ = getLast l₂ h₂ := by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ l₁ l₂ : List α
h₁ : l₁ ≠ []
h₂ : l₂ ≠ []
h₃ : l₁ = l₂
⊢ getLast l₁ h₁ = getLast l₂ h₂

Next tactic:
subst l₁
theorem getLast_congr {l₁ l₂ : List α} (h₁ : l₁ ≠ []) (h₂ : l₂ ≠ []) (h₃ : l₁ = l₂) :
    getLast l₁ h₁ = getLast l₂ h₂ := by subst l₁; 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂✝ l₂ : List α
h₂ h₁ : l₂ ≠ []
⊢ getLast l₂ h₁ = getLast l₂ h₂

Next tactic:
rfl
theorem getLast_mem : ∀ {l : List α} (h : l ≠ []), getLast l h ∈ l
  | [], h => absurd rfl h
  | [a], _ => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
x✝ : [a] ≠ []
⊢ getLast [a] x✝ ∈ [a]

Next tactic:
simp only [getLast, mem_singleton]
theorem getLast_mem : ∀ {l : List α} (h : l ≠ []), getLast l h ∈ l
  | [], h => absurd rfl h
  | [a], _ => by simp only [getLast, mem_singleton]
  | a :: b :: l, h =>
    List.mem_cons.2 <| Or.inr <| by
        

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
h : a :: b :: l ≠ []
⊢ getLast (a :: b :: l) h ∈ b :: l

Next tactic:
rw [getLast_cons_cons]
theorem getLast_mem : ∀ {l : List α} (h : l ≠ []), getLast l h ∈ l
  | [], h => absurd rfl h
  | [a], _ => by simp only [getLast, mem_singleton]
  | a :: b :: l, h =>
    List.mem_cons.2 <| Or.inr <| by
        rw [getLast_cons_cons]
        

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
h : a :: b :: l ≠ []
⊢ getLast (b :: l) (_ : b :: l ≠ []) ∈ b :: l

Next tactic:
exact getLast_mem (cons_ne_nil b l)
theorem getLast_replicate_succ (m : ℕ) (a : α) :
    (replicate (m + 1) a).getLast (ne_nil_of_length_eq_succ (length_replicate _ _)) = a := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
m : ℕ
a : α
⊢ getLast (replicate (m + 1) a) (_ : replicate (m + 1) a ≠ []) = a

Next tactic:
simp only [replicate_succ']
theorem getLast_replicate_succ (m : ℕ) (a : α) :
    (replicate (m + 1) a).getLast (ne_nil_of_length_eq_succ (length_replicate _ _)) = a := by
  simp only [replicate_succ']
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
m : ℕ
a : α
⊢ getLast (replicate m a ++ [a]) (_ : replicate m a ++ [a] ≠ []) = a

Next tactic:
exact getLast_append_singleton _
@[simp]
theorem getLast?_isNone : ∀ {l : List α}, (getLast? l).isNone ↔ l = []
  | [] => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
⊢ Option.isNone (getLast? []) = true ↔ [] = []

Next tactic:
simp
@[simp]
theorem getLast?_isNone : ∀ {l : List α}, (getLast? l).isNone ↔ l = []
  | [] => by simp
  | [a] => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
⊢ Option.isNone (getLast? [a]) = true ↔ [a] = []

Next tactic:
simp
@[simp]
theorem getLast?_isNone : ∀ {l : List α}, (getLast? l).isNone ↔ l = []
  | [] => by simp
  | [a] => by simp
  | a :: b :: l => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
⊢ Option.isNone (getLast? (a :: b :: l)) = true ↔ a :: b :: l = []

Next tactic:
simp [@getLast?_isNone (b :: l)]
@[simp]
theorem getLast?_isSome : ∀ {l : List α}, l.getLast?.isSome ↔ l ≠ []
  | [] => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
⊢ Option.isSome (getLast? []) = true ↔ [] ≠ []

Next tactic:
simp
@[simp]
theorem getLast?_isSome : ∀ {l : List α}, l.getLast?.isSome ↔ l ≠ []
  | [] => by simp
  | [a] => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
⊢ Option.isSome (getLast? [a]) = true ↔ [a] ≠ []

Next tactic:
simp
@[simp]
theorem getLast?_isSome : ∀ {l : List α}, l.getLast?.isSome ↔ l ≠ []
  | [] => by simp
  | [a] => by simp
  | a :: b :: l => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
⊢ Option.isSome (getLast? (a :: b :: l)) = true ↔ a :: b :: l ≠ []

Next tactic:
simp [@getLast?_isSome (b :: l)]
theorem mem_getLast?_eq_getLast : ∀ {l : List α} {x : α}, x ∈ l.getLast? → ∃ h, x = getLast l h
  | [], x, hx => False.elim <| by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
x : α
hx : x ∈ getLast? []
⊢ False

Next tactic:
simp at hx
theorem mem_getLast?_eq_getLast : ∀ {l : List α} {x : α}, x ∈ l.getLast? → ∃ h, x = getLast l h
  | [], x, hx => False.elim <| by simp at hx
  | [a], x, hx =>
    have : a = x := by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a x : α
hx : x ∈ getLast? [a]
⊢ a = x

Next tactic:
simpa using hx
theorem mem_getLast?_eq_getLast : ∀ {l : List α} {x : α}, x ∈ l.getLast? → ∃ h, x = getLast l h
  | [], x, hx => False.elim <| by simp at hx
  | [a], x, hx =>
    have : a = x := by simpa using hx
    this ▸ ⟨cons_ne_nil a [], rfl⟩
  | a :: b :: l, x, hx => by
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
x : α
hx : x ∈ getLast? (a :: b :: l)
⊢ ∃ h, x = getLast (a :: b :: l) h

Next tactic:
rw [getLast?_cons_cons] at hx
theorem mem_getLast?_eq_getLast : ∀ {l : List α} {x : α}, x ∈ l.getLast? → ∃ h, x = getLast l h
  | [], x, hx => False.elim <| by simp at hx
  | [a], x, hx =>
    have : a = x := by simpa using hx
    this ▸ ⟨cons_ne_nil a [], rfl⟩
  | a :: b :: l, x, hx => by
    rw [getLast?_cons_cons] at hx
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
x : α
hx : x ∈ getLast? (b :: l)
⊢ ∃ h, x = getLast (a :: b :: l) h

Next tactic:
rcases mem_getLast?_eq_getLast hx with ⟨_, h₂⟩
theorem mem_getLast?_eq_getLast : ∀ {l : List α} {x : α}, x ∈ l.getLast? → ∃ h, x = getLast l h
  | [], x, hx => False.elim <| by simp at hx
  | [a], x, hx =>
    have : a = x := by simpa using hx
    this ▸ ⟨cons_ne_nil a [], rfl⟩
  | a :: b :: l, x, hx => by
    rw [getLast?_cons_cons] at hx
    rcases mem_getLast?_eq_getLast hx with ⟨_, h₂⟩
    

Proof state:
case intro
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
x : α
hx : x ∈ getLast? (b :: l)
w✝ : b :: l ≠ []
h₂ : x = getLast (b :: l) w✝
⊢ ∃ h, x = getLast (a :: b :: l) h

Next tactic:
use cons_ne_nil _ _
theorem mem_getLast?_eq_getLast : ∀ {l : List α} {x : α}, x ∈ l.getLast? → ∃ h, x = getLast l h
  | [], x, hx => False.elim <| by simp at hx
  | [a], x, hx =>
    have : a = x := by simpa using hx
    this ▸ ⟨cons_ne_nil a [], rfl⟩
  | a :: b :: l, x, hx => by
    rw [getLast?_cons_cons] at hx
    rcases mem_getLast?_eq_getLast hx with ⟨_, h₂⟩
    use cons_ne_nil _ _
    

Proof state:
case h
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
x : α
hx : x ∈ getLast? (b :: l)
w✝ : b :: l ≠ []
h₂ : x = getLast (b :: l) w✝
⊢ x = getLast (a :: b :: l) (_ : a :: b :: l ≠ [])

Next tactic:
assumption
theorem mem_getLast?_cons {x y : α} : ∀ {l : List α}, x ∈ l.getLast? → x ∈ (y :: l).getLast?
  | [], _ => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
x y : α
x✝ : x ∈ getLast? []
⊢ x ∈ getLast? [y]

Next tactic:
contradiction
theorem dropLast_append_getLast? : ∀ {l : List α}, ∀ a ∈ l.getLast?, dropLast l ++ [a] = l
  | [], a, ha => (Option.not_mem_none a ha).elim
  | [a], _, rfl => rfl
  | a :: b :: l, c, hc => by
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
c : α
hc : c ∈ getLast? (a :: b :: l)
⊢ dropLast (a :: b :: l) ++ [c] = a :: b :: l

Next tactic:
rw [getLast?_cons_cons] at hc
theorem dropLast_append_getLast? : ∀ {l : List α}, ∀ a ∈ l.getLast?, dropLast l ++ [a] = l
  | [], a, ha => (Option.not_mem_none a ha).elim
  | [a], _, rfl => rfl
  | a :: b :: l, c, hc => by
    rw [getLast?_cons_cons] at hc
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a b : α
l : List α
c : α
hc : c ∈ getLast? (b :: l)
⊢ dropLast (a :: b :: l) ++ [c] = a :: b :: l

Next tactic:
rw [dropLast_cons₂, cons_append, dropLast_append_getLast? _ hc]
theorem getLastI_eq_getLast? [Inhabited α] : ∀ l : List α, l.getLastI = l.getLast?.iget
  | [] => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
⊢ getLastI [] = Option.iget (getLast? [])

Next tactic:
simp [getLastI, Inhabited.default]
theorem getLastI_eq_getLast? [Inhabited α] : ∀ l : List α, l.getLastI = l.getLast?.iget
  | [] => by simp [getLastI, Inhabited.default]
  | [a] => rfl
  | [a, b] => rfl
  | [a, b, c] => rfl
  | _ :: _ :: c :: l => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : Inhabited α
head✝¹ head✝ c : α
l : List α
⊢ getLastI (head✝¹ :: head✝ :: c :: l) = Option.iget (getLast? (head✝¹ :: head✝ :: c :: l))

Next tactic:
simp [getLastI, getLastI_eq_getLast? (c :: l)]
@[simp]
theorem getLast?_append_cons :
    ∀ (l₁ : List α) (a : α) (l₂ : List α), getLast? (l₁ ++ a :: l₂) = getLast? (a :: l₂)
  | [], a, l₂ => rfl
  | [b], a, l₂ => rfl
  | b :: c :: l₁, a, l₂ => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ : List α
b c : α
l₁ : List α
a : α
l₂ : List α
⊢ getLast? (b :: c :: l₁ ++ a :: l₂) = getLast? (a :: l₂)

Next tactic:
rw [cons_append, cons_append, getLast?_cons_cons,
    ← cons_append, getLast?_append_cons (c :: l₁)]
theorem getLast?_append_of_ne_nil (l₁ : List α) :
    ∀ {l₂ : List α} (_ : l₂ ≠ []), getLast? (l₁ ++ l₂) = getLast? l₂
  | [], hl₂ => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂ l₁ : List α
hl₂ : [] ≠ []
⊢ getLast? (l₁ ++ []) = getLast? []

Next tactic:
contradiction
theorem getLast?_append {l₁ l₂ : List α} {x : α} (h : x ∈ l₂.getLast?) :
    x ∈ (l₁ ++ l₂).getLast? := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂✝ l₁ l₂ : List α
x : α
h : x ∈ getLast? l₂
⊢ x ∈ getLast? (l₁ ++ l₂)

Next tactic:
cases l₂
theorem getLast?_append {l₁ l₂ : List α} {x : α} (h : x ∈ l₂.getLast?) :
    x ∈ (l₁ ++ l₂).getLast? := by
  cases l₂
  · 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁✝ l₂ l₁ : List α
x : α
h : x ∈ getLast? []
⊢ x ∈ getLast? (l₁ ++ [])

Next tactic:
contradiction