l3lab/ntp-mathlib huggingface dataset:
theorem move_ok {p k₁ k₂ q s L₁ o L₂} {S : K' → List Γ'} (h₁ : k₁ ≠ k₂)
    (e : splitAtPred p (S k₁) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.move p k₁ k₂ q), s, S⟩
      ⟨some q, o, update (update S k₁ L₂) k₂ (L₁.reverseAux (S k₂))⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · rw [(_ : [].reverseAux _ = _), Function.update_eq_self]
    swap
    · rw [Function.update_noteq h₁.symm]
      rfl
    refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim, ne_eq]
    revert e; cases' S k₁ with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons, Option.iget_some] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · simp only [e]
      rfl
  · refine' TransGen.head rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim, ne_eq, List.reverseAux_cons]
    cases' e₁ : S k₁ with a' Sk <;> rw [e₁, splitAtPred] at e
    · cases e
    cases e₂ : p a' <;> simp only [e₂, cond] at e
    swap
    · cases e
    rcases e₃ : splitAtPred p Sk with ⟨_, _, _⟩
    rw [e₃] at e
    cases e
    simp only [List.head?_cons, e₂, List.tail_cons, ne_eq, cond_false]
    convert @IH _ (update (update S k₁ Sk) k₂ (a :: S k₂)) _ using 2 <;>
      

Proof state:
case h.e'_2.h.e'_7
p : Γ' → Bool
k₁ k₂ : K'
q : Λ'
h₁ : k₁ ≠ k₂
a : Γ'
s : Option Γ'
S : K' → List Γ'
Sk fst✝¹ : List Γ'
fst✝ : Option Γ'
snd✝ : List Γ'
e₃ : splitAtPred p Sk = (fst✝¹, fst✝, snd✝)
e₁ : S k₁ = a :: Sk
e₂ : p a = false
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k₁) = ((fst✝¹, fst✝, snd✝).1, (fst✝¹, fst✝, snd✝).2.1, (fst✝¹, fst✝, snd✝).2.2) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.move p k₁ k₂ q), var := s, stk := S }
        { l := some q, var := (fst✝¹, fst✝, snd✝).2.1,
          stk := update (update S k₁ (fst✝¹, fst✝, snd✝).2.2) k₂ (List.reverseAux (fst✝¹, fst✝, snd✝).1 (S k₂)) }
⊢ update (update S k₁ snd✝) k₂ (List.reverseAux fst✝¹ (a :: S k₂)) =
    update (update (update (update S k₁ Sk) k₂ (a :: S k₂)) k₁ (fst✝¹, fst✝, snd✝).2.2) k₂
      (List.reverseAux (fst✝¹, fst✝, snd✝).1 (update (update S k₁ Sk) k₂ (a :: S k₂) k₂))

Next tactic:
simp [Function.update_noteq, h₁, h₁.symm, e₃, List.reverseAux]
theorem move_ok {p k₁ k₂ q s L₁ o L₂} {S : K' → List Γ'} (h₁ : k₁ ≠ k₂)
    (e : splitAtPred p (S k₁) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.move p k₁ k₂ q), s, S⟩
      ⟨some q, o, update (update S k₁ L₂) k₂ (L₁.reverseAux (S k₂))⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · rw [(_ : [].reverseAux _ = _), Function.update_eq_self]
    swap
    · rw [Function.update_noteq h₁.symm]
      rfl
    refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim, ne_eq]
    revert e; cases' S k₁ with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons, Option.iget_some] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · simp only [e]
      rfl
  · refine' TransGen.head rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim, ne_eq, List.reverseAux_cons]
    cases' e₁ : S k₁ with a' Sk <;> rw [e₁, splitAtPred] at e
    · cases e
    cases e₂ : p a' <;> simp only [e₂, cond] at e
    swap
    · cases e
    rcases e₃ : splitAtPred p Sk with ⟨_, _, _⟩
    rw [e₃] at e
    cases e
    simp only [List.head?_cons, e₂, List.tail_cons, ne_eq, cond_false]
    convert @IH _ (update (update S k₁ Sk) k₂ (a :: S k₂)) _ using 2 <;>
      

Proof state:
case cons.cons.false.mk.mk.refl.convert_2
p : Γ' → Bool
k₁ k₂ : K'
q : Λ'
h₁ : k₁ ≠ k₂
a : Γ'
s : Option Γ'
S : K' → List Γ'
Sk fst✝¹ : List Γ'
fst✝ : Option Γ'
snd✝ : List Γ'
e₃ : splitAtPred p Sk = (fst✝¹, fst✝, snd✝)
e₁ : S k₁ = a :: Sk
e₂ : p a = false
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k₁) = ((fst✝¹, fst✝, snd✝).1, (fst✝¹, fst✝, snd✝).2.1, (fst✝¹, fst✝, snd✝).2.2) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.move p k₁ k₂ q), var := s, stk := S }
        { l := some q, var := (fst✝¹, fst✝, snd✝).2.1,
          stk := update (update S k₁ (fst✝¹, fst✝, snd✝).2.2) k₂ (List.reverseAux (fst✝¹, fst✝, snd✝).1 (S k₂)) }
⊢ splitAtPred p (update (update S k₁ Sk) k₂ (a :: S k₂) k₁) =
    ((fst✝¹, fst✝, snd✝).1, (fst✝¹, fst✝, snd✝).2.1, (fst✝¹, fst✝, snd✝).2.2)

Next tactic:
simp [Function.update_noteq, h₁, h₁.symm, e₃, List.reverseAux]
theorem move_ok {p k₁ k₂ q s L₁ o L₂} {S : K' → List Γ'} (h₁ : k₁ ≠ k₂)
    (e : splitAtPred p (S k₁) = (L₁, o, L₂)) :
    Reaches₁ (TM2.step tr) ⟨some (Λ'.move p k₁ k₂ q), s, S⟩
      ⟨some q, o, update (update S k₁ L₂) k₂ (L₁.reverseAux (S k₂))⟩ := by
  induction' L₁ with a L₁ IH generalizing S s
  · rw [(_ : [].reverseAux _ = _), Function.update_eq_self]
    swap
    · rw [Function.update_noteq h₁.symm]
      rfl
    refine' TransGen.head' rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim, ne_eq]
    revert e; cases' S k₁ with a Sk <;> intro e
    · cases e
      rfl
    simp only [splitAtPred, Option.elim, List.head?, List.tail_cons, Option.iget_some] at e ⊢
    revert e; cases p a <;> intro e <;>
      simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢
    · simp only [e]
      rfl
  · refine' TransGen.head rfl _
    simp only [TM2.step, Option.mem_def, TM2.stepAux, Option.elim, ne_eq, List.reverseAux_cons]
    cases' e₁ : S k₁ with a' Sk <;> rw [e₁, splitAtPred] at e
    · cases e
    cases e₂ : p a' <;> simp only [e₂, cond] at e
    swap
    · cases e
    rcases e₃ : splitAtPred p Sk with ⟨_, _, _⟩
    rw [e₃] at e
    cases e
    simp only [List.head?_cons, e₂, List.tail_cons, ne_eq, cond_false]
    convert @IH _ (update (update S k₁ Sk) k₂ (a :: S k₂)) _ using 2 <;>
      simp [Function.update_noteq, h₁, h₁.symm, e₃, List.reverseAux]
    

Proof state:
case h.e'_2.h.e'_7
p : Γ' → Bool
k₁ k₂ : K'
q : Λ'
h₁ : k₁ ≠ k₂
a : Γ'
s : Option Γ'
S : K' → List Γ'
Sk fst✝¹ : List Γ'
fst✝ : Option Γ'
snd✝ : List Γ'
e₃ : splitAtPred p Sk = (fst✝¹, fst✝, snd✝)
e₁ : S k₁ = a :: Sk
e₂ : p a = false
IH :
  ∀ {s : Option Γ'} {S : K' → List Γ'},
    splitAtPred p (S k₁) = ((fst✝¹, fst✝, snd✝).1, (fst✝¹, fst✝, snd✝).2.1, (fst✝¹, fst✝, snd✝).2.2) →
      Reaches₁ (TM2.step tr) { l := some (Λ'.move p k₁ k₂ q), var := s, stk := S }
        { l := some q, var := (fst✝¹, fst✝, snd✝).2.1,
          stk := update (update S k₁ (fst✝¹, fst✝, snd✝).2.2) k₂ (List.reverseAux (fst✝¹, fst✝, snd✝).1 (S k₂)) }
⊢ update (update S k₁ snd✝) k₂ (List.reverseAux fst✝¹ (a :: S k₂)) =
    update (update (update (update S k₁ Sk) k₂ (a :: S k₂)) k₁ snd✝) k₂ (List.reverseAux fst✝¹ (a :: S k₂))

Next tactic:
simp [Function.update_comm h₁.symm]
theorem unrev_ok {q s} {S : K' → List Γ'} :
    Reaches₁ (TM2.step tr) ⟨some (unrev q), s, S⟩
      ⟨some q, none, update (update S rev []) main (List.reverseAux (S rev) (S main))⟩ :=
  move_ok (by 

Proof state:
q : Λ'
s : Option Γ'
S : K' → List Γ'
⊢ rev ≠ main

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

Proof state:
p : Γ' → Bool
k₁ k₂ : K'
q : Λ'
s : Option Γ'
L₁ : List Γ'
o : Option Γ'
L₂ : List Γ'
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) { l := some (move₂ p k₁ k₂ q), var := s, stk := S }
    { l := some q, var := none, stk := update (update S k₁ (Option.elim o id List.cons L₂)) k₂ (L₁ ++ S k₂) }

Next tactic:
refine' (move_ok h₁.1 e).trans (TransGen.head rfl _)
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 _)
  

Proof state:
p : Γ' → Bool
k₁ k₂ : K'
q : Λ'
s : Option Γ'
L₁ : List Γ'
o : Option Γ'
L₂ : List Γ'
S : K' → List Γ'
h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂
h₂ : S rev = []
e : splitAtPred p (S k₁) = (L₁, o, L₂)
⊢ TransGen (fun a b => b ∈ TM2.step tr a)
    (TM2.stepAux (tr (Λ'.push k₁ id (Λ'.move (fun x => false) rev k₂ q))) o
      (update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev))))
    { l := some q, var := none, stk := update (update S k₁ (Option.elim o id List.cons L₂)) k₂ (L₁ ++ S k₂) }

Next tactic:
simp only [TM2.step, Option.mem_def, TM2.stepAux, id_eq, ne_eq, Option.elim]
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]
  

Proof state:
p : Γ' → Bool
k₁ k₂ : K'
q : Λ'
s : Option Γ'
L₁ : List Γ'
o : Option Γ'
L₂ : List Γ'
S : K' → List Γ'
h₁ : k₁ ≠ rev ∧ k₂ ≠ rev ∧ k₁ ≠ k₂
h₂ : S rev = []
e : splitAtPred p (S k₁) = (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 Option.isSome o then
      { l := some (Λ'.move (fun x => false) rev k₂ q), var := o,
        stk :=
          update (update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev))) k₁
            (Option.iget o :: update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev)) k₁) }
    else
      { l := some (Λ'.move (fun x => false) rev k₂ q), var := o,
        stk := update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev)) })
    { l := some q, var := none,
      stk :=
        update
          (update S k₁
            ((match (motive := Option Γ' → (List Γ' → List Γ') → (Γ' → List Γ' → List Γ') → List Γ' → List Γ') o, id,
                List.cons with
              | some x, x_1, f => f x
              | none, y, x => y)
              L₂))
          k₂ (L₁ ++ S k₂) }

Next tactic:
cases o
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 <;> 

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

Next tactic:
simp only [Option.elim, id.def]
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 <;> 

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)
    (bif Option.isSome (some val✝) then
      { 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₁) }
    else
      { l := some (Λ'.move (fun x => false) rev k₂ q), var := some val✝,
        stk := update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev)) })
    { l := some q, var := none,
      stk :=
        update
          (update S k₁
            ((match (motive := Option Γ' → (List Γ' → List Γ') → (Γ' → List Γ' → List Γ') → List Γ' → List Γ')
                some val✝, id, List.cons with
              | some x, x_1, f => f x
              | none, y, x => y)
              L₂))
          k₂ (L₁ ++ S k₂) }

Next tactic:
simp only [Option.elim, id.def]
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]
  · 

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

Next tactic:
simp only [TM2.stepAux, Option.isSome, cond_false]
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]
    

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

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 = []
e : splitAtPred p (S k₁) = (L₁, none, L₂)
⊢ update (update S k₁ L₂) k₂ (L₁ ++ S k₂) =
    update (update (update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev))) rev []) k₂
      (List.reverseAux (update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev)) rev)
        (update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev)) k₂))

Next tactic:
simp only [Function.update_comm h₁.1, 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]
    

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 = []
e : splitAtPred p (S k₁) = (L₁, none, L₂)
⊢ update (update S k₁ L₂) k₂ (L₁ ++ S k₂) =
    update (update (update S rev []) k₁ L₂) k₂
      (List.reverseAux (update (update S rev (List.reverseAux L₁ (S rev))) k₁ L₂ rev)
        (update (update S rev (List.reverseAux L₁ (S rev))) k₁ 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 

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 = []
e : splitAtPred p (S k₁) = (L₁, none, 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]]
    

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 = []
e : splitAtPred p (S k₁) = (L₁, none, L₂)
⊢ update (update S k₁ L₂) k₂ (L₁ ++ S k₂) =
    update (update S k₁ L₂) k₂
      (List.reverseAux (update (update S rev (List.reverseAux L₁ (S rev))) k₁ L₂ rev)
        (update (update S rev (List.reverseAux L₁ (S rev))) k₁ L₂ k₂))

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

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)
    (bif Option.isSome (some val✝) then
      { 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₁) }
    else
      { l := some (Λ'.move (fun x => false) rev k₂ q), var := some val✝,
        stk := update (update S k₁ L₂) rev (List.reverseAux L₁ (S rev)) })
    { l := some q, var := none, stk := update (update S k₁ (val✝ :: L₂)) k₂ (L₁ ++ S k₂) }

Next tactic:
simp only [TM2.stepAux, Option.isSome, cond_true]