l3lab/ntp-mathlib huggingface dataset:
/-- Induction principle from the right for lists: if a property holds for the empty list, and
for `l ++ [a]` if it holds for `l`, then it holds for all lists. The principle is given for
a `Sort`-valued predicate, i.e., it can also be used to construct data. -/
@[elab_as_elim]
def reverseRecOn {C : List α → Sort*} (l : List α) (H0 : C [])
    (H1 : ∀ (l : List α) (a : α), C l → C (l ++ [a])) : C l := by
  rw [← reverse_reverse l]
  match h:(reverse l) with
  | [] => exact H0
  | head :: tail =>
    have : tail.length < l.length := by
      rw [← length_reverse l, h, length_cons]
      simp [Nat.lt_succ]
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
l : List α
H0 : C []
H1 : (l : List α) → (a : α) → C l → C (l ++ [a])
head : α
tail : List α
h : reverse l = head :: tail
this : length tail < length l
⊢ C (reverse (head :: tail))

Next tactic:
let ih := reverseRecOn (reverse tail) H0 H1
/-- Induction principle from the right for lists: if a property holds for the empty list, and
for `l ++ [a]` if it holds for `l`, then it holds for all lists. The principle is given for
a `Sort`-valued predicate, i.e., it can also be used to construct data. -/
@[elab_as_elim]
def reverseRecOn {C : List α → Sort*} (l : List α) (H0 : C [])
    (H1 : ∀ (l : List α) (a : α), C l → C (l ++ [a])) : C l := by
  rw [← reverse_reverse l]
  match h:(reverse l) with
  | [] => exact H0
  | head :: tail =>
    have : tail.length < l.length := by
      rw [← length_reverse l, h, length_cons]
      simp [Nat.lt_succ]
    let ih := reverseRecOn (reverse tail) H0 H1
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
l : List α
H0 : C []
H1 : (l : List α) → (a : α) → C l → C (l ++ [a])
head : α
tail : List α
h : reverse l = head :: tail
this : length tail < length l
ih : C (reverse tail) := reverseRecOn (reverse tail) H0 H1
⊢ C (reverse (head :: tail))

Next tactic:
rw [reverse_cons]
/-- Induction principle from the right for lists: if a property holds for the empty list, and
for `l ++ [a]` if it holds for `l`, then it holds for all lists. The principle is given for
a `Sort`-valued predicate, i.e., it can also be used to construct data. -/
@[elab_as_elim]
def reverseRecOn {C : List α → Sort*} (l : List α) (H0 : C [])
    (H1 : ∀ (l : List α) (a : α), C l → C (l ++ [a])) : C l := by
  rw [← reverse_reverse l]
  match h:(reverse l) with
  | [] => exact H0
  | head :: tail =>
    have : tail.length < l.length := by
      rw [← length_reverse l, h, length_cons]
      simp [Nat.lt_succ]
    let ih := reverseRecOn (reverse tail) H0 H1
    rw [reverse_cons]
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
l : List α
H0 : C []
H1 : (l : List α) → (a : α) → C l → C (l ++ [a])
head : α
tail : List α
h : reverse l = head :: tail
this : length tail < length l
ih : C (reverse tail) := reverseRecOn (reverse tail) H0 H1
⊢ C (reverse tail ++ [head])

Next tactic:
exact H1 _ _ ih
/-- Bidirectional induction principle for lists: if a property holds for the empty list, the
singleton list, and `a :: (l ++ [b])` from `l`, then it holds for all lists. This can be used to
prove statements about palindromes. The principle is given for a `Sort`-valued predicate, i.e., it
can also be used to construct data. -/
def bidirectionalRec {C : List α → Sort*} (H0 : C []) (H1 : ∀ a : α, C [a])
    (Hn : ∀ (a : α) (l : List α) (b : α), C l → C (a :: (l ++ [b]))) : ∀ l, C l
  | [] => H0
  | [a] => H1 a
  | a :: b :: l => by
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
H0 : C []
H1 : (a : α) → C [a]
Hn : (a : α) → (l : List α) → (b : α) → C l → C (a :: (l ++ [b]))
a b : α
l : List α
⊢ C (a :: b :: l)

Next tactic:
let l' := dropLast (b :: l)
/-- Bidirectional induction principle for lists: if a property holds for the empty list, the
singleton list, and `a :: (l ++ [b])` from `l`, then it holds for all lists. This can be used to
prove statements about palindromes. The principle is given for a `Sort`-valued predicate, i.e., it
can also be used to construct data. -/
def bidirectionalRec {C : List α → Sort*} (H0 : C []) (H1 : ∀ a : α, C [a])
    (Hn : ∀ (a : α) (l : List α) (b : α), C l → C (a :: (l ++ [b]))) : ∀ l, C l
  | [] => H0
  | [a] => H1 a
  | a :: b :: l => by
    let l' := dropLast (b :: l)
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
H0 : C []
H1 : (a : α) → C [a]
Hn : (a : α) → (l : List α) → (b : α) → C l → C (a :: (l ++ [b]))
a b : α
l : List α
l' : List α := dropLast (b :: l)
⊢ C (a :: b :: l)

Next tactic:
let b' := getLast (b :: l) (cons_ne_nil _ _)
/-- Bidirectional induction principle for lists: if a property holds for the empty list, the
singleton list, and `a :: (l ++ [b])` from `l`, then it holds for all lists. This can be used to
prove statements about palindromes. The principle is given for a `Sort`-valued predicate, i.e., it
can also be used to construct data. -/
def bidirectionalRec {C : List α → Sort*} (H0 : C []) (H1 : ∀ a : α, C [a])
    (Hn : ∀ (a : α) (l : List α) (b : α), C l → C (a :: (l ++ [b]))) : ∀ l, C l
  | [] => H0
  | [a] => H1 a
  | a :: b :: l => by
    let l' := dropLast (b :: l)
    let b' := getLast (b :: l) (cons_ne_nil _ _)
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
H0 : C []
H1 : (a : α) → C [a]
Hn : (a : α) → (l : List α) → (b : α) → C l → C (a :: (l ++ [b]))
a b : α
l : List α
l' : List α := dropLast (b :: l)
b' : α := getLast (b :: l) (_ : b :: l ≠ [])
⊢ C (a :: b :: l)

Next tactic:
rw [← dropLast_append_getLast (cons_ne_nil b l)]
/-- Bidirectional induction principle for lists: if a property holds for the empty list, the
singleton list, and `a :: (l ++ [b])` from `l`, then it holds for all lists. This can be used to
prove statements about palindromes. The principle is given for a `Sort`-valued predicate, i.e., it
can also be used to construct data. -/
def bidirectionalRec {C : List α → Sort*} (H0 : C []) (H1 : ∀ a : α, C [a])
    (Hn : ∀ (a : α) (l : List α) (b : α), C l → C (a :: (l ++ [b]))) : ∀ l, C l
  | [] => H0
  | [a] => H1 a
  | a :: b :: l => by
    let l' := dropLast (b :: l)
    let b' := getLast (b :: l) (cons_ne_nil _ _)
    rw [← dropLast_append_getLast (cons_ne_nil b l)]
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
H0 : C []
H1 : (a : α) → C [a]
Hn : (a : α) → (l : List α) → (b : α) → C l → C (a :: (l ++ [b]))
a b : α
l : List α
l' : List α := dropLast (b :: l)
b' : α := getLast (b :: l) (_ : b :: l ≠ [])
⊢ C (a :: (dropLast (b :: l) ++ [getLast (b :: l) (_ : b :: l ≠ [])]))

Next tactic:
have : C l' := bidirectionalRec H0 H1 Hn l'
/-- Bidirectional induction principle for lists: if a property holds for the empty list, the
singleton list, and `a :: (l ++ [b])` from `l`, then it holds for all lists. This can be used to
prove statements about palindromes. The principle is given for a `Sort`-valued predicate, i.e., it
can also be used to construct data. -/
def bidirectionalRec {C : List α → Sort*} (H0 : C []) (H1 : ∀ a : α, C [a])
    (Hn : ∀ (a : α) (l : List α) (b : α), C l → C (a :: (l ++ [b]))) : ∀ l, C l
  | [] => H0
  | [a] => H1 a
  | a :: b :: l => by
    let l' := dropLast (b :: l)
    let b' := getLast (b :: l) (cons_ne_nil _ _)
    rw [← dropLast_append_getLast (cons_ne_nil b l)]
    have : C l' := bidirectionalRec H0 H1 Hn l'
    

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
C : List α → Sort u_2
H0 : C []
H1 : (a : α) → C [a]
Hn : (a : α) → (l : List α) → (b : α) → C l → C (a :: (l ++ [b]))
a b : α
l : List α
l' : List α := dropLast (b :: l)
b' : α := getLast (b :: l) (_ : b :: l ≠ [])
this : C l'
⊢ C (a :: (dropLast (b :: l) ++ [getLast (b :: l) (_ : b :: l ≠ [])]))

Next tactic:
exact Hn a l' b' this
@[simp] lemma sublist_singleton {l : List α} {a : α} : l <+ [a] ↔ l = [] ∨ l = [a] := by
  

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

Next tactic:
constructor
@[simp] lemma sublist_singleton {l : List α} {a : α} : l <+ [a] ↔ l = [] ∨ l = [a] := by
  constructor <;> 

Proof state:
case mp
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
a : α
⊢ l <+ [a] → l = [] ∨ l = [a]

Next tactic:
rintro (_ | _)
@[simp] lemma sublist_singleton {l : List α} {a : α} : l <+ [a] ↔ l = [] ∨ l = [a] := by
  constructor <;> 

Proof state:
case mpr
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
a : α
⊢ l = [] ∨ l = [a] → l <+ [a]

Next tactic:
rintro (_ | _)
@[simp] lemma sublist_singleton {l : List α} {a : α} : l <+ [a] ↔ l = [] ∨ l = [a] := by
  constructor <;> rintro (_ | _) <;> 

Proof state:
case mp.cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
a : α
a✝ : l <+ []
⊢ l = [] ∨ l = [a]

Next tactic:
aesop
@[simp] lemma sublist_singleton {l : List α} {a : α} : l <+ [a] ↔ l = [] ∨ l = [a] := by
  constructor <;> rintro (_ | _) <;> 

Proof state:
case mp.cons₂
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
l₁✝ : List α
a✝ : l₁✝ <+ []
⊢ a :: l₁✝ = [] ∨ a :: l₁✝ = [a]

Next tactic:
aesop
@[simp] lemma sublist_singleton {l : List α} {a : α} : l <+ [a] ↔ l = [] ∨ l = [a] := by
  constructor <;> rintro (_ | _) <;> 

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

Next tactic:
aesop
@[simp] lemma sublist_singleton {l : List α} {a : α} : l <+ [a] ↔ l = [] ∨ l = [a] := by
  constructor <;> rintro (_ | _) <;> 

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

Next tactic:
aesop
theorem sublist_replicate_iff {l : List α} {a : α} {n : ℕ} :
    l <+ replicate n a ↔ ∃ k ≤ n, l = replicate k a :=
  ⟨fun h =>
    ⟨l.length, h.length_le.trans_eq (length_replicate _ _),
      eq_replicate_length.mpr fun b hb => eq_of_mem_replicate (h.subset hb)⟩,
    by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ l : List α
a : α
n : ℕ
⊢ (∃ k, k ≤ n ∧ l = replicate k a) → l <+ replicate n a

Next tactic:
rintro ⟨k, h, rfl⟩
theorem sublist_replicate_iff {l : List α} {a : α} {n : ℕ} :
    l <+ replicate n a ↔ ∃ k ≤ n, l = replicate k a :=
  ⟨fun h =>
    ⟨l.length, h.length_le.trans_eq (length_replicate _ _),
      eq_replicate_length.mpr fun b hb => eq_of_mem_replicate (h.subset hb)⟩,
    by rintro ⟨k, h, rfl⟩; 

Proof state:
case intro.intro
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
a : α
n k : ℕ
h : k ≤ n
⊢ replicate k a <+ replicate n a

Next tactic:
exact (replicate_sublist_replicate _).mpr h
@[simp]
theorem indexOf_cons_self (a : α) (l : List α) : indexOf a (a :: l) = 0 := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a : α
l : List α
⊢ indexOf a (a :: l) = 0

Next tactic:
rw [indexOf, findIdx_cons, beq_self_eq_true, cond]
theorem indexOf_cons_eq {a b : α} (l : List α) : b = a → indexOf a (b :: l) = 0
  | e => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
x✝ : b = a
e : b = a := x✝
⊢ indexOf a (b :: l) = 0

Next tactic:
rw [← e]
theorem indexOf_cons_eq {a b : α} (l : List α) : b = a → indexOf a (b :: l) = 0
  | e => by rw [← e]; 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
x✝ : b = a
e : b = a := x✝
⊢ indexOf b (b :: l) = 0

Next tactic:
exact indexOf_cons_self b l
@[simp]
theorem indexOf_cons_ne {a b : α} (l : List α) : b ≠ a → indexOf a (b :: l) = succ (indexOf a l)
  | h => by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
x✝ : b ≠ a
h : b ≠ a := x✝
⊢ indexOf a (b :: l) = succ (indexOf a l)

Next tactic:
simp only [indexOf, findIdx_cons, Bool.cond_eq_ite, beq_iff_eq, h, ite_false]
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a : α
l : List α
⊢ indexOf a l = length l ↔ ¬a ∈ l

Next tactic:
induction' l with b l ih
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  induction' l with b l ih
  · 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a : α
⊢ indexOf a [] = length [] ↔ ¬a ∈ []

Next tactic:
exact iff_of_true rfl (not_mem_nil _)
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  induction' l with b l ih
  · exact iff_of_true rfl (not_mem_nil _)
  

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l = length l ↔ ¬a ∈ l
⊢ indexOf a (b :: l) = length (b :: l) ↔ ¬a ∈ b :: l

Next tactic:
simp only [length, mem_cons, indexOf_cons, eq_comm]
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  induction' l with b l ih
  · exact iff_of_true rfl (not_mem_nil _)
  simp only [length, mem_cons, indexOf_cons, eq_comm]
  

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l = length l ↔ ¬a ∈ l
⊢ (bif b == a then 0 else indexOf a l + 1) = length l + 1 ↔ ¬(a = b ∨ a ∈ l)

Next tactic:
rw [cond_eq_if]
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  induction' l with b l ih
  · exact iff_of_true rfl (not_mem_nil _)
  simp only [length, mem_cons, indexOf_cons, eq_comm]
  rw [cond_eq_if]
  

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l = length l ↔ ¬a ∈ l
⊢ (if (b == a) = true then 0 else indexOf a l + 1) = length l + 1 ↔ ¬(a = b ∨ a ∈ l)

Next tactic:
split_ifs with h
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  induction' l with b l ih
  · exact iff_of_true rfl (not_mem_nil _)
  simp only [length, mem_cons, indexOf_cons, eq_comm]
  rw [cond_eq_if]
  split_ifs with h <;> 

Proof state:
case pos
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l = length l ↔ ¬a ∈ l
h : (b == a) = true
⊢ 0 = length l + 1 ↔ ¬(a = b ∨ a ∈ l)

Next tactic:
simp at h
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  induction' l with b l ih
  · exact iff_of_true rfl (not_mem_nil _)
  simp only [length, mem_cons, indexOf_cons, eq_comm]
  rw [cond_eq_if]
  split_ifs with h <;> 

Proof state:
case neg
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l = length l ↔ ¬a ∈ l
h : ¬(b == a) = true
⊢ indexOf a l + 1 = length l + 1 ↔ ¬(a = b ∨ a ∈ l)

Next tactic:
simp at h
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  induction' l with b l ih
  · exact iff_of_true rfl (not_mem_nil _)
  simp only [length, mem_cons, indexOf_cons, eq_comm]
  rw [cond_eq_if]
  split_ifs with h <;> simp at h
  · 

Proof state:
case pos
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l = length l ↔ ¬a ∈ l
h : b = a
⊢ 0 = length l + 1 ↔ ¬(a = b ∨ a ∈ l)

Next tactic:
exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h.symm
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  induction' l with b l ih
  · exact iff_of_true rfl (not_mem_nil _)
  simp only [length, mem_cons, indexOf_cons, eq_comm]
  rw [cond_eq_if]
  split_ifs with h <;> simp at h
  · exact iff_of_false (by 

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l = length l ↔ ¬a ∈ l
h : b = a
⊢ ¬0 = length l + 1

Next tactic:
rintro ⟨⟩
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  induction' l with b l ih
  · exact iff_of_true rfl (not_mem_nil _)
  simp only [length, mem_cons, indexOf_cons, eq_comm]
  rw [cond_eq_if]
  split_ifs with h <;> simp at h
  · exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h.symm
  · 

Proof state:
case neg
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l = length l ↔ ¬a ∈ l
h : ¬b = a
⊢ indexOf a l + 1 = length l + 1 ↔ ¬(a = b ∨ a ∈ l)

Next tactic:
simp only [Ne.symm h, false_or_iff]
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  induction' l with b l ih
  · exact iff_of_true rfl (not_mem_nil _)
  simp only [length, mem_cons, indexOf_cons, eq_comm]
  rw [cond_eq_if]
  split_ifs with h <;> simp at h
  · exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h.symm
  · simp only [Ne.symm h, false_or_iff]
    

Proof state:
case neg
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l = length l ↔ ¬a ∈ l
h : ¬b = a
⊢ indexOf a l + 1 = length l + 1 ↔ ¬a ∈ l

Next tactic:
rw [← ih]
theorem indexOf_eq_length {a : α} {l : List α} : indexOf a l = length l ↔ a ∉ l := by
  induction' l with b l ih
  · exact iff_of_true rfl (not_mem_nil _)
  simp only [length, mem_cons, indexOf_cons, eq_comm]
  rw [cond_eq_if]
  split_ifs with h <;> simp at h
  · exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h.symm
  · simp only [Ne.symm h, false_or_iff]
    rw [← ih]
    

Proof state:
case neg
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l = length l ↔ ¬a ∈ l
h : ¬b = a
⊢ indexOf a l + 1 = length l + 1 ↔ indexOf a l = length l

Next tactic:
exact succ_inj'
theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a : α
l : List α
⊢ indexOf a l ≤ length l

Next tactic:
induction' l with b l ih
theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by
  induction' l with b l ih; · 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a : α
⊢ indexOf a [] ≤ length []

Next tactic:
rfl
theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by
  induction' l with b l ih; · rfl
  

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l ≤ length l
⊢ indexOf a (b :: l) ≤ length (b :: l)

Next tactic:
simp only [length, indexOf_cons, cond_eq_if, beq_iff_eq]
theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by
  induction' l with b l ih; · rfl
  simp only [length, indexOf_cons, cond_eq_if, beq_iff_eq]
  

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l ≤ length l
⊢ (if b = a then 0 else indexOf a l + 1) ≤ length l + 1

Next tactic:
by_cases h : b = a
theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by
  induction' l with b l ih; · rfl
  simp only [length, indexOf_cons, cond_eq_if, beq_iff_eq]
  by_cases h : b = a
  · 

Proof state:
case pos
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l ≤ length l
h : b = a
⊢ (if b = a then 0 else indexOf a l + 1) ≤ length l + 1

Next tactic:
rw [if_pos h]
theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by
  induction' l with b l ih; · rfl
  simp only [length, indexOf_cons, cond_eq_if, beq_iff_eq]
  by_cases h : b = a
  · rw [if_pos h]; 

Proof state:
case pos
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l ≤ length l
h : b = a
⊢ 0 ≤ length l + 1

Next tactic:
exact Nat.zero_le _
theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by
  induction' l with b l ih; · rfl
  simp only [length, indexOf_cons, cond_eq_if, beq_iff_eq]
  by_cases h : b = a
  · rw [if_pos h]; exact Nat.zero_le _
  · 

Proof state:
case neg
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l ≤ length l
h : ¬b = a
⊢ (if b = a then 0 else indexOf a l + 1) ≤ length l + 1

Next tactic:
rw [if_neg h]
theorem indexOf_le_length {a : α} {l : List α} : indexOf a l ≤ length l := by
  induction' l with b l ih; · rfl
  simp only [length, indexOf_cons, cond_eq_if, beq_iff_eq]
  by_cases h : b = a
  · rw [if_pos h]; exact Nat.zero_le _
  · rw [if_neg h]; 

Proof state:
case neg
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a b : α
l : List α
ih : indexOf a l ≤ length l
h : ¬b = a
⊢ indexOf a l + 1 ≤ length l + 1

Next tactic:
exact succ_le_succ ih
theorem indexOf_append_of_mem {a : α} (h : a ∈ l₁) : indexOf a (l₁ ++ l₂) = indexOf a l₁ := by
  

Proof state:
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a : α
h : a ∈ l₁
⊢ indexOf a (l₁ ++ l₂) = indexOf a l₁

Next tactic:
induction' l₁ with d₁ t₁ ih
theorem indexOf_append_of_mem {a : α} (h : a ∈ l₁) : indexOf a (l₁ ++ l₂) = indexOf a l₁ := by
  induction' l₁ with d₁ t₁ ih
  · 

Proof state:
case nil
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a : α
h : a ∈ []
⊢ indexOf a ([] ++ l₂) = indexOf a []

Next tactic:
exfalso
theorem indexOf_append_of_mem {a : α} (h : a ∈ l₁) : indexOf a (l₁ ++ l₂) = indexOf a l₁ := by
  induction' l₁ with d₁ t₁ ih
  · exfalso
    

Proof state:
case nil.h
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a : α
h : a ∈ []
⊢ False

Next tactic:
exact not_mem_nil a h
theorem indexOf_append_of_mem {a : α} (h : a ∈ l₁) : indexOf a (l₁ ++ l₂) = indexOf a l₁ := by
  induction' l₁ with d₁ t₁ ih
  · exfalso
    exact not_mem_nil a h
  

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a d₁ : α
t₁ : List α
ih : a ∈ t₁ → indexOf a (t₁ ++ l₂) = indexOf a t₁
h : a ∈ d₁ :: t₁
⊢ indexOf a (d₁ :: t₁ ++ l₂) = indexOf a (d₁ :: t₁)

Next tactic:
rw [List.cons_append]
theorem indexOf_append_of_mem {a : α} (h : a ∈ l₁) : indexOf a (l₁ ++ l₂) = indexOf a l₁ := by
  induction' l₁ with d₁ t₁ ih
  · exfalso
    exact not_mem_nil a h
  rw [List.cons_append]
  

Proof state:
case cons
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a d₁ : α
t₁ : List α
ih : a ∈ t₁ → indexOf a (t₁ ++ l₂) = indexOf a t₁
h : a ∈ d₁ :: t₁
⊢ indexOf a (d₁ :: (t₁ ++ l₂)) = indexOf a (d₁ :: t₁)

Next tactic:
by_cases hh : d₁ = a
theorem indexOf_append_of_mem {a : α} (h : a ∈ l₁) : indexOf a (l₁ ++ l₂) = indexOf a l₁ := by
  induction' l₁ with d₁ t₁ ih
  · exfalso
    exact not_mem_nil a h
  rw [List.cons_append]
  by_cases hh : d₁ = a
  · 

Proof state:
case pos
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a d₁ : α
t₁ : List α
ih : a ∈ t₁ → indexOf a (t₁ ++ l₂) = indexOf a t₁
h : a ∈ d₁ :: t₁
hh : d₁ = a
⊢ indexOf a (d₁ :: (t₁ ++ l₂)) = indexOf a (d₁ :: t₁)

Next tactic:
iterate 2 rw [indexOf_cons_eq _ hh]
theorem indexOf_append_of_mem {a : α} (h : a ∈ l₁) : indexOf a (l₁ ++ l₂) = indexOf a l₁ := by
  induction' l₁ with d₁ t₁ ih
  · exfalso
    exact not_mem_nil a h
  rw [List.cons_append]
  by_cases hh : d₁ = a
  · iterate 2 

Proof state:
case pos
ι : Type u_1
α : Type u
β : Type v
γ : Type w
l₁ l₂ : List α
inst✝ : DecidableEq α
a d₁ : α
t₁ : List α
ih : a ∈ t₁ → indexOf a (t₁ ++ l₂) = indexOf a t₁
h : a ∈ d₁ :: t₁
hh : d₁ = a
⊢ indexOf a (d₁ :: (t₁ ++ l₂)) = indexOf a (d₁ :: t₁)

Next tactic:
rw [indexOf_cons_eq _ hh]