<p>As long as the cost of the empty cell fix is constant time, the differences between machine A and machine B are computationally inconsequential. However, for machine A, the mathematician is greatly inconvenienced if he cares to write down the contents of the tape, as he will need some means of communicating that a tape cell is empty. As a mathematician is wont to do, he would invent a symbol to express this meaning. The cup, empty box, or null set symbol are all possible choices. As soon as a choice is made, the only difference between Turing Machine A and Turing Machine B becomes a translation step between the symbol that represents an empty cell, and the symbol that is used to communicate this same meaning to the Turing Machine. The same symbol could be used for both purposes, thus eliminating the need for the translation. When this is done Turing Machine A becomes identical to Turing Machine B.</p>
- <p>To say that a tape cell has never been written, is to say that the history of the tape cell is known. But no history is required to look at a blank piece of paper and to know it has no symbols on it. In addition, Turing allows that a tape cell can be "erased", so an empty cell is not necessarily one that has never been written. There is no need know the full history of the cell, how many times it has been written and erased, rather only a single bit of information is required. This bit can be toggled when the cell is written, then toggled back when it is erased. This toggle can be the empty symbol existence. If the cell is marked as being empty, because it is holding the empty symbol, it is said to be empty, otherwise it is not. This is a description of machine B.</p>
+ <p>To say that a tape cell has never been written, is to say that the history of the tape cell is known. But no history is required to look at a blank piece of paper and to know it has no symbols on it. In addition, Turing allows that a tape cell can be "erased", so an empty cell is not necessarily one that has never been written. There is no need to know the full history of the cell, i.e. how many times it has been written and erased, rather only a single bit of information is required. This bit can be toggled when the cell is written, then toggled back when it is erased. This toggle can be the empty symbol existence. If the cell is marked as being empty, because it is holding the empty symbol, it is said to be empty, otherwise it is not. This is a description of machine B.</p>
<p>Thus it seems that no matter what is done to try and save the machine A model, it turns into machine B. There is a simple reason for this. No structural definition has been given for emptiness, rather its existence is pushed on to a symbol. Consequently, discussion of machine A always brings back the symbol.</p>
<p>Computational theorists often describe a two-step process. First, a Turing Machine writes a string to be studied onto a tape initially filled with all empty symbols; second, the tape is moved to another Turing Machine whose purpose is to recognize a property of the string being studied. In this process, a tape is used as a communication medium, so it follows that communication theory can be applied to this messaging scenario. Messages sent on a channel must be formatted so they can be placed on the channel and later recovered. The specification for such structuring is called a communication <RT·term>protocol</RT·term>. The protocol implies a higher authority, as both the sender and the receiver must have knowledge of the same designed-in protocol. In a sense, a protocol is the meta-message sent before the message itself.</p>
- <p>The intention of the later innovation of placing the empty symbol in <RT·math>Γ</RT·math> but not in <RT·math>Σ</RT·math> appears to be that of making the empty symbol serve additional duty: firstly as a default value for a cell that has never been written, secondly to effect erasure, and now thirdly as a control component of a communications protocol. Accordingly then, this protocol was designed by mathematicians with the goal of making it impossible for programmers to send 'to be studied' string messages, that cannot always be recovered by a receiving recognizer Turing Machine. In short, the empty symbol is also being used as an in-band EOT (end of transmission) symbol.</p>
+ <p>The intention of the later innovation of placing the empty symbol in <RT·math>Γ</RT·math> but not in <RT·math>Σ</RT·math> appears to be that of making the empty symbol serve additional duty: firstly as a default value for a cell that has never been written to, secondly to effect erasure, and now thirdly as a control component of a communications protocol. Accordingly then, this protocol was designed by mathematicians with a specific goal. They intended to make it impossible for programmers to send 'to be studied' string messages that cannot always be recovered by a receiving recognizer Turing Machine. In short, the empty symbol is also being used as an in-band EOT (end of transmission) symbol.</p>
- <p>However, if this is the intention, the protocol is flawed, because Turing Machines are bestowed with the ability to erase characters. An input machine could, for example, happily output an array of strings while using an arbitrary number of empty symbols to separate the elements of a variable-length array. It can put these empty symbols into the input, by first writing another symbol, then erasing it. A receiving machine could then not know how many elements it should try to recover, or when to say a separator is sufficiently long to no longer be considered a separator. Nothing in the Turing Machine definition prevents this.</p>
+ <p>However, if this is the intention, the protocol is flawed, because Turing Machines are bestowed with the ability to erase characters. An input machine could, for example, happily output an array of strings while using an arbitrary number of empty symbols to separate the elements of a variable-length array. It can put these empty symbols into the input by first writing another symbol, then erasing it. A receiving machine could then not know how many elements it should try to recover, or when to say a separator is sufficiently long to no longer be considered a separator. Nothing in the Turing Machine definition prevents this.</p>
<p>Furthermore, the Universal Turing Machine can act as the aforementioned higher authority. In this case, Turing Machines, and sometimes their tapes, are written to a Universal Turing Machine's tape. Consequently, it is not only possible to want to terminate multiple strings in series, as mentioned in the prior paragraph; the termination issue itself is embedded in proofs such as the Halting Problem.</p>
<p>The standard 9-track tape introduced by IBM in 1964 came from the factory unformatted. The format operation would write a header and an EOF marker to mark the end of the device file. Then, a standard library call such as open(), followed by write(), would write over the EOF marker, continue writing data, and finally append a new EOF marker, essentially pushing the EOF boundary back. EOF could be pushed back until the physical EOT marker was struck. This matches, in some ways, how the empty symbol is used on the computation theoretic Turing Machine in the Hopcroft and Ullman book if we consider it to be an EOF marker. However, a difference exists in that the real machine would never use an EOF to erase data characters.</p>
- <p>While using the standard library to write tapes, the empty part of the tape could not be read until after it was written, so early tape machines indeed enforced the "no read until after a write" rule. However, if the programmer were to seek the head back into the device file to do fresh work and perform reads and writes, the device EOF would be nowhere in sight. The burden of the "no read until after a write" rule would then fall on the shoulders of the programmer, as would the structuring of the data.</p>
+ <p>While using the standard library to write tapes, the uninitialized part of the tape could not be read until after it was written, so early tape machines indeed enforced the "read only after a write" rule. However, if the programmer were to seek the head back into the device file to do fresh work and perform reads and writes, the device EOF would be nowhere in sight. The burden of the "read only after a write" rule would then fall on the shoulders of the programmer, as would the structuring of the data.</p>
- <p>Core memory, and later system memory, was random access and initially fully accessible. The data would be whatever scrambled mess the machine booted with, or in early virtual memory systems, whatever was left over from the prior use of the page. The approach of recycling pages was a security hazard, so today a page is initially allocated from a read-only zero page, and due to a copy-on-write trap, a new page will be created in memory then scrubbed with zeros. If the computational Turing Machine's empty symbol maps to a word of zeros, then the empty symbol remains a poor model, because generally the data message, say sent between the <em>input</em> writer and the <em>recognizer</em> receiver, will also contain many zeros. The advantage is that if a programmer attempts to dereference a zero pointer, a segmentation fault occurs. So in this system, the program is again burdened with maintaining the "no read until after a write" rule.</p>
+ <p>Core memory, and later system memory, was random access and initially fully accessible. The data would be whatever scrambled mess the machine booted with, or in early virtual memory systems, whatever was left over from the prior use of the page. The approach of recycling pages was a security hazard, so today a page is initially allocated from a read-only zero page, and due to a copy-on-write trap, a new page will be created in memory then scrubbed with zeros. If the computational Turing Machine's empty symbol maps to a word of zeros, then the empty symbol remains a poor model, because generally the data message, say sent between the <em>input</em> writer and the <em>recognizer</em> receiver, will also contain many zeros. The advantage is that if a programmer attempts to dereference a zero pointer, a segmentation fault occurs. So in this system, the programmer is again burdened with maintaining the "read only after write" rule.</p>
- <p>A violation of "read only after a write" could be detected by a modified computation theoretic Turing Machine if, instead of an empty symbol, the initial tape is filled with the <RT·code>unspecified</RT·code> symbol. The end objective is to detect an erroneous condition, which is useful for debugging and testing. Conventionally, mathematicians do not concern themselves with the test and debug phases of programming a Turing Machine, but rather concern themselves with answering computation theoretic questions about known working Turing Machine programs. Though perhaps an algorithm could be studied for this very quality of not ever making decisions based on unspecified data. Nor do real machines have an <RT·code>unspecified</RT·code> symbol; rather, a program reads garbage from memory locations with unspecified data. There is precedent for an <RT·code>x</RT·code>, <em>unknown</em>, logic state in hardware simulators.</p>
+ <p>A violation of "read only after write" could be detected by a modified computation theoretic Turing Machine if, instead of an empty symbol, the initial tape is filled with the <RT·code>unspecified</RT·code> symbol. The end objective is to detect an erroneous condition, which is useful for debugging and testing. Conventionally, mathematicians do not concern themselves with the test and debug phases of programming a Turing Machine, but rather concern themselves with answering computation theoretic questions about known working Turing Machine programs. Though perhaps an algorithm could be studied for this very quality of not ever making decisions based on unspecified data. Nor do real machines have an <RT·code>unspecified</RT·code> symbol; rather, a program reads garbage from memory locations with unspecified data. There is precedent for an <RT·code>x</RT·code>, <em>unknown</em>, logic state in hardware simulators.</p>
<p>Like the <RT·code>empty</RT·code> symbol, <RT·code>unspecified</RT·code> is a meta-symbol. It describes the data, or lack thereof, rather than being the data. Specifically, the <RT·code>unspecified</RT·code> symbol says that there is a singular alphabet symbol at the memory location, but the machine is not being instructed as to which symbol it is. Because the Turing Machine state transition function requires a specific symbol value, reading an <RT·code>unspecified</RT·code> symbol would break the machine. Of course, that would be a bad thing, so some sort of modification to the Turing Machine definition is required for working with an <RT·code>unspecified</RT·code> symbol.</p>
- <p>The three reasons that data can be unspecified are that it was not initialized, that the history that led up to it is unknown or ignored by the program doing the read, or that it was written from the output of a true random number generator. Technically, the output of a pseudo-random number generator belongs in the 'unknown or ignored history' category.</p>
+ <p>The three reasons that memory can be <RT·code>unspecified</RT·code>:</p>
+ <ol>
+ <li>The memory was not initialized.</li>
+ <li>The memory holds stale data written by an unrelated process, such as a reused memory allocation.</li>
+ <li>The memory holds data that the program explicitly ignores, rendering it effectively unspecified.</li>
+ </ol>
+
+ <p>An example of effectively unspecified data would be a program that reverses a string without looking at the values being reversed. A string reverse function need not inspect the value of the string; it only needs to recognize the structural boundaries established by the writing protocol. So here is a second problem: under the conventional Turing Machine definition, treating data as effectively unspecified by ignoring it is impossible. Reading the value under the tape head is structurally integrated into the machine; it unavoidably gates the state transition function on every single step.</p>
- <p>An example of purposefully ignoring history would be a program that reverses a string without looking at the values being reversed. A string reverse function need not be apprised of the value of the string being reversed; it need only be aware of the structure given to it according to the protocol followed by the machine that wrote the string. However, given the conventional Turing Machine definition, it is impossible to write a string reverse function that does not look at the value of the data being reversed. This is because reading the value under the head is integrated into the machine definition, so it always happens, and it always gates the next state transition function.</p>
<h2>The TTCA computation theoretic Turing Machine</h2>
<p>A goal of the computation theorist in defining a Turing Machine is to make the math concise and elegant. However, the goal of the computer architect is to define a machine that is intuitive to design and test, and that performs well. Perhaps if a computer architect were to define the computation theoretic Turing Machine, this change in emphasis would favor a different definition.</p>
- <p>The following modifications will be made to the computation theoretic Turing Machine definition so as to support the <RT·code>unspecified</RT·code> symbol.</p>
+ <p>The following modifications will be made to the computation theoretic Turing Machine definition so as to support the <RT·code>unspecified</RT·code> symbol:</p>
<ol>
<li>Move to a Moore style programmed state controller, so that actions can be managed separately from state transitions.</li>
- <li>Among the new explicit actions, have two read instructions: a state transition gating symbol read, and a data symbol read, while targeting dedicated registers.</li>
- <li>To match the two read functions, the write function can specify to write a constant symbol, or the contents of one of the read registers.</li>
+ <li>Introduce explicit actions for reading: a state transition gating read (<RT·code>read_g</RT·code>) and a data read (<RT·code>read_d</RT·code>), which target their respective dedicated registers. Additionally, provide a <RT·code>status</RT·code> action that also targets a dedicated register.</li>
+ <li>To match the read functions, the write actions can specify writing a constant symbol (<RT·code>write_σ</RT·code>), or the contents of either the data or gate register (<RT·code>write_d</RT·code>, <RT·code>write_g</RT·code>).</li>
<li>If the <RT·code>unspecified</RT·code> symbol is read into the state transition gating register, the machine transitions to the predefined <RT·code>unspecified_decision</RT·code> state.</li>
</ol>
- <p>For ease of programming, the new machine will have three layers of next-state functions. The first one takes into account both the current state and the gate register value. If there is no match for the state and gate register value, then a second next-state function is called; in this case, the current state is not an operand. This is for defining default next state transitions. If a next state is still not defined, the machine moves to a third next-state function which is unconditional. Hence, this is the state the machine goes to if there is no next state specified and there is no default next state defined.</p>
+ <p>For ease of programming, the new machine evaluates next-state transitions through a strict four-layer hierarchy:</p>
+ <ol>
+ <li><strong>Fixed Hardware Trap (<RT·math>δF_0</RT·math>):</strong> A global interrupt. If the gate register holds the <RT·code>unspecified</RT·code> symbol, the machine unconditionally traps to the <RT·code>unspecified_decision</RT·code> state.</li>
+ <li><strong>Programmed Conditional (<RT·math>δ_1</RT·math>):</strong> Evaluates the current state alongside the contents of a targeted read register (either data or gate) to determine the next state.</li>
+ <li><strong>Programmed Default (<RT·math>δ_2</RT·math>):</strong> If no register-specific condition is met, this layer provides a default destination state based solely on the current state, ignoring register contents.</li>
+ <li><strong>Global Fallback (<RT·math>δ_3</RT·math>):</strong> An unconditional transition of last resort if no prior layer provides a valid next state.</li>
+ </ol>
+
+ <p>For clarity of presentation, the definition will be partitioned according to separation of concerns. The first section defines the fixed hardware components that dictate universal Turing Machine behavior. The second section defines the memory elements (variables). The third section describes the programmable components, which vary between specific Turing Machines depending on their purposes.</p>
- <p>For clarity of presentation, the definition will be partitioned according to separation of concerns, the first being the fixed part that defines all Turing Machine behavior. Then the memory elements of the Turing Machine will be defined. The third section describes the programmable part of the Turing Machine. The programmable part varies between Turing Machines depending on their purposes.</p>
+ <p>There is a mechanical procedure for converting a Moore Machine into a Mealy Machine, and the reverse. Two such converted machines are equally expressive. Making the read operation an explicit action, instead of having it implied by a state transition, increases the number of states in a controller, and consequently the number of steps that must be taken. However, the new machine can do in two steps anything the former machine could do in one; consequently, this change affects the multiplier constant on the linear term of the step count formula but does not change the computation complexity class determined from such a step count. The layers of next-state functions can be collapsed into one layer, where the missing arguments are filled in with all possible unused values. This potentially increases the number of state transition arcs that must be specified, but the state transition logic and the number of states remain unchanged. Partitioning the machine definition by separation of concerns does not change the total specification. Hence, these modifications are computationally inconsequential.</p>
- <p>There is a mechanical procedure for converting a Moore Machine into a Mealy Machine, and the reverse. Two such converted machines are equally expressive. Making the read operation an explicit action, instead of having it implied by a state transition, increases the number of states in a controller, and consequently the number of steps that must be taken. However, the new machine can do in two steps anything the former machine could do in one; consequently, this change affects the multiplier constant on the linear term of the step count formula but does not change the computation complexity class determined from such a step count. The three layers of next-state functions are equivalent to one layer where the missing arguments are filled in with all possible values. This potentially increases the number of state transition arcs that must be specified, but the state transition logic and the number of states remain unchanged. Partitioning the machine definition by separation of concerns, does not change the total specification. Hence, these modifications are computationally inconsequential.</p>
<h3>The TTCA Turing Machine fixed part</h3>
<div style="margin-left: 2em;">
<RT·math>
- MF = (QF, ΣF, AF, λF)
+ MF = (QF, ΣF, AF, δF_0)
</RT·math>
</div>
+ <p>In the following the middle dot acts as a namespace operator, <RT·math>N{·}x</RT·math>. By doing this we assure there will be no aliasing with the symbols provided by the programmer when he defines the programmed state controller.</p>
+
<p>The set of predefined <em>states</em>:</p>
<div style="margin-left: 2em;">
<RT·math>QF = \{QF{·}\mathtt{initial}, QF{·}\mathtt{unspecified\_decision}\}</RT·math>
</div>
- <p>Here the middle dot acts as a namespace operator, <RT·math>N{·}x</RT·math>. By doing this we assure there will be no aliasing with the symbols provided by the programmer when he defines the programmed state controller.</p>
+ <p>The state controller always starts in the <RT·code>QF·initial</RT·code> state. This is a symbol representing the state, it is not a register that holds a state. The 'F' values are all fixed.</p>
- <p>The set of predefined symbols:</p>
- <div style="margin-left: 2em;">
- <RT·math>ΣF = \{ΣF{·}\mathtt{unspecified}, ΣF{·}\mathtt{left\_of\_leftmost}\}</RT·math>
- </div>
+ <p>If a decision is attempted to be made on an <RT·code>ΣF·unspecified</RT·code> symbol, the machine transitions to the <RT·code>QF·unspecified_decision</RT·code> state, due to the global default transition defined in <RT·math>δF_0</RT·math>.</p>
<p>The set of available actions:</p>
<div style="margin-left: 2em;">
<RT·math>
\begin{aligned}
- AF = \{ & \mathtt{no\_op} \\
+ AF = \{\\
+ & \mathtt{no\_op} \\
, & \mathtt{left} \\
, & \mathtt{right} \\
, & \mathtt{read\_d} \\
, & \mathtt{read\_g} \\
+ , & \mathtt{status} \\
, & \mathtt{write\_σ}(σ) \\
, & \mathtt{write\_d} \\
- , & \mathtt{write\_g} \}
+ , & \mathtt{write\_g} \\
+ \}
\end{aligned}
</RT·math>
</div>
<RT·math>ΣF = \{ΣF{·}\mathtt{unspecified}, ΣF{·}\mathtt{on\_leftmost}\}</RT·math>
</div>
+ <p>The set <RT·math>δF_0</RT·math> holds one global default predefined transition of the form,
+ <div style="margin-left: 2em;">
+ <RT·math>
+ \{\langle \mathtt{g{.}ΣF{·}unspecified}, \mathtt{QF{·}unspecified\_decision} \rangle\}
+ </RT·math>
+ </div>
+
+ <p>In any state if the <RT·code>g</RT·code> register holds the symbol <RT·math>\mathtt{ΣF{·}unspecified}</RT·math>, then the next state will be <RT·math>\mathtt{QF{·}unspecified\_decision}</RT·math>, independent of all other defined next state transitions.</p>
+
+
<h3>The TTCA Turing Machine variables</h3>
<div style="margin-left: 2em;">
<div style="margin-left: 2em;">
<RT·math>
- MP = (QP, ΣP, λP, δ, δ_1, δ_2)
+ MP = (QP, ΣP, λP, δ_1, δ_2, δ_3)
</RT·math>
</div>
<p>A set of state transition triples; each triple is of the form:</p>
<div style="margin-left: 2em;">
- <RT·math>δ = \{ \langle q_0, r{·}σ, q_1 \rangle, \dots \}</RT·math>
+ <RT·math>δ_1 = \{ \langle q_0, r{·}σ, q_1 \rangle, \dots \}</RT·math>
</div>
- <p>where <RT·math>q_0</RT·math> is matched to the current state of the machine. <RT·math>r{·}σ</RT·math> is a symbol in register <RT·math>r</RT·math>. <RT·math>q_1</RT·math> is the next state. <RT·math>q_0</RT·math> and <RT·math>q_1</RT·math> come from the total set <RT·math>Q</RT·math>. <RT·math>σ</RT·math> comes from the total set <RT·math>Σ</RT·math>. <RT·math>r</RT·math> is either <RT·math>d</RT·math> or <RT·math>g</RT·math>.</p>
+ <p>where <RT·math>q_0</RT·math> is matched to the current state of the machine. <RT·math>r{·}σ</RT·math> is a symbol in register <RT·math>r</RT·math>, where <RT·math>r</RT·math> is either <RT·math>d</RT·math> or <RT·math>g</RT·math>. <RT·math>q_1</RT·math> is the next state. When <RT·math>q_0</RT·math> matches the current state, <RT·math>q_1</RT·math> becomes the next state. Both <RT·math>q_0</RT·math> and <RT·math>q_1</RT·math> come from the total set <RT·math>Q</RT·math>. <RT·math>σ</RT·math> comes from the total set <RT·math>Σ</RT·math>. </p>
<p>The default transition table. A set of state transition pairs; each pair is of the form:</p>
<div style="margin-left: 2em;">
- <RT·math>δ_1 = \{ \langle r{·}σ, q_1 \rangle, \dots \}</RT·math>
+ <RT·math>δ_2 = \{ \langle q_0, q_1 \rangle, \dots \}</RT·math>
</div>
- <p>where <RT·math>r{·}σ</RT·math> is a symbol found in the specified register, either <RT·math>d</RT·math> or <RT·math>g</RT·math>. <RT·math>q_1</RT·math> will be taken as the next state.</p>
+ <p>where <RT·math>q_0</RT·math> is matched to the current state, and upon a match <RT·math>q_1</RT·math> will be taken as the next state.</p>
<p>A default next state:</p>
<div style="margin-left: 2em;">
- <RT·math>δ_2</RT·math>
+ <RT·math>δ_3 = q_1</RT·math>
</div>
+ <p>This is the transition of last resort. It is unconditional, the next state becomes <RT·math>q_1</RT·math>.</p>
+
<h3>The TTCA Turing Machine in total</h3>
<div style="margin-left: 2em;">
<RT·math>
- M = (Q, Σ, A, λ, δ, δ_1, δ_2)
+ M = (Q, Σ, AF, λP, δ)
</RT·math>
</div>
<RT·math>Σ = ΣF \cup ΣP</RT·math>
</div>
- <p>The complete set of available actions the machine can execute. Because the operational mechanics are strictly architectural, this is exactly the fixed set:</p>
- <div style="margin-left: 2em;">
- <RT·math>A = AF</RT·math>
- </div>
-
- <p>The complete action table mapping states to actions, uniting the predefined actions and the programmed actions:</p>
- <div style="margin-left: 2em;">
- <RT·math>λ = λF \cup λP</RT·math>
- </div>
-
- <p>The highest priority programmed next-state transition rules, requiring both a matching state and a matching read symbol to gate the transition:</p>
+ <p>The ordered sequence of next state transition rules:</p>
<div style="margin-left: 2em;">
- <RT·math>δ</RT·math>
+ <RT·math>δ = [δF_0 | δ_1 | δ_2 | δ_3]</RT·math>
</div>
- <p>The secondary default transition rules, evaluated solely on the read symbol if <RT·math>δ</RT·math> yields no next state:</p>
- <div style="margin-left: 2em;">
- <RT·math>δ_1</RT·math>
- </div>
-
- <p>The final unconditional next state, taken if neither <RT·math>δ</RT·math> nor <RT·math>δ_1</RT·math> provides a valid transition:</p>
- <div style="margin-left: 2em;">
- <RT·math>δ_2</RT·math>
- </div>
-
-
<h2>The TTCA programmed string reverse</h2>
<p>Because the TTCA architecture cleanly separates the data path from the control path, and isolates actions into a Moore-style programmed controller, it is possible to definitively prove that reversing a string does not require inspecting the payload. The programmed controller only needs to recognize the structural boundaries of the data protocol.</p>