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Λ.Kis 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:
Stmtis 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".Cfgis the set of instantaneous configurations, that is, the state of the machine together with its environment.Machineis 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 Cfgis the function that describes how the state evolves over one step. Ifstep c = none, thencis a terminal state, and the result of the computation is read off fromc. Because of the type ofstep, these models are all deterministic by construction.init : Input → Cfgsets up the initial state. The typeInputdepends on the model; in most cases it isList Γ.eval : Machine → Input → Part Output, given a machineMand inputi, starts frominit i, runsstepuntil it reaches an output, and then applies a functionCfg → Outputto the final state to obtain the result. The typeOutputdepends on the model.Supports : Machine → Finset Λ → Propasserts that a machineMstarts inS : Finset Λ, and can only ever jump to other states insideS. This implies that the behavior ofMon any input cannot depend on its values outsideS. 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.
The BlankExtends partial order holds of l₁ and l₂ if l₂ is obtained by adding
blanks (default : Γ) to the end of l₁.
Equations
- Turing.BlankExtends l₁ l₂ = ∃ (n : ℕ), l₂ = l₁ ++ List.replicate n default
Instances For
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
- One or more equations did not get rendered due to their size.
Instances For
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
- Turing.BlankRel l₁ l₂ = (Turing.BlankExtends l₁ l₂ ∨ Turing.BlankExtends l₂ l₁)
Instances For
Given two BlankRel lists, there exists (constructively) a common join.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Given two BlankRel lists, there exists (constructively) a common meet.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Construct a setoid instance for BlankRel.
Equations
- Turing.BlankRel.setoid Γ = { r := Turing.BlankRel, iseqv := (_ : Equivalence Turing.BlankRel) }
Instances For
Equations
- Turing.ListBlank.inhabited = { default := Quotient.mk'' [] }
Equations
- Turing.ListBlank.hasEmptyc = { emptyCollection := Quotient.mk'' [] }
A modified version of Quotient.liftOn' specialized for ListBlank, with the stronger
precondition BlankExtends instead of BlankRel.
Equations
- Turing.ListBlank.liftOn l f H = Quotient.liftOn' l f (_ : ∀ (a b : List Γ), Setoid.r a b → f a = f b)
Instances For
The head of a ListBlank is well defined.
Equations
- Turing.ListBlank.head l = Turing.ListBlank.liftOn l List.headI (_ : ∀ (a b : List Γ), Turing.BlankExtends a b → List.headI a = List.headI b)
Instances For
The tail of a ListBlank is well defined (up to the tail of blanks).
Equations
- One or more equations did not get rendered due to their size.
Instances For
We can cons an element onto a ListBlank.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The cons and head/tail functions are mutually inverse, unlike in the case of List where
this only holds for nonempty lists.
The cons and head/tail functions are mutually inverse, unlike in the case of List where
this only holds for nonempty lists.
The n-th element of a ListBlank is well defined for all n : ℕ, unlike in a List.
Equations
- Turing.ListBlank.nth l n = Turing.ListBlank.liftOn l (fun (l : List Γ) => List.getI l n) (_ : ∀ (l b : List Γ), Turing.BlankExtends l b → List.getI l n = List.getI b n)
Instances For
Apply a function to a value stored at the nth position of the list.
Equations
Instances For
Equations
- Turing.instCoeFunPointedMapForAll = { coe := Turing.PointedMap.f }
The map function on lists is well defined on ListBlanks provided that the map is
pointed.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The i-th projection as a pointed map.
Equations
- Turing.proj i = { f := fun (a : (i : ι) → Γ i) => a i, map_pt' := (_ : (fun (a : (i : ι) → Γ i) => a i) default = (fun (a : (i : ι) → Γ i) => a i) default) }
Instances For
Append a list on the left side of a ListBlank.
Equations
- Turing.ListBlank.append [] x = x
- Turing.ListBlank.append (a :: l) x = Turing.ListBlank.cons a (Turing.ListBlank.append l x)
Instances For
The bind function on lists is well defined on ListBlanks provided that the default element
is sent to a sequence of default elements.
Equations
- One or more equations did not get rendered due to their size.
Instances For
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.
- head : Γ
- left : Turing.ListBlank Γ
- right : Turing.ListBlank Γ
Instances For
Equations
- Turing.Tape.inhabited = { default := { head := default, left := default, right := default } }
A direction for the Turing machine move command, either
left or right.
- left: Turing.Dir
- right: Turing.Dir
Instances For
Equations
- Turing.instDecidableEqDir x y = if h : Turing.Dir.toCtorIdx x = Turing.Dir.toCtorIdx y then isTrue (_ : x = y) else isFalse (_ : x = y → False)
Equations
- Turing.instInhabitedDir = { default := Turing.Dir.left }
The "inclusive" left side of the tape, including both left and head.
Equations
- Turing.Tape.left₀ T = Turing.ListBlank.cons T.head T.left
Instances For
The "inclusive" right side of the tape, including both right and head.
Equations
- Turing.Tape.right₀ T = Turing.ListBlank.cons T.head T.right
Instances For
Construct a tape from a left side and an inclusive right side.
Equations
- Turing.Tape.mk' L R = { head := Turing.ListBlank.head R, left := L, right := Turing.ListBlank.tail R }
Instances For
Construct a tape from a left side and an inclusive right side.
Equations
Instances For
Construct a tape from a list, with the head of the list at the TM head and the rest going to the right.
Equations
- Turing.Tape.mk₁ l = Turing.Tape.mk₂ [] l
Instances For
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
- Turing.Tape.nth T x = match x with | Int.ofNat 0 => T.head | Int.ofNat (Nat.succ n) => Turing.ListBlank.nth T.right n | Int.negSucc n => Turing.ListBlank.nth T.left n
Instances For
Replace the current value of the head on the tape.
Equations
- Turing.Tape.write b T = { head := b, left := T.left, right := T.right }
Instances For
Apply a pointed map to a tape to change the alphabet.
Equations
- Turing.Tape.map f T = { head := f.f T.head, left := Turing.ListBlank.map f T.left, right := Turing.ListBlank.map f T.right }
Instances For
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
- Turing.eval f = PFun.fix fun (s : σ) => Part.some (Option.elim (f s) (Sum.inl s) Sum.inr)
Instances For
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
- Turing.Reaches f = Relation.ReflTransGen fun (a b : σ) => b ∈ f a
Instances For
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
- Turing.Reaches₁ f = Relation.TransGen fun (a b : σ) => b ∈ f a
Instances For
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
- Turing.Reaches₀ f a b = ∀ (c : σ), Turing.Reaches₁ f b c → Turing.Reaches₁ f a c
Instances For
(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
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
A simpler version of Respects when the state transition relation tr is a function.
Equations
- Turing.FRespects f₂ tr a₂ x = match x with | some b₁ => Turing.Reaches₁ f₂ a₂ (tr b₁) | none => f₂ a₂ = none
Instances For
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 actions : Stmtand then transitions to stateq'.
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.)
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} → Turing.Dir → Turing.TM0.Stmt Γ
- write: {Γ : Type u_1} → Γ → Turing.TM0.Stmt Γ
Instances For
Equations
- Turing.TM0.Stmt.inhabited Γ = { default := Turing.TM0.Stmt.write default }
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
- Turing.TM0.Machine Γ Λ = (Λ → Γ → Option (Λ × Turing.TM0.Stmt Γ))
Instances For
Equations
- Turing.TM0.Machine.inhabited Γ Λ = id inferInstance
The configuration state of a Turing machine during operation
consists of a label (machine state), and a tape, 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 : Λ
- Tape : Turing.Tape Γ
Instances For
Equations
- Turing.TM0.Cfg.inhabited Γ Λ = { default := { q := default, Tape := default } }
Execution semantics of the Turing machine.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The statement Reaches M s₁ s₂ means that s₂ is obtained
starting from s₁ after a finite number of steps from s₂.
Equations
- Turing.TM0.Reaches M = Relation.ReflTransGen fun (a b : Turing.TM0.Cfg Γ Λ) => b ∈ Turing.TM0.step M a
Instances For
The initial configuration.
Equations
- Turing.TM0.init l = { q := default, Tape := Turing.Tape.mk₁ l }
Instances For
Evaluate a Turing machine on initial input to a final state, if it terminates.
Equations
- Turing.TM0.eval M l = Part.map (fun (c : Turing.TM0.Cfg Γ Λ) => Turing.Tape.right₀ c.Tape) (Turing.eval (Turing.TM0.step M) (Turing.TM0.init l))
Instances For
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
- Turing.TM0.Supports M S = (default ∈ S ∧ ∀ {q : Λ} {a : Γ} {q' : Λ} {s : Turing.TM0.Stmt Γ}, (q', s) ∈ M q a → q ∈ S → q' ∈ S)
Instances For
Map a TM statement across a function. This does nothing to move statements and maps the write values.
Equations
- Turing.TM0.Stmt.map f x = match x with | Turing.TM0.Stmt.move d => Turing.TM0.Stmt.move d | Turing.TM0.Stmt.write a => Turing.TM0.Stmt.write (f.f a)
Instances For
Map a configuration across a function, given f : Γ → Γ' a map of the alphabets and
g : Λ → Λ' a map of the machine states.
Equations
- Turing.TM0.Cfg.map f g x = match x with | { q := q, Tape := T } => { q := g q, Tape := Turing.Tape.map f T }
Instances For
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
- Turing.TM0.Machine.map M f₁ f₂ g₁ g₂ x✝ x = match x✝, x with | q, l => Option.map (Prod.map g₁ (Turing.TM0.Stmt.map f₁)) (M (g₂ q) (f₂.f l))
Instances For
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 doqwrite (f : Γ → σ → Γ) q: writef a T.headto the tape, then doqload (f : Γ → σ → σ) q: change the internal state tof a T.headbranch (f : Γ → σ → Bool) qtrue qfalse: Iff a T.headis true, doqtrue, elseqfalsegoto (f : Γ → σ → Λ): Go to labelf a T.headhalt: 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.
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 → Turing.TM1.Stmt Γ Λ σ → Turing.TM1.Stmt Γ Λ σ
- write: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → (Γ → σ → Γ) → Turing.TM1.Stmt Γ Λ σ → Turing.TM1.Stmt Γ Λ σ
- load: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → (Γ → σ → σ) → Turing.TM1.Stmt Γ Λ σ → Turing.TM1.Stmt Γ Λ σ
- branch: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → (Γ → σ → Bool) → Turing.TM1.Stmt Γ Λ σ → Turing.TM1.Stmt Γ Λ σ → Turing.TM1.Stmt Γ Λ σ
- goto: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → (Γ → σ → Λ) → Turing.TM1.Stmt Γ Λ σ
- halt: {Γ : Type u_1} → {Λ : Type u_2} → {σ : Type u_3} → Turing.TM1.Stmt Γ Λ σ
Instances For
Equations
- Turing.TM1.Stmt.inhabited Γ Λ σ = { default := Turing.TM1.Stmt.halt }
The configuration of a TM1 machine is given by the currently evaluating statement, the variable store value, and the tape.
- l : Option Λ
- var : σ
- Tape : Turing.Tape Γ
Instances For
Equations
- Turing.TM1.Cfg.inhabited Γ Λ σ = { default := { l := default, var := default, Tape := default } }
The semantics of TM1 evaluation.
Equations
- Turing.TM1.stepAux (Turing.TM1.Stmt.move d q) x✝ x = Turing.TM1.stepAux q x✝ (Turing.Tape.move d x)
- Turing.TM1.stepAux (Turing.TM1.Stmt.write a q) x✝ x = Turing.TM1.stepAux q x✝ (Turing.Tape.write (a x.head x✝) x)
- Turing.TM1.stepAux (Turing.TM1.Stmt.load s q) x✝ x = Turing.TM1.stepAux q (s x.head x✝) x
- Turing.TM1.stepAux (Turing.TM1.Stmt.branch p q₁ q₂) x✝ x = bif p x.head x✝ then Turing.TM1.stepAux q₁ x✝ x else Turing.TM1.stepAux q₂ x✝ x
- Turing.TM1.stepAux (Turing.TM1.Stmt.goto l) x✝ x = { l := some (l x.head x✝), var := x✝, Tape := x }
- Turing.TM1.stepAux Turing.TM1.Stmt.halt x✝ x = { l := none, var := x✝, Tape := x }
Instances For
The state transition function.
Equations
- Turing.TM1.step M x = 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
A set S of labels supports the statement q if all the goto
statements in q refer only to other functions in S.
Equations
- Turing.TM1.SupportsStmt S (Turing.TM1.Stmt.move a q) = Turing.TM1.SupportsStmt S q
- Turing.TM1.SupportsStmt S (Turing.TM1.Stmt.write a q) = Turing.TM1.SupportsStmt S q
- Turing.TM1.SupportsStmt S (Turing.TM1.Stmt.load a q) = Turing.TM1.SupportsStmt S q
- Turing.TM1.SupportsStmt S (Turing.TM1.Stmt.branch a q₁ q₂) = (Turing.TM1.SupportsStmt S q₁ ∧ Turing.TM1.SupportsStmt S q₂)
- Turing.TM1.SupportsStmt S (Turing.TM1.Stmt.goto l) = ∀ (a : Γ) (v : σ), l a v ∈ S
- Turing.TM1.SupportsStmt S Turing.TM1.Stmt.halt = True
Instances For
The subterm closure of a statement.
Equations
- Turing.TM1.stmts₁ (Turing.TM1.Stmt.move a q) = insert (Turing.TM1.Stmt.move a q) (Turing.TM1.stmts₁ q)
- Turing.TM1.stmts₁ (Turing.TM1.Stmt.write a q) = insert (Turing.TM1.Stmt.write a q) (Turing.TM1.stmts₁ q)
- Turing.TM1.stmts₁ (Turing.TM1.Stmt.load a q) = insert (Turing.TM1.Stmt.load a q) (Turing.TM1.stmts₁ q)
- Turing.TM1.stmts₁ (Turing.TM1.Stmt.branch a q₁ q₂) = insert (Turing.TM1.Stmt.branch a q₁ q₂) (Turing.TM1.stmts₁ q₁ ∪ Turing.TM1.stmts₁ q₂)
- Turing.TM1.stmts₁ x = {x}
Instances For
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
- Turing.TM1.stmts M S = Finset.insertNone (Finset.biUnion S fun (q : Λ) => Turing.TM1.stmts₁ (M q))
Instances For
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
- Turing.TM1.Supports M S = (default ∈ S ∧ ∀ q ∈ S, Turing.TM1.SupportsStmt S (M q))
Instances For
The initial state, given a finite input that is placed on the tape starting at the TM head and going to the right.
Equations
- Turing.TM1.init l = { l := some default, var := default, Tape := Turing.Tape.mk₁ l }
Instances For
Evaluate a TM to completion, resulting in an output list on the tape (with an indeterminate number of blanks on the end).
Equations
- Turing.TM1.eval M l = Part.map (fun (c : Turing.TM1.Cfg Γ Λ σ) => Turing.Tape.right₀ c.Tape) (Turing.eval (Turing.TM1.step M) (Turing.TM1.init l))
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 beOption Stmt₁ × σ, that is, a TM1 statement ornonerepresenting halt, and the possible settings of the internal variables. Note that this is an infinite set, becauseStmt₁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.
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
- Turing.TM1to0.Λ' M = (Option (Turing.TM1.Stmt Γ Λ σ) × σ)
Instances For
Equations
- Turing.TM1to0.instInhabitedΛ' M = { default := (some (M default), default) }
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
- Turing.TM1to0.trAux M s (Turing.TM1.Stmt.move d q) x = ((some q, x), Turing.TM0.Stmt.move d)
- Turing.TM1to0.trAux M s (Turing.TM1.Stmt.write a q) x = ((some q, x), Turing.TM0.Stmt.write (a s x))
- Turing.TM1to0.trAux M s (Turing.TM1.Stmt.load a q) x = Turing.TM1to0.trAux M s q (a s x)
- Turing.TM1to0.trAux M s (Turing.TM1.Stmt.branch p q₁ q₂) x = bif p s x then Turing.TM1to0.trAux M s q₁ x else Turing.TM1to0.trAux M s q₂ x
- Turing.TM1to0.trAux M s (Turing.TM1.Stmt.goto l) x = ((some (M (l s x)), x), Turing.TM0.Stmt.write s)
- Turing.TM1to0.trAux M s Turing.TM1.Stmt.halt x = ((none, x), Turing.TM0.Stmt.write s)
Instances For
The translated TM0 machine (given the TM1 machine input).
Equations
- Turing.TM1to0.tr M x✝ x = match x✝, x with | (none, snd), x => none | (some q, v), s => some (Turing.TM1to0.trAux M s q v)
Instances For
Translate configurations from TM1 to TM0.
Equations
- Turing.TM1to0.trCfg M x = match x with | { l := l, var := v, Tape := T } => { q := (Option.map M l, v), Tape := T }
Instances For
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
- Turing.TM1to0.trStmts M S = Turing.TM1.stmts M S ×ˢ Finset.univ
Instances For
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.
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.TM1.Stmt Γ Λ σ → Turing.TM1to1.Λ'
Instances For
Equations
- Turing.TM1to1.instInhabitedΛ' = { default := Turing.TM1to1.Λ'.normal default }
Read a vector of length n from the tape.
Equations
- One or more equations did not get rendered due to their size.
- Turing.TM1to1.readAux 0 f = f Vector.nil
Instances For
A move left or right corresponds to n moves across the super-cell.
Instances For
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
- Turing.TM1to1.read dec f = Turing.TM1to1.readAux n fun (v : Vector Bool n) => Turing.TM1to1.move Turing.Dir.left (f (dec v))
Instances For
Write a list of bools on the tape.
Equations
- Turing.TM1to1.write [] x = x
- Turing.TM1to1.write (a :: l) x = Turing.TM1.Stmt.write (fun (x : Bool) (x : σ) => a) (Turing.TM1.Stmt.move Turing.Dir.right (Turing.TM1to1.write l x))
Instances For
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
- One or more equations did not get rendered due to their size.
- Turing.TM1to1.trNormal dec (Turing.TM1.Stmt.move a q) = Turing.TM1to1.move a (Turing.TM1to1.trNormal dec q)
- Turing.TM1to1.trNormal dec (Turing.TM1.Stmt.write a q) = Turing.TM1to1.read dec fun (a_1 : Γ) => Turing.TM1.Stmt.goto fun (x : Bool) (s : σ) => Turing.TM1to1.Λ'.write (a a_1 s) q
- Turing.TM1to1.trNormal dec (Turing.TM1.Stmt.load a q) = Turing.TM1to1.read dec fun (a_1 : Γ) => Turing.TM1.Stmt.load (fun (x : Bool) (s : σ) => a a_1 s) (Turing.TM1to1.trNormal dec q)
- Turing.TM1to1.trNormal dec (Turing.TM1.Stmt.goto l) = Turing.TM1to1.read dec fun (a : Γ) => Turing.TM1.Stmt.goto fun (x : Bool) (s : σ) => Turing.TM1to1.Λ'.normal (l a s)
- Turing.TM1to1.trNormal dec Turing.TM1.Stmt.halt = Turing.TM1.Stmt.halt
Instances For
The low level tape corresponding to the given tape over alphabet Γ.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The low level tape corresponding to the given tape over alphabet Γ.
Equations
- Turing.TM1to1.trTape enc0 T = Turing.TM1to1.trTape' enc0 T.left (Turing.Tape.right₀ T)
Instances For
The top level program.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The machine configuration translation.
Equations
- Turing.TM1to1.trCfg enc enc0 x = match x with | { l := l, var := v, Tape := T } => { l := Option.map Turing.TM1to1.Λ'.normal l, var := v, Tape := Turing.TM1to1.trTape enc0 T }
Instances For
The set of accessible Λ'.write machine states.
Equations
- Turing.TM1to1.writes (Turing.TM1.Stmt.move a q) = Turing.TM1to1.writes q
- Turing.TM1to1.writes (Turing.TM1.Stmt.write a q) = Finset.image (fun (a : Γ) => Turing.TM1to1.Λ'.write a q) Finset.univ ∪ Turing.TM1to1.writes q
- Turing.TM1to1.writes (Turing.TM1.Stmt.load a q) = Turing.TM1to1.writes q
- Turing.TM1to1.writes (Turing.TM1.Stmt.branch a q₁ q₂) = Turing.TM1to1.writes q₁ ∪ Turing.TM1to1.writes q₂
- Turing.TM1to1.writes (Turing.TM1.Stmt.goto l) = ∅
- Turing.TM1to1.writes Turing.TM1.Stmt.halt = ∅
Instances For
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
- Turing.TM1to1.trSupp M S = Finset.biUnion S fun (l : Λ) => insert (Turing.TM1to1.Λ'.normal l) (Turing.TM1to1.writes (M l))
Instances For
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).
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.TM0.Stmt Γ → Λ → Turing.TM0to1.Λ'
Instances For
Equations
- Turing.TM0to1.instInhabitedΛ' = { default := Turing.TM0to1.Λ'.normal default }
The program.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The configuration translation.
Equations
- Turing.TM0to1.trCfg M x = match x with | { q := q, Tape := T } => { l := bif Option.isSome (M q T.head) then some (Turing.TM0to1.Λ'.normal q) else none, var := (), Tape := T }
Instances For
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) qputsf aon thek-th stack, then doesq.pop k (f : σ → Option (Γ k) → σ) qchanges the state tof a (S k).head, whereS kis the value of thek-th stack, and removes this element from the stack, then doesq.peek k (f : σ → Option (Γ k) → σ) qchanges the state tof a (S k).head, whereS kis the value of thek-th stack, then doesq.load (f : σ → σ) qreads nothing but appliesfto the internal state, then doesq.branch (f : σ → Bool) qtrue qfalsedoesqtrueorqfalseaccording tof a.goto (f : σ → Λ)jumps to labelf a.halthalts 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.
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} → {Γ : K → Type u_2} → {Λ : Type u_3} → {σ : Type u_4} → (k : K) → (σ → Γ k) → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ
- peek: {K : Type u_1} → {Γ : K → Type u_2} → {Λ : Type u_3} → {σ : Type u_4} → (k : K) → (σ → Option (Γ k) → σ) → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ
- pop: {K : Type u_1} → {Γ : K → Type u_2} → {Λ : Type u_3} → {σ : Type u_4} → (k : K) → (σ → Option (Γ k) → σ) → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ
- load: {K : Type u_1} → {Γ : K → Type u_2} → {Λ : Type u_3} → {σ : Type u_4} → (σ → σ) → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ
- branch: {K : Type u_1} → {Γ : K → Type u_2} → {Λ : Type u_3} → {σ : Type u_4} → (σ → Bool) → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ → Turing.TM2.Stmt Γ Λ σ
- goto: {K : Type u_1} → {Γ : K → Type u_2} → {Λ : Type u_3} → {σ : Type u_4} → (σ → Λ) → Turing.TM2.Stmt Γ Λ σ
- halt: {K : Type u_1} → {Γ : K → Type u_2} → {Λ : Type u_3} → {σ : Type u_4} → Turing.TM2.Stmt Γ Λ σ
Instances For
Equations
- Turing.TM2.Stmt.inhabited Γ Λ σ = { default := Turing.TM2.Stmt.halt }
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.)
Instances For
Equations
- Turing.TM2.Cfg.inhabited Γ Λ σ = { default := { l := default, var := default, stk := default } }
The step function for the TM2 model.
Equations
- Turing.TM2.stepAux (Turing.TM2.Stmt.push k f q) x✝ x = Turing.TM2.stepAux q x✝ (Function.update x k (f x✝ :: x k))
- Turing.TM2.stepAux (Turing.TM2.Stmt.peek k f q) x✝ x = Turing.TM2.stepAux q (f x✝ (List.head? (x k))) x
- Turing.TM2.stepAux (Turing.TM2.Stmt.pop k f q) x✝ x = Turing.TM2.stepAux q (f x✝ (List.head? (x k))) (Function.update x k (List.tail (x k)))
- Turing.TM2.stepAux (Turing.TM2.Stmt.load a q) x✝ x = Turing.TM2.stepAux q (a x✝) x
- Turing.TM2.stepAux (Turing.TM2.Stmt.branch f q₁ q₂) x✝ x = bif f x✝ then Turing.TM2.stepAux q₁ x✝ x else Turing.TM2.stepAux q₂ x✝ x
- Turing.TM2.stepAux (Turing.TM2.Stmt.goto f) x✝ x = { l := some (f x✝), var := x✝, stk := x }
- Turing.TM2.stepAux Turing.TM2.Stmt.halt x✝ x = { l := none, var := x✝, stk := x }
Instances For
The step function for the TM2 model.
Equations
- Turing.TM2.step M x = 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
The (reflexive) reachability relation for the TM2 model.
Equations
- Turing.TM2.Reaches M = Relation.ReflTransGen fun (a b : Turing.TM2.Cfg Γ Λ σ) => b ∈ Turing.TM2.step M a
Instances For
Given a set S of states, SupportsStmt S q means that q only jumps to states in S.
Equations
- Turing.TM2.SupportsStmt S (Turing.TM2.Stmt.push k a q) = Turing.TM2.SupportsStmt S q
- Turing.TM2.SupportsStmt S (Turing.TM2.Stmt.peek k a q) = Turing.TM2.SupportsStmt S q
- Turing.TM2.SupportsStmt S (Turing.TM2.Stmt.pop k a q) = Turing.TM2.SupportsStmt S q
- Turing.TM2.SupportsStmt S (Turing.TM2.Stmt.load a q) = Turing.TM2.SupportsStmt S q
- Turing.TM2.SupportsStmt S (Turing.TM2.Stmt.branch a q₁ q₂) = (Turing.TM2.SupportsStmt S q₁ ∧ Turing.TM2.SupportsStmt S q₂)
- Turing.TM2.SupportsStmt S (Turing.TM2.Stmt.goto l) = ∀ (v : σ), l v ∈ S
- Turing.TM2.SupportsStmt S Turing.TM2.Stmt.halt = True
Instances For
The set of subtree statements in a statement.
Equations
- Turing.TM2.stmts₁ (Turing.TM2.Stmt.push k a q) = insert (Turing.TM2.Stmt.push k a q) (Turing.TM2.stmts₁ q)
- Turing.TM2.stmts₁ (Turing.TM2.Stmt.peek k a q) = insert (Turing.TM2.Stmt.peek k a q) (Turing.TM2.stmts₁ q)
- Turing.TM2.stmts₁ (Turing.TM2.Stmt.pop k a q) = insert (Turing.TM2.Stmt.pop k a q) (Turing.TM2.stmts₁ q)
- Turing.TM2.stmts₁ (Turing.TM2.Stmt.load a q) = insert (Turing.TM2.Stmt.load a q) (Turing.TM2.stmts₁ q)
- Turing.TM2.stmts₁ (Turing.TM2.Stmt.branch a q₁ q₂) = insert (Turing.TM2.Stmt.branch a q₁ q₂) (Turing.TM2.stmts₁ q₁ ∪ Turing.TM2.stmts₁ q₂)
- Turing.TM2.stmts₁ (Turing.TM2.Stmt.goto a) = {Turing.TM2.Stmt.goto a}
- Turing.TM2.stmts₁ Turing.TM2.Stmt.halt = {Turing.TM2.Stmt.halt}
Instances For
The set of statements accessible from initial set S of labels.
Equations
- Turing.TM2.stmts M S = Finset.insertNone (Finset.biUnion S fun (q : Λ) => Turing.TM2.stmts₁ (M q))
Instances For
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
- Turing.TM2.Supports M S = (default ∈ S ∧ ∀ q ∈ S, Turing.TM2.SupportsStmt S (M q))
Instances For
The initial state of the TM2 model. The input is provided on a designated stack.
Equations
- Turing.TM2.init k L = { l := some default, var := default, stk := Function.update (fun (x : K) => []) k L }
Instances For
Evaluates a TM2 program to completion, with the output on the same stack as the input.
Equations
- Turing.TM2.eval M k L = Part.map (fun (c : Turing.TM2.Cfg Γ Λ σ) => c.stk k) (Turing.eval (Turing.TM2.step M) (Turing.TM2.init k L))
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 : Boolis 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 thek-th stack, if in range, otherwisenone(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 atbottomto execute functionlgo k (s : StAct k) (q : Stmt₂): travelling to the right to get to the end of stackkin order to perform stack actions, and later continue with executingqret (q : Stmt₂): travelling to the left after having performed a stack action, and executingqonce 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.
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.
Instances For
Equations
- Turing.TM2to1.Γ'.fintype = instFintypeProd Bool ((k : K) → Option (Γ k))
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
- One or more equations did not get rendered due to their size.
Instances For
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} → {Γ : K → Type u_2} → {σ : Type u_4} → {k : K} → (σ → Γ k) → Turing.TM2to1.StAct k
- peek: {K : Type u_1} → {Γ : K → Type u_2} → {σ : Type u_4} → {k : K} → (σ → Option (Γ k) → σ) → Turing.TM2to1.StAct k
- pop: {K : Type u_1} → {Γ : K → Type u_2} → {σ : Type u_4} → {k : K} → (σ → Option (Γ k) → σ) → Turing.TM2to1.StAct k
Instances For
Equations
- Turing.TM2to1.StAct.inhabited = { default := Turing.TM2to1.StAct.peek fun (s : σ) (x : Option (Γ k)) => s }
The TM2 statement corresponding to a stack action.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The effect of a stack action on the local variables, given the value of the stack.
Equations
- Turing.TM2to1.stVar v l x = match x with | Turing.TM2to1.StAct.push a => v | Turing.TM2to1.StAct.peek f => f v (List.head? l) | Turing.TM2to1.StAct.pop f => f v (List.head? l)
Instances For
The effect of a stack action on the stack.
Equations
- Turing.TM2to1.stWrite v l x = match x with | Turing.TM2to1.StAct.push f => f v :: l | Turing.TM2to1.StAct.peek a => l | Turing.TM2to1.StAct.pop a => List.tail l
Instances For
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
- Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ (Turing.TM2.Stmt.push k a q) = H₁ k (Turing.TM2to1.StAct.push a) q (Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ q)
- Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ (Turing.TM2.Stmt.peek k a q) = H₁ k (Turing.TM2to1.StAct.peek a) q (Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ q)
- Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ (Turing.TM2.Stmt.pop k a q) = H₁ k (Turing.TM2to1.StAct.pop a) q (Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ q)
- Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ (Turing.TM2.Stmt.load a q) = H₂ a q (Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ q)
- Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ (Turing.TM2.Stmt.branch a q₁ q₂) = H₃ a q₁ q₂ (Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ q₁) (Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ q₂)
- Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ (Turing.TM2.Stmt.goto l) = H₄ l
- Turing.TM2to1.stmtStRec H₁ H₂ H₃ H₄ H₅ Turing.TM2.Stmt.halt = H₅
Instances For
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} → {Γ : K → Type u_2} → {Λ : Type u_3} → {σ : Type u_4} → Λ → Turing.TM2to1.Λ'
- go: {K : Type u_1} → {Γ : K → Type u_2} → {Λ : Type u_3} → {σ : Type u_4} → (k : K) → Turing.TM2to1.StAct k → Turing.TM2.Stmt Γ Λ σ → Turing.TM2to1.Λ'
- ret: {K : Type u_1} → {Γ : K → Type u_2} → {Λ : Type u_3} → {σ : Type u_4} → Turing.TM2.Stmt Γ Λ σ → Turing.TM2to1.Λ'
Instances For
Equations
- Turing.TM2to1.Λ'.inhabited = { default := Turing.TM2to1.Λ'.normal default }
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
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
- Turing.TM2to1.trInit k L = let L' := List.map (fun (a : Γ k) => (false, Function.update (fun (x : K) => none) k (some a))) (List.reverse L); (true, (List.headI L').2) :: List.tail L'
Instances For
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
- Turing.TM2to1.trNormal (Turing.TM2.Stmt.push k a q) = Turing.TM1.Stmt.goto fun (x : Turing.TM2to1.Γ') (x : σ) => Turing.TM2to1.Λ'.go k (Turing.TM2to1.StAct.push a) q
- Turing.TM2to1.trNormal (Turing.TM2.Stmt.peek k a q) = Turing.TM1.Stmt.goto fun (x : Turing.TM2to1.Γ') (x : σ) => Turing.TM2to1.Λ'.go k (Turing.TM2to1.StAct.peek a) q
- Turing.TM2to1.trNormal (Turing.TM2.Stmt.pop k a q) = Turing.TM1.Stmt.goto fun (x : Turing.TM2to1.Γ') (x : σ) => Turing.TM2to1.Λ'.go k (Turing.TM2to1.StAct.pop a) q
- Turing.TM2to1.trNormal (Turing.TM2.Stmt.load a q) = Turing.TM1.Stmt.load (fun (x : Turing.TM2to1.Γ') => a) (Turing.TM2to1.trNormal q)
- Turing.TM2to1.trNormal (Turing.TM2.Stmt.branch a q₁ q₂) = Turing.TM1.Stmt.branch (fun (x : Turing.TM2to1.Γ') => a) (Turing.TM2to1.trNormal q₁) (Turing.TM2to1.trNormal q₂)
- Turing.TM2to1.trNormal (Turing.TM2.Stmt.goto l) = Turing.TM1.Stmt.goto fun (x : Turing.TM2to1.Γ') (s : σ) => Turing.TM2to1.Λ'.normal (l s)
- Turing.TM2to1.trNormal Turing.TM2.Stmt.halt = Turing.TM1.Stmt.halt
Instances For
The set of machine states accessible from an initial TM2 statement.
Equations
- Turing.TM2to1.trStmts₁ (Turing.TM2.Stmt.push k f q) = {Turing.TM2to1.Λ'.go k (Turing.TM2to1.StAct.push f) q, Turing.TM2to1.Λ'.ret q} ∪ Turing.TM2to1.trStmts₁ q
- Turing.TM2to1.trStmts₁ (Turing.TM2.Stmt.peek k f q) = {Turing.TM2to1.Λ'.go k (Turing.TM2to1.StAct.peek f) q, Turing.TM2to1.Λ'.ret q} ∪ Turing.TM2to1.trStmts₁ q
- Turing.TM2to1.trStmts₁ (Turing.TM2.Stmt.pop k f q) = {Turing.TM2to1.Λ'.go k (Turing.TM2to1.StAct.pop f) q, Turing.TM2to1.Λ'.ret q} ∪ Turing.TM2to1.trStmts₁ q
- Turing.TM2to1.trStmts₁ (Turing.TM2.Stmt.load a q) = Turing.TM2to1.trStmts₁ q
- Turing.TM2to1.trStmts₁ (Turing.TM2.Stmt.branch a q₁ q₂) = Turing.TM2to1.trStmts₁ q₁ ∪ Turing.TM2to1.trStmts₁ q₂
- Turing.TM2to1.trStmts₁ x = ∅
Instances For
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
The relation between TM2 configurations and TM1 configurations of the TM2 emulator.
- mk: ∀ {K : Type u_1} {Γ : K → Type u_2} {Λ : Type u_3} {σ : Type u_4} {q : Option Λ} {v : σ} {S : (k : K) → List (Γ k)} (L : Turing.ListBlank ((k : K) → Option (Γ k))), (∀ (k : K), Turing.ListBlank.map (Turing.proj k) L = Turing.ListBlank.mk (List.reverse (List.map some (S k)))) → 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) }
Instances For
The support of a set of TM2 states in the TM2 emulator.
Equations
- Turing.TM2to1.trSupp M S = Finset.biUnion S fun (l : Λ) => insert (Turing.TM2to1.Λ'.normal l) (Turing.TM2to1.trStmts₁ (M l))