Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / artificial-intelligence / machine-learning

Creating a Turing Machine in Python – Part 3

4.20/5 (3 votes)
22 Dec 2017CPOL4 min read 8.4K  
In this part of this series, we will add some more Turing machines and extend the logging.

Now that our Turing machine is up and running, it’s time to add some more interesting machines. We will stick with unary Turing machines and implement one for Decrement, Addition and Subtraction each.

Before we do so, however, let’s add some logging to visualize how the Turing machine is working and help us debug it.

Logging

We will handle the logging in a single method inside the TuringMachine class, that I called _log_process. Notice again the underscore which makes it clear to consumers of the machine that this is an internal/protected method and shouldn’t be used from outside.

Python
def _log_process(self, step):
    print('\nTape after step {0}: '.format(step))
    print('[', end='')

    for i in range(0, self.tape.get_length()):
        if self.tape.head_position == i:
            print("\033[4m" + self.tape._tape[i] + "\033[0m", end='')
        else:
            print(self.tape._tape[i], end='')

    print(']')

It takes a step parameter and prints each character of the tape on a line. The character at the head_position will be printed with an underscore, that is why we need these ugly ASCII formatting.

Now, let’s plug this method into our process method. First, we have to declare the steps variable. Then we can call this method with each iteration of the Turing machine. Additionally, I added a call before the while loop, to display the initial state of the Turing machine:

Python
def process(self):
    current_state = self.start_state
    step = 0
    self._log_process(step)

    while current_state.type != StateType.Final:
        ...
        step += 1
        self._log_process(step)

If we now rerun the Increment machine from the previous chapter, we should see the following output:

Image 1

Now we can see how the Turing machine works its way from the left side of the tape to the right side and when it writes the final |. This kind of logging will be very handy for the Turing machines we are going to create next.

Decrement Machine

The Turing machine for decrementation works very similar to the one for incrementation. However, instead of adding a |, we have to remove the last one after we reach the end of the tape. This means we have to move to the right until we reach the first # character. Then, we can simply go one character to the left and remove that |:

Image 2
 

In Python, we can represent this Turing machine with the following code:

Python
tape = Tape('|||', '|')
states = [
            State("s0", StateType.Start),
            State("s1", StateType.Empty),
            State("s2", StateType.Empty),
            State("sf", StateType.Final)
         ]

transitions = [
                 Transition("s0", "$", "s1", "$", Direction.Right),
                 Transition("s1", "|", "s1", "|", Direction.Right),
                 Transition("s1", "#", "s2", "#", Direction.Left),
                 Transition("s2", "$", "sf", "$", Direction.Neutral),
                 Transition("s2", "|", "sf", "#", Direction.Neutral)
              ]

tm = TuringMachine(states, transitions, tape)
tm.process(True)

Addition Machine

Another simple Turing machine we can create is one that adds two numbers. We will represent the addition operation by two unary numbers separated by a &. For example, to calculate the sum of the numbers two and three, we would initialize the tape like this: $||%|||.
To add these numbers, all we have to do is to replace the & with a | and then remove the last |. For the tape above, this would result in $|||||. To realize this, the Turing machine has to go to the right until it reaches the %, replace it with | and then move further to the right until it reaches the end of the tape, marked by a #. Finally, it has to go one character to the left and remove the final |:

Image 3

This translates into the following Python code:

Python
tape = Tape('|||&||', '|&')
states = [
            State("s0", StateType.Start),
            State("s1", StateType.Empty),
            State("s2", StateType.Empty),
            State("s3", StateType.Empty),
            State("s4", StateType.Empty),
            State("sf", StateType.Final)
         ]

transitions = [
                 Transition("s0", "$", "s1", "$", Direction.Right),
                 Transition("s1", "#", "sf", "#", Direction.Neutral),
                 Transition("s1", "|", "s1", "|", Direction.Right),
                 Transition("s1", "&", "s2", "|", Direction.Right),
                 Transition("s2", "|", "s2", "|", Direction.Right),
                 Transition("s2", "#", "s3", "#", Direction.Left),
                 Transition("s3", "|", "s4", "#", Direction.Left),
                 Transition("s4", "|", "s4", "|", Direction.Left),
                 Transition("s4", "$", "sf", "$", Direction.Neutral),
              ]

tm = TuringMachine(states, transitions, tape)
tm.process(True)

Subtraction Machine

So far, our Turing machines have been fairly trivial. Now, let’s tackle a more complicated problem: Subtraction. One way to solve this problem is to move through the tape until we reach the first # (which we will use as Minus operator). Then, we have to remove the next | on its right and left side and replace them with #.
For example, given the tape $|||#||#, after these first steps, the tape would look like this: $||###|#. If we repeat this process until there are no more | on the right side of the initial #, the subtraction will be complete. In the case above, we will end up with a tape like: $|#####.

This process will work for tapes of any length. However, since we have to move through an increasing number of # with every step, the Turing machine will take a very long time for large inputs.
As you can see in the image below, the diagram for this Turing machine is much more complicated than the previous ones and it takes some time to fully understand it.

Image 4

In Python, this is represented by the following code:

Python
tape = Tape('|||#||', '|&')
states = [
            State("s0", StateType.Start),
            State("s1", StateType.Empty),
            State("s2", StateType.Empty),
            State("s3", StateType.Empty),
            State("s4", StateType.Empty),
            State("s5", StateType.Empty),
            State("s6", StateType.Empty),
            State("s7", StateType.Empty),
            State("s8", StateType.Empty),
            State("sf", StateType.Final)
         ]

transitions = [
                 Transition("s0", "$", "s0", "$", Direction.Right),
                 Transition("s0", "#", "sf", "#", Direction.Neutral),
                 Transition("s0", "|", "s1", "|", Direction.Right),
                 Transition("s1", "|", "s1", "|", Direction.Right),
                 Transition("s1", "#", "s2", "#", Direction.Right),
                 Transition("s2", "#", "s2", "#", Direction.Right),
                 Transition("s2", "|", "s3", "|", Direction.Right),
                 Transition("s3", "|", "s4", "|", Direction.Left),
                 Transition("s3", "#", "s6", "#", Direction.Left),
                 Transition("s4", "|", "s5", "#", Direction.Left),
                 Transition("s5", "#", "s5", "#", Direction.Left),
                 Transition("s5", "|", "s2", "#", Direction.Right),
                 Transition("s5", "$", "s2", "$", Direction.Right),
                 Transition("s6", "|", "s7", "#", Direction.Left),
                 Transition("s7", "#", "s7", "#", Direction.Left),
                 Transition("s7", "$", "sf", "$", Direction.Neutral),
                 Transition("s7", "|", "s8", "#", Direction.Left),
                 Transition("s8", "|", "s8", "|", Direction.Left),
                 Transition("s8", "$", "sf", "$", Direction.Neutral)
              ]

tm = TuringMachine(states, transitions, tape)
tm.process(True)

This concludes our collection of Turing machines. I encourage you to play around with them and create new ones. For example, you can try to implement Turing machines for Multiplication and Division.

I hope you enjoyed this series. If you have any questions, problems or feedback, please let me know in the comments.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)