<html lang="en">
<head>
<meta charset="UTF-8">
- <title>TTCA: Chapters 1-8</title>
+ <title>TM-2026</title>
<script src="setup.js"></script>
<script>
window.StyleRT.include('RT/theme');
<RT-TOC level="1-2"></RT-TOC>
+ <h1>Preface</h1>
-<h1>Introduction</h1>
-
-<p>
- The Turing machine was introduced by Alan Turing in 1936
- <RT-cite ref="Alan Turing, On Computable Numbers, with an Application to the Entscheidungsproblem, Proceedings of the London Mathematical Society, 1936"></RT-cite>
- and later refined into the standard textbook formulation given by Lewis and Papadimitriou
- <RT-cite ref="Harry Lewis and Christos Papadimitriou, Elements of the Theory of Computation, ISBN 978-0132624787"></RT-cite>.
- The definition presented in the first chapter of this book reformulates that classical automaton
- with explicit structural components (a single‑ended tape, a read/write head, a read‑value buffer,
- and a Moore‑style controller) that anticipate a hardware mapping. This reformulation is
- functionally equivalent to the classical machine; the differences are presentational, chosen to
- serve the architectural direction of this volume.
-</p>
-
-<p>
- Classical computation theory typically explores the limits of computation, such as the complexity of algorithms and the decidability of questions, while assuming unbounded resources. In this volume we reverse the direction: we begin with a practical, hardware‑oriented reformulation of the Turing machine and work upward, constructing a rigorous bridge from pure theory to a high‑integrity <RT-term>computer architecture</RT-term>. To achieve a faithful physical mapping, we must close the conceptual gap between ideal mathematical machines and the hard spatial realities of memory, finite tapes, and structural constraints.
-</p>
-
-<p>
- A computer architecture is will be Turing Complete, if the only errors that can occur from a faultless realization of the architecture are due to the underlying mathematical properties of the program being run, a program logic flaw, or due to a lack of memory resources.
-</p>
-
-<p>
- Computation theorists have hedged over the infinite nature of the Turing Machine tape. Turing described the tape as “unlimited”. Minsky called it “potentially infinite", and explains that it is finite at any moment but always able to grow <RT-cite ref="Alan Turing, On Computable Numbers, with an Application to the Entscheidungsproblem, Proceedings of the London Mathematical Society, 1936"></RT-cite>. ”<RT-cite ref="Marvin Minsky, Computation: Finite and Infinite Machines, Prentice-Hall, 1967"></RT-cite>. Though Hopcroft, Motwani, and Ullman <RT-cite ref="John E. Hopcroft, Rajeev Motwani, Jeffrey D. Ullman, Introduction to Automata Theory, Languages, and Computation, Addison-Wesley, ISBN 978-0321455369"></RT-cite> define a single ended tape that is infinite to the right; however they also note that only a finite prefix is ever used during a halting computation.
-</p>
-
-<p>
- With the aim of building up from Turing Machines toward computer architecture we will start with the Turing Machine and build up to a more hardware like computing model in three steps, first by talking about Turing Machines in a more computer architecture like manner. This is merely a change in nomenclature. Building on that hardware‑terminology Turing machine, we introduce the
- <RT-neologism>TTCA Turing Machine</RT-neologism>, a bounded variation that replaces the infinite tape with an explicitly <em>finite but extendable</em> tape, enforces a <em>write‑before‑read</em> constraint, and adds explicit append and delete commands.
- As the third step, we compound to the read, write, and step commands to create a command language that is under program control. We literally provide this command language as a software library for interfacing programs with memory.
-</p>
-
-<p>
- The changes introduced in the TTCA Turing machine are <em>inconsequential</em> for existence proofs and complexity classes, yet they guarantee that every computational run remains structurally finite, a property that directly mirrors a physical memory system. The practical consequence is that a correctly programmed TTCA machine halts only for reasons of program logic, mathematical impossibility, or genuine resource exhaustion, and even the last of these can be deferred if memory is hot‑swapped at the boundary. By casting the definition in an explicit, hardware‑like specification, we create a framework where the theoretical model and a physical implementation are structurally isomorphic throughout execution. The result is a baseline execution engine that preserves the theoretical power of the Turing machine while embedding the constraints that real hardware demands. Subsequent chapters refine this engine, replace the fixed state controller with a software‑driven command set, and ultimately demonstrate how a carefully chosen theoretical foundation can evolve into a practical, programmable computer architecture. The TTCA Turing Machine is not a mere theoretical object; it is a realizable specification, and thus serves as a computational foundation without the need for the “imagine if …” caveat.
-</p>
-
-
-
-<h1>Introduction</h1>
-
-<p>
- The Turing machine was introduced by Alan Turing in 1936
- <RT-cite ref="Alan Turing, On Computable Numbers, with an Application to the Entscheidungsproblem, Proceedings of the London Mathematical Society, 1936"></RT-cite>
- and later refined into the standard textbook formulation given by Lewis and Papadimitriou
- <RT-cite ref="Harry Lewis and Christos Papadimitriou, Elements of the Theory of Computation, ISBN 978-0132624787"></RT-cite>.
- The definition presented in the first chapter of this book reformulates that classical automaton
- with explicit structural components (a single‑ended tape, a read/write head, a read‑value buffer,
- and a Moore‑style controller) that anticipate a hardware mapping. This reformulation is
- functionally equivalent to the classical machine; the differences are presentational, chosen to
- serve the architectural direction of this volume.
-</p>
-
-<p>
- Classical computation theory typically explores the limits of computation, such as the
- complexity of algorithms and the decidability of questions, while assuming unbounded resources.
- In this volume we reverse the direction: we begin with a practical, hardware‑oriented
- reformulation of the Turing machine and work upward, constructing a rigorous bridge from pure
- theory to a high‑integrity <RT-term>computer architecture</RT-term>. To achieve a faithful
- physical mapping, we must close the conceptual gap between ideal mathematical machines and the
- hard spatial realities of memory, finite tapes, and structural constraints.
-</p>
-
-<p>
- Building on that reformulated Turing machine, we introduce the
- <RT-neologism>TTCA Turing Machine</RT-neologism>, a bounded variation that replaces the infinite tape
- with a <em>finite but extendable</em> tape, enforces a <em>write‑before‑read</em> constraint, and
- adds explicit append and delete commands. These changes are <em>inconsequential</em> for
- existence proofs and complexity classes, yet they guarantee that every computational run remains
- structurally finite, a property that directly mirrors a physical memory system. The practical
- consequence is that a correctly programmed TTCA machine halts only for reasons of program logic,
- mathematical impossibility, or genuine resource exhaustion—and even the last of these can be
- deferred if memory is hot‑swapped at the boundary. By casting the definition in an explicit,
- hardware‑like specification, we create a framework where the theoretical model and a physical
- implementation are structurally isomorphic throughout execution. The result is a baseline
- execution engine that preserves the theoretical power of the Turing machine while embedding the
- constraints that real hardware demands. Subsequent chapters refine this engine, add higher‑level
- abstractions, and ultimately demonstrate how a carefully chosen theoretical foundation can evolve
- into a practical, programmable computer architecture. The TTCA Turing Machine is not a mere
- theoretical object; it is a realizable specification, and thus serves as a computational
- foundation without the need for the “imagine if …” caveat.
-</p>
-
- <h1>The TTCA Turing Machine variation</h1>
- <p>The material in this chapter owes a great deal to, <RT-term-em>Elements of the Theory of Computation</RT-term-em>.<RT-cite ref="Harry Lewis and Christos Papadimitriou, Elements of the Theory of Computation, ISBN 978-0132624787"></RT-cite></p>
+ <p>
+ This is the first volume of the book Tom's Turing Complete Computer Architecture. The initial chapters here set down the theory of the TM, Tape Machine. Following the theory chapters is a description of a software library for using the TM as a general iterator and container. The TM software library was first released in 2022 for Common Lisp on MELPA. Since then, ad hoc versions were developed in C, Java, and Python. The TM-2026 GitHub project has as its purpose unifying the various language versions with a revised command language.
+ </p>
+
+ <h1>Introduction</h1>
+
+ <p>
+ In their 1928 book Grundzüge der theoretischen Logik, Hilbert and Ackermann asked the question, "Does there exist an algorithm that, given any statement in first-order logic, can decide whether that statement is universally valid (i.e., provable from the axioms)?" They called this the Entscheidungsproblem, which in English translates to the <RT-term>decider problem</RT-term>. The Turing machine was introduced by Alan Turing in 1936 <RT-cite ref="Alan Turing, On Computable Numbers, with an Application to the Entscheidungsproblem, Proceedings of the London Mathematical Society, 1936"></RT-cite>. The abstraction was formally refined in early textbooks by Stephen Kleene <RT-cite ref="Stephen C. Kleene, Introduction to Metamathematics, 1952"></RT-cite>, Martin Davis <RT-cite ref="Martin Davis, Computability and Unsolvability, 1958"></RT-cite>, and Marvin Minsky <RT-cite ref="Marvin L. Minsky, Computation: Finite and Infinite Machines, Prentice Hall, 1967"></RT-cite>, leading to the modern standard presentations by authors such as John Hopcroft and Jeffrey Ullman <RT-cite ref="John E. Hopcroft and Jeffrey D. Ullman, Introduction to Automata Theory, Languages, and Computation, 1979"></RT-cite>, as well as Lewis and Papadimitriou <RT-cite ref="Harry R. Lewis and Christos H. Papadimitriou, Elements of the Theory of Computation, ISBN 978-0132624787"></RT-cite>. Turing used his model to prove that no decider program can be written such that, when a program is given to the decider to analyze, the decider can always answer 'yes' or 'no' to the question of whether the given program will halt. This resolved the Entscheidungsproblem in the negative.
+ </p>
+
+ <p>
+ For Hilbert and Ackermann's question to be truly answered by Alan Turing, a mathematical isomorphism between Turing Machine programs and algorithms as understood by Hilbert must be established. Turing addressed this in his paper, and with many reviewers over decades acting as a jury, he did so successfully. For Turing's purposes in his 1936 paper, the equivalence between algorithms and Turing Machine programs was sufficient.
+ </p>
+
+ <p>
+ Furthermore, a connection must be made to modern computer architectures to confirm that Turing Machine results apply to them. While the Universal Turing Machine conceptually introduced programs stored as data on a tape, Turing could not provide the formal explanation of the connection to modern architectures, if for no other reason than the fact such architectures did not yet exist. The practical engineering context of 1936 was limited to calculating machines programmed via patch panels. Though Charles Babbage's 1842 Analytical Engine touched on these concepts, they would wait until the 1940s to re-emerge. For example, there is no explanation in his paper as to why a von Neumann architecture machine (1945) running a program would have the same computation theoretic results as a Turing Machine (1936). Here, by <em>modern</em>, I refer to physical computer organizations utilizing random-access system memory, dedicated instruction fetch streams with dynamic branching, and discrete processing units. To establish this missing connection, the volumes of the TTCA, starting in the following chapters, transform the Turing Machine into a modern architecture in a stepwise fashion, while ensuring that at each step the modifications are <RT-term>inconsequential</RT-term> to existence proofs and complexity class results.
+ </p>
+
+ <p>
+ The Turing Machine is structurally limited to stepping the read/write head over one cell per machine execution step. Thus, for any finite number of steps, only a finite amount of tape is ever used. But for a given computation, how much tape is that? Resolving this by assuming more tape is simply attached when needed is analogous to cheating in a 'guess the bigger number' game by declaring, "My number is always one bigger than the given number, so I will tell you my guess after you state your number." Some mathematicians suggest that what is meant by infinity is precisely a rule of this sort. For engineers building physical hardware, however, to state that a resource starts finite and expands incrementally over time is structurally a very different proposition than being asked to install infinite memory on a machine in the first place.
+ </p>
+
+ <p>
+ In 1967, Marvin Minsky addressed this very topic in saying: "We need not think of the machine's tape as infinite. We imagine instead that the machine begins with a finite tape, but that, whenever an end is encountered, another unit of tape is attached." <RT-cite ref="Marvin L. Minsky, Computation: Finite and Infinite Machines, Prentice Hall, 1967, p. 167"></RT-cite> In 1967, this was a perfectly natural thing to suggest, as computers utilized magnetic tape memory on manually mounted reels, and it was entirely possible for a computation to stop and request a new reel of tape to be mounted. Contemporary computer architectures could achieve similar effects by swapping memory pages out to ever-expanding pools of networked auxiliary storage. In practice, however, once local storage is depleted, the operating system abruptly terminates the process rather than pausing to autonomously provision additional capacity. This observation highlights the necessity to consider the OS as part of the <em>architecture</em>, i.e. the programmer's view of the machine.
+ </p>
+
+ <p>
+ Like a Turing Machine, a computer architecture is an abstraction. The box sitting on a person's desk is a realization of some computer architecture. To say a Turing Machine does something is to say that the Turing Machine was analyzed and the result of the analysis is that 'something'. The same can be said when stating that a computer architecture does something. A computer architecture is said to be Turing Complete when it can do anything that a Turing Machine can do. What this means for the realization of a computer architecture is that a running program will only throw an error because a) the program logic told it to, b) the program has a flaw, or c) there is a mathematical fact standing in the way of execution. It is tolerable to call a computer architecture Turing Complete if it has the built-in ability to pause a program until a 'more memory' request is fulfilled. If there can be any other errors from a realization running a program, such as running out of address space or integer overflow, then the architecture is not Turing Complete.
+ </p>
+
+ <p>
+ In reading Alan Turing's 1936 paper, it is striking how modern the text feels, specifically because he discusses algorithms, stored programs, and the mechanical limits of computation. Turing was not alone in conducting theoretical computational analysis; he explicitly notes Alonzo Church in his paper as also formulating the set of computable numbers. During this era, the academic community produced a flurry of foundational logic: Jacques Herbrand (providing the initial structural definition of computable recursive functions, 1931), Kurt Gödel (publishing the Incompleteness Theorems and formalizing general recursive functions, 1931 and 1934), Alonzo Church (inventing the lambda calculus to definitively model computable functions, 1936), Emil Post (defining "Finite Combinatory Processes" as a theoretical architecture mathematically identical to Turing, 1936), and Stephen Kleene (proving the absolute mathematical equivalence of lambda calculus, recursive functions, and theoretical machines, 1936). However, while his contemporaries largely built purely mathematical and logical frameworks, Turing uniquely tied computation theory directly to the abstraction of machines executing stored programs. Because physical hardware capable of executing stored memory programs had not yet been invented, this explicit architectural grounding makes Turing's work remarkably prescient and gives it a distinctly modern feel.
+ </p>
+
+ <p>
+ Turing's <RT-term>a-machine</RT-term> utilizes binary. George Boole's work (1847, 1854) was well established by then, so from a theoretical standpoint, it was a sensible simplification. However, utilizing binary within the context of a machine effectively bridged the gap to the more practically minded engineers of the time. Alan Turing's paper arrived at the same time that switched telephone networks had reached a scale that made them difficult to maintain without systematic approaches. These networks were built upon electromechanical relays, which were decisively binary devices. At least seven men in addition to Alan Turing appear to have independently contemplated the intersection of Boolean algebra, logic, and physical computing: Victor Shestakov (1935, proposed mapping Boolean algebra to electromechanical relay circuits), Konrad Zuse (1936, adopted base 2 architecture to bypass the physical complexity of decimal mechanical gears), Akira Nakashima (1936, published the mathematical equivalence of Boolean algebra and two-terminal switching networks), Louis Couffignal (1936, proved calculating machines must shift to binary linkages to reduce physical friction), Claude Shannon (1937, published the definitive mathematical proof mapping Boolean algebra to electrical relays), George Stibitz (1937, constructed the first electromechanical binary adder), and John Vincent Atanasoff (1937, adopted binary to keep the vacuum tube count of electronic circuits physically viable).
+ </p>
+
+
+ <h1>Symbol</h1>
+
+ <p>
+ A <RT-term>symbol</RT-term> is a distinct mathematical object capable of being instantiated. Within a given context, any instance of a specific symbol evaluates as equal to any other instance of that identical symbol, and evaluates as not equal to any instance of a different symbol. (As a matter of convenience in this document, sequences of letters and/or digits are utilized for symbol instances.)
+ </p>
+
+ <p>
+ Put more formally, given a set of instantiable objects and a collection of instances created from them, for these objects to be symbols, two structural conditions must be met. First, it must be possible to define an instance comparison operation, denoted <RT-math>=</RT-math>, that acts as an equivalence relation to partition the collection into discrete equivalence classes. Second, this partitioning must result in a strict one-to-one correspondence between the resulting equivalence classes and the original instantiable objects from which the member instances were derived.
+ </p>
+
+ <p>
+ It follows from this definition that the distinct equivalence classes can be used as a proxy for the instantiable objects themselves. That is, a person can name either the instantiable object or the equivalence class, and then through this correspondence, find the other and definitively know the class members.
+ </p>
+
+
+<h2>The factory interpretation</h2>
+
+ <p>
+ In the context of real machines, the symbol itself can be defined as a factory that produces symbol instances. A new symbol instance of the given symbol is created by calling the factory's <RT-code>make</RT-code> function. All of the symbol instances created by the factory constitute the members of the corresponding equivalence class.
+ </p>
+
+ <p>
+ A <RT-term>symbol instance</RT-term> newly minted by the factory is said to <RT-neologism>come direct from the factory</RT-neologism>. A <RT-term>symbol instance</RT-term> direct from the factory is also called an <RT-neologism>original</RT-neologism>.
+ </p>
+
+ <h3>Required properties of symbol factories</h3>
+
+ <p>
+ Any two <RT-term>symbol instance</RT-term>s returned directly from two distinct factories will always evaluate to <RT-code>False</RT-code> during an equality comparison. In other words, two distinct <RT-neologism>original</RT-neologism>s will always be not equal.
+ </p>
+
+ <p>
+ Given an <RT-neologism>original</RT-neologism>, all copies <RT-neologism>stemming from</RT-neologism> it will be equal to each other and to the <RT-neologism>original</RT-neologism>. By <RT-neologism-em>stemming from</RT-neologism-em>, this definition includes all direct copies and copies of copies.
+ </p>
+
+ <p>
+ Given any two <RT-neologism>original</RT-neologism>s, say <var>A</var> and <var>B</var>, it is established that <var>A</var> is not equal to <var>B</var>, as discussed above. Note also that <var>A</var> is not equal to any copy <RT-neologism>stemming from</RT-neologism> <var>B</var>, and <var>B</var> is not equal to any copy <RT-neologism>stemming from</RT-neologism> <var>A</var>.
+ </p>
+
+ <p>
+ Though <RT-term>symbol instance</RT-term>s are integer-like in that copy and equality comparison operations can be used with them, <RT-term>symbol instance</RT-term>s are strictly disallowed from being used with other integer operators. <RT-term>Symbol</RT-term>s cannot be compared for greater-than or less-than; they cannot be incremented, added, nor subtracted.
+ </p>
+
+ <h2>Instance implementation</h2>
+
+ <p>
+ A reference to the factory can be used as a symbol instance, which will cause the factory to become trivial, because making a new instance merely requires copying the factory reference. In this case, there will be nothing in memory that the base factory reference is pointing to.
+ </p>
+
+ <p>
+ In general, memory addresses are built-in symbol instances, hence within the context of a single process run, a program can make use of these symbols. However, this diminishes the size of the address space and leaves the memory at those addresses unused. A common hedge is then to use references into a dictionary, where the data looked up in the dictionary is the <RT-term>name</RT-term> of the symbol.
+ </p>
+
+ <p>
+ Such symbol names are non-structural strings, so do not need to follow the rules of symbols. For example, a program written purely to use references as strings could give multiple, or all, strings the same name, and would function. Conventionally, the names are also required to be distinct to avoid confusion.
+ </p>
+
+ <p>
+ An alternative implementation is to have the factory return an integer value. Each factory has a base integer that is distinct from that of other factories. Calling <RT-code>make</RT-code> then returns the base integer.
+ </p>
+
+ <p>
+ As another alternative, each factory can be given a base string, and then <RT-code>make</RT-code> returns the string. At the time of this writing many machines use 64 bit words for storing integers or addresses. That is equivalent to 8 ASCII characters, while the average size of an identifier is about 5 characters. Hence the approach of using a string as a symbol might not be as inefficient as it seems to be at first. Using strings has the advantages that symbol instances can carry semantic clues for the programmer, and that it has integrity across contexts, such as between processes (note the section below on crossing context boundaries). The drawback is that the strings are typically ad hoc so the guarantee of distinctness becomes a contract with the programmer.
+ </p>
- <p>However in this volume we are exploring the nature of computation in the other direction. We are trying to work our way up from computation theory to arrive at a practical computer architecture. Towards this end we start with a definition for the Turing Machine that itself resembles a computer architecture specification.</p>
+ <p>
+ The time that a Turing Machine takes to copy a symbol to or from tape is considered to be a single machine step. The Turing Machine is defined with a finite alphabet, and a constant number of additional symbols. Then on a real machine, the factory would be used to create the alphabet, and the couple of additional symbols at the time the machine is being defined. Hence the time is not part of the asymptotic behavior of a program. At run time, to copy 1 of N constants there is a constant time that can be defined as the worst case. So the real machine does not introduce a consequential new behavior.
+ </p>
+
+ <h2>Distinctness across contexts</h2>
+ <p>
+ If a <RT-term>symbol</RT-term> persists across contexts (such as across scopes or processes), it must remain distinct from all other <RT-term>symbol</RT-term>s in its new context.
+ </p>
+
+ <p>
+ This structural boundary creates challenges in computer science across many contexts. One solution is to find a scope encompassing both contexts and to place the symbol factory there. Another solution is to give each context a distinct root symbol and to use an array of symbols in place of the imported symbol. Yet another approach is to associate an imported symbol with a new symbol in the given new context using a correspondence map.
+ </p>
+
+ <p>
+ When utilizing memory addresses as symbols in a virtual memory environment, the most common approach in computing is to disallow addresses in one process from being used in another. If that isolation is insufficient, it is often adequate to use indexes instead of addresses, taking the address to the base of the data structure. Though the absolute address of the data structure might differ across contexts, the relative offset remains constant. Another approach is to reserve memory address blocks and to guarantee imported pages have the exact same addresses as before, though they might be imported sequentially to reuse the memory block. In architecture, this is generally known as the pointer swizzling problem.
+ </p>
+
+ <h2>Alphabet</h2>
+
+ <p>
+ An alphabet is a finite set of symbols. Because it is simply a set, an infinite number of distinct alphabets can exist. The Turing Machine specification discusses '<em>the</em> alphabet' strictly because a given Turing Machine instance utilizes only one specific alphabet.
+ </p>
+
+ <h2>Examples</h2>
+
+ <p>
+ The <RT-code>enum</RT-code> structure of C is an example of a mechanism for creating alphabets of named symbols. Each entry in the enum is a static symbol factory, where instances are distinct integers.
+ </p>
+
+ <RT-code>
+ typedef enum {
+ SYMBOL_EMPTY = 0,
+ SYMBOL_ZERO = 1,
+ SYMBOL_ONE = 2,
+ SYMBOL_A = 3,
+ SYMBOL_B = 4
+ } TapeAlphabet;
+
+ /* The enum definition acts as the factory. */
+ /* Instantiating copies of the symbols: */
+ TapeAlphabet cell_1 = SYMBOL_A;
+ TapeAlphabet cell_2 = SYMBOL_A;
+
+ /* Equality comparison over instances */
+ if (cell_1 == cell_2) {
+ /* Evaluates to True */
+ }
+ </RT-code>
+
+ <p>
+ While the <RT-code>enum</RT-code> effectively demonstrates a static hardware mapping, a string interning symbol table is a rigorous example of a dynamic runtime factory. This physically demonstrates the <RT-code>make</RT-code> function taking an arbitrary string, checking a correspondence map, and returning a canonical, unique pointer in memory (the <RT-neologism>original</RT-neologism>).
+ </p>
+
+ <RT-code>
+ #include <string.h>
+
+ #define TABLE_SIZE 100
+ typedef const char* SymbolInstance;
+
+ SymbolInstance symbol_table[TABLE_SIZE];
+ int table_count = 0;
+
+ /* The Factory 'make' function */
+ SymbolInstance make_symbol(const char* name) {
+ /* Search for an existing original */
+ for (int i = 0; i < table_count; i++) {
+ if (strcmp(symbol_table[i], name) == 0) {
+ return symbol_table[i]; /* Return a copy of the instance */
+ }
+ }
+
+ /* Mint a new original if one does not exist */
+ symbol_table[table_count] = strdup(name);
+ return symbol_table[table_count++];
+ }
+
+ /* Usage */
+ SymbolInstance x = make_symbol("START");
+ SymbolInstance y = make_symbol("START");
+
+ /* x == y evaluates to True based purely on the physical memory address,
+ bypassing the need for further string comparisons. */
+ </RT-code>
+
+ <h1>The Turing Machine</h1>
+
+ <p>
+ In this interpretation of the Turing Machine, the architecture utilizes a single-ended tape, aligning with the foundational model presented by Hopcroft and Ullman <RT-cite ref="John E. Hopcroft and Jeffrey D. Ullman, Introduction to Automata Theory, Languages, and Computation, 1979"></RT-cite>. If a computation strictly requires a two-way infinite tape, the single-ended tape can simulate it by interleaving the addresses: assigning odd-addressed cells to represent the right-going half, and even-addressed cells to represent the left-going half. Structurally, this simulation requires taking two steps instead of one to advance in a given logical direction. When analyzing the time complexity of an algorithm, this structural overhead merely doubles the constant on the linear term, leaving the asymptotic order of complexity entirely unchanged. The outcomes of decider programs are unaffected. Therefore, utilizing a single-ended tape is an <RT-term>inconsequential</RT-term> variation of the two-way tape machine.
+ </p>
+
+ <p>
+ Furthermore, this definition adopts the language of hardware specification rather than formal mathematics. Because this is strictly a terminology change with direct structural correspondences between operations, the resulting model remains isomorphic to the Hopcroft and Ullman definition. Adopting this architectural perspective facilitates the overarching goal of building upward toward a physical computer architecture rather than strictly preparing for formal mathematical analysis, though it certainly does not preclude such analysis. In this model, the fixed components of the machine are conceptually hardwired, while the variable components represent memory or registers. As detailed in the control procedures below, data flows dynamically through the variable memory parts, while the fixed hardware components remain strictly read-only.
+ </p>
<figure>
- <img src="figure_1.png" alt="A Turing Machine">
+ <img src="machine fig.png" class="rt-diagram" alt="Figure 1: A Turing Machine">
<figcaption>Figure 1 A Turing Machine</figcaption>
</figure>
- <p>Accordingly, our Turing machine consists of a:</p>
+
+ <p>The Turing Machine consists of:</p>
<ul>
- <li>fixed finite <RT-term>alphabet</RT-term></li>
- <li>fixed distinct <RT-term>empty-symbol</RT-term></li>
- <li>variable single ended <RT-term>tape</RT-term></li>
- <li>variable read/write <RT-term>head</RT-term></li>
- <li>variable read value buffer</li>
- <li>fixed state machine <RT-term>controller</RT-term></li>
- <li>fixed left from leftmost error</li>
- <li>fixed start-state</li>
- <li>fixed halt-state</li>
- <li>variable current-state</li>
- <li>fixed procedure for using these.</li>
+ <li>a read-only <RT-term>alphabet</RT-term> that instances can be made from</li>
+ <li>a read-only <RT-term>empty-symbol</RT-term> that instances can be made from</li>
+ <li>a structurally constant <RT-term>tape</RT-term> consisting of read-writable cells</li>
+ <li>a read-only left from leftmost error symbol that instances can be made from</li>
+ <li>a <RT-term>head</RT-term> bearing tape transport mechanism</li>
+ <li>a read-writable single symbol read data buffer</li>
+ <li>a constant state machine <RT-term>controller</RT-term> with states that can be referenced</li>
+ <li>a constant start-state reference</li>
+ <li>a constant halt-state reference</li>
+ <li>a read-writable current-state reference variable</li>
+ <li>a constant procedure where each step can be referenced</li>
+ <li>a read-writable procedure step reference counter</li>
+ <li>a fixed hardware comparator to evaluate state and symbol equivalencies</li>
+ <li>a constant physical clock to generate discrete execution steps</li>
+ <li>a structurally constant interconnect network to route data and control signals</li>
+ <li>a reset button that activates logic that initializes the machine</li>
</ul>
- <p>The values assigned to the variables are excluded from the definition.</p>
+ <p>The distinct empty-symbol can be any symbol that is excluded from the alphabet. Like the alphabet symbols, this empty-symbol can appear on the tape.</p>
- <p>A <RT-term>symbol</RT-term> has permission to be any mathematical object for which there is a probability to be multiple instances, where within a given context, instances compare to be equal among other instances of the same symbol, but compare not equal to instances of other symbols. As a matter of convenience in this document, I use sequences of letters and/or digits for symbol instances.</p>
+ <p>Only instances of alphabet symbols or the empty-symbol are permitted to be written to the tape.</p>
- <p>The alphabet is a finite set of symbols.</p>
+ <p>Intuitively, a person might consider that the alphabet symbols are useful while the empty symbol is merely taking up space while waiting to be displaced, in the same manner that a person considers a bookshelf to be empty rather than being full of air. (And if a person puts a bookshelf underwater, is it still empty, or is it full of water?).</p>
- <p>The distinct empty-symbol has permission to be any symbol that is excluded from the alphabet.</p>
- <p>Like alphabet symbols, this symbol has a probability to appear in the tape sequence.</p>
+ <p>
+ Without reset being held during power up, a real machine can land in an illegal state that depending on the design might not be resetable, and could conceivably be damaging. Hence, reset is normally held during power up, and it is reset, not power up, that causes a machine to land in a known start state. This is a required component for a Turing Machine.
+ </p>
+ <p>
+ This design assumes that when reset is released, the then initialized machine starts running. This is fine for our purposes here, but for the delux model, we could contemplate a separate 'go' button and the associated logic.
+ </p>
- <p>Only instances of alphabet symbols or the empty-symbol are permitted to be written to the tape.</p>
+ <p>
+ Note that we packaged a tape transport along with the head. In this volume we will talk about sending step commands to the head, but of course a head doesn't step, rather a tape transport mechanism steps. Hence, we when we talk about 'stepping the head' implied is that the head remains stationary, and the tape transport mechanism moves the tape. As the tape is normally very long and held on spools, even if we could move the head, that would not be very effective.
+ </p>
+
+ <p>
+ The constant procedure should not be conflated with the Turing Machine program. For a microcode controlled machine, the procedure will be found in microcode memory, and it will be execute as though a program. Each line of the procedure when read results in a set of bits connected to control lines. Some of those control lines will control what the procedure does, and some will extend out into the data path, give commands to execution units, and gate the flow of data.
+ </p>
+
+ <p>
+ For a hardwired machine, the control program will be expressed with logic gates and flip-flops (single bit memory registers). Whether a machine is microcode controlled, or hardware controlled is a question of <RT-term>implementation</RT-term>. The architecture remains the same independent of implementation decisions, hence they are <RT-term>inconsequential</RT-term> to our architecture discussion. An <RT-term>implementation</RT-term> is the design given to the folks who actually build things. The result of what the design builds is called the <RT-term>realization</RT-term>. An <RT-term>realization</RT-term> is intended to function faithfully to the <RT-term>implementation</RT-term> so the <RT-term>realization</RT-term> is also <RT-term>inconsequential</RT-term>. And thus, the sole question remaining is the one of architecture.
+ </p>
+
+ <p>
+ The Turing Machine architecture specifies an infinite tape, which can neither be implemented, nor realized. Though we will successful address this issue in a later chapter.
+ </p>
+
+ <p>A <RT-term>symbol</RT-term> can be any mathematical object for which there can be multiple instances, where within a given context, instances compare to be equal among other instances of the same symbol, but compare not equal to instances of other symbols. As a matter of convenience in this document, I use sequences of letters and/or digits for symbol instances.</p>
+
+
+ <h2>The Turing Machine tape cell</h2>
+
+ <p>
+ A <RT-term>cell</RT-term> is the <RT-term>square</RT-term> from Alan Turing's 1936 paper <RT-cite ref="Alan Turing, On Computable Numbers, with an Application to the Entscheidungsproblem, Proceedings of the London Mathematical Society, 1936"></RT-cite>.
+ A cell is a foundational mathematical object that has no meaning apart from its distinct identity and its capacity to hold specific structural properties. Due to its distinct identity, a cell can be referenced.
+ </p>
+
+ <p>
+ A leftmost cell possesses exactly two compulsory properties: a right neighbor and data. A rightmost cell also possesses exactly two compulsory properties: a left neighbor and data. An interstitial cell possesses all three compulsory properties: a left neighbor, a right neighbor, and data.
+ </p>
+
+ <p>
+ Said neighbor properties are singular. When the left neighbor property is present, there is exactly one left neighbor, and when the right neighbor property is present, there is exactly one right neighbor. Said data property is restricted to being either an instance of an alphabet symbol, or alternatively, an instance of the <RT-term>empty-symbol</RT-term>.
+ </p>
+
+ <h2>The Turing Machine tape</h2>
+
+ <p>
+ The Turing Machine tape is a set containing exactly one leftmost cell and an infinite number of interstitial cells. For each cell in the set, called cell A, if cell A has a right neighbor that is cell B, then cell B's left neighbor is cell A. Similarly, if cell A has a left neighbor of cell B, then cell B's right neighbor is cell A. Furthermore, every cell in the set must be reachable by traversing right neighbors starting from the leftmost cell.
+ </p>
+
+ <p>
+ Once a tape is defined, properties can not be added nor removed from the constituent cells. Further, the neighbor properties definitions are fixed. Cells don't move, new cells can not be added, and cells existing on the tape can not be removed. We can say that a Turing Machine tape has a constant, fixed, <RT-term>topology</RT-term>.
+ </p>
+
+ <p>
+ Nor can the data property be removed; however, unlike neighbor properties, the data property is a variable. While a Turing Machine is operating, the data property can be set to different values.
+ </p>
+
+ <p>
+ Initially the Turing Machine tape is filled with empty symbols. A Turing Machine does not have the ability to fill an empty tape in a finite number of steps, so no Turing machine can compute and erase an entire tape. The initial tape must be made by other means, and at this point in our discussion we punt this issue, as all others have done thus far, and <em>define</em> that there is a supply of initially pristine tapes. Because empty tapes are made only by definition, the empty symbol is special. This is the reason that we defined the empty-symbol separately from the alphabet. As we will further discover later in this volume, the very concept of emptiness is special.
+ </p>
- <p>Intuitively we might consider that the alphabet symbols are useful while the empty symbol is merely taking up space while waiting to be displaced, in the same manner that we consider a bookshelf to be empty rather than being full of air. (And if we put a bookshelf underwater is it still empty, or is it full of water?).</p>
+ <p>
+ There is no concept of 'in between' cells in the Turing Machine model. The head either points at one cell, or its neighbor. There is no half step. This is a feature of the tape, and this feature facilitates the view that the tape is an abstraction of an addressed computer memory. As there are no fractional addresses to a computer memory, there are in between address memory values. This is also theoretically important, as it ties back to the Peano Axioms and Peano arithmetic, which is often made use of in computation theoretic proofs.
+ </p>
- <p>The tape is an infinite sequence.</p>
+ <p>
+ It is because there is no 'in between', that the tape is a different object than a Path Graph, as a Path Graph has edge objects in between vertices, and those edges can carry properties.
+ It is possible to create a correspondence while carrying a this no properties constraint. I.e. that the cells in the tape correspond to vertices, that the neighbor properties correspond to edges, and, the adding the constraint that the edges are not allowed to have properties. Though again, that constraint causes the tape to a different object. However, this is not to say that a tape can not be used to hold the representation of a path graph. Doing so would require some additional overhead beyond that of an array of cells representing vertices.
+ </p>
- <p>We say that the first element in the tape sequence is the <RT-term>leftmost</RT-term> element.</p>
- <p>The second element in the sequence is then the <RT-term>right neighbor</RT-term> of the leftmost element. Etc. this nomenclature is drawn from a left to right writing convention for sequences. The leftmost element has no left neighbor, but it does have a right neighbor. All other sequence elements have both a left neighbor and a right neighbor. A Turing Machine tape has no rightmost element because it is an infinite sequence.</p>
+ <h2>The Turing Machine tape head</h2>
- <p>We notice three special subsequences:</p>
- <ol>
- <li>a first, leftmost, element which is either an alphabet symbol or the empty-symbol</li>
- <li>optionally this is followed by a sequence extending to a rightmost alphabet symbol</li>
- <li>if the second subsequence is finite, it is followed by an infinite sequence of empty-symbols.</li>
- </ol>
+ <p>
+ The tape head is a set of four functions and a reference to exactly one of the tape cells. Namely, <RT-code>read</RT-code>, <RT-code>write</RT-code>, <RT-code>step-left</RT-code>, <RT-code>step-right</RT-code>. In addition the tape head can throw an error, <RT-code>left-of-leftmost</RT-code> if the Turing Machine attempts to step left of the leftmost cell. When stepping the cell reference in the head is changed based on the properties found in the currently referenced cell. The cell referenced by the head is called <RT-term>the cell the head is on</RT-term>, or more simply, <RT-term>the head cell</RT-term>.
+ </p>
- <p>So as to distinguish this tape partitioning from others found in this volume, we give it the name, the <RT-neologism>Leftmost Rightmost Partitioning</RT-neologism>, because it emphasizes the location of the leftmost element (alphabet or empty) and the rightmost alphabet element.</p>
+ <p>
+ We can say that the head indexes the cell, but his should not be confused with an index in the sense of indexing an array. This definition of the Turing Machine is built on fundamental principles and does not depend on the definition of Natural Numbers. We will discuss addresses, which are Natural Numbers, further on in this volume.
+ </p>
- <p>It is because of this third subsequence, the infinite tail, that the empty-symbol became distinct from the alphabet.</p>
+ <p>
+ We call a subset of contiguous cells an <RT-term>area</RT-term>.
+ A tape can be partitioned into multiple areas.
+ </p>
- <p>A Turing Machine lacks the capacity to compute an infinite empty tail, so such a tail must come from somewhere else. Here, we provide it by definition.</p>
+ <p>A tape that has no alphabet characters on it is said to be an <RT-term>empty tape</RT-term>.
+ </p>
- <p>Putting together the first two subsequences noted above gives us the <RT-term>active area</RT-term>.</p>
+ <h2>Some tape partitions</h2>
- <p>If there is no alphabet character on the tape, then there is no active area (i.e. the active area has length 0).</p>
+ <h3>Head partition</h3>
- <p>The infinite right going tail of cells holding the empty-symbol is then the <RT-term>inactive area</RT-term>.</p>
+ <ol>
+ <li>The left side: a potentially empty finite set containing all of the cells to the left of the cell the head is on.</li>
- <p>The initial active area provided to a Turing Machine is called the <RT-term>input</RT-term>.</p>
+ <li>Head: the head cell</li>
- <p>The final active area, obtained after the Turing Machine halts, is called the <RT-term>output</RT-term>.</p>
+ <li>The right side: The infinite set extending from the right neighbor of the head cell.</li>
+ </ol>
- <p>If the input has been computed solely from another Turing Machine, then that input, will necessarily be finite in length.</p>
+ <h3>Leftmost/remaining partition</h3>
- <p>If the input is provided as a general mathematical object, perhaps even one abstracted from 'what a Turing Machine computation would produce if it ran to an infinite limit number of steps', then the input has permission to be either finite or infinite.</p>
+ <ol>
+ <li>Leftmost: the leftmost cell</li>
+ <li>Remaining: the infinite set including the right neighbor of the leftmost cell, and all cells further to the right.</li>
+ </ol>
- <p>The read/write head indicates one of the elements in the tape sequence.</p>
+ <h3>Active area partition</h3>
- <p>The head functions differently than a Natural Number, as Thomas is probably accustomed to for sequence element indexes.</p>
+ <p>A non-empty tape can be partitioned into the following areas:
+ </p>
- <p>Such a definition would be circular because later we use a Turing Machine to define Natural Numbers and the concept of an address.</p>
+ <ol>
+ <li>The left empty tail: a potentially empty finite set containing all of the cells that have not been written thus far in the computation starting from the leftmost cell extending to the right up to, but not including the leftmost cell that has been written. (For a two way tape, this will be an infinite left going set.)</li>
- <p>Instead, we can think of the head as partitioning the tape into two subsequences. We will call this the <RT-neologism>Head Centric</RT-neologism> partitioning.</p>
+ <li>Active area: A possibly empty finite subset containing the cells extending from the leftmost cell that has been written up to and including the rightmost cell that has been written</li>
- <p>The first subsequence extends from the leftmost element up to the indicated element, inclusively. During computation this first subsequence is necessarily finite. We call it the <RT-term>left-hand side</RT-term>.</p>
+ <li>The right empty tail: The infinite set extending from the right neighbor of the rightmost cell the Turing machine has written thus far, extending rightward.</li>
+ </ol>
- <p>The second subsequence holds the rest of the tape. We call it the <RT-term>right-hand side</RT-term>.</p>
+ <p>
+ In general a Turing Machine can not step across a tape reading cells to find the right empty tail. Say this were attempted, an the machine discovered an empty cell, the Turing Machine could still not know if it continued stepping that it would discover another cell with an alphabet symbol written to it, or not.
+ </p>
- <p>To step the head to the right we remove the leftmost element from the right-hand side, and then append it to, i.e. make it the new rightmost element of, the left-hand side.</p>
+ <p>
+ However, a Turing Machine which is aware that it started computing with an empty tape, could keep track of the address of the rightmost cell that it wrote, and thus know the rightmost cell of the active area. If a Turing Machine is started with a input tape, the problem becomes one of communicating control.
+ </p>
- <p>To step the head left, we remove the rightmost element of the left-hand side, and prepend it, i.e. make it the leftmost element of, the right-hand side.</p>
+ <p>
+ By definition, a computation must finish in a finite number of steps. Hence the activate area when a Turing Machine halts will always be finite. Consequently, if a Turing Machine initially starts working with a tape that was computed by another Turing Machine, the length of the input will be finite. Still that input will be in the active area, so the receiving Turing Machine will likely need to be able read data control data that encodes the location of the end of the active area.
+ </p>
- <p>In the section, <RT-crossref>Addresses and cells</RT-crossref>, we will justify using the term <RT-term>cell</RT-term> in place of element, and then we will be able to say such things as the cell that the head is on, or the indicated cell.</p>
+ <p>If an input tape is provided as a general mathematical object, either decreed by definition, or perhaps abstracted from 'what a Turing Machine computation would produce if it ran to an infinite limit number of steps', then the input can be either finite or infinite.
+ </p>
- <p>The controlling state machine is a graph.</p>
- <p>It has permission to be either a Mealy or Moore style state machine graph, as these are equally expressive.</p>
+ <h2>The controlling state machine</h2>
- <p>Only the fixed procedure would change. We describe a Moore style machine and corresponding procedure here.</p>
+ <p>That controlling state machine can be either a Mealy or Moore style state machine graph, as these are equally expressive. In this volume we describe a Moore style machine and corresponding procedure here.
+ </p>
- <p>The graph is a set containing three elements:</p>
+ <p>The state machine graph is a set containing three elements:</p>
<ul>
<li>set of states</li>
<li>set of <state, command> pairings</li>
<li>set of arcs</li>
</ul>
- <p>A state is a symbol. Instances of state symbols appear in a different context than those of alphabet symbols or the empty-symbol, and thus they do not need to be distinct from them.</p>
+ <p>
+ A state is a symbol. Instances of state symbols appear in a different context than those of alphabet symbols or the empty-symbol, and thus they do not need to be distinct from them.
+ </p>
- <p>Each state has a command attached to it, <state, command>. Each state appears in exactly one such pairing.</p>
+ <p>
+ Each state has a command attached to it, <state, command>. Each state appears in exactly one such pairing.
+ </p>
- <p>We have a fixed set of commands: { do-nothing, step-left, step-right, and write(value) }, where the value parameter is set when the controller is defined.</p>
+ <p>
+ We have a fixed set of commands: { do-nothing, step-left, step-right, and write(value) }, where the value parameter is set when the controller is defined.
+ </p>
- <p>value must be an instance of an alphabet symbol or an instance of the empty-symbol.</p>
+ <p>Data must be an instance of an alphabet symbol or an instance of the empty-symbol.</p>
<p>In addition, we should not forget the implied read command that returns a value from the tape, and is used by the fixed procedure.</p>
go to 2
</RT-code>
- <p>As reviewed by Papadimitriou<RT-cite ref="Harry Lewis and Christos Papadimitriou, Elements of the Theory of Computation"></RT-cite>, such non-deterministic machines can be converted to deterministic ones. This is done by calling each unique 'state set' a state.</p>
+ <p>As reviewed by Papadimitriou <RT-cite ref="Harry Lewis and Christos Papadimitriou, Elements of the Theory of Computation"></RT-cite>, such non-deterministic machines can be converted to deterministic ones. This is done by calling each unique 'state set' a state.</p>
<p>Thomas might recall from our definition of symbol, that we can use any mathematical object for which instances are comparable.</p>
<h2>Natural Number, address</h2>
- <p>We can define a Turing Machine that is identical to the recursive definition of Natural Numbers as given by Peano.<RT-cite ref="Giuseppe Peano, Arithmetices principia, nova methodo exposita"></RT-cite></p>
+ <p>We can define a Turing Machine that is identical to the recursive definition of Natural Numbers as given by Peano. <RT-cite ref="Giuseppe Peano, Arithmetices principia, nova methodo exposita"></RT-cite></p>
<p>As the Natural Numbers never end, we cannot run this machine to a halting point, but we can analyze it.</p>