l3lab/ntp-mathlib huggingface dataset:
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      

Proof state:
case nil.cons.false
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
a : Γ'
Sk : List Γ'
e :
  (bif false then ([], some a, Sk) else (a :: (splitAtPred p Sk).1, (splitAtPred p Sk).2.1, (splitAtPred p Sk).2.2)) =
    ([], o, L₂)
⊢ ReflTransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    (bif false then { l := some q, var := some a, stk := update S k Sk }
    else { l := some (Λ'.clear p k q), var := some a, stk := update S k Sk })
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      

Proof state:
case nil.cons.true
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
a : Γ'
Sk : List Γ'
e :
  (bif true then ([], some a, Sk) else (a :: (splitAtPred p Sk).1, (splitAtPred p Sk).2.1, (splitAtPred p Sk).2.2)) =
    ([], o, L₂)
⊢ ReflTransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    (bif true then { l := some q, var := some a, stk := update S k Sk }
    else { l := some (Λ'.clear p k q), var := some a, stk := update S k Sk })
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · 

Proof state:
case nil.cons.true
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
a : Γ'
Sk : List Γ'
e : some a = o ∧ Sk = L₂
⊢ ReflTransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    { l := some q, var := some a, stk := update S k Sk } { l := some q, var := o, stk := update S k L₂ }

Next tactic:
rcases e with ⟨e₁, e₂⟩
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · rcases e with ⟨e₁, e₂⟩
      

Proof state:
case nil.cons.true.intro
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
a : Γ'
Sk : List Γ'
e₁ : some a = o
e₂ : Sk = L₂
⊢ ReflTransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    { l := some q, var := some a, stk := update S k Sk } { l := some q, var := o, stk := update S k L₂ }

Next tactic:
rw [e₁, e₂]
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · rcases e with ⟨e₁, e₂⟩
      rw [e₁, e₂]
  · 

Proof state:
case cons
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
a : Γ'
L₁ : List Γ'
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k) = (L₁, o, L₂) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
        { l := some q, var := o, stk := update S k L₂ }
s : Option Γ'
S : K' → List Γ'
e : splitAtPred p (S k) = (a :: L₁, o, L₂)
⊢ Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
refine' TransGen.head rfl _
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · rcases e with ⟨e₁, e₂⟩
      rw [e₁, e₂]
  · refine' TransGen.head rfl _
    

Proof state:
case cons
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
a : Γ'
L₁ : List Γ'
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k) = (L₁, o, L₂) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
        { l := some q, var := o, stk := update S k L₂ }
s : Option Γ'
S : K' → List Γ'
e : splitAtPred p (S k) = (a :: L₁, o, L₂)
⊢ TransGen (fun a b => b ∈ TM2.step tr a) (TM2.stepAux (tr (Λ'.clear p k q)) s S)
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · rcases e with ⟨e₁, e₂⟩
      rw [e₁, e₂]
  · refine' TransGen.head rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    

Proof state:
case cons
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
a : Γ'
L₁ : List Γ'
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k) = (L₁, o, L₂) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
        { l := some q, var := o, stk := update S k L₂ }
s : Option Γ'
S : K' → List Γ'
e : splitAtPred p (S k) = (a :: L₁, o, L₂)
⊢ TransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    (bif
        match List.head? (S k), true, p with
        | some x, x_1, f => f x
        | none, y, x => y then
      { l := some q, var := List.head? (S k), stk := update S k (List.tail (S k)) }
    else { l := some (Λ'.clear p k q), var := List.head? (S k), stk := update S k (List.tail (S k)) })
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
cases' e₁ : S k with a' Sk
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · rcases e with ⟨e₁, e₂⟩
      rw [e₁, e₂]
  · refine' TransGen.head rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    cases' e₁ : S k with a' Sk <;> 

Proof state:
case cons.nil
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
a : Γ'
L₁ : List Γ'
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k) = (L₁, o, L₂) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
        { l := some q, var := o, stk := update S k L₂ }
s : Option Γ'
S : K' → List Γ'
e : splitAtPred p (S k) = (a :: L₁, o, L₂)
e₁ : S k = []
⊢ TransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    (bif
        match List.head? [], true, p with
        | some x, x_1, f => f x
        | none, y, x => y then
      { l := some q, var := List.head? [], stk := update S k (List.tail []) }
    else { l := some (Λ'.clear p k q), var := List.head? [], stk := update S k (List.tail []) })
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
rw [e₁, splitAtPred] at e
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · rcases e with ⟨e₁, e₂⟩
      rw [e₁, e₂]
  · refine' TransGen.head rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    cases' e₁ : S k with a' Sk <;> 

Proof state:
case cons.cons
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
a : Γ'
L₁ : List Γ'
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k) = (L₁, o, L₂) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
        { l := some q, var := o, stk := update S k L₂ }
s : Option Γ'
S : K' → List Γ'
e : splitAtPred p (S k) = (a :: L₁, o, L₂)
a' : Γ'
Sk : List Γ'
e₁ : S k = a' :: Sk
⊢ TransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    (bif
        match List.head? (a' :: Sk), true, p with
        | some x, x_1, f => f x
        | none, y, x => y then
      { l := some q, var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) }
    else { l := some (Λ'.clear p k q), var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) })
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
rw [e₁, splitAtPred] at e
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · rcases e with ⟨e₁, e₂⟩
      rw [e₁, e₂]
  · refine' TransGen.head rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    cases' e₁ : S k with a' Sk <;> rw [e₁, splitAtPred] at e
    · 

Proof state:
case cons.nil
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
a : Γ'
L₁ : List Γ'
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k) = (L₁, o, L₂) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
        { l := some q, var := o, stk := update S k L₂ }
s : Option Γ'
S : K' → List Γ'
e : ([], none, []) = (a :: L₁, o, L₂)
e₁ : S k = []
⊢ TransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    (bif
        match List.head? [], true, p with
        | some x, x_1, f => f x
        | none, y, x => y then
      { l := some q, var := List.head? [], stk := update S k (List.tail []) }
    else { l := some (Λ'.clear p k q), var := List.head? [], stk := update S k (List.tail []) })
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
cases e
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · rcases e with ⟨e₁, e₂⟩
      rw [e₁, e₂]
  · refine' TransGen.head rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    cases' e₁ : S k with a' Sk <;> rw [e₁, splitAtPred] at e
    · cases e
    

Proof state:
case cons.cons
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
a : Γ'
L₁ : List Γ'
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k) = (L₁, o, L₂) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
        { l := some q, var := o, stk := update S k L₂ }
s : Option Γ'
S : K' → List Γ'
a' : Γ'
Sk : List Γ'
e :
  (bif p a' then ([], some a', Sk)
    else
      match splitAtPred p Sk with
      | (l₁, o, l₂) => (a' :: l₁, o, l₂)) =
    (a :: L₁, o, L₂)
e₁ : S k = a' :: Sk
⊢ TransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    (bif
        match List.head? (a' :: Sk), true, p with
        | some x, x_1, f => f x
        | none, y, x => y then
      { l := some q, var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) }
    else { l := some (Λ'.clear p k q), var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) })
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
cases e₂ : p a'
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · rcases e with ⟨e₁, e₂⟩
      rw [e₁, e₂]
  · refine' TransGen.head rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    cases' e₁ : S k with a' Sk <;> rw [e₁, splitAtPred] at e
    · cases e
    cases e₂ : p a' <;> 

Proof state:
case cons.cons.false
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
a : Γ'
L₁ : List Γ'
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k) = (L₁, o, L₂) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
        { l := some q, var := o, stk := update S k L₂ }
s : Option Γ'
S : K' → List Γ'
a' : Γ'
Sk : List Γ'
e :
  (bif p a' then ([], some a', Sk)
    else
      match splitAtPred p Sk with
      | (l₁, o, l₂) => (a' :: l₁, o, l₂)) =
    (a :: L₁, o, L₂)
e₁ : S k = a' :: Sk
e₂ : p a' = false
⊢ TransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    (bif
        match List.head? (a' :: Sk), true, p with
        | some x, x_1, f => f x
        | none, y, x => y then
      { l := some q, var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) }
    else { l := some (Λ'.clear p k q), var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) })
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
simp only [e₂, cond] at e
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · rcases e with ⟨e₁, e₂⟩
      rw [e₁, e₂]
  · refine' TransGen.head rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    cases' e₁ : S k with a' Sk <;> rw [e₁, splitAtPred] at e
    · cases e
    cases e₂ : p a' <;> 

Proof state:
case cons.cons.true
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
a : Γ'
L₁ : List Γ'
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k) = (L₁, o, L₂) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
        { l := some q, var := o, stk := update S k L₂ }
s : Option Γ'
S : K' → List Γ'
a' : Γ'
Sk : List Γ'
e :
  (bif p a' then ([], some a', Sk)
    else
      match splitAtPred p Sk with
      | (l₁, o, l₂) => (a' :: l₁, o, l₂)) =
    (a :: L₁, o, L₂)
e₁ : S k = a' :: Sk
e₂ : p a' = true
⊢ TransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    (bif
        match List.head? (a' :: Sk), true, p with
        | some x, x_1, f => f x
        | none, y, x => y then
      { l := some q, var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) }
    else { l := some (Λ'.clear p k q), var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) })
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
simp only [e₂, cond] at e
theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p (S k) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.clear p k q), s, S⟩ ⟨some q, o, update S k L₂⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    revert e; cases' S k with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · rcases e with ⟨e₁, e₂⟩
      rw [e₁, e₂]
  · refine' TransGen.head rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim]
    cases' e₁ : S k with a' Sk <;> rw [e₁, splitAtPred] at e
    · cases e
    cases e₂ : p a' <;> simp only [e₂, cond] at e
    

Proof state:
case cons.cons.false
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
a : Γ'
L₁ : List Γ'
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k) = (L₁, o, L₂) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
        { l := some q, var := o, stk := update S k L₂ }
s : Option Γ'
S : K' → List Γ'
a' : Γ'
Sk : List Γ'
e₁ : S k = a' :: Sk
e₂ : p a' = false
e : (a' :: (splitAtPred p Sk).1, (splitAtPred p Sk).2.1, (splitAtPred p Sk).2.2) = (a :: L₁, o, L₂)
⊢ TransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    (bif
        match List.head? (a' :: Sk), true, p with
        | some x, x_1, f => f x
        | none, y, x => y then
      { l := some q, var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) }
    else { l := some (Λ'.clear p k q), var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) })
    { l := some q, var := o, stk := update S k L₂ }
case cons.cons.true
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
a : Γ'
L₁ : List Γ'
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k) = (L₁, o, L₂) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.clear p k q), var := s, stk := S }
        { l := some q, var := o, stk := update S k L₂ }
s : Option Γ'
S : K' → List Γ'
a' : Γ'
Sk : List Γ'
e₁ : S k = a' :: Sk
e₂ : p a' = true
e : ([], some a', Sk) = (a :: L₁, o, L₂)
⊢ TransGen
    (fun a b =>
      (match a with
        | { l := none, var := var, stk := stk } => none
        | { l := some l, var := v, stk := S } => some (TM2.stepAux (tr l) v S)) =
        some b)
    (bif
        match List.head? (a' :: Sk), true, p with
        | some x, x_1, f => f x
        | none, y, x => y then
      { l := some q, var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) }
    else { l := some (Λ'.clear p k q), var := List.head? (a' :: Sk), stk := update S k (List.tail (a' :: Sk)) })
    { l := some q, var := o, stk := update S k L₂ }

Next tactic:
swap