{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
""
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"id": "5ju1mn7Tur1V"
},
"source": [
"# Universal programs\n",
"\n",
"We discuss universal programs:\n",
"these are programs that take a program as an inputs and (act as if they) run\n",
"the input program.\n",
" \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "F2axy4PUvHFm"
},
"outputs": [],
"source": [
"#@title\n",
"!python -m pip install -U setuptools\n",
"!python -m pip install -U git+https://github.com/lmoss/onesharp.git@main\n",
"from onesharp.interpreter.interpreter import *"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"```{admonition} Definition\n",
":class: attention\n",
"\n",
"A word $u$ is *universal* if\n",
"\n",
"$$\n",
"[\\![u]\\!] (x) \\simeq [\\![x]\\!](\\ )\n",
"$$\n",
"\n",
"for all words $x$.\n",
"```\n",
"\n",
"This means that if running $x$ on all empty registers eventually gives some output in R1 (and all other registers are empty), then that same output would be the result of running $u$ with $p$ in R1 and all other registers empty. In the other direction, *if* running $x$ with all empty registers gives some output, say $y$, in R1 (and all registers empty at the end), then we would get the same output $y$ in R1 when we run $u$ with $x$ in R1 and all other registers empty.\n",
"\n",
"Let's take a look at such a program and try it out."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 571
},
"id": "4X9YC9eTu3M1",
"outputId": "974ba216-d1b7-4ba7-d1c7-6bb04e92426a"
},
"outputs": [],
"source": [
"u = universal\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"id": "TQkSinvCvOPp"
},
"source": [
"```{admonition} Examples\n",
"\n",
"$[\\![u]\\!](\\one\\hash) \\simeq \\one$ because $[\\![\\one\\hash]\\!](\\ )\\simeq \\one$.\n",
"\n",
"$[\\![u]\\!](\\one)\\!\\uparrow$ because $\\one$ is not a program.\n",
"```\n",
"\n",
"```{admonition} More examples\n",
"You might try to figure out what the next two should be and then confirm your guesses by running them.\n",
"\n",
"$[\\![u]\\!](\\one\\hash\\one\\hash\\hash)$\n",
"\n",
"\n",
"$[\\![u]\\!](\\one\\hash \\one\\hash\\hash \\one\\hash \\one\\hash \\hash \\one\\hash \\hash+ u)$\n",
" \n",
"```\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"id": "ff5wd-MKyn9C"
},
"source": [
"\n",
"### Let's write a universal program\n",
"\n",
"\n",
"The next goal is for you to write a universal program\n",
"yourself, either alone or with others. \n",
"The next sections guide you, using a series of exercises.\n",
"\n",
"We hasten to make two remarks: first of all, it would be more\n",
"instructive for you to forget about the rest of this lesson \n",
"entirely and to just write your own universal program. But \n",
" most readers would probably appreciate the hints and will find\n",
"enough of a challenge in the construction of a long working program.\n",
"\n",
"Second, the sections to come do not guide you to write a program that\n",
"is *exactly* like $u$ above. The program $u$ \n",
"above was designed to be as short as possible.\n",
"In fact, we leave you with a challenge: write a universal\n",
"program with the smallest number of instructions. The one above has \n",
"300."
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"id": "rDOKl29NwPvA"
},
"source": [
"### Simplification\n",
"\n",
"We are going to simplify the requirements in order to make\n",
"it easier to write a universal program. So we'll outline how\n",
"to write a program that is close to a universal program,\n",
"but not quite a universal program.\n",
"\n",
"We'll write a program $u$ that acts like a universal\n",
"program, but *only for programs which use only R1, R2, and R3*.\n",
"In more detail:\n",
" \n",
"Let $p$ be any\n",
"program of ```1#``` which only uses R1, R2, and R3.\n",
"Let $x$ be any word on our alphabet ```{1#}```,\n",
"including possibly the empty word. Then the following are equivalent: \n",
"\n",
"(A')\n",
"If $p$ is started with all empty registers, then eventually we halt\n",
"with $x$ in R1. \n",
"\n",
"(B') If $u$ is started with $p$ in R1 and with the empty word \n",
"in all other\n",
"registers, then eventually we halt with $x$ in R1. \n",
"\n",
"Once again, the work of this section sketches a construction of \n",
"such a program $u$. You will need to do much of the work yourself\n",
"in actually getting the program from the sketch. And even when we\n",
"have $u$, it will not be what we really want, since\n",
"the resulting program $u$ will only behave right on programs which use the first\n",
"three registers. \n",
"Later on, we'll come\n",
"back and drop this simplification to get a program which is truly \n",
"universal.\n",
"\n",
"At this point, we are ready to sketch a method for you to\n",
"write a universal program subject to this simplification.\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"We are going to use pseudo-registers as follows:\n",
"\n",
"
R1: the input program p |
R2: an instruction number 1n\n", " | \n", "
R3: the nth instruction of p \n", " |
R4: the contents of the real R1 |
R5: the contents of the real R2 |
R6: the contents of the real R3 |
\n",
"That is, we are going to simulate the \n",
"computation of a register machine on a program p by\n",
"using six registers. Our universal program u \n",
"mimics what a register machine would do.\n",
"The only difference is that one step of a real register machine\n",
"would be done by *many* steps of our universal program.\n",
"\n",
"\n",
"The registers above hold what is sometimes called a snapshot\n",
"of a register machine run. \n",
"This means that they hold all of the relevant information about a register\n",
"machine computation at one particular point in time: they tell what program is\n",
"running, which instruction would be run next and what number instruction it is,\n",
"and also the contents of all of the registers that the program is using.\n",
"Now a real register machine goes from snapshot to snapshot in one step,\n",
"but the universal machine that we are building will take many steps to\n",
"go from one snapshot to the next. \n",
"
\n",
"Our universal program is composed of a few sub-programs.\n",
"We shall illustrate the ideas behind several sub-programs by making a\n",
"large chart. This chart shows just one example\n",
"of how a universal program could work, when we take\n",
"p\n",
"to be the program \n",
"\n",
"$$ \n",
"\\begin{array}{lcl} p & = & \\mathtt{1\\#\\#} + \\mathtt{write}\\\\\n",
"& = & \\mathtt{1\\#1\\#\\#\\#\\#\\#111111111\\#\\#\\#11111\\#\\#\\#11\\#11\\#\\#11\\#\\#111111\\#\\#\\#\\#11\\#11\\#\\#111111111\\#\\#\\#\\#11\\#\\#\\#\\#\\#111111\\#\\#\\#111\\#\\#\\#1\\#\\#1111\\#\\#\\#\\#1\\#111111\\#\\#\\#\\#} \n",
"\\end{array}\n",
"$$\n",
"\n",
" \n",
"
\n",
"
\n", "Let's parse this program and number the \n", "instructions:\n", "
1 | \n", "2 | \n", "3 | \n", "4 | \n", "5 | \n", "6 | \n", "7 | \n", "8 | \n", "9 | \n", "
1## | \n", "1##### | \n", "111111111### | \n", "11111### | \n", "11# | \n", "11## | \n", "11## | \n", "111111#### | \n", "11# | \n", "
10 | \n", "11 | \n", "12 | \n", "13 | \n", "14 | \n", "15 | \n", "16 | \n", "17 | \n", "18 | \n", "
11## | \n", "111111111#### | \n", "11##### | \n", "111111### | \n", "111### | \n", "1## | \n", "1111#### | \n", "1# | \n", "111111#### | \n", "
\n",
"What we are going to show is tables of what the various\n",
"registers show after different parts of a run of a universal program\n",
"u on this program 1# + write.\n",
"We hasten to add that the universal program exhibited above\n",
"does not conform to the tables. (This is because\n",
"registers work differently in it. Also, the program\n",
"above is designed to work even without our simplifying\n",
"assumption.)\n",
"
\n",
"Here are the tables; we'll have some words below about them.\n",
"
\n",
" \n",
"
\n",
" \n",
" R1: the input program p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" \n",
" R2: an instruction number 1n\n",
" \n",
" \n",
" 1 \n",
" 1 \n",
" 11 \n",
" 11 \n",
" 11111 \n",
" 11111 \n",
" 16 \n",
" 16 \n",
" 17 \n",
" 17 \n",
" 18 \n",
" 18 \n",
" \n",
" R3: the nth instruction of p \n",
" \n",
" \n",
" 1## \n",
" \n",
" 1##### \n",
" \n",
" 11# \n",
" \n",
" 11## \n",
" \n",
" 11## \n",
" \n",
" 16 #### \n",
" \n",
" R4: the contents of R1 \n",
" \n",
" \n",
" \n",
" # \n",
" # \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" R5: the contents of R2 \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" 1 \n",
" \t1 \n",
" 1# \n",
" \t1# \n",
" 1## \n",
" 1## \n",
" \n",
"R6: the contents of R3 \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
"
\n",
"continuing\n",
"
\n",
" \n",
"
\n",
" \n",
" R1: the input program p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" \n",
" R2: an instr number 1n\n",
" \n",
" 11 \n",
" 11 \n",
" 111 \n",
" 111 \n",
" 112 \n",
" 112 \n",
" 114 \n",
" 114 \n",
" 117 \n",
" 117 \n",
" 118 \n",
" 118 \n",
" \n",
" R3: the nth instruction of p \n",
" \n",
" 1##### \n",
" \n",
" 19 ### \n",
" \n",
" 11##### \n",
" \n",
" 111### \n",
" \n",
" 1# \n",
" \n",
" 16 #### \n",
" \n",
" R4: the contents of R1 \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" 1 \n",
" 1 \n",
" \n",
" R5: the contents of R2 \n",
" 1## \n",
" 1## \n",
" 1## \n",
" 1## \n",
" 1## \n",
" 1## \n",
" 1## \n",
" \t1## \n",
" ## \n",
" \t## \n",
" ## \n",
" ## \n",
" \n",
"R6: the contents of R3 \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
"
\n",
"and going further in the move2,1 part\n",
"at the end of write\n",
" \n",
"
\n",
" \n",
" R1: the input program p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" \n",
" R2: an instruction number 1n\n",
" \n",
" 112 \n",
" 112 \n",
" 115 \n",
" 115 \n",
" 116 \n",
" 116 \n",
" 112 \n",
" 112 \n",
" 115 \n",
" 115 \n",
" 116 \n",
" 116 \n",
" \n",
" R3: the nth instruction of p \n",
" \n",
" 11##### \n",
" \n",
" 1## \n",
" \n",
" 14#### \n",
" \n",
" 11##### \n",
" \n",
" 1## \n",
" \n",
" 14#### \n",
" \n",
" R4: the contents of R1 \n",
" 1 \n",
" 1 \n",
" 1 \n",
" 1 \n",
" 1# \n",
" 1# \n",
" 1# \n",
" 1# \n",
" 1# \n",
" 1# \n",
" 1## \n",
" 1## \n",
" \n",
" R5: the contents of R2 \n",
" ## \n",
" ## \n",
" # \n",
" # \n",
" # \n",
" # \n",
" # \n",
" \t# \n",
" \n",
" \t \n",
" \n",
" \n",
" \n",
"R6: the contents of R3 \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
"
\n",
"
\n",
"and concluding\n",
"
\n",
" \n",
"
\n",
" \n",
" R1: the input program p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" p \n",
" 1## \n",
" \n",
" R2: an instruction number 1n\n",
" \n",
" 112 \n",
" 112 \n",
" 113 \n",
" 113 \n",
" 119 \n",
" \n",
" \n",
" R3: the nth instruction of p \n",
" \n",
" 11##### \n",
" \n",
" 16 ### \n",
" \n",
" \n",
" \n",
" R4: the contents of R1 \n",
" 1## \n",
" 1## \n",
" 1## \n",
" 1## \n",
" 1## \n",
" \n",
" \n",
" R5: the contents of R2 \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
"\n",
" \n",
"R6: the contents of R3 \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
"
\n", "As you can see, there are four different colors of the columns.\n", "\n", "
orange: starting out by pre-processing the input (if desired) and putting 1 in R2 |
beige: put into R3 the nth instruction of the program in R1, where 1n is in R2 |
green: execute the action in R3, but using R4 instead of R1, R5 instead of R2, and R6 instead of R3 |
yellow: finishing up by moving and clearing the relevant registers |
\n",
"The colors indicate the sub-programs of u.\n",
"The columns themselves indicate the register contents when one\n",
"of the sub-programs begins.\n",
"
\n",
"The first color shown is orange.\n",
"This is the the easiest to explain. The orange sub-program could be 11#. \n",
"This indicates that at the\n",
"very beginning of the execution of\n",
"the input program, the instruction to look at first is instruction 1. But if you decide to pre-process the input program (see below), then the orange sup-program would do this as well.\n",
"
\n",
"The beige columns alternate with the green columns.\n",
"The purpose of the beige program is to take the input program\n",
"(in R1) and the next instruction number (R2), and to\n",
"look up the appropriate \n",
"instruction and put it into R3. But we need to be sure that the contents\n",
"of R1 and R2 are not destroyed at the end. The way to understand\n",
"the beige columns is that they tell the contents of the various registers\n",
"at the beginning of the operation of the \"beige\n",
"sub-program\". You will need to write that sub-program.\n",
"It is a fairly straightforward modification of a program which\n",
"takes an input program q and a number n and gives the nth instruction of\n",
"q. But you need to be\n",
"sure that the output goes in R3, and that the input is preserved.\n",
"
\n",
"The main action of the steps is done in the green columns;\n",
"more precisely, \n",
"the columns shown are the beginnings of the\n",
"\"green\" sub-program, and then the results of that sub-program\n",
"are the beige columns which follow.\n",
"The exact action depends on what kind of instruction is in R3 in \n",
"the given green column. For example, if R3 has `≈, then\n",
"in the next beige column we add a # to R5 (not R2: it is R5\n",
"that models what is in R2 of the real machine when we run \n",
"program). We also must add 1 to R2 in simulating the execution\n",
"of 11#, since after 11#, we go to the very next instruction.\n",
"This is how the green columns work when we execute an instruction\n",
"11#. The other cases are left for you to think about.\n",
"Note also that each time the green sub-program runs, R3 is emptied \n",
"at the end.\n",
"
\n",
"The last column color is the yellow one at the very end.\n",
"Before the yellow one starts up, the beige program\n",
"has determined (in some sense) that \n",
" our program $p$ has 18 instructions and we have \n",
" come to a point where we ask for instruction 19. Thus, \n",
" the input program has halted. We therefore want to\n",
" take the contents of R1 as run by the input program\n",
" (this is the word in R4), and move this to R1.\n",
" Also, we would like to clear out the contents of\n",
" whichever registers are not empty. We do this so that \n",
" the program we are writing will itself come to a good halt\n",
" on its input.\n",
"
\n",
"
\n",
"It might seem silly to have R1 unchanged throughout.\n",
"But this isn't really what is happening at all.\n",
"In the course of the beige subprograms, parts of R1 are copied\n",
"to other registers, and the copied back. So at the \n",
"end of the beige sub-programs, we have the original\n",
"program p back in R1. \n",
"
\n", "Similarly, it might seem weird to have R6 completely unused\n", "in running a universal program on p. This is due\n", "to the fact that our program p only uses R1 and R2.\n", "If we worked with an example program that used R3, then R6\n", "would not have remained empty in the tables.\n", "\n", "\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "id": "Vq9XIPJ-3JVP" }, "source": [ "## Coding unboundedly many registers into one\n", "\n", "The simplified form of the universal program that we just saw could be modified to work on programs with any fixed finite number of registers. But we want one universal programs that works on *all* programs, without a pre-established bound. For this, we need a new idea. \n", "\n", "We now call upon a technique introduced in a separate notebook in this course, the technique of [two-by-two encoding](two_by_two.ipynb). That notebook shows how we can add an *end of register marker* to R1, and the work with a simple encoding of symbols by pairs. We took the end of register marker to be ```##```, and we encoded ```1``` by ```11``` and ```#``` by ```1#```. \n", "\n", "All of that work was for R1 alone. But we could do the same work for all of the other registers. \n", "\n", "Following this, the idea is to simply run all of the encoded registers into one. \n", "\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": { "id": "frwGL8oj9fWQ" }, "source": [ "For an example of what we mean, suppose that we were dealing with the following snapshot:\n", "\n", "
R1: 11# | \n", "R2: | \n", "R3: ## | \n", "R4: | \n", "R5: | \n", "R6: 1 | \n", "R7: # | \n", "R8: ##1 | \n", "
Contents | \n", "R1: 11# | \n", "R2: | \n", "R3: ## | \n", "R4: | \n", "R5: | \n", "R6: 1 | \n", "R7: # | \n", "R8: ##1 | \n", "
Encoded as | \n", "11111### | \n", "## | \n", "1#1### | \n", "## | \n", "## | \n", "11## | \n", "1# ## | \n", "1#1#11## | \n", "
\n",
"
\n",
"
\n", "Here is what each group needs to do:\n", "