File: Mathlib/Computability/TuringMachine.lean

full_name: Turing.BlankExtends
code: /-- The `BlankExtends` partial order holds of `l₁` and `l₂` if `l₂` is obtained by adding
blanks (`default : Γ`) to the end of `l₁`. -/
def BlankExtends {Γ} [Inhabited Γ] (l₁ l₂ : List Γ) : Prop 
goal: Prop

full_name: Turing.BlankExtends.refl
code: @[refl]
theorem BlankExtends.refl {Γ} [Inhabited Γ] (l : List Γ) : BlankExtends l l 
goal: Turing.BlankExtends l l

full_name: Turing.BlankExtends.trans
code: @[trans]
theorem BlankExtends.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankExtends l₁ l₂ → BlankExtends l₂ l₃ → BlankExtends l₁ l₃ 
goal: Turing.BlankExtends l₁ l₂ → Turing.BlankExtends l₂ l₃ → Turing.BlankExtends l₁ l₃

full_name: Turing.BlankExtends.below_of_le
code: theorem BlankExtends.below_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l l₁ → BlankExtends l l₂ → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ 
goal: Turing.BlankExtends l l₁ → Turing.BlankExtends l l₂ → l₁.length ≤ l₂.length → Turing.BlankExtends l₁ l₂

full_name: Turing.BlankExtends.above
code: /-- Any two extensions by blank `l₁,l₂` of `l` have a common join (which can be taken to be the
longer of `l₁` and `l₂`). -/
def BlankExtends.above {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} (h₁ : BlankExtends l l₁)
    (h₂ : BlankExtends l l₂) : { l' // BlankExtends l₁ l' ∧ BlankExtends l₂ l' } 
goal: { l' // Turing.BlankExtends l₁ l' ∧ Turing.BlankExtends l₂ l' }

full_name: Turing.BlankExtends.above_of_le
code: theorem BlankExtends.above_of_le {Γ} [Inhabited Γ] {l l₁ l₂ : List Γ} :
    BlankExtends l₁ l → BlankExtends l₂ l → l₁.length ≤ l₂.length → BlankExtends l₁ l₂ 
goal: Turing.BlankExtends l₁ l → Turing.BlankExtends l₂ l → l₁.length ≤ l₂.length → Turing.BlankExtends l₁ l₂

full_name: Turing.BlankRel
code: /-- `BlankRel` is the symmetric closure of `BlankExtends`, turning it into an equivalence
relation. Two lists are related by `BlankRel` if one extends the other by blanks. -/
def BlankRel {Γ} [Inhabited Γ] (l₁ l₂ : List Γ) : Prop 
goal: Prop

full_name: Turing.BlankRel.refl
code: @[refl]
theorem BlankRel.refl {Γ} [Inhabited Γ] (l : List Γ) : BlankRel l l 
goal: Turing.BlankRel l l

full_name: Turing.BlankRel.symm
code: @[symm]
theorem BlankRel.symm {Γ} [Inhabited Γ] {l₁ l₂ : List Γ} : BlankRel l₁ l₂ → BlankRel l₂ l₁ 
goal: Turing.BlankRel l₁ l₂ → Turing.BlankRel l₂ l₁

full_name: Turing.BlankRel.trans
code: @[trans]
theorem BlankRel.trans {Γ} [Inhabited Γ] {l₁ l₂ l₃ : List Γ} :
    BlankRel l₁ l₂ → BlankRel l₂ l₃ → BlankRel l₁ l₃ 
goal: Turing.BlankRel l₁ l₂ → Turing.BlankRel l₂ l₃ → Turing.BlankRel l₁ l₃

full_name: Turing.BlankRel.above
code: /-- Given two `BlankRel` lists, there exists (constructively) a common join. -/
def BlankRel.above {Γ} [Inhabited Γ] {l₁ l₂ : List Γ} (h : BlankRel l₁ l₂) :
    { l // BlankExtends l₁ l ∧ BlankExtends l₂ l } 
goal: { l // Turing.BlankExtends l₁ l ∧ Turing.BlankExtends l₂ l }

full_name: Turing.BlankRel.below
code: /-- Given two `BlankRel` lists, there exists (constructively) a common meet. -/
def BlankRel.below {Γ} [Inhabited Γ] {l₁ l₂ : List Γ} (h : BlankRel l₁ l₂) :
    { l // BlankExtends l l₁ ∧ BlankExtends l l₂ } 
goal: { l // Turing.BlankExtends l l₁ ∧ Turing.BlankExtends l l₂ }

full_name: Turing.BlankRel.equivalence
code: theorem BlankRel.equivalence (Γ) [Inhabited Γ] : Equivalence (@BlankRel Γ _) 
goal: Equivalence Turing.BlankRel

full_name: Turing.BlankRel.setoid
code: /-- Construct a setoid instance for `BlankRel`. -/
def BlankRel.setoid (Γ) [Inhabited Γ] : Setoid (List Γ) 
goal: Setoid (List Γ)

full_name: Turing.ListBlank
code: /-- A `ListBlank Γ` is a quotient of `List Γ` by extension by blanks at the end. This is used to
represent half-tapes of a Turing machine, so that we can pretend that the list continues
infinitely with blanks. -/
def ListBlank (Γ) [Inhabited Γ] 
goal: Type u_1

full_name: Turing.ListBlank.inhabited
code: instance ListBlank.inhabited {Γ} [Inhabited Γ] : Inhabited (ListBlank Γ) 
goal: Inhabited (Turing.ListBlank Γ)

full_name: Turing.ListBlank.hasEmptyc
code: instance ListBlank.hasEmptyc {Γ} [Inhabited Γ] : EmptyCollection (ListBlank Γ) 
goal: EmptyCollection (Turing.ListBlank Γ)

full_name: Turing.ListBlank.liftOn
code: /-- A modified version of `Quotient.liftOn'` specialized for `ListBlank`, with the stronger
precondition `BlankExtends` instead of `BlankRel`. -/
-- Porting note: Removed `@[elab_as_elim]`
protected abbrev ListBlank.liftOn {Γ} [Inhabited Γ] {α} (l : ListBlank Γ) (f : List Γ → α)
    (H : ∀ a b, BlankExtends a b → f a = f b) : α 
goal: α

full_name: Turing.ListBlank.mk
code: /-- The quotient map turning a `List` into a `ListBlank`. -/
def ListBlank.mk {Γ} [Inhabited Γ] : List Γ → ListBlank Γ 
goal: List Γ → Turing.ListBlank Γ

full_name: Turing.ListBlank.induction_on
code: @[elab_as_elim]
protected theorem ListBlank.induction_on {Γ} [Inhabited Γ] {p : ListBlank Γ → Prop}
    (q : ListBlank Γ) (h : ∀ a, p (ListBlank.mk a)) : p q 
goal: p q

full_name: Turing.ListBlank.head
code: /-- The head of a `ListBlank` is well defined. -/
def ListBlank.head {Γ} [Inhabited Γ] (l : ListBlank Γ) : Γ 
goal: Γ

full_name: Turing.ListBlank.head_mk
code: @[simp]
theorem ListBlank.head_mk {Γ} [Inhabited Γ] (l : List Γ) :
    ListBlank.head (ListBlank.mk l) = l.headI 
goal: (Turing.ListBlank.mk l).head = l.headI

full_name: Turing.ListBlank.tail
code: /-- The tail of a `ListBlank` is well defined (up to the tail of blanks). -/
def ListBlank.tail {Γ} [Inhabited Γ] (l : ListBlank Γ) : ListBlank Γ 
goal: Turing.ListBlank Γ

full_name: Turing.ListBlank.tail_mk
code: @[simp]
theorem ListBlank.tail_mk {Γ} [Inhabited Γ] (l : List Γ) :
    ListBlank.tail (ListBlank.mk l) = ListBlank.mk l.tail 
goal: (Turing.ListBlank.mk l).tail = Turing.ListBlank.mk l.tail

full_name: Turing.ListBlank.cons
code: /-- We can cons an element onto a `ListBlank`. -/
def ListBlank.cons {Γ} [Inhabited Γ] (a : Γ) (l : ListBlank Γ) : ListBlank Γ 
goal: Turing.ListBlank Γ

full_name: Turing.ListBlank.cons_mk
code: @[simp]
theorem ListBlank.cons_mk {Γ} [Inhabited Γ] (a : Γ) (l : List Γ) :
    ListBlank.cons a (ListBlank.mk l) = ListBlank.mk (a :: l) 
goal: Turing.ListBlank.cons a (Turing.ListBlank.mk l) = Turing.ListBlank.mk (a :: l)

full_name: Turing.ListBlank.head_cons
code: @[simp]
theorem ListBlank.head_cons {Γ} [Inhabited Γ] (a : Γ) : ∀ l : ListBlank Γ, (l.cons a).head = a 
goal: (Turing.ListBlank.cons a l).head = a

full_name: Turing.ListBlank.tail_cons
code: @[simp]
theorem ListBlank.tail_cons {Γ} [Inhabited Γ] (a : Γ) : ∀ l : ListBlank Γ, (l.cons a).tail = l 
goal: (Turing.ListBlank.cons a l).tail = l

full_name: Turing.ListBlank.cons_head_tail
code: /-- The `cons` and `head`/`tail` functions are mutually inverse, unlike in the case of `List` where
this only holds for nonempty lists. -/
@[simp]
theorem ListBlank.cons_head_tail {Γ} [Inhabited Γ] : ∀ l : ListBlank Γ, l.tail.cons l.head = l 
goal: Turing.ListBlank.cons l.head l.tail = l

full_name: Turing.ListBlank.exists_cons
code: /-- The `cons` and `head`/`tail` functions are mutually inverse, unlike in the case of `List` where
this only holds for nonempty lists. -/
theorem ListBlank.exists_cons {Γ} [Inhabited Γ] (l : ListBlank Γ) :
    ∃ a l', l = ListBlank.cons a l' 
goal: ∃ a l', l = Turing.ListBlank.cons a l'

full_name: Turing.ListBlank.nth
code: /-- The n-th element of a `ListBlank` is well defined for all `n : ℕ`, unlike in a `List`. -/
def ListBlank.nth {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : Γ 
goal: Γ

full_name: Turing.ListBlank.nth_mk
code: @[simp]
theorem ListBlank.nth_mk {Γ} [Inhabited Γ] (l : List Γ) (n : ℕ) :
    (ListBlank.mk l).nth n = l.getI n 
goal: (Turing.ListBlank.mk l).nth n = l.getI n

full_name: Turing.ListBlank.nth_zero
code: @[simp]
theorem ListBlank.nth_zero {Γ} [Inhabited Γ] (l : ListBlank Γ) : l.nth 0 = l.head 
goal: l.nth 0 = l.head

full_name: Turing.ListBlank.nth_succ
code: @[simp]
theorem ListBlank.nth_succ {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) :
    l.nth (n + 1) = l.tail.nth n 
goal: l.nth (n + 1) = l.tail.nth n

full_name: Turing.ListBlank.ext
code: @[ext]
theorem ListBlank.ext {Γ} [i : Inhabited Γ] {L₁ L₂ : ListBlank Γ} :
    (∀ i, L₁.nth i = L₂.nth i) → L₁ = L₂ 
goal: (∀ (i_1 : ℕ), L₁.nth i_1 = L₂.nth i_1) → L₁ = L₂

full_name: Turing.ListBlank.modifyNth
code: /-- Apply a function to a value stored at the nth position of the list. -/
@[simp]
def ListBlank.modifyNth {Γ} [Inhabited Γ] (f : Γ → Γ) : ℕ → ListBlank Γ → ListBlank Γ
  
goal: ℕ → Turing.ListBlank Γ → Turing.ListBlank Γ

full_name: Turing.ListBlank.nth_modifyNth
code: theorem ListBlank.nth_modifyNth {Γ} [Inhabited Γ] (f : Γ → Γ) (n i) (L : ListBlank Γ) :
    (L.modifyNth f n).nth i = if i = n then f (L.nth i) else L.nth i 
goal: (Turing.ListBlank.modifyNth f n L).nth i = if i = n then f (L.nth i) else L.nth i

full_name: Turing.PointedMap.f
code: /-- A pointed map of `Inhabited` types is a map that sends one default value to the other. -/
structure PointedMap.{u, v} (Γ : Type u) (Γ' : Type v) [Inhabited Γ] [Inhabited Γ'] :
    Type max u v where
  /-- The map underlying this instance. -/
  f : Γ → Γ'
  map_pt' : f default = default
goal: Γ → Γ'

full_name: Turing.PointedMap.map_pt'
code: /-- A pointed map of `Inhabited` types is a map that sends one default value to the other. -/
structure PointedMap.{u, v} (Γ : Type u) (Γ' : Type v) [Inhabited Γ] [Inhabited Γ'] :
    Type max u v where
  /-- The map underlying this instance. -/
  f : Γ → Γ'
  map_pt' : f default = default
goal: self.f default = default

full_name: Turing.instInhabitedPointedMap
code: instance {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] : Inhabited (PointedMap Γ Γ') 
goal: Inhabited (Turing.PointedMap Γ Γ')

full_name: Turing.instCoeFunPointedMapForall
code: instance {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] : CoeFun (PointedMap Γ Γ') fun _ ↦ Γ → Γ' 
goal: CoeFun (Turing.PointedMap Γ Γ') fun x => Γ → Γ'

full_name: Turing.PointedMap.mk_val
code: theorem PointedMap.mk_val {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : Γ → Γ') (pt) :
    (PointedMap.mk f pt : Γ → Γ') = f 
goal: { f := f, map_pt' := pt }.f = f

full_name: Turing.PointedMap.map_pt
code: @[simp]
theorem PointedMap.map_pt {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') :
    f default = default 
goal: f.f default = default

full_name: Turing.PointedMap.headI_map
code: @[simp]
theorem PointedMap.headI_map {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ')
    (l : List Γ) : (l.map f).headI = f l.headI 
goal: (List.map f.f l).headI = f.f l.headI

full_name: Turing.ListBlank.map
code: /-- The `map` function on lists is well defined on `ListBlank`s provided that the map is
pointed. -/
def ListBlank.map {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') (l : ListBlank Γ) :
    ListBlank Γ' 
goal: Turing.ListBlank Γ'

full_name: Turing.ListBlank.map_mk
code: @[simp]
theorem ListBlank.map_mk {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') (l : List Γ) :
    (ListBlank.mk l).map f = ListBlank.mk (l.map f) 
goal: Turing.ListBlank.map f (Turing.ListBlank.mk l) = Turing.ListBlank.mk (List.map f.f l)

full_name: Turing.ListBlank.head_map
code: @[simp]
theorem ListBlank.head_map {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ')
    (l : ListBlank Γ) : (l.map f).head = f l.head 
goal: (Turing.ListBlank.map f l).head = f.f l.head

full_name: Turing.ListBlank.tail_map
code: @[simp]
theorem ListBlank.tail_map {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ')
    (l : ListBlank Γ) : (l.map f).tail = l.tail.map f 
goal: (Turing.ListBlank.map f l).tail = Turing.ListBlank.map f l.tail

full_name: Turing.ListBlank.map_cons
code: @[simp]
theorem ListBlank.map_cons {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ')
    (l : ListBlank Γ) (a : Γ) : (l.cons a).map f = (l.map f).cons (f a) 
goal: Turing.ListBlank.map f (Turing.ListBlank.cons a l) = Turing.ListBlank.cons (f.f a) (Turing.ListBlank.map f l)

full_name: Turing.ListBlank.nth_map
code: @[simp]
theorem ListBlank.nth_map {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ')
    (l : ListBlank Γ) (n : ℕ) : (l.map f).nth n = f (l.nth n) 
goal: (Turing.ListBlank.map f l).nth n = f.f (l.nth n)

full_name: Turing.proj
code: /-- The `i`-th projection as a pointed map. -/
def proj {ι : Type*} {Γ : ι → Type*} [∀ i, Inhabited (Γ i)] (i : ι) :
    PointedMap (∀ i, Γ i) (Γ i) 
goal: Turing.PointedMap ((i : ι) → Γ i) (Γ i)

full_name: Turing.proj_map_nth
code: theorem proj_map_nth {ι : Type*} {Γ : ι → Type*} [∀ i, Inhabited (Γ i)] (i : ι) (L n) :
    (ListBlank.map (@proj ι Γ _ i) L).nth n = L.nth n i 
goal: (Turing.ListBlank.map (Turing.proj i) L).nth n = L.nth n i

full_name: Turing.ListBlank.map_modifyNth
code: theorem ListBlank.map_modifyNth {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (F : PointedMap Γ Γ')
    (f : Γ → Γ) (f' : Γ' → Γ') (H : ∀ x, F (f x) = f' (F x)) (n) (L : ListBlank Γ) :
    (L.modifyNth f n).map F = (L.map F).modifyNth f' n 
goal: Turing.ListBlank.map F (Turing.ListBlank.modifyNth f n L) = Turing.ListBlank.modifyNth f' n (Turing.ListBlank.map F L)

full_name: Turing.ListBlank.append
code: /-- Append a list on the left side of a `ListBlank`. -/
@[simp]
def ListBlank.append {Γ} [Inhabited Γ] : List Γ → ListBlank Γ → ListBlank Γ
  
goal: List Γ → Turing.ListBlank Γ → Turing.ListBlank Γ

full_name: Turing.ListBlank.append_mk
code: @[simp]
theorem ListBlank.append_mk {Γ} [Inhabited Γ] (l₁ l₂ : List Γ) :
    ListBlank.append l₁ (ListBlank.mk l₂) = ListBlank.mk (l₁ ++ l₂) 
goal: Turing.ListBlank.append l₁ (Turing.ListBlank.mk l₂) = Turing.ListBlank.mk (l₁ ++ l₂)

full_name: Turing.ListBlank.append_assoc
code: theorem ListBlank.append_assoc {Γ} [Inhabited Γ] (l₁ l₂ : List Γ) (l₃ : ListBlank Γ) :
    ListBlank.append (l₁ ++ l₂) l₃ = ListBlank.append l₁ (ListBlank.append l₂ l₃) 
goal: Turing.ListBlank.append (l₁ ++ l₂) l₃ = Turing.ListBlank.append l₁ (Turing.ListBlank.append l₂ l₃)

full_name: Turing.ListBlank.bind
code: /-- The `bind` function on lists is well defined on `ListBlank`s provided that the default element
is sent to a sequence of default elements. -/
def ListBlank.bind {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (l : ListBlank Γ) (f : Γ → List Γ')
    (hf : ∃ n, f default = List.replicate n default) : ListBlank Γ' 
goal: Turing.ListBlank Γ'

full_name: Turing.ListBlank.bind_mk
code: @[simp]
theorem ListBlank.bind_mk {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (l : List Γ) (f : Γ → List Γ') (hf) :
    (ListBlank.mk l).bind f hf = ListBlank.mk (l.bind f) 
goal: (Turing.ListBlank.mk l).bind f hf = Turing.ListBlank.mk (l.bind f)

full_name: Turing.ListBlank.cons_bind
code: @[simp]
theorem ListBlank.cons_bind {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (a : Γ) (l : ListBlank Γ)
    (f : Γ → List Γ') (hf) : (l.cons a).bind f hf = (l.bind f hf).append (f a) 
goal: (Turing.ListBlank.cons a l).bind f hf = Turing.ListBlank.append (f a) (l.bind f hf)

full_name: Turing.Tape.head
code: /-- The tape of a Turing machine is composed of a head element (which we imagine to be the
current position of the head), together with two `ListBlank`s denoting the portions of the tape
going off to the left and right. When the Turing machine moves right, an element is pulled from the
right side and becomes the new head, while the head element is `cons`ed onto the left side. -/
structure Tape (Γ : Type*) [Inhabited Γ] where
  /-- The current position of the head. -/
  head : Γ
  /-- The portion of the tape going off to the left. -/
  left : ListBlank Γ
  /-- The portion of the tape going off to the right. -/
  right : ListBlank Γ
goal: Γ

full_name: Turing.Tape.right
code: /-- The tape of a Turing machine is composed of a head element (which we imagine to be the
current position of the head), together with two `ListBlank`s denoting the portions of the tape
going off to the left and right. When the Turing machine moves right, an element is pulled from the
right side and becomes the new head, while the head element is `cons`ed onto the left side. -/
structure Tape (Γ : Type*) [Inhabited Γ] where
  /-- The current position of the head. -/
  head : Γ
  /-- The portion of the tape going off to the left. -/
  left : ListBlank Γ
  /-- The portion of the tape going off to the right. -/
  right : ListBlank Γ
goal: Turing.ListBlank Γ

full_name: Turing.Tape.left
code: /-- The tape of a Turing machine is composed of a head element (which we imagine to be the
current position of the head), together with two `ListBlank`s denoting the portions of the tape
going off to the left and right. When the Turing machine moves right, an element is pulled from the
right side and becomes the new head, while the head element is `cons`ed onto the left side. -/
structure Tape (Γ : Type*) [Inhabited Γ] where
  /-- The current position of the head. -/
  head : Γ
  /-- The portion of the tape going off to the left. -/
  left : ListBlank Γ
  /-- The portion of the tape going off to the right. -/
  right : ListBlank Γ
goal: Turing.ListBlank Γ

full_name: Turing.Tape
code: /-- The tape of a Turing machine is composed of a head element (which we imagine to be the
current position of the head), together with two `ListBlank`s denoting the portions of the tape
going off to the left and right. When the Turing machine moves right, an element is pulled from the
right side and becomes the new head, while the head element is `cons`ed onto the left side. -/
structure Tape (Γ : Type*) [Inhabited Γ] where
  /-- The current position of the head. -/
  head : Γ
  /-- The portion of the tape going off to the left. -/
  left : ListBlank Γ
  /-- The portion of the tape going off to the right. -/
  right : ListBlank Γ
goal: Type u_1

full_name: Turing.Tape.inhabited
code: instance Tape.inhabited {Γ} [Inhabited Γ] : Inhabited (Tape Γ) 
goal: Inhabited (Turing.Tape Γ)

full_name: Turing.Dir
code: /-- A direction for the Turing machine `move` command, either
  left or right. -/
inductive Dir
  | left
  | right
  deriving DecidableEq, Inhabited
goal: Type

full_name: Turing.Dir.left
code: /-- A direction for the Turing machine `move` command, either
  left or right. -/
inductive Dir
  | left
  | right
  deriving DecidableEq, Inhabited
goal: Turing.Dir

full_name: Turing.instInhabitedDir
code: /-- A direction for the Turing machine `move` command, either
  left or right. -/
inductive Dir
  | left
  | right
  deriving DecidableEq, Inhabited
goal: Inhabited Turing.Dir

full_name: Turing.Dir.right
code: /-- A direction for the Turing machine `move` command, either
  left or right. -/
inductive Dir
  | left
  | right
  deriving DecidableEq, Inhabited
goal: Turing.Dir

full_name: Turing.instDecidableEqDir
code: /-- A direction for the Turing machine `move` command, either
  left or right. -/
inductive Dir
  | left
  | right
  deriving DecidableEq, Inhabited
goal: DecidableEq Turing.Dir

full_name: Turing.Tape.left₀
code: /-- The "inclusive" left side of the tape, including both `left` and `head`. -/
def Tape.left₀ {Γ} [Inhabited Γ] (T : Tape Γ) : ListBlank Γ 
goal: Turing.ListBlank Γ

full_name: Turing.Tape.right₀
code: /-- The "inclusive" right side of the tape, including both `right` and `head`. -/
def Tape.right₀ {Γ} [Inhabited Γ] (T : Tape Γ) : ListBlank Γ 
goal: Turing.ListBlank Γ

full_name: Turing.Tape.move
code: /-- Move the tape in response to a motion of the Turing machine. Note that `T.move Dir.left` makes
`T.left` smaller; the Turing machine is moving left and the tape is moving right. -/
def Tape.move {Γ} [Inhabited Γ] : Dir → Tape Γ → Tape Γ
  
goal: Turing.Dir → Turing.Tape Γ → Turing.Tape Γ

full_name: Turing.Tape.move_left_right
code: @[simp]
theorem Tape.move_left_right {Γ} [Inhabited Γ] (T : Tape Γ) :
    (T.move Dir.left).move Dir.right = T 
goal: Turing.Tape.move Turing.Dir.right (Turing.Tape.move Turing.Dir.left T) = T

full_name: Turing.Tape.move_right_left
code: @[simp]
theorem Tape.move_right_left {Γ} [Inhabited Γ] (T : Tape Γ) :
    (T.move Dir.right).move Dir.left = T 
goal: Turing.Tape.move Turing.Dir.left (Turing.Tape.move Turing.Dir.right T) = T

full_name: Turing.Tape.mk'
code: /-- Construct a tape from a left side and an inclusive right side. -/
def Tape.mk' {Γ} [Inhabited Γ] (L R : ListBlank Γ) : Tape Γ 
goal: Turing.Tape Γ

full_name: Turing.Tape.mk'_left
code: @[simp]
theorem Tape.mk'_left {Γ} [Inhabited Γ] (L R : ListBlank Γ) : (Tape.mk' L R).left = L 
goal: (Turing.Tape.mk' L R).left = L

full_name: Turing.Tape.mk'_head
code: @[simp]
theorem Tape.mk'_head {Γ} [Inhabited Γ] (L R : ListBlank Γ) : (Tape.mk' L R).head = R.head 
goal: (Turing.Tape.mk' L R).head = R.head

full_name: Turing.Tape.mk'_right
code: @[simp]
theorem Tape.mk'_right {Γ} [Inhabited Γ] (L R : ListBlank Γ) : (Tape.mk' L R).right = R.tail 
goal: (Turing.Tape.mk' L R).right = R.tail

full_name: Turing.Tape.mk'_right₀
code: @[simp]
theorem Tape.mk'_right₀ {Γ} [Inhabited Γ] (L R : ListBlank Γ) : (Tape.mk' L R).right₀ = R 
goal: (Turing.Tape.mk' L R).right₀ = R

full_name: Turing.Tape.mk'_left_right₀
code: @[simp]
theorem Tape.mk'_left_right₀ {Γ} [Inhabited Γ] (T : Tape Γ) : Tape.mk' T.left T.right₀ = T 
goal: Turing.Tape.mk' T.left T.right₀ = T

full_name: Turing.Tape.exists_mk'
code: theorem Tape.exists_mk' {Γ} [Inhabited Γ] (T : Tape Γ) : ∃ L R, T = Tape.mk' L R 
goal: ∃ L R, T = Turing.Tape.mk' L R

full_name: Turing.Tape.move_left_mk'
code: @[simp]
theorem Tape.move_left_mk' {Γ} [Inhabited Γ] (L R : ListBlank Γ) :
    (Tape.mk' L R).move Dir.left = Tape.mk' L.tail (R.cons L.head) 
goal: Turing.Tape.move Turing.Dir.left (Turing.Tape.mk' L R) = Turing.Tape.mk' L.tail (Turing.ListBlank.cons L.head R)

full_name: Turing.Tape.move_right_mk'
code: @[simp]
theorem Tape.move_right_mk' {Γ} [Inhabited Γ] (L R : ListBlank Γ) :
    (Tape.mk' L R).move Dir.right = Tape.mk' (L.cons R.head) R.tail 
goal: Turing.Tape.move Turing.Dir.right (Turing.Tape.mk' L R) = Turing.Tape.mk' (Turing.ListBlank.cons R.head L) R.tail

full_name: Turing.Tape.mk₂
code: /-- Construct a tape from a left side and an inclusive right side. -/
def Tape.mk₂ {Γ} [Inhabited Γ] (L R : List Γ) : Tape Γ 
goal: Turing.Tape Γ

full_name: Turing.Tape.mk₁
code: /-- Construct a tape from a list, with the head of the list at the TM head and the rest going
to the right. -/
def Tape.mk₁ {Γ} [Inhabited Γ] (l : List Γ) : Tape Γ 
goal: Turing.Tape Γ

full_name: Turing.Tape.nth
code: /-- The `nth` function of a tape is integer-valued, with index `0` being the head, negative indexes
on the left and positive indexes on the right. (Picture a number line.) -/
def Tape.nth {Γ} [Inhabited Γ] (T : Tape Γ) : ℤ → Γ
  
goal: ℤ → Γ

full_name: Turing.Tape.nth_zero
code: @[simp]
theorem Tape.nth_zero {Γ} [Inhabited Γ] (T : Tape Γ) : T.nth 0 = T.1 
goal: T.nth 0 = T.head

full_name: Turing.Tape.right₀_nth
code: theorem Tape.right₀_nth {Γ} [Inhabited Γ] (T : Tape Γ) (n : ℕ) : T.right₀.nth n = T.nth n 
goal: T.right₀.nth n = T.nth ↑n

full_name: Turing.Tape.mk'_nth_nat
code: @[simp]
theorem Tape.mk'_nth_nat {Γ} [Inhabited Γ] (L R : ListBlank Γ) (n : ℕ) :
    (Tape.mk' L R).nth n = R.nth n 
goal: (Turing.Tape.mk' L R).nth ↑n = R.nth n

full_name: Turing.Tape.move_left_nth
code: @[simp]
theorem Tape.move_left_nth {Γ} [Inhabited Γ] :
    ∀ (T : Tape Γ) (i : ℤ), (T.move Dir.left).nth i = T.nth (i - 1)
  
goal: (Turing.Tape.move Turing.Dir.left T).nth i = T.nth (i - 1)

full_name: Turing.Tape.move_right_nth
code: @[simp]
theorem Tape.move_right_nth {Γ} [Inhabited Γ] (T : Tape Γ) (i : ℤ) :
    (T.move Dir.right).nth i = T.nth (i + 1) 
goal: (Turing.Tape.move Turing.Dir.right T).nth i = T.nth (i + 1)

full_name: Turing.Tape.move_right_n_head
code: @[simp]
theorem Tape.move_right_n_head {Γ} [Inhabited Γ] (T : Tape Γ) (i : ℕ) :
    ((Tape.move Dir.right)^[i] T).head = T.nth i 
goal: ((Turing.Tape.move Turing.Dir.right)^[i] T).head = T.nth ↑i

full_name: Turing.Tape.write
code: /-- Replace the current value of the head on the tape. -/
def Tape.write {Γ} [Inhabited Γ] (b : Γ) (T : Tape Γ) : Tape Γ 
goal: Turing.Tape Γ

full_name: Turing.Tape.write_self
code: @[simp]
theorem Tape.write_self {Γ} [Inhabited Γ] : ∀ T : Tape Γ, T.write T.1 = T 
goal: Turing.Tape.write T.head T = T

full_name: Turing.Tape.write_nth
code: @[simp]
theorem Tape.write_nth {Γ} [Inhabited Γ] (b : Γ) :
    ∀ (T : Tape Γ) {i : ℤ}, (T.write b).nth i = if i = 0 then b else T.nth i
  
goal: (Turing.Tape.write b T).nth i = if i = 0 then b else T.nth i

full_name: Turing.Tape.write_mk'
code: @[simp]
theorem Tape.write_mk' {Γ} [Inhabited Γ] (a b : Γ) (L R : ListBlank Γ) :
    (Tape.mk' L (R.cons a)).write b = Tape.mk' L (R.cons b) 
goal: Turing.Tape.write b (Turing.Tape.mk' L (Turing.ListBlank.cons a R)) = Turing.Tape.mk' L (Turing.ListBlank.cons b R)

full_name: Turing.Tape.map
code: /-- Apply a pointed map to a tape to change the alphabet. -/
def Tape.map {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') (T : Tape Γ) : Tape Γ' 
goal: Turing.Tape Γ'

full_name: Turing.Tape.map_fst
code: @[simp]
theorem Tape.map_fst {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') :
    ∀ T : Tape Γ, (T.map f).1 = f T.1 
goal: (Turing.Tape.map f T).head = f.f T.head

full_name: Turing.Tape.map_write
code: @[simp]
theorem Tape.map_write {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') (b : Γ) :
    ∀ T : Tape Γ, (T.write b).map f = (T.map f).write (f b) 
goal: Turing.Tape.map f (Turing.Tape.write b T) = Turing.Tape.write (f.f b) (Turing.Tape.map f T)

full_name: Turing.Tape.write_move_right_n
code: @[simp, nolint simpNF]
theorem Tape.write_move_right_n {Γ} [Inhabited Γ] (f : Γ → Γ) (L R : ListBlank Γ) (n : ℕ) :
    ((Tape.move Dir.right)^[n] (Tape.mk' L R)).write (f (R.nth n)) =
      (Tape.move Dir.right)^[n] (Tape.mk' L (R.modifyNth f n)) 
goal: Turing.Tape.write (f (R.nth n)) ((Turing.Tape.move Turing.Dir.right)^[n] (Turing.Tape.mk' L R)) =
  (Turing.Tape.move Turing.Dir.right)^[n] (Turing.Tape.mk' L (Turing.ListBlank.modifyNth f n R))

full_name: Turing.Tape.map_move
code: theorem Tape.map_move {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') (T : Tape Γ) (d) :
    (T.move d).map f = (T.map f).move d 
goal: Turing.Tape.map f (Turing.Tape.move d T) = Turing.Tape.move d (Turing.Tape.map f T)

full_name: Turing.Tape.map_mk'
code: theorem Tape.map_mk' {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') (L R : ListBlank Γ) :
    (Tape.mk' L R).map f = Tape.mk' (L.map f) (R.map f) 
goal: Turing.Tape.map f (Turing.Tape.mk' L R) = Turing.Tape.mk' (Turing.ListBlank.map f L) (Turing.ListBlank.map f R)

full_name: Turing.Tape.map_mk₂
code: theorem Tape.map_mk₂ {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') (L R : List Γ) :
    (Tape.mk₂ L R).map f = Tape.mk₂ (L.map f) (R.map f) 
goal: Turing.Tape.map f (Turing.Tape.mk₂ L R) = Turing.Tape.mk₂ (List.map f.f L) (List.map f.f R)

full_name: Turing.Tape.map_mk₁
code: theorem Tape.map_mk₁ {Γ Γ'} [Inhabited Γ] [Inhabited Γ'] (f : PointedMap Γ Γ') (l : List Γ) :
    (Tape.mk₁ l).map f = Tape.mk₁ (l.map f) 
goal: Turing.Tape.map f (Turing.Tape.mk₁ l) = Turing.Tape.mk₁ (List.map f.f l)

full_name: Turing.eval
code: /-- Run a state transition function `σ → Option σ` "to completion". The return value is the last
state returned before a `none` result. If the state transition function always returns `some`,
then the computation diverges, returning `Part.none`. -/
def eval {σ} (f : σ → Option σ) : σ → Part σ 
goal: σ → Part σ

full_name: Turing.Reaches
code: /-- The reflexive transitive closure of a state transition function. `Reaches f a b` means
there is a finite sequence of steps `f a = some a₁`, `f a₁ = some a₂`, ... such that `aₙ = b`.
This relation permits zero steps of the state transition function. -/
def Reaches {σ} (f : σ → Option σ) : σ → σ → Prop 
goal: σ → σ → Prop

full_name: Turing.Reaches₁
code: /-- The transitive closure of a state transition function. `Reaches₁ f a b` means there is a
nonempty finite sequence of steps `f a = some a₁`, `f a₁ = some a₂`, ... such that `aₙ = b`.
This relation does not permit zero steps of the state transition function. -/
def Reaches₁ {σ} (f : σ → Option σ) : σ → σ → Prop 
goal: σ → σ → Prop

full_name: Turing.reaches₁_eq
code: theorem reaches₁_eq {σ} {f : σ → Option σ} {a b c} (h : f a = f b) :
    Reaches₁ f a c ↔ Reaches₁ f b c 
goal: Turing.Reaches₁ f a c ↔ Turing.Reaches₁ f b c

full_name: Turing.reaches_total
code: theorem reaches_total {σ} {f : σ → Option σ} {a b c} (hab : Reaches f a b) (hac : Reaches f a c) :
    Reaches f b c ∨ Reaches f c b 
goal: Turing.Reaches f b c ∨ Turing.Reaches f c b

full_name: Turing.reaches₁_fwd
code: theorem reaches₁_fwd {σ} {f : σ → Option σ} {a b c} (h₁ : Reaches₁ f a c) (h₂ : b ∈ f a) :
    Reaches f b c 
goal: Turing.Reaches f b c

full_name: Turing.Reaches₀
code: /-- A variation on `Reaches`. `Reaches₀ f a b` holds if whenever `Reaches₁ f b c` then
`Reaches₁ f a c`. This is a weaker property than `Reaches` and is useful for replacing states with
equivalent states without taking a step. -/
def Reaches₀ {σ} (f : σ → Option σ) (a b : σ) : Prop 
goal: Prop

full_name: Turing.Reaches₀.trans
code: theorem Reaches₀.trans {σ} {f : σ → Option σ} {a b c : σ} (h₁ : Reaches₀ f a b)
    (h₂ : Reaches₀ f b c) : Reaches₀ f a c
  
goal: Turing.Reaches₀ f a c

full_name: Turing.Reaches₀.refl
code: @[refl]
theorem Reaches₀.refl {σ} {f : σ → Option σ} (a : σ) : Reaches₀ f a a
  
goal: Turing.Reaches₀ f a a

full_name: Turing.Reaches₀.single
code: theorem Reaches₀.single {σ} {f : σ → Option σ} {a b : σ} (h : b ∈ f a) : Reaches₀ f a b
  
goal: Turing.Reaches₀ f a b

full_name: Turing.Reaches₀.head
code: theorem Reaches₀.head {σ} {f : σ → Option σ} {a b c : σ} (h : b ∈ f a) (h₂ : Reaches₀ f b c) :
    Reaches₀ f a c 
goal: Turing.Reaches₀ f a c

full_name: Turing.Reaches₀.tail
code: theorem Reaches₀.tail {σ} {f : σ → Option σ} {a b c : σ} (h₁ : Reaches₀ f a b) (h : c ∈ f b) :
    Reaches₀ f a c 
goal: Turing.Reaches₀ f a c

full_name: Turing.reaches₀_eq
code: theorem reaches₀_eq {σ} {f : σ → Option σ} {a b} (e : f a = f b) : Reaches₀ f a b
  
goal: Turing.Reaches₀ f a b

full_name: Turing.Reaches₁.to₀
code: theorem Reaches₁.to₀ {σ} {f : σ → Option σ} {a b : σ} (h : Reaches₁ f a b) : Reaches₀ f a b
  
goal: Turing.Reaches₀ f a b

full_name: Turing.Reaches.to₀
code: theorem Reaches.to₀ {σ} {f : σ → Option σ} {a b : σ} (h : Reaches f a b) : Reaches₀ f a b
  
goal: Turing.Reaches₀ f a b

full_name: Turing.Reaches₀.tail'
code: theorem Reaches₀.tail' {σ} {f : σ → Option σ} {a b c : σ} (h : Reaches₀ f a b) (h₂ : c ∈ f b) :
    Reaches₁ f a c 
goal: Turing.Reaches₁ f a c

full_name: Turing.evalInduction
code: /-- (co-)Induction principle for `eval`. If a property `C` holds of any point `a` evaluating to `b`
which is either terminal (meaning `a = b`) or where the next point also satisfies `C`, then it
holds of any point where `eval f a` evaluates to `b`. This formalizes the notion that if
`eval f a` evaluates to `b` then it reaches terminal state `b` in finitely many steps. -/
@[elab_as_elim]
def evalInduction {σ} {f : σ → Option σ} {b : σ} {C : σ → Sort*} {a : σ}
    (h : b ∈ eval f a) (H : ∀ a, b ∈ eval f a → (∀ a', f a = some a' → C a') → C a) : C a 
goal: C a

full_name: Turing.mem_eval
code: theorem mem_eval {σ} {f : σ → Option σ} {a b} : b ∈ eval f a ↔ Reaches f a b ∧ f b = none 
goal: b ∈ Turing.eval f a ↔ Turing.Reaches f a b ∧ f b = none

full_name: Turing.eval_maximal₁
code: theorem eval_maximal₁ {σ} {f : σ → Option σ} {a b} (h : b ∈ eval f a) (c) : ¬Reaches₁ f b c
  
goal: ¬Turing.Reaches₁ f b c

full_name: Turing.eval_maximal
code: theorem eval_maximal {σ} {f : σ → Option σ} {a b} (h : b ∈ eval f a) {c} : Reaches f b c ↔ c = b 
goal: Turing.Reaches f b c ↔ c = b

full_name: Turing.reaches_eval
code: theorem reaches_eval {σ} {f : σ → Option σ} {a b} (ab : Reaches f a b) : eval f a = eval f b 
goal: Turing.eval f a = Turing.eval f b

full_name: Turing.Respects
code: /-- Given a relation `tr : σ₁ → σ₂ → Prop` between state spaces, and state transition functions
`f₁ : σ₁ → Option σ₁` and `f₂ : σ₂ → Option σ₂`, `Respects f₁ f₂ tr` means that if `tr a₁ a₂` holds
initially and `f₁` takes a step to `a₂` then `f₂` will take one or more steps before reaching a
state `b₂` satisfying `tr a₂ b₂`, and if `f₁ a₁` terminates then `f₂ a₂` also terminates.
Such a relation `tr` is also known as a refinement. -/
def Respects {σ₁ σ₂} (f₁ : σ₁ → Option σ₁) (f₂ : σ₂ → Option σ₂) (tr : σ₁ → σ₂ → Prop) 
goal: Prop

full_name: Turing.tr_reaches₁
code: theorem tr_reaches₁ {σ₁ σ₂ f₁ f₂} {tr : σ₁ → σ₂ → Prop} (H : Respects f₁ f₂ tr) {a₁ a₂}
    (aa : tr a₁ a₂) {b₁} (ab : Reaches₁ f₁ a₁ b₁) : ∃ b₂, tr b₁ b₂ ∧ Reaches₁ f₂ a₂ b₂ 
goal: ∃ b₂, tr b₁ b₂ ∧ Turing.Reaches₁ f₂ a₂ b₂

full_name: Turing.tr_reaches
code: theorem tr_reaches {σ₁ σ₂ f₁ f₂} {tr : σ₁ → σ₂ → Prop} (H : Respects f₁ f₂ tr) {a₁ a₂}
    (aa : tr a₁ a₂) {b₁} (ab : Reaches f₁ a₁ b₁) : ∃ b₂, tr b₁ b₂ ∧ Reaches f₂ a₂ b₂ 
goal: ∃ b₂, tr b₁ b₂ ∧ Turing.Reaches f₂ a₂ b₂

full_name: Turing.tr_reaches_rev
code: theorem tr_reaches_rev {σ₁ σ₂ f₁ f₂} {tr : σ₁ → σ₂ → Prop} (H : Respects f₁ f₂ tr) {a₁ a₂}
    (aa : tr a₁ a₂) {b₂} (ab : Reaches f₂ a₂ b₂) :
    ∃ c₁ c₂, Reaches f₂ b₂ c₂ ∧ tr c₁ c₂ ∧ Reaches f₁ a₁ c₁ 
goal: ∃ c₁ c₂, Turing.Reaches f₂ b₂ c₂ ∧ tr c₁ c₂ ∧ Turing.Reaches f₁ a₁ c₁

full_name: Turing.tr_eval
code: theorem tr_eval {σ₁ σ₂ f₁ f₂} {tr : σ₁ → σ₂ → Prop} (H : Respects f₁ f₂ tr) {a₁ b₁ a₂}
    (aa : tr a₁ a₂) (ab : b₁ ∈ eval f₁ a₁) : ∃ b₂, tr b₁ b₂ ∧ b₂ ∈ eval f₂ a₂ 
goal: ∃ b₂, tr b₁ b₂ ∧ b₂ ∈ Turing.eval f₂ a₂

full_name: Turing.tr_eval_rev
code: theorem tr_eval_rev {σ₁ σ₂ f₁ f₂} {tr : σ₁ → σ₂ → Prop} (H : Respects f₁ f₂ tr) {a₁ b₂ a₂}
    (aa : tr a₁ a₂) (ab : b₂ ∈ eval f₂ a₂) : ∃ b₁, tr b₁ b₂ ∧ b₁ ∈ eval f₁ a₁ 
goal: ∃ b₁, tr b₁ b₂ ∧ b₁ ∈ Turing.eval f₁ a₁

full_name: Turing.tr_eval_dom
code: theorem tr_eval_dom {σ₁ σ₂ f₁ f₂} {tr : σ₁ → σ₂ → Prop} (H : Respects f₁ f₂ tr) {a₁ a₂}
    (aa : tr a₁ a₂) : (eval f₂ a₂).Dom ↔ (eval f₁ a₁).Dom 
goal: (Turing.eval f₂ a₂).Dom ↔ (Turing.eval f₁ a₁).Dom

full_name: Turing.FRespects
code: /-- A simpler version of `Respects` when the state transition relation `tr` is a function. -/
def FRespects {σ₁ σ₂} (f₂ : σ₂ → Option σ₂) (tr : σ₁ → σ₂) (a₂ : σ₂) : Option σ₁ → Prop
  
goal: Option σ₁ → Prop

full_name: Turing.frespects_eq
code: theorem frespects_eq {σ₁ σ₂} {f₂ : σ₂ → Option σ₂} {tr : σ₁ → σ₂} {a₂ b₂} (h : f₂ a₂ = f₂ b₂) :
    ∀ {b₁}, FRespects f₂ tr a₂ b₁ ↔ FRespects f₂ tr b₂ b₁
  
goal: Turing.FRespects f₂ tr a₂ b₁ ↔ Turing.FRespects f₂ tr b₂ b₁

full_name: Turing.fun_respects
code: theorem fun_respects {σ₁ σ₂ f₁ f₂} {tr : σ₁ → σ₂} :
    (Respects f₁ f₂ fun a b ↦ tr a = b) ↔ ∀ ⦃a₁⦄, FRespects f₂ tr (tr a₁) (f₁ a₁) 
goal: (Turing.Respects f₁ f₂ fun a b => tr a = b) ↔ ∀ ⦃a₁ : σ₁⦄, Turing.FRespects f₂ tr (tr a₁) (f₁ a₁)

full_name: Turing.tr_eval'
code: theorem tr_eval' {σ₁ σ₂} (f₁ : σ₁ → Option σ₁) (f₂ : σ₂ → Option σ₂) (tr : σ₁ → σ₂)
    (H : Respects f₁ f₂ fun a b ↦ tr a = b) (a₁) : eval f₂ (tr a₁) = tr <$> eval f₁ a₁ 
goal: Turing.eval f₂ (tr a₁) = tr <$> Turing.eval f₁ a₁

full_name: Turing.TM0.Stmt.move
code: /-- A Turing machine "statement" is just a command to either move
  left or right, or write a symbol on the tape. -/
inductive Stmt
  | move : Dir → Stmt
  | write : Γ → Stmt
goal: Turing.Dir → Turing.TM0.Stmt Γ

full_name: Turing.TM0.Stmt.write
code: /-- A Turing machine "statement" is just a command to either move
  left or right, or write a symbol on the tape. -/
inductive Stmt
  | move : Dir → Stmt
  | write : Γ → Stmt
goal: Γ → Turing.TM0.Stmt Γ

full_name: Turing.TM0.Stmt
code: /-- A Turing machine "statement" is just a command to either move
  left or right, or write a symbol on the tape. -/
inductive Stmt
  | move : Dir → Stmt
  | write : Γ → Stmt
goal: Type u_1

full_name: Turing.TM0._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM0_termStmt₀_1
code: local notation "Stmt₀" => Stmt Γ
goal: Lean.Macro

full_name: Turing.TM0._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM0_Stmt_1
code: local notation "Stmt₀" => Stmt Γ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM0.Stmt.inhabited
code: instance Stmt.inhabited : Inhabited Stmt₀ 
goal: Inhabited (Turing.TM0.Stmt Γ)

full_name: Turing.TM0.Machine
code: /-- A Post-Turing machine with symbol type `Γ` and label type `Λ`
  is a function which, given the current state `q : Λ` and
  the tape head `a : Γ`, either halts (returns `none`) or returns
  a new state `q' : Λ` and a `Stmt` describing what to do,
  either a move left or right, or a write command.

  Both `Λ` and `Γ` are required to be inhabited; the default value
  for `Γ` is the "blank" tape value, and the default value of `Λ` is
  the initial state. -/
@[nolint unusedArguments] -- this is a deliberate addition, see comment
def Machine [Inhabited Λ] 
goal: Type (max (max u_1 u_2) u_1 u_2)

full_name: Turing.TM0._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM0_Machine_1
code: local notation "Machine₀" => Machine Γ Λ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM0._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM0_termMachine₀_1
code: local notation "Machine₀" => Machine Γ Λ
goal: Lean.Macro

full_name: Turing.TM0.Machine.inhabited
code: instance Machine.inhabited : Inhabited Machine₀ 
goal: Inhabited (Turing.TM0.Machine Γ Λ)

full_name: Turing.TM0.Cfg
code: /-- The configuration state of a Turing machine during operation
  consists of a label (machine state), and a tape.
  The tape is represented in the form `(a, L, R)`, meaning the tape looks like `L.rev ++ [a] ++ R`
  with the machine currently reading the `a`. The lists are
  automatically extended with blanks as the machine moves around. -/
structure Cfg where
  /-- The current machine state. -/
  q : Λ
  /-- The current state of the tape: current symbol, left and right parts. -/
  Tape : Tape Γ
goal: Type (max u_1 u_2)

full_name: Turing.TM0.Cfg.Tape
code: /-- The configuration state of a Turing machine during operation
  consists of a label (machine state), and a tape.
  The tape is represented in the form `(a, L, R)`, meaning the tape looks like `L.rev ++ [a] ++ R`
  with the machine currently reading the `a`. The lists are
  automatically extended with blanks as the machine moves around. -/
structure Cfg where
  /-- The current machine state. -/
  q : Λ
  /-- The current state of the tape: current symbol, left and right parts. -/
  Tape : Tape Γ
goal: Turing.Tape Γ

full_name: Turing.TM0.Cfg.q
code: /-- The configuration state of a Turing machine during operation
  consists of a label (machine state), and a tape.
  The tape is represented in the form `(a, L, R)`, meaning the tape looks like `L.rev ++ [a] ++ R`
  with the machine currently reading the `a`. The lists are
  automatically extended with blanks as the machine moves around. -/
structure Cfg where
  /-- The current machine state. -/
  q : Λ
  /-- The current state of the tape: current symbol, left and right parts. -/
  Tape : Tape Γ
goal: Λ

full_name: Turing.TM0._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM0_Cfg_1
code: local notation "Cfg₀" => Cfg Γ Λ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM0._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM0_termCfg₀_1
code: local notation "Cfg₀" => Cfg Γ Λ
goal: Lean.Macro

full_name: Turing.TM0.Cfg.inhabited
code: instance Cfg.inhabited : Inhabited Cfg₀ 
goal: Inhabited (Turing.TM0.Cfg Γ Λ)

full_name: Turing.TM0.step
code: /-- Execution semantics of the Turing machine. -/
def step (M : Machine₀) : Cfg₀ → Option Cfg₀ 
goal: Turing.TM0.Cfg Γ Λ → Option (Turing.TM0.Cfg Γ Λ)

full_name: Turing.TM0.Reaches
code: /-- The statement `Reaches M s₁ s₂` means that `s₂` is obtained
  starting from `s₁` after a finite number of steps from `s₂`. -/
def Reaches (M : Machine₀) : Cfg₀ → Cfg₀ → Prop 
goal: Turing.TM0.Cfg Γ Λ → Turing.TM0.Cfg Γ Λ → Prop

full_name: Turing.TM0.init
code: /-- The initial configuration. -/
def init (l : List Γ) : Cfg₀ 
goal: Turing.TM0.Cfg Γ Λ

full_name: Turing.TM0.eval
code: /-- Evaluate a Turing machine on initial input to a final state,
  if it terminates. -/
def eval (M : Machine₀) (l : List Γ) : Part (ListBlank Γ) 
goal: Part (Turing.ListBlank Γ)

full_name: Turing.TM0.Supports
code: /-- The raw definition of a Turing machine does not require that
  `Γ` and `Λ` are finite, and in practice we will be interested
  in the infinite `Λ` case. We recover instead a notion of
  "effectively finite" Turing machines, which only make use of a
  finite subset of their states. We say that a set `S ⊆ Λ`
  supports a Turing machine `M` if `S` is closed under the
  transition function and contains the initial state. -/
def Supports (M : Machine₀) (S : Set Λ) 
goal: Prop

full_name: Turing.TM0.step_supports
code: theorem step_supports (M : Machine₀) {S : Set Λ} (ss : Supports M S) :
    ∀ {c c' : Cfg₀}, c' ∈ step M c → c.q ∈ S → c'.q ∈ S 
goal: c' ∈ Turing.TM0.step M c → c.q ∈ S → c'.q ∈ S

full_name: Turing.TM0.univ_supports
code: theorem univ_supports (M : Machine₀) : Supports M Set.univ 
goal: Turing.TM0.Supports M Set.univ

full_name: Turing.TM0.Stmt.map
code: /-- Map a TM statement across a function. This does nothing to move statements and maps the write
values. -/
def Stmt.map (f : PointedMap Γ Γ') : Stmt Γ → Stmt Γ'
  
goal: Turing.TM0.Stmt Γ → Turing.TM0.Stmt Γ'

full_name: Turing.TM0.Cfg.map
code: /-- Map a configuration across a function, given `f : Γ → Γ'` a map of the alphabets and
`g : Λ → Λ'` a map of the machine states. -/
def Cfg.map (f : PointedMap Γ Γ') (g : Λ → Λ') : Cfg Γ Λ → Cfg Γ' Λ'
  
goal: Turing.TM0.Cfg Γ Λ → Turing.TM0.Cfg Γ' Λ'

full_name: Turing.TM0.Machine.map
code: /-- Because the state transition function uses the alphabet and machine states in both the input
and output, to map a machine from one alphabet and machine state space to another we need functions
in both directions, essentially an `Equiv` without the laws. -/
def Machine.map : Machine Γ' Λ'
  
goal: Turing.TM0.Machine Γ' Λ'

full_name: Turing.TM0.Machine.map_step
code: theorem Machine.map_step {S : Set Λ} (f₂₁ : Function.RightInverse f₁ f₂)
    (g₂₁ : ∀ q ∈ S, g₂ (g₁ q) = q) :
    ∀ c : Cfg Γ Λ,
      c.q ∈ S → (step M c).map (Cfg.map f₁ g₁) = step (M.map f₁ f₂ g₁ g₂) (Cfg.map f₁ g₁ c)
  
goal: c.q ∈ S →
  Option.map (Turing.TM0.Cfg.map f₁ g₁) (Turing.TM0.step M c) =
    Turing.TM0.step (M.map f₁ f₂ g₁ g₂) (Turing.TM0.Cfg.map f₁ g₁ c)

full_name: Turing.TM0.map_init
code: theorem map_init (g₁ : PointedMap Λ Λ') (l : List Γ) : (init l).map f₁ g₁ = init (l.map f₁) 
goal: Turing.TM0.Cfg.map f₁ g₁.f (Turing.TM0.init l) = Turing.TM0.init (List.map f₁.f l)

full_name: Turing.TM0.Machine.map_respects
code: theorem Machine.map_respects (g₁ : PointedMap Λ Λ') (g₂ : Λ' → Λ) {S} (ss : Supports M S)
    (f₂₁ : Function.RightInverse f₁ f₂) (g₂₁ : ∀ q ∈ S, g₂ (g₁ q) = q) :
    Respects (step M) (step (M.map f₁ f₂ g₁ g₂)) fun a b ↦ a.q ∈ S ∧ Cfg.map f₁ g₁ a = b 
goal: Turing.Respects (Turing.TM0.step M) (Turing.TM0.step (M.map f₁ f₂ g₁.f g₂)) fun a b =>
  a.q ∈ S ∧ Turing.TM0.Cfg.map f₁ g₁.f a = b

full_name: Turing.TM1.Stmt.load
code: /-- The TM1 model is a simplification and extension of TM0
  (Post-Turing model) in the direction of Wang B-machines. The machine's
  internal state is extended with a (finite) store `σ` of variables
  that may be accessed and updated at any time.
  A machine is given by a `Λ` indexed set of procedures or functions.
  Each function has a body which is a `Stmt`, which can either be a
  `move` or `write` command, a `branch` (if statement based on the
  current tape value), a `load` (set the variable value),
  a `goto` (call another function), or `halt`. Note that here
  most statements do not have labels; `goto` commands can only
  go to a new function. All commands have access to the variable value
  and current tape value. -/
inductive Stmt
  | move : Dir → Stmt → Stmt
  | write : (Γ → σ → Γ) → Stmt → Stmt
  | load : (Γ → σ → σ) → Stmt → Stmt
  | branch : (Γ → σ → Bool) → Stmt → Stmt → Stmt
  | goto : (Γ → σ → Λ) → Stmt
  | halt : Stmt
goal: (Γ → σ → σ) → Turing.TM1.Stmt Γ Λ σ → Turing.TM1.Stmt Γ Λ σ

full_name: Turing.TM1.Stmt.move
code: /-- The TM1 model is a simplification and extension of TM0
  (Post-Turing model) in the direction of Wang B-machines. The machine's
  internal state is extended with a (finite) store `σ` of variables
  that may be accessed and updated at any time.
  A machine is given by a `Λ` indexed set of procedures or functions.
  Each function has a body which is a `Stmt`, which can either be a
  `move` or `write` command, a `branch` (if statement based on the
  current tape value), a `load` (set the variable value),
  a `goto` (call another function), or `halt`. Note that here
  most statements do not have labels; `goto` commands can only
  go to a new function. All commands have access to the variable value
  and current tape value. -/
inductive Stmt
  | move : Dir → Stmt → Stmt
  | write : (Γ → σ → Γ) → Stmt → Stmt
  | load : (Γ → σ → σ) → Stmt → Stmt
  | branch : (Γ → σ → Bool) → Stmt → Stmt → Stmt
  | goto : (Γ → σ → Λ) → Stmt
  | halt : Stmt
goal: Turing.Dir → Turing.TM1.Stmt Γ Λ σ → Turing.TM1.Stmt Γ Λ σ

full_name: Turing.TM1.Stmt.goto
code: /-- The TM1 model is a simplification and extension of TM0
  (Post-Turing model) in the direction of Wang B-machines. The machine's
  internal state is extended with a (finite) store `σ` of variables
  that may be accessed and updated at any time.
  A machine is given by a `Λ` indexed set of procedures or functions.
  Each function has a body which is a `Stmt`, which can either be a
  `move` or `write` command, a `branch` (if statement based on the
  current tape value), a `load` (set the variable value),
  a `goto` (call another function), or `halt`. Note that here
  most statements do not have labels; `goto` commands can only
  go to a new function. All commands have access to the variable value
  and current tape value. -/
inductive Stmt
  | move : Dir → Stmt → Stmt
  | write : (Γ → σ → Γ) → Stmt → Stmt
  | load : (Γ → σ → σ) → Stmt → Stmt
  | branch : (Γ → σ → Bool) → Stmt → Stmt → Stmt
  | goto : (Γ → σ → Λ) → Stmt
  | halt : Stmt
goal: (Γ → σ → Λ) → Turing.TM1.Stmt Γ Λ σ

full_name: Turing.TM1.Stmt.write
code: /-- The TM1 model is a simplification and extension of TM0
  (Post-Turing model) in the direction of Wang B-machines. The machine's
  internal state is extended with a (finite) store `σ` of variables
  that may be accessed and updated at any time.
  A machine is given by a `Λ` indexed set of procedures or functions.
  Each function has a body which is a `Stmt`, which can either be a
  `move` or `write` command, a `branch` (if statement based on the
  current tape value), a `load` (set the variable value),
  a `goto` (call another function), or `halt`. Note that here
  most statements do not have labels; `goto` commands can only
  go to a new function. All commands have access to the variable value
  and current tape value. -/
inductive Stmt
  | move : Dir → Stmt → Stmt
  | write : (Γ → σ → Γ) → Stmt → Stmt
  | load : (Γ → σ → σ) → Stmt → Stmt
  | branch : (Γ → σ → Bool) → Stmt → Stmt → Stmt
  | goto : (Γ → σ → Λ) → Stmt
  | halt : Stmt
goal: (Γ → σ → Γ) → Turing.TM1.Stmt Γ Λ σ → Turing.TM1.Stmt Γ Λ σ

full_name: Turing.TM1.Stmt
code: /-- The TM1 model is a simplification and extension of TM0
  (Post-Turing model) in the direction of Wang B-machines. The machine's
  internal state is extended with a (finite) store `σ` of variables
  that may be accessed and updated at any time.
  A machine is given by a `Λ` indexed set of procedures or functions.
  Each function has a body which is a `Stmt`, which can either be a
  `move` or `write` command, a `branch` (if statement based on the
  current tape value), a `load` (set the variable value),
  a `goto` (call another function), or `halt`. Note that here
  most statements do not have labels; `goto` commands can only
  go to a new function. All commands have access to the variable value
  and current tape value. -/
inductive Stmt
  | move : Dir → Stmt → Stmt
  | write : (Γ → σ → Γ) → Stmt → Stmt
  | load : (Γ → σ → σ) → Stmt → Stmt
  | branch : (Γ → σ → Bool) → Stmt → Stmt → Stmt
  | goto : (Γ → σ → Λ) → Stmt
  | halt : Stmt
goal: Type (max (max u_1 u_2) u_3)

full_name: Turing.TM1.Stmt.branch
code: /-- The TM1 model is a simplification and extension of TM0
  (Post-Turing model) in the direction of Wang B-machines. The machine's
  internal state is extended with a (finite) store `σ` of variables
  that may be accessed and updated at any time.
  A machine is given by a `Λ` indexed set of procedures or functions.
  Each function has a body which is a `Stmt`, which can either be a
  `move` or `write` command, a `branch` (if statement based on the
  current tape value), a `load` (set the variable value),
  a `goto` (call another function), or `halt`. Note that here
  most statements do not have labels; `goto` commands can only
  go to a new function. All commands have access to the variable value
  and current tape value. -/
inductive Stmt
  | move : Dir → Stmt → Stmt
  | write : (Γ → σ → Γ) → Stmt → Stmt
  | load : (Γ → σ → σ) → Stmt → Stmt
  | branch : (Γ → σ → Bool) → Stmt → Stmt → Stmt
  | goto : (Γ → σ → Λ) → Stmt
  | halt : Stmt
goal: (Γ → σ → Bool) → Turing.TM1.Stmt Γ Λ σ → Turing.TM1.Stmt Γ Λ σ → Turing.TM1.Stmt Γ Λ σ

full_name: Turing.TM1.Stmt.halt
code: /-- The TM1 model is a simplification and extension of TM0
  (Post-Turing model) in the direction of Wang B-machines. The machine's
  internal state is extended with a (finite) store `σ` of variables
  that may be accessed and updated at any time.
  A machine is given by a `Λ` indexed set of procedures or functions.
  Each function has a body which is a `Stmt`, which can either be a
  `move` or `write` command, a `branch` (if statement based on the
  current tape value), a `load` (set the variable value),
  a `goto` (call another function), or `halt`. Note that here
  most statements do not have labels; `goto` commands can only
  go to a new function. All commands have access to the variable value
  and current tape value. -/
inductive Stmt
  | move : Dir → Stmt → Stmt
  | write : (Γ → σ → Γ) → Stmt → Stmt
  | load : (Γ → σ → σ) → Stmt → Stmt
  | branch : (Γ → σ → Bool) → Stmt → Stmt → Stmt
  | goto : (Γ → σ → Λ) → Stmt
  | halt : Stmt
goal: Turing.TM1.Stmt Γ Λ σ

full_name: Turing.TM1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Stmt_1
code: local notation "Stmt₁" => Stmt Γ Λ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1_termStmt₁_1
code: local notation "Stmt₁" => Stmt Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM1.Stmt.inhabited
code: instance Stmt.inhabited : Inhabited Stmt₁ 
goal: Inhabited (Turing.TM1.Stmt Γ Λ σ)

full_name: Turing.TM1.Cfg.var
code: /-- The configuration of a TM1 machine is given by the currently
  evaluating statement, the variable store value, and the tape. -/
structure Cfg where
  /-- The statement (if any) which is currently evaluated -/
  l : Option Λ
  /-- The current value of the variable store -/
  var : σ
  /-- The current state of the tape -/
  Tape : Tape Γ
goal: σ

full_name: Turing.TM1.Cfg
code: /-- The configuration of a TM1 machine is given by the currently
  evaluating statement, the variable store value, and the tape. -/
structure Cfg where
  /-- The statement (if any) which is currently evaluated -/
  l : Option Λ
  /-- The current value of the variable store -/
  var : σ
  /-- The current state of the tape -/
  Tape : Tape Γ
goal: Type (max (max u_1 u_2) u_3)

full_name: Turing.TM1.Cfg.l
code: /-- The configuration of a TM1 machine is given by the currently
  evaluating statement, the variable store value, and the tape. -/
structure Cfg where
  /-- The statement (if any) which is currently evaluated -/
  l : Option Λ
  /-- The current value of the variable store -/
  var : σ
  /-- The current state of the tape -/
  Tape : Tape Γ
goal: Option Λ

full_name: Turing.TM1.Cfg.Tape
code: /-- The configuration of a TM1 machine is given by the currently
  evaluating statement, the variable store value, and the tape. -/
structure Cfg where
  /-- The statement (if any) which is currently evaluated -/
  l : Option Λ
  /-- The current value of the variable store -/
  var : σ
  /-- The current state of the tape -/
  Tape : Tape Γ
goal: Turing.Tape Γ

full_name: Turing.TM1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Cfg_1
code: local notation "Cfg₁" => Cfg Γ Λ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1_termCfg₁_1
code: local notation "Cfg₁" => Cfg Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM1.Cfg.inhabited
code: instance Cfg.inhabited [Inhabited σ] : Inhabited Cfg₁ 
goal: Inhabited (Turing.TM1.Cfg Γ Λ σ)

full_name: Turing.TM1.stepAux
code: /-- The semantics of TM1 evaluation. -/
def stepAux : Stmt₁ → σ → Tape Γ → Cfg₁
  
goal: Turing.TM1.Stmt Γ Λ σ → σ → Turing.Tape Γ → Turing.TM1.Cfg Γ Λ σ

full_name: Turing.TM1.step
code: /-- The state transition function. -/
def step (M : Λ → Stmt₁) : Cfg₁ → Option Cfg₁
  
goal: Turing.TM1.Cfg Γ Λ σ → Option (Turing.TM1.Cfg Γ Λ σ)

full_name: Turing.TM1.SupportsStmt
code: /-- A set `S` of labels supports the statement `q` if all the `goto`
  statements in `q` refer only to other functions in `S`. -/
def SupportsStmt (S : Finset Λ) : Stmt₁ → Prop
  
goal: Turing.TM1.Stmt Γ Λ σ → Prop

full_name: Turing.TM1.stmts₁
code: /-- The subterm closure of a statement. -/
noncomputable def stmts₁ : Stmt₁ → Finset Stmt₁
  
goal: Turing.TM1.Stmt Γ Λ σ → Finset (Turing.TM1.Stmt Γ Λ σ)

full_name: Turing.TM1.stmts₁_self
code: theorem stmts₁_self {q : Stmt₁} : q ∈ stmts₁ q 
goal: q ∈ Turing.TM1.stmts₁ q

full_name: Turing.TM1.stmts₁_trans
code: theorem stmts₁_trans {q₁ q₂ : Stmt₁} : q₁ ∈ stmts₁ q₂ → stmts₁ q₁ ⊆ stmts₁ q₂ 
goal: q₁ ∈ Turing.TM1.stmts₁ q₂ → Turing.TM1.stmts₁ q₁ ⊆ Turing.TM1.stmts₁ q₂

full_name: Turing.TM1.stmts₁_supportsStmt_mono
code: theorem stmts₁_supportsStmt_mono {S : Finset Λ} {q₁ q₂ : Stmt₁} (h : q₁ ∈ stmts₁ q₂)
    (hs : SupportsStmt S q₂) : SupportsStmt S q₁ 
goal: Turing.TM1.SupportsStmt S q₁

full_name: Turing.TM1.stmts
code: /-- The set of all statements in a Turing machine, plus one extra value `none` representing the
halt state. This is used in the TM1 to TM0 reduction. -/
noncomputable def stmts (M : Λ → Stmt₁) (S : Finset Λ) : Finset (Option Stmt₁) 
goal: Finset (Option (Turing.TM1.Stmt Γ Λ σ))

full_name: Turing.TM1.stmts_trans
code: theorem stmts_trans {M : Λ → Stmt₁} {S : Finset Λ} {q₁ q₂ : Stmt₁} (h₁ : q₁ ∈ stmts₁ q₂) :
    some q₂ ∈ stmts M S → some q₁ ∈ stmts M S 
goal: some q₂ ∈ Turing.TM1.stmts M S → some q₁ ∈ Turing.TM1.stmts M S

full_name: Turing.TM1.Supports
code: /-- A set `S` of labels supports machine `M` if all the `goto`
  statements in the functions in `S` refer only to other functions
  in `S`. -/
def Supports (M : Λ → Stmt₁) (S : Finset Λ) 
goal: Prop

full_name: Turing.TM1.stmts_supportsStmt
code: theorem stmts_supportsStmt {M : Λ → Stmt₁} {S : Finset Λ} {q : Stmt₁} (ss : Supports M S) :
    some q ∈ stmts M S → SupportsStmt S q 
goal: some q ∈ Turing.TM1.stmts M S → Turing.TM1.SupportsStmt S q

full_name: Turing.TM1.step_supports
code: theorem step_supports (M : Λ → Stmt₁) {S : Finset Λ} (ss : Supports M S) :
    ∀ {c c' : Cfg₁}, c' ∈ step M c → c.l ∈ Finset.insertNone S → c'.l ∈ Finset.insertNone S
  
goal: c' ∈ Turing.TM1.step M c → c.l ∈ Finset.insertNone S → c'.l ∈ Finset.insertNone S

full_name: Turing.TM1.init
code: /-- The initial state, given a finite input that is placed on the tape starting at the TM head and
going to the right. -/
def init (l : List Γ) : Cfg₁ 
goal: Turing.TM1.Cfg Γ Λ σ

full_name: Turing.TM1.eval
code: /-- Evaluate a TM to completion, resulting in an output list on the tape (with an indeterminate
number of blanks on the end). -/
def eval (M : Λ → Stmt₁) (l : List Γ) : Part (ListBlank Γ) 
goal: Part (Turing.ListBlank Γ)

full_name: Turing.TM1to0._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1to0_termStmt₁_1
code: local notation "Stmt₁" => TM1.Stmt Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM1to0._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Stmt_1
code: local notation "Stmt₁" => TM1.Stmt Γ Λ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM1to0._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1to0_termCfg₁_1
code: local notation "Cfg₁" => TM1.Cfg Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM1to0._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Cfg_1
code: local notation "Cfg₁" => TM1.Cfg Γ Λ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM1to0._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1to0_termStmt₀_1
code: local notation "Stmt₀" => TM0.Stmt Γ
goal: Lean.Macro

full_name: Turing.TM1to0._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM0_Stmt_1
code: local notation "Stmt₀" => TM0.Stmt Γ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM1to0.Λ'
code: /-- The base machine state space is a pair of an `Option Stmt₁` representing the current program
to be executed, or `none` for the halt state, and a `σ` which is the local state (stored in the TM,
not the tape). Because there are an infinite number of programs, this state space is infinite, but
for a finitely supported TM1 machine and a finite type `σ`, only finitely many of these states are
reachable. -/
@[nolint unusedArguments] -- We need the M assumption
def Λ' (M : Λ → TM1.Stmt Γ Λ σ) 
goal: Type (max (max (max u_3 u_2) u_1) u_3)

full_name: Turing.TM1to0._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1to0_termΛ'₁₀_1
code: local notation "Λ'₁₀" => Λ' M
goal: Lean.Macro

full_name: Turing.TM1to0._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1to0_Λ'_1
code: local notation "Λ'₁₀" => Λ' M
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM1to0.instInhabitedΛ'
code: instance : Inhabited Λ'₁₀ 
goal: Inhabited (Turing.TM1to0.Λ' M)

full_name: Turing.TM1to0.trAux
code: /-- The core TM1 → TM0 translation function. Here `s` is the current value on the tape, and the
`Stmt₁` is the TM1 statement to translate, with local state `v : σ`. We evaluate all regular
instructions recursively until we reach either a `move` or `write` command, or a `goto`; in the
latter case we emit a dummy `write s` step and transition to the new target location. -/
def trAux (s : Γ) : Stmt₁ → σ → Λ'₁₀ × Stmt₀
  
goal: Turing.TM1.Stmt Γ Λ σ → σ → Turing.TM1to0.Λ' M × Turing.TM0.Stmt Γ

full_name: Turing.TM1to0._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM0_Cfg_1
code: local notation "Cfg₁₀" => TM0.Cfg Γ Λ'₁₀
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM1to0._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1to0_termCfg₁₀_1
code: local notation "Cfg₁₀" => TM0.Cfg Γ Λ'₁₀
goal: Lean.Macro

full_name: Turing.TM1to0.tr
code: /-- The translated TM0 machine (given the TM1 machine input). -/
def tr : TM0.Machine Γ Λ'₁₀
  
goal: Turing.TM0.Machine Γ (Turing.TM1to0.Λ' M)

full_name: Turing.TM1to0.trCfg
code: /-- Translate configurations from TM1 to TM0. -/
def trCfg : Cfg₁ → Cfg₁₀
  
goal: Turing.TM1.Cfg Γ Λ σ → Turing.TM0.Cfg Γ (Turing.TM1to0.Λ' M)

full_name: Turing.TM1to0.tr_respects
code: theorem tr_respects :
    Respects (TM1.step M) (TM0.step (tr M)) fun (c₁ : Cfg₁) (c₂ : Cfg₁₀) ↦ trCfg M c₁ = c₂ 
goal: Turing.Respects (Turing.TM1.step M) (Turing.TM0.step (Turing.TM1to0.tr M)) fun c₁ c₂ => Turing.TM1to0.trCfg M c₁ = c₂

full_name: Turing.TM1to0.tr_eval
code: theorem tr_eval (l : List Γ) : TM0.eval (tr M) l = TM1.eval M l 
goal: Turing.TM0.eval (Turing.TM1to0.tr M) l = Turing.TM1.eval M l

full_name: Turing.TM1to0.trStmts
code: /-- Given a finite set of accessible `Λ` machine states, there is a finite set of accessible
machine states in the target (even though the type `Λ'` is infinite). -/
noncomputable def trStmts (S : Finset Λ) : Finset Λ'₁₀ 
goal: Finset (Turing.TM1to0.Λ' M)

full_name: Turing.TM1to0.tr_supports
code: theorem tr_supports {S : Finset Λ} (ss : TM1.Supports M S) :
    TM0.Supports (tr M) ↑(trStmts M S) 
goal: Turing.TM0.Supports (Turing.TM1to0.tr M) ↑(Turing.TM1to0.trStmts M S)

full_name: Turing.TM1to1.exists_enc_dec
code: theorem exists_enc_dec [Finite Γ] : ∃ (n : ℕ) (enc : Γ → Vector Bool n) (dec : Vector Bool n → Γ),
    enc default = Vector.replicate n false ∧ ∀ a, dec (enc a) = a 
goal: ∃ n enc dec, enc default = Mathlib.Vector.replicate n false ∧ ∀ (a : Γ), dec (enc a) = a

full_name: Turing.TM1to1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Stmt_1
code: local notation "Stmt₁" => Stmt Γ Λ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM1to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1to1_termStmt₁_1
code: local notation "Stmt₁" => Stmt Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM1to1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Cfg_1
code: local notation "Cfg₁" => Cfg Γ Λ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM1to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1to1_termCfg₁_1
code: local notation "Cfg₁" => Cfg Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM1to1.Λ'
code: /-- The configuration state of the TM. -/
inductive Λ'
  | normal : Λ → Λ'
  | write : Γ → Stmt₁ → Λ'
goal: Type (max (max u_1 u_2) u_3)

full_name: Turing.TM1to1.Λ'.normal
code: /-- The configuration state of the TM. -/
inductive Λ'
  | normal : Λ → Λ'
  | write : Γ → Stmt₁ → Λ'
goal: Λ → Turing.TM1to1.Λ'

full_name: Turing.TM1to1.Λ'.write
code: /-- The configuration state of the TM. -/
inductive Λ'
  | normal : Λ → Λ'
  | write : Γ → Stmt₁ → Λ'
goal: Γ → Turing.TM1.Stmt Γ Λ σ → Turing.TM1to1.Λ'

full_name: Turing.TM1to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1to1_termΛ'₁_1
code: local notation "Λ'₁" => @Λ' Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM1to1.instInhabitedΛ'
code: instance : Inhabited Λ'₁ 
goal: Inhabited Turing.TM1to1.Λ'

full_name: Turing.TM1to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1to1_termStmt'₁_1
code: local notation "Stmt'₁" => Stmt Bool Λ'₁ σ
goal: Lean.Macro

full_name: Turing.TM1to1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Stmt_2
code: local notation "Stmt'₁" => Stmt Bool Λ'₁ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM1to1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Cfg_2
code: local notation "Cfg'₁" => Cfg Bool Λ'₁ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM1to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1to1_termCfg'₁_1
code: local notation "Cfg'₁" => Cfg Bool Λ'₁ σ
goal: Lean.Macro

full_name: Turing.TM1to1.readAux
code: /-- Read a vector of length `n` from the tape. -/
def readAux : ∀ n, (Vector Bool n → Stmt'₁) → Stmt'₁
  
goal: (Mathlib.Vector Bool n → Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ) → Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ

full_name: Turing.TM1to1.move
code: /-- A move left or right corresponds to `n` moves across the super-cell. -/
def move (d : Dir) (q : Stmt'₁) : Stmt'₁ 
goal: Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ

full_name: Turing.TM1to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM1to1_termMoveₙ_1
code: local notation "moveₙ" => @move Γ Λ σ n
goal: Lean.Macro

full_name: Turing.TM1to1.read
code: /-- To read a symbol from the tape, we use `readAux` to traverse the symbol,
then return to the original position with `n` moves to the left. -/
def read (f : Γ → Stmt'₁) : Stmt'₁ 
goal: Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ

full_name: Turing.TM1to1.write
code: /-- Write a list of bools on the tape. -/
def write : List Bool → Stmt'₁ → Stmt'₁
  
goal: List Bool → Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ → Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ

full_name: Turing.TM1to1.trNormal
code: /-- Translate a normal instruction. For the `write` command, we use a `goto` indirection so that
we can access the current value of the tape. -/
def trNormal : Stmt₁ → Stmt'₁
  
goal: Turing.TM1.Stmt Γ Λ σ → Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ

full_name: Turing.TM1to1.stepAux_move
code: theorem stepAux_move (d : Dir) (q : Stmt'₁) (v : σ) (T : Tape Bool) :
    stepAux (moveₙ d q) v T = stepAux q v ((Tape.move d)^[n] T) 
goal: Turing.TM1.stepAux (Turing.TM1to1.move d q) v T = Turing.TM1.stepAux q v ((Turing.Tape.move d)^[n] T)

full_name: Turing.TM1to1.supportsStmt_move
code: theorem supportsStmt_move {S : Finset Λ'₁} {d : Dir} {q : Stmt'₁} :
    SupportsStmt S (moveₙ d q) = SupportsStmt S q 
goal: Turing.TM1.SupportsStmt S (Turing.TM1to1.move d q) = Turing.TM1.SupportsStmt S q

full_name: Turing.TM1to1.supportsStmt_write
code: theorem supportsStmt_write {S : Finset Λ'₁} {l : List Bool} {q : Stmt'₁} :
    SupportsStmt S (write l q) = SupportsStmt S q 
goal: Turing.TM1.SupportsStmt S (Turing.TM1to1.write l q) = Turing.TM1.SupportsStmt S q

full_name: Turing.TM1to1.supportsStmt_read
code: theorem supportsStmt_read {S : Finset Λ'₁} :
    ∀ {f : Γ → Stmt'₁}, (∀ a, SupportsStmt S (f a)) → SupportsStmt S (read dec f) 
goal: (∀ (a : Γ), Turing.TM1.SupportsStmt S (f a)) → Turing.TM1.SupportsStmt S (Turing.TM1to1.read dec f)

full_name: Turing.TM1to1.trTape'
code: /-- The low level tape corresponding to the given tape over alphabet `Γ`. -/
def trTape' (L R : ListBlank Γ) : Tape Bool 
goal: Turing.Tape Bool

full_name: Turing.TM1to1.trTape
code: /-- The low level tape corresponding to the given tape over alphabet `Γ`. -/
def trTape (T : Tape Γ) : Tape Bool 
goal: Turing.Tape Bool

full_name: Turing.TM1to1.trTape_mk'
code: theorem trTape_mk' (L R : ListBlank Γ) : trTape enc0 (Tape.mk' L R) = trTape' enc0 L R 
goal: Turing.TM1to1.trTape enc0 (Turing.Tape.mk' L R) = Turing.TM1to1.trTape' enc0 L R

full_name: Turing.TM1to1.tr
code: /-- The top level program. -/
def tr : Λ'₁ → Stmt'₁
  
goal: Turing.TM1to1.Λ' → Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ

full_name: Turing.TM1to1.trCfg
code: /-- The machine configuration translation. -/
def trCfg : Cfg₁ → Cfg'₁
  
goal: Turing.TM1.Cfg Γ Λ σ → Turing.TM1.Cfg Bool Turing.TM1to1.Λ' σ

full_name: Turing.TM1to1.trTape'_move_left
code: theorem trTape'_move_left (L R : ListBlank Γ) :
    (Tape.move Dir.left)^[n] (trTape' enc0 L R) = trTape' enc0 L.tail (R.cons L.head) 
goal: (Turing.Tape.move Turing.Dir.left)^[n] (Turing.TM1to1.trTape' enc0 L R) =
  Turing.TM1to1.trTape' enc0 L.tail (Turing.ListBlank.cons L.head R)

full_name: Turing.TM1to1.trTape'_move_right
code: theorem trTape'_move_right (L R : ListBlank Γ) :
    (Tape.move Dir.right)^[n] (trTape' enc0 L R) = trTape' enc0 (L.cons R.head) R.tail 
goal: (Turing.Tape.move Turing.Dir.right)^[n] (Turing.TM1to1.trTape' enc0 L R) =
  Turing.TM1to1.trTape' enc0 (Turing.ListBlank.cons R.head L) R.tail

full_name: Turing.TM1to1.stepAux_write
code: theorem stepAux_write (q : Stmt'₁) (v : σ) (a b : Γ) (L R : ListBlank Γ) :
    stepAux (write (enc a).toList q) v (trTape' enc0 L (ListBlank.cons b R)) =
      stepAux q v (trTape' enc0 (ListBlank.cons a L) R) 
goal: Turing.TM1.stepAux (Turing.TM1to1.write (enc a).toList q) v (Turing.TM1to1.trTape' enc0 L (Turing.ListBlank.cons b R)) =
  Turing.TM1.stepAux q v (Turing.TM1to1.trTape' enc0 (Turing.ListBlank.cons a L) R)

full_name: Turing.TM1to1.stepAux_read
code: theorem stepAux_read (f : Γ → Stmt'₁) (v : σ) (L R : ListBlank Γ) :
    stepAux (read dec f) v (trTape' enc0 L R) = stepAux (f R.head) v (trTape' enc0 L R) 
goal: Turing.TM1.stepAux (Turing.TM1to1.read dec f) v (Turing.TM1to1.trTape' enc0 L R) =
  Turing.TM1.stepAux (f R.head) v (Turing.TM1to1.trTape' enc0 L R)

full_name: Turing.TM1to1.tr_respects
code: theorem tr_respects {enc₀} :
    Respects (step M) (step (tr enc dec M)) fun c₁ c₂ ↦ trCfg enc enc₀ c₁ = c₂ 
goal: Turing.Respects (Turing.TM1.step M) (Turing.TM1.step (Turing.TM1to1.tr enc dec M)) fun c₁ c₂ =>
  Turing.TM1to1.trCfg enc enc₀ c₁ = c₂

full_name: Turing.TM1to1.writes
code: /-- The set of accessible `Λ'.write` machine states. -/
noncomputable def writes : Stmt₁ → Finset Λ'₁
  
goal: Turing.TM1.Stmt Γ Λ σ → Finset Turing.TM1to1.Λ'

full_name: Turing.TM1to1.trSupp
code: /-- The set of accessible machine states, assuming that the input machine is supported on `S`,
are the normal states embedded from `S`, plus all write states accessible from these states. -/
noncomputable def trSupp (S : Finset Λ) : Finset Λ'₁ 
goal: Finset Turing.TM1to1.Λ'

full_name: Turing.TM1to1.tr_supports
code: theorem tr_supports {S : Finset Λ} (ss : Supports M S) : Supports (tr enc dec M) (trSupp M S) 
goal: Turing.TM1.Supports (Turing.TM1to1.tr enc dec M) (Turing.TM1to1.trSupp M S)

full_name: Turing.TM0to1.Λ'.normal
code: /-- The machine states for a TM1 emulating a TM0 machine. States of the TM0 machine are embedded
as `normal q` states, but the actual operation is split into two parts, a jump to `act s q`
followed by the action and a jump to the next `normal` state. -/
inductive Λ'
  | normal : Λ → Λ'
  | act : TM0.Stmt Γ → Λ → Λ'
goal: Λ → Turing.TM0to1.Λ'

full_name: Turing.TM0to1.Λ'.act
code: /-- The machine states for a TM1 emulating a TM0 machine. States of the TM0 machine are embedded
as `normal q` states, but the actual operation is split into two parts, a jump to `act s q`
followed by the action and a jump to the next `normal` state. -/
inductive Λ'
  | normal : Λ → Λ'
  | act : TM0.Stmt Γ → Λ → Λ'
goal: Turing.TM0.Stmt Γ → Λ → Turing.TM0to1.Λ'

full_name: Turing.TM0to1.Λ'
code: /-- The machine states for a TM1 emulating a TM0 machine. States of the TM0 machine are embedded
as `normal q` states, but the actual operation is split into two parts, a jump to `act s q`
followed by the action and a jump to the next `normal` state. -/
inductive Λ'
  | normal : Λ → Λ'
  | act : TM0.Stmt Γ → Λ → Λ'
goal: Type (max u_1 u_2)

full_name: Turing.TM0to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM0to1_termΛ'₁_1
code: local notation "Λ'₁" => @Λ' Γ Λ
goal: Lean.Macro

full_name: Turing.TM0to1.instInhabitedΛ'
code: instance : Inhabited Λ'₁ 
goal: Inhabited Turing.TM0to1.Λ'

full_name: Turing.TM0to1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM0_Cfg_1
code: local notation "Cfg₀" => TM0.Cfg Γ Λ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM0to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM0to1_termCfg₀_1
code: local notation "Cfg₀" => TM0.Cfg Γ Λ
goal: Lean.Macro

full_name: Turing.TM0to1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Stmt_1
code: local notation "Stmt₁" => TM1.Stmt Γ Λ'₁ Unit
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM0to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM0to1_termStmt₁_1
code: local notation "Stmt₁" => TM1.Stmt Γ Λ'₁ Unit
goal: Lean.Macro

full_name: Turing.TM0to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM0to1_termCfg₁_1
code: local notation "Cfg₁" => TM1.Cfg Γ Λ'₁ Unit
goal: Lean.Macro

full_name: Turing.TM0to1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Cfg_1
code: local notation "Cfg₁" => TM1.Cfg Γ Λ'₁ Unit
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM0to1.tr
code: /-- The program. -/
def tr : Λ'₁ → Stmt₁
  
goal: Turing.TM0to1.Λ' → Turing.TM1.Stmt Γ Turing.TM0to1.Λ' Unit

full_name: Turing.TM0to1.trCfg
code: /-- The configuration translation. -/
def trCfg : Cfg₀ → Cfg₁
  
goal: Turing.TM0.Cfg Γ Λ → Turing.TM1.Cfg Γ Turing.TM0to1.Λ' Unit

full_name: Turing.TM0to1.tr_respects
code: theorem tr_respects : Respects (TM0.step M) (TM1.step (tr M)) fun a b ↦ trCfg M a = b 
goal: Turing.Respects (Turing.TM0.step M) (Turing.TM1.step (Turing.TM0to1.tr M)) fun a b => Turing.TM0to1.trCfg M a = b

full_name: Turing.TM2.Stmt.pop
code: /-- The TM2 model removes the tape entirely from the TM1 model,
  replacing it with an arbitrary (finite) collection of stacks.
  The operation `push` puts an element on one of the stacks,
  and `pop` removes an element from a stack (and modifying the
  internal state based on the result). `peek` modifies the
  internal state but does not remove an element. -/
inductive Stmt
  | push : ∀ k, (σ → Γ k) → Stmt → Stmt
  | peek : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | pop : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | load : (σ → σ) → Stmt → Stmt
  | branch : (σ → Bool) → Stmt → Stmt → Stmt
  | goto : (σ → Λ) → Stmt
  | halt : Stmt
goal: (σ → Option (Γ k) → σ) → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ

full_name: Turing.TM2.Stmt.goto
code: /-- The TM2 model removes the tape entirely from the TM1 model,
  replacing it with an arbitrary (finite) collection of stacks.
  The operation `push` puts an element on one of the stacks,
  and `pop` removes an element from a stack (and modifying the
  internal state based on the result). `peek` modifies the
  internal state but does not remove an element. -/
inductive Stmt
  | push : ∀ k, (σ → Γ k) → Stmt → Stmt
  | peek : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | pop : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | load : (σ → σ) → Stmt → Stmt
  | branch : (σ → Bool) → Stmt → Stmt → Stmt
  | goto : (σ → Λ) → Stmt
  | halt : Stmt
goal: (σ → Λ) → Turing.TM2.Stmt Γ Λ σ

full_name: Turing.TM2.Stmt
code: /-- The TM2 model removes the tape entirely from the TM1 model,
  replacing it with an arbitrary (finite) collection of stacks.
  The operation `push` puts an element on one of the stacks,
  and `pop` removes an element from a stack (and modifying the
  internal state based on the result). `peek` modifies the
  internal state but does not remove an element. -/
inductive Stmt
  | push : ∀ k, (σ → Γ k) → Stmt → Stmt
  | peek : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | pop : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | load : (σ → σ) → Stmt → Stmt
  | branch : (σ → Bool) → Stmt → Stmt → Stmt
  | goto : (σ → Λ) → Stmt
  | halt : Stmt
goal: Type (max (max (max u_1 u_2) u_3) u_4)

full_name: Turing.TM2.Stmt.halt
code: /-- The TM2 model removes the tape entirely from the TM1 model,
  replacing it with an arbitrary (finite) collection of stacks.
  The operation `push` puts an element on one of the stacks,
  and `pop` removes an element from a stack (and modifying the
  internal state based on the result). `peek` modifies the
  internal state but does not remove an element. -/
inductive Stmt
  | push : ∀ k, (σ → Γ k) → Stmt → Stmt
  | peek : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | pop : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | load : (σ → σ) → Stmt → Stmt
  | branch : (σ → Bool) → Stmt → Stmt → Stmt
  | goto : (σ → Λ) → Stmt
  | halt : Stmt
goal: Turing.TM2.Stmt Γ Λ σ

full_name: Turing.TM2.Stmt.load
code: /-- The TM2 model removes the tape entirely from the TM1 model,
  replacing it with an arbitrary (finite) collection of stacks.
  The operation `push` puts an element on one of the stacks,
  and `pop` removes an element from a stack (and modifying the
  internal state based on the result). `peek` modifies the
  internal state but does not remove an element. -/
inductive Stmt
  | push : ∀ k, (σ → Γ k) → Stmt → Stmt
  | peek : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | pop : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | load : (σ → σ) → Stmt → Stmt
  | branch : (σ → Bool) → Stmt → Stmt → Stmt
  | goto : (σ → Λ) → Stmt
  | halt : Stmt
goal: (σ → σ) → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ

full_name: Turing.TM2.Stmt.branch
code: /-- The TM2 model removes the tape entirely from the TM1 model,
  replacing it with an arbitrary (finite) collection of stacks.
  The operation `push` puts an element on one of the stacks,
  and `pop` removes an element from a stack (and modifying the
  internal state based on the result). `peek` modifies the
  internal state but does not remove an element. -/
inductive Stmt
  | push : ∀ k, (σ → Γ k) → Stmt → Stmt
  | peek : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | pop : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | load : (σ → σ) → Stmt → Stmt
  | branch : (σ → Bool) → Stmt → Stmt → Stmt
  | goto : (σ → Λ) → Stmt
  | halt : Stmt
goal: (σ → Bool) → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ

full_name: Turing.TM2.Stmt.peek
code: /-- The TM2 model removes the tape entirely from the TM1 model,
  replacing it with an arbitrary (finite) collection of stacks.
  The operation `push` puts an element on one of the stacks,
  and `pop` removes an element from a stack (and modifying the
  internal state based on the result). `peek` modifies the
  internal state but does not remove an element. -/
inductive Stmt
  | push : ∀ k, (σ → Γ k) → Stmt → Stmt
  | peek : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | pop : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | load : (σ → σ) → Stmt → Stmt
  | branch : (σ → Bool) → Stmt → Stmt → Stmt
  | goto : (σ → Λ) → Stmt
  | halt : Stmt
goal: (σ → Option (Γ k) → σ) → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ

full_name: Turing.TM2.Stmt.push
code: /-- The TM2 model removes the tape entirely from the TM1 model,
  replacing it with an arbitrary (finite) collection of stacks.
  The operation `push` puts an element on one of the stacks,
  and `pop` removes an element from a stack (and modifying the
  internal state based on the result). `peek` modifies the
  internal state but does not remove an element. -/
inductive Stmt
  | push : ∀ k, (σ → Γ k) → Stmt → Stmt
  | peek : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | pop : ∀ k, (σ → Option (Γ k) → σ) → Stmt → Stmt
  | load : (σ → σ) → Stmt → Stmt
  | branch : (σ → Bool) → Stmt → Stmt → Stmt
  | goto : (σ → Λ) → Stmt
  | halt : Stmt
goal: (σ → Γ k) → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ

full_name: Turing.TM2._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM2_termStmt₂_1
code: local notation "Stmt₂" => Stmt Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM2._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM2_Stmt_1
code: local notation "Stmt₂" => Stmt Γ Λ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM2.Stmt.inhabited
code: instance Stmt.inhabited : Inhabited Stmt₂ 
goal: Inhabited (Turing.TM2.Stmt Γ Λ σ)

full_name: Turing.TM2.Cfg.stk
code: /-- A configuration in the TM2 model is a label (or `none` for the halt state), the state of
local variables, and the stacks. (Note that the stacks are not `ListBlank`s, they have a definite
size.) -/
structure Cfg where
  /-- The current label to run (or `none` for the halting state) -/
  l : Option Λ
  /-- The internal state -/
  var : σ
  /-- The (finite) collection of internal stacks -/
  stk : ∀ k, List (Γ k)
goal: List (Γ k)

full_name: Turing.TM2.Cfg.l
code: /-- A configuration in the TM2 model is a label (or `none` for the halt state), the state of
local variables, and the stacks. (Note that the stacks are not `ListBlank`s, they have a definite
size.) -/
structure Cfg where
  /-- The current label to run (or `none` for the halting state) -/
  l : Option Λ
  /-- The internal state -/
  var : σ
  /-- The (finite) collection of internal stacks -/
  stk : ∀ k, List (Γ k)
goal: Option Λ

full_name: Turing.TM2.Cfg.var
code: /-- A configuration in the TM2 model is a label (or `none` for the halt state), the state of
local variables, and the stacks. (Note that the stacks are not `ListBlank`s, they have a definite
size.) -/
structure Cfg where
  /-- The current label to run (or `none` for the halting state) -/
  l : Option Λ
  /-- The internal state -/
  var : σ
  /-- The (finite) collection of internal stacks -/
  stk : ∀ k, List (Γ k)
goal: σ

full_name: Turing.TM2.Cfg
code: /-- A configuration in the TM2 model is a label (or `none` for the halt state), the state of
local variables, and the stacks. (Note that the stacks are not `ListBlank`s, they have a definite
size.) -/
structure Cfg where
  /-- The current label to run (or `none` for the halting state) -/
  l : Option Λ
  /-- The internal state -/
  var : σ
  /-- The (finite) collection of internal stacks -/
  stk : ∀ k, List (Γ k)
goal: Type (max (max (max u_1 u_2) u_3) u_4)

full_name: Turing.TM2._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM2_termCfg₂_1
code: local notation "Cfg₂" => Cfg Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM2._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM2_Cfg_1
code: local notation "Cfg₂" => Cfg Γ Λ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM2.Cfg.inhabited
code: instance Cfg.inhabited [Inhabited σ] : Inhabited Cfg₂ 
goal: Inhabited (Turing.TM2.Cfg Γ Λ σ)

full_name: Turing.TM2.stepAux
code: /-- The step function for the TM2 model. -/
@[simp]
def stepAux : Stmt₂ → σ → (∀ k, List (Γ k)) → Cfg₂
  
goal: Turing.TM2.Stmt Γ Λ σ → σ → ((k : K) → List (Γ k)) → Turing.TM2.Cfg Γ Λ σ

full_name: Turing.TM2.step
code: /-- The step function for the TM2 model. -/
@[simp]
def step (M : Λ → Stmt₂) : Cfg₂ → Option Cfg₂
  
goal: Turing.TM2.Cfg Γ Λ σ → Option (Turing.TM2.Cfg Γ Λ σ)

full_name: Turing.TM2.Reaches
code: /-- The (reflexive) reachability relation for the TM2 model. -/
def Reaches (M : Λ → Stmt₂) : Cfg₂ → Cfg₂ → Prop 
goal: Turing.TM2.Cfg Γ Λ σ → Turing.TM2.Cfg Γ Λ σ → Prop

full_name: Turing.TM2.SupportsStmt
code: /-- Given a set `S` of states, `SupportsStmt S q` means that `q` only jumps to states in `S`. -/
def SupportsStmt (S : Finset Λ) : Stmt₂ → Prop
  
goal: Turing.TM2.Stmt Γ Λ σ → Prop

full_name: Turing.TM2.stmts₁
code: /-- The set of subtree statements in a statement. -/
noncomputable def stmts₁ : Stmt₂ → Finset Stmt₂
  
goal: Turing.TM2.Stmt Γ Λ σ → Finset (Turing.TM2.Stmt Γ Λ σ)

full_name: Turing.TM2.stmts₁_self
code: theorem stmts₁_self {q : Stmt₂} : q ∈ stmts₁ q 
goal: q ∈ Turing.TM2.stmts₁ q

full_name: Turing.TM2.stmts₁_trans
code: theorem stmts₁_trans {q₁ q₂ : Stmt₂} : q₁ ∈ stmts₁ q₂ → stmts₁ q₁ ⊆ stmts₁ q₂ 
goal: q₁ ∈ Turing.TM2.stmts₁ q₂ → Turing.TM2.stmts₁ q₁ ⊆ Turing.TM2.stmts₁ q₂

full_name: Turing.TM2.stmts₁_supportsStmt_mono
code: theorem stmts₁_supportsStmt_mono {S : Finset Λ} {q₁ q₂ : Stmt₂} (h : q₁ ∈ stmts₁ q₂)
    (hs : SupportsStmt S q₂) : SupportsStmt S q₁ 
goal: Turing.TM2.SupportsStmt S q₁

full_name: Turing.TM2.stmts
code: /-- The set of statements accessible from initial set `S` of labels. -/
noncomputable def stmts (M : Λ → Stmt₂) (S : Finset Λ) : Finset (Option Stmt₂) 
goal: Finset (Option (Turing.TM2.Stmt Γ Λ σ))

full_name: Turing.TM2.stmts_trans
code: theorem stmts_trans {M : Λ → Stmt₂} {S : Finset Λ} {q₁ q₂ : Stmt₂} (h₁ : q₁ ∈ stmts₁ q₂) :
    some q₂ ∈ stmts M S → some q₁ ∈ stmts M S 
goal: some q₂ ∈ Turing.TM2.stmts M S → some q₁ ∈ Turing.TM2.stmts M S

full_name: Turing.TM2.Supports
code: /-- Given a TM2 machine `M` and a set `S` of states, `Supports M S` means that all states in
`S` jump only to other states in `S`. -/
def Supports (M : Λ → Stmt₂) (S : Finset Λ) 
goal: Prop

full_name: Turing.TM2.stmts_supportsStmt
code: theorem stmts_supportsStmt {M : Λ → Stmt₂} {S : Finset Λ} {q : Stmt₂} (ss : Supports M S) :
    some q ∈ stmts M S → SupportsStmt S q 
goal: some q ∈ Turing.TM2.stmts M S → Turing.TM2.SupportsStmt S q

full_name: Turing.TM2.step_supports
code: theorem step_supports (M : Λ → Stmt₂) {S : Finset Λ} (ss : Supports M S) :
    ∀ {c c' : Cfg₂}, c' ∈ step M c → c.l ∈ Finset.insertNone S → c'.l ∈ Finset.insertNone S
  
goal: c' ∈ Turing.TM2.step M c → c.l ∈ Finset.insertNone S → c'.l ∈ Finset.insertNone S

full_name: Turing.TM2.init
code: /-- The initial state of the TM2 model. The input is provided on a designated stack. -/
def init (k : K) (L : List (Γ k)) : Cfg₂ 
goal: Turing.TM2.Cfg Γ Λ σ

full_name: Turing.TM2.eval
code: /-- Evaluates a TM2 program to completion, with the output on the same stack as the input. -/
def eval (M : Λ → Stmt₂) (k : K) (L : List (Γ k)) : Part (List (Γ k)) 
goal: Part (List (Γ k))

full_name: Turing.TM2to1.stk_nth_val
code: theorem stk_nth_val {K : Type*} {Γ : K → Type*} {L : ListBlank (∀ k, Option (Γ k))} {k S} (n)
    (hL : ListBlank.map (proj k) L = ListBlank.mk (List.map some S).reverse) :
    L.nth n k = S.reverse.get? n 
goal: L.nth n k = S.reverse.get? n

full_name: Turing.TM2to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM2to1_termStmt₂_1
code: local notation "Stmt₂" => TM2.Stmt Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM2to1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM2_Stmt_1
code: local notation "Stmt₂" => TM2.Stmt Γ Λ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM2to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM2to1_termCfg₂_1
code: local notation "Cfg₂" => TM2.Cfg Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM2to1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM2_Cfg_1
code: local notation "Cfg₂" => TM2.Cfg Γ Λ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM2to1.Γ'
code: /-- The alphabet of the TM2 simulator on TM1 is a marker for the stack bottom,
plus a vector of stack elements for each stack, or none if the stack does not extend this far. -/
def Γ' 
goal: Type (max u_1 u_2)

full_name: Turing.TM2to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM2to1_termΓ'₂₁_1
code: local notation "Γ'₂₁" => @Γ' K Γ
goal: Lean.Macro

full_name: Turing.TM2to1.Γ'.inhabited
code: instance Γ'.inhabited : Inhabited Γ'₂₁ 
goal: Inhabited Turing.TM2to1.Γ'

full_name: Turing.TM2to1.Γ'.fintype
code: instance Γ'.fintype [Fintype K] [∀ k, Fintype (Γ k)] : Fintype Γ'₂₁ 
goal: Fintype Turing.TM2to1.Γ'

full_name: Turing.TM2to1.addBottom
code: /-- The bottom marker is fixed throughout the calculation, so we use the `addBottom` function
to express the program state in terms of a tape with only the stacks themselves. -/
def addBottom (L : ListBlank (∀ k, Option (Γ k))) : ListBlank Γ'₂₁ 
goal: Turing.ListBlank Turing.TM2to1.Γ'

full_name: Turing.TM2to1.addBottom_map
code: theorem addBottom_map (L : ListBlank (∀ k, Option (Γ k))) :
    (addBottom L).map ⟨Prod.snd, by rfl⟩ = L 
goal: Turing.ListBlank.map { f := Prod.snd, map_pt' := ⋯ } (Turing.TM2to1.addBottom L) = L

full_name: Turing.TM2to1.addBottom_modifyNth
code: theorem addBottom_modifyNth (f : (∀ k, Option (Γ k)) → ∀ k, Option (Γ k))
    (L : ListBlank (∀ k, Option (Γ k))) (n : ℕ) :
    (addBottom L).modifyNth (fun a ↦ (a.1, f a.2)) n = addBottom (L.modifyNth f n) 
goal: Turing.ListBlank.modifyNth (fun a => (a.1, f a.2)) n (Turing.TM2to1.addBottom L) =
  Turing.TM2to1.addBottom (Turing.ListBlank.modifyNth f n L)

full_name: Turing.TM2to1.addBottom_nth_snd
code: theorem addBottom_nth_snd (L : ListBlank (∀ k, Option (Γ k))) (n : ℕ) :
    ((addBottom L).nth n).2 = L.nth n 
goal: ((Turing.TM2to1.addBottom L).nth n).2 = L.nth n

full_name: Turing.TM2to1.addBottom_nth_succ_fst
code: theorem addBottom_nth_succ_fst (L : ListBlank (∀ k, Option (Γ k))) (n : ℕ) :
    ((addBottom L).nth (n + 1)).1 = false 
goal: ((Turing.TM2to1.addBottom L).nth (n + 1)).1 = false

full_name: Turing.TM2to1.addBottom_head_fst
code: theorem addBottom_head_fst (L : ListBlank (∀ k, Option (Γ k))) : (addBottom L).head.1 = true 
goal: (Turing.TM2to1.addBottom L).head.1 = true

full_name: Turing.TM2to1.StAct.push
code: /-- A stack action is a command that interacts with the top of a stack. Our default position
is at the bottom of all the stacks, so we have to hold on to this action while going to the end
to modify the stack. -/
inductive StAct (k : K)
  | push : (σ → Γ k) → StAct k
  | peek : (σ → Option (Γ k) → σ) → StAct k
  | pop : (σ → Option (Γ k) → σ) → StAct k
goal: (σ → Γ k) → Turing.TM2to1.StAct k

full_name: Turing.TM2to1.StAct
code: /-- A stack action is a command that interacts with the top of a stack. Our default position
is at the bottom of all the stacks, so we have to hold on to this action while going to the end
to modify the stack. -/
inductive StAct (k : K)
  | push : (σ → Γ k) → StAct k
  | peek : (σ → Option (Γ k) → σ) → StAct k
  | pop : (σ → Option (Γ k) → σ) → StAct k
goal: Type (max u_2 u_4)

full_name: Turing.TM2to1.StAct.peek
code: /-- A stack action is a command that interacts with the top of a stack. Our default position
is at the bottom of all the stacks, so we have to hold on to this action while going to the end
to modify the stack. -/
inductive StAct (k : K)
  | push : (σ → Γ k) → StAct k
  | peek : (σ → Option (Γ k) → σ) → StAct k
  | pop : (σ → Option (Γ k) → σ) → StAct k
goal: (σ → Option (Γ k) → σ) → Turing.TM2to1.StAct k

full_name: Turing.TM2to1.StAct.pop
code: /-- A stack action is a command that interacts with the top of a stack. Our default position
is at the bottom of all the stacks, so we have to hold on to this action while going to the end
to modify the stack. -/
inductive StAct (k : K)
  | push : (σ → Γ k) → StAct k
  | peek : (σ → Option (Γ k) → σ) → StAct k
  | pop : (σ → Option (Γ k) → σ) → StAct k
goal: (σ → Option (Γ k) → σ) → Turing.TM2to1.StAct k

full_name: Turing.TM2to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM2to1_termStAct₂_1
code: local notation "StAct₂" => @StAct K Γ σ
goal: Lean.Macro

full_name: Turing.TM2to1.StAct.inhabited
code: instance StAct.inhabited {k : K} : Inhabited (StAct₂ k) 
goal: Inhabited (Turing.TM2to1.StAct k)

full_name: Turing.TM2to1.stRun
code: /-- The TM2 statement corresponding to a stack action. -/
def stRun {k : K} : StAct₂ k → Stmt₂ → Stmt₂
  
goal: Turing.TM2to1.StAct k → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ

full_name: Turing.TM2to1.stVar
code: /-- The effect of a stack action on the local variables, given the value of the stack. -/
def stVar {k : K} (v : σ) (l : List (Γ k)) : StAct₂ k → σ
  
goal: Turing.TM2to1.StAct k → σ

full_name: Turing.TM2to1.stWrite
code: /-- The effect of a stack action on the stack. -/
def stWrite {k : K} (v : σ) (l : List (Γ k)) : StAct₂ k → List (Γ k)
  
goal: Turing.TM2to1.StAct k → List (Γ k)

full_name: Turing.TM2to1.stmtStRec
code: /-- We have partitioned the TM2 statements into "stack actions", which require going to the end
of the stack, and all other actions, which do not. This is a modified recursor which lumps the
stack actions into one. -/
@[elab_as_elim]
def stmtStRec.{l} {C : Stmt₂ → Sort l} (H₁ : ∀ (k) (s : StAct₂ k) (q) (_ : C q), C (stRun s q))
    (H₂ : ∀ (a q) (_ : C q), C (TM2.Stmt.load a q))
    (H₃ : ∀ (p q₁ q₂) (_ : C q₁) (_ : C q₂), C (TM2.Stmt.branch p q₁ q₂))
    (H₄ : ∀ l, C (TM2.Stmt.goto l)) (H₅ : C TM2.Stmt.halt) : ∀ n, C n
  
goal: C n

full_name: Turing.TM2to1.supports_run
code: theorem supports_run (S : Finset Λ) {k : K} (s : StAct₂ k) (q : Stmt₂) :
    TM2.SupportsStmt S (stRun s q) ↔ TM2.SupportsStmt S q 
goal: Turing.TM2.SupportsStmt S (Turing.TM2to1.stRun s q) ↔ Turing.TM2.SupportsStmt S q

full_name: Turing.TM2to1.Λ'.normal
code: /-- The machine states of the TM2 emulator. We can either be in a normal state when waiting for the
next TM2 action, or we can be in the "go" and "return" states to go to the top of the stack and
return to the bottom, respectively. -/
inductive Λ'
  | normal : Λ → Λ'
  | go (k : K) : StAct₂ k → Stmt₂ → Λ'
  | ret : Stmt₂ → Λ'
goal: Λ → Turing.TM2to1.Λ'

full_name: Turing.TM2to1.Λ'.ret
code: /-- The machine states of the TM2 emulator. We can either be in a normal state when waiting for the
next TM2 action, or we can be in the "go" and "return" states to go to the top of the stack and
return to the bottom, respectively. -/
inductive Λ'
  | normal : Λ → Λ'
  | go (k : K) : StAct₂ k → Stmt₂ → Λ'
  | ret : Stmt₂ → Λ'
goal: Turing.TM2.Stmt Γ Λ σ → Turing.TM2to1.Λ'

full_name: Turing.TM2to1.Λ'.go
code: /-- The machine states of the TM2 emulator. We can either be in a normal state when waiting for the
next TM2 action, or we can be in the "go" and "return" states to go to the top of the stack and
return to the bottom, respectively. -/
inductive Λ'
  | normal : Λ → Λ'
  | go (k : K) : StAct₂ k → Stmt₂ → Λ'
  | ret : Stmt₂ → Λ'
goal: Turing.TM2to1.StAct k → Turing.TM2.Stmt Γ Λ σ → Turing.TM2to1.Λ'

full_name: Turing.TM2to1.Λ'
code: /-- The machine states of the TM2 emulator. We can either be in a normal state when waiting for the
next TM2 action, or we can be in the "go" and "return" states to go to the top of the stack and
return to the bottom, respectively. -/
inductive Λ'
  | normal : Λ → Λ'
  | go (k : K) : StAct₂ k → Stmt₂ → Λ'
  | ret : Stmt₂ → Λ'
goal: Type (max (max (max u_1 u_2) u_3) u_4)

full_name: Turing.TM2to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM2to1_termΛ'₂₁_1
code: local notation "Λ'₂₁" => @Λ' K Γ Λ σ
goal: Lean.Macro

full_name: Turing.TM2to1.Λ'.inhabited
code: instance Λ'.inhabited : Inhabited Λ'₂₁ 
goal: Inhabited Turing.TM2to1.Λ'

full_name: Turing.TM2to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM2to1_termStmt₂₁_1
code: local notation "Stmt₂₁" => TM1.Stmt Γ'₂₁ Λ'₂₁ σ
goal: Lean.Macro

full_name: Turing.TM2to1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Stmt_1
code: local notation "Stmt₂₁" => TM1.Stmt Γ'₂₁ Λ'₂₁ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM2to1._aux_Mathlib_Computability_TuringMachine___unexpand_Turing_TM1_Cfg_1
code: local notation "Cfg₂₁" => TM1.Cfg Γ'₂₁ Λ'₂₁ σ
goal: Lean.PrettyPrinter.Unexpander

full_name: Turing.TM2to1._aux_Mathlib_Computability_TuringMachine___macroRules_Turing_TM2to1_termCfg₂₁_1
code: local notation "Cfg₂₁" => TM1.Cfg Γ'₂₁ Λ'₂₁ σ
goal: Lean.Macro

full_name: Turing.TM2to1.trStAct
code: /-- The program corresponding to state transitions at the end of a stack. Here we start out just
after the top of the stack, and should end just after the new top of the stack. -/
def trStAct {k : K} (q : Stmt₂₁) : StAct₂ k → Stmt₂₁
  
goal: Turing.TM2to1.StAct k → Turing.TM1.Stmt Turing.TM2to1.Γ' Turing.TM2to1.Λ' σ

full_name: Turing.TM2to1.trInit
code: /-- The initial state for the TM2 emulator, given an initial TM2 state. All stacks start out empty
except for the input stack, and the stack bottom mark is set at the head. -/
def trInit (k : K) (L : List (Γ k)) : List Γ'₂₁ 
goal: List Turing.TM2to1.Γ'

full_name: Turing.TM2to1.step_run
code: theorem step_run {k : K} (q : Stmt₂) (v : σ) (S : ∀ k, List (Γ k)) : ∀ s : StAct₂ k,
    TM2.stepAux (stRun s q) v S = TM2.stepAux q (stVar v (S k) s) (update S k (stWrite v (S k) s))
  
goal: Turing.TM2.stepAux (Turing.TM2to1.stRun s q) v S =
  Turing.TM2.stepAux q (Turing.TM2to1.stVar v (S k) s) (Function.update S k (Turing.TM2to1.stWrite v (S k) s))

full_name: Turing.TM2to1.trNormal
code: /-- The translation of TM2 statements to TM1 statements. regular actions have direct equivalents,
but stack actions are deferred by going to the corresponding `go` state, so that we can find the
appropriate stack top. -/
def trNormal : Stmt₂ → Stmt₂₁
  
goal: Turing.TM2.Stmt Γ Λ σ → Turing.TM1.Stmt Turing.TM2to1.Γ' Turing.TM2to1.Λ' σ

full_name: Turing.TM2to1.trNormal_run
code: theorem trNormal_run {k : K} (s : StAct₂ k) (q : Stmt₂) :
    trNormal (stRun s q) = goto fun _ _ ↦ go k s q 
goal: Turing.TM2to1.trNormal (Turing.TM2to1.stRun s q) = Turing.TM1.Stmt.goto fun x x => Turing.TM2to1.Λ'.go k s q

full_name: Turing.TM2to1.trStmts₁
code: /-- The set of machine states accessible from an initial TM2 statement. -/
noncomputable def trStmts₁ : Stmt₂ → Finset Λ'₂₁
  
goal: Turing.TM2.Stmt Γ Λ σ → Finset Turing.TM2to1.Λ'

full_name: Turing.TM2to1.trStmts₁_run
code: theorem trStmts₁_run {k : K} {s : StAct₂ k} {q : Stmt₂} :
    trStmts₁ (stRun s q) = {go k s q, ret q} ∪ trStmts₁ q 
goal: Turing.TM2to1.trStmts₁ (Turing.TM2to1.stRun s q) =
  {Turing.TM2to1.Λ'.go k s q, Turing.TM2to1.Λ'.ret q} ∪ Turing.TM2to1.trStmts₁ q

full_name: Turing.TM2to1.tr_respects_aux₂
code: theorem tr_respects_aux₂ {k : K} {q : Stmt₂₁} {v : σ} {S : ∀ k, List (Γ k)}
    {L : ListBlank (∀ k, Option (Γ k))}
    (hL : ∀ k, L.map (proj k) = ListBlank.mk ((S k).map some).reverse) (o : StAct₂ k) :
    let v' := stVar v (S k) o
    let Sk' := stWrite v (S k) o
    let S' := update S k Sk'
    ∃ L' : ListBlank (∀ k, Option (Γ k)),
      (∀ k, L'.map (proj k) = ListBlank.mk ((S' k).map some).reverse) ∧
        TM1.stepAux (trStAct q o) v
            ((Tape.move Dir.right)^[(S k).length] (Tape.mk' ∅ (addBottom L))) =
          TM1.stepAux q v' ((Tape.move Dir.right)^[(S' k).length] (Tape.mk' ∅ (addBottom L'))) 
goal: let v' := Turing.TM2to1.stVar v (S k) o;
let Sk' := Turing.TM2to1.stWrite v (S k) o;
let S' := Function.update S k Sk';
∃ L',
  (∀ (k : K), Turing.ListBlank.map (Turing.proj k) L' = Turing.ListBlank.mk (List.map some (S' k)).reverse) ∧
    Turing.TM1.stepAux (Turing.TM2to1.trStAct q o) v
        ((Turing.Tape.move Turing.Dir.right)^[(S k).length] (Turing.Tape.mk' ∅ (Turing.TM2to1.addBottom L))) =
      Turing.TM1.stepAux q v'
        ((Turing.Tape.move Turing.Dir.right)^[(S' k).length] (Turing.Tape.mk' ∅ (Turing.TM2to1.addBottom L')))

full_name: Turing.TM2to1.tr
code: /-- The TM2 emulator machine states written as a TM1 program.
This handles the `go` and `ret` states, which shuttle to and from a stack top. -/
def tr : Λ'₂₁ → Stmt₂₁
  
goal: Turing.TM2to1.Λ' → Turing.TM1.Stmt Turing.TM2to1.Γ' Turing.TM2to1.Λ' σ

full_name: Turing.TM2to1.TrCfg.mk
code: /-- The relation between TM2 configurations and TM1 configurations of the TM2 emulator. -/
inductive TrCfg : Cfg₂ → Cfg₂₁ → Prop
  | mk {q : Option Λ} {v : σ} {S : ∀ k, List (Γ k)} (L : ListBlank (∀ k, Option (Γ k))) :
    (∀ k, L.map (proj k) = ListBlank.mk ((S k).map some).reverse) →
      TrCfg ⟨q, v, S⟩ ⟨q.map normal, v, Tape.mk' ∅ (addBottom L)⟩
goal: (∀ (k : K), Turing.ListBlank.map (Turing.proj k) L = Turing.ListBlank.mk (List.map some (S k)).reverse) →
  Turing.TM2to1.TrCfg { l := q, var := v, stk := S }
    { l := Option.map Turing.TM2to1.Λ'.normal q, var := v, Tape := Turing.Tape.mk' ∅ (Turing.TM2to1.addBottom L) }

full_name: Turing.TM2to1.TrCfg
code: /-- The relation between TM2 configurations and TM1 configurations of the TM2 emulator. -/
inductive TrCfg : Cfg₂ → Cfg₂₁ → Prop
  | mk {q : Option Λ} {v : σ} {S : ∀ k, List (Γ k)} (L : ListBlank (∀ k, Option (Γ k))) :
    (∀ k, L.map (proj k) = ListBlank.mk ((S k).map some).reverse) →
      TrCfg ⟨q, v, S⟩ ⟨q.map normal, v, Tape.mk' ∅ (addBottom L)⟩
goal: Turing.TM2.Cfg Γ Λ σ → Turing.TM1.Cfg Turing.TM2to1.Γ' Turing.TM2to1.Λ' σ → Prop

full_name: Turing.TM2to1.tr_respects_aux₁
code: theorem tr_respects_aux₁ {k} (o q v) {S : List (Γ k)} {L : ListBlank (∀ k, Option (Γ k))}
    (hL : L.map (proj k) = ListBlank.mk (S.map some).reverse) (n) (H : n ≤ S.length) :
    Reaches₀ (TM1.step (tr M)) ⟨some (go k o q), v, Tape.mk' ∅ (addBottom L)⟩
      ⟨some (go k o q), v, (Tape.move Dir.right)^[n] (Tape.mk' ∅ (addBottom L))⟩ 
goal: Turing.Reaches₀ (Turing.TM1.step (Turing.TM2to1.tr M))
  { l := some (Turing.TM2to1.Λ'.go k o q), var := v, Tape := Turing.Tape.mk' ∅ (Turing.TM2to1.addBottom L) }
  { l := some (Turing.TM2to1.Λ'.go k o q), var := v,
    Tape := (Turing.Tape.move Turing.Dir.right)^[n] (Turing.Tape.mk' ∅ (Turing.TM2to1.addBottom L)) }

full_name: Turing.TM2to1.tr_respects_aux₃
code: theorem tr_respects_aux₃ {q v} {L : ListBlank (∀ k, Option (Γ k))} (n) : Reaches₀ (TM1.step (tr M))
    ⟨some (ret q), v, (Tape.move Dir.right)^[n] (Tape.mk' ∅ (addBottom L))⟩
    ⟨some (ret q), v, Tape.mk' ∅ (addBottom L)⟩ 
goal: Turing.Reaches₀ (Turing.TM1.step (Turing.TM2to1.tr M))
  { l := some (Turing.TM2to1.Λ'.ret q), var := v,
    Tape := (Turing.Tape.move Turing.Dir.right)^[n] (Turing.Tape.mk' ∅ (Turing.TM2to1.addBottom L)) }
  { l := some (Turing.TM2to1.Λ'.ret q), var := v, Tape := Turing.Tape.mk' ∅ (Turing.TM2to1.addBottom L) }

full_name: Turing.TM2to1.tr_respects_aux
code: theorem tr_respects_aux {q v T k} {S : ∀ k, List (Γ k)}
    (hT : ∀ k, ListBlank.map (proj k) T = ListBlank.mk ((S k).map some).reverse) (o : StAct₂ k)
    (IH : ∀ {v : σ} {S : ∀ k : K, List (Γ k)} {T : ListBlank (∀ k, Option (Γ k))},
      (∀ k, ListBlank.map (proj k) T = ListBlank.mk ((S k).map some).reverse) →
      ∃ b, TrCfg (TM2.stepAux q v S) b ∧
        Reaches (TM1.step (tr M)) (TM1.stepAux (trNormal q) v (Tape.mk' ∅ (addBottom T))) b) :
    ∃ b, TrCfg (TM2.stepAux (stRun o q) v S) b ∧ Reaches (TM1.step (tr M))
      (TM1.stepAux (trNormal (stRun o q)) v (Tape.mk' ∅ (addBottom T))) b 
goal: ∃ b,
  Turing.TM2to1.TrCfg (Turing.TM2.stepAux (Turing.TM2to1.stRun o q) v S) b ∧
    Turing.Reaches (Turing.TM1.step (Turing.TM2to1.tr M))
      (Turing.TM1.stepAux (Turing.TM2to1.trNormal (Turing.TM2to1.stRun o q)) v
        (Turing.Tape.mk' ∅ (Turing.TM2to1.addBottom T)))
      b

full_name: Turing.TM2to1.tr_respects
code: theorem tr_respects : Respects (TM2.step M) (TM1.step (tr M)) TrCfg 
goal: Turing.Respects (Turing.TM2.step M) (Turing.TM1.step (Turing.TM2to1.tr M)) Turing.TM2to1.TrCfg

full_name: Turing.TM2to1.trCfg_init
code: theorem trCfg_init (k) (L : List (Γ k)) : TrCfg (TM2.init k L) (TM1.init (trInit k L) : Cfg₂₁) 
goal: Turing.TM2to1.TrCfg (Turing.TM2.init k L) (Turing.TM1.init (Turing.TM2to1.trInit k L))

full_name: Turing.TM2to1.tr_eval_dom
code: theorem tr_eval_dom (k) (L : List (Γ k)) :
    (TM1.eval (tr M) (trInit k L)).Dom ↔ (TM2.eval M k L).Dom 
goal: (Turing.TM1.eval (Turing.TM2to1.tr M) (Turing.TM2to1.trInit k L)).Dom ↔ (Turing.TM2.eval M k L).Dom

full_name: Turing.TM2to1.tr_eval
code: theorem tr_eval (k) (L : List (Γ k)) {L₁ L₂} (H₁ : L₁ ∈ TM1.eval (tr M) (trInit k L))
    (H₂ : L₂ ∈ TM2.eval M k L) :
    ∃ (S : ∀ k, List (Γ k)) (L' : ListBlank (∀ k, Option (Γ k))),
      addBottom L' = L₁ ∧
        (∀ k, L'.map (proj k) = ListBlank.mk ((S k).map some).reverse) ∧ S k = L₂ 
goal: ∃ S L',
  Turing.TM2to1.addBottom L' = L₁ ∧
    (∀ (k : K), Turing.ListBlank.map (Turing.proj k) L' = Turing.ListBlank.mk (List.map some (S k)).reverse) ∧ S k = L₂

full_name: Turing.TM2to1.trSupp
code: /-- The support of a set of TM2 states in the TM2 emulator. -/
noncomputable def trSupp (S : Finset Λ) : Finset Λ'₂₁ 
goal: Finset Turing.TM2to1.Λ'

full_name: Turing.TM2to1.tr_supports
code: theorem tr_supports {S} (ss : TM2.Supports M S) : TM1.Supports (tr M) (trSupp M S) 
goal: Turing.TM1.Supports (Turing.TM2to1.tr M) (Turing.TM2to1.trSupp M S)