2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -5,10 +5,12 @@ Indeed one way to definitively prove that a language
|
|||
is [[wp:Turing_completeness|turing-complete]]
|
||||
is to implement a universal Turing machine in it.
|
||||
|
||||
'''The task'''
|
||||
|
||||
For this task you would simulate such a machine capable
|
||||
;Task:
|
||||
|
||||
Simulate such a machine capable
|
||||
of taking the definition of any other Turing machine and executing it.
|
||||
|
||||
Of course, you will not have an infinite tape,
|
||||
but you should emulate this as much as is possible.
|
||||
|
||||
|
|
@ -18,6 +20,7 @@ To test your universal Turing machine (and prove your programming language
|
|||
is Turing complete!), you should execute the following two Turing machines
|
||||
based on the following definitions.
|
||||
|
||||
|
||||
'''Simple incrementer'''
|
||||
* '''States:''' q0, qf
|
||||
* '''Initial state:''' q0
|
||||
|
|
@ -28,8 +31,10 @@ based on the following definitions.
|
|||
** (q0, 1, 1, right, q0)
|
||||
** (q0, B, 1, stay, qf)
|
||||
|
||||
<br>
|
||||
The input for this machine should be a tape of <code>1 1 1</code>
|
||||
|
||||
|
||||
'''Three-state busy beaver'''
|
||||
* '''States:''' a, b, c, halt
|
||||
* '''Initial state:''' a
|
||||
|
|
@ -44,8 +49,10 @@ The input for this machine should be a tape of <code>1 1 1</code>
|
|||
** (c, 0, 1, left, b)
|
||||
** (c, 1, 1, stay, halt)
|
||||
|
||||
<br>
|
||||
The input for this machine should be an empty tape.
|
||||
|
||||
|
||||
'''Bonus:'''
|
||||
|
||||
'''5-state, 2-symbol probable Busy Beaver machine from Wikipedia'''
|
||||
|
|
@ -66,6 +73,8 @@ The input for this machine should be an empty tape.
|
|||
** (E, 0, 1, stay, H)
|
||||
** (E, 1, 0, left, A)
|
||||
|
||||
<br>
|
||||
The input for this machine should be an empty tape.
|
||||
|
||||
This machine runs for more than 47 millions steps.
|
||||
<br><br>
|
||||
|
|
|
|||
231
Task/Universal-Turing-machine/C/universal-turing-machine.c
Normal file
231
Task/Universal-Turing-machine/C/universal-turing-machine.c
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
enum {
|
||||
LEFT,
|
||||
RIGHT,
|
||||
STAY
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int state1;
|
||||
int symbol1;
|
||||
int symbol2;
|
||||
int dir;
|
||||
int state2;
|
||||
} transition_t;
|
||||
|
||||
typedef struct tape_t tape_t;
|
||||
struct tape_t {
|
||||
int symbol;
|
||||
tape_t *left;
|
||||
tape_t *right;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int states_len;
|
||||
char **states;
|
||||
int final_states_len;
|
||||
int *final_states;
|
||||
int symbols_len;
|
||||
char *symbols;
|
||||
int blank;
|
||||
int state;
|
||||
int tape_len;
|
||||
tape_t *tape;
|
||||
int transitions_len;
|
||||
transition_t ***transitions;
|
||||
} turing_t;
|
||||
|
||||
int state_index (turing_t *t, char *state) {
|
||||
int i;
|
||||
for (i = 0; i < t->states_len; i++) {
|
||||
if (!strcmp(t->states[i], state)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int symbol_index (turing_t *t, char symbol) {
|
||||
int i;
|
||||
for (i = 0; i < t->symbols_len; i++) {
|
||||
if (t->symbols[i] == symbol) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void move (turing_t *t, int dir) {
|
||||
tape_t *orig = t->tape;
|
||||
if (dir == RIGHT) {
|
||||
if (orig && orig->right) {
|
||||
t->tape = orig->right;
|
||||
}
|
||||
else {
|
||||
t->tape = calloc(1, sizeof (tape_t));
|
||||
t->tape->symbol = t->blank;
|
||||
if (orig) {
|
||||
t->tape->left = orig;
|
||||
orig->right = t->tape;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dir == LEFT) {
|
||||
if (orig && orig->left) {
|
||||
t->tape = orig->left;
|
||||
}
|
||||
else {
|
||||
t->tape = calloc(1, sizeof (tape_t));
|
||||
t->tape->symbol = t->blank;
|
||||
if (orig) {
|
||||
t->tape->right = orig;
|
||||
orig->left = t->tape;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
turing_t *create (int states_len, ...) {
|
||||
va_list args;
|
||||
va_start(args, states_len);
|
||||
turing_t *t = malloc(sizeof (turing_t));
|
||||
t->states_len = states_len;
|
||||
t->states = malloc(states_len * sizeof (char *));
|
||||
int i;
|
||||
for (i = 0; i < states_len; i++) {
|
||||
t->states[i] = va_arg(args, char *);
|
||||
}
|
||||
t->final_states_len = va_arg(args, int);
|
||||
t->final_states = malloc(t->final_states_len * sizeof (int));
|
||||
for (i = 0; i < t->final_states_len; i++) {
|
||||
t->final_states[i] = state_index(t, va_arg(args, char *));
|
||||
}
|
||||
t->symbols_len = va_arg(args, int);
|
||||
t->symbols = malloc(t->symbols_len);
|
||||
for (i = 0; i < t->symbols_len; i++) {
|
||||
t->symbols[i] = va_arg(args, int);
|
||||
}
|
||||
t->blank = symbol_index(t, va_arg(args, int));
|
||||
t->state = state_index(t, va_arg(args, char *));
|
||||
t->tape_len = va_arg(args, int);
|
||||
t->tape = NULL;
|
||||
for (i = 0; i < t->tape_len; i++) {
|
||||
move(t, RIGHT);
|
||||
t->tape->symbol = symbol_index(t, va_arg(args, int));
|
||||
}
|
||||
if (!t->tape_len) {
|
||||
move(t, RIGHT);
|
||||
}
|
||||
while (t->tape->left) {
|
||||
t->tape = t->tape->left;
|
||||
}
|
||||
t->transitions_len = va_arg(args, int);
|
||||
t->transitions = malloc(t->states_len * sizeof (transition_t **));
|
||||
for (i = 0; i < t->states_len; i++) {
|
||||
t->transitions[i] = malloc(t->symbols_len * sizeof (transition_t *));
|
||||
}
|
||||
for (i = 0; i < t->transitions_len; i++) {
|
||||
transition_t *tran = malloc(sizeof (transition_t));
|
||||
tran->state1 = state_index(t, va_arg(args, char *));
|
||||
tran->symbol1 = symbol_index(t, va_arg(args, int));
|
||||
tran->symbol2 = symbol_index(t, va_arg(args, int));
|
||||
tran->dir = va_arg(args, int);
|
||||
tran->state2 = state_index(t, va_arg(args, char *));
|
||||
t->transitions[tran->state1][tran->symbol1] = tran;
|
||||
}
|
||||
va_end(args);
|
||||
return t;
|
||||
}
|
||||
|
||||
void print_state (turing_t *t) {
|
||||
printf("%-10s ", t->states[t->state]);
|
||||
tape_t *tape = t->tape;
|
||||
while (tape->left) {
|
||||
tape = tape->left;
|
||||
}
|
||||
while (tape) {
|
||||
if (tape == t->tape) {
|
||||
printf("[%c]", t->symbols[tape->symbol]);
|
||||
}
|
||||
else {
|
||||
printf(" %c ", t->symbols[tape->symbol]);
|
||||
}
|
||||
tape = tape->right;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void run (turing_t *t) {
|
||||
int i;
|
||||
while (1) {
|
||||
print_state(t);
|
||||
for (i = 0; i < t->final_states_len; i++) {
|
||||
if (t->final_states[i] == t->state) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
transition_t *tran = t->transitions[t->state][t->tape->symbol];
|
||||
t->tape->symbol = tran->symbol2;
|
||||
move(t, tran->dir);
|
||||
t->state = tran->state2;
|
||||
}
|
||||
}
|
||||
|
||||
int main () {
|
||||
printf("Simple incrementer\n");
|
||||
turing_t *t = create(
|
||||
/* states */ 2, "q0", "qf",
|
||||
/* final_states */ 1, "qf",
|
||||
/* symbols */ 2, 'B', '1',
|
||||
/* blank */ 'B',
|
||||
/* initial_state */ "q0",
|
||||
/* initial_tape */ 3, '1', '1', '1',
|
||||
/* transitions */ 2,
|
||||
"q0", '1', '1', RIGHT, "q0",
|
||||
"q0", 'B', '1', STAY, "qf"
|
||||
);
|
||||
run(t);
|
||||
printf("\nThree-state busy beaver\n");
|
||||
t = create(
|
||||
/* states */ 4, "a", "b", "c", "halt",
|
||||
/* final_states */ 1, "halt",
|
||||
/* symbols */ 2, '0', '1',
|
||||
/* blank */ '0',
|
||||
/* initial_state */ "a",
|
||||
/* initial_tape */ 0,
|
||||
/* transitions */ 6,
|
||||
"a", '0', '1', RIGHT, "b",
|
||||
"a", '1', '1', LEFT, "c",
|
||||
"b", '0', '1', LEFT, "a",
|
||||
"b", '1', '1', RIGHT, "b",
|
||||
"c", '0', '1', LEFT, "b",
|
||||
"c", '1', '1', STAY, "halt"
|
||||
);
|
||||
run(t);
|
||||
return 0;
|
||||
printf("\nFive-state two-symbol probable busy beaver\n");
|
||||
t = create(
|
||||
/* states */ 6, "A", "B", "C", "D", "E", "H",
|
||||
/* final_states */ 1, "H",
|
||||
/* symbols */ 2, '0', '1',
|
||||
/* blank */ '0',
|
||||
/* initial_state */ "A",
|
||||
/* initial_tape */ 0,
|
||||
/* transitions */ 10,
|
||||
"A", '0', '1', RIGHT, "B",
|
||||
"A", '1', '1', LEFT, "C",
|
||||
"B", '0', '1', RIGHT, "C",
|
||||
"B", '1', '1', RIGHT, "B",
|
||||
"C", '0', '1', RIGHT, "D",
|
||||
"C", '1', '0', LEFT, "E",
|
||||
"D", '0', '1', LEFT, "A",
|
||||
"D", '1', '1', LEFT, "D",
|
||||
"E", '0', '1', STAY, "H",
|
||||
"E", '1', '0', LEFT, "A"
|
||||
);
|
||||
run(t);
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
200 I = STATE*NSYMBOL - ICHAR(TAPE(HEAD)) !Index the transition.
|
||||
TAPE(HEAD) = MARK(I) !Do it. Possibly not changing the symbol.
|
||||
HEAD = HEAD + MOVE(I) !Possibly not moving the head.
|
||||
STATE = ICHAR(NEXT(I)) !Hopefully, something has changed!
|
||||
IF (STATE.GT.0) GO TO 200 !Otherwise, we might loop forever...
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
PROGRAM U !Reads a specification of a Turing machine, and executes it.
|
||||
Careful! Reserves a symbol #0 to represent blank tape as a blank.
|
||||
INTEGER MANY,FIRST,LAST !Some sizes must be decided upon.
|
||||
PARAMETER (MANY = 66, FIRST = 1, LAST = 666) !These should do.
|
||||
INTEGER HERE(MANY)
|
||||
CHARACTER*1 MARK(MANY) !The transition table.
|
||||
INTEGER*1 MOVE(MANY) !Three related arrays.
|
||||
CHARACTER*1 NEXT(MANY) !All with the same indexing.
|
||||
CHARACTER*1 TAPE(FIRST:LAST)!Notionally, no final bound, in both directions - a potential infinity..
|
||||
INTEGER STATE !Execution starts with state 1.
|
||||
INTEGER HEAD !And the tape read/write head at position 1.
|
||||
INTEGER STEP !And we might as well keep count.
|
||||
INTEGER OFFSET !An affine shift.
|
||||
INTEGER NSTATE !Counts can be helpful.
|
||||
INTEGER NSYMBOL !The count of recognised symbols.
|
||||
INTEGER S,S1 !Symbol numbers.
|
||||
CHARACTER*1 RS,WS !Input scanning: read symbol, write symbol.
|
||||
CHARACTER*1 SYMBOL(0:MANY) !I reserve SYMBOL(0).
|
||||
CHARACTER*(MANY) SYMBOLS !Up to 255, for single character variables.
|
||||
EQUIVALENCE (SYMBOL(1),SYMBOLS) !Individually or collectively.
|
||||
INTEGER I,J,K,L,IT !Assistants.
|
||||
INTEGER LONG !Now for some text scanning.
|
||||
PARAMETER (LONG = 80) !This should suffice.
|
||||
CHARACTER*(LONG) ALINE !A scratchpad.
|
||||
REAL T0,T1 !Some CPU time attempts.
|
||||
INTEGER KBD,MSG,INF !Some I/O unit numbers.
|
||||
|
||||
KBD = 5 !Standard input.
|
||||
MSG = 6 !Standard output
|
||||
INF = 10 !Suitable for a disc file.
|
||||
OPEN (INF,FILE = "TestAdd1.dat",ACTION="READ") !Go for one.
|
||||
READ (INF,1) ALINE !The first line is to be a heding.
|
||||
1 FORMAT (A) !Just plain text.
|
||||
WRITE (MSG,2) ALINE !Reveal it.
|
||||
2 FORMAT ("Turing machine simulation for... ",A) !Announce the plan.
|
||||
READ (INF,*) SYMBOLS !Allows a quoted string.
|
||||
NSYMBOL = LEN_TRIM(SYMBOLS) !How many symbols? (Trailing spaces will be lost)
|
||||
WRITE (MSG,3) NSYMBOL,SYMBOLS(1:NSYMBOL) !They will be symbol number 0, 1, ..., NSYMBOL - 1.
|
||||
3 FORMAT (I0," symbols: >",A,"<") !And this is their count.
|
||||
IF (NSYMBOL.LE.1) STOP "Expect at least two symbols!"
|
||||
SYMBOL(0) = " " !My special state meaning "never before seen".
|
||||
NSYMBOL = NSYMBOL + 1 !So, one more is in actual use.
|
||||
NSTATE = 0 !As for states, I haven't seen any.
|
||||
MOVE = -66 !This should cause trouble and be noticed!
|
||||
MARK = CHAR(0) !In case a state is omitted.
|
||||
NEXT = CHAR(0) !Like, mention state seven, but omit mention of state six.
|
||||
HERE = 0 !Clear the counts.
|
||||
|
||||
Collate the transition table.
|
||||
10 READ (INF,*) STATE !Read this once, rather than for every transition.
|
||||
IF (STATE.LE.0) GO TO 20 !Ah, finished.
|
||||
WRITE (MSG,11) STATE !But they can come in any order.
|
||||
NSTATE = MAX(STATE,NSTATE)!And I'd like to know how many.
|
||||
11 FORMAT ("Entry: Read Write Move Next. For state ",I0) !Prepare a nice heading.
|
||||
IF (STATE.LE.0) STOP "Positive STATE numbers only!" !It may not be followed.
|
||||
IF (STATE*NSYMBOL.GT.MANY) STOP"My transition table is too small!" !But the value of STATE is shown.
|
||||
DO S = 0,NSYMBOL - 1 !Initialise the transitions for STATE.
|
||||
IT = STATE*NSYMBOL - S !Finger the one for S.
|
||||
MARK(IT) = CHAR(S) !No change to what's under the head.
|
||||
NEXT(IT) = CHAR(0) !And this stops the run.
|
||||
END DO !Just in case a symbol's number is omitted.
|
||||
DO S = 1,NSYMBOL - 1 !A transition for every symbol must be given or the read process will get out of step.
|
||||
READ(INF,*) RS,WS,K,L !Read symbol, write symbol, move, next.
|
||||
I = INDEX(SYMBOLS(1:NSYMBOL - 1),RS) !Convert the character to a symbol number.
|
||||
J = INDEX(SYMBOLS(1:NSYMBOL - 1),WS) !To enable decorative glyphs, not just digits.
|
||||
IF (I.LE.0) STOP "Unrecognised read symbol!" !This really should be more helpful.
|
||||
IF (J.LE.0) STOP "Unrecognised write symbol!" !By reading into ALINE and showing it, etc.
|
||||
IT = STATE*NSYMBOL - I !Locate the entry for the state x symbol pair.
|
||||
MARK(IT) = CHAR(J) !The value to be written.
|
||||
MOVE(IT) = K !The movement of the tape head.
|
||||
NEXT(IT) = CHAR(L) !The next state.
|
||||
IF (I.EQ.1) S1 = IT !This transition will be duplicated. SYMBOL(1) is for blank tape.
|
||||
END DO !On to the next symbol's transition.
|
||||
Copy SYMBOL(1)'s transition to the transition for the secret extra, SYMBOL(0).
|
||||
IT = STATE*NSYMBOL !Finger the interpolated entry for SYMBOL(0).
|
||||
MARK(IT) = MARK(S1) !Thus will SYMBOL(0), shown as a space, be overwritten.
|
||||
MOVE(IT) = MOVE(S1) !And SYMBOL(0) treated
|
||||
NEXT(IT) = NEXT(S1) !Exactly as if it were SYMBOL(1).
|
||||
Cast forth the transition table for STATE, not mentioning SYMBOL(0) - but see label 911.
|
||||
DO S = 1,NSYMBOL - 1 !Roll them out in the order as given in SYMBOL.
|
||||
IT = STATE*NSYMBOL - S !But the entry number will be odd.
|
||||
WRITE (ALINE,12) IT,SYMBOL(S), !The character's code value is irrelevant.
|
||||
1 SYMBOL(ICHAR(MARK(IT))),MOVE(IT),ICHAR(NEXT(IT)) !Append the details just read.
|
||||
12 FORMAT (I5,":",2X,'"',A1,'"',3X'"',A1,'"',I5,I5,I13) !Revealing the symbols, not their number.
|
||||
IF (MOVE(IT).GT.0) ALINE(21:21) = "+" !I want a leading + for positive, not zero.
|
||||
WRITE (MSG,1) ALINE(1:27) !The SP format code is unhelpful for zero.
|
||||
END DO !Hopefully, I'm still in sync with the input.
|
||||
GO TO 10 !Perhaps another state follows.
|
||||
|
||||
Chew tape. The initial state is some sequence of symbols, starting at TAPE(1).
|
||||
20 TAPE = CHAR(0) !Set every cell to zero. Not blank.
|
||||
OFFSET = 12 !Affine shift. The numerical value of HEAD is not seen.
|
||||
READ (INF,1) ALINE !Get text, for the tape's initial state.
|
||||
L = LEN_TRIM(ALINE) !Last non-blank. Flexible format this isn't.
|
||||
DO I = 1,L !Step through cells 1 to L.
|
||||
TAPE(I + OFFSET - 1) = CHAR(INDEX(SYMBOLS,ALINE(I:I))) !Character code to symbol number.
|
||||
END DO !Rather than reading as I1.
|
||||
CLOSE (INF) !Finished with the input, and not much checking either.
|
||||
WRITE (MSG,*) !Take a breath.
|
||||
Cast forth a heading..
|
||||
WRITE (MSG,99) !Announce.
|
||||
99 FORMAT ("Starts with State 1 and the tape head at 1.") !Positioned for OFFSET = 12.
|
||||
ALINE = " Step: Head State|Tape..." !Prepare a heading for the trace.
|
||||
L = 18 + OFFSET*2 !Locate the start position.
|
||||
ALINE(L - 1:L + 1) = "<H>"!No underlining, no overprinting, no colour (neither background nor foreground). Sigh.
|
||||
WRITE (MSG,1) ALINE !Take that!
|
||||
CALL CPU_TIME(T0) !Start the clock.
|
||||
HEAD = OFFSET !This is counted as position one.
|
||||
STATE = 1 !The initial state.
|
||||
STEP = 0 !No steps yet.
|
||||
|
||||
Chase through the transitions. Could check that HEAD is within bounds FIRST:LAST.
|
||||
100 IF (STEP.GE.200) GO TO 200 !Perhaps an extended campaign.
|
||||
STEP = STEP + 1 !Otherwise, here we go.
|
||||
DO I = 1,LONG/2 !Scan TAPE(1:LONG/2).
|
||||
IT = 2*I - 1 !Allowing two positions each.
|
||||
ALINE(IT:IT) = " " !So a leading space.
|
||||
ALINE(IT + 1:IT + 1) = SYMBOL(ICHAR(TAPE(I))) !And the indicated symbol.
|
||||
END DO !On to the enxt.
|
||||
I = HEAD*2 !The head's location in the display span.
|
||||
IF (I.GT.1 .AND. I.LT.LONG) THEN !Within range?
|
||||
IF (ALINE(I:I).EQ.SYMBOL(0)) ALINE(I:I) = SYMBOL(1) !Yes. Am I looking at a new cell?
|
||||
ALINE(I - 1:I - 1) = "<" !Bracket the head's cell.
|
||||
ALINE(I + 1:I + 1) = ">" !In ALINE.
|
||||
END IF !So much for showing the head's position.
|
||||
WRITE (MSG,102) STEP,HEAD - OFFSET + 1,STATE,ALINE !Splot the state.
|
||||
102 FORMAT (I5,":",I5,I6,"|",A) !Aligns with FORMAT 99.
|
||||
I = STATE*NSYMBOL - ICHAR(TAPE(HEAD)) !For this STATE and the symbol under TAPE(HEAD)
|
||||
HERE(I) = HERE(I) + 1 !Count my visits.
|
||||
TAPE(HEAD) = MARK(I) !Place the new symbol.
|
||||
HEAD = HEAD + MOVE(I) !Move the head.
|
||||
IF (HEAD.LT.FIRST .OR. HEAD.GT.LAST) GO TO 110 !Check the bounds.
|
||||
STATE = ICHAR(NEXT(I)) !The new state.
|
||||
IF (STATE.GT.0) GO TO 100 !Go to it.
|
||||
Cease.
|
||||
I = HEAD*2 !Locate HEAD within ALINE.
|
||||
IF (I.GT.1 .AND. I.LT.LONG) ALINE(I:I) = SYMBOL(ICHAR(TAPE(HEAD))) !The only change.
|
||||
WRITE (MSG,103) HEAD - OFFSET + 1,STATE,ALINE !Show.
|
||||
103 FORMAT ("HALT!",I6,I6,"|",A) !But, no step count to start with. See FORMAT 102.
|
||||
GO TO 900 !Done.
|
||||
Can't continue! Insufficient tape, alas.
|
||||
110 WRITE (MSG,*) "Insufficient tape!" !Oh dear.
|
||||
GO TO 900 !Give in.
|
||||
|
||||
Change into high gear: no trace and no test thereof neither.
|
||||
200 STEP = STEP + 1 !So, advance.
|
||||
IF (MOD(STEP,10000000).EQ.0) WRITE (MSG,201) STEP !Ah, still some timewasting.
|
||||
201 FORMAT ("Step ",I0) !No screen action is rather discouraging.
|
||||
I = STATE*NSYMBOL - ICHAR(TAPE(HEAD)) !Index the transition.
|
||||
HERE(I) = HERE(I) + 1 !Another visit.
|
||||
TAPE(HEAD) = MARK(I) !Do it. Possibly not changing the symbol.
|
||||
HEAD = HEAD + MOVE(I) !Possibly not moving the head.
|
||||
IF (HEAD.LT.FIRST .OR. HEAD.GT.LAST) GO TO 110 !But checking the bounds just in case.
|
||||
STATE = ICHAR(NEXT(I)) !Hopefully, something has changed!
|
||||
IF (STATE.GT.0) GO TO 200 !Otherwise, we might loop forever...
|
||||
|
||||
Closedown.
|
||||
900 CALL CPU_TIME(T1) !Where did it all go?
|
||||
WRITE (MSG,901) STEP,STATE !Announce the ending.
|
||||
901 FORMAT ("After step ",I0,", state = ",I0,".") !Thus.
|
||||
DO I = FIRST,LAST !Scan the tape.
|
||||
IF (ICHAR(TAPE(I)).NE.0) EXIT !This is the whole point of SYMBOL(0).
|
||||
END DO !So that the bounds
|
||||
DO J = LAST,FIRST,-1 !Of tape access
|
||||
IF (ICHAR(TAPE(J)).NE.0) EXIT !(and placement of the initial state)
|
||||
END DO !Can be found without tedious ongoing MIN and MAX.
|
||||
WRITE (MSG,902) HEAD - OFFSET + 1, !Tediously,
|
||||
1 I - OFFSET + 1, !Reverse the offset
|
||||
2 J - OFFSET + 1 !So as to seem that HEAD = 1, to start with.
|
||||
902 FORMAT ("The head is at position ",I0, !Now announce the results.
|
||||
1 " and wandered over ",I0," to ",I0) !This will affect the dimension chosen for TAPE.
|
||||
T1 = T1 - T0 !Some time may have been accurately measured.
|
||||
IF (T1.GT.0.1) WRITE (MSG,903) T1 !And this may be sort of correct.
|
||||
903 FORMAT ("CPU time",F9.3) !Though distinct from elapsed time.
|
||||
Curious about the usage of the transition table?
|
||||
910 WRITE (MSG,911) !Possibly not,
|
||||
911 FORMAT (/,35X,"Usage.") !But here it comes.
|
||||
DO STATE = 1,NSTATE !For every state
|
||||
WRITE (MSG,11) STATE !Name the state, as before.
|
||||
DO S = 0,NSYMBOL - 1 !But this time, roll every symbol.
|
||||
IT = STATE*NSYMBOL - S !Including my "secret" symbol.
|
||||
WRITE (ALINE,12) IT,SYMBOL(S), !The same sequence,
|
||||
1 SYMBOL(ICHAR(MARK(IT))),MOVE(IT),ICHAR(NEXT(IT)),HERE(IT) !But with an addendum here.
|
||||
IF (MOVE(IT).GT.0) ALINE(21:21) = "+" !SIGN(i,i) gives -1, 0, +1 but -60 for -60.
|
||||
WRITE (MSG,1) ALINE(1:40) !When what I want is -1. SIGN(1,i) doesn't give zero.
|
||||
END DO !On to the next symbol in the order as supplied.
|
||||
END DO !And the next state, in numbers order.
|
||||
END !That was fun.
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
function tm(d,s,e,i,b,t,... r) {
|
||||
document.write(d, '<br>')
|
||||
if (i<0||i>=t.length) return
|
||||
write('*',s,i,t=t.split(''))
|
||||
var p={}; r.forEach(e=>((s,r,w,m,n)=>{p[s+'.'+r]={w,n,m:[0,1,-1][1+'RL'.indexOf(m)]}})(... e.split(/[ .:,]+/)))
|
||||
for (var n=1; s!=e; n+=1) {
|
||||
with (p[s+'.'+t[i]]) t[i]=w,s=n,i+=m
|
||||
if (i==-1) i=0,t.unshift(b)
|
||||
else if (i==t.length) t[i]=b
|
||||
write(n,s,i,t)
|
||||
}
|
||||
document.write('<br>')
|
||||
function write(n, s, i, t) {
|
||||
t = t.join('')
|
||||
t = t.substring(0,i) + '<u>' + t.charAt(i) + '</u>' + t.substr(i+1)
|
||||
document.write((' '+n).slice(-3).replace(/ /g,' '), ': ', s, ' [', t.replace(b,' ','g'), ']', '<br>')
|
||||
}
|
||||
}
|
||||
|
||||
tm( 'Unary incrementer',
|
||||
// s e i b t
|
||||
'a', 'h', 0, 'B', '111',
|
||||
// s.r: w, m, n
|
||||
'a.1: 1, L, a',
|
||||
'a.B: 1, S, h'
|
||||
)
|
||||
|
||||
tm( 'Unary adder',
|
||||
1, 0, 0, '0', '1110111',
|
||||
'1.1: 0, R, 2', // write 0 rigth goto 2
|
||||
'2.0: 0, S, 0', // if (0) halt
|
||||
'2.1: 0, R, 3', // write 0 rigth goto 3
|
||||
'3.1: 1, R, 3', // while (1) rigth
|
||||
'3.0: 1, S, 0', // write 1 halt
|
||||
)
|
||||
|
||||
tm( 'Three-state busy beaver',
|
||||
1, 0, 0, '0', '0',
|
||||
'1.0: 1, R, 2',
|
||||
'1.1: 1, R, 0',
|
||||
'2.0: 0, R, 3',
|
||||
'2.1: 1, R, 2',
|
||||
'3.0: 1, L, 3',
|
||||
'3.1: 1, L, 1'
|
||||
)
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
-- Machine definitions
|
||||
local incrementer = {
|
||||
name = "Simple incrementer",
|
||||
initState = "q0",
|
||||
endState = "qf",
|
||||
blank = "B",
|
||||
rules = {
|
||||
{"q0", "1", "1", "right", "q0"},
|
||||
{"q0", "B", "1", "stay", "qf"}
|
||||
}
|
||||
}
|
||||
|
||||
local threeStateBB = {
|
||||
name = "Three-state busy beaver",
|
||||
initState = "a",
|
||||
endState = "halt",
|
||||
blank = "0",
|
||||
rules = {
|
||||
{"a", "0", "1", "right", "b"},
|
||||
{"a", "1", "1", "left", "c"},
|
||||
{"b", "0", "1", "left", "a"},
|
||||
{"b", "1", "1", "right", "b"},
|
||||
{"c", "0", "1", "left", "b"},
|
||||
{"c", "1", "1", "stay", "halt"}
|
||||
}
|
||||
}
|
||||
|
||||
local fiveStateBB = {
|
||||
name = "Five-state busy beaver",
|
||||
initState = "A",
|
||||
endState = "H",
|
||||
blank = "0",
|
||||
rules = {
|
||||
{"A", "0", "1", "right", "B"},
|
||||
{"A", "1", "1", "left", "C"},
|
||||
{"B", "0", "1", "right", "C"},
|
||||
{"B", "1", "1", "right", "B"},
|
||||
{"C", "0", "1", "right", "D"},
|
||||
{"C", "1", "0", "left", "E"},
|
||||
{"D", "0", "1", "left", "A"},
|
||||
{"D", "1", "1", "left", "D"},
|
||||
{"E", "0", "1", "stay", "H"},
|
||||
{"E", "1", "0", "left", "A"}
|
||||
}
|
||||
}
|
||||
|
||||
-- Display a representation of the tape and machine state on the screen
|
||||
function show (state, headPos, tape)
|
||||
local leftEdge = 1
|
||||
while tape[leftEdge - 1] do leftEdge = leftEdge - 1 end
|
||||
io.write(" " .. state .. "\t| ")
|
||||
for pos = leftEdge, #tape do
|
||||
if pos == headPos then io.write("[" .. tape[pos] .. "] ") else io.write(" " .. tape[pos] .. " ") end
|
||||
end
|
||||
print()
|
||||
end
|
||||
|
||||
-- Simulate a turing machine
|
||||
function UTM (machine, tape, countOnly)
|
||||
local state, headPos, counter = machine.initState, 1, 0
|
||||
print("\n\n" .. machine.name)
|
||||
print(string.rep("=", #machine.name) .. "\n")
|
||||
if not countOnly then print(" State", "| Tape [head]\n---------------------") end
|
||||
repeat
|
||||
if not tape[headPos] then tape[headPos] = machine.blank end
|
||||
if not countOnly then show(state, headPos, tape) end
|
||||
for _, rule in ipairs(machine.rules) do
|
||||
if rule[1] == state and rule[2] == tape[headPos] then
|
||||
tape[headPos] = rule[3]
|
||||
if rule[4] == "left" then headPos = headPos - 1 end
|
||||
if rule[4] == "right" then headPos = headPos + 1 end
|
||||
state = rule[5]
|
||||
break
|
||||
end
|
||||
end
|
||||
counter = counter + 1
|
||||
until state == machine.endState
|
||||
if countOnly then print("Steps taken: " .. counter) else show(state, headPos, tape) end
|
||||
end
|
||||
|
||||
-- Main procedure
|
||||
UTM(incrementer, {"1", "1", "1"})
|
||||
UTM(threeStateBB, {})
|
||||
UTM(fiveStateBB, {}, "countOnly")
|
||||
|
|
@ -0,0 +1,373 @@
|
|||
;; "A Turing Turtle": a Turing Machine implemented in NetLogo
|
||||
;; by Dan Dewey 1/16/2016
|
||||
;;
|
||||
;; This NetLogo code implements a Turing Machine, see, e.g.,
|
||||
;; http://en.wikipedia.org/wiki/Turing_machine
|
||||
;; The Turing machine fits nicely into the NetLogo paradigm in which
|
||||
;; there are agents (aka the turtles), that move around
|
||||
;; in a world of "patches" (2D cells).
|
||||
;; Here, a single agent represents the Turing machine read/write head
|
||||
;; and the patches represent the Turing tape values via their colors.
|
||||
;; The 2D array of patches is treated as a single long 1D tape in an
|
||||
;; obvious way.
|
||||
|
||||
;; This program is presented as a NetLogo example on the page:
|
||||
;; http://rosettacode.org/wiki/Universal_Turing_machine
|
||||
;; This file may be larger than others on that page, note however
|
||||
;; that I include many comments in the code and I have made no
|
||||
;; effort to 'condense' the code, prefering clarity over compactness.
|
||||
;; A demo and discussion of this program is on the web page:
|
||||
;; http://sites.google.com/site/dan3deweyscspaimsportfolio/extra-turing-machine
|
||||
;; The Copy example machine was taken from:
|
||||
;; http://en.wikipedia.org/wiki/Turing_machine_examples
|
||||
;; The "Busy Beaver" machines encoded below were taken from:
|
||||
;; http://www.logique.jussieu.fr/~michel/ha.html
|
||||
|
||||
;; The implementation here allows 3 symbols (blank, 0, 1) on the tape
|
||||
;; and 3 head motions (left, stay, right).
|
||||
|
||||
;; The 2D world is nominally set to be 29x29, going from (-14,-14) to
|
||||
;; (14,14) from lower left to upper right and with (0,0) at the center.
|
||||
;; This gives a total Turing tape length of 29^2 = 841 cells, sufficient for the
|
||||
;; "Lazy" Beaver 5,2 example.
|
||||
;; Since the max-pxcor variable is used in the code below (as opposed to
|
||||
;; a hard-coded number), the effective tape size can be changed by
|
||||
;; changing the size of the 2D world with the Settings... button on the interface.
|
||||
|
||||
;; The "Info" tab of the NetLogo interface contains some further comments.
|
||||
;; - - - - - - -
|
||||
|
||||
|
||||
;; - - - - - - - - - - - Global/Agent variables
|
||||
;; These three 2D arrays (lists of lists) encode the Turing Machine rules:
|
||||
;; WhatToWrite: -1 (Blank), 0, 1
|
||||
;; HowToMove: -1 (left), 0(stay), 1 (right)
|
||||
;; NextState: 0 to N-1, negative value goes to a halt state.
|
||||
;; The above are a function of the current state and the current tape (patch) value.
|
||||
;; MachineState is used by the turtle to pass the current state of the Turing machine
|
||||
;; (or the halt code) to the observer.
|
||||
globals [ WhatToWrite HowToMove NextState MachineState
|
||||
;; some other golobals of secondary importance...
|
||||
;; set different patch colors to record the Turing tape values
|
||||
BlankColor ZeroColor OneColor
|
||||
;; a delay constant to slow down the operation
|
||||
RealTimePerTick ]
|
||||
|
||||
;; We'll have one turtle which is the Turing machine read/write head
|
||||
;; it will keep track of the current Turing state in its own MyState value
|
||||
turtles-own [ MyState ]
|
||||
|
||||
|
||||
;; - - - - - - - - - - -
|
||||
to Setup ;; sets up the world
|
||||
clear-all ;; clears the world first
|
||||
|
||||
;; Try to not have (too many) ad hoc numbers in the code,
|
||||
;; collect and set various values here especially if they might be used in multiple places:
|
||||
;; The colors for Blank, Zero and One : (user can can change as desired)
|
||||
set BlankColor 2 ;; dark gray
|
||||
set OneColor green
|
||||
set ZeroColor red
|
||||
;; slow it down for the humans to watch
|
||||
set RealTimePerTick 0.2 ;; have simulation go at nice realtime speed
|
||||
|
||||
create-turtles 1 ;; create the one Turing turtle
|
||||
[ ;; set default parameters
|
||||
set size 2 ;; set a nominal size
|
||||
set color yellow ;; color of border
|
||||
;; set the starting location, some Turing programs will adjust this if needed:
|
||||
setxy 0 0 ;; -1 * max-pxcor -1 * max-pxcor
|
||||
set shape "square2empty" ;; edited version of "square 2" to have clear in middle
|
||||
|
||||
;; set the starting state - always 0
|
||||
set MyState 0
|
||||
set MachineState 0 ;; the turtle will update this global value from now on
|
||||
]
|
||||
|
||||
;; Define the Turing machine rules with 2D lists.
|
||||
;; Based on the selection made on interface panel, setting the string Turing_Program_Selection.
|
||||
;; This routine has all the Turing 'programs' in it - it's at the very bottom of this file.
|
||||
LoadTuringProgram
|
||||
|
||||
;; the environment, e.g. the Turing tape
|
||||
ask patches
|
||||
[
|
||||
;; all patches are set to the blank color
|
||||
set pcolor BlankColor
|
||||
]
|
||||
|
||||
;; keep track of time; each tick is a Turing step
|
||||
reset-ticks
|
||||
end
|
||||
|
||||
|
||||
;; - - - - - - - - - - - - - - - -
|
||||
to Go ;; this repeatedly does steps
|
||||
|
||||
;; The turtle does the main work
|
||||
ask turtles
|
||||
[
|
||||
DoOneStep
|
||||
wait RealTimePerTick
|
||||
]
|
||||
|
||||
tick
|
||||
|
||||
;; The Turing turtle will die if it tries to go beyond the cells,
|
||||
;; in that case (no turtles left) we'll stop.
|
||||
;; Also stop if the MachineState has been set to a negative number (a halt state).
|
||||
if ((count turtles = 0) or (MachineState < 0))
|
||||
[ stop ]
|
||||
|
||||
end
|
||||
|
||||
to DoOneStep
|
||||
;; have the turtle do one Turing step
|
||||
;; First, 'read the tape', i.e., based on the patch color here:
|
||||
let tapeValue GetTapeValue
|
||||
|
||||
;; using the tapeValue and MyState, get the desired actions here:
|
||||
;; (the item commands extract the appropriate value from the list-of-lists)
|
||||
let myWrite item (tapeValue + 1) (item MyState WhatToWrite)
|
||||
let myMove item (tapeValue + 1) (item MyState HowToMove)
|
||||
let myNextState item (tapeValue + 1) (item MyState NextState)
|
||||
|
||||
;; Write to the tape as appropriate
|
||||
SetTapeValue myWrite
|
||||
|
||||
;; Move as appropriate
|
||||
if (myMove = 1) [MoveForward]
|
||||
if (myMove = -1) [MoveBackward]
|
||||
|
||||
;; Go to the next state; check if it is a halt state.
|
||||
;; Update the global MachineState value
|
||||
set MachineState myNextState
|
||||
ifelse (myNextState < 0)
|
||||
[
|
||||
;; It's a halt state. The negative MachineState will signal the stop.
|
||||
;; Go back to the starting state so it can be re-run if desired.
|
||||
set MyState 0]
|
||||
[
|
||||
;; Not a halt state, so change to the desired next state
|
||||
set MyState myNextState
|
||||
]
|
||||
end
|
||||
|
||||
to MoveForward
|
||||
;; move the turtle forward one cell, including line wrapping.
|
||||
set heading 90
|
||||
ifelse (xcor = max-pxcor)
|
||||
[set xcor -1 * max-pxcor
|
||||
;; and go up a row if possible... otherwise die
|
||||
ifelse ycor = max-pxcor
|
||||
[ die ] ;; tape too short - a somewhat crude end of things ;-)
|
||||
[set ycor ycor + 1]
|
||||
]
|
||||
[jump 1]
|
||||
end
|
||||
|
||||
to MoveBackward
|
||||
;; move the turtle backward one cell, including line-wrapping.
|
||||
set heading -90
|
||||
ifelse (xcor = -1 * max-pxcor)
|
||||
[
|
||||
set xcor max-pxcor
|
||||
;; and go down a row... or die
|
||||
ifelse ycor = -1 * max-pxcor
|
||||
[ die ] ;; tape too short - a somewhat crude end of things ;-)
|
||||
[set ycor ycor - 1]
|
||||
]
|
||||
[jump 1]
|
||||
end
|
||||
|
||||
to-report GetTapeValue
|
||||
;; report the tape color equivalent value
|
||||
if (pcolor = ZeroColor) [report 0]
|
||||
if (pcolor = OneColor) [report 1]
|
||||
report -1
|
||||
end
|
||||
|
||||
to SetTapeValue [ value ]
|
||||
;; write the appropriate color on the tape
|
||||
ifelse (value = 1)
|
||||
[set pcolor OneColor]
|
||||
[ ifelse (value = 0)
|
||||
[set pcolor ZeroColor][set pcolor BlankColor]]
|
||||
end
|
||||
|
||||
|
||||
;; - - - - - OK, here are the data for the various Turing programs...
|
||||
;; Note that besdes settting the rules (array values) these sections can also
|
||||
;; include commands to clear the tape, position the r/w head, adjust wait time, etc.
|
||||
to LoadTuringProgram
|
||||
|
||||
;; A template of the rules structure: a list of lists
|
||||
;; E.g. values are given for States 0 to 4, when looking at Blank, Zero, One:
|
||||
;; For 2-symbol machines use Blank(-1) and One(1) and ignore the middle values (never see zero).
|
||||
;; Normal Halt will be state -1, the -9 default shows an unexpected halt.
|
||||
;; state 0 state 1 state 2 state 3 state 4
|
||||
set WhatToWrite (list (list -1 0 1) (list -1 0 1) (list -1 0 1) (list -1 0 1) (list -1 0 1) )
|
||||
set HowToMove (list (list 0 0 0) (list 0 0 0) (list 0 0 0) (list 0 0 0) (list 0 0 0) )
|
||||
set NextState(list (list -9 -9 -9) (list -9 -9 -9) (list -9 -9 -9) (list -9 -9 -9) (list -9 -9 -9) )
|
||||
|
||||
;; Fill the rules based on the selected case
|
||||
if (Turing_Program_Selection = "Simple Incrementor")
|
||||
[
|
||||
;; simple Incrementor - this is from the RosettaCode Universal Turing Machine page - very simple!
|
||||
set WhatToWrite (list (list 1 0 1) )
|
||||
set HowToMove (list (list 0 0 1) )
|
||||
set NextState (list (list -1 -9 0) )
|
||||
]
|
||||
|
||||
;; Fill the rules based on the selected case
|
||||
if (Turing_Program_Selection = "Incrementor w/Return")
|
||||
[
|
||||
;; modified Incrementor: it returns to the first 1 on the left.
|
||||
;; This version allows the "Copy Ones to right" program to directly follow it.
|
||||
;; move right append one back to beginning
|
||||
set WhatToWrite (list (list -1 0 1) (list 1 0 1) (list -1 0 1) )
|
||||
set HowToMove (list (list 1 0 1) (list 0 0 1) (list 1 0 -1) )
|
||||
set NextState (list (list 1 -9 1) (list 2 -9 1) (list -1 -9 2) )
|
||||
]
|
||||
|
||||
;; Fill the rules based on the selected case
|
||||
if (Turing_Program_Selection = "Copy Ones to right")
|
||||
[
|
||||
;; "Copy" from Wiki "Turing machine examples" page; slight mod so that it ends on first 1
|
||||
;; of the copy allowing Copy to be re-executed to create another copy.
|
||||
;; Has 5 states and uses Blank and 1 to make a copy of a string of ones;
|
||||
;; this can be run after runs of the "Incrementor w/Return".
|
||||
;; state 0 state 1 state 2 state 3 state 4
|
||||
set WhatToWrite (list (list -1 0 -1) (list -1 0 1) (list 1 0 1) (list -1 0 1) (list 1 0 1) )
|
||||
set HowToMove (list (list 1 0 1) (list 1 0 1) (list -1 0 1) (list -1 0 -1) (list 1 0 -1) )
|
||||
set NextState (list (list -1 -9 1) (list 2 -9 1) (list 3 -9 2) (list 4 -9 3) (list 0 -9 4) )
|
||||
]
|
||||
|
||||
;; Fill the rules based on the selected case
|
||||
if (Turing_Program_Selection = "Binary Counter")
|
||||
[
|
||||
;; Count in binary - can start on a blank space.
|
||||
;; States: start carry-1 back-to-beginning
|
||||
set WhatToWrite (list (list 1 1 0) (list 1 1 0) (list -1 0 1) )
|
||||
set HowToMove (list (list 0 0 -1) (list 0 0 -1) (list -1 1 1) )
|
||||
set NextState (list (list -1 -1 1) (list 2 2 1) (list -1 2 2) )
|
||||
;; Select line above from these two:
|
||||
;; can either count by 1 each time it is run:
|
||||
;; set NextState (list (list -1 -1 1) (list 2 2 1) (list -1 2 2) )
|
||||
;; or count forever once started:
|
||||
;; set NextState (list (list 0 0 1) (list 2 2 1) (list 0 2 2) )
|
||||
set RealTimePerTick 0.2
|
||||
]
|
||||
|
||||
if (Turing_Program_Selection = "Busy-Beaver 3-State, 2-Sym")
|
||||
[
|
||||
;; from the RosettaCode.org Universal Turing Machine page
|
||||
;; state name: a b c
|
||||
set WhatToWrite (list (list 1 0 1) (list 1 0 1) (list 1 0 1) (list -1 0 1) (list -1 0 1) )
|
||||
set HowToMove (list (list 1 0 -1) (list -1 0 1) (list -1 0 0) (list 0 0 0) (list 0 0 0) )
|
||||
set NextState (list (list 1 -9 2) (list 0 -9 1) (list 1 -9 -1) (list -9 -9 -9) (list -9 -9 -9) )
|
||||
;; Clear the tape
|
||||
ask Patches [set pcolor BlankColor]
|
||||
]
|
||||
|
||||
;; should output 13 ones and take 107 steps to do it...
|
||||
if (Turing_Program_Selection = "Busy-Beaver 4-State, 2-Sym")
|
||||
[
|
||||
;; from the RosettaCode.org Universal Turing Machine page
|
||||
;; state name: A B C D
|
||||
set WhatToWrite (list (list 1 0 1) (list 1 0 -1) (list 1 0 1) (list 1 0 -1) (list -1 0 1) )
|
||||
set HowToMove (list (list 1 0 -1) (list -1 0 -1) (list 1 0 -1) (list 1 0 1) (list 0 0 0) )
|
||||
set NextState (list (list 1 -9 1) (list 0 -9 2) (list -1 -9 3) (list 3 -9 0) (list -9 -9 -9) )
|
||||
;; Clear the tape
|
||||
ask Patches [set pcolor BlankColor]
|
||||
]
|
||||
|
||||
;; This takes 38 steps to write 9 ones/zeroes
|
||||
if (Turing_Program_Selection = "Busy-Beaver 2-State, 3-Sym")
|
||||
[
|
||||
;; A B
|
||||
set WhatToWrite (list (list 0 1 0) (list 1 1 0) (list -1 0 1) (list -1 0 1) (list -1 0 1) )
|
||||
set HowToMove (list (list 1 -1 1) (list -1 1 -1) (list 0 0 0) (list 0 0 0) (list 0 0 0) )
|
||||
set NextState(list (list 1 1 -1) (list 0 1 1) (list -9 -9 -9) (list -9 -9 -9) (list -9 -9 -9) )
|
||||
;; Clear the tape
|
||||
ask Patches [set pcolor BlankColor]
|
||||
]
|
||||
|
||||
;; This only makes 501 ones and stops after 134,467 steps -- it does do that !!!
|
||||
if (Turing_Program_Selection = "Lazy-Beaver 5-State, 2-Sym")
|
||||
[
|
||||
;; from the RosettaCode.org Universal Turing Machine page
|
||||
;; state name: A0 B1 C2 D3 E4
|
||||
set WhatToWrite (list (list 1 0 -1) (list 1 0 1) (list 1 0 -1) (list -1 0 1) (list 1 0 1) )
|
||||
set HowToMove (list (list 1 0 -1) (list 1 0 1) (list -1 0 1) (list 1 0 1) (list -1 0 1) )
|
||||
set NextState (list (list 1 -9 2) (list 2 -9 3) (list 0 -9 1) (list 4 -9 -1) (list 2 -9 0) )
|
||||
;; Clear the tape
|
||||
ask Patches [set pcolor BlankColor]
|
||||
;; Looks like it goes much more forward than back on the tape
|
||||
;; so start the head just a row from the bottom:
|
||||
ask turtles [setxy 0 -1 * max-pxcor + 1]
|
||||
;; and go faster
|
||||
set RealTimePerTick 0.02
|
||||
]
|
||||
|
||||
;; The rest have large outputs and run for a long time, so I haven't confirmed
|
||||
;; that they work as advertised...
|
||||
|
||||
;; This is the 5,2 record holder: 4098 ones in 47,176,870 steps.
|
||||
;; With max-pxcor of 14 and offset r/w head start (below), this will
|
||||
;; run off the tape at about 150,000+steps...
|
||||
if (Turing_Program_Selection = "Busy-Beaver 5-State, 2-Sym")
|
||||
[
|
||||
;; from the RosettaCode.org Universal Turing Machine page
|
||||
;; state name: A B C D E
|
||||
set WhatToWrite (list (list 1 0 1) (list 1 0 1) (list 1 0 -1) (list 1 0 1) (list 1 0 -1) )
|
||||
set HowToMove (list (list 1 0 -1) (list 1 0 1) (list 1 0 -1) (list -1 0 -1) (list 1 0 -1) )
|
||||
set NextState (list (list 1 -9 2) (list 2 -9 1) (list 3 -9 4) (list 0 -9 3) (list -1 -9 0) )
|
||||
;; Clear the tape
|
||||
ask Patches [set pcolor BlankColor]
|
||||
;; Writes more backward than forward, so start a few rows from the top:
|
||||
ask turtles [setxy 0 max-pxcor - 3]
|
||||
;; and go faster
|
||||
set RealTimePerTick 0.02
|
||||
]
|
||||
|
||||
if (Turing_Program_Selection = "Lazy-Beaver 3-State, 3-Sym")
|
||||
[
|
||||
;; This should write 5600 ones/zeros and take 29,403,894 steps.
|
||||
;; Ran it to 175,000+ steps and only covered 1/2 of the cells (w/max-pxcor = 14)...
|
||||
;; state name: A B C
|
||||
set WhatToWrite (list (list 0 1 0) (list 1 -1 0) (list 0 1 0) (list -1 0 1) (list -1 0 1) )
|
||||
set HowToMove (list (list 1 1 -1) (list -1 1 1) (list 1 -1 1) (list 0 0 0) (list 0 0 0) )
|
||||
set NextState (list (list 1 0 0) (list 2 2 1) (list -1 0 1) (list -9 -9 -9) (list -9 -9 -9) )
|
||||
;; Clear the tape
|
||||
ask Patches [set pcolor BlankColor]
|
||||
;; It goes much more forward than back on the tape
|
||||
;; so start the head just a row from the bottom:
|
||||
ask turtles [setxy 0 -1 * max-pxcor + 1]
|
||||
;; and go faster
|
||||
set RealTimePerTick 0.02
|
||||
]
|
||||
|
||||
if (Turing_Program_Selection = "Busy-Beaver 3-State, 3-Sym")
|
||||
[
|
||||
;; This should write 374,676,383 ones/zeros and take 119,112,334,170,342,540 (!!!) steps.
|
||||
;; Rn it to ~ 175,000 steps covering about 2/3 of the max-pxcor=14 cells.
|
||||
;; state name: A B C
|
||||
set WhatToWrite (list (list 0 1 0) (list -1 1 0) (list 0 0 0) (list -1 0 1) (list -1 0 1) )
|
||||
set HowToMove (list (list 1 -1 -1) (list -1 1 -1) (list 1 1 1) (list 0 0 0) (list 0 0 0) )
|
||||
set NextState (list (list 1 0 2) (list 0 1 1) (list -1 0 2) (list -9 -9 -9) (list -9 -9 -9) )
|
||||
;; Clear the tape
|
||||
ask Patches [set pcolor BlankColor]
|
||||
;; Writes more backward than forward, so start a rowish from the top:
|
||||
ask turtles [setxy 0 max-pxcor - 1]
|
||||
;; and go faster
|
||||
set RealTimePerTick 0.02
|
||||
]
|
||||
|
||||
;; in all cases reset the machine state to 0:
|
||||
ask turtles [set MyState 0]
|
||||
set MachineState 0
|
||||
;; and the ticks
|
||||
reset-ticks
|
||||
|
||||
end
|
||||
|
|
@ -1,41 +1,45 @@
|
|||
/*REXX pgm executes a Turing machine based on initial state, tape, rules*/
|
||||
state = 'q0' /*initial Turing machine state. */
|
||||
term = 'qf' /*a state that is used for halt. */
|
||||
blank = 'B' /*this character is a true blank.*/
|
||||
call turing_rule 'q0 1 1 right q0' /*define a rule for the machine. */
|
||||
call turing_rule 'q0 B 1 stay qf' /* " " " " " " */
|
||||
call turing_init 1 1 1 /*initialize tape to string(s). */
|
||||
call turing_machine /*go invoke the Turning machine. */
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────TURING_MACHINE subroutine───────────*/
|
||||
turing_machine: !=1; bot=1; top=1 /*start at the tape location 1. */
|
||||
say /*might as well show a blank line*/
|
||||
do cycle=1 until state==term /*do Turing machine instructions.*/
|
||||
do k=1 for rules /*process the Turning mach. rules*/
|
||||
parse var rule.k rState rTape rWrite rMove rNext . /*pick pieces*/
|
||||
if state\==rState | @.!\==rTape then iterate /*wrong rule?*/
|
||||
@.!=rWrite /*right rule; write it ──► tape.*/
|
||||
if rMove== 'left' then !=!-1 /*Move left? Then subtract one.*/
|
||||
if rMove=='right' then !=!+1 /*Move right? Then add one.*/
|
||||
bot=min(bot,!); top=max(top,!) /*find the tape bottom and top.*/
|
||||
state=rNext /*use this for the next state. */
|
||||
iterate cycle /*go process another instruction.*/
|
||||
end /*k*/
|
||||
say '***error!*** unknown state:' state; leave /*oops.*/
|
||||
end /*cycle*/
|
||||
$= /*start with empty string (tape).*/
|
||||
do t=bot to top; _=@.t; if _==blank then _=' ' /*translate?*/
|
||||
$=$ || pad || _ /*build chr by chr, maybe pad it.*/
|
||||
end /*t*/ /* [↑] build the tape's contents.*/
|
||||
if $='' then $= "[tape is blank.]" /*make an empty tape visible.*/
|
||||
say 'Turning machine used' rules "rules in" cycle 'cycles, tape is:' $
|
||||
return
|
||||
/*──────────────────────────────────TURING_INIT subroutine──────────────*/
|
||||
turing_init: @.=blank; parse arg x
|
||||
do j=1 for words(x); @.j=word(x,j); end /*j*/
|
||||
return
|
||||
/*──────────────────────────────────TURING_RULE subroutine──────────────*/
|
||||
turing_rule: if symbol('RULES')=="LIT" then rules=0; rules=rules+1
|
||||
pad=left('',length(word(arg(1),2))\==1) /*used if any symbol's length>1.*/
|
||||
rule.rules=arg(1); say right('rule' rules,20) "═══►" rule.rules
|
||||
return
|
||||
/*REXX program executes a Turing machine based on initial state, tape, and rules. */
|
||||
state = 'q0' /*the initial Turing machine state. */
|
||||
term = 'qf' /*a state that is used for a halt. */
|
||||
blank = 'B' /*this character is a "true" blank. */
|
||||
call Turing_rule 'q0 1 1 right q0' /*define a rule for the Turing machine.*/
|
||||
call Turing_rule 'q0 B 1 stay qf' /* " " " " " " " */
|
||||
call Turing_init 1 1 1 /*initialize the tape to some string(s)*/
|
||||
call TM /*go and invoke the Turning machine. */
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
TM: !=1; bot=1; top=1; @er= '***error***' /*start at the tape location 1. */
|
||||
say /*might as well display a blank line. */
|
||||
do cycle=1 until state==term /*process Turing machine instructions.*/
|
||||
do k=1 for rules /* " " " rules. */
|
||||
parse var rule.k rState rTape rWrite rMove rNext . /*pick pieces. */
|
||||
if state\==rState | @.!\==rTape then iterate /*wrong rule ? */
|
||||
@.!=rWrite /*right rule; write it ───► the tape. */
|
||||
if rMove== 'left' then !=!-1 /*Are we moving left? Then subtract 1*/
|
||||
if rMove=='right' then !=!+1 /* " " " right? " add 1*/
|
||||
bot=min(bot, !); top=max(top, !) /*find the tape bottom and top. */
|
||||
state=rNext /*use this for the next state. */
|
||||
iterate cycle /*go process another TM instruction. */
|
||||
end /*k*/
|
||||
say @er 'unknown state:' state; leave /*oops, we have an unknown state error.*/
|
||||
end /*cycle*/
|
||||
$= /*start with empty string (the tape). */
|
||||
do t=bot to top; _=@.t
|
||||
if _==blank then _=' ' /*do we need to translate a true blank?*/
|
||||
$=$ || pad || _ /*construct char by char, maybe pad it.*/
|
||||
end /*t*/ /* [↑] construct the tape's contents.*/
|
||||
L=length($)
|
||||
if L==0 then $= "[tape is blank.]" /*make an empty tape visible to user.*/
|
||||
if L>1000 then $=left($, 1000) ... /*truncate tape to 1k bytes, append ···*/
|
||||
say "tape's contents:" $ /*show the tape's contents (or 1st 1k).*/
|
||||
say "tape's length: " L /* " " " length. */
|
||||
say 'Turning machine used ' rules " rules in " cycle ' cycles.'
|
||||
return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
Turing_init: @.=blank; parse arg x; do j=1 for words(x); @.j=word(x,j); end /*j*/
|
||||
return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
Turing_rule: if symbol('RULES')=="LIT" then rules=0; rules=rules+1
|
||||
pad=left('', length( word( arg(1),2 ) ) \==1 ) /*padding for rule*/
|
||||
rule.rules=arg(1); say right('rule' rules, 20) "═══►" rule.rules
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
/*REXX pgm executes a Turing machine based on initial state, tape, rules*/
|
||||
state = 'a' /*initial Turing machine state. */
|
||||
term = 'halt' /*a state that is used for halt. */
|
||||
blank = 0 /*this character is a true blank.*/
|
||||
call turing_rule 'a 0 1 right b' /*define a rule for the machine. */
|
||||
call turing_rule 'a 1 1 left c' /* " " " " " " */
|
||||
call turing_rule 'b 0 1 left a' /* " " " " " " */
|
||||
call turing_rule 'b 1 1 right b' /* " " " " " " */
|
||||
call turing_rule 'c 0 1 left b' /* " " " " " " */
|
||||
call turing_rule 'c 1 1 stay halt' /* " " " " " " */
|
||||
call turing_init /*initialize tape to string(s). */
|
||||
call turing_machine /*go invoke the Turning machine. */
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────TURING_MACHINE subroutine───────────*/
|
||||
turing_machine ∙∙∙
|
||||
/*REXX program executes a Turing machine based on initial state, tape, and rules. */
|
||||
state = 'a' /*the initial Turing machine state. */
|
||||
term = 'halt' /*a state that is used for a halt. */
|
||||
blank = 0 /*this character is a "true" blank. */
|
||||
call Turing_rule 'a 0 1 right b' /*define a rule for the Turing machine.*/
|
||||
call Turing_rule 'a 1 1 left c' /* " " " " " " " */
|
||||
call Turing_rule 'b 0 1 left a' /* " " " " " " " */
|
||||
call Turing_rule 'b 1 1 right b' /* " " " " " " " */
|
||||
call Turing_rule 'c 0 1 left b' /* " " " " " " " */
|
||||
call Turing_rule 'c 1 1 stay halt' /* " " " " " " " */
|
||||
call Turing_init /*initialize the tape to some string(s)*/
|
||||
call TM /*go and invoke the Turning machine. */
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
TM: ∙∙∙
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
/*REXX pgm executes a Turing machine based on initial state, tape, rules*/
|
||||
state = 'A' /*initial Turing machine state. */
|
||||
term = 'H' /*a state that is used for halt. */
|
||||
blank = 0 /*this character is a true blank.*/
|
||||
call turing_rule 'A 0 1 right B' /*define a rule for the machine. */
|
||||
call turing_rule 'A 1 1 left C' /* " " " " " " */
|
||||
call turing_rule 'B 0 1 right C' /* " " " " " " */
|
||||
call turing_rule 'B 1 1 right B' /* " " " " " " */
|
||||
call turing_rule 'C 0 1 right D' /* " " " " " " */
|
||||
call turing_rule 'C 1 1 left E' /* " " " " " " */
|
||||
call turing_rule 'D 0 1 left A' /* " " " " " " */
|
||||
call turing_rule 'D 1 1 left D' /* " " " " " " */
|
||||
call turing_rule 'E 0 1 stay H' /* " " " " " " */
|
||||
call turing_rule 'E 1 1 left A' /* " " " " " " */
|
||||
call turing_init /*initialize tape to string(s). */
|
||||
call turing_machine /*go invoke the Turning machine. */
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────TURING_MACHINE subroutine───────────*/
|
||||
turing_machine ∙∙∙
|
||||
/*REXX program executes a Turing machine based on initial state, tape, and rules. */
|
||||
state = 'A' /*initialize the Turing machine state.*/
|
||||
term = 'H' /*a state that is used for the halt. */
|
||||
blank = 0 /*this character is a "true" blank. */
|
||||
call Turing_rule 'A 0 1 right B' /*define a rule for the Turing machine.*/
|
||||
call Turing_rule 'A 1 1 left C' /* " " " " " " " */
|
||||
call Turing_rule 'B 0 1 right C' /* " " " " " " " */
|
||||
call Turing_rule 'B 1 1 right B' /* " " " " " " " */
|
||||
call Turing_rule 'C 0 1 right D' /* " " " " " " " */
|
||||
call Turing_rule 'C 1 0 left E' /* " " " " " " " */
|
||||
call Turing_rule 'D 0 1 left A' /* " " " " " " " */
|
||||
call Turing_rule 'D 1 1 left D' /* " " " " " " " */
|
||||
call Turing_rule 'E 0 1 stay H' /* " " " " " " " */
|
||||
call Turing_rule 'E 1 0 left A' /* " " " " " " " */
|
||||
call Turing_init /*initialize the tape to some string(s)*/
|
||||
call TM /*go and invoke the Turning machine. */
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
TM: ∙∙∙
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
/*REXX pgm executes a Turing machine based on initial state, tape, rules*/
|
||||
state = 'A' /*initial Turing machine state. */
|
||||
term = 'halt' /*a state that is used for halt. */
|
||||
blank = 0 /*this character is a true blank.*/
|
||||
call turing_rule 'A 1 1 right A' /*define a rule for the machine. */
|
||||
call turing_rule 'A 2 3 right B' /* " " " " " " */
|
||||
call turing_rule 'A 0 0 left E' /* " " " " " " */
|
||||
call turing_rule 'B 1 1 right B' /* " " " " " " */
|
||||
call turing_rule 'B 2 2 right B' /* " " " " " " */
|
||||
call turing_rule 'B 0 0 left C' /* " " " " " " */
|
||||
call turing_rule 'C 1 2 left D' /* " " " " " " */
|
||||
call turing_rule 'C 2 2 left C' /* " " " " " " */
|
||||
call turing_rule 'C 3 2 left E' /* " " " " " " */
|
||||
call turing_rule 'D 1 1 left D' /* " " " " " " */
|
||||
call turing_rule 'D 2 2 left D' /* " " " " " " */
|
||||
call turing_rule 'D 3 1 right A' /* " " " " " " */
|
||||
call turing_rule 'E 1 1 left E' /* " " " " " " */
|
||||
call turing_rule 'E 0 0 right halt' /* " " " " " " */
|
||||
call turing_init 1 2 2 1 2 2 1 2 1 2 1 2 1 2 /*init. tape to string(s). */
|
||||
call turing_machine /*go invoke the Turning machine. */
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────TURING_MACHINE subroutine───────────*/
|
||||
turing_machine ∙∙∙
|
||||
/*REXX program executes a Turing machine based on initial state, tape, and rules. */
|
||||
state = 'A' /*the initial Turing machine state. */
|
||||
term = 'halt' /*a state that is used for the halt. */
|
||||
blank = 0 /*this character is a "true" blank. */
|
||||
call Turing_rule 'A 1 1 right A' /*define a rule for the Turing machine.*/
|
||||
call Turing_rule 'A 2 3 right B' /* " " " " " " " */
|
||||
call Turing_rule 'A 0 0 left E' /* " " " " " " " */
|
||||
call Turing_rule 'B 1 1 right B' /* " " " " " " " */
|
||||
call Turing_rule 'B 2 2 right B' /* " " " " " " " */
|
||||
call Turing_rule 'B 0 0 left C' /* " " " " " " " */
|
||||
call Turing_rule 'C 1 2 left D' /* " " " " " " " */
|
||||
call Turing_rule 'C 2 2 left C' /* " " " " " " " */
|
||||
call Turing_rule 'C 3 2 left E' /* " " " " " " " */
|
||||
call Turing_rule 'D 1 1 left D' /* " " " " " " " */
|
||||
call Turing_rule 'D 2 2 left D' /* " " " " " " " */
|
||||
call Turing_rule 'D 3 1 right A' /* " " " " " " " */
|
||||
call Turing_rule 'E 1 1 left E' /* " " " " " " " */
|
||||
call Turing_rule 'E 0 0 right halt' /* " " " " " " " */
|
||||
call Turing_init 1 2 2 1 2 2 1 2 1 2 1 2 1 2 /*initialize the tape to some string(s)*/
|
||||
call TM /*go and invoke the Turning machine. */
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
TM: ∙∙∙
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue