l3lab/ntp-mathlib huggingface dataset:
theorem move₂_ok {p k₁ k₂ q s L₁ o L₂} {S : K' → List Γ'} (h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂)
    (h₂ : S rev = []) (e : splitAtPred p (S k₁) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (move₂ p k₁ k₂ q), s, S⟩
      ⟨some q, none, update (update S k₁ (o.elim id List.cons L₂)) k₂ (L₁ ++ S k₂)⟩ := by
  refine' (move_ok h₁.1 e).trans (TransGen.head rfl _)
  simp only [TM2.step, Option.mem_def, TM2.stepAux, id_eq, ne_eq, Option.elim]
  cases o <;> simp only [Option.elim, id.def]
  · simp only [TM2.stepAux, Option.isSome, cond_false]
    convert move_ok h₁.2.1.symm (splitAtPred_false _) using 2
    simp only [Function.update_comm h₁.1, Function.update_idem]
    rw [show update S rev [] = S by rw [← h₂, Function.update_eq_self]]
    simp only [Function.update_noteq h₁.2.2.symm, Function.update_noteq h₁.2.1,
      Function.update_noteq h₁.1.symm, List.reverseAux_eq, h₂, Function.update_same,
      List.append_nil, List.reverse_reverse]
  · simp only [TM2.stepAux, Option.isSome, cond_true]
    

Proof state:
case some
p : Γ' → Bool
k₁ k₂ : K'
q : Λ'
s : Option Γ'
L₁ L₂ : List Γ'
S : K' → List Γ'
h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂
h₂ : S rev = []
val✝ : Γ'
e : splitAtPred p (S k₁) = (L₁, some val✝, 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)
    { l := some (Λ'.move (fun x => false) rev k₂ q), var := some val✝,
      stk :=
        update (update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev))) k₁
          (Option.iget (some val✝) :: update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev)) k₁) }
    { l := some q, var := none, stk := update (update S k₁ (val✝ :: L₂)) k₂ (L₁ ++ S k₂) }

Next tactic:
convert move_ok h₁.2.1.symm (splitAtPred_false _) using 2
theorem move₂_ok {p k₁ k₂ q s L₁ o L₂} {S : K' → List Γ'} (h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂)
    (h₂ : S rev = []) (e : splitAtPred p (S k₁) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (move₂ p k₁ k₂ q), s, S⟩
      ⟨some q, none, update (update S k₁ (o.elim id List.cons L₂)) k₂ (L₁ ++ S k₂)⟩ := by
  refine' (move_ok h₁.1 e).trans (TransGen.head rfl _)
  simp only [TM2.step, Option.mem_def, TM2.stepAux, id_eq, ne_eq, Option.elim]
  cases o <;> simp only [Option.elim, id.def]
  · simp only [TM2.stepAux, Option.isSome, cond_false]
    convert move_ok h₁.2.1.symm (splitAtPred_false _) using 2
    simp only [Function.update_comm h₁.1, Function.update_idem]
    rw [show update S rev [] = S by rw [← h₂, Function.update_eq_self]]
    simp only [Function.update_noteq h₁.2.2.symm, Function.update_noteq h₁.2.1,
      Function.update_noteq h₁.1.symm, List.reverseAux_eq, h₂, Function.update_same,
      List.append_nil, List.reverse_reverse]
  · simp only [TM2.stepAux, Option.isSome, cond_true]
    convert move_ok h₁.2.1.symm (splitAtPred_false _) using 2
    

Proof state:
case h.e'_2.h.e'_7
p : Γ' → Bool
k₁ k₂ : K'
q : Λ'
s : Option Γ'
L₁ L₂ : List Γ'
S : K' → List Γ'
h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂
h₂ : S rev = []
val✝ : Γ'
e : splitAtPred p (S k₁) = (L₁, some val✝, L₂)
⊢ update (update S k₁ (val✝ :: L₂)) k₂ (L₁ ++ S k₂) =
    update
      (update
        (update (update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev))) k₁
          (Option.iget (some val✝) :: update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev)) k₁))
        rev [])
      k₂
      (List.reverseAux
        (update (update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev))) k₁
          (Option.iget (some val✝) :: update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev)) k₁) rev)
        (update (update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev))) k₁
          (Option.iget (some val✝) :: update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev)) k₁) k₂))

Next tactic:
simp only [h₂, Function.update_comm h₁.1, List.reverseAux_eq, Function.update_same,
      List.append_nil, Function.update_idem]
theorem move₂_ok {p k₁ k₂ q s L₁ o L₂} {S : K' → List Γ'} (h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂)
    (h₂ : S rev = []) (e : splitAtPred p (S k₁) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (move₂ p k₁ k₂ q), s, S⟩
      ⟨some q, none, update (update S k₁ (o.elim id List.cons L₂)) k₂ (L₁ ++ S k₂)⟩ := by
  refine' (move_ok h₁.1 e).trans (TransGen.head rfl _)
  simp only [TM2.step, Option.mem_def, TM2.stepAux, id_eq, ne_eq, Option.elim]
  cases o <;> simp only [Option.elim, id.def]
  · simp only [TM2.stepAux, Option.isSome, cond_false]
    convert move_ok h₁.2.1.symm (splitAtPred_false _) using 2
    simp only [Function.update_comm h₁.1, Function.update_idem]
    rw [show update S rev [] = S by rw [← h₂, Function.update_eq_self]]
    simp only [Function.update_noteq h₁.2.2.symm, Function.update_noteq h₁.2.1,
      Function.update_noteq h₁.1.symm, List.reverseAux_eq, h₂, Function.update_same,
      List.append_nil, List.reverse_reverse]
  · simp only [TM2.stepAux, Option.isSome, cond_true]
    convert move_ok h₁.2.1.symm (splitAtPred_false _) using 2
    simp only [h₂, Function.update_comm h₁.1, List.reverseAux_eq, Function.update_same,
      List.append_nil, Function.update_idem]
    

Proof state:
case h.e'_2.h.e'_7
p : Γ' → Bool
k₁ k₂ : K'
q : Λ'
s : Option Γ'
L₁ L₂ : List Γ'
S : K' → List Γ'
h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂
h₂ : S rev = []
val✝ : Γ'
e : splitAtPred p (S k₁) = (L₁, some val✝, L₂)
⊢ update (update S k₁ (val✝ :: L₂)) k₂ (L₁ ++ S k₂) =
    update (update (update S rev []) k₁ (Option.iget (some val✝) :: L₂)) k₂
      (List.reverse (update (update S rev (List.reverse L₁)) k₁ (Option.iget (some val✝) :: L₂) rev) ++
        update (update S rev (List.reverse L₁)) k₁ (Option.iget (some val✝) :: L₂) k₂)

Next tactic:
rw [show update S rev [] = S by rw [← h₂, Function.update_eq_self]]
theorem move₂_ok {p k₁ k₂ q s L₁ o L₂} {S : K' → List Γ'} (h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂)
    (h₂ : S rev = []) (e : splitAtPred p (S k₁) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (move₂ p k₁ k₂ q), s, S⟩
      ⟨some q, none, update (update S k₁ (o.elim id List.cons L₂)) k₂ (L₁ ++ S k₂)⟩ := by
  refine' (move_ok h₁.1 e).trans (TransGen.head rfl _)
  simp only [TM2.step, Option.mem_def, TM2.stepAux, id_eq, ne_eq, Option.elim]
  cases o <;> simp only [Option.elim, id.def]
  · simp only [TM2.stepAux, Option.isSome, cond_false]
    convert move_ok h₁.2.1.symm (splitAtPred_false _) using 2
    simp only [Function.update_comm h₁.1, Function.update_idem]
    rw [show update S rev [] = S by rw [← h₂, Function.update_eq_self]]
    simp only [Function.update_noteq h₁.2.2.symm, Function.update_noteq h₁.2.1,
      Function.update_noteq h₁.1.symm, List.reverseAux_eq, h₂, Function.update_same,
      List.append_nil, List.reverse_reverse]
  · simp only [TM2.stepAux, Option.isSome, cond_true]
    convert move_ok h₁.2.1.symm (splitAtPred_false _) using 2
    simp only [h₂, Function.update_comm h₁.1, List.reverseAux_eq, Function.update_same,
      List.append_nil, Function.update_idem]
    rw [show update S rev [] = S by 

Proof state:
p : Γ' → Bool
k₁ k₂ : K'
q : Λ'
s : Option Γ'
L₁ L₂ : List Γ'
S : K' → List Γ'
h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂
h₂ : S rev = []
val✝ : Γ'
e : splitAtPred p (S k₁) = (L₁, some val✝, L₂)
⊢ update S rev [] = S

Next tactic:
rw [← h₂, Function.update_eq_self]
theorem move₂_ok {p k₁ k₂ q s L₁ o L₂} {S : K' → List Γ'} (h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂)
    (h₂ : S rev = []) (e : splitAtPred p (S k₁) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (move₂ p k₁ k₂ q), s, S⟩
      ⟨some q, none, update (update S k₁ (o.elim id List.cons L₂)) k₂ (L₁ ++ S k₂)⟩ := by
  refine' (move_ok h₁.1 e).trans (TransGen.head rfl _)
  simp only [TM2.step, Option.mem_def, TM2.stepAux, id_eq, ne_eq, Option.elim]
  cases o <;> simp only [Option.elim, id.def]
  · simp only [TM2.stepAux, Option.isSome, cond_false]
    convert move_ok h₁.2.1.symm (splitAtPred_false _) using 2
    simp only [Function.update_comm h₁.1, Function.update_idem]
    rw [show update S rev [] = S by rw [← h₂, Function.update_eq_self]]
    simp only [Function.update_noteq h₁.2.2.symm, Function.update_noteq h₁.2.1,
      Function.update_noteq h₁.1.symm, List.reverseAux_eq, h₂, Function.update_same,
      List.append_nil, List.reverse_reverse]
  · simp only [TM2.stepAux, Option.isSome, cond_true]
    convert move_ok h₁.2.1.symm (splitAtPred_false _) using 2
    simp only [h₂, Function.update_comm h₁.1, List.reverseAux_eq, Function.update_same,
      List.append_nil, Function.update_idem]
    rw [show update S rev [] = S by rw [← h₂, Function.update_eq_self]]
    

Proof state:
case h.e'_2.h.e'_7
p : Γ' → Bool
k₁ k₂ : K'
q : Λ'
s : Option Γ'
L₁ L₂ : List Γ'
S : K' → List Γ'
h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂
h₂ : S rev = []
val✝ : Γ'
e : splitAtPred p (S k₁) = (L₁, some val✝, L₂)
⊢ update (update S k₁ (val✝ :: L₂)) k₂ (L₁ ++ S k₂) =
    update (update S k₁ (Option.iget (some val✝) :: L₂)) k₂
      (List.reverse (update (update S rev (List.reverse L₁)) k₁ (Option.iget (some val✝) :: L₂) rev) ++
        update (update S rev (List.reverse L₁)) k₁ (Option.iget (some val✝) :: L₂) k₂)

Next tactic:
simp only [Function.update_noteq h₁.1.symm, Function.update_noteq h₁.2.2.symm,
      Function.update_noteq h₁.2.1, Function.update_same, List.reverse_reverse]
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
  

Proof state:
p : Γ' → Bool
k : K'
q : Λ'
s : Option Γ'
L₁ : List Γ'
o : Option Γ'
L₂ : List Γ'
S : K' → List Γ'
e : 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₂ }

Next tactic:
induction' L₁ with a L₁ IH generalizing S s
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
  · 

Proof state:
case nil
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
e : splitAtPred p (S k) = ([], 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 _
    

Proof state:
case nil
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
e : splitAtPred p (S k) = ([], o, L₂)
⊢ ReflTransGen (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]
    

Proof state:
case nil
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
e : splitAtPred p (S k) = ([], 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
        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:
revert 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; 

Proof state:
case nil
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
⊢ splitAtPred p (S k) = ([], 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
          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' 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 <;> 

Proof state:
case nil.nil
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
⊢ splitAtPred p [] = ([], 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
          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:
intro 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 <;> 

Proof state:
case nil.cons
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
a : Γ'
Sk : List Γ'
⊢ splitAtPred p (a :: Sk) = ([], 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
          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:
intro 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
    · 

Proof state:
case nil.nil
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
e : splitAtPred p [] = ([], 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
        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
      

Proof state:
case nil.nil.refl
p : Γ' → Bool
k : K'
q : Λ'
s : Option Γ'
S : K' → List Γ'
⊢ 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
        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 := none, stk := update S k [] }

Next tactic:
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
    

Proof state:
case nil.cons
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
a : Γ'
Sk : List Γ'
e : splitAtPred p (a :: Sk) = ([], 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
        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 [splitAtPred, Option.elim, List.head?, List.tail_cons] 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 ⊢
    

Proof state:
case nil.cons
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
a : Γ'
Sk : List Γ'
e :
  (bif p a 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 p a 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:
revert 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; 

Proof state:
case nil.cons
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
a : Γ'
Sk : List Γ'
⊢ (bif p a 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 p a 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:
cases 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 <;> 

Proof state:
case nil.cons.false
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
a : Γ'
Sk : List Γ'
⊢ (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:
intro 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 <;> 

Proof state:
case nil.cons.true
p : Γ' → Bool
k : K'
q : Λ'
o : Option Γ'
L₂ : List Γ'
s : Option Γ'
S : K' → List Γ'
a : Γ'
Sk : List Γ'
⊢ (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:
intro e