Turing machines #

This file defines a sequence of simple machine languages, starting with Turing machines and working up to more complex languages based on Wang B-machines.

Naming conventions #

Each model of computation in this file shares a naming convention for the elements of a model of computation. These are the parameters for the language:

• Γ is the alphabet on the tape.
• Λ is the set of labels, or internal machine states.
• σ is the type of internal memory, not on the tape. This does not exist in the TM0 model, and later models achieve this by mixing it into Λ.
• K is used in the TM2 model, which has multiple stacks, and denotes the number of such stacks.

All of these variables denote "essentially finite" types, but for technical reasons it is convenient to allow them to be infinite anyway. When using an infinite type, we will be interested to prove that only finitely many values of the type are ever interacted with.

Given these parameters, there are a few common structures for the model that arise:

• Stmt is the set of all actions that can be performed in one step. For the TM0 model this set is finite, and for later models it is an infinite inductive type representing "possible program texts".
• Cfg is the set of instantaneous configurations, that is, the state of the machine together with its environment.
• Machine is the set of all machines in the model. Usually this is approximately a function Λ → Stmt, although different models have different ways of halting and other actions.
• step : Cfg → Option Cfg is the function that describes how the state evolves over one step. If step c = none, then c is a terminal state, and the result of the computation is read off from c. Because of the type of step, these models are all deterministic by construction.
• init : Input → Cfg sets up the initial state. The type Input depends on the model; in most cases it is List Γ.
• eval : Machine → Input → Part Output, given a machine M and input i, starts from init i, runs step until it reaches an output, and then applies a function Cfg → Output to the final state to obtain the result. The type Output depends on the model.
• Supports : Machine → Finset Λ → Prop asserts that a machine M starts in S : Finset Λ, and can only ever jump to other states inside S. This implies that the behavior of M on any input cannot depend on its values outside S. We use this to allow Λ to be an infinite set when convenient, and prove that only finitely many of these states are actually accessible. This formalizes "essentially finite" mentioned above.
def Turing.BlankExtends {Γ : Type u_1} [] (l₁ : List Γ) (l₂ : List Γ) :

The BlankExtends partial order holds of l₁ and l₂ if l₂ is obtained by adding blanks (default : Γ) to the end of l₁.

Equations
Instances For
theorem Turing.BlankExtends.refl {Γ : Type u_1} [] (l : List Γ) :
theorem Turing.BlankExtends.trans {Γ : Type u_1} [] {l₁ : List Γ} {l₂ : List Γ} {l₃ : List Γ} :
theorem Turing.BlankExtends.below_of_le {Γ : Type u_1} [] {l : List Γ} {l₁ : List Γ} {l₂ : List Γ} :
l₁.length l₂.length
def Turing.BlankExtends.above {Γ : Type u_1} [] {l : List Γ} {l₁ : List Γ} {l₂ : List Γ} (h₁ : ) (h₂ : ) :
{ l' : List Γ // }

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₂).

Equations
• h₁.above h₂ = if h : l₁.length l₂.length then l₂, else l₁,
Instances For
theorem Turing.BlankExtends.above_of_le {Γ : Type u_1} [] {l : List Γ} {l₁ : List Γ} {l₂ : List Γ} :
l₁.length l₂.length
def Turing.BlankRel {Γ : Type u_1} [] (l₁ : List Γ) (l₂ : List Γ) :

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.

Equations
Instances For
theorem Turing.BlankRel.refl {Γ : Type u_1} [] (l : List Γ) :
theorem Turing.BlankRel.symm {Γ : Type u_1} [] {l₁ : List Γ} {l₂ : List Γ} :
Turing.BlankRel l₁ l₂Turing.BlankRel l₂ l₁
theorem Turing.BlankRel.trans {Γ : Type u_1} [] {l₁ : List Γ} {l₂ : List Γ} {l₃ : List Γ} :
Turing.BlankRel l₁ l₂Turing.BlankRel l₂ l₃Turing.BlankRel l₁ l₃
def Turing.BlankRel.above {Γ : Type u_1} [] {l₁ : List Γ} {l₂ : List Γ} (h : Turing.BlankRel l₁ l₂) :
{ l : List Γ // }

Given two BlankRel lists, there exists (constructively) a common join.

Equations
• h.above = if hl : l₁.length l₂.length then l₂, else l₁,
Instances For
def Turing.BlankRel.below {Γ : Type u_1} [] {l₁ : List Γ} {l₂ : List Γ} (h : Turing.BlankRel l₁ l₂) :
{ l : List Γ // }

Given two BlankRel lists, there exists (constructively) a common meet.

Equations
• h.below = if hl : l₁.length l₂.length then l₁, else l₂,
Instances For
theorem Turing.BlankRel.equivalence (Γ : Type u_1) [] :
Equivalence Turing.BlankRel
def Turing.BlankRel.setoid (Γ : Type u_1) [] :

Construct a setoid instance for BlankRel.

Equations
• = { r := Turing.BlankRel, iseqv := }
Instances For
def Turing.ListBlank (Γ : Type u_1) [] :
Type u_1

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.

Equations
Instances For
instance Turing.ListBlank.inhabited {Γ : Type u_1} [] :
Equations
• Turing.ListBlank.inhabited = { default := }
instance Turing.ListBlank.hasEmptyc {Γ : Type u_1} [] :
Equations
• Turing.ListBlank.hasEmptyc = { emptyCollection := }
@[reducible, inline]
abbrev Turing.ListBlank.liftOn {Γ : Type u_1} [] {α : Sort u_2} (l : ) (f : List Γα) (H : ∀ (a b : List Γ), f a = f b) :
α

A modified version of Quotient.liftOn' specialized for ListBlank, with the stronger precondition BlankExtends instead of BlankRel.

Equations
• l.liftOn f H =
Instances For
def Turing.ListBlank.mk {Γ : Type u_1} [] :
List Γ

The quotient map turning a List into a ListBlank.

Equations
• Turing.ListBlank.mk = Quotient.mk''
Instances For
theorem Turing.ListBlank.induction_on {Γ : Type u_1} [] {p : } (q : ) (h : ∀ (a : List Γ), p ) :
p q
def Turing.ListBlank.head {Γ : Type u_1} [] (l : ) :
Γ

The head of a ListBlank is well defined.

Equations
Instances For
@[simp]
theorem Turing.ListBlank.head_mk {Γ : Type u_1} [] (l : List Γ) :
def Turing.ListBlank.tail {Γ : Type u_1} [] (l : ) :

The tail of a ListBlank is well defined (up to the tail of blanks).

Equations
Instances For
@[simp]
theorem Turing.ListBlank.tail_mk {Γ : Type u_1} [] (l : List Γ) :
.tail = Turing.ListBlank.mk l.tail
def Turing.ListBlank.cons {Γ : Type u_1} [] (a : Γ) (l : ) :

We can cons an element onto a ListBlank.

Equations
Instances For
@[simp]
theorem Turing.ListBlank.cons_mk {Γ : Type u_1} [] (a : Γ) (l : List Γ) :
@[simp]
theorem Turing.ListBlank.head_cons {Γ : Type u_1} [] (a : Γ) (l : ) :
@[simp]
theorem Turing.ListBlank.tail_cons {Γ : Type u_1} [] (a : Γ) (l : ) :
().tail = l
@[simp]
theorem Turing.ListBlank.cons_head_tail {Γ : Type u_1} [] (l : ) :

The cons and head/tail functions are mutually inverse, unlike in the case of List where this only holds for nonempty lists.

theorem Turing.ListBlank.exists_cons {Γ : Type u_1} [] (l : ) :
∃ (a : Γ) (l' : ), l =

The cons and head/tail functions are mutually inverse, unlike in the case of List where this only holds for nonempty lists.

def Turing.ListBlank.nth {Γ : Type u_1} [] (l : ) (n : ) :
Γ

The n-th element of a ListBlank is well defined for all n : ℕ, unlike in a List.

Equations
• l.nth n = l.liftOn (fun (l : List Γ) => l.getI n)
Instances For
@[simp]
theorem Turing.ListBlank.nth_mk {Γ : Type u_1} [] (l : List Γ) (n : ) :
.nth n = l.getI n
@[simp]
theorem Turing.ListBlank.nth_zero {Γ : Type u_1} [] (l : ) :
@[simp]
theorem Turing.ListBlank.nth_succ {Γ : Type u_1} [] (l : ) (n : ) :
l.nth (n + 1) = l.tail.nth n
theorem Turing.ListBlank.ext {Γ : Type u_1} [i : ] {L₁ : } {L₂ : } :
(∀ (i_1 : ), L₁.nth i_1 = L₂.nth i_1)L₁ = L₂
def Turing.ListBlank.modifyNth {Γ : Type u_1} [] (f : ΓΓ) :

Apply a function to a value stored at the nth position of the list.

Equations
Instances For
theorem Turing.ListBlank.nth_modifyNth {Γ : Type u_1} [] (f : ΓΓ) (n : ) (i : ) (L : ) :
().nth i = if i = n then f (L.nth i) else L.nth i
structure Turing.PointedMap (Γ : Type u) (Γ' : Type v) [] [] :
Type (max u v)

A pointed map of Inhabited types is a map that sends one default value to the other.

• f : ΓΓ'

The map underlying this instance.

• map_pt' : self.f default = default
Instances For
theorem Turing.PointedMap.map_pt' {Γ : Type u} {Γ' : Type v} [] [] (self : ) :
self.f default = default
instance Turing.instInhabitedPointedMap {Γ : Type u_1} {Γ' : Type u_2} [] [] :
Equations
• Turing.instInhabitedPointedMap = { default := { f := default, map_pt' := } }
instance Turing.instCoeFunPointedMapForall {Γ : Type u_1} {Γ' : Type u_2} [] [] :
CoeFun () fun (x : ) => ΓΓ'
Equations
• Turing.instCoeFunPointedMapForall = { coe := Turing.PointedMap.f }
theorem Turing.PointedMap.mk_val {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ΓΓ') (pt : f default = default) :
{ f := f, map_pt' := pt }.f = f
@[simp]
theorem Turing.PointedMap.map_pt {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) :
f.f default = default
@[simp]
theorem Turing.PointedMap.headI_map {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (l : List Γ) :
def Turing.ListBlank.map {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (l : ) :

The map function on lists is well defined on ListBlanks provided that the map is pointed.

Equations
Instances For
@[simp]
theorem Turing.ListBlank.map_mk {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (l : List Γ) :
@[simp]
theorem Turing.ListBlank.head_map {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (l : ) :
@[simp]
theorem Turing.ListBlank.tail_map {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (l : ) :
().tail = Turing.ListBlank.map f l.tail
@[simp]
theorem Turing.ListBlank.map_cons {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (l : ) (a : Γ) :
@[simp]
theorem Turing.ListBlank.nth_map {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (l : ) (n : ) :
().nth n = f.f (l.nth n)
def Turing.proj {ι : Type u_1} {Γ : ιType u_2} [(i : ι) → Inhabited (Γ i)] (i : ι) :
Turing.PointedMap ((i : ι) → Γ i) (Γ i)

The i-th projection as a pointed map.

Equations
• = { f := fun (a : (i : ι) → Γ i) => a i, map_pt' := }
Instances For
theorem Turing.proj_map_nth {ι : Type u_1} {Γ : ιType u_2} [(i : ι) → Inhabited (Γ i)] (i : ι) (L : Turing.ListBlank ((i : ι) → Γ i)) (n : ) :
().nth n = L.nth n i
theorem Turing.ListBlank.map_modifyNth {Γ : Type u_1} {Γ' : Type u_2} [] [] (F : ) (f : ΓΓ) (f' : Γ'Γ') (H : ∀ (x : Γ), F.f (f x) = f' (F.f x)) (n : ) (L : ) :
def Turing.ListBlank.append {Γ : Type u_1} [] :
List Γ

Append a list on the left side of a ListBlank.

Equations
Instances For
@[simp]
theorem Turing.ListBlank.append_mk {Γ : Type u_1} [] (l₁ : List Γ) (l₂ : List Γ) :
= Turing.ListBlank.mk (l₁ ++ l₂)
theorem Turing.ListBlank.append_assoc {Γ : Type u_1} [] (l₁ : List Γ) (l₂ : List Γ) (l₃ : ) :
Turing.ListBlank.append (l₁ ++ l₂) l₃ =
def Turing.ListBlank.bind {Γ : Type u_1} {Γ' : Type u_2} [] [] (l : ) (f : ΓList Γ') (hf : ∃ (n : ), f default = List.replicate n default) :

The bind function on lists is well defined on ListBlanks provided that the default element is sent to a sequence of default elements.

Equations
Instances For
@[simp]
theorem Turing.ListBlank.bind_mk {Γ : Type u_1} {Γ' : Type u_2} [] [] (l : List Γ) (f : ΓList Γ') (hf : ∃ (n : ), f default = List.replicate n default) :
.bind f hf = Turing.ListBlank.mk (l.bind f)
@[simp]
theorem Turing.ListBlank.cons_bind {Γ : Type u_1} {Γ' : Type u_2} [] [] (a : Γ) (l : ) (f : ΓList Γ') (hf : ∃ (n : ), f default = List.replicate n default) :
().bind f hf = Turing.ListBlank.append (f a) (l.bind f hf)
structure Turing.Tape (Γ : Type u_1) [] :
Type u_1

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 ListBlanks 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 consed onto the left side.

The current position of the head.

• left :

The portion of the tape going off to the left.

• right :

The portion of the tape going off to the right.

Instances For
instance Turing.Tape.inhabited {Γ : Type u_1} [] :
Equations
• Turing.Tape.inhabited = { default := { head := default, left := default, right := default } }
inductive Turing.Dir :

A direction for the Turing machine move command, either left or right.

Instances For
Equations
• = if h : x.toCtorIdx = y.toCtorIdx then else
def Turing.Tape.left₀ {Γ : Type u_1} [] (T : ) :

The "inclusive" left side of the tape, including both left and head.

Equations
Instances For
def Turing.Tape.right₀ {Γ : Type u_1} [] (T : ) :

The "inclusive" right side of the tape, including both right and head.

Equations
Instances For
def Turing.Tape.move {Γ : Type u_1} [] :

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.

Equations
• One or more equations did not get rendered due to their size.
Instances For
@[simp]
theorem Turing.Tape.move_left_right {Γ : Type u_1} [] (T : ) :
@[simp]
theorem Turing.Tape.move_right_left {Γ : Type u_1} [] (T : ) :
def Turing.Tape.mk' {Γ : Type u_1} [] (L : ) (R : ) :

Construct a tape from a left side and an inclusive right side.

Equations
• = { head := R.head, left := L, right := R.tail }
Instances For
@[simp]
theorem Turing.Tape.mk'_left {Γ : Type u_1} [] (L : ) (R : ) :
().left = L
@[simp]
theorem Turing.Tape.mk'_head {Γ : Type u_1} [] (L : ) (R : ) :
@[simp]
theorem Turing.Tape.mk'_right {Γ : Type u_1} [] (L : ) (R : ) :
().right = R.tail
@[simp]
theorem Turing.Tape.mk'_right₀ {Γ : Type u_1} [] (L : ) (R : ) :
().right₀ = R
@[simp]
theorem Turing.Tape.mk'_left_right₀ {Γ : Type u_1} [] (T : ) :
Turing.Tape.mk' T.left T.right₀ = T
theorem Turing.Tape.exists_mk' {Γ : Type u_1} [] (T : ) :
∃ (L : ) (R : ), T =
@[simp]
theorem Turing.Tape.move_left_mk' {Γ : Type u_1} [] (L : ) (R : ) :
@[simp]
theorem Turing.Tape.move_right_mk' {Γ : Type u_1} [] (L : ) (R : ) :
def Turing.Tape.mk₂ {Γ : Type u_1} [] (L : List Γ) (R : List Γ) :

Construct a tape from a left side and an inclusive right side.

Equations
Instances For
def Turing.Tape.mk₁ {Γ : Type u_1} [] (l : List Γ) :

Construct a tape from a list, with the head of the list at the TM head and the rest going to the right.

Equations
Instances For
def Turing.Tape.nth {Γ : Type u_1} [] (T : ) :
Γ

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.)

Equations
• T.nth x = match x with | 0 => T.head | Int.ofNat n.succ => T.right.nth n | => T.left.nth n
Instances For
@[simp]
theorem Turing.Tape.nth_zero {Γ : Type u_1} [] (T : ) :
theorem Turing.Tape.right₀_nth {Γ : Type u_1} [] (T : ) (n : ) :
T.right₀.nth n = T.nth n
@[simp]
theorem Turing.Tape.mk'_nth_nat {Γ : Type u_1} [] (L : ) (R : ) (n : ) :
().nth n = R.nth n
@[simp]
theorem Turing.Tape.move_left_nth {Γ : Type u_1} [] (T : ) (i : ) :
.nth i = T.nth (i - 1)
@[simp]
theorem Turing.Tape.move_right_nth {Γ : Type u_1} [] (T : ) (i : ) :
.nth i = T.nth (i + 1)
@[simp]
theorem Turing.Tape.move_right_n_head {Γ : Type u_1} [] (T : ) (i : ) :
def Turing.Tape.write {Γ : Type u_1} [] (b : Γ) (T : ) :

Replace the current value of the head on the tape.

Equations
• = { head := b, left := T.left, right := T.right }
Instances For
@[simp]
theorem Turing.Tape.write_self {Γ : Type u_1} [] (T : ) :
@[simp]
theorem Turing.Tape.write_nth {Γ : Type u_1} [] (b : Γ) (T : ) {i : } :
().nth i = if i = 0 then b else T.nth i
@[simp]
theorem Turing.Tape.write_mk' {Γ : Type u_1} [] (a : Γ) (b : Γ) (L : ) (R : ) :
=
def Turing.Tape.map {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (T : ) :

Apply a pointed map to a tape to change the alphabet.

Equations
Instances For
@[simp]
theorem Turing.Tape.map_fst {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (T : ) :
@[simp]
theorem Turing.Tape.map_write {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (b : Γ) (T : ) :
= Turing.Tape.write (f.f b) ()
@[simp]
theorem Turing.Tape.write_move_right_n {Γ : Type u_1} [] (f : ΓΓ) (L : ) (R : ) (n : ) :
Turing.Tape.write (f (R.nth n)) () =
theorem Turing.Tape.map_move {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (T : ) (d : Turing.Dir) :
=
theorem Turing.Tape.map_mk' {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (L : ) (R : ) :
=
theorem Turing.Tape.map_mk₂ {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (L : List Γ) (R : List Γ) :
theorem Turing.Tape.map_mk₁ {Γ : Type u_1} {Γ' : Type u_2} [] [] (f : ) (l : List Γ) :
def Turing.eval {σ : Type u_1} (f : σ) :
σPart σ

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.

Equations
Instances For
def Turing.Reaches {σ : Type u_1} (f : σ) :
σσProp

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.

Equations
Instances For
def Turing.Reaches₁ {σ : Type u_1} (f : σ) :
σσProp

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.

Equations
Instances For
theorem Turing.reaches₁_eq {σ : Type u_1} {f : σ} {a : σ} {b : σ} {c : σ} (h : f a = f b) :
theorem Turing.reaches_total {σ : Type u_1} {f : σ} {a : σ} {b : σ} {c : σ} (hab : ) (hac : ) :
theorem Turing.reaches₁_fwd {σ : Type u_1} {f : σ} {a : σ} {b : σ} {c : σ} (h₁ : ) (h₂ : b f a) :
def Turing.Reaches₀ {σ : Type u_1} (f : σ) (a : σ) (b : σ) :

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.

Equations
• = ∀ (c : σ),
Instances For
theorem Turing.Reaches₀.trans {σ : Type u_1} {f : σ} {a : σ} {b : σ} {c : σ} (h₁ : ) (h₂ : ) :
theorem Turing.Reaches₀.refl {σ : Type u_1} {f : σ} (a : σ) :
theorem Turing.Reaches₀.single {σ : Type u_1} {f : σ} {a : σ} {b : σ} (h : b f a) :
theorem Turing.Reaches₀.head {σ : Type u_1} {f : σ} {a : σ} {b : σ} {c : σ} (h : b f a) (h₂ : ) :
theorem Turing.Reaches₀.tail {σ : Type u_1} {f : σ} {a : σ} {b : σ} {c : σ} (h₁ : ) (h : c f b) :
theorem Turing.reaches₀_eq {σ : Type u_1} {f : σ} {a : σ} {b : σ} (e : f a = f b) :
theorem Turing.Reaches₁.to₀ {σ : Type u_1} {f : σ} {a : σ} {b : σ} (h : ) :
theorem Turing.Reaches.to₀ {σ : Type u_1} {f : σ} {a : σ} {b : σ} (h : ) :
theorem Turing.Reaches₀.tail' {σ : Type u_1} {f : σ} {a : σ} {b : σ} {c : σ} (h : ) (h₂ : c f b) :
def Turing.evalInduction {σ : Type u_2} {f : σ} {b : σ} {C : σSort u_1} {a : σ} (h : b ) (H : (a : σ) → b ((a' : σ) → f a = some a'C a')C a) :
C a

(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.

Equations
• One or more equations did not get rendered due to their size.
Instances For
theorem Turing.mem_eval {σ : Type u_1} {f : σ} {a : σ} {b : σ} :
b f b = none
theorem Turing.eval_maximal₁ {σ : Type u_1} {f : σ} {a : σ} {b : σ} (h : b ) (c : σ) :
theorem Turing.eval_maximal {σ : Type u_1} {f : σ} {a : σ} {b : σ} (h : b ) {c : σ} :
c = b
theorem Turing.reaches_eval {σ : Type u_1} {f : σ} {a : σ} {b : σ} (ab : ) :
=
def Turing.Respects {σ₁ : Type u_1} {σ₂ : Type u_2} (f₁ : σ₁Option σ₁) (f₂ : σ₂Option σ₂) (tr : σ₁σ₂Prop) :

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.

Equations
• Turing.Respects f₁ f₂ tr = ∀ ⦃a₁ : σ₁⦄ ⦃a₂ : σ₂⦄, tr a₁ a₂match f₁ a₁ with | some b₁ => ∃ (b₂ : σ₂), tr b₁ b₂ Turing.Reaches₁ f₂ a₂ b₂ | none => f₂ a₂ = none
Instances For
theorem Turing.tr_reaches₁ {σ₁ : Type u_1} {σ₂ : Type u_2} {f₁ : σ₁Option σ₁} {f₂ : σ₂Option σ₂} {tr : σ₁σ₂Prop} (H : Turing.Respects f₁ f₂ tr) {a₁ : σ₁} {a₂ : σ₂} (aa : tr a₁ a₂) {b₁ : σ₁} (ab : Turing.Reaches₁ f₁ a₁ b₁) :
∃ (b₂ : σ₂), tr b₁ b₂ Turing.Reaches₁ f₂ a₂ b₂
theorem Turing.tr_reaches {σ₁ : Type u_1} {σ₂ : Type u_2} {f₁ : σ₁Option σ₁} {f₂ : σ₂Option σ₂} {tr : σ₁σ₂Prop} (H : Turing.Respects f₁ f₂ tr) {a₁ : σ₁} {a₂ : σ₂} (aa : tr a₁ a₂) {b₁ : σ₁} (ab : Turing.Reaches f₁ a₁ b₁) :
∃ (b₂ : σ₂), tr b₁ b₂ Turing.Reaches f₂ a₂ b₂
theorem Turing.tr_reaches_rev {σ₁ : Type u_1} {σ₂ : Type u_2} {f₁ : σ₁Option σ₁} {f₂ : σ₂Option σ₂} {tr : σ₁σ₂Prop} (H : Turing.Respects f₁ f₂ tr) {a₁ : σ₁} {a₂ : σ₂} (aa : tr a₁ a₂) {b₂ : σ₂} (ab : Turing.Reaches f₂ a₂ b₂) :
∃ (c₁ : σ₁) (c₂ : σ₂), Turing.Reaches f₂ b₂ c₂ tr c₁ c₂ Turing.Reaches f₁ a₁ c₁
theorem Turing.tr_eval {σ₁ : Type u_1} {σ₂ : Type u_2} {f₁ : σ₁Option σ₁} {f₂ : σ₂Option σ₂} {tr : σ₁σ₂Prop} (H : Turing.Respects f₁ f₂ tr) {a₁ : σ₁} {b₁ : σ₁} {a₂ : σ₂} (aa : tr a₁ a₂) (ab : b₁ Turing.eval f₁ a₁) :
∃ (b₂ : σ₂), tr b₁ b₂ b₂ Turing.eval f₂ a₂
theorem Turing.tr_eval_rev {σ₁ : Type u_1} {σ₂ : Type u_2} {f₁ : σ₁Option σ₁} {f₂ : σ₂Option σ₂} {tr : σ₁σ₂Prop} (H : Turing.Respects f₁ f₂ tr) {a₁ : σ₁} {b₂ : σ₂} {a₂ : σ₂} (aa : tr a₁ a₂) (ab : b₂ Turing.eval f₂ a₂) :
∃ (b₁ : σ₁), tr b₁ b₂ b₁ Turing.eval f₁ a₁
theorem Turing.tr_eval_dom {σ₁ : Type u_1} {σ₂ : Type u_2} {f₁ : σ₁Option σ₁} {f₂ : σ₂Option σ₂} {tr : σ₁σ₂Prop} (H : Turing.Respects f₁ f₂ tr) {a₁ : σ₁} {a₂ : σ₂} (aa : tr a₁ a₂) :
(Turing.eval f₂ a₂).Dom (Turing.eval f₁ a₁).Dom
def Turing.FRespects {σ₁ : Type u_1} {σ₂ : Type u_2} (f₂ : σ₂Option σ₂) (tr : σ₁σ₂) (a₂ : σ₂) :
Option σ₁Prop

A simpler version of Respects when the state transition relation tr is a function.

Equations
Instances For
theorem Turing.frespects_eq {σ₁ : Type u_1} {σ₂ : Type u_2} {f₂ : σ₂Option σ₂} {tr : σ₁σ₂} {a₂ : σ₂} {b₂ : σ₂} (h : f₂ a₂ = f₂ b₂) {b₁ : Option σ₁} :
Turing.FRespects f₂ tr a₂ b₁ Turing.FRespects f₂ tr b₂ b₁
theorem Turing.fun_respects {σ₁ : Type u_1} {σ₂ : Type u_2} {f₁ : σ₁Option σ₁} {f₂ : σ₂Option σ₂} {tr : σ₁σ₂} :
(Turing.Respects f₁ f₂ fun (a : σ₁) (b : σ₂) => tr a = b) ∀ ⦃a₁ : σ₁⦄, Turing.FRespects f₂ tr (tr a₁) (f₁ a₁)
theorem Turing.tr_eval' {σ₁ : Type u_1} {σ₂ : Type u_1} (f₁ : σ₁Option σ₁) (f₂ : σ₂Option σ₂) (tr : σ₁σ₂) (H : Turing.Respects f₁ f₂ fun (a : σ₁) (b : σ₂) => tr a = b) (a₁ : σ₁) :
Turing.eval f₂ (tr a₁) = tr <\$> Turing.eval f₁ a₁

The TM0 model #

A TM0 Turing machine is essentially a Post-Turing machine, adapted for type theory.

A Post-Turing machine with symbol type Γ and label type Λ is a function Λ → Γ → Option (Λ × Stmt), where a Stmt can be either move left, move right or write a for a : Γ. The machine works over a "tape", a doubly-infinite sequence of elements of Γ, and an instantaneous configuration, Cfg, is a label q : Λ indicating the current internal state of the machine, and a Tape Γ (which is essentially ℤ →₀ Γ). The evolution is described by the step function:

• If M q T.head = none, then the machine halts.
• If M q T.head = some (q', s), then the machine performs action s : Stmt and then transitions to state q'.

The initial state takes a List Γ and produces a Tape Γ where the head of the list is the head of the tape and the rest of the list extends to the right, with the left side all blank. The final state takes the entire right side of the tape right or equal to the current position of the machine. (This is actually a ListBlank Γ, not a List Γ, because we don't know, at this level of generality, where the output ends. If equality to default : Γ is decidable we can trim the list to remove the infinite tail of blanks.)

inductive Turing.TM0.Stmt (Γ : Type u_1) :
Type u_1

A Turing machine "statement" is just a command to either move left or right, or write a symbol on the tape.

• move: {Γ : Type u_1} →
• write: {Γ : Type u_1} → Γ
Instances For
instance Turing.TM0.Stmt.inhabited (Γ : Type u_1) [] :
Equations
def Turing.TM0.Machine (Γ : Type u_1) (Λ : Type u_2) [] :
Type (max (max u_1 u_2) u_1 u_2)

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.

Equations
Instances For
instance Turing.TM0.Machine.inhabited (Γ : Type u_1) (Λ : Type u_2) [] :
Equations
• = id inferInstance
structure Turing.TM0.Cfg (Γ : Type u_1) [] (Λ : Type u_2) :
Type (max u_1 u_2)

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.

• q : Λ

The current machine state.

• Tape :

The current state of the tape: current symbol, left and right parts.

Instances For
instance Turing.TM0.Cfg.inhabited (Γ : Type u_1) [] (Λ : Type u_2) [] :
Equations
• = { default := { q := default, Tape := default } }
def Turing.TM0.step {Γ : Type u_1} [] {Λ : Type u_2} [] (M : ) :
Option ()

Execution semantics of the Turing machine.

Equations
• One or more equations did not get rendered due to their size.
Instances For
def Turing.TM0.Reaches {Γ : Type u_1} [] {Λ : Type u_2} [] (M : ) :
Prop

The statement Reaches M s₁ s₂ means that s₂ is obtained starting from s₁ after a finite number of steps from s₂.

Equations
Instances For
def Turing.TM0.init {Γ : Type u_1} [] {Λ : Type u_2} [] (l : List Γ) :

The initial configuration.

Equations
• = { q := default, Tape := }
Instances For
def Turing.TM0.eval {Γ : Type u_1} [] {Λ : Type u_2} [] (M : ) (l : List Γ) :

Evaluate a Turing machine on initial input to a final state, if it terminates.

Equations
• = Part.map (fun (c : ) => c.Tape.right₀) ()
Instances For
def Turing.TM0.Supports {Γ : Type u_1} {Λ : Type u_2} [] (M : ) (S : Set Λ) :

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.

Equations
• = (default S ∀ {q : Λ} {a : Γ} {q' : Λ} {s : }, (q', s) M q aq Sq' S)
Instances For
theorem Turing.TM0.step_supports {Γ : Type u_1} [] {Λ : Type u_2} [] (M : ) {S : Set Λ} (ss : ) {c : } {c' : } :
c' c.q Sc'.q S
theorem Turing.TM0.univ_supports {Γ : Type u_1} {Λ : Type u_2} [] (M : ) :
def Turing.TM0.Stmt.map {Γ : Type u_1} [] {Γ' : Type u_2} [] (f : ) :

Map a TM statement across a function. This does nothing to move statements and maps the write values.

Equations
Instances For
def Turing.TM0.Cfg.map {Γ : Type u_1} [] {Γ' : Type u_2} [] {Λ : Type u_3} {Λ' : Type u_4} (f : ) (g : ΛΛ') :
Turing.TM0.Cfg Γ' Λ'

Map a configuration across a function, given f : Γ → Γ' a map of the alphabets and g : Λ → Λ' a map of the machine states.

Equations
• = match x with | { q := q, Tape := T } => { q := g q, Tape := }
Instances For
def Turing.TM0.Machine.map {Γ : Type u_1} [] {Γ' : Type u_2} [] {Λ : Type u_3} [] {Λ' : Type u_4} [] (M : ) (f₁ : ) (f₂ : ) (g₁ : ΛΛ') (g₂ : Λ'Λ) :

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.

Equations
• M.map f₁ f₂ g₁ g₂ x✝ x = match x✝, x with | q, l => Option.map (Prod.map g₁ ()) (M (g₂ q) (f₂.f l))
Instances For
theorem Turing.TM0.Machine.map_step {Γ : Type u_1} [] {Γ' : Type u_2} [] {Λ : Type u_3} [] {Λ' : Type u_4} [] (M : ) (f₁ : ) (f₂ : ) (g₁ : ΛΛ') (g₂ : Λ'Λ) {S : Set Λ} (f₂₁ : Function.RightInverse f₁.f f₂.f) (g₂₁ : qS, g₂ (g₁ q) = q) (c : ) :
c.q SOption.map () () = Turing.TM0.step (M.map f₁ f₂ g₁ g₂) (Turing.TM0.Cfg.map f₁ g₁ c)
theorem Turing.TM0.map_init {Γ : Type u_1} [] {Γ' : Type u_2} [] {Λ : Type u_3} [] {Λ' : Type u_4} [] (f₁ : ) (g₁ : ) (l : List Γ) :
Turing.TM0.Cfg.map f₁ g₁.f () = Turing.TM0.init (List.map f₁.f l)
theorem Turing.TM0.Machine.map_respects {Γ : Type u_1} [] {Γ' : Type u_2} [] {Λ : Type u_3} [] {Λ' : Type u_4} [] (M : ) (f₁ : ) (f₂ : ) (g₁ : ) (g₂ : Λ'Λ) {S : Set Λ} (ss : ) (f₂₁ : Function.RightInverse f₁.f f₂.f) (g₂₁ : qS, g₂ (g₁.f q) = q) :
Turing.Respects () (Turing.TM0.step (M.map f₁ f₂ g₁.f g₂)) fun (a : ) (b : Turing.TM0.Cfg Γ' Λ') => a.q S Turing.TM0.Cfg.map f₁ g₁.f a = b

The TM1 model #

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. Most of the regular commands are allowed to use the current value a of the local variables and the value T.head on the tape to calculate what to write or how to change local state, but the statements themselves have a fixed structure. The Stmts can be as follows:

• move d q: move left or right, and then do q
• write (f : Γ → σ → Γ) q: write f a T.head to the tape, then do q
• load (f : Γ → σ → σ) q: change the internal state to f a T.head
• branch (f : Γ → σ → Bool) qtrue qfalse: If f a T.head is true, do qtrue, else qfalse
• goto (f : Γ → σ → Λ): Go to label f a T.head
• halt: Transition to the halting state, which halts on the following step

Note that here most statements do not have labels; goto commands can only go to a new function. Only the goto and halt statements actually take a step; the rest is done by recursion on statements and so take 0 steps. (There is a uniform bound on how many statements can be executed before the next goto, so this is an O(1) speedup with the constant depending on the machine.)

The halt command has a one step stutter before actually halting so that any changes made before the halt have a chance to be "committed", since the eval relation uses the final configuration before the halt as the output, and move and write etc. take 0 steps in this model.

inductive Turing.TM1.Stmt (Γ : Type u_1) (Λ : Type u_2) (σ : Type u_3) :
Type (max (max u_1 u_2) u_3)

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.

• move: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → Turing.Dir
• write: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → (ΓσΓ)
• load: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → (Γσσ)
• branch: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → (ΓσBool) → →
• goto: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → (ΓσΛ)
• halt: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} →
Instances For
instance Turing.TM1.Stmt.inhabited (Γ : Type u_1) (Λ : Type u_2) (σ : Type u_3) :
Equations
• = { default := Turing.TM1.Stmt.halt }
structure Turing.TM1.Cfg (Γ : Type u_1) [] (Λ : Type u_2) (σ : Type u_3) :
Type (max (max u_1 u_2) u_3)

The configuration of a TM1 machine is given by the currently evaluating statement, the variable store value, and the tape.

• l :

The statement (if any) which is currently evaluated

• var : σ

The current value of the variable store

• Tape :

The current state of the tape

Instances For
instance Turing.TM1.Cfg.inhabited (Γ : Type u_1) [] (Λ : Type u_2) (σ : Type u_3) [] :
Equations
• = { default := { l := default, var := default, Tape := default } }
def Turing.TM1.stepAux {Γ : Type u_1} [] {Λ : Type u_2} {σ : Type u_3} :
σ

The semantics of TM1 evaluation.

Equations
Instances For
def Turing.TM1.step {Γ : Type u_1} [] {Λ : Type u_2} {σ : Type u_3} (M : Λ) :
Option ()

The state transition function.

Equations
• = match x with | { l := none, var := var, Tape := Tape } => none | { l := some l, var := v, Tape := T } => some (Turing.TM1.stepAux (M l) v T)
Instances For
def Turing.TM1.SupportsStmt {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} (S : ) :
Prop

A set S of labels supports the statement q if all the goto statements in q refer only to other functions in S.

Equations
Instances For
noncomputable def Turing.TM1.stmts₁ {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} :
Finset ()

The subterm closure of a statement.

Equations
Instances For
theorem Turing.TM1.stmts₁_self {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {q : } :
theorem Turing.TM1.stmts₁_trans {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {q₁ : } {q₂ : } :
q₁
theorem Turing.TM1.stmts₁_supportsStmt_mono {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {S : } {q₁ : } {q₂ : } (h : q₁ ) (hs : ) :
noncomputable def Turing.TM1.stmts {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} (M : Λ) (S : ) :

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.

Equations
Instances For
theorem Turing.TM1.stmts_trans {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {M : Λ} {S : } {q₁ : } {q₂ : } (h₁ : q₁ ) :
some q₂ some q₁
def Turing.TM1.Supports {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} [] (M : Λ) (S : ) :

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.

Equations
Instances For
theorem Turing.TM1.stmts_supportsStmt {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} [] {M : Λ} {S : } {q : } (ss : ) :
some q
theorem Turing.TM1.step_supports {Γ : Type u_1} [] {Λ : Type u_2} {σ : Type u_3} [] (M : Λ) {S : } (ss : ) {c : } {c' : } :
c' c.l Finset.insertNone Sc'.l Finset.insertNone S
def Turing.TM1.init {Γ : Type u_1} [] {Λ : Type u_2} {σ : Type u_3} [] [] (l : List Γ) :

The initial state, given a finite input that is placed on the tape starting at the TM head and going to the right.

Equations
• = { l := some default, var := default, Tape := }
Instances For
def Turing.TM1.eval {Γ : Type u_1} [] {Λ : Type u_2} {σ : Type u_3} [] [] (M : Λ) (l : List Γ) :

Evaluate a TM to completion, resulting in an output list on the tape (with an indeterminate number of blanks on the end).

Equations
• = Part.map (fun (c : ) => c.Tape.right₀) ()
Instances For

TM1 emulator in TM0 #

To prove that TM1 computable functions are TM0 computable, we need to reduce each TM1 program to a TM0 program. So suppose a TM1 program is given. We take the following:

• The alphabet Γ is the same for both TM1 and TM0
• The set of states Λ' is defined to be Option Stmt₁ × σ, that is, a TM1 statement or none representing halt, and the possible settings of the internal variables. Note that this is an infinite set, because Stmt₁ is infinite. This is okay because we assume that from the initial TM1 state, only finitely many other labels are reachable, and there are only finitely many statements that appear in all of these functions.

Even though Stmt₁ contains a statement called halt, we must separate it from none (some halt steps to none and none actually halts) because there is a one step stutter in the TM1 semantics.

def Turing.TM1to0.Λ' {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} (M : Λ) :
Type (max (max (max u_3 u_2) u_1) u_3)

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.

Equations
Instances For
instance Turing.TM1to0.instInhabitedΛ' {Γ : Type u_1} {Λ : Type u_2} [] {σ : Type u_3} [] (M : Λ) :
Equations
• = { default := (some (M default), default) }
def Turing.TM1to0.trAux {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} (M : Λ) (s : Γ) :
σ

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.

Equations
Instances For
def Turing.TM1to0.tr {Γ : Type u_1} {Λ : Type u_2} [] {σ : Type u_3} [] (M : Λ) :

The translated TM0 machine (given the TM1 machine input).

Equations
Instances For
def Turing.TM1to0.trCfg {Γ : Type u_1} [] {Λ : Type u_2} {σ : Type u_3} (M : Λ) :

Translate configurations from TM1 to TM0.

Equations
• = match x with | { l := l, var := v, Tape := T } => { q := (, v), Tape := T }
Instances For
theorem Turing.TM1to0.tr_respects {Γ : Type u_1} [] {Λ : Type u_2} [] {σ : Type u_3} [] (M : Λ) :
Turing.Respects () fun (c₁ : ) (c₂ : ) => = c₂
theorem Turing.TM1to0.tr_eval {Γ : Type u_1} [] {Λ : Type u_2} [] {σ : Type u_3} [] (M : Λ) (l : List Γ) :
noncomputable def Turing.TM1to0.trStmts {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} (M : Λ) [] (S : ) :

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).

Equations
Instances For
theorem Turing.TM1to0.tr_supports {Γ : Type u_1} {Λ : Type u_2} [] {σ : Type u_3} [] (M : Λ) [] {S : } (ss : ) :

TM1(Γ) emulator in TM1(Bool) #

The most parsimonious Turing machine model that is still Turing complete is TM0 with Γ = Bool. Because our construction in the previous section reducing TM1 to TM0 doesn't change the alphabet, we can do the alphabet reduction on TM1 instead of TM0 directly.

The basic idea is to use a bijection between Γ and a subset of Vector Bool n, where n is a fixed constant. Each tape element is represented as a block of n bools. Whenever the machine wants to read a symbol from the tape, it traverses over the block, performing n branch instructions to each any of the 2^n results.

For the write instruction, we have to use a goto because we need to follow a different code path depending on the local state, which is not available in the TM1 model, so instead we jump to a label computed using the read value and the local state, which performs the writing and returns to normal execution.

Emulation overhead is O(1). If not for the above write behavior it would be 1-1 because we are exploiting the 0-step behavior of regular commands to avoid taking steps, but there are nevertheless a bounded number of write calls between goto statements because TM1 statements are finitely long.

theorem Turing.TM1to1.exists_enc_dec {Γ : Type u_1} [] [] :
∃ (n : ) (enc : Γ) (dec : Γ), enc default = ∀ (a : Γ), dec (enc a) = a
inductive Turing.TM1to1.Λ' {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} :
Type (max (max u_1 u_2) u_3)

The configuration state of the TM.

• normal: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → ΛTuring.TM1to1.Λ'
• write: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → ΓTuring.TM1to1.Λ'
Instances For
instance Turing.TM1to1.instInhabitedΛ' {Γ : Type u_1} {Λ : Type u_2} [] {σ : Type u_3} :
Inhabited Turing.TM1to1.Λ'
Equations
def Turing.TM1to1.readAux {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} (n : ) :
(Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ)Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ

Read a vector of length n from the tape.

Equations
• One or more equations did not get rendered due to their size.
• = f Mathlib.Vector.nil
Instances For
def Turing.TM1to1.move {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {n : } (d : Turing.Dir) (q : Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ) :
Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ

A move left or right corresponds to n moves across the super-cell.

Equations
Instances For
def Turing.TM1to1.read {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {n : } (dec : Γ) (f : ΓTuring.TM1.Stmt Bool Turing.TM1to1.Λ' σ) :
Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ

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.

Equations
Instances For
def Turing.TM1to1.write {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} :
Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σTuring.TM1.Stmt Bool Turing.TM1to1.Λ' σ

Write a list of bools on the tape.

Equations
Instances For
def Turing.TM1to1.trNormal {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {n : } (dec : Γ) :
Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ

Translate a normal instruction. For the write command, we use a goto indirection so that we can access the current value of the tape.

Equations
Instances For
theorem Turing.TM1to1.stepAux_move {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {n : } (d : Turing.Dir) (q : Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ) (v : σ) (T : ) :
theorem Turing.TM1to1.supportsStmt_move {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {n : } {S : Finset Turing.TM1to1.Λ'} {d : Turing.Dir} {q : Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ} :
theorem Turing.TM1to1.supportsStmt_write {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {S : Finset Turing.TM1to1.Λ'} {l : } {q : Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ} :
theorem Turing.TM1to1.supportsStmt_read {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {n : } (dec : Γ) {S : Finset Turing.TM1to1.Λ'} {f : ΓTuring.TM1.Stmt Bool Turing.TM1to1.Λ' σ} :
(∀ (a : Γ), Turing.TM1.SupportsStmt S (f a))
def Turing.TM1to1.trTape' {Γ : Type u_1} [] {n : } {enc : Γ} (enc0 : enc default = ) (L : ) (R : ) :

The low level tape corresponding to the given tape over alphabet Γ.

Equations
Instances For
def Turing.TM1to1.trTape {Γ : Type u_1} [] {n : } {enc : Γ} (enc0 : enc default = ) (T : ) :

The low level tape corresponding to the given tape over alphabet Γ.

Equations
Instances For
theorem Turing.TM1to1.trTape_mk' {Γ : Type u_1} [] {n : } {enc : Γ} (enc0 : enc default = ) (L : ) (R : ) :
def Turing.TM1to1.tr {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} {n : } (enc : Γ) (dec : Γ) (M : Λ) :
Turing.TM1to1.Λ'Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ

The top level program.

Equations
• One or more equations did not get rendered due to their size.
Instances For
def Turing.TM1to1.trCfg {Γ : Type u_1} [] {Λ : Type u_2} {σ : Type u_3} {n : } (enc : Γ) (enc0 : enc default = ) :
Turing.TM1.Cfg Bool Turing.TM1to1.Λ' σ

The machine configuration translation.

Equations
Instances For
theorem Turing.TM1to1.trTape'_move_left {Γ : Type u_1} [] {n : } {enc : Γ} (enc0 : enc default = ) (L : ) (R : ) :
theorem Turing.TM1to1.trTape'_move_right {Γ : Type u_1} [] {n : } {enc : Γ} (enc0 : enc default = ) (L : ) (R : ) :
theorem Turing.TM1to1.stepAux_write {Γ : Type u_1} [] {Λ : Type u_2} {σ : Type u_3} {n : } {enc : Γ} (enc0 : enc default = ) (q : Turing.TM1.Stmt Bool Turing.TM1to1.Λ' σ) (v : σ) (a : Γ) (b : Γ) (L : ) (R : ) :
theorem Turing.TM1to1.stepAux_read {Γ : Type u_1} [] {Λ : Type u_2} {σ : Type u_3} {n : } {enc : Γ} (dec : Γ) (enc0 : enc default = ) (encdec : ∀ (a : Γ), dec (enc a) = a) (f : ΓTuring.TM1.Stmt Bool Turing.TM1to1.Λ' σ) (v : σ) (L : ) (R : ) :
theorem Turing.TM1to1.tr_respects {Γ : Type u_1} [] {Λ : Type u_2} {σ : Type u_3} {n : } {enc : Γ} (dec : Γ) (enc0 : enc default = ) (M : Λ) (encdec : ∀ (a : Γ), dec (enc a) = a) {enc₀ : enc default = } :
Turing.Respects () (Turing.TM1.step (Turing.TM1to1.tr enc dec M)) fun (c₁ : ) (c₂ : Turing.TM1.Cfg Bool Turing.TM1to1.Λ' σ) => Turing.TM1to1.trCfg enc enc₀ c₁ = c₂
noncomputable def Turing.TM1to1.writes {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} [] :
Finset Turing.TM1to1.Λ'

The set of accessible Λ'.write machine states.

Equations
Instances For
noncomputable def Turing.TM1to1.trSupp {Γ : Type u_1} {Λ : Type u_2} {σ : Type u_3} (M : Λ) [] (S : ) :
Finset Turing.TM1to1.Λ'

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.

Equations
• = S.biUnion fun (l : Λ) =>
Instances For
theorem Turing.TM1to1.tr_supports {Γ : Type u_1} {Λ : Type u_2} [] {σ : Type u_3} {n : } {enc : Γ} (dec : Γ) (M : Λ) [] {S : } (ss : ) :

TM0 emulator in TM1 #

To establish that TM0 and TM1 are equivalent computational models, we must also have a TM0 emulator in TM1. The main complication here is that TM0 allows an action to depend on the value at the head and local state, while TM1 doesn't (in order to have more programming language-like semantics). So we use a computed goto to go to a state that performs the desired action and then returns to normal execution.

One issue with this is that the halt instruction is supposed to halt immediately, not take a step to a halting state. To resolve this we do a check for halt first, then goto (with an unreachable branch).

inductive Turing.TM0to1.Λ' {Γ : Type u_1} {Λ : Type u_2} :
Type (max u_1 u_2)

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.

• normal: {Γ : Type u_1} → {Λ : Type u_2} → ΛTuring.TM0to1.Λ'
• act: {Γ : Type u_1} → {Λ : Type u_2} → ΛTuring.TM0to1.Λ'
Instances For
instance Turing.TM0to1.instInhabitedΛ' {Γ : Type u_1} {Λ : Type u_2} [] :
Inhabited Turing.TM0to1.Λ'
Equations
def Turing.TM0to1.tr {Γ : Type u_1} {Λ : Type u_2} [] (M : ) :
Turing.TM0to1.Λ'Turing.TM1.Stmt Γ Turing.TM0to1.Λ' Unit

The program.

Equations
• One or more equations did not get rendered due to their size.
Instances For
def Turing.TM0to1.trCfg {Γ : Type u_1} [] {Λ : Type u_2} [] (M : ) :
Turing.TM1.Cfg Γ Turing.TM0to1.Λ' Unit

The configuration translation.

Equations
• = match x with | { q := q, Tape := T } => { l := bif (M q T.head).isSome then else none, var := (), Tape := T }
Instances For
theorem Turing.TM0to1.tr_respects {Γ : Type u_1} [] {Λ : Type u_2} [] (M : ) :
Turing.Respects () fun (a : ) (b : Turing.TM1.Cfg Γ Turing.TM0to1.Λ' Unit) => = b

The TM2 model #

The TM2 model removes the tape entirely from the TM1 model, replacing it with an arbitrary (finite) collection of stacks, each with elements of different types (the alphabet of stack k : K is Γ k). The statements are:

• push k (f : σ → Γ k) q puts f a on the k-th stack, then does q.
• pop k (f : σ → Option (Γ k) → σ) q changes the state to f a (S k).head, where S k is the value of the k-th stack, and removes this element from the stack, then does q.
• peek k (f : σ → Option (Γ k) → σ) q changes the state to f a (S k).head, where S k is the value of the k-th stack, then does q.
• load (f : σ → σ) q reads nothing but applies f to the internal state, then does q.
• branch (f : σ → Bool) qtrue qfalse does qtrue or qfalse according to f a.
• goto (f : σ → Λ) jumps to label f a.
• halt halts on the next step.

The configuration is a tuple (l, var, stk) where l : Option Λ is the current label to run or none for the halting state, var : σ is the (finite) internal state, and stk : ∀ k, List (Γ k) is the collection of stacks. (Note that unlike the TM0 and TM1 models, these are not ListBlanks, they have definite ends that can be detected by the pop command.)

Given a designated stack k and a value L : List (Γ k), the initial configuration has all the stacks empty except the designated "input" stack; in eval this designated stack also functions as the output stack.

inductive Turing.TM2.Stmt {K : Type u_1} (Γ : KType u_2) (Λ : Type u_3) (σ : Type u_4) :
Type (max (max (max u_1 u_2) u_3) u_4)

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.

• push: {K : Type u_1} → {Γ : KType u_2} → {Λ : Type u_3} → {σ : Type u_4} → (k : K) → (σΓ k)
• peek: {K : Type u_1} → {Γ : KType u_2} → {Λ : Type u_3} → {σ : Type u_4} → (k : K) → (σOption (Γ k)σ)
• pop: {K : Type u_1} → {Γ : KType u_2} → {Λ : Type u_3} → {σ : Type u_4} → (k : K) → (σOption (Γ k)σ)
• load: {K : Type u_1} → {Γ : KType u_2} → {Λ : Type u_3} → {σ : Type u_4} → (σσ)
• branch: {K : Type u_1} → {Γ : KType u_2} → {Λ : Type u_3} → {σ : Type u_4} → (σBool) → →
• goto: {K : Type u_1} → {Γ : KType u_2} → {Λ : Type u_3} → {σ : Type u_4} → (σΛ)
• halt: {K : Type u_1} → {Γ : KType u_2} → {Λ : Type u_3} → {σ : Type u_4} →
Instances For
instance Turing.TM2.Stmt.inhabited {K : Type u_1} (Γ : KType u_2) (Λ : Type u_3) (σ : Type u_4) :
Equations
• = { default := Turing.TM2.Stmt.halt }
structure Turing.TM2.Cfg {K : Type u_1} (Γ : KType u_2) (Λ : Type u_3) (σ : Type u_4) :
Type (max (max (max u_1 u_2) u_3) u_4)

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 ListBlanks, they have a definite size.)

• l :

The current label to run (or none for the halting state)

• var : σ

The internal state

• stk : (k : K) → List (Γ k)

The (finite) collection of internal stacks

Instances For
instance Turing.TM2.Cfg.inhabited {K : Type u_1} (Γ : KType u_2) (Λ : Type u_3) (σ : Type u_4) [] :
Equations
• = { default := { l := default, var := default, stk := default } }
def Turing.TM2.stepAux {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} :
σ((k : K) → List (Γ k))

The step function for the TM2 model.

Equations
Instances For
def Turing.TM2.step {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} (M : Λ) :
Option ()

The step function for the TM2 model.

Equations
• = match x with | { l := none, var := var, stk := stk } => none | { l := some l, var := v, stk := S } => some (Turing.TM2.stepAux (M l) v S)
Instances For
def Turing.TM2.Reaches {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} (M : Λ) :
Prop

The (reflexive) reachability relation for the TM2 model.

Equations
Instances For
def Turing.TM2.SupportsStmt {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} (S : ) :
Prop

Given a set S of states, SupportsStmt S q means that q only jumps to states in S.

Equations
Instances For
noncomputable def Turing.TM2.stmts₁ {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} :
Finset ()

The set of subtree statements in a statement.

Equations
Instances For
theorem Turing.TM2.stmts₁_self {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} {q : } :
theorem Turing.TM2.stmts₁_trans {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} {q₁ : } {q₂ : } :
q₁
theorem Turing.TM2.stmts₁_supportsStmt_mono {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} {S : } {q₁ : } {q₂ : } (h : q₁ ) (hs : ) :
noncomputable def Turing.TM2.stmts {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} (M : Λ) (S : ) :

The set of statements accessible from initial set S of labels.

Equations
Instances For
theorem Turing.TM2.stmts_trans {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} {M : Λ} {S : } {q₁ : } {q₂ : } (h₁ : q₁ ) :
some q₂ some q₁
def Turing.TM2.Supports {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} [] (M : Λ) (S : ) :

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.

Equations
Instances For
theorem Turing.TM2.stmts_supportsStmt {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} [] {M : Λ} {S : } {q : } (ss : ) :
some q
theorem Turing.TM2.step_supports {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} [] (M : Λ) {S : } (ss : ) {c : } {c' : } :
c' c.l Finset.insertNone Sc'.l Finset.insertNone S
def Turing.TM2.init {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} [] [] (k : K) (L : List (Γ k)) :

The initial state of the TM2 model. The input is provided on a designated stack.

Equations
Instances For
def Turing.TM2.eval {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} [] [] (M : Λ) (k : K) (L : List (Γ k)) :
Part (List (Γ k))

Evaluates a TM2 program to completion, with the output on the same stack as the input.

Equations
Instances For

TM2 emulator in TM1 #

To prove that TM2 computable functions are TM1 computable, we need to reduce each TM2 program to a TM1 program. So suppose a TM2 program is given. This program has to maintain a whole collection of stacks, but we have only one tape, so we must "multiplex" them all together. Pictorially, if stack 1 contains [a, b] and stack 2 contains [c, d, e, f] then the tape looks like this:

 bottom:  ... | _ | T | _ | _ | _ | _ | ...
stack 1: ... | _ | b | a | _ | _ | _ | ...
stack 2: ... | _ | f | e | d | c | _ | ...


where a tape element is a vertical slice through the diagram. Here the alphabet is Γ' := Bool × ∀ k, Option (Γ k), where:

• bottom : Bool is marked only in one place, the initial position of the TM, and represents the tail of all stacks. It is never modified.
• stk k : Option (Γ k) is the value of the k-th stack, if in range, otherwise none (which is the blank value). Note that the head of the stack is at the far end; this is so that push and pop don't have to do any shifting.

In "resting" position, the TM is sitting at the position marked bottom. For non-stack actions, it operates in place, but for the stack actions push, peek, and pop, it must shuttle to the end of the appropriate stack, make its changes, and then return to the bottom. So the states are:

• normal (l : Λ): waiting at bottom to execute function l
• go k (s : StAct k) (q : Stmt₂): travelling to the right to get to the end of stack k in order to perform stack action s, and later continue with executing q
• ret (q : Stmt₂): travelling to the left after having performed a stack action, and executing q once we arrive

Because of the shuttling, emulation overhead is O(n), where n is the current maximum of the length of all stacks. Therefore a program that takes k steps to run in TM2 takes O((m+k)k) steps to run when emulated in TM1, where m is the length of the input.

theorem Turing.TM2to1.stk_nth_val {K : Type u_1} {Γ : KType u_2} {L : Turing.ListBlank ((k : K) → Option (Γ k))} {k : K} {S : List (Γ k)} (n : ) (hL : = Turing.ListBlank.mk (List.map some S).reverse) :
L.nth n k = S.reverse.get? n
def Turing.TM2to1.Γ' {K : Type u_1} {Γ : KType u_2} :
Type (max u_1 u_2)

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.

Equations
Instances For
instance Turing.TM2to1.Γ'.inhabited {K : Type u_1} {Γ : KType u_2} :
Inhabited Turing.TM2to1.Γ'
Equations
• Turing.TM2to1.Γ'.inhabited = { default := (false, fun (x : K) => none) }
instance Turing.TM2to1.Γ'.fintype {K : Type u_1} [] {Γ : KType u_2} [] [(k : K) → Fintype (Γ k)] :
Fintype Turing.TM2to1.Γ'
Equations
def Turing.TM2to1.addBottom {K : Type u_1} {Γ : KType u_2} (L : Turing.ListBlank ((k : K) → Option (Γ k))) :
Turing.ListBlank Turing.TM2to1.Γ'

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.

Equations
Instances For
theorem Turing.TM2to1.addBottom_map {K : Type u_1} {Γ : KType u_2} (L : Turing.ListBlank ((k : K) → Option (Γ k))) :
Turing.ListBlank.map { f := Prod.snd, map_pt' := } = L
theorem Turing.TM2to1.addBottom_modifyNth {K : Type u_1} {Γ : KType u_2} (f : ((k : K) → Option (Γ k))(k : K) → Option (Γ k)) (L : Turing.ListBlank ((k : K) → Option (Γ k))) (n : ) :
Turing.ListBlank.modifyNth (fun (a : Bool × ((k : K) → Option (Γ k))) => (a.1, f a.2)) n =
theorem Turing.TM2to1.addBottom_nth_snd {K : Type u_1} {Γ : KType u_2} (L : Turing.ListBlank ((k : K) → Option (Γ k))) (n : ) :
(.nth n).2 = L.nth n
theorem Turing.TM2to1.addBottom_nth_succ_fst {K : Type u_1} {Γ : KType u_2} (L : Turing.ListBlank ((k : K) → Option (Γ k))) (n : ) :
(.nth (n + 1)).1 = false
theorem Turing.TM2to1.addBottom_head_fst {K : Type u_1} {Γ : KType u_2} (L : Turing.ListBlank ((k : K) → Option (Γ k))) :
inductive Turing.TM2to1.StAct {K : Type u_1} {Γ : KType u_2} {σ : Type u_4} (k : K) :
Type (max u_2 u_4)

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.

• push: {K : Type u_1} → {Γ : KType u_2} → {σ : Type u_4} → {k : K} → (σΓ k)
• peek: {K : Type u_1} → {Γ : KType u_2} → {σ : Type u_4} → {k : K} → (σOption (Γ k)σ)
• pop: {K : Type u_1} → {Γ : KType u_2} → {σ : Type u_4} → {k : K} → (σOption (Γ k)σ)
Instances For
instance Turing.TM2to1.StAct.inhabited {K : Type u_1} {Γ : KType u_2} {σ : Type u_4} {k : K} :
Equations
def Turing.TM2to1.stRun {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} {k : K} :

The TM2 statement corresponding to a stack action.

Equations
• One or more equations did not get rendered due to their size.
Instances For
def Turing.TM2to1.stVar {K : Type u_1} {Γ : KType u_2} {σ : Type u_4} {k : K} (v : σ) (l : List (Γ k)) :

The effect of a stack action on the local variables, given the value of the stack.

Equations
• = match x with | => v | => f v l.head? | => f v l.head?
Instances For
def Turing.TM2to1.stWrite {K : Type u_1} {Γ : KType u_2} {σ : Type u_4} {k : K} (v : σ) (l : List (Γ k)) :
List (Γ k)

The effect of a stack action on the stack.

Equations
• = match x with | => f v :: l | => l | => l.tail
Instances For
def Turing.TM2to1.stmtStRec {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} {C : Sort l} (H₁ : (k : K) → (s : ) → (q : ) → C qC ()) (H₂ : (a : σσ) → (q : ) → C qC ()) (H₃ : (p : σBool) → (q₁ q₂ : ) → C q₁C q₂C ()) (H₄ : (l : σΛ) → C ) (H₅ : C Turing.TM2.Stmt.halt) (n : ) :
C n

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.

Equations
Instances For
theorem Turing.TM2to1.supports_run {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} (S : ) {k : K} (s : ) (q : ) :
inductive Turing.TM2to1.Λ' {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} :
Type (max (max (max u_1 u_2) u_3) u_4)

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.

• normal: {K : Type u_1} → {Γ : KType u_2} → {Λ : Type u_3} → {σ : Type u_4} → ΛTuring.TM2to1.Λ'
• go: {K : Type u_1} → {Γ : KType u_2} → {Λ : Type u_3} → {σ : Type u_4} → (k : K) → Turing.TM2to1.Λ'
• ret: {K : Type u_1} → {Γ : KType u_2} → {Λ : Type u_3} → {σ : Type u_4} → Turing.TM2to1.Λ'
Instances For
instance Turing.TM2to1.Λ'.inhabited {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} [] {σ : Type u_4} :
Inhabited Turing.TM2to1.Λ'
Equations
def Turing.TM2to1.trStAct {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} {k : K} (q : Turing.TM1.Stmt Turing.TM2to1.Γ' Turing.TM2to1.Λ' σ) :
Turing.TM1.Stmt Turing.TM2to1.Γ' Turing.TM2to1.Λ' σ

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.

Equations
• One or more equations did not get rendered due to their size.
Instances For
def Turing.TM2to1.trInit {K : Type u_1} [] {Γ : KType u_2} (k : K) (L : List (Γ k)) :
List Turing.TM2to1.Γ'

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.

Equations
Instances For
theorem Turing.TM2to1.step_run {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} {k : K} (q : ) (v : σ) (S : (k : K) → List (Γ k)) (s : ) :
def Turing.TM2to1.trNormal {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} :
Turing.TM1.Stmt Turing.TM2to1.Γ' Turing.TM2to1.Λ' σ

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.

Equations
Instances For
theorem Turing.TM2to1.trNormal_run {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} {k : K} (s : ) (q : ) :
= Turing.TM1.Stmt.goto fun (x : Turing.TM2to1.Γ') (x : σ) =>
noncomputable def Turing.TM2to1.trStmts₁ {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} :
Finset Turing.TM2to1.Λ'

The set of machine states accessible from an initial TM2 statement.

Equations
Instances For
theorem Turing.TM2to1.trStmts₁_run {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} {k : K} {s : } {q : } :
theorem Turing.TM2to1.tr_respects_aux₂ {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} {k : K} {q : Turing.TM1.Stmt Turing.TM2to1.Γ' Turing.TM2to1.Λ' σ} {v : σ} {S : (k : K) → List (Γ k)} {L : Turing.ListBlank ((k : K) → Option (Γ k))} (hL : ∀ (k : K), = Turing.ListBlank.mk (List.map some (S k)).reverse) (o : ) :
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' : Turing.ListBlank ((k : K) → Option (Γ k))), (∀ (k : K), = Turing.ListBlank.mk (List.map some (S' k)).reverse) Turing.TM1.stepAux () v (^[(S k).length] ) = Turing.TM1.stepAux q v' (^[(S' k).length] )
def Turing.TM2to1.tr {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} (M : Λ) :
Turing.TM2to1.Λ'Turing.TM1.Stmt Turing.TM2to1.Γ' Turing.TM2to1.Λ' σ

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.

Equations
• One or more equations did not get rendered due to their size.
Instances For
inductive Turing.TM2to1.TrCfg {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} :
Turing.TM1.Cfg Turing.TM2to1.Γ' Turing.TM2to1.Λ' σProp

The relation between TM2 configurations and TM1 configurations of the TM2 emulator.

Instances For
theorem Turing.TM2to1.tr_respects_aux₁ {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} (M : Λ) {k : K} (o : ) (q : ) (v : σ) {S : List (Γ k)} {L : Turing.ListBlank ((k : K) → Option (Γ k))} (hL : = Turing.ListBlank.mk (List.map some S).reverse) (n : ) (H : n S.length) :
Turing.Reaches₀ { l := some (), var := v, Tape := } { l := some (), var := v, Tape := }
theorem Turing.TM2to1.tr_respects_aux₃ {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} (M : Λ) {q : } {v : σ} {L : Turing.ListBlank ((k : K) → Option (Γ k))} (n : ) :
Turing.Reaches₀ { l := , var := v, Tape := } { l := , var := v, Tape := }
theorem Turing.TM2to1.tr_respects_aux {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} (M : Λ) {q : } {v : σ} {T : Turing.ListBlank ((i : K) → Option (Γ i))} {k : K} {S : (k : K) → List (Γ k)} (hT : ∀ (k : K), = Turing.ListBlank.mk (List.map some (S k)).reverse) (o : ) (IH : ∀ {v : σ} {S : (k : K) → List (Γ k)} {T : Turing.ListBlank ((k : K) → Option (Γ k))}, (∀ (k : K), = Turing.ListBlank.mk (List.map some (S k)).reverse)∃ (b : Turing.TM1.Cfg Turing.TM2to1.Γ' Turing.TM2to1.Λ' σ), ) :
∃ (b : Turing.TM1.Cfg Turing.TM2to1.Γ' Turing.TM2to1.Λ' σ), Turing.TM2to1.TrCfg () b Turing.Reaches () b
theorem Turing.TM2to1.tr_respects {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} (M : Λ) :
Turing.Respects () Turing.TM2to1.TrCfg
theorem Turing.TM2to1.trCfg_init {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} [] {σ : Type u_4} [] (k : K) (L : List (Γ k)) :
theorem Turing.TM2to1.tr_eval_dom {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} [] {σ : Type u_4} [] (M : Λ) (k : K) (L : List (Γ k)) :
().Dom ().Dom
theorem Turing.TM2to1.tr_eval {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} [] {σ : Type u_4} [] (M : Λ) (k : K) (L : List (Γ k)) {L₁ : Turing.ListBlank Turing.TM2to1.Γ'} {L₂ : List (Γ k)} (H₁ : L₁ ) (H₂ : L₂ ) :
∃ (S : (k : K) → List (Γ k)) (L' : Turing.ListBlank ((k : K) → Option (Γ k))), (∀ (k : K), = Turing.ListBlank.mk (List.map some (S k)).reverse) S k = L₂
noncomputable def Turing.TM2to1.trSupp {K : Type u_1} {Γ : KType u_2} {Λ : Type u_3} {σ : Type u_4} (M : Λ) (S : ) :
Finset Turing.TM2to1.Λ'

The support of a set of TM2 states in the TM2 emulator.

Equations
• = S.biUnion fun (l : Λ) =>
Instances For
theorem Turing.TM2to1.tr_supports {K : Type u_1} [] {Γ : KType u_2} {Λ : Type u_3} [] {σ : Type u_4} (M : Λ) {S : } (ss : ) :