Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -1,10 +1,22 @@
One of the foundational mathematical constructs behind computer science is the [[wp:Universal Turing machine|universal Turing Machine]]. Indeed one way to definitively prove that a language is Turing complete is to implement a universal Turing machine in it.
One of the foundational mathematical constructs behind computer science
is the [[wp:Universal Turing machine|universal Turing Machine]].
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 of taking the definition of any other Turing machine and executing it. You will not, of course, have an infinite tape, but you should emulate this as much as is possible. The three permissible actions on the tape are "left", "right" and "stay".
For this task you would 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.
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.
The three permissible actions on the tape are "left", "right" and "stay".
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

View file

@ -0,0 +1,35 @@
(defun turing (initial terminal blank rules tape &optional (verbose NIL))
(labels ((combine (front back)
(if front
(combine (cdr front) (cons (car front) back))
back))
(update-tape (old-front old-back new-content move)
(cond ((eq move 'right)
(list (cons new-content old-front)
(cdr old-back)))
((eq move 'left)
(list (cdr old-front)
(list* (car old-front) new-content (cdr old-back))))
(T (list old-front
(cons new-content (cdr old-back))))))
(show-tape (front back)
(format T "~{~a~}[~a]~{~a~}~%"
(nreverse (subseq front 0 (min 10 (length front))))
(or (car back) blank)
(subseq (cdr back) 0 (min 10 (length (cdr back)))))))
(loop for back = tape then new-back
for front = '() then new-front
for state = initial then new-state
for content = (or (car back) blank)
for (new-state new-content move) = (gethash (cons state content) rules)
for (new-front new-back) = (update-tape front back new-content move)
until (equal state terminal)
do (when verbose
(show-tape front back))
finally (progn
(when verbose
(show-tape front back))
(return (combine front back))))))

View file

@ -0,0 +1,37 @@
(defun turing (initial terminal blank rules tape &optional (verbose NIL))
(labels ((run (state front back)
(if (equal state terminal)
(progn
(when verbose
(show-tape front back))
(combine front back))
(let ((current-content (or (car back) blank)))
(destructuring-bind
(new-state new-content move)
(gethash (cons state current-content) rules)
(when verbose
(show-tape front back))
(cond ((eq move 'right)
(run new-state
(cons new-content front)
(cdr back)))
((eq move 'left)
(run new-state
(cdr front)
(list* (car front) new-content (cdr back))))
(T (run new-state
front
(cons new-content (cdr back)))))))))
(show-tape (front back)
(format T "~{~a~}[~a]~{~a~}~%"
(nreverse (subseq front 0 (min 10 (length front))))
(or (car back) blank)
(subseq (cdr back) 0 (min 10 (length (cdr back))))))
(combine (front back)
(if front
(combine (cdr front) (cons (car front) back))
back)))
(run initial '() tape)))

View file

@ -0,0 +1,55 @@
;; Helper function for creating the rules table
(defun make-rules-table (rules-list)
(let ((rules (make-hash-table :test 'equal)))
(loop for (state content new-content dir new-state) in rules-list
do (setf (gethash (cons state content) rules)
(list new-state new-content dir)))
rules))
(format T "Simple incrementer~%")
(turing 'q0 'qf 'B (make-rules-table '((q0 1 1 right q0) (q0 B 1 stay qf))) '(1 1 1) T)
(format T "Three-state busy beaver~%")
(turing 'a 'halt 0
(make-rules-table '((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)))
'() T)
(format T "Sort (final tape)~%")
(format T "~{~a~}~%"
(turing 'A 'H 0
(make-rules-table '((A 1 1 right A)
(A 2 3 right B)
(A 0 0 left E)
(B 1 1 right B)
(B 2 2 right B)
(B 0 0 left C)
(C 1 2 left D)
(C 2 2 left C)
(C 3 2 left E)
(D 1 1 left D)
(D 2 2 left D)
(D 3 1 right A)
(E 1 1 left E)
(E 0 0 right H)))
'(2 1 2 2 2 1 1)))
(format T "5-state busy beaver (first 20 cells)~%")
(format T "~{~a~}...~%"
(subseq (turing 'A 'H 0
(make-rules-table '((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)))
'())
0 20))

View file

@ -5,13 +5,11 @@ struct UTM(State, Symbol, bool doShow=true)
if (is(State == enum) && is(Symbol == enum)) {
static assert(is(typeof({ size_t x = State.init; })),
"State must to be usable as array index.");
static assert([EnumMembers!State]
.equal(EnumMembers!State.length.iota),
static assert([EnumMembers!State].equal(EnumMembers!State.length.iota),
"State must be a plain enum.");
static assert(is(typeof({ size_t x = Symbol.init; })),
"Symbol must to be usable as array index.");
static assert([EnumMembers!Symbol]
.equal(EnumMembers!Symbol.length.iota),
static assert([EnumMembers!Symbol].equal(EnumMembers!Symbol.length.iota),
"Symbol must be a plain enum.");
enum Direction { right, left, stay }
@ -23,16 +21,15 @@ if (is(State == enum) && is(Symbol == enum)) {
// The first index of this 'rules' matrix is a subtype of State
// because it can't contain H, but currently D can't enforce this,
// statically unlike Ada language.
Rule[EnumMembers!Symbol.length]
[EnumMembers!State.length - 1] mRules;
Rule[EnumMembers!Symbol.length][EnumMembers!State.length - 1] mRules;
static struct Rule {
Symbol toWrite;
Direction direction;
State nextState;
this(in Symbol toWrite_, in Direction direction_,
in State nextState_) pure nothrow {
this(in Symbol toWrite_, in Direction direction_, in State nextState_)
pure nothrow @safe @nogc {
this.toWrite = toWrite_;
this.direction = direction_;
this.nextState = nextState_;
@ -57,18 +54,18 @@ if (is(State == enum) && is(Symbol == enum)) {
const SymbolMap sMap;
size_t nSteps;
this(in ref TuringMachine t) pure /*nothrow*/ {
this(in ref TuringMachine t) pure nothrow @safe {
this.blank = EnumMembers!Symbol[0];
//tapeRight = t.input.empty ? [this.blank] : t.input.dup;
if (t.input.empty)
this.tapeRight = [this.blank];
else
this.tapeRight = t.input.dup; // Not nothrow.
this.tapeRight = t.input.dup;
this.position = 0;
this.sMap = t.symbolMap;
}
pure nothrow invariant() {
pure nothrow @safe @nogc invariant {
assert(this.tapeRight.length > 0);
if (this.position >= 0)
assert(this.position < this.tapeRight.length);
@ -76,18 +73,18 @@ if (is(State == enum) && is(Symbol == enum)) {
assert(this.position.abs <= this.tapeLeft.length);
}
Symbol readSymb() const pure nothrow {
Symbol readSymb() const pure nothrow @safe @nogc {
if (this.position >= 0)
return this.tapeRight[this.position];
else
return this.tapeLeft[this.position.abs - 1];
}
void showSymb() const {
void showSymb() const @safe {
this.write;
}
void writeSymb(in Symbol symbol) {
void writeSymb(in Symbol symbol) @safe {
static if (doShow)
showSymb;
if (this.position >= 0)
@ -96,19 +93,19 @@ if (is(State == enum) && is(Symbol == enum)) {
this.tapeLeft[this.position.abs - 1] = symbol;
}
void goRight() pure nothrow {
void goRight() pure nothrow @safe {
this.position++;
if (position > 0 && position == tapeRight.length)
tapeRight ~= blank;
}
void goLeft() pure nothrow {
void goLeft() pure nothrow @safe {
this.position--;
if (position < 0 && (position.abs - 1) == tapeLeft.length)
tapeLeft ~= blank;
}
void move(in Direction dir) pure nothrow {
void move(in Direction dir) pure nothrow @safe {
nSteps++;
final switch (dir) with (Direction) {
case left: goLeft; break;
@ -117,10 +114,9 @@ if (is(State == enum) && is(Symbol == enum)) {
}
}
string toString() const {
const pos = cast(int)tapeLeft.length + this.position + 4;
return format("...%-(%)...", tapeLeft.retro
.chain(tapeRight)
string toString() const @safe {
immutable pos = tapeLeft.length.signed + this.position + 4;
return format("...%-(%)...", tapeLeft.retro.chain(tapeRight)
.map!(s => sMap[s])) ~
'\n' ~
format("%" ~ pos.text ~ "s", "^") ~
@ -128,25 +124,22 @@ if (is(State == enum) && is(Symbol == enum)) {
}
}
void show() const {
void show() const @safe {
head.showSymb;
}
this(in ref TuringMachine tm_) {
static assert(__traits(compiles, State.H),
"State needs a 'H' (Halt).");
this(in ref TuringMachine tm_) @safe {
static assert(__traits(compiles, State.H), "State needs a 'H' (Halt).");
immutable errMsg = "Invalid input.";
auto runningStates = remove!(s => s == State.H)
([EnumMembers!State]);
auto runningStates = remove!(s => s == State.H)([EnumMembers!State]);
enforce(!runningStates.empty, errMsg);
enforce(tm_.rules.length == EnumMembers!State.length - 1,
errMsg);
enforce(tm_.rules.length == EnumMembers!State.length - 1, errMsg);
enforce(State.H !in tm_.rules, errMsg);
enforce(runningStates.canFind(tm_.initialState), errMsg);
// Create a matrix to reduce running time.
foreach (const State st, const rset; tm_.rules)
foreach (const Symbol sy, const rule; rset)
foreach (immutable State st, const rset; tm_.rules)
foreach (immutable Symbol sy, immutable rule; rset)
mRules[st][sy] = rule;
this.tm = tm_;
@ -165,7 +158,7 @@ if (is(State == enum) && is(Symbol == enum)) {
}
}
void main() {
void main() @safe {
"Incrementer:".writeln;
enum States1 : ubyte { A, H }
enum Symbols1 : ubyte { s0, s1 }

View file

@ -0,0 +1,177 @@
package turing
type Symbol byte
type Motion byte
const (
Left Motion = 'L'
Right Motion = 'R'
Stay Motion = 'N'
)
type Tape struct {
data []Symbol
pos, left int
blank Symbol
}
// NewTape returns a new tape filled with 'data' and position set to 'start'.
// 'start' does not need to be range, the tape will be extended if required.
func NewTape(blank Symbol, start int, data []Symbol) *Tape {
t := &Tape{
data: data,
blank: blank,
}
if start < 0 {
t.Left(-start)
}
t.Right(start)
return t
}
func (t *Tape) Stay() {}
func (t *Tape) Data() []Symbol { return t.data[t.left:] }
func (t *Tape) Read() Symbol { return t.data[t.pos] }
func (t *Tape) Write(s Symbol) { t.data[t.pos] = s }
func (t *Tape) Dup() *Tape {
t2 := &Tape{
data: make([]Symbol, len(t.Data())),
blank: t.blank,
}
copy(t2.data, t.Data())
t2.pos = t.pos - t.left
return t2
}
func (t *Tape) String() string {
s := ""
for i := t.left; i < len(t.data); i++ {
b := t.data[i]
if i == t.pos {
s += "[" + string(b) + "]"
} else {
s += " " + string(b) + " "
}
}
return s
}
func (t *Tape) Move(a Motion) {
switch a {
case Left:
t.Left(1)
case Right:
t.Right(1)
case Stay:
t.Stay()
}
}
const minSz = 16
func (t *Tape) Left(n int) {
t.pos -= n
if t.pos < 0 {
// Extend left
var sz int
for sz = minSz; cap(t.data[t.left:])-t.pos >= sz; sz <<= 1 {
}
newd := make([]Symbol, sz)
newl := len(newd) - cap(t.data[t.left:])
n := copy(newd[newl:], t.data[t.left:])
t.data = newd[:newl+n]
t.pos += newl - t.left
t.left = newl
}
if t.pos < t.left {
if t.blank != 0 {
for i := t.pos; i < t.left; i++ {
t.data[i] = t.blank
}
}
t.left = t.pos
}
}
func (t *Tape) Right(n int) {
t.pos += n
if t.pos >= cap(t.data) {
// Extend right
var sz int
for sz = minSz; t.pos >= sz; sz <<= 1 {
}
newd := make([]Symbol, sz)
n := copy(newd[t.left:], t.data[t.left:])
t.data = newd[:t.left+n]
}
if i := len(t.data); t.pos >= i {
t.data = t.data[:t.pos+1]
if t.blank != 0 {
for ; i < len(t.data); i++ {
t.data[i] = t.blank
}
}
}
}
type State string
type Rule struct {
State
Symbol
Write Symbol
Motion
Next State
}
func (i *Rule) key() key { return key{i.State, i.Symbol} }
func (i *Rule) action() action { return action{i.Write, i.Motion, i.Next} }
type key struct {
State
Symbol
}
type action struct {
write Symbol
Motion
next State
}
type Machine struct {
tape *Tape
start, state State
transition map[key]action
l func(string, ...interface{}) // XXX
}
func NewMachine(rules []Rule) *Machine {
m := &Machine{transition: make(map[key]action, len(rules))}
if len(rules) > 0 {
m.start = rules[0].State
}
for _, r := range rules {
m.transition[r.key()] = r.action()
}
return m
}
func (m *Machine) Run(input *Tape) (int, *Tape) {
m.tape = input.Dup()
m.state = m.start
for cnt := 0; ; cnt++ {
if m.l != nil {
m.l("%3d %4s: %v\n", cnt, m.state, m.tape)
}
sym := m.tape.Read()
act, ok := m.transition[key{m.state, sym}]
if !ok {
return cnt, m.tape
}
m.tape.Write(act.write)
m.tape.Move(act.Motion)
m.state = act.next
}
}

View file

@ -0,0 +1,71 @@
package main
import (
".." // XXX path to above turing package
"fmt"
)
func main() {
var incrementer = turing.NewMachine([]turing.Rule{
{"q0", '1', '1', turing.Right, "q0"},
{"q0", 'B', '1', turing.Stay, "qf"},
})
input := turing.NewTape('B', 0, []turing.Symbol{'1', '1', '1'})
cnt, output := incrementer.Run(input)
fmt.Println("Turing machine halts after", cnt, "operations")
fmt.Println("Resulting tape:", output)
var beaver = turing.NewMachine([]turing.Rule{
{"a", '0', '1', turing.Right, "b"},
{"a", '1', '1', turing.Left, "c"},
{"b", '0', '1', turing.Left, "a"},
{"b", '1', '1', turing.Right, "b"},
{"c", '0', '1', turing.Left, "b"},
{"c", '1', '1', turing.Stay, "halt"},
})
cnt, output = beaver.Run(turing.NewTape('0', 0, nil))
fmt.Println("Turing machine halts after", cnt, "operations")
fmt.Println("Resulting tape:", output)
beaver = turing.NewMachine([]turing.Rule{
{"A", '0', '1', turing.Right, "B"},
{"A", '1', '1', turing.Left, "C"},
{"B", '0', '1', turing.Right, "C"},
{"B", '1', '1', turing.Right, "B"},
{"C", '0', '1', turing.Right, "D"},
{"C", '1', '0', turing.Left, "E"},
{"D", '0', '1', turing.Left, "A"},
{"D", '1', '1', turing.Left, "D"},
{"E", '0', '1', turing.Stay, "H"},
{"E", '1', '0', turing.Left, "A"},
})
cnt, output = beaver.Run(turing.NewTape('0', 0, nil))
fmt.Println("Turing machine halts after", cnt, "operations")
fmt.Println("Resulting tape has", len(output.Data()), "cells")
var sort = turing.NewMachine([]turing.Rule{
// Moving right, first b→B;s1
{"s0", 'a', 'a', turing.Right, "s0"},
{"s0", 'b', 'B', turing.Right, "s1"},
{"s0", ' ', ' ', turing.Left, "se"},
// Conintue right to end of tape → s2
{"s1", 'a', 'a', turing.Right, "s1"},
{"s1", 'b', 'b', turing.Right, "s1"},
{"s1", ' ', ' ', turing.Left, "s2"},
// Continue left over b. a→b;s3, B→b;se
{"s2", 'a', 'b', turing.Left, "s3"},
{"s2", 'b', 'b', turing.Left, "s2"},
{"s2", 'B', 'b', turing.Left, "se"},
// Continue left until B→a;s0
{"s3", 'a', 'a', turing.Left, "s3"},
{"s3", 'b', 'b', turing.Left, "s3"},
{"s3", 'B', 'a', turing.Right, "s0"},
// Move to tape start → halt
{"se", 'a', 'a', turing.Left, "se"},
{"se", ' ', ' ', turing.Right, "see"},
})
input = turing.NewTape(' ', 0, []turing.Symbol("abbabbabababab"))
cnt, output = sort.Run(input)
fmt.Println("Turing machine halts after", cnt, "operations")
fmt.Println("Resulting tape:", output)
}

View file

@ -1,5 +1,6 @@
".@(('utm=. '),,)@(];._2)@(noun=. ".@('(0 : 0)'"_))_ NB. Fixed tacit universal Turing machine code...
". noun define -. CRLF NB. Fixed tacit universal Turing machine code...
utm=.
(((":@:(]&:>)@:(6&({::)) ,: (":@] 9&({::))) ,. ':'"_) ,. 2&({::) >@:(((
48 + ]) { a."_)@[ ; (] $ ' '"_) , '^'"_) 3&({::))@:([ (0 0 $ 1!:2&2)@:(
'A changeless cycle was detected!'"_)^:(-.@:(_1"_ = 1&({::))))@:((((3&(

View file

@ -1,7 +1,9 @@
Noun=. ".@('(0 : 0)'"_)
NB. Simple Incrementer...
NB. 0 1 Tape Symbol Scan
NB. S p m g p m g (p,m,g) → (print,move,goto)
QS=. (noun _) ; 0 NB. Reading the transition table and setting the initial state
QS=. (Noun _) ; 0 NB. Reading the transition table and setting the initial state
0 1 0 _1 1 1 0
)
TPF=. 1 1 1 ; 0 ; 1 NB. Setting the tape, its pointer and the display frequency

View file

@ -1,7 +1,7 @@
NB. Three-state busy beaver..
NB. 0 1 Tape Symbol Scan
NB. S p m g p m g (p,m,g) → (print,move,goto)
QS=. (noun _) ; 0 NB. Reading the transition table and setting the initial state
QS=. (Noun _) ; 0 NB. Reading the transition table and setting the initial state
0 1 1 1 1 _1 2
1 1 _1 0 1 1 1
2 1 _1 1 1 0 _1

View file

@ -1,7 +1,7 @@
NB. Sorting stress test...
NB. 0 1 2 3 Tape Symbol Scan
NB. S p m g p m g p m g p m g (p,m,g) ➜ (print,move,goto)
QS=. (noun _) ; 0 NB. Reading the transition table and setting the initial state
QS=. (Noun _) ; 0 NB. Reading the transition table and setting the initial state
0 0 _1 4 1 1 0 3 1 1 _ _ _
1 0 _1 2 1 1 1 2 1 1 _ _ _
2 _ _ _ 2 _1 3 2 _1 2 2 _1 4

View file

@ -0,0 +1,18 @@
left = 1; right = -1; stay = 0;
cmp[s_] := ToExpression[StringSplit[s, ","]];
utm[rules_, initial_, head_] :=
Module[{tape = initial, rh = head, n = 1},
Clear[nxt];
nxt[state_, field_] :=
nxt[state, field] = Position[rules, {rules[[state, 5]], field, _, _, _}][[1, 1]];
n = Position[rules, {rules[[n, 1]], BitGet[tape, rh], _, _, _}][[1,1]];
While[rules[[n, 4]] != 0,
If[rules[[n, 3]] != BitGet[tape, rh],
If[rules[[n, 3]] == 1, tape = BitSet[tape, rh],
tape = BitClear[tape, rh]]];
rh = rh + rules[[n, 4]];
If[rh < 0, rh = 0; tape = 2*tape];
n = nxt[n, BitGet[tape, rh]];
]; {tape, rh}
];
];

View file

@ -0,0 +1,18 @@
printMachine[tape_,pos_]:=(mach=IntegerString[tape,2];
ptr=StringReplace[mach,{"0"-> " ","1"->" "}];
Print[mach];Print[StringInsert[ptr,"^",StringLength[ptr]-pos]];);
simpleIncr={"q0,1,1,right,q0","q0,B,1,stay,qf"};
simpleIncr=Map[cmp,simpleIncr]/.B->0;
fin=utm[simpleIncr,7,2];
printMachine[fin[[1]],fin[[2]]];
busyBeaver3S={
"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"};
fin=utm[Map[cmp,busyBeaver3S],0,0];
printMachine[fin[[1]],fin[[2]]];

View file

@ -0,0 +1,17 @@
probable5S={
"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"};
fin=utm[Map[cmp,probable5S],0,0];
]
fin[[1]]//N
3.254757786465838*10^3698

View file

@ -0,0 +1,76 @@
# Finite state machine
(de turing (Tape Init Halt Blank Rules Verbose)
(let
(Head 1
State Init
Rule NIL
S 'start
C (length Tape))
(catch NIL
(loop
(state 'S
(start 'print
(when (=0 C)
(setq Tape (insert Head Tape Blank))
(inc 'C) ) )
(print 'lookup
(when Verbose
(for (N . I) Tape
(if (= N Head)
(print (list I))
(prin I) ) )
(prinl) )
(when (= State Halt) (throw NIL) ) )
(lookup 'do
(setq Rule
(find
'((X)
(and
(= (car X) State)
(= (cadr X) (car (nth Tape Head))) ) )
Rules ) ) )
(do 'step
(setq Tape (place Head Tape (caddr Rule))) )
(step 'print
(cond
((= (cadddr Rule) 'R) (inc 'Head))
((= (cadddr Rule) 'L) (dec 'Head)) )
(cond
((< Head 1)
(setq Tape (insert Head Tape Blank))
(inc 'C)
(one Head) )
((> Head C)
(setq Tape (insert Head Tape Blank))
(inc 'C) ) )
(setq State (last Rule)) ) ) ) ) )
Tape )
(println "Simple incrementer")
(turing '(1 1 1) 'A 'H 'B '((A 1 1 R A) (A B 1 S H)) T)
(println "Three-state busy beaver")
(turing '() 'A 'H 0
'((A 0 1 R B)
(A 1 1 L C)
(B 0 1 L A)
(B 1 1 R B)
(C 0 1 L B)
(C 1 1 S H)) T )
(println "Five-state busy beaver")
(let Tape (turing '() 'A 'H 0
'((A 0 1 R B)
(A 1 1 L C)
(B 0 1 R C)
(B 1 1 R B)
(C 0 1 R D)
(C 1 0 L E)
(D 0 1 L A)
(D 1 1 L D)
(E 0 1 S H)
(E 1 0 L A)) NIL)
(println '0s: (cnt '((X) (= 0 X)) Tape))
(println '1s: (cnt '((X) (= 1 X)) Tape)) )
(bye)