From ea4f5cd3604723fc06ae6813ff9f0967e7b818eb Mon Sep 17 00:00:00 2001 From: JingyuYan Date: Fri, 1 Nov 2024 00:04:25 +0800 Subject: [PATCH 1/2] working --- URM_en.ipynb | 2611 +++++++++++++++++++++++++++----------------------- 1 file changed, 1427 insertions(+), 1184 deletions(-) diff --git a/URM_en.ipynb b/URM_en.ipynb index a979f76..6383ce0 100644 --- a/URM_en.ipynb +++ b/URM_en.ipynb @@ -1,1215 +1,1458 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "view-in-github" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9znhUfwKqTbC" + }, + "source": [ + "

Unlimited Register Machine

" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "j80Dq1uYTM5X" + }, + "source": [ + "**U**nlimited **R**egister **M**achine (URM) is a realization of the approach to programming based on the automaton concept.\n", + "URM is an easier-to-understand alternative to a Turing machine.\n", + "\n", + "It has (to a certain extent) the same capabilities as the Turing machine, to which URM is logically equivalent.\n", + "The URM was presented in an article published in 1963\n", + "\n", + ">[John C. Shepherdson and H.E. Sturgis: *Computability of Recursive Functions*. J. ACM Vol. 10, no. 2, pp. 217–255.](https://dl.acm.org/doi/pdf/10.1145/321160.321170)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "v09Os5dUx9HG" + }, + "source": [ + "# Preparing a notebook to use" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { "colab": { - "provenance": [], - "toc_visible": true, - "include_colab_link": true - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" + "base_uri": "https://localhost:8080/" }, - "language_info": { - "name": "python" + "id": "0uybnLWmIUXM", + "outputId": "3f49375b-bccc-4466-a2cd-f7912e9b4489" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Mounted at /content/drive\n" + ] } + ], + "source": [ + "from google.colab import drive\n", + "drive.mount('/content/drive')\n", + "\n", + "import sys\n", + "sys.path.append('/content/drive/MyDrive/ColabNotebooks/Computability')" + ] }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "view-in-github", - "colab_type": "text" - }, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "source": [ - "

Unlimited Register Machine

" - ], - "metadata": { - "id": "9znhUfwKqTbC" - } - }, - { - "cell_type": "markdown", - "source": [ - "**U**nlimited **R**egister **M**achine (URM) is a realization of the approach to programming based on the automaton concept.\n", - "URM is an easier-to-understand alternative to a Turing machine.\n", - "\n", - "It has (to a certain extent) the same capabilities as the Turing machine, to which URM is logically equivalent.\n", - "The URM was presented in an article published in 1963\n", - "\n", - ">[John C. Shepherdson and H.E. Sturgis: *Computability of Recursive Functions*. J. ACM Vol. 10, no. 2, pp. 217–255.](https://dl.acm.org/doi/pdf/10.1145/321160.321170)" - ], - "metadata": { - "id": "j80Dq1uYTM5X" - } - }, - { - "cell_type": "markdown", - "source": [ - "# Preparing a notebook to use" - ], - "metadata": { - "id": "v09Os5dUx9HG" - } - }, - { - "cell_type": "code", - "source": [ - "from google.colab import drive\n", - "drive.mount('/content/drive')\n", - "\n", - "import sys\n", - "sys.path.append('/content/drive/MyDrive/ColabNotebooks/Computability')" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "0uybnLWmIUXM", - "outputId": "3f49375b-bccc-4466-a2cd-f7912e9b4489" - }, - "execution_count": 1, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Mounted at /content/drive\n" - ] - } - ] - }, - { - "cell_type": "code", - "source": [ - "from typing import Dict, Any, Optional, Tuple, List\n", - "from typing_extensions import Self\n", - "from functools import reduce\n", - "from compy.nat import nat" - ], - "metadata": { - "id": "UXJMbTOywbm7" - }, - "execution_count": 2, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "# Memory of UMR" - ], - "metadata": { - "id": "HzUdUTt7HgUK" - } - }, - { - "cell_type": "markdown", - "source": [ - "## Registers" - ], - "metadata": { - "id": "yYfVbwVlUtTA" - } - }, - { - "cell_type": "markdown", - "source": [ - "URM has an enumerated set of ***registers***, each of which can store a natural number $n\\in\\mathbb{N}$, where $\\mathbb{N}=\\{0,1,2,\\dotsc\\} $.\n", - "\n", - "Each URM program can use only a finite set of registers.\n", - "\n", - "Registers are usually denoted by a capital letter $R$ with an index: $R_{0},R_{1},R_{2},\\dotsc$.\n", - "The index (which is a natural number) is called the ***register index***.\n", - "The number holding register $R_{n}$ is usually denoted by $r_{n}$.\n", - "\n", - "Registers are unlimited in the following two senses:\n", - "\n", - "- even though a URM program can use only a finite set of registers, there is no upper limit for the number of registers used by the programs;\n", - "- there is no upper limit for numbers stored by registers." - ], - "metadata": { - "id": "5feB_pFWU738" - } - }, - { - "cell_type": "markdown", - "source": [ - "## Memory states" - ], - "metadata": { - "id": "4ehurE3IWVKK" - } - }, - { - "cell_type": "markdown", - "source": [ - "The state of the memory is determined by the values ​​stored in the registers." - ], - "metadata": { - "id": "hlqyf9r6WamQ" - } - }, - { - "cell_type": "markdown", - "source": [ - "## Software implementation" - ], - "metadata": { - "id": "JKN8B0vKW0OB" - } - }, - { - "cell_type": "markdown", - "source": [ - "The memory of URM is implemented as class `memory` inherited from the built-in type `list`.\n", - "\n", - "The property `size` equals the length of the corresponding list.\n", - "\n", - "The methods `read()` and `write()` provide correct reading from and writing to the memory." - ], - "metadata": { - "id": "IGQ1ohl7kIzK" - } - }, - { - "cell_type": "code", - "source": [ - "class memory(list):\n", - "\n", - " def __new__(cls) -> Self:\n", - " return super().__new__(cls, [])\n", - "\n", - " @property\n", - " def size(self) -> int:\n", - " return len(self)\n", - "\n", - " def read(self, addr: int) -> nat:\n", - " try:\n", - " n = nat(addr)\n", - " except ValueError:\n", - " raise ValueError(\"memory.read() error! Bad argument\")\n", - " try:\n", - " return self[n]\n", - " except IndexError:\n", - " return nat(0)\n", - "\n", - " def write(self, addr: int, value: Any) -> None:\n", - " try:\n", - " n, v = nat(addr), nat(value)\n", - " except ValueError:\n", - " raise ValueError(\"memory.write() error! Bad argument(s)\")\n", - " diff = self.size - n\n", - " if diff <= 0: # access to a register that is not yet allocated\n", - " self += (1 - diff) * [nat(0)] # allocate additional registers\n", - " self[n] = v\n" - ], - "metadata": { - "id": "SivyyEI1H1El" - }, - "execution_count": 3, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## URM-programs" - ], - "metadata": { - "id": "K2ea07zgWg6Q" - } - }, - { - "cell_type": "markdown", - "source": [ - "***Execution states***, that is, the value of the registers and the instruction counter, is changed by programs.\n", - "\n", - "A ***URM program*** is a finite list of ***instructions***.\n", - "\n", - "Program instructions are written in a certain order and numbered with positive natural numbers $1,2,3,\\dotsc$.
\n", - "**Please note!** Instruction number 0 does not exist in the program.\n", - "\n", - "The instruction number for historical reasons is called the ***program line number***." - ], - "metadata": { - "id": "lWOiwFXtWpDZ" - } - }, - { - "cell_type": "markdown", - "source": [ - "## Instruction counter" - ], - "metadata": { - "id": "32IJjIbpWBGs" - } - }, - { - "cell_type": "markdown", - "source": [ - "The ***instruction counter*** is an additional register that stores a natural number.\n", - "This register is denoted by $IC$ and its contents are $ic$." - ], - "metadata": { - "id": "eBeuV9d4WL7h" - } - }, - { - "cell_type": "markdown", - "source": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
NameMnemonic codeEffectDescription
Zero$\\mathtt{Z}(n)$$R_n\\gets 0$
$IC\\gets ic+1$
Replace the value in $R_{n}$ with $0$ and jump to the nextline of the
program
Successor$\\mathtt{S}(n)$$R_n\\gets r_n+1$
$IC\\gets ic+1$
Increase the value of register $R_{n}$ by $1$ and jump to the next line of
the program
Copy$\\mathtt{C}(m,n)$$R_n\\gets r_m$
$IC\\gets ic+1$
Replace the value in $R_{n}$ with the content of $R_{m}$ (keeping the
content of $R_{m}$) and jump to the next line of the program
Jump$\\mathtt{J}(m,n,k)$$IC\\gets k\\ \\mathtt{if}\\ r_m=r_n\\ \\mathtt{else}\\ ic+1$If the values ​​stored in $R_{m}$ and $R_{n}$ match, then jump to the
program line with number $k$, otherwise to the next program line
" - ], - "metadata": { - "id": "8qzxofV3XxDd" - } - }, - { - "cell_type": "markdown", - "source": [ - "## Software implementation" - ], - "metadata": { - "id": "nmmw7_IM66tM" - } - }, - { - "cell_type": "markdown", - "source": [ - "The `ins` class provides the data type implementation inhabited by the URM instructions.\n", - "\n", - "- The instruction `Z(n)` is represented by a tuple `(0, n)`.\n", - "- The instruction `S(n)` is represented by a tuple `(1, n)`.\n", - "- The instruction `C(m, n)` is represented by the tuple `(2, m, n)`.\n", - "- The instruction `J(m, n, k)` is represented by the tuple `(3, m, n, k)`.\n", - "\n", - "To correctly represent instructions by strings, the `__str__()` method is overloaded for this class.\n", - "\n", - "The class methods `Z()`, `S()`, `C()` and `J()` provide convenient instruction creation." - ], - "metadata": { - "id": "6ccI_PKAazXL" - } - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "id": "b6jA7G8rqOg9" - }, - "outputs": [], - "source": [ - "class ins(tuple):\n", - "\n", - " def __new__(cls, *args: Tuple[int]) -> Self:\n", - " if not (2 <= len(args) <= 4):\n", - " raise ValueError(\"ins() error! Invalid number of arguments\")\n", - " if not all(type(arg) == int for arg in args):\n", - " raise ValueError(\"ins() error! Invalid type of argument(s)\")\n", - " if args[0] > 3:\n", - " raise ValueError(\"ins() error! Invalid instruction code\")\n", - " if not all(arg >= 0 for arg in args[1 :]):\n", - " raise ValueError(\"ins() error! Invalid value of operand(s)\")\n", - " return super().__new__(cls, args)\n", - "\n", - " def __str__(self) -> str:\n", - " if self[0] == 0:\n", - " return f\"Z({self[1]})\"\n", - " if self[0] == 1:\n", - " return f\"S({self[1]})\"\n", - " if self[0] == 2:\n", - " return f\"C{self[1 :]}\"\n", - " # self[0] == 3\n", - " return f\"J{self[1 :]}\"\n", - "\n", - " @classmethod\n", - " def Z(cls, n: Any) -> Self:\n", - " try:\n", - " return ins(0, n)\n", - " except ValueError:\n", - " raise ValueError(\"Z() error! Bad operand\")\n", - "\n", - " @classmethod\n", - " def S(cls, n: Any) -> Self:\n", - " try:\n", - " return ins(1, n)\n", - " except ValueError:\n", - " raise ValueError(\"S() error! Bad operand\")\n", - "\n", - " @classmethod\n", - " def C(cls, m: Any, n: Any) -> Self:\n", - " try:\n", - " return ins(2, m, n)\n", - " except ValueError:\n", - " raise ValueError(\"C() error! Bad operand(s)\")\n", - "\n", - " @classmethod\n", - " def J(cls, m: Any, n: Any, k: Any) -> Self:\n", - " try:\n", - " return ins(3, m, n, k)\n", - " except ValueError:\n", - " raise ValueError(\"J() error! Bad operand(s)\")\n" - ] - }, - { - "cell_type": "markdown", - "source": [ - "## Instructions execution" - ], - "metadata": { - "id": "789mprGe7NE-" - } - }, - { - "cell_type": "markdown", - "source": [ - "The execution of `instruction: ins` if the memory state is `memory_state` implements by calling `apply(instruction, to=memory_state)`, which provides returning the pair `(how_to_change_IC, new_memory_state)`.\n", - "\n", - "The value of `how_to_change_IC` is equal to\n", - "\n", - "- `None`, if after the instruction `instruction` it is necessary to execute the instruction in the next line of the program;\n", - "- the line number of the instruction that will be executed next, if it is not the next in order in the program.\n", - "\n", - "The value `new_memory_state` is the state of the memory after the execution of the instruction `instruction`." - ], - "metadata": { - "id": "MiHtXnCkhpPQ" - } - }, - { - "cell_type": "code", - "source": [ - "def apply(i: ins, to: memory) -> Tuple[Optional[int], memory]:\n", - " if type(to) != memory:\n", - " raise ValueError(\"do() error! Invalid type of memory\")\n", - " if type(i) != ins:\n", - " raise ValueError(\"do() error! Invalid type of instruction\")\n", - " if i[0] == 0:\n", - " to.write(i[1], 0)\n", - " return (None, to)\n", - " if i[0] == 1:\n", - " to.write(i[1], to.read(i[1]) + 1)\n", - " return (None, to)\n", - " if i[0] == 2:\n", - " to.write(i[2], to.read(i[1]))\n", - " return (None, to)\n", - " # i[0] == 3\n", - " return (i[3] if to.read(i[1]) == to.read(i[2]) else None, to)" - ], - "metadata": { - "id": "7Z2kQRzF7SpR" - }, - "execution_count": 5, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "m = memory()\n", - "for n in range(10):\n", - " m.write(n, n)\n", - "print(f\"{13 * ' '}m = {m}\")\n", - "next, m = apply(ins.Z(9), to=m)\n", - "print(f\"next = {next}; m = {m}\")\n", - "next, m = apply(ins.S(9), to=m)\n", - "print(f\"next = {next}; m = {m}\")\n", - "next, m = apply(ins.C(9, 0), to=m)\n", - "print(f\"next = {next}; m = {m}\")\n", - "next, m = apply(ins.J(1, 9, 5), to=m)\n", - "print(f\"next = {next}; m = {m}\")\n", - "next, m = apply(ins.J(2, 3, 10), to=m)\n", - "print(f\"next = {next}; m = {m}\")" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "J2-oNVEWd959", - "outputId": "73051929-cfff-4441-f57b-8865cfada4ee" - }, - "execution_count": 6, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - " m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", - "next = None; m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 0]\n", - "next = None; m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", - "next = None; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", - "next = 5; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", - "next = None; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "# URM-programs and their execution" - ], - "metadata": { - "id": "l74nSpgBSl7m" - } - }, - { - "cell_type": "markdown", - "source": [ - "## Translation of a source text into an instruction list" - ], - "metadata": { - "id": "w54V9h05mE5q" - } - }, - { - "cell_type": "markdown", - "source": [ - "The function `compile()` converts the text into a list of URM instructions." - ], - "metadata": { - "id": "WlcJ1IPezSwS" - } - }, - { - "cell_type": "code", - "source": [ - "def compile(text: str) -> Tuple[ins]:\n", - " if not isinstance(text, str):\n", - " raise ValueError(\"compile() error! Invalid argument type\")\n", - " # split `text` into the list of non empty lines\n", - " lines = [line for line in [item.strip() for\n", - " item in text.split('\\n')] if\n", - " line]\n", - " # the function compiles a line\n", - " def compile_line(line: str) -> ins:\n", - " # remove the tail of 'line' beginning with ')'\n", - " item, sep, _ = line.partition(')')\n", - " if not sep: # ')' is absent in the line\n", - " raise ValueError(\"compile_line() error! Bad instruction format\")\n", - " code, sep, item = item.partition('(')\n", - " if not sep: # '(' is absent in the line\n", - " raise ValueError(\"compile_line() error! Bad instruction format\")\n", - " if code.strip() == 'Z':\n", - " try: # to recognize Z-instruction\n", - " return ins.Z(int(item))\n", - " except ValueError:\n", - " raise ValueError(\"compile_line() error! Bad Z-instruction\")\n", - " elif code.strip() == 'S':\n", - " try: # to recognize S-instruction\n", - " return ins.S(int(item))\n", - " except ValueError:\n", - " raise ValueError(\"compile_line() error! Bad S-instruction\")\n", - " elif code.strip() == 'C':\n", - " op1, sep, item = item.partition(',')\n", - " try: # to recognize C-instruction\n", - " return ins.C(int(op1), int(item))\n", - " except ValueError:\n", - " raise ValueError(\"compile_line() error! Bad C-instruction\")\n", - " elif code.strip() == 'J':\n", - " op1, sep, item = item.partition(',')\n", - " op2, sep, item = item.partition(',')\n", - " try: # to recognize J-instruction\n", - " return ins.J(int(op1), int(op2), int(item))\n", - " except:\n", - " raise ValueError(\"compile_line() error! Bad J-instruction\")\n", - " raise ValueError(\"compile_line() error! Bad instruction format\")\n", - " # end of compile_line()\n", - " return tuple(compile_line(line) for line in lines)" - ], - "metadata": { - "id": "OfLgefRfrGCj" - }, - "execution_count": 7, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "An example of using the `compile()` function." - ], - "metadata": { - "id": "eBcW57NO6-aM" - } - }, - { - "cell_type": "code", - "source": [ - "text = \"\"\"\n", - " C(2, 0)\n", - " Z (2)\n", - "\n", - " J(1, 2, 0) check loop condition\n", - " S(0)\n", - " S(2)\n", - " J(0, 0, 3) repeat loop\n", - "\"\"\"\n", - "\n", - "ins_tuple = compile(text)\n", - "for ni, i in enumerate(ins_tuple):\n", - " print(f\"{ni + 1:3d}: {i}\")" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "5wMcWBoqmnEZ", - "outputId": "569dbfd1-554e-409b-e996-6510e2252283" - }, - "execution_count": 8, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - " 1: C(2, 0)\n", - " 2: Z(2)\n", - " 3: J(1, 2, 0)\n", - " 4: S(0)\n", - " 5: S(2)\n", - " 6: J(0, 0, 3)\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "## URM-programs" - ], - "metadata": { - "id": "FV-cDiTES0V4" - } - }, - { - "cell_type": "markdown", - "source": [ - "### Software implementation of a URM-program" - ], - "metadata": { - "id": "rir1QLi5B160" - } - }, - { - "cell_type": "code", - "source": [ - "class program(tuple):\n", - "\n", - " def __new__(cls, instructions: Tuple[ins]) -> Self:\n", - " if not type(instructions) == tuple:\n", - " raise ValueError(\"program() error! Invalid argument type\")\n", - " if not all(type(instruction) == ins for instruction in instructions):\n", - " raise ValueError(\"program() error! Invalid type of argument member\")\n", - " return super().__new__(cls, instructions)\n", - "\n", - " def __str__(self):\n", - " return \"\\n\".join([f\"{ni + 1: 3d}: {i}\" for ni, i in enumerate(self)])\n", - "\n", - " @property\n", - " def length(self):\n", - " return len(self)\n", - "\n", - " @property\n", - " def haddr(self):\n", - " temp = 0\n", - " for i in self:\n", - " temp = max(temp, *i[1 : 3])\n", - " return temp\n", - "\n", - " def get_instruction(self, lineno: int) -> Optional[ins]:\n", - " if type(lineno) != int:\n", - " raise ValueError(\"program.get_instruction() error! Bad line number\")\n", - " if lineno < 1:\n", - " return None\n", - " try:\n", - " return self[lineno - 1]\n", - " except IndexError:\n", - " return None" - ], - "metadata": { - "id": "irEaC4-iS6nD" - }, - "execution_count": 9, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "p = program(compile(text))\n", - "print(f\"Program text:\\n{p}\")\n", - "print(f\"Program length = {p.length}\")\n", - "print(f\"Program highest address = {p.haddr}\")" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "ca3jyBTE7Nu9", - "outputId": "318d3dda-98cb-4311-bfb7-78f196e6b156" - }, - "execution_count": 12, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Program text:\n", - " 1: C(2, 0)\n", - " 2: Z(2)\n", - " 3: J(1, 2, 0)\n", - " 4: S(0)\n", - " 5: S(2)\n", - " 6: J(0, 0, 3)\n", - "Program length = 6\n", - "Program highest address = 2\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "### Execution of a URM-program" - ], - "metadata": { - "id": "bNrUp10RB9KH" - } + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "UXJMbTOywbm7" + }, + "outputs": [], + "source": [ + "from typing import Dict, Any, Optional, Tuple, List\n", + "from typing_extensions import Self\n", + "from functools import reduce\n", + "from compy.nat import nat" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HzUdUTt7HgUK" + }, + "source": [ + "# Memory of UMR" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yYfVbwVlUtTA" + }, + "source": [ + "## Registers" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5feB_pFWU738" + }, + "source": [ + "URM has an enumerated set of ***registers***, each of which can store a natural number $n\\in\\mathbb{N}$, where $\\mathbb{N}=\\{0,1,2,\\dotsc\\} $.\n", + "\n", + "Each URM program can use only a finite set of registers.\n", + "\n", + "Registers are usually denoted by a capital letter $R$ with an index: $R_{0},R_{1},R_{2},\\dotsc$.\n", + "The index (which is a natural number) is called the ***register index***.\n", + "The number holding register $R_{n}$ is usually denoted by $r_{n}$.\n", + "\n", + "Registers are unlimited in the following two senses:\n", + "\n", + "- even though a URM program can use only a finite set of registers, there is no upper limit for the number of registers used by the programs;\n", + "- there is no upper limit for numbers stored by registers." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4ehurE3IWVKK" + }, + "source": [ + "## Memory states" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "hlqyf9r6WamQ" + }, + "source": [ + "The state of the memory is determined by the values ​​stored in the registers." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JKN8B0vKW0OB" + }, + "source": [ + "## Software implementation" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IGQ1ohl7kIzK" + }, + "source": [ + "The memory of URM is implemented as class `memory` inherited from the built-in type `list`.\n", + "\n", + "The property `size` equals the length of the corresponding list.\n", + "\n", + "The methods `read()` and `write()` provide correct reading from and writing to the memory." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "id": "SivyyEI1H1El" + }, + "outputs": [], + "source": [ + "class memory(list):\n", + "\n", + " def __new__(cls) -> Self:\n", + " return super().__new__(cls, [])\n", + "\n", + " @property\n", + " def size(self) -> int:\n", + " return len(self)\n", + "\n", + " def read(self, addr: int) -> nat:\n", + " try:\n", + " n = nat(addr)\n", + " except ValueError:\n", + " raise ValueError(\"memory.read() error! Bad argument\")\n", + " try:\n", + " return self[n]\n", + " except IndexError:\n", + " return nat(0)\n", + "\n", + " def write(self, addr: int, value: Any) -> None:\n", + " try:\n", + " n, v = nat(addr), nat(value)\n", + " except ValueError:\n", + " raise ValueError(\"memory.write() error! Bad argument(s)\")\n", + " diff = self.size - n\n", + " if diff <= 0: # access to a register that is not yet allocated\n", + " self += (1 - diff) * [nat(0)] # allocate additional registers\n", + " self[n] = v\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "K2ea07zgWg6Q" + }, + "source": [ + "## URM-programs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lWOiwFXtWpDZ" + }, + "source": [ + "***Execution states***, that is, the value of the registers and the instruction counter, is changed by programs.\n", + "\n", + "A ***URM program*** is a finite list of ***instructions***.\n", + "\n", + "Program instructions are written in a certain order and numbered with positive natural numbers $1,2,3,\\dotsc$.
\n", + "**Please note!** Instruction number 0 does not exist in the program.\n", + "\n", + "The instruction number for historical reasons is called the ***program line number***." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "32IJjIbpWBGs" + }, + "source": [ + "## Instruction counter" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eBeuV9d4WL7h" + }, + "source": [ + "The ***instruction counter*** is an additional register that stores a natural number.\n", + "This register is denoted by $IC$ and its contents are $ic$." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8qzxofV3XxDd" + }, + "source": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
NameMnemonic codeEffectDescription
Zero$\\mathtt{Z}(n)$$R_n\\gets 0$
$IC\\gets ic+1$
Replace the value in $R_{n}$ with $0$ and jump to the nextline of the
program
Successor$\\mathtt{S}(n)$$R_n\\gets r_n+1$
$IC\\gets ic+1$
Increase the value of register $R_{n}$ by $1$ and jump to the next line of
the program
Copy$\\mathtt{C}(m,n)$$R_n\\gets r_m$
$IC\\gets ic+1$
Replace the value in $R_{n}$ with the content of $R_{m}$ (keeping the
content of $R_{m}$) and jump to the next line of the program
Jump$\\mathtt{J}(m,n,k)$$IC\\gets k\\ \\mathtt{if}\\ r_m=r_n\\ \\mathtt{else}\\ ic+1$If the values ​​stored in $R_{m}$ and $R_{n}$ match, then jump to the
program line with number $k$, otherwise to the next program line
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nmmw7_IM66tM" + }, + "source": [ + "## Software implementation" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6ccI_PKAazXL" + }, + "source": [ + "The `ins` class provides the data type implementation inhabited by the URM instructions.\n", + "\n", + "- The instruction `Z(n)` is represented by a tuple `(0, n)`.\n", + "- The instruction `S(n)` is represented by a tuple `(1, n)`.\n", + "- The instruction `C(m, n)` is represented by the tuple `(2, m, n)`.\n", + "- The instruction `J(m, n, k)` is represented by the tuple `(3, m, n, k)`.\n", + "\n", + "To correctly represent instructions by strings, the `__str__()` method is overloaded for this class.\n", + "\n", + "The class methods `Z()`, `S()`, `C()` and `J()` provide convenient instruction creation." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "b6jA7G8rqOg9" + }, + "outputs": [], + "source": [ + "class ins(tuple):\n", + "\n", + " def __new__(cls, *args: Tuple[int]) -> Self:\n", + " if not (2 <= len(args) <= 4):\n", + " raise ValueError(\"ins() error! Invalid number of arguments\")\n", + " if not all(type(arg) == int for arg in args):\n", + " raise ValueError(\"ins() error! Invalid type of argument(s)\")\n", + " if args[0] > 3:\n", + " raise ValueError(\"ins() error! Invalid instruction code\")\n", + " if not all(arg >= 0 for arg in args[1 :]):\n", + " raise ValueError(\"ins() error! Invalid value of operand(s)\")\n", + " return super().__new__(cls, args)\n", + "\n", + " def __str__(self) -> str:\n", + " if self[0] == 0:\n", + " return f\"Z({self[1]})\"\n", + " if self[0] == 1:\n", + " return f\"S({self[1]})\"\n", + " if self[0] == 2:\n", + " return f\"C{self[1 :]}\"\n", + " # self[0] == 3\n", + " return f\"J{self[1 :]}\"\n", + "\n", + " @classmethod\n", + " def Z(cls, n: Any) -> Self:\n", + " try:\n", + " return ins(0, n)\n", + " except ValueError:\n", + " raise ValueError(\"Z() error! Bad operand\")\n", + "\n", + " @classmethod\n", + " def S(cls, n: Any) -> Self:\n", + " try:\n", + " return ins(1, n)\n", + " except ValueError:\n", + " raise ValueError(\"S() error! Bad operand\")\n", + "\n", + " @classmethod\n", + " def C(cls, m: Any, n: Any) -> Self:\n", + " try:\n", + " return ins(2, m, n)\n", + " except ValueError:\n", + " raise ValueError(\"C() error! Bad operand(s)\")\n", + "\n", + " @classmethod\n", + " def J(cls, m: Any, n: Any, k: Any) -> Self:\n", + " try:\n", + " return ins(3, m, n, k)\n", + " except ValueError:\n", + " raise ValueError(\"J() error! Bad operand(s)\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "789mprGe7NE-" + }, + "source": [ + "## Instructions execution" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MiHtXnCkhpPQ" + }, + "source": [ + "The execution of `instruction: ins` if the memory state is `memory_state` implements by calling `apply(instruction, to=memory_state)`, which provides returning the pair `(how_to_change_IC, new_memory_state)`.\n", + "\n", + "The value of `how_to_change_IC` is equal to\n", + "\n", + "- `None`, if after the instruction `instruction` it is necessary to execute the instruction in the next line of the program;\n", + "- the line number of the instruction that will be executed next, if it is not the next in order in the program.\n", + "\n", + "The value `new_memory_state` is the state of the memory after the execution of the instruction `instruction`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "7Z2kQRzF7SpR" + }, + "outputs": [], + "source": [ + "def apply(i: ins, to: memory) -> Tuple[Optional[int], memory]:\n", + " if type(to) != memory:\n", + " raise ValueError(\"do() error! Invalid type of memory\")\n", + " if type(i) != ins:\n", + " raise ValueError(\"do() error! Invalid type of instruction\")\n", + " if i[0] == 0:\n", + " to.write(i[1], 0)\n", + " return (None, to)\n", + " if i[0] == 1:\n", + " to.write(i[1], to.read(i[1]) + 1)\n", + " return (None, to)\n", + " if i[0] == 2:\n", + " to.write(i[2], to.read(i[1]))\n", + " return (None, to)\n", + " # i[0] == 3\n", + " return (i[3] if to.read(i[1]) == to.read(i[2]) else None, to)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "J2-oNVEWd959", + "outputId": "73051929-cfff-4441-f57b-8865cfada4ee" + }, + "outputs": [ { - "cell_type": "code", - "source": [ - "def run(prgm: program, *data: Tuple[Any]) -> nat:\n", - " if type(prgm) != program:\n", - " raise ValueError(\"run() error! Bad program\")\n", - " try:\n", - " data = (nat(x) for x in data)\n", - " except:\n", - " raise ValueError(\"run() error! Invalid data\")\n", - " m = memory()\n", - " for addr, value in enumerate(data):\n", - " m.write(addr + 1, value)\n", - " ic = 1\n", - " while True:\n", - " i = prgm.get_instruction(ic)\n", - " if i is None:\n", - " return m.read(0)\n", - " q, m = apply(i, to=m)\n", - " ic = ic + 1 if q is None else q" - ], - "metadata": { - "id": "vNtaMaamB8Hu" - }, - "execution_count": 13, - "outputs": [] + "name": "stdout", + "output_type": "stream", + "text": [ + " m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", + "next = None; m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 0]\n", + "next = None; m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", + "next = None; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", + "next = 5; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", + "next = None; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n" + ] + } + ], + "source": [ + "m = memory()\n", + "for n in range(10):\n", + " m.write(n, n)\n", + "print(f\"{13 * ' '}m = {m}\")\n", + "next, m = apply(ins.Z(9), to=m)\n", + "print(f\"next = {next}; m = {m}\")\n", + "next, m = apply(ins.S(9), to=m)\n", + "print(f\"next = {next}; m = {m}\")\n", + "next, m = apply(ins.C(9, 0), to=m)\n", + "print(f\"next = {next}; m = {m}\")\n", + "next, m = apply(ins.J(1, 9, 5), to=m)\n", + "print(f\"next = {next}; m = {m}\")\n", + "next, m = apply(ins.J(2, 3, 10), to=m)\n", + "print(f\"next = {next}; m = {m}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "l74nSpgBSl7m" + }, + "source": [ + "# URM-programs and their execution" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "w54V9h05mE5q" + }, + "source": [ + "## Translation of a source text into an instruction list" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "WlcJ1IPezSwS" + }, + "source": [ + "The function `compile()` converts the text into a list of URM instructions." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "OfLgefRfrGCj" + }, + "outputs": [], + "source": [ + "def compile(text: str) -> Tuple[ins]:\n", + " if not isinstance(text, str):\n", + " raise ValueError(\"compile() error! Invalid argument type\")\n", + " # split `text` into the list of non empty lines\n", + " lines = [line for line in [item.strip() for\n", + " item in text.split('\\n')] if\n", + " line]\n", + " # the function compiles a line\n", + " def compile_line(line: str) -> ins:\n", + " # remove the tail of 'line' beginning with ')'\n", + " item, sep, _ = line.partition(')')\n", + " if not sep: # ')' is absent in the line\n", + " raise ValueError(\"compile_line() error! Bad instruction format\")\n", + " code, sep, item = item.partition('(')\n", + " if not sep: # '(' is absent in the line\n", + " raise ValueError(\"compile_line() error! Bad instruction format\")\n", + " if code.strip() == 'Z':\n", + " try: # to recognize Z-instruction\n", + " return ins.Z(int(item))\n", + " except ValueError:\n", + " raise ValueError(\"compile_line() error! Bad Z-instruction\")\n", + " elif code.strip() == 'S':\n", + " try: # to recognize S-instruction\n", + " return ins.S(int(item))\n", + " except ValueError:\n", + " raise ValueError(\"compile_line() error! Bad S-instruction\")\n", + " elif code.strip() == 'C':\n", + " op1, sep, item = item.partition(',')\n", + " try: # to recognize C-instruction\n", + " return ins.C(int(op1), int(item))\n", + " except ValueError:\n", + " raise ValueError(\"compile_line() error! Bad C-instruction\")\n", + " elif code.strip() == 'J':\n", + " op1, sep, item = item.partition(',')\n", + " op2, sep, item = item.partition(',')\n", + " try: # to recognize J-instruction\n", + " return ins.J(int(op1), int(op2), int(item))\n", + " except:\n", + " raise ValueError(\"compile_line() error! Bad J-instruction\")\n", + " raise ValueError(\"compile_line() error! Bad instruction format\")\n", + " # end of compile_line()\n", + " return tuple(compile_line(line) for line in lines)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eBcW57NO6-aM" + }, + "source": [ + "An example of using the `compile()` function." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "5wMcWBoqmnEZ", + "outputId": "569dbfd1-554e-409b-e996-6510e2252283" + }, + "outputs": [ { - "cell_type": "code", - "source": [ - "report = [(x, y, run(p, x, y)) for x in range(10) for y in range(10)]\n", - "report_items = [\" \".join(\n", - " (f\"{x}\", \"+\", f\"{y}\", \"=\", f\"{z:2d}\")) for (x, y, z) in report]\n", - "report_lines = [\" : \".join(report_items[ic + c * 20] for c in range(5)) for\n", - " ic in range(20)]\n", - "for line in report_lines:\n", - " print(line)" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "hVheckP1FJQX", - "outputId": "6b427e9e-3457-49e6-aa18-9e336dd490da" - }, - "execution_count": 14, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "0 + 0 = 0 : 2 + 0 = 2 : 4 + 0 = 4 : 6 + 0 = 6 : 8 + 0 = 8\n", - "0 + 1 = 1 : 2 + 1 = 3 : 4 + 1 = 5 : 6 + 1 = 7 : 8 + 1 = 9\n", - "0 + 2 = 2 : 2 + 2 = 4 : 4 + 2 = 6 : 6 + 2 = 8 : 8 + 2 = 10\n", - "0 + 3 = 3 : 2 + 3 = 5 : 4 + 3 = 7 : 6 + 3 = 9 : 8 + 3 = 11\n", - "0 + 4 = 4 : 2 + 4 = 6 : 4 + 4 = 8 : 6 + 4 = 10 : 8 + 4 = 12\n", - "0 + 5 = 5 : 2 + 5 = 7 : 4 + 5 = 9 : 6 + 5 = 11 : 8 + 5 = 13\n", - "0 + 6 = 6 : 2 + 6 = 8 : 4 + 6 = 10 : 6 + 6 = 12 : 8 + 6 = 14\n", - "0 + 7 = 7 : 2 + 7 = 9 : 4 + 7 = 11 : 6 + 7 = 13 : 8 + 7 = 15\n", - "0 + 8 = 8 : 2 + 8 = 10 : 4 + 8 = 12 : 6 + 8 = 14 : 8 + 8 = 16\n", - "0 + 9 = 9 : 2 + 9 = 11 : 4 + 9 = 13 : 6 + 9 = 15 : 8 + 9 = 17\n", - "1 + 0 = 1 : 3 + 0 = 3 : 5 + 0 = 5 : 7 + 0 = 7 : 9 + 0 = 9\n", - "1 + 1 = 2 : 3 + 1 = 4 : 5 + 1 = 6 : 7 + 1 = 8 : 9 + 1 = 10\n", - "1 + 2 = 3 : 3 + 2 = 5 : 5 + 2 = 7 : 7 + 2 = 9 : 9 + 2 = 11\n", - "1 + 3 = 4 : 3 + 3 = 6 : 5 + 3 = 8 : 7 + 3 = 10 : 9 + 3 = 12\n", - "1 + 4 = 5 : 3 + 4 = 7 : 5 + 4 = 9 : 7 + 4 = 11 : 9 + 4 = 13\n", - "1 + 5 = 6 : 3 + 5 = 8 : 5 + 5 = 10 : 7 + 5 = 12 : 9 + 5 = 14\n", - "1 + 6 = 7 : 3 + 6 = 9 : 5 + 6 = 11 : 7 + 6 = 13 : 9 + 6 = 15\n", - "1 + 7 = 8 : 3 + 7 = 10 : 5 + 7 = 12 : 7 + 7 = 14 : 9 + 7 = 16\n", - "1 + 8 = 9 : 3 + 8 = 11 : 5 + 8 = 13 : 7 + 8 = 15 : 9 + 8 = 17\n", - "1 + 9 = 10 : 3 + 9 = 12 : 5 + 9 = 14 : 7 + 9 = 16 : 9 + 9 = 18\n" - ] - } - ] + "name": "stdout", + "output_type": "stream", + "text": [ + " 1: C(2, 0)\n", + " 2: Z(2)\n", + " 3: J(1, 2, 0)\n", + " 4: S(0)\n", + " 5: S(2)\n", + " 6: J(0, 0, 3)\n" + ] + } + ], + "source": [ + "text = \"\"\"\n", + " C(2, 0)\n", + " Z (2)\n", + "\n", + " J(1, 2, 0) check loop condition\n", + " S(0)\n", + " S(2)\n", + " J(0, 0, 3) repeat loop\n", + "\"\"\"\n", + "\n", + "ins_tuple = compile(text)\n", + "for ni, i in enumerate(ins_tuple):\n", + " print(f\"{ni + 1:3d}: {i}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "FV-cDiTES0V4" + }, + "source": [ + "## URM-programs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rir1QLi5B160" + }, + "source": [ + "### Software implementation of a URM-program" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "irEaC4-iS6nD" + }, + "outputs": [], + "source": [ + "class program(tuple):\n", + "\n", + " def __new__(cls, instructions: Tuple[ins]) -> Self:\n", + " if not type(instructions) == tuple:\n", + " raise ValueError(\"program() error! Invalid argument type\")\n", + " if not all(type(instruction) == ins for instruction in instructions):\n", + " raise ValueError(\"program() error! Invalid type of argument member\")\n", + " return super().__new__(cls, instructions)\n", + "\n", + " def __str__(self):\n", + " return \"\\n\".join([f\"{ni + 1: 3d}: {i}\" for ni, i in enumerate(self)])\n", + "\n", + " @property\n", + " def length(self):\n", + " return len(self)\n", + "\n", + " @property\n", + " def haddr(self):\n", + " temp = 0\n", + " for i in self:\n", + " temp = max(temp, *i[1 : 3])\n", + " return temp\n", + "\n", + " def get_instruction(self, lineno: int) -> Optional[ins]:\n", + " if type(lineno) != int:\n", + " raise ValueError(\"program.get_instruction() error! Bad line number\")\n", + " if lineno < 1:\n", + " return None\n", + " try:\n", + " return self[lineno - 1]\n", + " except IndexError:\n", + " return None" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "ca3jyBTE7Nu9", + "outputId": "318d3dda-98cb-4311-bfb7-78f196e6b156" + }, + "outputs": [ { - "cell_type": "markdown", - "source": [ - "# Manipulating URM-programs" - ], - "metadata": { - "id": "M7d0jt0l7e9b" - } + "name": "stdout", + "output_type": "stream", + "text": [ + "Program text:\n", + " 1: C(2, 0)\n", + " 2: Z(2)\n", + " 3: J(1, 2, 0)\n", + " 4: S(0)\n", + " 5: S(2)\n", + " 6: J(0, 0, 3)\n", + "Program length = 6\n", + "Program highest address = 2\n" + ] + } + ], + "source": [ + "p = program(compile(text))\n", + "print(f\"Program text:\\n{p}\")\n", + "print(f\"Program length = {p.length}\")\n", + "print(f\"Program highest address = {p.haddr}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bNrUp10RB9KH" + }, + "source": [ + "### Execution of a URM-program" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "id": "vNtaMaamB8Hu" + }, + "outputs": [], + "source": [ + "def run(prgm: program, *data: Tuple[Any], verbose=False) -> nat:\n", + " if type(prgm) != program:\n", + " raise ValueError(\"run() error! Bad program\")\n", + " try:\n", + " data = (nat(x) for x in data)\n", + " except:\n", + " raise ValueError(\"run() error! Invalid data\")\n", + " m = memory()\n", + " for addr, value in enumerate(data):\n", + " m.write(addr + 1, value)\n", + " ic = 1\n", + " while True:\n", + " i = prgm.get_instruction(ic)\n", + " if i is None:\n", + " return m.read(0)\n", + " q, m = apply(i, to=m)\n", + " ic = ic + 1 if q is None else q\n", + " if verbose:\n", + " print(m, i)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "hVheckP1FJQX", + "outputId": "6b427e9e-3457-49e6-aa18-9e336dd490da" + }, + "outputs": [ { - "cell_type": "markdown", - "source": [ - "## Normalization of URM-programs" - ], - "metadata": { - "id": "Ihhd9seSXQaf" - } + "name": "stdout", + "output_type": "stream", + "text": [ + "0 + 0 = 0 : 2 + 0 = 2 : 4 + 0 = 4 : 6 + 0 = 6 : 8 + 0 = 8\n", + "0 + 1 = 1 : 2 + 1 = 3 : 4 + 1 = 5 : 6 + 1 = 7 : 8 + 1 = 9\n", + "0 + 2 = 2 : 2 + 2 = 4 : 4 + 2 = 6 : 6 + 2 = 8 : 8 + 2 = 10\n", + "0 + 3 = 3 : 2 + 3 = 5 : 4 + 3 = 7 : 6 + 3 = 9 : 8 + 3 = 11\n", + "0 + 4 = 4 : 2 + 4 = 6 : 4 + 4 = 8 : 6 + 4 = 10 : 8 + 4 = 12\n", + "0 + 5 = 5 : 2 + 5 = 7 : 4 + 5 = 9 : 6 + 5 = 11 : 8 + 5 = 13\n", + "0 + 6 = 6 : 2 + 6 = 8 : 4 + 6 = 10 : 6 + 6 = 12 : 8 + 6 = 14\n", + "0 + 7 = 7 : 2 + 7 = 9 : 4 + 7 = 11 : 6 + 7 = 13 : 8 + 7 = 15\n", + "0 + 8 = 8 : 2 + 8 = 10 : 4 + 8 = 12 : 6 + 8 = 14 : 8 + 8 = 16\n", + "0 + 9 = 9 : 2 + 9 = 11 : 4 + 9 = 13 : 6 + 9 = 15 : 8 + 9 = 17\n", + "1 + 0 = 1 : 3 + 0 = 3 : 5 + 0 = 5 : 7 + 0 = 7 : 9 + 0 = 9\n", + "1 + 1 = 2 : 3 + 1 = 4 : 5 + 1 = 6 : 7 + 1 = 8 : 9 + 1 = 10\n", + "1 + 2 = 3 : 3 + 2 = 5 : 5 + 2 = 7 : 7 + 2 = 9 : 9 + 2 = 11\n", + "1 + 3 = 4 : 3 + 3 = 6 : 5 + 3 = 8 : 7 + 3 = 10 : 9 + 3 = 12\n", + "1 + 4 = 5 : 3 + 4 = 7 : 5 + 4 = 9 : 7 + 4 = 11 : 9 + 4 = 13\n", + "1 + 5 = 6 : 3 + 5 = 8 : 5 + 5 = 10 : 7 + 5 = 12 : 9 + 5 = 14\n", + "1 + 6 = 7 : 3 + 6 = 9 : 5 + 6 = 11 : 7 + 6 = 13 : 9 + 6 = 15\n", + "1 + 7 = 8 : 3 + 7 = 10 : 5 + 7 = 12 : 7 + 7 = 14 : 9 + 7 = 16\n", + "1 + 8 = 9 : 3 + 8 = 11 : 5 + 8 = 13 : 7 + 8 = 15 : 9 + 8 = 17\n", + "1 + 9 = 10 : 3 + 9 = 12 : 5 + 9 = 14 : 7 + 9 = 16 : 9 + 9 = 18\n" + ] + } + ], + "source": [ + "report = [(x, y, run(p, x, y)) for x in range(10) for y in range(10)]\n", + "report_items = [\" \".join(\n", + " (f\"{x}\", \"+\", f\"{y}\", \"=\", f\"{z:2d}\")) for (x, y, z) in report]\n", + "report_lines = [\" : \".join(report_items[ic + c * 20] for c in range(5)) for\n", + " ic in range(20)]\n", + "for line in report_lines:\n", + " print(line)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "M7d0jt0l7e9b" + }, + "source": [ + "# Manipulating URM-programs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ihhd9seSXQaf" + }, + "source": [ + "## Normalization of URM-programs" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "id": "ICB0f78XXRkY" + }, + "outputs": [], + "source": [ + "def normalize(P: program) -> program:\n", + " \"\"\"\n", + " The function normalizes a URM program by ensuring all jump instructions\n", + " have valid targets. If a jump target k is not in range [1, program_size],\n", + " it is set to program_size + 1.\n", + "\n", + " Arguments\n", + " P: program\n", + "\n", + " Returns\n", + " program\n", + " \"\"\"\n", + " if type(P) != program:\n", + " raise ValueError(\"normalize() error! Invalid argument type\")\n", + " if P.length == 0:\n", + " return P\n", + " normalized_instructions = []\n", + " program_size = P.length\n", + " for i, instruction in enumerate(P):\n", + " if instruction[0] == 3:\n", + " m, n, k = instruction[1:]\n", + " if not (1 <= k <= program_size):\n", + " k = program_size + 1\n", + " normalized_instructions.append(ins.J(m, n, k))\n", + " else:\n", + " normalized_instructions.append(instruction)\n", + "\n", + " return program(tuple(normalized_instructions))" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "V16SKgpoXdQh", + "outputId": "6c624feb-59f9-4f16-9bbe-de97d9374c1b" + }, + "outputs": [ { - "cell_type": "code", - "source": [ - "def normalize(P: program) -> program:\n", - " \"\"\"\n", - " The function normalizes a URM program by ensuring all jump instructions\n", - " have valid targets. If a jump target k is not in range [1, program_size],\n", - " it is set to program_size + 1.\n", - "\n", - " Arguments\n", - " P: program\n", - "\n", - " Returns\n", - " program\n", - " \"\"\"\n", - " if type(P) != program:\n", - " raise ValueError(\"normalize() error! Invalid argument type\")\n", - " if P.length == 0:\n", - " return P\n", - " normalized_instructions = []\n", - " program_size = P.length\n", - " for i, instruction in enumerate(P):\n", - " if instruction[0] == 3:\n", - " m, n, k = instruction[1:]\n", - " if not (1 <= k <= program_size):\n", - " k = program_size + 1\n", - " normalized_instructions.append(ins.J(m, n, k))\n", - " else:\n", - " normalized_instructions.append(instruction)\n", - "\n", - " return program(tuple(normalized_instructions))" - ], - "metadata": { - "id": "ICB0f78XXRkY" - }, - "execution_count": 15, - "outputs": [] + "name": "stdout", + "output_type": "stream", + "text": [ + "Original program:\n", + " 1: C(2, 0)\n", + " 2: Z(2)\n", + " 3: J(1, 2, 0)\n", + " 4: S(0)\n", + " 5: S(2)\n", + " 6: J(0, 0, 3)\n", + "Normalized program:\n", + " 1: C(2, 0)\n", + " 2: Z(2)\n", + " 3: J(1, 2, 7)\n", + " 4: S(0)\n", + " 5: S(2)\n", + " 6: J(0, 0, 3)\n" + ] + } + ], + "source": [ + "# Check normalized program\n", + "p = program(compile(text))\n", + "print(f\"Original program:\\n{p}\")\n", + "p_n = normalize(p)\n", + "report = [(x, y, run(p_n, x, y)) for x in range(10) for y in range(10)]\n", + "for x, y, ret in report:\n", + " assert (x + y) == int(ret), f\"Failed: {x} + {y} = {ret} (expected {x+y})\"\n", + "print(f\"Normalized program:\\n{p_n}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3Ou42OZw7Ci8" + }, + "source": [ + "## Concatenation of URM-programs" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "id": "d1h7TKbA8AfB" + }, + "outputs": [], + "source": [ + "def concat(P: program, Q: program) -> program:\n", + " \"\"\"\n", + " The function returns the program that operates as P until\n", + " its termination and then as Q.\n", + "\n", + " Arguments\n", + " P, Q: program\n", + "\n", + " Returns\n", + " program\n", + " \"\"\"\n", + " if not (isinstance(P, program) and isinstance(Q, program)):\n", + " raise ValueError(\"concat() error! Invalid program type\")\n", + " if P.length == 0:\n", + " return Q\n", + "\n", + " P_normalized = normalize(P)\n", + " offset = P_normalized.length\n", + " Q_adjusted = []\n", + " for instruction in Q:\n", + " if instruction[0] == 3: # Jump instruction\n", + " m, n, k = instruction[1:]\n", + " new_k = k + offset if k > 0 else k\n", + " Q_adjusted.append(ins.J(m, n, new_k))\n", + " else:\n", + " Q_adjusted.append(instruction)\n", + "\n", + " cat = list(P_normalized) + Q_adjusted\n", + "\n", + " return program(tuple(cat))" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "b8pVbesRXikf", + "outputId": "5aa6daf9-52a6-43e6-9bf7-20ab9aa7c206" + }, + "outputs": [ { - "cell_type": "code", - "source": [ - "# Check normalized program\n", - "p = program(compile(text))\n", - "print(f\"Original program:\\n{p}\")\n", - "p_n = normalize(p)\n", - "report = [(x, y, run(p_n, x, y)) for x in range(10) for y in range(10)]\n", - "for x, y, ret in report:\n", - " assert (x + y) == int(ret), f\"Failed: {x} + {y} = {ret} (expected {x+y})\"\n", - "print(f\"Normalized program:\\n{p_n}\")" - ], - "metadata": { - "id": "V16SKgpoXdQh", - "colab": { - "base_uri": "https://localhost:8080/" - }, - "outputId": "6c624feb-59f9-4f16-9bbe-de97d9374c1b" - }, - "execution_count": 20, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Original program:\n", - " 1: C(2, 0)\n", - " 2: Z(2)\n", - " 3: J(1, 2, 0)\n", - " 4: S(0)\n", - " 5: S(2)\n", - " 6: J(0, 0, 3)\n", - "Normalized program:\n", - " 1: C(2, 0)\n", - " 2: Z(2)\n", - " 3: J(1, 2, 7)\n", - " 4: S(0)\n", - " 5: S(2)\n", - " 6: J(0, 0, 3)\n" - ] - } - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Concatenation: \n", + " 1: Z(0)\n", + " 2: C(1, 2)\n", + " 3: S(0)\n", + " 4: J(3, 4, 5)\n", + " 5: S(0)\n", + " 6: J(3, 4, 0)\n", + " 7: Z(0)\n", + " 8: C(1, 0)\n" + ] + } + ], + "source": [ + "text_P = \"\"\"Z(0)\n", + " C(1,2)\n", + " S(0)\n", + " J(3,4,0)\n", + " \"\"\"\n", + "text_Q = \"\"\"\n", + " S(0)\n", + " J(3,4,0)\n", + " Z(0)\n", + " C(1,0)\n", + " \"\"\"\n", + "P, Q = program(compile(text_P)), program(compile(text_Q))\n", + "C = concat(P, Q)\n", + "print(f'Concatenation: \\n{C}')" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "FxzKfPMtXk-f", + "outputId": "44405bc9-b1bd-4e5a-e53b-4611ea9217cb" + }, + "outputs": [ { - "cell_type": "markdown", - "source": [ - "## Concatenation of URM-programs" - ], - "metadata": { - "id": "3Ou42OZw7Ci8" - } + "name": "stdout", + "output_type": "stream", + "text": [ + "Programs Concatenation Comparison:\n", + "------------------------------------------------------------\n", + "Program P \tProgram Q \tP concatenated with Q\n", + "------------------------------------------------------------\n", + "Z(0) \t \tZ(0)\n", + "C(1, 2) \t \tC(1, 2)\n", + "S(0) \t \tS(0)\n", + "J(3, 4, 0) \t \tJ(3, 4, 5)\n", + " \tS(0) \tS(0)\n", + " \tJ(3, 4, 0) \tJ(3, 4, 0)\n", + " \tZ(0) \tZ(0)\n", + " \tC(1, 0) \tC(1, 0)\n", + "------------------------------------------------------------\n" + ] + } + ], + "source": [ + "# Pretty print\n", + "COLUMN_WIDTH = 13\n", + "SEPARATOR = '\\t'\n", + "\n", + "print(\"Programs Concatenation Comparison:\")\n", + "print(\"-\" * 60)\n", + "\n", + "print(f\"{'Program P':13}{SEPARATOR}{'Program Q':13}{SEPARATOR}\"\n", + " f\"{'P concatenated with Q'}\")\n", + "print(\"-\" * 60)\n", + "\n", + "for line in range(P.length):\n", + " print(f\"{str(P[line]):{COLUMN_WIDTH}}\"\n", + " f\"{SEPARATOR}{COLUMN_WIDTH * ' '}\"\n", + " f\"{SEPARATOR}{C[line]}\")\n", + "\n", + "for line in range(Q.length):\n", + " print(f\"{COLUMN_WIDTH * ' '}\"\n", + " f\"{SEPARATOR}{str(Q[line]):{COLUMN_WIDTH}}\"\n", + " f\"{SEPARATOR}{C[P.length + line]}\")\n", + "\n", + "print(\"-\" * 60)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Kr_yQyZ19BR9" + }, + "source": [ + "## Moving URM-program in Memory" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "id": "cMTdPqrK9HwV" + }, + "outputs": [], + "source": [ + "def move(P: program, off: int=0) -> program:\n", + " \"\"\"\n", + " The function returns the program that operates as P in the registers\n", + " R[off], R[off + 1], ...\n", + "\n", + " Arguments\n", + " P: program\n", + " off: int {off >= 0}\n", + " Returns\n", + " program\n", + " \"\"\"\n", + " if not isinstance(P, program):\n", + " raise ValueError(\"move() error! Invalid program type\")\n", + " if not isinstance(off, int) or off < 0:\n", + " raise ValueError(\"move() error! Invalid offset\")\n", + " # end of checking arguments\n", + " if P.length == 0 or off == 0:\n", + " return P\n", + " moved_instructions = []\n", + " for instruction in P:\n", + " # Handle different op\n", + " if instruction[0] == 0: # Z()\n", + " moved_instructions.append(ins.Z(instruction[1] + off))\n", + " elif instruction[0] == 1: # S()\n", + " moved_instructions.append(ins.S(instruction[1] + off))\n", + " elif instruction[0] == 2: # C()\n", + " moved_instructions.append(ins.C(instruction[1] + off,\n", + " instruction[2] + off))\n", + " else: # J()\n", + " moved_instructions.append(ins.J(instruction[1] + off,\n", + " instruction[2] + off,\n", + " instruction[3]))\n", + " return program(tuple(moved_instructions))" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "zMt9kqJOXpmM", + "outputId": "457a01c7-2207-4b2a-d983-36cd507c6519" + }, + "outputs": [ { - "cell_type": "code", - "source": [ - "def concat(P: program, Q: program) -> program:\n", - " \"\"\"\n", - " The function returns the program that operates as P until\n", - " its termination and then as Q.\n", - "\n", - " Arguments\n", - " P, Q: program\n", - "\n", - " Returns\n", - " program\n", - " \"\"\"\n", - " if not (isinstance(P, program) and isinstance(Q, program)):\n", - " raise ValueError(\"concat() error! Invalid program type\")\n", - " if P.length == 0:\n", - " return Q\n", - "\n", - " P_normalized = normalize(P)\n", - " offset = P_normalized.length\n", - " Q_adjusted = []\n", - " for instruction in Q:\n", - " if instruction[0] == 3: # Jump instruction\n", - " m, n, k = instruction[1:]\n", - " new_k = k + offset if k > 0 else k\n", - " Q_adjusted.append(ins.J(m, n, new_k))\n", - " else:\n", - " Q_adjusted.append(instruction)\n", - "\n", - " cat = list(P_normalized) + Q_adjusted\n", - "\n", - " return program(tuple(cat))" - ], - "metadata": { - "id": "d1h7TKbA8AfB" - }, - "execution_count": 22, - "outputs": [] + "name": "stdout", + "output_type": "stream", + "text": [ + "Original vs Moved Program (offset=5):\n", + "------------------------------------------------------------\n", + "Original \tMoved \t\n", + "------------------------------------------------------------\n", + "C(2, 0) \tC(7, 5) \n", + "Z(2) \tZ(7) \n", + "J(1, 2, 0) \tJ(6, 7, 0) \n", + "S(0) \tS(5) \n", + "S(2) \tS(7) \n", + "J(0, 0, 3) \tJ(5, 5, 3) \n", + "------------------------------------------------------------\n" + ] + } + ], + "source": [ + "# Make the move of an add() program to memory offset by 5\n", + "text_add = \"\"\"\n", + " C(2, 0)\n", + " Z (2)\n", + "\n", + " J(1, 2, 0) check loop condition\n", + " S(0)\n", + " S(2)\n", + " J(0, 0, 3) repeat loop\n", + "\"\"\"\n", + "add = program(compile(text_add))\n", + "offset = 5\n", + "add_moved = move(add, offset)\n", + "\n", + "# Pretty print\n", + "COLUMN_WIDTH = 13\n", + "SEPARATOR = '\\t'\n", + "\n", + "print(\"Original vs Moved Program (offset=5):\")\n", + "print(\"-\" * 60)\n", + "print(f\"{'Original':13}{SEPARATOR}{'Moved':13}{SEPARATOR}\")\n", + "print(\"-\" * 60)\n", + "\n", + "for line in range(add.length):\n", + " print(f\"{str(add[line]):{COLUMN_WIDTH}}\"\n", + " f\"{SEPARATOR}{str(add_moved[line]):{COLUMN_WIDTH}}\")\n", + "\n", + "print(\"-\" * 60)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "2QNC084mXrVH", + "outputId": "b1d4eb64-4f77-4615-c71c-16eb2b38a110" + }, + "outputs": [ { - "cell_type": "code", - "source": [ - "text_P = \"\"\"Z(0)\n", - " C(1,2)\n", - " S(0)\n", - " J(3,4,0)\n", - " \"\"\"\n", - "text_Q = \"\"\"\n", - " S(0)\n", - " J(3,4,0)\n", - " Z(0)\n", - " C(1,0)\n", - " \"\"\"\n", - "P, Q = program(compile(text_P)), program(compile(text_Q))\n", - "C = concat(P, Q)\n", - "print(f'Concatenation: \\n{C}')" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "b8pVbesRXikf", - "outputId": "5aa6daf9-52a6-43e6-9bf7-20ab9aa7c206" - }, - "execution_count": 23, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Concatenation: \n", - " 1: Z(0)\n", - " 2: C(1, 2)\n", - " 3: S(0)\n", - " 4: J(3, 4, 5)\n", - " 5: S(0)\n", - " 6: J(3, 4, 0)\n", - " 7: Z(0)\n", - " 8: C(1, 0)\n" - ] - } - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + " 1: C(7, 5)\n", + " 2: Z(7)\n", + " 3: J(6, 7, 7)\n", + " 4: S(5)\n", + " 5: S(7)\n", + " 6: J(5, 5, 3)\n", + " 7: C(5, 0)\n", + "\n", + "2 + 6 = 8\n" + ] + } + ], + "source": [ + "# Check moved program\n", + "args = (2, 6)\n", + "args_padding = tuple([0] * offset) + args\n", + "# Add a C() to tail for copying result\n", + "cp = program(tuple([ins.C(offset, 0)]))\n", + "add_moved_c = concat(add_moved, cp)\n", + "print(f\"{add_moved_c}\")\n", + "ret = run(add_moved_c, *args_padding)\n", + "# Check\n", + "assert args[0] + args[1] == int(ret), \"Error, check the move function\"\n", + "print(f\"\\n{args[0]} + {args[1]} = {ret}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5uiyEjU2oHx2" + }, + "source": [ + "## Alternating Execution of Programs" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "id": "GCa3GB5wpQfd" + }, + "outputs": [], + "source": [ + "def alter(P: program, Q: program) -> program:\n", + " \"\"\"\n", + " The function returns the program implementing the following algorithm:\n", + " 1. provide to execute of P and Q in disjoint memory segments\n", + " 2. do one step of P\n", + " 3. if the execution of P terminates return the corresponding result\n", + " 4. do one step of Q\n", + " 5. if the execution of Q terminates return the corresponding result\n", + " 6. jump to item 2\n", + " Arguments:\n", + " P: program\n", + " Q: program\n", + " Returns\n", + " program\n", + " \"\"\"\n", + " if not isinstance(P, program) or not isinstance(Q, program):\n", + " raise ValueError(\"alter() error! Invalid program type\")\n", + "\n", + " # Step 1: Move Q to a disjoint memory segment\n", + " P_haddr = P.haddr\n", + " offset_Q = P_haddr + 1 # Offset for Q registers\n", + " P_moved = move(P, 0) # P remains at its original position\n", + " Q_moved = move(Q, offset_Q)\n", + "\n", + " # Define result registers\n", + " r_p = 0 # P: result register (after move, remains 0)\n", + " r_q = offset_Q # Q: result register (after move)\n", + "\n", + " # Step 2: Interleave instructions and build line maps\n", + " interleaved_instructions = []\n", + " line_map_P = {}\n", + " line_map_Q = {}\n", + " instr_origin = [] # Keep track of the origin (P or Q) of each instruction\n", + "\n", + " idx = 1\n", + " P_idx = 1\n", + " Q_idx = 1\n", + " P_length = P_moved.length\n", + " Q_length = Q_moved.length\n", + " while P_idx <= P_length or Q_idx <= Q_length:\n", + " if P_idx <= P_length:\n", + " line_map_P[P_idx] = idx\n", + " interleaved_instructions.append(P_moved[P_idx - 1])\n", + " instr_origin.append('P')\n", + " idx += 1\n", + " P_idx += 1\n", + " if Q_idx <= Q_length:\n", + " line_map_Q[Q_idx] = idx\n", + " interleaved_instructions.append(Q_moved[Q_idx - 1])\n", + " instr_origin.append('Q')\n", + " idx += 1\n", + " Q_idx += 1\n", + "\n", + " # Step 3: Add termination code for P and Q\n", + " t_p = idx\n", + " interleaved_instructions.append(ins.C(r_p, 0)) # Copy P result to R0\n", + " instr_origin.append('Termination_P')\n", + " idx += 1\n", + "\n", + " t_q = idx\n", + " interleaved_instructions.append(ins.C(r_q, 1)) # Copy Q result to R1\n", + " instr_origin.append('Termination_Q')\n", + " idx += 1\n", + "\n", + " # Step 4: Adjust jump instructions\n", + " adjusted_instructions = []\n", + " for i, instr in enumerate(interleaved_instructions):\n", + " if instr[0] == 3: # Jumps\n", + " m, n, k = instr[1:]\n", + " origin = instr_origin[i]\n", + " if origin == 'P':\n", + " if k == 0:\n", + " new_k = t_p # Jump to P termination code\n", + " else:\n", + " new_k = line_map_P.get(k, idx) # Default to program end if not found\n", + " elif origin == 'Q':\n", + " if k == 0:\n", + " new_k = t_q # Jump to Q termination code\n", + " else:\n", + " new_k = line_map_Q.get(k, idx)\n", + " else:\n", + " new_k = k # For termination code, k remains the same\n", + " adjusted_instr = ins.J(m, n, new_k)\n", + " adjusted_instructions.append(adjusted_instr)\n", + " else:\n", + " adjusted_instructions.append(instr)\n", + "\n", + " return program(tuple(adjusted_instructions))" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "source": [ - "# Pretty print\n", - "COLUMN_WIDTH = 13\n", - "SEPARATOR = '\\t'\n", - "\n", - "print(\"Programs Concatenation Comparison:\")\n", - "print(\"-\" * 60)\n", - "\n", - "print(f\"{'Program P':13}{SEPARATOR}{'Program Q':13}{SEPARATOR}\"\n", - " f\"{'P concatenated with Q'}\")\n", - "print(\"-\" * 60)\n", - "\n", - "for line in range(P.length):\n", - " print(f\"{str(P[line]):{COLUMN_WIDTH}}\"\n", - " f\"{SEPARATOR}{COLUMN_WIDTH * ' '}\"\n", - " f\"{SEPARATOR}{C[line]}\")\n", - "\n", - "for line in range(Q.length):\n", - " print(f\"{COLUMN_WIDTH * ' '}\"\n", - " f\"{SEPARATOR}{str(Q[line]):{COLUMN_WIDTH}}\"\n", - " f\"{SEPARATOR}{C[P.length + line]}\")\n", - "\n", - "print(\"-\" * 60)" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "FxzKfPMtXk-f", - "outputId": "44405bc9-b1bd-4e5a-e53b-4611ea9217cb" - }, - "execution_count": 25, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Programs Concatenation Comparison:\n", - "------------------------------------------------------------\n", - "Program P \tProgram Q \tP concatenated with Q\n", - "------------------------------------------------------------\n", - "Z(0) \t \tZ(0)\n", - "C(1, 2) \t \tC(1, 2)\n", - "S(0) \t \tS(0)\n", - "J(3, 4, 0) \t \tJ(3, 4, 5)\n", - " \tS(0) \tS(0)\n", - " \tJ(3, 4, 0) \tJ(3, 4, 0)\n", - " \tZ(0) \tZ(0)\n", - " \tC(1, 0) \tC(1, 0)\n", - "------------------------------------------------------------\n" - ] - } - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "3 + 4 = 7\n" + ] + } + ], + "source": [ + "# Prepare 2 URM programs\n", + "text_add = \"\"\"\n", + " C(2, 0)\n", + " Z (2)\n", + "\n", + " J(1, 2, 0) check loop condition\n", + " S(0)\n", + " S(2)\n", + " J(0, 0, 3) repeat loop\n", + "\"\"\"\n", + "add = program(compile(text_add))\n", + "print(f\"3 + 4 = {run(add, 3, 4)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "source": [ - "## Moving URM-program in Memory" - ], - "metadata": { - "id": "Kr_yQyZ19BR9" - } - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "5 - 1 = 4\n" + ] + } + ], + "source": [ + "# Predecessor function\n", + "text_pred = \"\"\"\n", + " J(0, 1, 0),\n", + " S(2),\n", + " J(1, 2, 0),\n", + " S(0),\n", + " S(2),\n", + " J(0, 0, 3)\n", + "\"\"\"\n", + "pred = program(compile(text_pred))\n", + "print(f\"5 - 1 = {run(pred, 5)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "source": [ - "def move(P: program, off: int=0) -> program:\n", - " \"\"\"\n", - " The function returns the program that operates as P in the registers\n", - " R[off], R[off + 1], ...\n", - "\n", - " Arguments\n", - " P: program\n", - " off: int {off >= 0}\n", - " Returns\n", - " program\n", - " \"\"\"\n", - " if not isinstance(P, program):\n", - " raise ValueError(\"move() error! Invalid program type\")\n", - " if not isinstance(off, int) or off < 0:\n", - " raise ValueError(\"move() error! Invalid offset\")\n", - " # end of checking arguments\n", - " if P.length == 0 or off == 0:\n", - " return P\n", - " moved_instructions = []\n", - " for instruction in P:\n", - " # Handle different op\n", - " if instruction[0] == 0: # Z()\n", - " moved_instructions.append(ins.Z(instruction[1] + off))\n", - " elif instruction[0] == 1: # S()\n", - " moved_instructions.append(ins.S(instruction[1] + off))\n", - " elif instruction[0] == 2: # C()\n", - " moved_instructions.append(ins.C(instruction[1] + off,\n", - " instruction[2] + off))\n", - " else: # J()\n", - " moved_instructions.append(ins.J(instruction[1] + off,\n", - " instruction[2] + off,\n", - " instruction[3]))\n", - " return program(tuple(moved_instructions))" - ], - "metadata": { - "id": "cMTdPqrK9HwV" - }, - "execution_count": 26, - "outputs": [] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + " 1: C(2, 0)\n", + " 2: J(3, 4, 14)\n", + " 3: Z(2)\n", + " 4: S(5)\n", + " 5: J(1, 2, 13)\n", + " 6: J(4, 5, 14)\n", + " 7: S(0)\n", + " 8: S(3)\n", + " 9: S(2)\n", + " 10: S(5)\n", + " 11: J(0, 0, 5)\n", + " 12: J(3, 3, 6)\n", + " 13: C(0, 0)\n", + " 14: C(3, 1)\n" + ] + } + ], + "source": [ + "# Alternately merge two functions\n", + "merge = alter(add, pred)\n", + "print(merge)" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "source": [ - "# Make the move of an add() program to memory offset by 5\n", - "text_add = \"\"\"\n", - " C(2, 0)\n", - " Z (2)\n", - "\n", - " J(1, 2, 0) check loop condition\n", - " S(0)\n", - " S(2)\n", - " J(0, 0, 3) repeat loop\n", - "\"\"\"\n", - "add = program(compile(text_add))\n", - "offset = 5\n", - "add_moved = move(add, offset)\n", - "\n", - "# Pretty print\n", - "COLUMN_WIDTH = 13\n", - "SEPARATOR = '\\t'\n", - "\n", - "print(\"Original vs Moved Program (offset=5):\")\n", - "print(\"-\" * 60)\n", - "print(f\"{'Original':13}{SEPARATOR}{'Moved':13}{SEPARATOR}\")\n", - "print(\"-\" * 60)\n", - "\n", - "for line in range(add.length):\n", - " print(f\"{str(add[line]):{COLUMN_WIDTH}}\"\n", - " f\"{SEPARATOR}{str(add_moved[line]):{COLUMN_WIDTH}}\")\n", - "\n", - "print(\"-\" * 60)" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "zMt9kqJOXpmM", - "outputId": "457a01c7-2207-4b2a-d983-36cd507c6519" - }, - "execution_count": 27, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Original vs Moved Program (offset=5):\n", - "------------------------------------------------------------\n", - "Original \tMoved \t\n", - "------------------------------------------------------------\n", - "C(2, 0) \tC(7, 5) \n", - "Z(2) \tZ(7) \n", - "J(1, 2, 0) \tJ(6, 7, 0) \n", - "S(0) \tS(5) \n", - "S(2) \tS(7) \n", - "J(0, 0, 3) \tJ(5, 5, 3) \n", - "------------------------------------------------------------\n" - ] - } - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "[4, 3, 4, 0, 5] C(2, 0)\n", + "[4, 3, 4, 0, 5] J(3, 4, 14)\n", + "[4, 3, 0, 0, 5] Z(2)\n", + "[4, 3, 0, 0, 5, 1] S(5)\n", + "[4, 3, 0, 0, 5, 1] J(1, 2, 13)\n", + "[4, 3, 0, 0, 5, 1] J(4, 5, 14)\n", + "[5, 3, 0, 0, 5, 1] S(0)\n", + "[5, 3, 0, 1, 5, 1] S(3)\n", + "[5, 3, 1, 1, 5, 1] S(2)\n", + "[5, 3, 1, 1, 5, 2] S(5)\n", + "[5, 3, 1, 1, 5, 2] J(0, 0, 5)\n", + "[5, 3, 1, 1, 5, 2] J(1, 2, 13)\n", + "[5, 3, 1, 1, 5, 2] J(4, 5, 14)\n", + "[6, 3, 1, 1, 5, 2] S(0)\n", + "[6, 3, 1, 2, 5, 2] S(3)\n", + "[6, 3, 2, 2, 5, 2] S(2)\n", + "[6, 3, 2, 2, 5, 3] S(5)\n", + "[6, 3, 2, 2, 5, 3] J(0, 0, 5)\n", + "[6, 3, 2, 2, 5, 3] J(1, 2, 13)\n", + "[6, 3, 2, 2, 5, 3] J(4, 5, 14)\n", + "[7, 3, 2, 2, 5, 3] S(0)\n", + "[7, 3, 2, 3, 5, 3] S(3)\n", + "[7, 3, 3, 3, 5, 3] S(2)\n", + "[7, 3, 3, 3, 5, 4] S(5)\n", + "[7, 3, 3, 3, 5, 4] J(0, 0, 5)\n", + "[7, 3, 3, 3, 5, 4] J(1, 2, 13)\n", + "[7, 3, 3, 3, 5, 4] C(0, 0)\n", + "[7, 3, 3, 3, 5, 4] C(3, 1)\n" + ] }, { - "cell_type": "code", - "source": [ - "# Check moved program\n", - "args = (2, 6)\n", - "args_padding = tuple([0] * offset) + args\n", - "# Add a C() to tail for copying result\n", - "cp = program(tuple([ins.C(offset, 0)]))\n", - "add_moved_c = concat(add_moved, cp)\n", - "print(f\"{add_moved_c}\")\n", - "ret = run(add_moved_c, *args_padding)\n", - "# Check\n", - "assert args[0] + args[1] == int(ret), \"Error, check the move function\"\n", - "print(f\"\\n{args[0]} + {args[1]} = {ret}\")" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "2QNC084mXrVH", - "outputId": "b1d4eb64-4f77-4615-c71c-16eb2b38a110" - }, - "execution_count": 28, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - " 1: C(7, 5)\n", - " 2: Z(7)\n", - " 3: J(6, 7, 7)\n", - " 4: S(5)\n", - " 5: S(7)\n", - " 6: J(5, 5, 3)\n", - " 7: C(5, 0)\n", - "\n", - "2 + 6 = 8\n" - ] - } + "data": { + "text/plain": [ + "7" ] - }, - { - "cell_type": "markdown", - "source": [ - "## Alternating Execution of Programs" - ], - "metadata": { - "id": "5uiyEjU2oHx2" - } - }, - { - "cell_type": "code", - "source": [ - "def alter(P: program, Q: program) -> program:\n", - " \"\"\"\n", - " The function returns the program implementing the following algorithm:\n", - " 1. provide to execute of P and Q in disjoint memory segments\n", - " 2. do one step of P\n", - " 3. if the execution of P terminates return the corresponding result\n", - " 4. do one step of Q\n", - " 5. if the execution of Q terminates return the corresponding result\n", - " 6. jump to item 2\n", - " Arguments:\n", - " P: program\n", - " Q: program\n", - " Returns\n", - " program\n", - " \"\"\"\n", - " pass" - ], - "metadata": { - "id": "GCa3GB5wpQfd" - }, - "execution_count": null, - "outputs": [] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" } - ] -} \ No newline at end of file + ], + "source": [ + "# Try running this function\n", + "# Build parameters for \"3 + 4\" and \"5 - 1\"\n", + "input_args = (3, 4, 0, 5)\n", + "# Debug mode\n", + "run(merge, *(input_args), verbose=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Error: The merged program does not meet expectations. From observing the debug information, memory[0] being 7 is as expected, but memory[3] is 3, which does not match the expected value of 4. This seems to be caused by an issue where either program P or Q terminates the entire program once it finishes executing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "include_colab_link": true, + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} From 4161d7c384d1d277eb5e8fcb7951fedd550668d3 Mon Sep 17 00:00:00 2001 From: Jingyu Yan Date: Fri, 1 Nov 2024 00:30:36 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BD=BF=E7=94=A8=20Colab=20=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E8=80=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- URM_en.ipynb | 2863 +++++++++++++++++++++++++------------------------- 1 file changed, 1436 insertions(+), 1427 deletions(-) diff --git a/URM_en.ipynb b/URM_en.ipynb index 6383ce0..e29060c 100644 --- a/URM_en.ipynb +++ b/URM_en.ipynb @@ -1,1458 +1,1467 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "view-in-github" - }, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "9znhUfwKqTbC" - }, - "source": [ - "

Unlimited Register Machine

" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "j80Dq1uYTM5X" - }, - "source": [ - "**U**nlimited **R**egister **M**achine (URM) is a realization of the approach to programming based on the automaton concept.\n", - "URM is an easier-to-understand alternative to a Turing machine.\n", - "\n", - "It has (to a certain extent) the same capabilities as the Turing machine, to which URM is logically equivalent.\n", - "The URM was presented in an article published in 1963\n", - "\n", - ">[John C. Shepherdson and H.E. Sturgis: *Computability of Recursive Functions*. J. ACM Vol. 10, no. 2, pp. 217–255.](https://dl.acm.org/doi/pdf/10.1145/321160.321170)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "v09Os5dUx9HG" - }, - "source": [ - "# Preparing a notebook to use" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { "colab": { - "base_uri": "https://localhost:8080/" + "provenance": [], + "toc_visible": true, + "include_colab_link": true }, - "id": "0uybnLWmIUXM", - "outputId": "3f49375b-bccc-4466-a2cd-f7912e9b4489" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mounted at /content/drive\n" - ] + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" } - ], - "source": [ - "from google.colab import drive\n", - "drive.mount('/content/drive')\n", - "\n", - "import sys\n", - "sys.path.append('/content/drive/MyDrive/ColabNotebooks/Computability')" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "id": "UXJMbTOywbm7" - }, - "outputs": [], - "source": [ - "from typing import Dict, Any, Optional, Tuple, List\n", - "from typing_extensions import Self\n", - "from functools import reduce\n", - "from compy.nat import nat" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "HzUdUTt7HgUK" - }, - "source": [ - "# Memory of UMR" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "yYfVbwVlUtTA" - }, - "source": [ - "## Registers" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "5feB_pFWU738" - }, - "source": [ - "URM has an enumerated set of ***registers***, each of which can store a natural number $n\\in\\mathbb{N}$, where $\\mathbb{N}=\\{0,1,2,\\dotsc\\} $.\n", - "\n", - "Each URM program can use only a finite set of registers.\n", - "\n", - "Registers are usually denoted by a capital letter $R$ with an index: $R_{0},R_{1},R_{2},\\dotsc$.\n", - "The index (which is a natural number) is called the ***register index***.\n", - "The number holding register $R_{n}$ is usually denoted by $r_{n}$.\n", - "\n", - "Registers are unlimited in the following two senses:\n", - "\n", - "- even though a URM program can use only a finite set of registers, there is no upper limit for the number of registers used by the programs;\n", - "- there is no upper limit for numbers stored by registers." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "4ehurE3IWVKK" - }, - "source": [ - "## Memory states" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "hlqyf9r6WamQ" - }, - "source": [ - "The state of the memory is determined by the values ​​stored in the registers." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "JKN8B0vKW0OB" - }, - "source": [ - "## Software implementation" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "IGQ1ohl7kIzK" - }, - "source": [ - "The memory of URM is implemented as class `memory` inherited from the built-in type `list`.\n", - "\n", - "The property `size` equals the length of the corresponding list.\n", - "\n", - "The methods `read()` and `write()` provide correct reading from and writing to the memory." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "id": "SivyyEI1H1El" - }, - "outputs": [], - "source": [ - "class memory(list):\n", - "\n", - " def __new__(cls) -> Self:\n", - " return super().__new__(cls, [])\n", - "\n", - " @property\n", - " def size(self) -> int:\n", - " return len(self)\n", - "\n", - " def read(self, addr: int) -> nat:\n", - " try:\n", - " n = nat(addr)\n", - " except ValueError:\n", - " raise ValueError(\"memory.read() error! Bad argument\")\n", - " try:\n", - " return self[n]\n", - " except IndexError:\n", - " return nat(0)\n", - "\n", - " def write(self, addr: int, value: Any) -> None:\n", - " try:\n", - " n, v = nat(addr), nat(value)\n", - " except ValueError:\n", - " raise ValueError(\"memory.write() error! Bad argument(s)\")\n", - " diff = self.size - n\n", - " if diff <= 0: # access to a register that is not yet allocated\n", - " self += (1 - diff) * [nat(0)] # allocate additional registers\n", - " self[n] = v\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "K2ea07zgWg6Q" - }, - "source": [ - "## URM-programs" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "lWOiwFXtWpDZ" - }, - "source": [ - "***Execution states***, that is, the value of the registers and the instruction counter, is changed by programs.\n", - "\n", - "A ***URM program*** is a finite list of ***instructions***.\n", - "\n", - "Program instructions are written in a certain order and numbered with positive natural numbers $1,2,3,\\dotsc$.
\n", - "**Please note!** Instruction number 0 does not exist in the program.\n", - "\n", - "The instruction number for historical reasons is called the ***program line number***." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "32IJjIbpWBGs" - }, - "source": [ - "## Instruction counter" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "eBeuV9d4WL7h" - }, - "source": [ - "The ***instruction counter*** is an additional register that stores a natural number.\n", - "This register is denoted by $IC$ and its contents are $ic$." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "8qzxofV3XxDd" - }, - "source": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
NameMnemonic codeEffectDescription
Zero$\\mathtt{Z}(n)$$R_n\\gets 0$
$IC\\gets ic+1$
Replace the value in $R_{n}$ with $0$ and jump to the nextline of the
program
Successor$\\mathtt{S}(n)$$R_n\\gets r_n+1$
$IC\\gets ic+1$
Increase the value of register $R_{n}$ by $1$ and jump to the next line of
the program
Copy$\\mathtt{C}(m,n)$$R_n\\gets r_m$
$IC\\gets ic+1$
Replace the value in $R_{n}$ with the content of $R_{m}$ (keeping the
content of $R_{m}$) and jump to the next line of the program
Jump$\\mathtt{J}(m,n,k)$$IC\\gets k\\ \\mathtt{if}\\ r_m=r_n\\ \\mathtt{else}\\ ic+1$If the values ​​stored in $R_{m}$ and $R_{n}$ match, then jump to the
program line with number $k$, otherwise to the next program line
" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "nmmw7_IM66tM" - }, - "source": [ - "## Software implementation" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "6ccI_PKAazXL" - }, - "source": [ - "The `ins` class provides the data type implementation inhabited by the URM instructions.\n", - "\n", - "- The instruction `Z(n)` is represented by a tuple `(0, n)`.\n", - "- The instruction `S(n)` is represented by a tuple `(1, n)`.\n", - "- The instruction `C(m, n)` is represented by the tuple `(2, m, n)`.\n", - "- The instruction `J(m, n, k)` is represented by the tuple `(3, m, n, k)`.\n", - "\n", - "To correctly represent instructions by strings, the `__str__()` method is overloaded for this class.\n", - "\n", - "The class methods `Z()`, `S()`, `C()` and `J()` provide convenient instruction creation." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "id": "b6jA7G8rqOg9" - }, - "outputs": [], - "source": [ - "class ins(tuple):\n", - "\n", - " def __new__(cls, *args: Tuple[int]) -> Self:\n", - " if not (2 <= len(args) <= 4):\n", - " raise ValueError(\"ins() error! Invalid number of arguments\")\n", - " if not all(type(arg) == int for arg in args):\n", - " raise ValueError(\"ins() error! Invalid type of argument(s)\")\n", - " if args[0] > 3:\n", - " raise ValueError(\"ins() error! Invalid instruction code\")\n", - " if not all(arg >= 0 for arg in args[1 :]):\n", - " raise ValueError(\"ins() error! Invalid value of operand(s)\")\n", - " return super().__new__(cls, args)\n", - "\n", - " def __str__(self) -> str:\n", - " if self[0] == 0:\n", - " return f\"Z({self[1]})\"\n", - " if self[0] == 1:\n", - " return f\"S({self[1]})\"\n", - " if self[0] == 2:\n", - " return f\"C{self[1 :]}\"\n", - " # self[0] == 3\n", - " return f\"J{self[1 :]}\"\n", - "\n", - " @classmethod\n", - " def Z(cls, n: Any) -> Self:\n", - " try:\n", - " return ins(0, n)\n", - " except ValueError:\n", - " raise ValueError(\"Z() error! Bad operand\")\n", - "\n", - " @classmethod\n", - " def S(cls, n: Any) -> Self:\n", - " try:\n", - " return ins(1, n)\n", - " except ValueError:\n", - " raise ValueError(\"S() error! Bad operand\")\n", - "\n", - " @classmethod\n", - " def C(cls, m: Any, n: Any) -> Self:\n", - " try:\n", - " return ins(2, m, n)\n", - " except ValueError:\n", - " raise ValueError(\"C() error! Bad operand(s)\")\n", - "\n", - " @classmethod\n", - " def J(cls, m: Any, n: Any, k: Any) -> Self:\n", - " try:\n", - " return ins(3, m, n, k)\n", - " except ValueError:\n", - " raise ValueError(\"J() error! Bad operand(s)\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "789mprGe7NE-" - }, - "source": [ - "## Instructions execution" - ] }, - { - "cell_type": "markdown", - "metadata": { - "id": "MiHtXnCkhpPQ" - }, - "source": [ - "The execution of `instruction: ins` if the memory state is `memory_state` implements by calling `apply(instruction, to=memory_state)`, which provides returning the pair `(how_to_change_IC, new_memory_state)`.\n", - "\n", - "The value of `how_to_change_IC` is equal to\n", - "\n", - "- `None`, if after the instruction `instruction` it is necessary to execute the instruction in the next line of the program;\n", - "- the line number of the instruction that will be executed next, if it is not the next in order in the program.\n", - "\n", - "The value `new_memory_state` is the state of the memory after the execution of the instruction `instruction`." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "id": "7Z2kQRzF7SpR" - }, - "outputs": [], - "source": [ - "def apply(i: ins, to: memory) -> Tuple[Optional[int], memory]:\n", - " if type(to) != memory:\n", - " raise ValueError(\"do() error! Invalid type of memory\")\n", - " if type(i) != ins:\n", - " raise ValueError(\"do() error! Invalid type of instruction\")\n", - " if i[0] == 0:\n", - " to.write(i[1], 0)\n", - " return (None, to)\n", - " if i[0] == 1:\n", - " to.write(i[1], to.read(i[1]) + 1)\n", - " return (None, to)\n", - " if i[0] == 2:\n", - " to.write(i[2], to.read(i[1]))\n", - " return (None, to)\n", - " # i[0] == 3\n", - " return (i[3] if to.read(i[1]) == to.read(i[2]) else None, to)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] }, - "id": "J2-oNVEWd959", - "outputId": "73051929-cfff-4441-f57b-8865cfada4ee" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - " m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", - "next = None; m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 0]\n", - "next = None; m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", - "next = None; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", - "next = 5; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", - "next = None; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n" - ] - } - ], - "source": [ - "m = memory()\n", - "for n in range(10):\n", - " m.write(n, n)\n", - "print(f\"{13 * ' '}m = {m}\")\n", - "next, m = apply(ins.Z(9), to=m)\n", - "print(f\"next = {next}; m = {m}\")\n", - "next, m = apply(ins.S(9), to=m)\n", - "print(f\"next = {next}; m = {m}\")\n", - "next, m = apply(ins.C(9, 0), to=m)\n", - "print(f\"next = {next}; m = {m}\")\n", - "next, m = apply(ins.J(1, 9, 5), to=m)\n", - "print(f\"next = {next}; m = {m}\")\n", - "next, m = apply(ins.J(2, 3, 10), to=m)\n", - "print(f\"next = {next}; m = {m}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "l74nSpgBSl7m" - }, - "source": [ - "# URM-programs and their execution" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "w54V9h05mE5q" - }, - "source": [ - "## Translation of a source text into an instruction list" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "WlcJ1IPezSwS" - }, - "source": [ - "The function `compile()` converts the text into a list of URM instructions." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "id": "OfLgefRfrGCj" - }, - "outputs": [], - "source": [ - "def compile(text: str) -> Tuple[ins]:\n", - " if not isinstance(text, str):\n", - " raise ValueError(\"compile() error! Invalid argument type\")\n", - " # split `text` into the list of non empty lines\n", - " lines = [line for line in [item.strip() for\n", - " item in text.split('\\n')] if\n", - " line]\n", - " # the function compiles a line\n", - " def compile_line(line: str) -> ins:\n", - " # remove the tail of 'line' beginning with ')'\n", - " item, sep, _ = line.partition(')')\n", - " if not sep: # ')' is absent in the line\n", - " raise ValueError(\"compile_line() error! Bad instruction format\")\n", - " code, sep, item = item.partition('(')\n", - " if not sep: # '(' is absent in the line\n", - " raise ValueError(\"compile_line() error! Bad instruction format\")\n", - " if code.strip() == 'Z':\n", - " try: # to recognize Z-instruction\n", - " return ins.Z(int(item))\n", - " except ValueError:\n", - " raise ValueError(\"compile_line() error! Bad Z-instruction\")\n", - " elif code.strip() == 'S':\n", - " try: # to recognize S-instruction\n", - " return ins.S(int(item))\n", - " except ValueError:\n", - " raise ValueError(\"compile_line() error! Bad S-instruction\")\n", - " elif code.strip() == 'C':\n", - " op1, sep, item = item.partition(',')\n", - " try: # to recognize C-instruction\n", - " return ins.C(int(op1), int(item))\n", - " except ValueError:\n", - " raise ValueError(\"compile_line() error! Bad C-instruction\")\n", - " elif code.strip() == 'J':\n", - " op1, sep, item = item.partition(',')\n", - " op2, sep, item = item.partition(',')\n", - " try: # to recognize J-instruction\n", - " return ins.J(int(op1), int(op2), int(item))\n", - " except:\n", - " raise ValueError(\"compile_line() error! Bad J-instruction\")\n", - " raise ValueError(\"compile_line() error! Bad instruction format\")\n", - " # end of compile_line()\n", - " return tuple(compile_line(line) for line in lines)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "eBcW57NO6-aM" - }, - "source": [ - "An example of using the `compile()` function." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "markdown", + "source": [ + "

Unlimited Register Machine

" + ], + "metadata": { + "id": "9znhUfwKqTbC" + } }, - "id": "5wMcWBoqmnEZ", - "outputId": "569dbfd1-554e-409b-e996-6510e2252283" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - " 1: C(2, 0)\n", - " 2: Z(2)\n", - " 3: J(1, 2, 0)\n", - " 4: S(0)\n", - " 5: S(2)\n", - " 6: J(0, 0, 3)\n" - ] - } - ], - "source": [ - "text = \"\"\"\n", - " C(2, 0)\n", - " Z (2)\n", - "\n", - " J(1, 2, 0) check loop condition\n", - " S(0)\n", - " S(2)\n", - " J(0, 0, 3) repeat loop\n", - "\"\"\"\n", - "\n", - "ins_tuple = compile(text)\n", - "for ni, i in enumerate(ins_tuple):\n", - " print(f\"{ni + 1:3d}: {i}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "FV-cDiTES0V4" - }, - "source": [ - "## URM-programs" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "rir1QLi5B160" - }, - "source": [ - "### Software implementation of a URM-program" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "id": "irEaC4-iS6nD" - }, - "outputs": [], - "source": [ - "class program(tuple):\n", - "\n", - " def __new__(cls, instructions: Tuple[ins]) -> Self:\n", - " if not type(instructions) == tuple:\n", - " raise ValueError(\"program() error! Invalid argument type\")\n", - " if not all(type(instruction) == ins for instruction in instructions):\n", - " raise ValueError(\"program() error! Invalid type of argument member\")\n", - " return super().__new__(cls, instructions)\n", - "\n", - " def __str__(self):\n", - " return \"\\n\".join([f\"{ni + 1: 3d}: {i}\" for ni, i in enumerate(self)])\n", - "\n", - " @property\n", - " def length(self):\n", - " return len(self)\n", - "\n", - " @property\n", - " def haddr(self):\n", - " temp = 0\n", - " for i in self:\n", - " temp = max(temp, *i[1 : 3])\n", - " return temp\n", - "\n", - " def get_instruction(self, lineno: int) -> Optional[ins]:\n", - " if type(lineno) != int:\n", - " raise ValueError(\"program.get_instruction() error! Bad line number\")\n", - " if lineno < 1:\n", - " return None\n", - " try:\n", - " return self[lineno - 1]\n", - " except IndexError:\n", - " return None" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "markdown", + "source": [ + "**U**nlimited **R**egister **M**achine (URM) is a realization of the approach to programming based on the automaton concept.\n", + "URM is an easier-to-understand alternative to a Turing machine.\n", + "\n", + "It has (to a certain extent) the same capabilities as the Turing machine, to which URM is logically equivalent.\n", + "The URM was presented in an article published in 1963\n", + "\n", + ">[John C. Shepherdson and H.E. Sturgis: *Computability of Recursive Functions*. J. ACM Vol. 10, no. 2, pp. 217–255.](https://dl.acm.org/doi/pdf/10.1145/321160.321170)" + ], + "metadata": { + "id": "j80Dq1uYTM5X" + } }, - "id": "ca3jyBTE7Nu9", - "outputId": "318d3dda-98cb-4311-bfb7-78f196e6b156" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Program text:\n", - " 1: C(2, 0)\n", - " 2: Z(2)\n", - " 3: J(1, 2, 0)\n", - " 4: S(0)\n", - " 5: S(2)\n", - " 6: J(0, 0, 3)\n", - "Program length = 6\n", - "Program highest address = 2\n" - ] - } - ], - "source": [ - "p = program(compile(text))\n", - "print(f\"Program text:\\n{p}\")\n", - "print(f\"Program length = {p.length}\")\n", - "print(f\"Program highest address = {p.haddr}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "bNrUp10RB9KH" - }, - "source": [ - "### Execution of a URM-program" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "id": "vNtaMaamB8Hu" - }, - "outputs": [], - "source": [ - "def run(prgm: program, *data: Tuple[Any], verbose=False) -> nat:\n", - " if type(prgm) != program:\n", - " raise ValueError(\"run() error! Bad program\")\n", - " try:\n", - " data = (nat(x) for x in data)\n", - " except:\n", - " raise ValueError(\"run() error! Invalid data\")\n", - " m = memory()\n", - " for addr, value in enumerate(data):\n", - " m.write(addr + 1, value)\n", - " ic = 1\n", - " while True:\n", - " i = prgm.get_instruction(ic)\n", - " if i is None:\n", - " return m.read(0)\n", - " q, m = apply(i, to=m)\n", - " ic = ic + 1 if q is None else q\n", - " if verbose:\n", - " print(m, i)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "markdown", + "source": [ + "# Preparing a notebook to use" + ], + "metadata": { + "id": "v09Os5dUx9HG" + } }, - "id": "hVheckP1FJQX", - "outputId": "6b427e9e-3457-49e6-aa18-9e336dd490da" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 + 0 = 0 : 2 + 0 = 2 : 4 + 0 = 4 : 6 + 0 = 6 : 8 + 0 = 8\n", - "0 + 1 = 1 : 2 + 1 = 3 : 4 + 1 = 5 : 6 + 1 = 7 : 8 + 1 = 9\n", - "0 + 2 = 2 : 2 + 2 = 4 : 4 + 2 = 6 : 6 + 2 = 8 : 8 + 2 = 10\n", - "0 + 3 = 3 : 2 + 3 = 5 : 4 + 3 = 7 : 6 + 3 = 9 : 8 + 3 = 11\n", - "0 + 4 = 4 : 2 + 4 = 6 : 4 + 4 = 8 : 6 + 4 = 10 : 8 + 4 = 12\n", - "0 + 5 = 5 : 2 + 5 = 7 : 4 + 5 = 9 : 6 + 5 = 11 : 8 + 5 = 13\n", - "0 + 6 = 6 : 2 + 6 = 8 : 4 + 6 = 10 : 6 + 6 = 12 : 8 + 6 = 14\n", - "0 + 7 = 7 : 2 + 7 = 9 : 4 + 7 = 11 : 6 + 7 = 13 : 8 + 7 = 15\n", - "0 + 8 = 8 : 2 + 8 = 10 : 4 + 8 = 12 : 6 + 8 = 14 : 8 + 8 = 16\n", - "0 + 9 = 9 : 2 + 9 = 11 : 4 + 9 = 13 : 6 + 9 = 15 : 8 + 9 = 17\n", - "1 + 0 = 1 : 3 + 0 = 3 : 5 + 0 = 5 : 7 + 0 = 7 : 9 + 0 = 9\n", - "1 + 1 = 2 : 3 + 1 = 4 : 5 + 1 = 6 : 7 + 1 = 8 : 9 + 1 = 10\n", - "1 + 2 = 3 : 3 + 2 = 5 : 5 + 2 = 7 : 7 + 2 = 9 : 9 + 2 = 11\n", - "1 + 3 = 4 : 3 + 3 = 6 : 5 + 3 = 8 : 7 + 3 = 10 : 9 + 3 = 12\n", - "1 + 4 = 5 : 3 + 4 = 7 : 5 + 4 = 9 : 7 + 4 = 11 : 9 + 4 = 13\n", - "1 + 5 = 6 : 3 + 5 = 8 : 5 + 5 = 10 : 7 + 5 = 12 : 9 + 5 = 14\n", - "1 + 6 = 7 : 3 + 6 = 9 : 5 + 6 = 11 : 7 + 6 = 13 : 9 + 6 = 15\n", - "1 + 7 = 8 : 3 + 7 = 10 : 5 + 7 = 12 : 7 + 7 = 14 : 9 + 7 = 16\n", - "1 + 8 = 9 : 3 + 8 = 11 : 5 + 8 = 13 : 7 + 8 = 15 : 9 + 8 = 17\n", - "1 + 9 = 10 : 3 + 9 = 12 : 5 + 9 = 14 : 7 + 9 = 16 : 9 + 9 = 18\n" - ] - } - ], - "source": [ - "report = [(x, y, run(p, x, y)) for x in range(10) for y in range(10)]\n", - "report_items = [\" \".join(\n", - " (f\"{x}\", \"+\", f\"{y}\", \"=\", f\"{z:2d}\")) for (x, y, z) in report]\n", - "report_lines = [\" : \".join(report_items[ic + c * 20] for c in range(5)) for\n", - " ic in range(20)]\n", - "for line in report_lines:\n", - " print(line)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "M7d0jt0l7e9b" - }, - "source": [ - "# Manipulating URM-programs" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Ihhd9seSXQaf" - }, - "source": [ - "## Normalization of URM-programs" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "id": "ICB0f78XXRkY" - }, - "outputs": [], - "source": [ - "def normalize(P: program) -> program:\n", - " \"\"\"\n", - " The function normalizes a URM program by ensuring all jump instructions\n", - " have valid targets. If a jump target k is not in range [1, program_size],\n", - " it is set to program_size + 1.\n", - "\n", - " Arguments\n", - " P: program\n", - "\n", - " Returns\n", - " program\n", - " \"\"\"\n", - " if type(P) != program:\n", - " raise ValueError(\"normalize() error! Invalid argument type\")\n", - " if P.length == 0:\n", - " return P\n", - " normalized_instructions = []\n", - " program_size = P.length\n", - " for i, instruction in enumerate(P):\n", - " if instruction[0] == 3:\n", - " m, n, k = instruction[1:]\n", - " if not (1 <= k <= program_size):\n", - " k = program_size + 1\n", - " normalized_instructions.append(ins.J(m, n, k))\n", - " else:\n", - " normalized_instructions.append(instruction)\n", - "\n", - " return program(tuple(normalized_instructions))" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "code", + "source": [ + "from google.colab import drive\n", + "drive.mount('/content/drive')\n", + "\n", + "import sys\n", + "sys.path.append('/content/drive/MyDrive/ColabNotebooks/Computability')" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "0uybnLWmIUXM", + "outputId": "2dae9af2-975f-4c38-ac70-c5ae975a6ebe" + }, + "execution_count": 1, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Mounted at /content/drive\n" + ] + } + ] }, - "id": "V16SKgpoXdQh", - "outputId": "6c624feb-59f9-4f16-9bbe-de97d9374c1b" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Original program:\n", - " 1: C(2, 0)\n", - " 2: Z(2)\n", - " 3: J(1, 2, 0)\n", - " 4: S(0)\n", - " 5: S(2)\n", - " 6: J(0, 0, 3)\n", - "Normalized program:\n", - " 1: C(2, 0)\n", - " 2: Z(2)\n", - " 3: J(1, 2, 7)\n", - " 4: S(0)\n", - " 5: S(2)\n", - " 6: J(0, 0, 3)\n" - ] - } - ], - "source": [ - "# Check normalized program\n", - "p = program(compile(text))\n", - "print(f\"Original program:\\n{p}\")\n", - "p_n = normalize(p)\n", - "report = [(x, y, run(p_n, x, y)) for x in range(10) for y in range(10)]\n", - "for x, y, ret in report:\n", - " assert (x + y) == int(ret), f\"Failed: {x} + {y} = {ret} (expected {x+y})\"\n", - "print(f\"Normalized program:\\n{p_n}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "3Ou42OZw7Ci8" - }, - "source": [ - "## Concatenation of URM-programs" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "id": "d1h7TKbA8AfB" - }, - "outputs": [], - "source": [ - "def concat(P: program, Q: program) -> program:\n", - " \"\"\"\n", - " The function returns the program that operates as P until\n", - " its termination and then as Q.\n", - "\n", - " Arguments\n", - " P, Q: program\n", - "\n", - " Returns\n", - " program\n", - " \"\"\"\n", - " if not (isinstance(P, program) and isinstance(Q, program)):\n", - " raise ValueError(\"concat() error! Invalid program type\")\n", - " if P.length == 0:\n", - " return Q\n", - "\n", - " P_normalized = normalize(P)\n", - " offset = P_normalized.length\n", - " Q_adjusted = []\n", - " for instruction in Q:\n", - " if instruction[0] == 3: # Jump instruction\n", - " m, n, k = instruction[1:]\n", - " new_k = k + offset if k > 0 else k\n", - " Q_adjusted.append(ins.J(m, n, new_k))\n", - " else:\n", - " Q_adjusted.append(instruction)\n", - "\n", - " cat = list(P_normalized) + Q_adjusted\n", - "\n", - " return program(tuple(cat))" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "code", + "source": [ + "from typing import Dict, Any, Optional, Tuple, List\n", + "from typing_extensions import Self\n", + "from functools import reduce\n", + "from compy.nat import nat" + ], + "metadata": { + "id": "UXJMbTOywbm7" + }, + "execution_count": 2, + "outputs": [] }, - "id": "b8pVbesRXikf", - "outputId": "5aa6daf9-52a6-43e6-9bf7-20ab9aa7c206" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Concatenation: \n", - " 1: Z(0)\n", - " 2: C(1, 2)\n", - " 3: S(0)\n", - " 4: J(3, 4, 5)\n", - " 5: S(0)\n", - " 6: J(3, 4, 0)\n", - " 7: Z(0)\n", - " 8: C(1, 0)\n" - ] - } - ], - "source": [ - "text_P = \"\"\"Z(0)\n", - " C(1,2)\n", - " S(0)\n", - " J(3,4,0)\n", - " \"\"\"\n", - "text_Q = \"\"\"\n", - " S(0)\n", - " J(3,4,0)\n", - " Z(0)\n", - " C(1,0)\n", - " \"\"\"\n", - "P, Q = program(compile(text_P)), program(compile(text_Q))\n", - "C = concat(P, Q)\n", - "print(f'Concatenation: \\n{C}')" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "markdown", + "source": [ + "# Memory of UMR" + ], + "metadata": { + "id": "HzUdUTt7HgUK" + } }, - "id": "FxzKfPMtXk-f", - "outputId": "44405bc9-b1bd-4e5a-e53b-4611ea9217cb" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Programs Concatenation Comparison:\n", - "------------------------------------------------------------\n", - "Program P \tProgram Q \tP concatenated with Q\n", - "------------------------------------------------------------\n", - "Z(0) \t \tZ(0)\n", - "C(1, 2) \t \tC(1, 2)\n", - "S(0) \t \tS(0)\n", - "J(3, 4, 0) \t \tJ(3, 4, 5)\n", - " \tS(0) \tS(0)\n", - " \tJ(3, 4, 0) \tJ(3, 4, 0)\n", - " \tZ(0) \tZ(0)\n", - " \tC(1, 0) \tC(1, 0)\n", - "------------------------------------------------------------\n" - ] - } - ], - "source": [ - "# Pretty print\n", - "COLUMN_WIDTH = 13\n", - "SEPARATOR = '\\t'\n", - "\n", - "print(\"Programs Concatenation Comparison:\")\n", - "print(\"-\" * 60)\n", - "\n", - "print(f\"{'Program P':13}{SEPARATOR}{'Program Q':13}{SEPARATOR}\"\n", - " f\"{'P concatenated with Q'}\")\n", - "print(\"-\" * 60)\n", - "\n", - "for line in range(P.length):\n", - " print(f\"{str(P[line]):{COLUMN_WIDTH}}\"\n", - " f\"{SEPARATOR}{COLUMN_WIDTH * ' '}\"\n", - " f\"{SEPARATOR}{C[line]}\")\n", - "\n", - "for line in range(Q.length):\n", - " print(f\"{COLUMN_WIDTH * ' '}\"\n", - " f\"{SEPARATOR}{str(Q[line]):{COLUMN_WIDTH}}\"\n", - " f\"{SEPARATOR}{C[P.length + line]}\")\n", - "\n", - "print(\"-\" * 60)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Kr_yQyZ19BR9" - }, - "source": [ - "## Moving URM-program in Memory" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "id": "cMTdPqrK9HwV" - }, - "outputs": [], - "source": [ - "def move(P: program, off: int=0) -> program:\n", - " \"\"\"\n", - " The function returns the program that operates as P in the registers\n", - " R[off], R[off + 1], ...\n", - "\n", - " Arguments\n", - " P: program\n", - " off: int {off >= 0}\n", - " Returns\n", - " program\n", - " \"\"\"\n", - " if not isinstance(P, program):\n", - " raise ValueError(\"move() error! Invalid program type\")\n", - " if not isinstance(off, int) or off < 0:\n", - " raise ValueError(\"move() error! Invalid offset\")\n", - " # end of checking arguments\n", - " if P.length == 0 or off == 0:\n", - " return P\n", - " moved_instructions = []\n", - " for instruction in P:\n", - " # Handle different op\n", - " if instruction[0] == 0: # Z()\n", - " moved_instructions.append(ins.Z(instruction[1] + off))\n", - " elif instruction[0] == 1: # S()\n", - " moved_instructions.append(ins.S(instruction[1] + off))\n", - " elif instruction[0] == 2: # C()\n", - " moved_instructions.append(ins.C(instruction[1] + off,\n", - " instruction[2] + off))\n", - " else: # J()\n", - " moved_instructions.append(ins.J(instruction[1] + off,\n", - " instruction[2] + off,\n", - " instruction[3]))\n", - " return program(tuple(moved_instructions))" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "markdown", + "source": [ + "## Registers" + ], + "metadata": { + "id": "yYfVbwVlUtTA" + } }, - "id": "zMt9kqJOXpmM", - "outputId": "457a01c7-2207-4b2a-d983-36cd507c6519" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Original vs Moved Program (offset=5):\n", - "------------------------------------------------------------\n", - "Original \tMoved \t\n", - "------------------------------------------------------------\n", - "C(2, 0) \tC(7, 5) \n", - "Z(2) \tZ(7) \n", - "J(1, 2, 0) \tJ(6, 7, 0) \n", - "S(0) \tS(5) \n", - "S(2) \tS(7) \n", - "J(0, 0, 3) \tJ(5, 5, 3) \n", - "------------------------------------------------------------\n" - ] - } - ], - "source": [ - "# Make the move of an add() program to memory offset by 5\n", - "text_add = \"\"\"\n", - " C(2, 0)\n", - " Z (2)\n", - "\n", - " J(1, 2, 0) check loop condition\n", - " S(0)\n", - " S(2)\n", - " J(0, 0, 3) repeat loop\n", - "\"\"\"\n", - "add = program(compile(text_add))\n", - "offset = 5\n", - "add_moved = move(add, offset)\n", - "\n", - "# Pretty print\n", - "COLUMN_WIDTH = 13\n", - "SEPARATOR = '\\t'\n", - "\n", - "print(\"Original vs Moved Program (offset=5):\")\n", - "print(\"-\" * 60)\n", - "print(f\"{'Original':13}{SEPARATOR}{'Moved':13}{SEPARATOR}\")\n", - "print(\"-\" * 60)\n", - "\n", - "for line in range(add.length):\n", - " print(f\"{str(add[line]):{COLUMN_WIDTH}}\"\n", - " f\"{SEPARATOR}{str(add_moved[line]):{COLUMN_WIDTH}}\")\n", - "\n", - "print(\"-\" * 60)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "markdown", + "source": [ + "URM has an enumerated set of ***registers***, each of which can store a natural number $n\\in\\mathbb{N}$, where $\\mathbb{N}=\\{0,1,2,\\dotsc\\} $.\n", + "\n", + "Each URM program can use only a finite set of registers.\n", + "\n", + "Registers are usually denoted by a capital letter $R$ with an index: $R_{0},R_{1},R_{2},\\dotsc$.\n", + "The index (which is a natural number) is called the ***register index***.\n", + "The number holding register $R_{n}$ is usually denoted by $r_{n}$.\n", + "\n", + "Registers are unlimited in the following two senses:\n", + "\n", + "- even though a URM program can use only a finite set of registers, there is no upper limit for the number of registers used by the programs;\n", + "- there is no upper limit for numbers stored by registers." + ], + "metadata": { + "id": "5feB_pFWU738" + } }, - "id": "2QNC084mXrVH", - "outputId": "b1d4eb64-4f77-4615-c71c-16eb2b38a110" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - " 1: C(7, 5)\n", - " 2: Z(7)\n", - " 3: J(6, 7, 7)\n", - " 4: S(5)\n", - " 5: S(7)\n", - " 6: J(5, 5, 3)\n", - " 7: C(5, 0)\n", - "\n", - "2 + 6 = 8\n" - ] - } - ], - "source": [ - "# Check moved program\n", - "args = (2, 6)\n", - "args_padding = tuple([0] * offset) + args\n", - "# Add a C() to tail for copying result\n", - "cp = program(tuple([ins.C(offset, 0)]))\n", - "add_moved_c = concat(add_moved, cp)\n", - "print(f\"{add_moved_c}\")\n", - "ret = run(add_moved_c, *args_padding)\n", - "# Check\n", - "assert args[0] + args[1] == int(ret), \"Error, check the move function\"\n", - "print(f\"\\n{args[0]} + {args[1]} = {ret}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "5uiyEjU2oHx2" - }, - "source": [ - "## Alternating Execution of Programs" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": { - "id": "GCa3GB5wpQfd" - }, - "outputs": [], - "source": [ - "def alter(P: program, Q: program) -> program:\n", - " \"\"\"\n", - " The function returns the program implementing the following algorithm:\n", - " 1. provide to execute of P and Q in disjoint memory segments\n", - " 2. do one step of P\n", - " 3. if the execution of P terminates return the corresponding result\n", - " 4. do one step of Q\n", - " 5. if the execution of Q terminates return the corresponding result\n", - " 6. jump to item 2\n", - " Arguments:\n", - " P: program\n", - " Q: program\n", - " Returns\n", - " program\n", - " \"\"\"\n", - " if not isinstance(P, program) or not isinstance(Q, program):\n", - " raise ValueError(\"alter() error! Invalid program type\")\n", - "\n", - " # Step 1: Move Q to a disjoint memory segment\n", - " P_haddr = P.haddr\n", - " offset_Q = P_haddr + 1 # Offset for Q registers\n", - " P_moved = move(P, 0) # P remains at its original position\n", - " Q_moved = move(Q, offset_Q)\n", - "\n", - " # Define result registers\n", - " r_p = 0 # P: result register (after move, remains 0)\n", - " r_q = offset_Q # Q: result register (after move)\n", - "\n", - " # Step 2: Interleave instructions and build line maps\n", - " interleaved_instructions = []\n", - " line_map_P = {}\n", - " line_map_Q = {}\n", - " instr_origin = [] # Keep track of the origin (P or Q) of each instruction\n", - "\n", - " idx = 1\n", - " P_idx = 1\n", - " Q_idx = 1\n", - " P_length = P_moved.length\n", - " Q_length = Q_moved.length\n", - " while P_idx <= P_length or Q_idx <= Q_length:\n", - " if P_idx <= P_length:\n", - " line_map_P[P_idx] = idx\n", - " interleaved_instructions.append(P_moved[P_idx - 1])\n", - " instr_origin.append('P')\n", - " idx += 1\n", - " P_idx += 1\n", - " if Q_idx <= Q_length:\n", - " line_map_Q[Q_idx] = idx\n", - " interleaved_instructions.append(Q_moved[Q_idx - 1])\n", - " instr_origin.append('Q')\n", - " idx += 1\n", - " Q_idx += 1\n", - "\n", - " # Step 3: Add termination code for P and Q\n", - " t_p = idx\n", - " interleaved_instructions.append(ins.C(r_p, 0)) # Copy P result to R0\n", - " instr_origin.append('Termination_P')\n", - " idx += 1\n", - "\n", - " t_q = idx\n", - " interleaved_instructions.append(ins.C(r_q, 1)) # Copy Q result to R1\n", - " instr_origin.append('Termination_Q')\n", - " idx += 1\n", - "\n", - " # Step 4: Adjust jump instructions\n", - " adjusted_instructions = []\n", - " for i, instr in enumerate(interleaved_instructions):\n", - " if instr[0] == 3: # Jumps\n", - " m, n, k = instr[1:]\n", - " origin = instr_origin[i]\n", - " if origin == 'P':\n", - " if k == 0:\n", - " new_k = t_p # Jump to P termination code\n", - " else:\n", - " new_k = line_map_P.get(k, idx) # Default to program end if not found\n", - " elif origin == 'Q':\n", - " if k == 0:\n", - " new_k = t_q # Jump to Q termination code\n", - " else:\n", - " new_k = line_map_Q.get(k, idx)\n", - " else:\n", - " new_k = k # For termination code, k remains the same\n", - " adjusted_instr = ins.J(m, n, new_k)\n", - " adjusted_instructions.append(adjusted_instr)\n", - " else:\n", - " adjusted_instructions.append(instr)\n", - "\n", - " return program(tuple(adjusted_instructions))" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ + "cell_type": "markdown", + "source": [ + "## Memory states" + ], + "metadata": { + "id": "4ehurE3IWVKK" + } + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "3 + 4 = 7\n" - ] - } - ], - "source": [ - "# Prepare 2 URM programs\n", - "text_add = \"\"\"\n", - " C(2, 0)\n", - " Z (2)\n", - "\n", - " J(1, 2, 0) check loop condition\n", - " S(0)\n", - " S(2)\n", - " J(0, 0, 3) repeat loop\n", - "\"\"\"\n", - "add = program(compile(text_add))\n", - "print(f\"3 + 4 = {run(add, 3, 4)}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ + "cell_type": "markdown", + "source": [ + "The state of the memory is determined by the values ​​stored in the registers." + ], + "metadata": { + "id": "hlqyf9r6WamQ" + } + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "5 - 1 = 4\n" - ] - } - ], - "source": [ - "# Predecessor function\n", - "text_pred = \"\"\"\n", - " J(0, 1, 0),\n", - " S(2),\n", - " J(1, 2, 0),\n", - " S(0),\n", - " S(2),\n", - " J(0, 0, 3)\n", - "\"\"\"\n", - "pred = program(compile(text_pred))\n", - "print(f\"5 - 1 = {run(pred, 5)}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ + "cell_type": "markdown", + "source": [ + "## Software implementation" + ], + "metadata": { + "id": "JKN8B0vKW0OB" + } + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - " 1: C(2, 0)\n", - " 2: J(3, 4, 14)\n", - " 3: Z(2)\n", - " 4: S(5)\n", - " 5: J(1, 2, 13)\n", - " 6: J(4, 5, 14)\n", - " 7: S(0)\n", - " 8: S(3)\n", - " 9: S(2)\n", - " 10: S(5)\n", - " 11: J(0, 0, 5)\n", - " 12: J(3, 3, 6)\n", - " 13: C(0, 0)\n", - " 14: C(3, 1)\n" - ] - } - ], - "source": [ - "# Alternately merge two functions\n", - "merge = alter(add, pred)\n", - "print(merge)" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ + "cell_type": "markdown", + "source": [ + "The memory of URM is implemented as class `memory` inherited from the built-in type `list`.\n", + "\n", + "The property `size` equals the length of the corresponding list.\n", + "\n", + "The methods `read()` and `write()` provide correct reading from and writing to the memory." + ], + "metadata": { + "id": "IGQ1ohl7kIzK" + } + }, + { + "cell_type": "code", + "source": [ + "class memory(list):\n", + "\n", + " def __new__(cls) -> Self:\n", + " return super().__new__(cls, [])\n", + "\n", + " @property\n", + " def size(self) -> int:\n", + " return len(self)\n", + "\n", + " def read(self, addr: int) -> nat:\n", + " try:\n", + " n = nat(addr)\n", + " except ValueError:\n", + " raise ValueError(\"memory.read() error! Bad argument\")\n", + " try:\n", + " return self[n]\n", + " except IndexError:\n", + " return nat(0)\n", + "\n", + " def write(self, addr: int, value: Any) -> None:\n", + " try:\n", + " n, v = nat(addr), nat(value)\n", + " except ValueError:\n", + " raise ValueError(\"memory.write() error! Bad argument(s)\")\n", + " diff = self.size - n\n", + " if diff <= 0: # access to a register that is not yet allocated\n", + " self += (1 - diff) * [nat(0)] # allocate additional registers\n", + " self[n] = v\n" + ], + "metadata": { + "id": "SivyyEI1H1El" + }, + "execution_count": 3, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## URM-programs" + ], + "metadata": { + "id": "K2ea07zgWg6Q" + } + }, + { + "cell_type": "markdown", + "source": [ + "***Execution states***, that is, the value of the registers and the instruction counter, is changed by programs.\n", + "\n", + "A ***URM program*** is a finite list of ***instructions***.\n", + "\n", + "Program instructions are written in a certain order and numbered with positive natural numbers $1,2,3,\\dotsc$.
\n", + "**Please note!** Instruction number 0 does not exist in the program.\n", + "\n", + "The instruction number for historical reasons is called the ***program line number***." + ], + "metadata": { + "id": "lWOiwFXtWpDZ" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Instruction counter" + ], + "metadata": { + "id": "32IJjIbpWBGs" + } + }, + { + "cell_type": "markdown", + "source": [ + "The ***instruction counter*** is an additional register that stores a natural number.\n", + "This register is denoted by $IC$ and its contents are $ic$." + ], + "metadata": { + "id": "eBeuV9d4WL7h" + } + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
NameMnemonic codeEffectDescription
Zero$\\mathtt{Z}(n)$$R_n\\gets 0$
$IC\\gets ic+1$
Replace the value in $R_{n}$ with $0$ and jump to the nextline of the
program
Successor$\\mathtt{S}(n)$$R_n\\gets r_n+1$
$IC\\gets ic+1$
Increase the value of register $R_{n}$ by $1$ and jump to the next line of
the program
Copy$\\mathtt{C}(m,n)$$R_n\\gets r_m$
$IC\\gets ic+1$
Replace the value in $R_{n}$ with the content of $R_{m}$ (keeping the
content of $R_{m}$) and jump to the next line of the program
Jump$\\mathtt{J}(m,n,k)$$IC\\gets k\\ \\mathtt{if}\\ r_m=r_n\\ \\mathtt{else}\\ ic+1$If the values ​​stored in $R_{m}$ and $R_{n}$ match, then jump to the
program line with number $k$, otherwise to the next program line
" + ], + "metadata": { + "id": "8qzxofV3XxDd" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Software implementation" + ], + "metadata": { + "id": "nmmw7_IM66tM" + } + }, + { + "cell_type": "markdown", + "source": [ + "The `ins` class provides the data type implementation inhabited by the URM instructions.\n", + "\n", + "- The instruction `Z(n)` is represented by a tuple `(0, n)`.\n", + "- The instruction `S(n)` is represented by a tuple `(1, n)`.\n", + "- The instruction `C(m, n)` is represented by the tuple `(2, m, n)`.\n", + "- The instruction `J(m, n, k)` is represented by the tuple `(3, m, n, k)`.\n", + "\n", + "To correctly represent instructions by strings, the `__str__()` method is overloaded for this class.\n", + "\n", + "The class methods `Z()`, `S()`, `C()` and `J()` provide convenient instruction creation." + ], + "metadata": { + "id": "6ccI_PKAazXL" + } + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "b6jA7G8rqOg9" + }, + "outputs": [], + "source": [ + "class ins(tuple):\n", + "\n", + " def __new__(cls, *args: Tuple[int]) -> Self:\n", + " if not (2 <= len(args) <= 4):\n", + " raise ValueError(\"ins() error! Invalid number of arguments\")\n", + " if not all(type(arg) == int for arg in args):\n", + " raise ValueError(\"ins() error! Invalid type of argument(s)\")\n", + " if args[0] > 3:\n", + " raise ValueError(\"ins() error! Invalid instruction code\")\n", + " if not all(arg >= 0 for arg in args[1 :]):\n", + " raise ValueError(\"ins() error! Invalid value of operand(s)\")\n", + " return super().__new__(cls, args)\n", + "\n", + " def __str__(self) -> str:\n", + " if self[0] == 0:\n", + " return f\"Z({self[1]})\"\n", + " if self[0] == 1:\n", + " return f\"S({self[1]})\"\n", + " if self[0] == 2:\n", + " return f\"C{self[1 :]}\"\n", + " # self[0] == 3\n", + " return f\"J{self[1 :]}\"\n", + "\n", + " @classmethod\n", + " def Z(cls, n: Any) -> Self:\n", + " try:\n", + " return ins(0, n)\n", + " except ValueError:\n", + " raise ValueError(\"Z() error! Bad operand\")\n", + "\n", + " @classmethod\n", + " def S(cls, n: Any) -> Self:\n", + " try:\n", + " return ins(1, n)\n", + " except ValueError:\n", + " raise ValueError(\"S() error! Bad operand\")\n", + "\n", + " @classmethod\n", + " def C(cls, m: Any, n: Any) -> Self:\n", + " try:\n", + " return ins(2, m, n)\n", + " except ValueError:\n", + " raise ValueError(\"C() error! Bad operand(s)\")\n", + "\n", + " @classmethod\n", + " def J(cls, m: Any, n: Any, k: Any) -> Self:\n", + " try:\n", + " return ins(3, m, n, k)\n", + " except ValueError:\n", + " raise ValueError(\"J() error! Bad operand(s)\")\n" + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Instructions execution" + ], + "metadata": { + "id": "789mprGe7NE-" + } + }, + { + "cell_type": "markdown", + "source": [ + "The execution of `instruction: ins` if the memory state is `memory_state` implements by calling `apply(instruction, to=memory_state)`, which provides returning the pair `(how_to_change_IC, new_memory_state)`.\n", + "\n", + "The value of `how_to_change_IC` is equal to\n", + "\n", + "- `None`, if after the instruction `instruction` it is necessary to execute the instruction in the next line of the program;\n", + "- the line number of the instruction that will be executed next, if it is not the next in order in the program.\n", + "\n", + "The value `new_memory_state` is the state of the memory after the execution of the instruction `instruction`." + ], + "metadata": { + "id": "MiHtXnCkhpPQ" + } + }, + { + "cell_type": "code", + "source": [ + "def apply(i: ins, to: memory) -> Tuple[Optional[int], memory]:\n", + " if type(to) != memory:\n", + " raise ValueError(\"do() error! Invalid type of memory\")\n", + " if type(i) != ins:\n", + " raise ValueError(\"do() error! Invalid type of instruction\")\n", + " if i[0] == 0:\n", + " to.write(i[1], 0)\n", + " return (None, to)\n", + " if i[0] == 1:\n", + " to.write(i[1], to.read(i[1]) + 1)\n", + " return (None, to)\n", + " if i[0] == 2:\n", + " to.write(i[2], to.read(i[1]))\n", + " return (None, to)\n", + " # i[0] == 3\n", + " return (i[3] if to.read(i[1]) == to.read(i[2]) else None, to)" + ], + "metadata": { + "id": "7Z2kQRzF7SpR" + }, + "execution_count": 5, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "m = memory()\n", + "for n in range(10):\n", + " m.write(n, n)\n", + "print(f\"{13 * ' '}m = {m}\")\n", + "next, m = apply(ins.Z(9), to=m)\n", + "print(f\"next = {next}; m = {m}\")\n", + "next, m = apply(ins.S(9), to=m)\n", + "print(f\"next = {next}; m = {m}\")\n", + "next, m = apply(ins.C(9, 0), to=m)\n", + "print(f\"next = {next}; m = {m}\")\n", + "next, m = apply(ins.J(1, 9, 5), to=m)\n", + "print(f\"next = {next}; m = {m}\")\n", + "next, m = apply(ins.J(2, 3, 10), to=m)\n", + "print(f\"next = {next}; m = {m}\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "J2-oNVEWd959", + "outputId": "1ca851cd-d33c-4ee0-eca2-30d3be12fa94" + }, + "execution_count": 6, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", + "next = None; m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 0]\n", + "next = None; m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", + "next = None; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", + "next = 5; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n", + "next = None; m = [1, 1, 2, 3, 4, 5, 6, 7, 8, 1]\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# URM-programs and their execution" + ], + "metadata": { + "id": "l74nSpgBSl7m" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Translation of a source text into an instruction list" + ], + "metadata": { + "id": "w54V9h05mE5q" + } + }, + { + "cell_type": "markdown", + "source": [ + "The function `compile()` converts the text into a list of URM instructions." + ], + "metadata": { + "id": "WlcJ1IPezSwS" + } + }, + { + "cell_type": "code", + "source": [ + "def compile(text: str) -> Tuple[ins]:\n", + " if not isinstance(text, str):\n", + " raise ValueError(\"compile() error! Invalid argument type\")\n", + " # split `text` into the list of non empty lines\n", + " lines = [line for line in [item.strip() for\n", + " item in text.split('\\n')] if\n", + " line]\n", + " # the function compiles a line\n", + " def compile_line(line: str) -> ins:\n", + " # remove the tail of 'line' beginning with ')'\n", + " item, sep, _ = line.partition(')')\n", + " if not sep: # ')' is absent in the line\n", + " raise ValueError(\"compile_line() error! Bad instruction format\")\n", + " code, sep, item = item.partition('(')\n", + " if not sep: # '(' is absent in the line\n", + " raise ValueError(\"compile_line() error! Bad instruction format\")\n", + " if code.strip() == 'Z':\n", + " try: # to recognize Z-instruction\n", + " return ins.Z(int(item))\n", + " except ValueError:\n", + " raise ValueError(\"compile_line() error! Bad Z-instruction\")\n", + " elif code.strip() == 'S':\n", + " try: # to recognize S-instruction\n", + " return ins.S(int(item))\n", + " except ValueError:\n", + " raise ValueError(\"compile_line() error! Bad S-instruction\")\n", + " elif code.strip() == 'C':\n", + " op1, sep, item = item.partition(',')\n", + " try: # to recognize C-instruction\n", + " return ins.C(int(op1), int(item))\n", + " except ValueError:\n", + " raise ValueError(\"compile_line() error! Bad C-instruction\")\n", + " elif code.strip() == 'J':\n", + " op1, sep, item = item.partition(',')\n", + " op2, sep, item = item.partition(',')\n", + " try: # to recognize J-instruction\n", + " return ins.J(int(op1), int(op2), int(item))\n", + " except:\n", + " raise ValueError(\"compile_line() error! Bad J-instruction\")\n", + " raise ValueError(\"compile_line() error! Bad instruction format\")\n", + " # end of compile_line()\n", + " return tuple(compile_line(line) for line in lines)" + ], + "metadata": { + "id": "OfLgefRfrGCj" + }, + "execution_count": 7, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "An example of using the `compile()` function." + ], + "metadata": { + "id": "eBcW57NO6-aM" + } + }, + { + "cell_type": "code", + "source": [ + "text = \"\"\"\n", + " C(2, 0)\n", + " Z (2)\n", + "\n", + " J(1, 2, 0) check loop condition\n", + " S(0)\n", + " S(2)\n", + " J(0, 0, 3) repeat loop\n", + "\"\"\"\n", + "\n", + "ins_tuple = compile(text)\n", + "for ni, i in enumerate(ins_tuple):\n", + " print(f\"{ni + 1:3d}: {i}\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "5wMcWBoqmnEZ", + "outputId": "bc44b039-9b78-4b9d-fa92-db225a5c8062" + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " 1: C(2, 0)\n", + " 2: Z(2)\n", + " 3: J(1, 2, 0)\n", + " 4: S(0)\n", + " 5: S(2)\n", + " 6: J(0, 0, 3)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## URM-programs" + ], + "metadata": { + "id": "FV-cDiTES0V4" + } + }, + { + "cell_type": "markdown", + "source": [ + "### Software implementation of a URM-program" + ], + "metadata": { + "id": "rir1QLi5B160" + } + }, + { + "cell_type": "code", + "source": [ + "class program(tuple):\n", + "\n", + " def __new__(cls, instructions: Tuple[ins]) -> Self:\n", + " if not type(instructions) == tuple:\n", + " raise ValueError(\"program() error! Invalid argument type\")\n", + " if not all(type(instruction) == ins for instruction in instructions):\n", + " raise ValueError(\"program() error! Invalid type of argument member\")\n", + " return super().__new__(cls, instructions)\n", + "\n", + " def __str__(self):\n", + " return \"\\n\".join([f\"{ni + 1: 3d}: {i}\" for ni, i in enumerate(self)])\n", + "\n", + " @property\n", + " def length(self):\n", + " return len(self)\n", + "\n", + " @property\n", + " def haddr(self):\n", + " temp = 0\n", + " for i in self:\n", + " temp = max(temp, *i[1 : 3])\n", + " return temp\n", + "\n", + " def get_instruction(self, lineno: int) -> Optional[ins]:\n", + " if type(lineno) != int:\n", + " raise ValueError(\"program.get_instruction() error! Bad line number\")\n", + " if lineno < 1:\n", + " return None\n", + " try:\n", + " return self[lineno - 1]\n", + " except IndexError:\n", + " return None" + ], + "metadata": { + "id": "irEaC4-iS6nD" + }, + "execution_count": 9, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "p = program(compile(text))\n", + "print(f\"Program text:\\n{p}\")\n", + "print(f\"Program length = {p.length}\")\n", + "print(f\"Program highest address = {p.haddr}\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ca3jyBTE7Nu9", + "outputId": "bc7ba15d-c2f0-464e-ceb9-33d6fbb52596" + }, + "execution_count": 10, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Program text:\n", + " 1: C(2, 0)\n", + " 2: Z(2)\n", + " 3: J(1, 2, 0)\n", + " 4: S(0)\n", + " 5: S(2)\n", + " 6: J(0, 0, 3)\n", + "Program length = 6\n", + "Program highest address = 2\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### Execution of a URM-program" + ], + "metadata": { + "id": "bNrUp10RB9KH" + } + }, + { + "cell_type": "code", + "source": [ + "def run(prgm: program, *data: Tuple[Any], verbose=False) -> nat:\n", + " if type(prgm) != program:\n", + " raise ValueError(\"run() error! Bad program\")\n", + " try:\n", + " data = (nat(x) for x in data)\n", + " except:\n", + " raise ValueError(\"run() error! Invalid data\")\n", + " m = memory()\n", + " for addr, value in enumerate(data):\n", + " m.write(addr + 1, value)\n", + " ic = 1\n", + " while True:\n", + " i = prgm.get_instruction(ic)\n", + " if i is None:\n", + " return m.read(0)\n", + " q, m = apply(i, to=m)\n", + " ic = ic + 1 if q is None else q\n", + " if verbose:\n", + " print(m, i)" + ], + "metadata": { + "id": "vNtaMaamB8Hu" + }, + "execution_count": 26, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "report = [(x, y, run(p, x, y)) for x in range(10) for y in range(10)]\n", + "report_items = [\" \".join(\n", + " (f\"{x}\", \"+\", f\"{y}\", \"=\", f\"{z:2d}\")) for (x, y, z) in report]\n", + "report_lines = [\" : \".join(report_items[ic + c * 20] for c in range(5)) for\n", + " ic in range(20)]\n", + "for line in report_lines:\n", + " print(line)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hVheckP1FJQX", + "outputId": "10ac2934-aba0-494c-832e-c8d6ec82bea4" + }, + "execution_count": 12, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "0 + 0 = 0 : 2 + 0 = 2 : 4 + 0 = 4 : 6 + 0 = 6 : 8 + 0 = 8\n", + "0 + 1 = 1 : 2 + 1 = 3 : 4 + 1 = 5 : 6 + 1 = 7 : 8 + 1 = 9\n", + "0 + 2 = 2 : 2 + 2 = 4 : 4 + 2 = 6 : 6 + 2 = 8 : 8 + 2 = 10\n", + "0 + 3 = 3 : 2 + 3 = 5 : 4 + 3 = 7 : 6 + 3 = 9 : 8 + 3 = 11\n", + "0 + 4 = 4 : 2 + 4 = 6 : 4 + 4 = 8 : 6 + 4 = 10 : 8 + 4 = 12\n", + "0 + 5 = 5 : 2 + 5 = 7 : 4 + 5 = 9 : 6 + 5 = 11 : 8 + 5 = 13\n", + "0 + 6 = 6 : 2 + 6 = 8 : 4 + 6 = 10 : 6 + 6 = 12 : 8 + 6 = 14\n", + "0 + 7 = 7 : 2 + 7 = 9 : 4 + 7 = 11 : 6 + 7 = 13 : 8 + 7 = 15\n", + "0 + 8 = 8 : 2 + 8 = 10 : 4 + 8 = 12 : 6 + 8 = 14 : 8 + 8 = 16\n", + "0 + 9 = 9 : 2 + 9 = 11 : 4 + 9 = 13 : 6 + 9 = 15 : 8 + 9 = 17\n", + "1 + 0 = 1 : 3 + 0 = 3 : 5 + 0 = 5 : 7 + 0 = 7 : 9 + 0 = 9\n", + "1 + 1 = 2 : 3 + 1 = 4 : 5 + 1 = 6 : 7 + 1 = 8 : 9 + 1 = 10\n", + "1 + 2 = 3 : 3 + 2 = 5 : 5 + 2 = 7 : 7 + 2 = 9 : 9 + 2 = 11\n", + "1 + 3 = 4 : 3 + 3 = 6 : 5 + 3 = 8 : 7 + 3 = 10 : 9 + 3 = 12\n", + "1 + 4 = 5 : 3 + 4 = 7 : 5 + 4 = 9 : 7 + 4 = 11 : 9 + 4 = 13\n", + "1 + 5 = 6 : 3 + 5 = 8 : 5 + 5 = 10 : 7 + 5 = 12 : 9 + 5 = 14\n", + "1 + 6 = 7 : 3 + 6 = 9 : 5 + 6 = 11 : 7 + 6 = 13 : 9 + 6 = 15\n", + "1 + 7 = 8 : 3 + 7 = 10 : 5 + 7 = 12 : 7 + 7 = 14 : 9 + 7 = 16\n", + "1 + 8 = 9 : 3 + 8 = 11 : 5 + 8 = 13 : 7 + 8 = 15 : 9 + 8 = 17\n", + "1 + 9 = 10 : 3 + 9 = 12 : 5 + 9 = 14 : 7 + 9 = 16 : 9 + 9 = 18\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Manipulating URM-programs" + ], + "metadata": { + "id": "M7d0jt0l7e9b" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Normalization of URM-programs" + ], + "metadata": { + "id": "Ihhd9seSXQaf" + } + }, + { + "cell_type": "code", + "source": [ + "def normalize(P: program) -> program:\n", + " \"\"\"\n", + " The function normalizes a URM program by ensuring all jump instructions\n", + " have valid targets. If a jump target k is not in range [1, program_size],\n", + " it is set to program_size + 1.\n", + "\n", + " Arguments\n", + " P: program\n", + "\n", + " Returns\n", + " program\n", + " \"\"\"\n", + " if type(P) != program:\n", + " raise ValueError(\"normalize() error! Invalid argument type\")\n", + " if P.length == 0:\n", + " return P\n", + " normalized_instructions = []\n", + " program_size = P.length\n", + " for i, instruction in enumerate(P):\n", + " if instruction[0] == 3:\n", + " m, n, k = instruction[1:]\n", + " if not (1 <= k <= program_size):\n", + " k = program_size + 1\n", + " normalized_instructions.append(ins.J(m, n, k))\n", + " else:\n", + " normalized_instructions.append(instruction)\n", + "\n", + " return program(tuple(normalized_instructions))" + ], + "metadata": { + "id": "ICB0f78XXRkY" + }, + "execution_count": 13, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Check normalized program\n", + "p = program(compile(text))\n", + "print(f\"Original program:\\n{p}\")\n", + "p_n = normalize(p)\n", + "report = [(x, y, run(p_n, x, y)) for x in range(10) for y in range(10)]\n", + "for x, y, ret in report:\n", + " assert (x + y) == int(ret), f\"Failed: {x} + {y} = {ret} (expected {x+y})\"\n", + "print(f\"Normalized program:\\n{p_n}\")" + ], + "metadata": { + "id": "V16SKgpoXdQh", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "6c624feb-59f9-4f16-9bbe-de97d9374c1b" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Original program:\n", + " 1: C(2, 0)\n", + " 2: Z(2)\n", + " 3: J(1, 2, 0)\n", + " 4: S(0)\n", + " 5: S(2)\n", + " 6: J(0, 0, 3)\n", + "Normalized program:\n", + " 1: C(2, 0)\n", + " 2: Z(2)\n", + " 3: J(1, 2, 7)\n", + " 4: S(0)\n", + " 5: S(2)\n", + " 6: J(0, 0, 3)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Concatenation of URM-programs" + ], + "metadata": { + "id": "3Ou42OZw7Ci8" + } + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "[4, 3, 4, 0, 5] C(2, 0)\n", - "[4, 3, 4, 0, 5] J(3, 4, 14)\n", - "[4, 3, 0, 0, 5] Z(2)\n", - "[4, 3, 0, 0, 5, 1] S(5)\n", - "[4, 3, 0, 0, 5, 1] J(1, 2, 13)\n", - "[4, 3, 0, 0, 5, 1] J(4, 5, 14)\n", - "[5, 3, 0, 0, 5, 1] S(0)\n", - "[5, 3, 0, 1, 5, 1] S(3)\n", - "[5, 3, 1, 1, 5, 1] S(2)\n", - "[5, 3, 1, 1, 5, 2] S(5)\n", - "[5, 3, 1, 1, 5, 2] J(0, 0, 5)\n", - "[5, 3, 1, 1, 5, 2] J(1, 2, 13)\n", - "[5, 3, 1, 1, 5, 2] J(4, 5, 14)\n", - "[6, 3, 1, 1, 5, 2] S(0)\n", - "[6, 3, 1, 2, 5, 2] S(3)\n", - "[6, 3, 2, 2, 5, 2] S(2)\n", - "[6, 3, 2, 2, 5, 3] S(5)\n", - "[6, 3, 2, 2, 5, 3] J(0, 0, 5)\n", - "[6, 3, 2, 2, 5, 3] J(1, 2, 13)\n", - "[6, 3, 2, 2, 5, 3] J(4, 5, 14)\n", - "[7, 3, 2, 2, 5, 3] S(0)\n", - "[7, 3, 2, 3, 5, 3] S(3)\n", - "[7, 3, 3, 3, 5, 3] S(2)\n", - "[7, 3, 3, 3, 5, 4] S(5)\n", - "[7, 3, 3, 3, 5, 4] J(0, 0, 5)\n", - "[7, 3, 3, 3, 5, 4] J(1, 2, 13)\n", - "[7, 3, 3, 3, 5, 4] C(0, 0)\n", - "[7, 3, 3, 3, 5, 4] C(3, 1)\n" - ] + "cell_type": "code", + "source": [ + "def concat(P: program, Q: program) -> program:\n", + " \"\"\"\n", + " The function returns the program that operates as P until\n", + " its termination and then as Q.\n", + "\n", + " Arguments\n", + " P, Q: program\n", + "\n", + " Returns\n", + " program\n", + " \"\"\"\n", + " if not (isinstance(P, program) and isinstance(Q, program)):\n", + " raise ValueError(\"concat() error! Invalid program type\")\n", + " if P.length == 0:\n", + " return Q\n", + "\n", + " P_normalized = normalize(P)\n", + " offset = P_normalized.length\n", + " Q_adjusted = []\n", + " for instruction in Q:\n", + " if instruction[0] == 3: # Jump instruction\n", + " m, n, k = instruction[1:]\n", + " new_k = k + offset if k > 0 else k\n", + " Q_adjusted.append(ins.J(m, n, new_k))\n", + " else:\n", + " Q_adjusted.append(instruction)\n", + "\n", + " cat = list(P_normalized) + Q_adjusted\n", + "\n", + " return program(tuple(cat))" + ], + "metadata": { + "id": "d1h7TKbA8AfB" + }, + "execution_count": 14, + "outputs": [] }, { - "data": { - "text/plain": [ - "7" + "cell_type": "code", + "source": [ + "text_P = \"\"\"Z(0)\n", + " C(1,2)\n", + " S(0)\n", + " J(3,4,0)\n", + " \"\"\"\n", + "text_Q = \"\"\"\n", + " S(0)\n", + " J(3,4,0)\n", + " Z(0)\n", + " C(1,0)\n", + " \"\"\"\n", + "P, Q = program(compile(text_P)), program(compile(text_Q))\n", + "C = concat(P, Q)\n", + "print(f'Concatenation: \\n{C}')" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "b8pVbesRXikf", + "outputId": "4128a443-cb89-4984-f75a-8c78ae12eacf" + }, + "execution_count": 15, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Concatenation: \n", + " 1: Z(0)\n", + " 2: C(1, 2)\n", + " 3: S(0)\n", + " 4: J(3, 4, 5)\n", + " 5: S(0)\n", + " 6: J(3, 4, 0)\n", + " 7: Z(0)\n", + " 8: C(1, 0)\n" + ] + } ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" + }, + { + "cell_type": "code", + "source": [ + "# Pretty print\n", + "COLUMN_WIDTH = 13\n", + "SEPARATOR = '\\t'\n", + "\n", + "print(\"Programs Concatenation Comparison:\")\n", + "print(\"-\" * 60)\n", + "\n", + "print(f\"{'Program P':13}{SEPARATOR}{'Program Q':13}{SEPARATOR}\"\n", + " f\"{'P concatenated with Q'}\")\n", + "print(\"-\" * 60)\n", + "\n", + "for line in range(P.length):\n", + " print(f\"{str(P[line]):{COLUMN_WIDTH}}\"\n", + " f\"{SEPARATOR}{COLUMN_WIDTH * ' '}\"\n", + " f\"{SEPARATOR}{C[line]}\")\n", + "\n", + "for line in range(Q.length):\n", + " print(f\"{COLUMN_WIDTH * ' '}\"\n", + " f\"{SEPARATOR}{str(Q[line]):{COLUMN_WIDTH}}\"\n", + " f\"{SEPARATOR}{C[P.length + line]}\")\n", + "\n", + "print(\"-\" * 60)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "FxzKfPMtXk-f", + "outputId": "271d03bd-57c7-41db-a75f-2f5cf57adc92" + }, + "execution_count": 16, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Programs Concatenation Comparison:\n", + "------------------------------------------------------------\n", + "Program P \tProgram Q \tP concatenated with Q\n", + "------------------------------------------------------------\n", + "Z(0) \t \tZ(0)\n", + "C(1, 2) \t \tC(1, 2)\n", + "S(0) \t \tS(0)\n", + "J(3, 4, 0) \t \tJ(3, 4, 5)\n", + " \tS(0) \tS(0)\n", + " \tJ(3, 4, 0) \tJ(3, 4, 0)\n", + " \tZ(0) \tZ(0)\n", + " \tC(1, 0) \tC(1, 0)\n", + "------------------------------------------------------------\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Moving URM-program in Memory" + ], + "metadata": { + "id": "Kr_yQyZ19BR9" + } + }, + { + "cell_type": "code", + "source": [ + "def move(P: program, off: int=0) -> program:\n", + " \"\"\"\n", + " The function returns the program that operates as P in the registers\n", + " R[off], R[off + 1], ...\n", + "\n", + " Arguments\n", + " P: program\n", + " off: int {off >= 0}\n", + " Returns\n", + " program\n", + " \"\"\"\n", + " if not isinstance(P, program):\n", + " raise ValueError(\"move() error! Invalid program type\")\n", + " if not isinstance(off, int) or off < 0:\n", + " raise ValueError(\"move() error! Invalid offset\")\n", + " # end of checking arguments\n", + " if P.length == 0 or off == 0:\n", + " return P\n", + " moved_instructions = []\n", + " for instruction in P:\n", + " # Handle different op\n", + " if instruction[0] == 0: # Z()\n", + " moved_instructions.append(ins.Z(instruction[1] + off))\n", + " elif instruction[0] == 1: # S()\n", + " moved_instructions.append(ins.S(instruction[1] + off))\n", + " elif instruction[0] == 2: # C()\n", + " moved_instructions.append(ins.C(instruction[1] + off,\n", + " instruction[2] + off))\n", + " else: # J()\n", + " moved_instructions.append(ins.J(instruction[1] + off,\n", + " instruction[2] + off,\n", + " instruction[3]))\n", + " return program(tuple(moved_instructions))" + ], + "metadata": { + "id": "cMTdPqrK9HwV" + }, + "execution_count": 17, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Make the move of an add() program to memory offset by 5\n", + "text_add = \"\"\"\n", + " C(2, 0)\n", + " Z (2)\n", + "\n", + " J(1, 2, 0) check loop condition\n", + " S(0)\n", + " S(2)\n", + " J(0, 0, 3) repeat loop\n", + "\"\"\"\n", + "add = program(compile(text_add))\n", + "offset = 5\n", + "add_moved = move(add, offset)\n", + "\n", + "# Pretty print\n", + "COLUMN_WIDTH = 13\n", + "SEPARATOR = '\\t'\n", + "\n", + "print(\"Original vs Moved Program (offset=5):\")\n", + "print(\"-\" * 60)\n", + "print(f\"{'Original':13}{SEPARATOR}{'Moved':13}{SEPARATOR}\")\n", + "print(\"-\" * 60)\n", + "\n", + "for line in range(add.length):\n", + " print(f\"{str(add[line]):{COLUMN_WIDTH}}\"\n", + " f\"{SEPARATOR}{str(add_moved[line]):{COLUMN_WIDTH}}\")\n", + "\n", + "print(\"-\" * 60)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "zMt9kqJOXpmM", + "outputId": "e2bf7682-444a-4496-8310-f662ffb5b146" + }, + "execution_count": 18, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Original vs Moved Program (offset=5):\n", + "------------------------------------------------------------\n", + "Original \tMoved \t\n", + "------------------------------------------------------------\n", + "C(2, 0) \tC(7, 5) \n", + "Z(2) \tZ(7) \n", + "J(1, 2, 0) \tJ(6, 7, 0) \n", + "S(0) \tS(5) \n", + "S(2) \tS(7) \n", + "J(0, 0, 3) \tJ(5, 5, 3) \n", + "------------------------------------------------------------\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# Check moved program\n", + "args = (2, 6)\n", + "args_padding = tuple([0] * offset) + args\n", + "# Add a C() to tail for copying result\n", + "cp = program(tuple([ins.C(offset, 0)]))\n", + "add_moved_c = concat(add_moved, cp)\n", + "print(f\"{add_moved_c}\")\n", + "ret = run(add_moved_c, *args_padding)\n", + "# Check\n", + "assert args[0] + args[1] == int(ret), \"Error, check the move function\"\n", + "print(f\"\\n{args[0]} + {args[1]} = {ret}\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2QNC084mXrVH", + "outputId": "2ff10097-9fac-428f-b195-8fa8b0d4e842" + }, + "execution_count": 19, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " 1: C(7, 5)\n", + " 2: Z(7)\n", + " 3: J(6, 7, 7)\n", + " 4: S(5)\n", + " 5: S(7)\n", + " 6: J(5, 5, 3)\n", + " 7: C(5, 0)\n", + "\n", + "2 + 6 = 8\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Alternating Execution of Programs" + ], + "metadata": { + "id": "5uiyEjU2oHx2" + } + }, + { + "cell_type": "code", + "source": [ + "def alter(P: program, Q: program) -> program:\n", + " \"\"\"\n", + " The function returns the program implementing the following algorithm:\n", + " 1. provide to execute of P and Q in disjoint memory segments\n", + " 2. do one step of P\n", + " 3. if the execution of P terminates return the corresponding result\n", + " 4. do one step of Q\n", + " 5. if the execution of Q terminates return the corresponding result\n", + " 6. jump to item 2\n", + " Arguments:\n", + " P: program\n", + " Q: program\n", + " Returns\n", + " program\n", + " \"\"\"\n", + " if not isinstance(P, program) or not isinstance(Q, program):\n", + " raise ValueError(\"alter() error! Invalid program type\")\n", + "\n", + " # Step 1: Move Q to a disjoint memory segment\n", + " P_haddr = P.haddr\n", + " offset_Q = P_haddr + 1 # Offset for Q registers\n", + " P_moved = move(P, 0) # P remains at its original position\n", + " Q_moved = move(Q, offset_Q)\n", + "\n", + " # Define result registers\n", + " r_p = 0 # P: result register (after move, remains 0)\n", + " r_q = offset_Q # Q: result register (after move)\n", + "\n", + " # Step 2: Interleave instructions and build line maps\n", + " interleaved_instructions = []\n", + " line_map_P = {}\n", + " line_map_Q = {}\n", + " instr_origin = [] # Keep track of the origin (P or Q) of each instruction\n", + "\n", + " idx = 1\n", + " P_idx = 1\n", + " Q_idx = 1\n", + " P_length = P_moved.length\n", + " Q_length = Q_moved.length\n", + " while P_idx <= P_length or Q_idx <= Q_length:\n", + " if P_idx <= P_length:\n", + " line_map_P[P_idx] = idx\n", + " interleaved_instructions.append(P_moved[P_idx - 1])\n", + " instr_origin.append('P')\n", + " idx += 1\n", + " P_idx += 1\n", + " if Q_idx <= Q_length:\n", + " line_map_Q[Q_idx] = idx\n", + " interleaved_instructions.append(Q_moved[Q_idx - 1])\n", + " instr_origin.append('Q')\n", + " idx += 1\n", + " Q_idx += 1\n", + "\n", + " # Step 3: Add termination code for P and Q\n", + " t_p = idx\n", + " interleaved_instructions.append(ins.C(r_p, 0)) # Copy P result to R0\n", + " instr_origin.append('Termination_P')\n", + " idx += 1\n", + "\n", + " t_q = idx\n", + " interleaved_instructions.append(ins.C(r_q, 1)) # Copy Q result to R1\n", + " instr_origin.append('Termination_Q')\n", + " idx += 1\n", + "\n", + " # Step 4: Adjust jump instructions\n", + " adjusted_instructions = []\n", + " for i, instr in enumerate(interleaved_instructions):\n", + " if instr[0] == 3: # Jumps\n", + " m, n, k = instr[1:]\n", + " origin = instr_origin[i]\n", + " if origin == 'P':\n", + " if k == 0:\n", + " new_k = t_p # Jump to P termination code\n", + " else:\n", + " new_k = line_map_P.get(k, idx) # Default to program end if not found\n", + " elif origin == 'Q':\n", + " if k == 0:\n", + " new_k = t_q # Jump to Q termination code\n", + " else:\n", + " new_k = line_map_Q.get(k, idx)\n", + " else:\n", + " new_k = k # For termination code, k remains the same\n", + " adjusted_instr = ins.J(m, n, new_k)\n", + " adjusted_instructions.append(adjusted_instr)\n", + " else:\n", + " adjusted_instructions.append(instr)\n", + "\n", + " return program(tuple(adjusted_instructions))" + ], + "metadata": { + "id": "GCa3GB5wpQfd" + }, + "execution_count": 21, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# Prepare 2 URM programs\n", + "text_add = \"\"\"\n", + " C(2, 0)\n", + " Z (2)\n", + "\n", + " J(1, 2, 0) check loop condition\n", + " S(0)\n", + " S(2)\n", + " J(0, 0, 3) repeat loop\n", + "\"\"\"\n", + "add = program(compile(text_add))\n", + "print(f\"3 + 4 = {run(add, 3, 4)}\")" + ], + "metadata": { + "id": "wTYlHtLaW0BD", + "outputId": "1425a50d-03c9-4bc3-c619-39c92dfd9153", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "execution_count": 22, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "3 + 4 = 7\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# Predecessor function\n", + "text_pred = \"\"\"\n", + " J(0, 1, 0),\n", + " S(2),\n", + " J(1, 2, 0),\n", + " S(0),\n", + " S(2),\n", + " J(0, 0, 3)\n", + "\"\"\"\n", + "pred = program(compile(text_pred))\n", + "print(f\"5 - 1 = {run(pred, 5)}\")" + ], + "metadata": { + "id": "JztWeQReW2Eb", + "outputId": "718679db-a2d0-46d9-da40-aabeb41d03ac", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "execution_count": 23, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "5 - 1 = 4\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# Alternately merge two functions\n", + "merge = alter(add, pred)\n", + "print(merge)" + ], + "metadata": { + "id": "poXD5cUrW41Y", + "outputId": "f9bfb1de-b60e-4fd3-d82d-cee133b6c7ac", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "execution_count": 24, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " 1: C(2, 0)\n", + " 2: J(3, 4, 14)\n", + " 3: Z(2)\n", + " 4: S(5)\n", + " 5: J(1, 2, 13)\n", + " 6: J(4, 5, 14)\n", + " 7: S(0)\n", + " 8: S(3)\n", + " 9: S(2)\n", + " 10: S(5)\n", + " 11: J(0, 0, 5)\n", + " 12: J(3, 3, 6)\n", + " 13: C(0, 0)\n", + " 14: C(3, 1)\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# Try running this function\n", + "# Build parameters for \"3 + 4\" and \"5 - 1\"\n", + "input_args = (3, 4, 0, 5)\n", + "# Debug mode\n", + "run(merge, *(input_args), verbose=True)" + ], + "metadata": { + "id": "FBABcHZaW6-w", + "outputId": "356c5d7c-604e-4f24-9e97-982b1b5a990a", + "colab": { + "base_uri": "https://localhost:8080/" + } + }, + "execution_count": 27, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[4, 3, 4, 0, 5] C(2, 0)\n", + "[4, 3, 4, 0, 5] J(3, 4, 14)\n", + "[4, 3, 0, 0, 5] Z(2)\n", + "[4, 3, 0, 0, 5, 1] S(5)\n", + "[4, 3, 0, 0, 5, 1] J(1, 2, 13)\n", + "[4, 3, 0, 0, 5, 1] J(4, 5, 14)\n", + "[5, 3, 0, 0, 5, 1] S(0)\n", + "[5, 3, 0, 1, 5, 1] S(3)\n", + "[5, 3, 1, 1, 5, 1] S(2)\n", + "[5, 3, 1, 1, 5, 2] S(5)\n", + "[5, 3, 1, 1, 5, 2] J(0, 0, 5)\n", + "[5, 3, 1, 1, 5, 2] J(1, 2, 13)\n", + "[5, 3, 1, 1, 5, 2] J(4, 5, 14)\n", + "[6, 3, 1, 1, 5, 2] S(0)\n", + "[6, 3, 1, 2, 5, 2] S(3)\n", + "[6, 3, 2, 2, 5, 2] S(2)\n", + "[6, 3, 2, 2, 5, 3] S(5)\n", + "[6, 3, 2, 2, 5, 3] J(0, 0, 5)\n", + "[6, 3, 2, 2, 5, 3] J(1, 2, 13)\n", + "[6, 3, 2, 2, 5, 3] J(4, 5, 14)\n", + "[7, 3, 2, 2, 5, 3] S(0)\n", + "[7, 3, 2, 3, 5, 3] S(3)\n", + "[7, 3, 3, 3, 5, 3] S(2)\n", + "[7, 3, 3, 3, 5, 4] S(5)\n", + "[7, 3, 3, 3, 5, 4] J(0, 0, 5)\n", + "[7, 3, 3, 3, 5, 4] J(1, 2, 13)\n", + "[7, 3, 3, 3, 5, 4] C(0, 0)\n", + "[7, 3, 3, 3, 5, 4] C(3, 1)\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "7" + ] + }, + "metadata": {}, + "execution_count": 27 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "**Error**: The merged program does not meet expectations. From observing the debug information, memory[0] being 7 is as expected, but memory[3] is 3, which does not match the expected value of 4. This seems to be caused by an issue where either program P or Q terminates the entire program once it finishes executing." + ], + "metadata": { + "id": "2m9OpQnFXJ5V" + } } - ], - "source": [ - "# Try running this function\n", - "# Build parameters for \"3 + 4\" and \"5 - 1\"\n", - "input_args = (3, 4, 0, 5)\n", - "# Debug mode\n", - "run(merge, *(input_args), verbose=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Error: The merged program does not meet expectations. From observing the debug information, memory[0] being 7 is as expected, but memory[3] is 3, which does not match the expected value of 4. This seems to be caused by an issue where either program P or Q terminates the entire program once it finishes executing." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "colab": { - "include_colab_link": true, - "provenance": [], - "toc_visible": true - }, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.0" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} + ] +} \ No newline at end of file