├── draw_turing_machine.pl ├── busy-beaver.py ├── busy-beaver.cpp └── readme.txt /draw_turing_machine.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # Peteris Krumins (peter@catonmat.net) 4 | # http://www.catonmat.net -- good coders code, great reuse 5 | # 6 | # Turing Machine tape drawer. 7 | # More info at: http://www.catonmat.net/blog/busy-beaver 8 | # 9 | # Version 1.1 10 | # 11 | 12 | use warnings; 13 | use strict; 14 | use GD; 15 | 16 | $|++; 17 | 18 | my $input_file = shift or die 'Usage: $0 '; 19 | my $cell_size = shift || 4; 20 | my $im_file = "$input_file.png"; 21 | 22 | sub line_count { 23 | my $count = 0; 24 | open my $fh, '<', shift or die $!; 25 | $count += tr/\n/\n/ while sysread($fh, $_, 2**20); 26 | return $count; 27 | } 28 | 29 | sub get_last_line { 30 | my $file = shift; 31 | my $last_line = `tail -1 $file`; 32 | chomp $last_line; 33 | return $last_line; 34 | } 35 | 36 | my $nr_lines = line_count $input_file; 37 | my $last_line = get_last_line $input_file; 38 | my $last_width = length($last_line); 39 | 40 | my ($width, $height) = ($cell_size*$last_width, $cell_size*$nr_lines); 41 | 42 | my $im = GD::Image->new($width, $height); 43 | my $white = $im->colorAllocate(255,255,255); 44 | my $dark = $im->colorAllocate(40, 40, 40); 45 | 46 | my ($x, $y) = (0, $height-$cell_size); 47 | 48 | print "Starting to draw the image. Total states: $nr_lines.\n"; 49 | print "It will be $width x $height pizels in size.\n"; 50 | 51 | my $prev_line; 52 | my ($pad_left, $pad_right) = (0, 0); 53 | 54 | sub pad { 55 | my ($line, $left, $right) = @_; 56 | return '0'x$left . $line . '0'x$right; 57 | } 58 | 59 | open my $fh, "-|", "/usr/bin/tac $input_file" or die $!; 60 | while (<$fh>) { 61 | chomp; 62 | print "." if $. % 10 == 0; 63 | print "($.)" if $. % 500 == 0; 64 | 65 | $prev_line = $_ unless defined $prev_line; 66 | 67 | my $new_line; 68 | if (length $_ != length $prev_line) { 69 | if ($prev_line =~ /0$/) { 70 | $pad_right++; 71 | } 72 | elsif ($prev_line =~ /^0/) { 73 | $pad_left++; 74 | } 75 | else { 76 | die "unexpected data at $. in file $input_file"; 77 | } 78 | } 79 | $new_line = pad($_, $pad_left, $pad_right); 80 | $prev_line = $_; 81 | 82 | my @cells = split //, $new_line; 83 | for my $cell (@cells) { 84 | $im->filledRectangle($x, $y, $x + $cell_size, $y + $cell_size, 85 | $cell ? $dark : $white); 86 | $x += $cell_size; 87 | } 88 | $y -= $cell_size; 89 | $x = 0; 90 | 91 | } 92 | 93 | print "\n"; 94 | 95 | { 96 | open my $fh, ">", $im_file or die $!; 97 | print $fh $im->png; 98 | close $fh; 99 | } 100 | 101 | print "Done. Image saved to $im_file.\n"; 102 | 103 | -------------------------------------------------------------------------------- /busy-beaver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Peteris Krumins (peter@catonmat.net) 4 | # http://www.catonmat.net -- good coders code, great reuse 5 | # 6 | # Turing Machine simulator for Busy Beaver problem. 7 | # More info at: http://www.catonmat.net/blog/busy-beaver 8 | # 9 | # Version 1.0 10 | # 11 | 12 | import sys 13 | 14 | class Error(Exception): 15 | pass 16 | 17 | class TuringMachine(object): 18 | def __init__(self, program, start, halt, init): 19 | self.program = program 20 | self.start = start 21 | self.halt = halt 22 | self.init = init 23 | self.tape = [self.init] 24 | self.pos = 0 25 | self.state = self.start 26 | self.set_tape_callback(None) 27 | self.tape_changed = 1 28 | self.movez = 0 29 | 30 | def run(self): 31 | tape_callback = self.get_tape_callback() 32 | while self.state != self.halt: 33 | if tape_callback: 34 | tape_callback(self.tape, self.tape_changed) 35 | 36 | lhs = self.get_lhs() 37 | rhs = self.get_rhs(lhs) 38 | 39 | new_state, new_symbol, move = rhs 40 | 41 | old_symbol = lhs[1] 42 | self.update_tape(old_symbol, new_symbol) 43 | self.update_state(new_state) 44 | self.move_head(move) 45 | 46 | if tape_callback: 47 | tape_callback(self.tape, self.tape_changed) 48 | 49 | def set_tape_callback(self, fn): 50 | self.tape_callback = fn 51 | 52 | def get_tape_callback(self): 53 | return self.tape_callback 54 | 55 | property(get_tape_callback, set_tape_callback) 56 | 57 | @property 58 | def moves(self): 59 | return self.movez 60 | 61 | def update_tape(self, old_symbol, new_symbol): 62 | if old_symbol != new_symbol: 63 | self.tape[self.pos] = new_symbol 64 | self.tape_changed += 1 65 | else: 66 | self.tape_changed = 0 67 | 68 | def update_state(self, state): 69 | self.state = state 70 | 71 | def get_lhs(self): 72 | under_cursor = self.tape[self.pos] 73 | lhs = self.state + under_cursor 74 | return lhs 75 | 76 | def get_rhs(self, lhs): 77 | if lhs not in self.program: 78 | raise Error('Could not find transition for state "%s".' % lhs) 79 | return self.program[lhs] 80 | 81 | def move_head(self, move): 82 | if move == 'l': 83 | self.pos -= 1 84 | elif move == 'r': 85 | self.pos += 1 86 | else: 87 | raise Error('Unknown move "%s". It can only be left or right.' % move) 88 | 89 | if self.pos < 0: 90 | self.tape.insert(0, self.init) 91 | self.pos = 0 92 | if self.pos >= len(self.tape): 93 | self.tape.append(self.init) 94 | 95 | self.movez += 1 96 | 97 | beaver_programs = [ 98 | { }, 99 | 100 | {'a0': 'h1r' }, 101 | 102 | {'a0': 'b1r', 'a1': 'b1l', 103 | 'b0': 'a1l', 'b1': 'h1r'}, 104 | 105 | {'a0': 'b1r', 'a1': 'h1r', 106 | 'b0': 'c0r', 'b1': 'b1r', 107 | 'c0': 'c1l', 'c1': 'a1l'}, 108 | 109 | {'a0': 'b1r', 'a1': 'b1l', 110 | 'b0': 'a1l', 'b1': 'c0l', 111 | 'c0': 'h1r', 'c1': 'd1l', 112 | 'd0': 'd1r', 'd1': 'a0r'}, 113 | 114 | {'a0': 'b1l', 'a1': 'a1l', 115 | 'b0': 'c1r', 'b1': 'b1r', 116 | 'c0': 'a1l', 'c1': 'd1r', 117 | 'd0': 'a1l', 'd1': 'e1r', 118 | 'e0': 'h1r', 'e1': 'c0r'}, 119 | 120 | {'a0': 'b1r', 'a1': 'e0l', 121 | 'b0': 'c1l', 'b1': 'a0r', 122 | 'c0': 'd1l', 'c1': 'c0r', 123 | 'd0': 'e1l', 'd1': 'f0l', 124 | 'e0': 'a1l', 'e1': 'c1l', 125 | 'f0': 'e1l', 'f1': 'h1r'} 126 | ] 127 | 128 | def busy_beaver(n): 129 | def tape_callback(tape, tape_changed): 130 | print ''.join(tape) 131 | 132 | program = beaver_programs[n] 133 | 134 | print "Running Busy Beaver with %d states." % n 135 | tm = TuringMachine(program, 'a', 'h', '0') 136 | tm.set_tape_callback(tape_callback) 137 | tm.run() 138 | print "Busy beaver finished in %d steps." % tm.moves 139 | 140 | def usage(): 141 | print "Usage: %s [1|2|3|4|5|6]" % sys.argv[0] 142 | print "Runs Busy Beaver problem for 1 or 2 or 3 or 4 or 5 or 6 states." 143 | sys.exit(1) 144 | 145 | if __name__ == "__main__": 146 | if len(sys.argv[1:]) < 1: 147 | usage() 148 | 149 | n = int(sys.argv[1]) 150 | 151 | if n < 1 or n > 6: 152 | print "n must be between 1 and 6 inclusive" 153 | print 154 | usage() 155 | 156 | busy_beaver(n) 157 | 158 | -------------------------------------------------------------------------------- /busy-beaver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ** Peteris Krumins (peter@catonmat.net) 3 | ** http://www.catonmat.net -- good coders code, great reuse 4 | ** 5 | ** Turing Machine simulator for Busy Beaver problem. 6 | ** More info at: http://www.catonmat.net/blog/busy-beaver 7 | ** 8 | ** Version 1.0 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace std; 19 | 20 | typedef vector Tape; 21 | typedef map Program; 22 | 23 | class TuringMachine { 24 | private: 25 | Tape tape; 26 | Program program; 27 | char start, halt, init, state; 28 | bool tape_changed; 29 | int moves; 30 | int pos; 31 | public: 32 | TuringMachine(Program program, char start, char halt, char init): 33 | tape(1, init), program(program), start(start), halt(halt), 34 | init(init), state(start), moves(0), tape_changed(1), pos(0) 35 | { } 36 | 37 | void run() { 38 | while (state != halt) { 39 | print_tape(); 40 | string lhs = get_lhs(); 41 | string rhs = get_rhs(lhs); 42 | 43 | char new_state = rhs[0]; 44 | char new_symbol = rhs[1]; 45 | char move = rhs[2]; 46 | 47 | char old_symbol = lhs[1]; 48 | update_tape(old_symbol, new_symbol); 49 | update_state(new_state); 50 | move_head(move); 51 | } 52 | print_tape(); 53 | } 54 | 55 | int get_moves() { 56 | return moves; 57 | } 58 | 59 | private: 60 | inline void print_tape() { 61 | if (tape_changed) { 62 | for (int i=0; i= tape.size()) { 106 | tape.push_back(init); 107 | } 108 | moves++; 109 | } 110 | 111 | }; 112 | 113 | vector busy_beavers; 114 | 115 | void init_bb6() 116 | { 117 | Program bb6; 118 | bb6.insert(make_pair("a0", "b1r")); 119 | bb6.insert(make_pair("b0", "c1l")); 120 | bb6.insert(make_pair("c0", "d1l")); 121 | bb6.insert(make_pair("d0", "e1l")); 122 | bb6.insert(make_pair("e0", "a1l")); 123 | bb6.insert(make_pair("f0", "e1l")); 124 | 125 | bb6.insert(make_pair("a1", "e0l")); 126 | bb6.insert(make_pair("b1", "a0r")); 127 | bb6.insert(make_pair("c1", "c0r")); 128 | bb6.insert(make_pair("d1", "f0l")); 129 | bb6.insert(make_pair("e1", "c1l")); 130 | bb6.insert(make_pair("f1", "h1r")); 131 | 132 | busy_beavers.push_back(bb6); 133 | } 134 | 135 | void init_bb5() 136 | { 137 | Program bb5; 138 | bb5.insert(make_pair("a0", "b1l")); 139 | bb5.insert(make_pair("b0", "c1r")); 140 | bb5.insert(make_pair("c0", "a1l")); 141 | bb5.insert(make_pair("d0", "a1l")); 142 | bb5.insert(make_pair("e0", "h1r")); 143 | 144 | bb5.insert(make_pair("a1", "a1l")); 145 | bb5.insert(make_pair("b1", "b1r")); 146 | bb5.insert(make_pair("c1", "d1r")); 147 | bb5.insert(make_pair("d1", "e1r")); 148 | bb5.insert(make_pair("e1", "c0r")); 149 | 150 | busy_beavers.push_back(bb5); 151 | } 152 | 153 | void init_bb4() 154 | { 155 | Program bb4; 156 | bb4.insert(make_pair("a0", "b1r")); 157 | bb4.insert(make_pair("b0", "a1l")); 158 | bb4.insert(make_pair("c0", "h1r")); 159 | bb4.insert(make_pair("d0", "d1r")); 160 | 161 | bb4.insert(make_pair("a1", "b1l")); 162 | bb4.insert(make_pair("b1", "c0l")); 163 | bb4.insert(make_pair("c1", "d1l")); 164 | bb4.insert(make_pair("d1", "a0r")); 165 | 166 | busy_beavers.push_back(bb4); 167 | 168 | } 169 | 170 | void init_bb3() 171 | { 172 | Program bb3; 173 | bb3.insert(make_pair("a0", "b1r")); 174 | bb3.insert(make_pair("b0", "c0r")); 175 | bb3.insert(make_pair("c0", "c1l")); 176 | 177 | bb3.insert(make_pair("a1", "h1r")); 178 | bb3.insert(make_pair("b1", "b1r")); 179 | bb3.insert(make_pair("c1", "a1l")); 180 | 181 | busy_beavers.push_back(bb3); 182 | } 183 | 184 | void init_bb2() 185 | { 186 | Program bb2; 187 | bb2.insert(make_pair("a0", "b1r")); 188 | bb2.insert(make_pair("b0", "a1l")); 189 | 190 | bb2.insert(make_pair("a1", "b1l")); 191 | bb2.insert(make_pair("b1", "h1r")); 192 | 193 | busy_beavers.push_back(bb2); 194 | } 195 | 196 | void init_bb1() 197 | { 198 | Program bb1; 199 | bb1.insert(make_pair("a0", "h1r")); 200 | 201 | busy_beavers.push_back(bb1); 202 | } 203 | 204 | void init_busy_beavers() 205 | { 206 | busy_beavers.push_back(Program()); 207 | init_bb1(); 208 | init_bb2(); 209 | init_bb3(); 210 | init_bb4(); 211 | init_bb5(); 212 | init_bb6(); 213 | } 214 | 215 | void busy_beaver(int n) 216 | { 217 | cout << "Running Busy Beaver with " << n << " states." << endl; 218 | TuringMachine tm(busy_beavers[n], 'a', 'h', '0'); 219 | tm.run(); 220 | cout << "Busy Beaver finished in " << tm.get_moves() << " steps." << endl; 221 | } 222 | 223 | void usage(const char *prog) 224 | { 225 | cout << "Usage: " << prog << " [1|2|3|4|5|6]\n"; 226 | cout << "Runs Busy Beaver problem for 1 or 2 or 3 or 4 or 5 or 6 states." << endl; 227 | exit(1); 228 | } 229 | 230 | int main(int argc, char **argv) 231 | { 232 | if (argc < 2) { 233 | usage(argv[0]); 234 | } 235 | 236 | int n = atoi(argv[1]); 237 | if (n < 1 || n > 6) { 238 | cout << "n must be between 1 and 6 inclusive!\n"; 239 | cout << "\n"; 240 | usage(argv[0]); 241 | } 242 | 243 | init_busy_beavers(); 244 | busy_beaver(n); 245 | } 246 | 247 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | This is an implementation of The Busy Beaver Problem in Python and C++. 2 | 3 | It was written by Peteris Krumins (peter@catonmat.net). 4 | His blog is at http://www.catonmat.net -- good coders code, great reuse. 5 | 6 | The code is licensed under the MIT license. 7 | 8 | The code was written as a part of article "The Busy Beaver Problem" on my 9 | website. The whole article can be read at: 10 | 11 | http://www.catonmat.net/blog/busy-beaver/ 12 | 13 | ------------------------------------------------------------------------------ 14 | 15 | Table of contents: 16 | [1] Introduction to The Busy Beaver Problem. 17 | [2] Example Busy Beaver Turing Machine with 2 states. 18 | [3] Busy Beaver Turing Machines for 1, 2, 3, 4, 5, and 6 states. 19 | [4] busy-beaver.cpp and busy-beaver.py C++ and Python programs. 20 | [5] draw_turing_machine.pl Perl program. 21 | 22 | 23 | [1]-Introduction-to-The-Busy-Beaver-Problem----------------------------------- 24 | 25 | The busy beaver problem is a fun theoretical computer science problem to know. 26 | Intuitively, the problem is to find the smallest program that outputs as many 27 | data as possible and eventually *halts*. 28 | 29 | More formally it goes like this - given an n-state Turing Machine with a two 30 | symbol alphabet {0, 1}, what is the maximum number of 1s that the machine may 31 | print on an initially blank tape (0-filled) before halting? 32 | 33 | It turns out that this problem can't be solved. For a small number of states 34 | it can be reasoned about, but it can't be solved in general. Theorists call 35 | such problems non-computable. 36 | 37 | Currently people have managed to solve it for n=1,2,3,4 (for Turing Machines 38 | with 1, 2, 3 and 4 states) by reasoning about and running all the possible 39 | Turing Machines, but for n = 5 this task has currently been impossible. 40 | While most likely it will be solved for n=5, theorists doubt that it shall 41 | ever be computed for n=6. 42 | 43 | ... 44 | 45 | Continue reading on http://www.catonmat.net/blog/busy-beaver/ 46 | 47 | 48 | [2]-Example-Busy-Beaver-Turing-Machine-with-2-states-------------------------- 49 | 50 | Here is an example of a 2-state busy beaver. It's a Turing machine. 51 | 52 | a0 -> b1r a1 -> b1l 53 | b0 -> a1l b1 -> h1r 54 | 55 | The initial tape is filled with 0's. The starting state is 'a' and the halting 56 | state is 'h'. The notation 'a0 -> b1r' means "if we are in the state 'a' and 57 | the current symbol on the tape is '0', then put a '1' in the current cell, 58 | switch to state 'b' and move to the right 'r'. This process repeats until the 59 | machine ends up in the halting state 'h'. 60 | 61 | When run, it produces 4 ones on the tape and halts. 62 | 63 | Here are all the tape changes. The tape is infinite and initially blank 64 | (filled with 0's). 65 | 66 | . starting state 67 | | 68 | v state change 69 | ------------ 70 | ...|0|0|0|0|0|0|0|0|0|0|... a0 -> b1r 71 | ...|0|0|0|0|1|0|0|0|0|0|... b0 -> a1l 72 | ...|0|0|0|0|1|1|0|0|0|0|... a1 -> b1l 73 | ...|0|0|0|0|1|1|0|0|0|0|... b0 -> a1l 74 | ...|0|0|0|1|1|1|0|0|0|0|... a0 -> b1r 75 | ...|0|0|1|1|1|1|0|0|0|0|... b1 -> h1r HALT 76 | ...|0|0|1|1|1|1|0|0|0|0|... 77 | 78 | The busy beaver stopped after 6 steps and the tape got filled with 4 ones. 79 | 80 | 81 | [3]-Busy-Beaver-Turing-Machines-for-1-2-3-4-5-and-6-states-------------------- 82 | 83 | Turing Machine for 1-state Busy Beaver: 84 | 85 | a0 -> h1r 86 | 87 | The tape gets filled with 1 one and it terminates after 1 step. 88 | 89 | Turing Machine for 2-state Busy Beaver: 90 | 91 | a0 -> b1r a1 -> b1l 92 | b0 -> a1l b1 -> h1r 93 | 94 | The tape gets filled with 4 ones and it terminates after 6 steps. 95 | 96 | Turing Machine for 3-state Busy Beaver: 97 | 98 | a0 -> b1r a1 -> h1r 99 | b0 -> c0r b1 -> b1r 100 | c0 -> c1l c1 -> a1l 101 | 102 | The tape gets filled with 6 ones and it terminates after 14 steps. 103 | 104 | Turing Machine for 4-state Busy Beaver: 105 | 106 | a0 -> b1r a1 -> b1l 107 | b0 -> a1l b1 -> c0l 108 | c0 -> h1r c1 -> d1l 109 | d0 -> d1r d1 -> a0r 110 | 111 | The tape gets filled with 13 ones and it terminates after 107 steps. 112 | 113 | Turing Machine for 5-state Busy Beaver: 114 | 115 | a0 -> b1l a1 -> a1l 116 | b0 -> c1r b1 -> b1r 117 | c0 -> a1l c1 -> d1r 118 | d0 -> a1l d1 -> e1r 119 | e0 -> h1r e1 -> c0r 120 | 121 | The tape gets filled with 4098 ones and it terminates after 122 | 47176870 steps. 123 | 124 | Turing Machine for 6 state Busy Beaver: 125 | 126 | a0 -> b1r a1 -> e0l 127 | b0 -> c1l b1 -> a0r 128 | c0 -> d1l c1 -> c0r 129 | d0 -> e1l d1 -> f0l 130 | e0 -> a1l e1 -> c1l 131 | f0 -> e1l f1 -> h1r 132 | 133 | Currently best 6 state Busy Beaver outputs 4.6e1439 ones and 134 | terminates after 2.8e2879 steps. 135 | 136 | This result is a theoretical approximation. There are aproximately 137 | 0.3% of unchecked Turing Machines left. 138 | 139 | 140 | [4]-busy-beaver.cpp-and-busy-beaver.py-programs------------------------------- 141 | 142 | I decided to play with the busy beaver myself to verify the known results for 143 | n <= 5. I implemented a Turing Machine in Python, which turned out to be too 144 | slow, so I reimplemented it in C++. 145 | 146 | I also wrote a visualization tool in Perl that shows how the Turing Machine's 147 | tape changes from the start to the finish (see [5]). 148 | 149 | The Python program is called busy-beaver.py and it takes one argument - 150 | which n-state busy beaver to run. 151 | 152 | The C++ program is called busy-beaver.cpp and takes the same argument. 153 | 154 | Here is how to invoke the Python program: 155 | 156 | $ ./busy-beaver.py 2 157 | Running Busy Beaver with 2 states. 158 | 0 159 | 10 160 | 11 161 | 011 162 | 0111 163 | 1111 164 | 1111 165 | Busy beaver finished in 6 steps. 166 | 167 | The output is the tape changes and the final line tells us how many steps it 168 | took. 169 | 170 | You can use the tape change output and generate an image that shows the tape 171 | changes in a much visual way. See the Perl program [5] below. 172 | 173 | To use the C++ program, you have to first compile it: 174 | 175 | $ g++ busy-beaver.cpp -o busy-beaver 176 | 177 | And then you can run it as any other program: 178 | 179 | $ ./busy-beaver 3 180 | Running Busy Beaver with 3 states. 181 | 0 182 | 10 183 | 101 184 | 111 185 | 1111 186 | 111101 187 | 111111 188 | Busy Beaver finished in 14 steps. 189 | 190 | [5]-draw_turing_machine.pl-Perl-program. 191 | 192 | I also wrote a visualization program for the output from busy-beaver program. 193 | It takes the 0's and 1's you see above and turns into a nice png image. 194 | 195 | Take a look at the original article http://www.catonmat.net/blog/busy-beaver/ 196 | to see how these images look. 197 | 198 | ------------------------------------------------------------------------------ 199 | 200 | That's it. Enjoy the beavers! :) 201 | 202 | 203 | Sincerely, 204 | Peteris Krumins 205 | http://www.catonmat.net 206 | 207 | --------------------------------------------------------------------------------