Entwerfen Sie einen Computer mit einem Befehlssatz!

31

Hinweis: Ich bin bereit, für jede Antwort, die ich interessant finde, ein Kopfgeld zu zahlen.

Ihre Herausforderung besteht darin, einen Turing- Complete - One-Instruction-Set-Computer (OISC) zu entwerfen:

Ein OISC ist eine abstrakte Maschine, die nur einen Befehl verwendet - die Notwendigkeit eines maschinensprachlichen Opcodes entfällt. Mit einer vernünftigen Wahl für den einzelnen Befehl und mit unendlichen Ressourcen ist ein OISC in der Lage, ein universeller Computer zu sein, genauso wie herkömmliche Computer mit mehreren Befehlen.

Hier sind einige Beispiele für einzelne Befehle, die einen Turing-vollständigen OISC ausmachen.

Regeln:

Sie müssen eine Interpretation oder einen Beweis dafür vorlegen

Sie müssen einen Dolmetscher für Ihre Sprache bereitstellen. Dieser Interpreter sollte nur durch den Speicher / die Zeit eingeschränkt werden (z. B. darf er keine vom Benutzer auferlegten Einschränkungen aufweisen). Wenn Sie keinen Dolmetscher für Ihre Sprache zur Verfügung stellen (aus irgendeinem anderen Grund als Faulheit), müssen Sie nachweisen, dass es möglich ist, einen zu schreiben. Ein Dolmetscher muss möglich sein .

Sie müssen seine Turing-Vollständigkeit nachweisen

Sie müssen einen formellen Nachweis beifügen, dass Ihre Sprache Turing-vollständig ist. Eine einfache Möglichkeit, dies zu tun, besteht darin, nachzuweisen, dass es eine andere Sprache von Turing-complete interpretieren kann oder dasselbe Verhalten hat. Die grundlegendste zu interpretierende Sprache wäre Brainf ** k .

Eine normale Sprache mit denselben Befehlen wie Brainf ** k (und denselben vom Benutzer auferlegten Speicherbeschränkungen) ist beispielsweise Turing-complete, da alles, was in Brainf ** k implementiert werden kann, in der Sprache implementiert werden kann .

Hier ist eine Liste von sehr einfach zu implementierenden Turing-vollständigen Sprachen.

Zusätzliche OISC-Anforderungen

  • Diese OISC sollte nur eine Anweisung enthalten - sie kann nicht mehrere Anweisungen enthalten, von denen eine die Turing-Vervollständigung bewirkt.

  • Ihr OISC kann eine beliebige Syntax verwenden. Sie sollten in Ihrer Antwort definieren, was Anweisung ist, was Daten sind und was ein No-Op ist (z. B. Leerzeichen). Seien Sie kreativ!

  • Argumente müssen nicht nur ganze Zahlen sein. Zum Beispiel ist /// ein schönes Beispiel für ein Turing-vollständiges OISC.

  • Wie und ob Input und Output genommen und gegeben werden, bleibt Ihnen überlassen. Die meisten OISCs implementieren E / A über bestimmte Speicherorte. Möglicherweise gibt es jedoch auch andere Möglichkeiten, und Sie werden aufgefordert, eine zu finden.

  • Eine gültige Antwort muss einen Beispielcode in Ihrem OISC enthalten, entweder durch Einfügen in den Post oder durch Verknüpfen mit einer einfachen, in der Sprache gelösten Herausforderung.

Wählen

Wähler, bitte denken Sie daran, langweilige Einsendungen nicht zu unterstützen. Beispiele:

  • lenguage -Äquivalente
  • Eine Implementierung eines bestehenden OISC (Beantworter, bitte erstellen Sie Ihre eigenen!)
  • Ein "OISC", in dem das erste Argument einen aufzurufenden Befehl angibt ( Beispiel )

Sie sollten jedoch interessante, kreative Beiträge unterstützen, wie z. B .:

  • Ein OISC basierend auf einer mathematischen Gleichung
  • Ein Turing-vollständiges ZISC basierend auf einem neuronalen Netzwerk
  • Ein OISC, bei dem die Ausgabe-E / A auf andere Weise als an bestimmten Speicherorten erfolgt

Gewinnen

Wie beim gewinnt die Antwort mit den meisten Stimmen! Viel Glück!

MD XF
quelle
10
Was ist eine "Anweisung"? Und wie zählen wir sie?
Weizen-Assistent
1
@NoOneIsHere Ich wünschte, ich wüsste genug, nur um xD zu stimmen
Brian H.
2
Ich habe das abgelehnt. Ich halte das für eine sehr interessante Idee, aber Sie erklären nicht genau, was ein OISC ist und wie man bestätigt, dass es sich bei etwas um etwas handelt. Ich habe BF zu einem OISC gemacht, aber das ist eindeutig gegen den Geist der Frage, aber technisch gültig.
NoOneIsHere
1
@MDXF Ich glaube nicht, dass du /// bekommst: Es hat einen Ersetzungsbefehl und es hat Druckbefehle, was nicht nur eine Nebenwirkung des Ersetzungsbefehls ist
Destructible Lemon
1
@NoOneIsHere Weil Beliebtheitswettbewerb . Ja, es ist gültig, aber es hat eine schlechte Punktzahl (Stimmenzahl), so dass es nicht gewinnen wird.
User202729

Antworten:

20

XOISC

Diese OISC basiert auf Fokkers X-Combinator, der wie folgt definiert ist:

X=λf .f (λg h x .g x (h x)) (λa b c .a)

Wenn wir die Tatsache anerkennen, dass der SKI-Kalkül Turing vollständig ist, ist der obige Kombinator auch Turing vollständig. Das ist weilX , K und ich in Bezug auf X geschrieben werden können:SKIX

S=X (X X)K=X XI=S K K=X (X X) (X X) (X X)

So funktioniert XOISC

Intern hat XOISC einen (anfangs leeren) Stack, von dem aus die Anweisung, die als Argument verwendet, Folgendes bewirkt:n

  • Pop Elemente (Funktionen f 1f N ) aus dem Stapel, drücken Sie f 1 ( f 2 ( ( f N X ) ) )nf1fNf1 (f2 ((fN X)))

Sobald keine weiteren Anweisungen mehr vorhanden sind, überträgt XOISC alle Befehlszeilenargumente (falls vorhanden) an den Stack. Beispiel:

[s1,, sMstack before, a1,, aNarguments]

Die endgültige Berechnung lautet .((((s1 s2)) sM) a1))aN


Da der eine Befehl in XOISC nur ein Argument enthält (Speicheroffset), gibt es keinen Grund, einen Namen für diesen Befehl zu verwenden. Eine gültige Quelldatei besteht also ausschließlich aus Ganzzahlen, die durch Zeilenumbrüche oder Leerzeichen voneinander getrennt sind. Beispiel:

0 0 2 0 1 0 1

Probieren Sie es online!

Beispiel

Nehmen wir das obige Beispiel (Stapel wächst nach rechts):

0pop 0 und bewerbe dich (dh push single X):[X]0nochmal einfach drücken X:[X, X]2Pop 2 (ein,b) und drücken Sie ein (b X):[X (X X)]0einfach drücken X:[X (X X), X]1Pop 1 (ein) und drücken Sie ein X:[X (X X), X X]0einfach drücken X:[X (X X), X X, X]1Pop 1 (ein) und drücken Sie ein X:[X (X X), X X, X X]

((X (X X)) (X X)) (X X)X (X X) (X X) (X X)S K K

Vollständigkeit prüfen

Beweisidee

X

X

((X (X X)) (X X)) (X X)

  • bekommen X0
  • als nächstes befinden wir uns in einer neuen Ebene von Klammern, daher brauchen wir wieder nur eine 0
  • Jetzt schließen sich zwei Klammern und wir müssen 2 Elemente einfügen: 2
  • wieder sind wir in einer neuen Ebene von Klammern, also brauchen wir a 0
  • zwei Klammern, also wieder schließen a 2
  • und das selbe nochmal

Wir haben also ein anderes (aber semantisch äquivalentes) XOISC-Programm:

0 0 2 0 2 0 2 Probieren Sie es online!

Wenn wir bei dieser Strategie bleiben, können wir jeden Ausdruck, der aus leicht transformierenX Kombinatoren besteht, in ein XOISC-Programm umwandeln, das nur eine einzige Funktion auf dem Stapel belässt.

Formeller Beweis

Da der SKI-Kalkül vollständig ist, müssen wir zwei Dinge zeigen:

  1. X Kombinator ist eine Basis für die SKI-Rechnung
  2. XOISC kann jeden mit dem gebildeten Ausdruck darstellenX

Der erste Teil, in dem die drei Gleichheiten in der Einleitung bewiesen werden, ist sehr langwierig und platzraubend und auch nicht sehr interessant. Anstatt es in diesen Beitrag zu schreiben, finden Sie es hier * .

Der zweite Teil kann durch strukturelle Induktion bewiesen werden , obwohl es einfacher ist, eine etwas stärkere Aussage zu beweisen: Nämlich für jeden von gebildeten AusdruckX Kombinatoren gibt es nämlich ein Programm, das diesen Ausdruck als einen einzelnen Ausdruck auf dem Stapel belässt:

XXf GfG :

0XF1FNG1GKfGf G :

F1FN G1GK-1 (GK+1)fGGff G

Dolmetscher

Eingänge

Da die nicht typisierte Lambda-Rechnung es erfordert, dass wir für alles, was wir wollen, unsere eigenen Datentypen definieren. Dies ist umständlich, da der Dolmetscher die Zahlen der Kirche kennt - das heißt , wenn Sie liefern Eingänge es Nummern automatisch in ihren entsprechenden Kirche Zeichen verwandeln.

Als Beispiel sehen Sie hier ein Programm, das zwei Zahlen multipliziert: Probieren Sie es online aus!

Sie können auch Funktionen als Argumente bereitstellen, indem Sie De Bruijn-Indizes verwenden , z. B. den SKombinator \\\(3 1 (2 1))(oder λλλ(3 1 (2 1))). Allerdings erkennt er auch die S, K, Iund natürlichX combinator.

Ausgabe

Standardmäßig prüft der Interpreter, ob die Ausgabe eine Ganzzahl codiert. Wenn dies der Fall ist, wird die entsprechende Zahl (zusätzlich zum Ergebnis) ausgegeben. Für die Bequemlichkeit gibt es die-b Flag, mit dem der Interpreter versucht, einen Booleschen Wert zu finden (siehe letztes Beispiel).

Assembler

Natürlich benötigt jede Sprache auf niedriger Ebene einen Assembler, der eine Sprache auf hoher Ebene in diese konvertiert. Sie können einfach eine beliebige Eingabe (siehe oben) verwenden und sie mithilfe des -aFlags in ein XOISC-Programm übersetzen. Probieren Sie es online aus! **


* Falls der Link nicht funktioniert, finden Sie in diesem Beitrag eine Kopie als HTML-Kommentar.

** Dies führt zu einem Programm, das auf Ursprünglichkeit prüft. Probieren Sie es online aus!

ბიმო
quelle
1
Gibt es einen Grund, warum Sie den X-Kombinator anstelle des Iota-Kombinators ausgewählt haben?
Esolanging Fruit
1
@EsolangingFruit: Ja, es gibt noch einige andere Optionen. Letztendlich habe ich mich für diese Option entschieden, weil sie die wenigsten Anwendungen zum Erstellen von SK verwendet. Es schien, als würde es die beste Leistung bringen (obwohl ich selbst keinen Vergleich angestellt habe).
ბიმო
1
Btw. Wenn Sie interessiert sind, finden Sie im verlinkten Artikel einen schönen Vergleich mehrerer Kombinatoren.
ბიმო
19

Zeichnen

Draw ist ein OISC, der auf ein 2D-Gitter einwirkt und Quadrate ähnlich wie die Wang B-Maschine markiert. Um die Sprache so einfach und OISC-y wie möglich zu halten, markieren alle Anweisungen (von denen es insgesamt eine gibt) das gerade betretene Quadrat und treten, um anhalten zu können, auf ein markiertes Quadrat Beendet das Programm.

Das Programm besteht aus einer Folge von Zeilen, die einen Zeilenbezeichner (beliebige Zeichenfolge ohne # oder Leerzeichen), zwei Ganzzahlen ( xund y) und zwei weitere Zeilenbezeichner ( aund) enthältb ) enthält.

Das Programm läuft wie folgt ab:
Beginnend mit der Linie, die als startmit dem Zeiger gekennzeichnet ist, der auf Position (0, 0) zeigt, bewegen Sie den Zeiger um den Betrag, der durch xund angegeben ist, yund markieren Sie das Quadrat, auf dem sich der Zeiger jetzt befindet (es sei denn, das Quadrat ist bereits markiert). In diesem Fall wird die Ausführung abgebrochen. Springen Sie dann zur Linie, awenn mindestens eines der direkt benachbarten Quadrate ebenfalls markiert ist, und zur Linie , wenn dies nicht der Fall ist b.

Dolmetscher werden aufgefordert, das Endergebnis des Rasters als eine Art Bild, Leinwand usw. auszugeben.

Turing-Vollständigkeit

Draw ist Turing-complete, da es möglich ist, eine modifizierte Version (Alternate) einer Minsky-Maschine in die Sprache zu kompilieren.

Alternate verhält sich ähnlich wie ein Minsky-Computer mit zwei Zählern, die Befehle unterliegen jedoch einer großen Einschränkung: Die Befehle müssen abwechselnd auf den ersten und den zweiten Zähler abzielen. Um diese Änderung zu umgehen, wurde ein zusätzlicher Befehl hinzugefügt:nop . Dieser Befehl ändert den Zielzähler überhaupt nicht, wodurch es möglich ist, aufeinanderfolgende Änderungen an einem Zähler "aufzufüllen", wodurch die oben beschriebene Einschränkung erfüllt wird. Dies bedeutet auch, dass das zu modifizierende Register nicht angegeben werden muss und für einen gegebenen Befehl direkt aus den Befehlen abgeleitet werden kann, aus denen die Ausführung darauf springen kann.

Beispiel: Diese Minsky-Maschine

1 inc A 2
2 inc A 3
3 dec A 3 4
4 halt

wird zu diesem alternativen Programm:

1 inc 2
2 nop 3
3 inc 4
4 nop 5
5 dec 6 8
6 nop 5
7 halt
8 halt

Diese Einschränkung ist aufgrund der Art und Weise notwendig, in der das eventuelle Draw-Programm Register verarbeitet, dh, es wird überhaupt nicht zwischen diesen unterschieden. Stattdessen kopiert das Zeichenprogramm einfach das Register, das durch den vorhergehenden Befehl nicht geändert wurde, und ändert es entsprechend dem ausgeführten Befehl.

Anschließend wird das Alternativprogramm wie folgt direkt in Draw übersetzt:

Das Programm startet mit diesem Satz.

start 0 0 a a
a 3 0 b b
b -3 1 c c
c 3 0 d d
d -3 2 e e
e 3 0 f f
f 3 -3 i1_a i1_a

inc, decUnd nopsind in fast der gleichen Weise wie jede andere übersetzt. In allen Fällen besteht kein Unterschied zwischen dem Ändern des ersten oder des zweiten Registers (wie oben erläutert). Hier ist ein Inkrement, das äquivalent ist zu inc 2:

i1_y 0 -2 i1_z i1_y
i1_z 3 -1 i1_a i1_a
i1_a -5 1 i1_b i1_b
i1_b 0 2 i1_c i1_c
i1_c 0 2 i1_d i1_e
i1_d 0 2 i1_d i1_f

i1_e 5 0 i2_z i2_y
i1_f 5 0 i2_z i2_y

Ändern Sie die Nummern in den i1_xTeilen in den Index der aktuellen Anweisung und in deni2_x Teilen in den Index der nächsten auszuführenden Anweisung.

Die nopAnweisung kann folgendermaßen übersetzt werden:

i1_y 0 -2 i1_z i1_y
i1_z 3 -1 i1_a i1_a
i1_a -5 1 i1_b i1_b
i1_b 0 2 i1_c i1_c
i1_c 0 2 i1_d i1_e
i1_d 0 2 i1_d i1_f

i1_e 5 -2 i2_z i2_y
i1_f 5 -2 i2_z i2_y

Dies ist eine Dekrementierung:

i1_y 0 -2 i1_z i1_y
i1_z 3 -1 i1_a i1_a
i1_a -5 1 i1_b i1_b
i1_b 0 2 i1_c i1_c
i1_c 0 2 i1_d i1_e
i1_d 0 2 i1_d i1_f

i1_e 5 -2 i3_z i3_y
i1_f 5 -4 i2_z i2_y

i3_x verweist auf die Anweisung, die aufgerufen werden soll, wenn der Zähler bereits 1 ist.

Halt:

i1_y 0 0 0 0
i1_z 0 0 0 0

Ändern Sie die Beschriftungen entsprechend und verketten Sie einfach alles. Wenn Sie dies für das Beispiel von oben tun, wird das Draw-Programm im Repository von oben angezeigt.

Dolmetscher

Derzeit gibt es zwei Dolmetscher, die beide in Python geschrieben sind. Sie befinden sich im GitHub-Repository von Draw .

  1. draw.py : Dieser Interpreter ist für die Kommandozeile gedacht und verwendet die Programmquelle als Argument. Nach jedem Schritt wird der ausgeführte Befehl und die Position des Befehlszeigers ausgegeben. Nach dem Anhalten des Programms wird die Anzahl der markierten Zellen gedruckt.
  2. draw_golly.py : Diese Version verwendet Golly für genau den falschen Zweck. Einfachere grafische Ausgabe, wobei die Quelle beim Starten des Skripts über ein Popup- Fenster abgerufen wird . Golly kann mit Python etwas heikel sein, stellen Sie also sicher, dass Sie Python 2 installiert haben (und mischen Sie nicht 32-Bit-Golly mit 64-Bit-Python oder umgekehrt). Die Ausgabe erfolgt über das in Golly integrierte Zellenraster.

Das folgende Bild ist ein Beispiel für die Ausgabe des zweiten Interpreters. Wenn Sie das Beispielprogramm im Repository ausführen, erhalten Sie Folgendes (oder Ähnliches):

ivzem
quelle
1
Tolle! Herzlichen Glückwunsch zu einem einzigartigen Weg, die Herausforderung zu meistern.
MD XF
Ihre Sprache muss nicht stehen bleiben, um vollständig zu sein. Regel 110 endet nicht, ist aber dennoch vollständig.
Akangka
+1 für Golly, den besten Simulator für zellulare Automaten aller Zeiten.
Hochradioaktiv
14

-3

Hier ist das Wesentliche.

Erinnerung

Der Speicher ist eine Karte von Bändern, in der die Schlüssel Zeichenfolgen und die Werte Ganzzahlen beliebiger Größe sind.

Zusätzlich gibt es eine Reihe von Bezeichnungen, zu denen das Programm springen kann.

Es gibt einen Stapel, der die Operanden enthält, die Strings sind.

Es gibt einen Test, der steuert, auf welche Bänder im Speicher zugegriffen werden kann.

Die eine Anweisung

-. Zunächst wird eine Zeichenfolge LABELvom Stapel entfernt. Wenn dies LABELnicht als Etikett definiert ist, definiert es das Etikett und löscht die Quelle dieses Etiketts (dh woher es stammt) und die aktuelle Anweisung. Andernfalls führt er die folgende Berechnung, die beiden oberen Werte verwenden, Aund B:

if mem[A] < mem[B]:
    jump to LABEL
if mem[A] != mem[B]:
    mem[A]--
else:
    mem[B]++

Beachten Sie, dass das Programm einen Fehler ausführt und den Status des Programms anzeigt, wenn es überzählige oder unzureichende Argumente gibt.

Der Offset kann geändert werden, indem auf den Wert von zugegriffen wird ..

Beispielcode

X-

i i X-
i i X-
i i X-
i i X-
i i X-
i i X-
i i X-

Dies setzt die Variable iauf 7, indem die 7Zeiten erhöht werden .

X-

i i X-
i i X-
i i X-
LOOP-
    a a X-
    a a X-
    j i LOOP-

Dies multipliziert sich i+1mit der Konstanten 2.

Nachweis der Vollständigkeit

Ungeachtet der Int-Größen von C ++ (vorausgesetzt, sie sind unendlich) ist -3 Turing Complete durch Reduktion auf 3-Zellen-Brainfuck . Ich kann diese Größe ignorieren, da auf einem Computer mit unendlichem Speicher, der beliebig große Zellen hat, ein Interpreter für -3 geschrieben werden kann.

Ich glaube auch, dass jedes BCT als -3-Programm geschrieben werden kann.

Conor O'Brien
quelle
Da ich meinen Inhalt gerne verbessere, wäre eine Erklärung bezüglich der Abwahl dankbar
Conor O'Brien,