source: trunk/Examples/Others/utm.b

Last change on this file was 11, checked in by chronos, 12 years ago
  • Added: Some other examples from web.
File size: 18.4 KB
Line 
1[A universal Turing machine from Yurii Rogozhin's article "Small universal
2Turing machines", in Theoretical Computer Science, 168(2):215-240, 20 November
31996. Thus, a very direct proof that brainfuck is Turing-complete. For i/o
4formats and so on, read below; for fuller detail, dig up the article.
5
6If you just want a quick and complete test case, the input b1b1bbb1c1c11111d
7should produce the output 1c11111.
8
9Daniel B Cristofani (cristofdathevanetdotcom)
10http://www.hevanet.com/cristofd/brainfuck/
11
12
13
14This Turing machine achieves Turing-completeness not by simulating other
15Turing machines directly, but by simulating a Turing-complete class of
16tag-systems (a computational model invented by Emil Post and named after the
17children's game "tag"). A tag-system transforms strings over an alphabet A =
18{a[1], a[2], ... a[n], a[n+1]} as follows: a positive integer m is chosen, and
19so is a function P that maps each a[i] for 1<=i<=n to a string P(a[i]) over
20the alphabet A. Now:
21
221. if the string being transformed has fewer than m elements, the whole
23process stops now.
242. m elements are removed from the beginning of the string
253. call the first element removed a[k]; if k=n+1 the whole process stops now.
264. P(a[k]) is appended to the string.
275. steps 1-5 are repeated.
28
29The particular class of tag-systems this Turing machine simulates is the class
30where m=2, the initial string has length at least 2, and all P(a[i]) where
311<=i<=n are of the form a[n]a[n]B[i] where B[i] is some string over the
32alphabet A (B[i] is the empty string if and only if i=n).
33
34The input for this brainfuck program is mildly complex, and there is no error
35checking. The complexity comes from the encoding of tag-systems in terms of
36Turing machine tape configurations. Note that the set of initial tape
37configurations that represent tag-systems from the above class is a small,
38though Turing-complete, subset of the set of possible initial tape
39configurations for this Turing machine; and the following brainfuck program is
40only designed to accept inputs from that subset.
41
42-The representation of a symbol a[i] from the alphabet A is a string of 1s
43which is one element longer than twice the combined length of all P(a[j])
44where 1<=j<i.
45
46-a value like P(a[i]) = a[n]a[n]a[w]a[x]...a[y]a[z] is represented as follows:
47b 1
48b 111...(as many as required to represent a[z] as described above) b
49b 111...(to represent a[y] as described above) b
50.
51.
52.
53b 111...(to represent a[x]) b
54b 111...(to represent a[w]) b
55b 111...(to represent a[n]) b
56b 111...(as many as for a[n] as described above, MINUS the number of 1s that
57represent a[i]; and no final b)
58
59-The function P is represented by listing all its outputs in the order
60P(a[n]), P(a[n-1]), ... P(a[2]), P(a[1]). The representation of P(a[n+1])=STOP
61is done for you by the brainfuck program.
62
63-The initial string a[q]a[r]...a[s]a[t] to be transformed by the tag-system is
64represented as
65111...(as many as required to represent a[q] as above) c
66111...(to represent a[r]) c
67.
68.
69.
70111...(to represent a[s]) c
71111...(to represent a[t]; note that there is no final c.)
72
73-The input to this program is a function P as described above, then a single
74b, then the initial string to be transformed. Run all the 1s, bs, and cs
75together in one line with nothing between, followed by a linefeed, or a period
76if a linefeed is problematic for your implementation.
77
78-The output format, if the program terminates, is the same as the input format
79for the initial string, and represents the final state of the transformed
80string, with a final a[n+1] appended due to a peculiarity of the Turing
81machine's algorithm.
82
83-An example.
84A tag-system over the alphabet A = {a[1], a[2], a[3], a[4]}, where m = 2 and:
85P(a[1]) = a[3]a[3]a[2]a[1]a[4]
86P(a[2]) = a[3]a[3]a[1]
87P(a[3]) = a[3]a[3]
88P(a[4]) = STOP
89
90meets the criteria above; and when applied to the initial string a[2]a[1]a[1]
91it gives:
92a[2]a[1]a[1]
93 a[1]a[3]a[3]a[1]
94 a[3]a[1]a[3]a[3]a[2]a[1]a[4]
95 a[3]a[3]a[2]a[1]a[4]a[3]a[3]
96 a[2]a[1]a[4]a[3]a[3]a[3]a[3]
97 a[4]a[3]a[3]a[3]a[3]a[3]a[3]a[1]
98 a[3]a[3]a[3]a[3]a[3]a[1]
99and then it's done.
100
101Now, the encoding:
102
103a[1] is 1
104a[2] is 11111111111
105a[3] is 11111111111111111
106a[4] is 111111111111111111111
107
108P(a[1]) is b1 b111111111111111111111b b1b b11111111111b b11111111111111111b
109b1111111111111111
110P(a[2]) is b1 b1b b11111111111111111b b111111
111P(a[3]) is b1 b11111111111111111b b
112
113the initial string is 11111111111c1c1
114
115and so the whole input is
116
117b1 b11111111111111111b b
118b1 b1b b11111111111111111b b111111
119b1 b111111111111111111111b b1b b11111111111b b11111111111111111b
120b1111111111111111
121b
12211111111111c1c1
123
124which when run together for input to the program becomes
125
126b1b11111111111111111bbb1b1bb11111111111111111bb111111b1b111111111111111111111bb1bb11111111111bb11111111111111111bb1111111111111111b11111111111c1c1
127
128The output should be
12911111111111111111 c
13011111111111111111 c
13111111111111111111 c
13211111111111111111 c
13311111111111111111 c
1341 c
135111111111111111111111
136
137--that is,
13811111111111111111c11111111111111111c11111111111111111c11111111111111111c11111111111111111c1c111111111111111111111
139
140
141For those interested, the state table of the Turing machine itself is
14210<L1 201L2 30cR1 40cL2
14311<L1 210R2 311R3 410R4
1441b>R1 2b>L3 3b<R4 4bcL2
1451<0R1 2<>L2 3< H 4<
1461>bL1 2><R2 3>bR3 4><R4
1471c0R4 2cbR2 3c1R1 4cbR4
148where the initial state is 1, the blank symbol is "0", tape cells are set as
149per the input but with the termination code P(a[n+1])=STOP represented as a
150"< b" at the left end, and the head is initially at the first "1" in the code
151for the initial string. If and when the machine halts, the head is at the
152leftmost cell, a "<"; the representations of the rules are intact, in a form
153isomorphic to their original form (each "b" replaced with ">" and each "1"
154unchanged); they are followed by a series of "1" cells, then a "c" (the
155leftmost one at that time), then the cells representing the final state of the
156transformed string, then a "c" and a sequence of "1" cells representing a[n+1]
157as mentioned.
158
159The minimal test case b1b1bbb1c1c11111 represents the tag-system where P(a[1])
160= a[1]a[1] and P(a[2]) = STOP, applied to the string a[1]a[1]a[2]. This runs
161for 518 steps of the Turing machine, exercising all 23 Turing machine
162instructions, before halting with the output string a[1].
163
164
165Here is the brainfuck program that implements this Turing machine. The basic
166memory layout is as follows.
167Each Turing machine cell is represented by a brainfuck cell, with the symbols
168"0 1 b < > c" represented by 0, 1, 2, 3, 4, 5 respectively. The brainfuck
169cells representing the Turing machine cells are laid out contiguously from the
170beginning of the tape, except that the head of the Turing machine is
171represented by a gap of three brainfuck cells, just to the left of the
172brainfuck cell that represents the current Turing machine cell. At the start
173of each cycle, the rightmost of these three cells holds the Turing machine
174state, where states 1-4 are represented by 1-4 and "halt" (here treated as a
175separate state) is represented by 0. The other two cells hold zeroes.
176
177Now to walk through the code:
178
179+++>++>>>+[
180
181Set up 3 2 0 0 1, representing "< b" and the Turing machine head, in the
182initial state 1; we can put this at the left end of the brainfuck array
183because the Turing machine will never go left from the "<".
184Next, start the main input-processing loop. Each time through this loop, we
185begin at the rightmost tape cell that we have filled so far, or at the state
186cell of the Turing machine head if it is to the right of all tape cells (as it
187is initially). Each time through, we read a character; if it is "1" or "c", we
188add the appropriate code to the right end of the tape; if it is a "b", we not
189only add the code to the end of the tape but also move the head to the right
190of it, since the head must follow the rightmost "b" when the Turing machine
191starts; if the input character is a linefeed or other terminator, we add
192nothing to the tape but position the brainfuck pointer at the zero that
193follows the last filled tape cell, thus ending this loop.
194
195>>,[>+++++<[[->]<<]<[>]>]
196
197Read input, producing
198... x 0 'i 0 ...
199where "x" is a nonzero cell and "i" is the input.
200While i is nonzero, run this loop:
201-set up
202... x 0 'i 5 0 ...
203-If the input was six or greater, the [[->]<<] part will five times decrement
204both i and 5; the sixth time, it will only decrement i, and move to the cell
205left of i, producing
206... x '0 i 0 0 ...
207following which the code <[>]> will restore the pointer to i:
208... x 0 'i 0 0 ...
209In short, while i is at least six, the net effect of each iteration of the
210loop [>+++++<[[->]<<]<[>]>] is to reduce i by 6; so repeated iterations will
211change i to i mod 6; call this j. Then the loop will be run once more.
212Now legitimate input characters give the values 1, 2, 3, 4 when reduced mod 6;
213"1" gives 1, "b" gives 2, "c" gives 3, and linefeed and "." and "d" all give
2144. On the last run through the loop [>+++++<[[->]<<]<[>]>] , the [[->]<<] part
215will decrement both j and 5 repeatedly until j is zeroed, i.e. it will zero j
216while reducing 5 by j, leaving
217... x 0 '0 r 0 ...
218where r is 5-j. The code <[>]> leaves this configuration unchanged, and the
219loop exits.
220
221>-[<<+++++>>-[<<---->>-[->]<]]
222
223If r was 1, i mod 6 was 4, meaning a terminator. So we don't fill any tape
224cell but leave
225... x 0 0 '0 ...
226If r was 2, i mod 6 was 3, meaning "c". So we set up
227... x 5 0 '0 ...
228If r was 3, i mod 6 was 2, meaning "b". In this case we set up
229... x 1 0 '0 ...
230and skip the innermost [->] loop, then step left leaving
231... x 1 '0 0 ...
232(note the pointer position; only in this case is the pointer immediately to
233the right of a nonzero cell.)
234If r was 4, i mod 6 was 1, meaning "1". In this case we set up
235... x 1 0 '1 0 ...
236and enter the inner [->] loop, resulting in
237... x 1 0 0 '0 ...
238after which we step left, producing
239... x 1 0 '0 ...
240
241<[<-<[<]+<+[>]<<+>->>>]
242
243Now we step left. If and only if i was "b", we will enter this loop which will
244move the Turing machine head. Now the situation, including the head which is
245somewhere off to the left, is
246... 2 0 0 1 y ... y y y y '1 0 0 0 ...
247where each y is a 1 (since that is the only symbol that occurs between one b
248and the next b, in input strings that represent tag-systems).
249Now we zero one y and scan left:
250... 2 0 '0 1 y ... y y y 0 1 0 0 0 ...
251set two more 1's, and scan right (these two, and the 1 that was formerly the
252state cell of the head, now serve as tape symbols, so we label them y);
253... 2 y y y y ... y y y '0 1 0 0 0 ...
254next, we set up the head at its new position, and we set the cell to the left
255of it to b, and move the pointer just right of the 1 which is the state:
256... 2 y y y y ... y 2 0 0 1 '0 0 0 ...
257and now we're to the right of the rightmost nonzero cell, as we should be, so
258we end the head-moving loop.
259
260(In the degenerate case where we received two b's in a row, the process goes:
261...2 0 0 1 '1 0 0 0 ...
262...2 0 '0 0 1 0 0 0 ...
263...2 y y '0 1 0 0 0 ...
264...2 2 0 0 1 '0 0 0 ...
265as it should.)
266
267After either performing or skipping that loop, there are four possibilities
268corresponding to the four possible inputs.
269... x x x x 1 '0 ... if the input was a "1"
270... x 2 0 0 1 '0 ... if the input was a "b"
271... x x x x 5 '0 ... if the input was a "c"
272... x x x x 0 '0 ... if the input was a terminator.
273
274<]<[<]>[
275
276Now we move left and close the loop. If the input was anything but a
277terminator, this puts us at the rightmost nonzero cell and we repeat the
278input-processing loop. If the input was a terminator, this puts us at the zero
279after the rightmost nonzero cell, and the input is already finished; then we
280scan left to the gap that represents the Turing machine head, and position the
281pointer at the state cell. Then we begin the main loop, which will be executed
282once for each step of the Turing machine's operation, stopping when the state
283cell holds 0 (representing the halt state).
284
285-[>++++++<-]>[<+>-]
286
287At the beginning of each iteration of the main processing loop, the
288configuration is
289... w x 0 0 's y z ...
290where w, x, y, z are tape cells, with y being the current tape cell, and s is
291the state (1-4). First we combine the current state with the current symbol;
292we add (6*(s-1)) onto y, then move the result back into the former location of
293s. Call the combination g; its values range from 0 to 23, one for each
294state-symbol combination.
295... w x 0 0 '0 g z ...
296... w x 0 0 g '0 z ...
297
298Now we have to use g to select a new symbol, a new state, and a direction to
299move the head. We will provisionally move the head right one cell, and set a
300direction flag; if that flag is nonzero, we will move the head left two cells,
301resulting in a total movement of one cell to the left. That is, we want to use
302g in
303... w x 0 0 g 0 z ...
304to construct an appropriate
305... w x y d 0 s z ...
306where d is the direction flag, s is the new state, and y is the new symbol;
307then if d is nonzero ("move left after all") we want to shift this to produce
308... w 0 0 s x y z ...
309
310The way we use g to pick new values for s, y, and d is a very general scheme
311for mathematical functions of one variable, and this UTM is one place we need
312the generality. (See my rot13.b for a place where I didn't need the
313generality, and used this method anyway, leading to comically inconcise but
314fast code.) The basic idea is like
315>set f(0)<[>set f(1)<-[>set f(2)<-[>set f(3)<-[...&c...]]]]
316
317The argument (in this case, g) is gradually decremented; if it was (say) five,
318the program will enter the five outermost loops of this nest but will skip the
319sixth and those inside it, since by that point the argument will have been
320zeroed. So we just make sure the output cells have the right values for f(5)
321at that point, by setting them inside the fifth loop but outside the sixth.
322
323
324We get the outputs from the state table, naturally, reading down the columns.
325Recall that "01b<>c" map to 0 1 2 3 4 5, and that "d=1" means "left".
326
327+<<<+++>+>
328g>=0; set s=1, y=3, d=1
329
330[-
331g>=1; same values. There's some continuity in the table; only changes from one
332combination to the next will be commented hereafter.
333
334[<<+>->-
335g>=2; y=4, d=0
336
337[<<[-]>>-
338g>=3; y=0
339
340[<<++>+>-
341g>=4; y=2, d=1
342
343[<<-->->>+++<-
344g>=5; y=0, d=0, s=4
345
346[<<+>+>>--<-
347g>=6; y=1, d=1, s=2
348
349[<<->->-
350g>=7; y=0, d=0
351
352[<<++++>+>>+<-
353g>=8; y=4, d=1, s=3
354
355[>-<-
356g>=9; s=2
357
358[<<->->-
359g>=10; y=3, d=0
360
361[<<->>-
362g>=11; y=2
363
364[<<+++>>>-<-
365g>=12; y=5, s=1
366
367[<<---->>>++<-
368g>=13; y=1, s=3
369
370[<<++>>>+<-
371g>=14; y=3, s=4
372
373[>[-]<-
374g>=15; s=0 (this is the halt condition; having it produce d=0 is useful, since
375moving left would take us outside the brainfuck array, and the capability of
376actually not moving the head has been omitted as unnecessary, given that we're
377only going to output the part of the tape that holds the final state of the
378transformed string.)
379
380[<<->>>+++<-
381g>=16; y=2, s=3
382
383[<<->>>--<-
384g>=17; y=1, s=1
385
386[<<++++>+>>+<-
387g>=18; y=5, d=1, s=2
388
389[<<[-]>->>++<-
390g>=19; y=0, d=0, s=4
391
392[<<+++++>+>>--<-
393g>=20; y=5, d=1, s=2
394
395[<->>++<[<<->>-]]
396Here's a tricky part. g==21 is never produced by the Turing machine from
397correct input, so the remaining states to consider are g==22 and g==23, which
398should give (y=3, d=0, s=4) and (y=2, d=0, s=4) respectively. So we set up
399d=0, s=4 which are common to both, then we take the 2 or 3 that remains in g
400and subtract it from y to produce the right result for y.
401
402]]]]]]]]]]]]]]]]]]]]
403
404We arrive here when g has been zeroed. Again, the layout now is
405... w x y d '0 s z ...
406and y, d, and s have the correct values.
407
408<[->>[<<+>>-]<<<[>>>+<<<-]<[>>>+<<<-]]
409
410If d==1 we do:
411... w x y '0 0 s z ...
412... w x y s 0 '0 z ...
413... w x '0 s 0 y z ...
414... w '0 0 s x y z ...
415to move the head left and leave the pointer at the leftmost cell of the head,
416where it would be if d had been 0 also.
417
418>>]
419
420Go to the state cell, and if it is nonzero (not the halt state) go through the
421main Turing machine loop again.
422
423>[-[---[-<]]>]
424
425Now the Turing machine has halted. The situation is
4264 0 0 '0 x x ... x x 0 0 0 ...
427where each x is either 1, 4, or 5, and the leftmost 5 ("c") marks the start of
428the transformed string. So we scan through the tape looking for that 5, and
429incidentally clearing the tape as we go. When we find a 1, we decrement it,
430skip the loop [---[-<]], move right, and start fresh. When we find a 4, we
431decrement it down to 0, skip the loop [-<], move right, and start fresh. When
432we find a 5, we decrement it down to 0, move left, move right to the space the
4335 occupied (now 0), and end this loop.
434
435>[+++[<+++++>--]>]
436
437Now we want to output the part of the tape that represents the transformed
438string; the situation is
439... 0 '0 x x x ... x x x 0 0 0 ...
440where each x is either 1, representing "1", or 5, representing "c". To
441transform each to the right ASCII value we first add 3, producing 4 for "1"
442and 8 for "c", then multiply the resulting value by 5/2 while moving it left;
443this is safe because we know the value is even. We scan through the string
444this way, after which it consists of 10s (for "1") and 20s (for "c"), and the
445whole string has been shifted one cell left.
446
447+<++[[>+++++<-]<]
448
449Now we set two more cells to make the linefeed, producing
450... 0 x x x ... x x x '2 1 0 0 ...
451and multiply each cell by five while moving it right, producing
452... '0 0 x x x ... x x x 11 0 0 ...
453where each x is either 50 (for "1") or 100 (for "c").
454
455>>[-.>]
456
457Now we scan right, reducing each cell by one and outputting it; the values are
45849 (ASCII for "1"), 99 (ASCII for "c"), and 10 (ASCII for the final linefeed).
459After this loop there are no more commands, so the program terminates.]
460
461
462The entire program again without comments:
463
464+++>++>>>+[>>,[>+++++<[[->]<<]<[>]>]>-[<<+++++>>-[<<---->>-[->]<]]
465<[<-<[<]+<+[>]<<+>->>>]<]<[<]>[-[>++++++<-]>[<+>-]+<<<+++>+>
466 [-
467 [<<+>->-
468 [<<[-]>>-
469 [<<++>+>-
470 [<<-->->>+++<-
471 [<<+>+>>--<-
472 [<<->->-
473 [<<++++>+>>+<-
474 [>-<-
475 [<<->->-
476 [<<->>-
477 [<<+++>>>-<-
478 [<<---->>>++<-
479 [<<++>>>+<-
480 [>[-]<-
481 [<<->>>+++<-
482 [<<->>>--<-
483 [<<++++>+>>+<-
484 [<<[-]>->>++<-
485 [<<+++++>+>>--<-
486 [<->>++<
487 [<<->>-
488]]]]]]]]]]]]]]]]]]]]]]<[->>[<<+>>-]<<<[>>>+<<<-]<[>>>+<<<-]]>>]
489>[-[---[-<]]>]>[+++[<+++++>--]>]+<++[[>+++++<-]<]>>[-.>]
490
491
Note: See TracBrowser for help on using the repository browser.