简体   繁体   中英

Turing Machine Euclid's Algorithm for finding greatest common divisor python

My code is at the bottom: (if someone has enough patience to read it all, I'll be really surprised)

It outputs the incorrect number, but I don't know why. I've followed the algorithm. The input have to be 2 unary numbers such as 2 and 6 => 01101111110. If there's a easier way to code this algorithm, pls tell me. Here is the algorithm ( from the book The Emperor's New Mind by Roger Penrose )

在此处输入图片说明

And my code is:

x = input("Dos numeros en sistema unario separado por un 0: ")
x = list(x)
pos = 0
valorMaq = 0
while (True):
    if valorMaq==0 and x[pos]=='0':
        valorMaq=0
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==0 and x[pos]=='1':
        valorMaq=11
        x[pos]='0'
        pos=pos-1
        print(x)

    elif valorMaq==1 and x[pos]=='0':
        valorMaq=10
        x[pos]='1'
        pos=pos+1
        print(x)

    elif valorMaq==1 and x[pos]=='1':
        valorMaq=1
        x[pos]='1'
        pos=pos-1
        print(x)
############################################
    elif valorMaq==10 and x[pos]=='0':
        valorMaq=1010
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==10 and x[pos]=='1':
        valorMaq=11
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==11 and x[pos]=='0':
        valorMaq=100
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==11 and x[pos]=='1':
        valorMaq=11
        x[pos]='1'
        pos=pos+1
        print(x)
#############################################
    elif valorMaq==100 and x[pos]=='0':
        valorMaq=100
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==100 and x[pos]=='1':
        valorMaq=101
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==101 and x[pos]=='0':
        valorMaq=111
        x[pos]='0'
        pos=pos-1
        print(x)

    elif valorMaq==101 and x[pos]=='1':
        valorMaq=110
        x[pos]='1'
        pos=pos-1
        print(x)

    elif valorMaq==110 and x[pos]=='0':
        valorMaq=110
        x[pos]='0'
        pos=pos-1
        print(x)

    elif valorMaq==110 and x[pos]=='1':
        valorMaq=1
        x[pos]='1'
        pos=pos-1
        print(x)

    elif valorMaq==111 and x[pos]=='0':
        valorMaq=111
        x[pos]='0'
        pos=pos-1
        print(x)

    elif valorMaq==111 and x[pos]=='1':
        valorMaq=1000
        x[pos]='1'
        pos=pos-1
        print(x)
################################################
    elif valorMaq==1000 and x[pos]=='0':
        valorMaq=1001
        x[pos]='0'
        pos=pos-1
        print(x)

    elif valorMaq==1000 and x[pos]=='1':
        valorMaq=1000
        x[pos]='1'
        pos=pos-1

    elif valorMaq==1001 and x[pos]=='0':
        valorMaq=10
        x[pos]='0'
        pos=pos+1
        print(x)

    elif valorMaq==1001 and x[pos]=='1':
        valorMaq=1
        x[pos]='1'
        pos=pos-1
        print(x)

    elif valorMaq==1010 and x[pos]=='1':
        valorMaq=1010
        x[pos]='1'
        pos=pos+1
        print(x)

    elif valorMaq==1010 and x[pos]=='0':
        valorMaq=0
        x[pos]='0'
        pos=pos+1
        break
        print(x)

x = ''.join(x)
print("Maximo comun divisor: ", x)

Despite what you wrote, I did look at every line of your code.

Your implementation of the second rule is incorrect. Penrose has 0 1 →1 1 L but you programmed 0 1 →11 0 L. So change your lines 12 through 16 to

elif valorMaq==0 and x[pos]=='1':
    valorMaq=1
    x[pos]='1'
    pos=pos-1
    print(x)

That is the only wrong rule. However, you left out an important idea of a Turing machine: it is potentially infinite and automatically adds blank cells to either end of the tape whenever the reading head moves off the currently-defined tape. You could possibly implement that by adding more lines to each of your sections of code where pos is changed.

However, I recommend instead that you make thorough changes to your code. You make your code more difficult than it needs to be. For one, you use tabs for indentation, but that is not a good idea in Python--use 4 spaces for each level of indent.

For another, you have much repetitious code, which violates the DRY ( Don't Repeat Yourself principle. Replace your algorithm with a data structure such as a dictionary to represent the rules, and write a small engine that uses the input and that structure to execute the Turing machine. For example, rules[(0, '0')] could be the tuple (0, '0', +1) to represent staying in state zero, writing a '0' character to the current position, and adding 1 to the current position (ie moving right one cell). The second production would have rules[(0, '1')] as (1, '1', -1) for state 1, character '1', and move left. The STOP action could be represented by something the machine can never move, such as None. Such code would be much easier to understand and to debug.

Here is some code doing just that. I also improved the printout to show the current state and location in the tape and removed your requirement that an extra '0' character be at both ends of the input. I also made the code more flexible, extendable, and testable. I believe it is clear how to convert the rules as Penrose showed them to the format I use in the rules dictionary, though I used decimal numbers rather than Penrose's binary numbers for convenience and space. There is no error checking in this code. I tested this with pairs of numbers, each from 1 through 50, and it always gives the correct greatest common divisor in unary format. Penrose's algorithm is quite clever--I never would have thought of this algorithm, which uses no extra characters.

"""Calculate the greatest common divisor of two unary numbers using
Penrose's algorithm for a Turing machine.

Suggested by <https://stackoverflow.com/questions/44467401/turing-
machine-euclids-algorithm-for-finding-greatest-common-divisor-python>
which itself uses Roger Penrose's *The Emperor's New Mind*, Oxford
University Press 1989 (paperback) p.41, the algorithm called EUC.

No error checking is done to the rules dictionary or the input line
that the correct format is followed.

Possible changes:
    1.  Enforce Penrose's requirement that the ending position is to
        the right of the answer (perhaps with blanks between the answer
        and the position).
        a.  Perhaps return ''.join(tape[:pos]).strip(BLANK) which
            removes anything at and right of the ending position.
        b.  Perhaps check that only blanks are at and right of the
            ending position.
"""

# Constants for magic numbers
BLANK = '0'  # blank character
STOP = None  # code to end the calcuation
STATEWIDTH = 3  # number of spaces to print current state in

# A rules dictionary, each entry in the format
#   (oldstate, currentcharacter): (newstate, newcharacter, move_or_stop)
EUC = {
    ( 0, '0'): ( 0, '0', +1),    ( 0, '1'): ( 1, '1', -1),  # state  0 =    0
    ( 1, '0'): ( 2, '1', +1),    ( 1, '1'): ( 1, '1', -1),  # state  1 =    1
    ( 2, '0'): (10, '0', +1),    ( 2, '1'): ( 3, '0', +1),  # state  2 =   10
    ( 3, '0'): ( 4, '0', +1),    ( 3, '1'): ( 3, '1', +1),  # state  3 =   11
    ( 4, '0'): ( 4, '0', +1),    ( 4, '1'): ( 5, '0', +1),  # state  4 =  100
    ( 5, '0'): ( 7, '0', -1),    ( 5, '1'): ( 6, '1', -1),  # state  5 =  101
    ( 6, '0'): ( 6, '0', -1),    ( 6, '1'): ( 1, '1', -1),  # state  6 =  110
    ( 7, '0'): ( 7, '0', -1),    ( 7, '1'): ( 8, '1', -1),  # state  7 =  111
    ( 8, '0'): ( 9, '0', -1),    ( 8, '1'): ( 8, '1', -1),  # state  8 = 1000
    ( 9, '0'): ( 2, '0', +1),    ( 9, '1'): ( 1, '1', -1),  # state  9 = 1001
    (10, '0'): ( 0, '0', STOP),  (10, '1'): (10, '1', +1),  # state 10 = 1010
}

def print_situation(state, tape, pos, printlines):
    if printlines:
        print(str(state).rjust(STATEWIDTH), ''.join(tape))
        print(''.rjust(STATEWIDTH), '^'.rjust(pos + 1))

def turing_machine(inputline, rules, printlines=True):
    tape = list(inputline)
    state = 0
    pos = 0
    print_situation(state, tape, pos, printlines)
    move = 1  # something other than STOP
    while move != STOP:
        # Do the next action
        state, tape[pos], move = rules[(state, tape[pos])]
        if move != STOP:
            pos += move
        else:
            pos += 1  # Penrose says all stops move right once
        # Add any needed blank characters to an end of the tape
        while pos < 0:
            tape.insert(0, BLANK)
            pos += 1  # pos is relative to left end of tape, so adjust both
        while pos >= len(tape):
            tape.append(BLANK)  # left end not changed so pos not adjusted
        # Print current situation
        print_situation(state, tape, pos, printlines)
    return ''.join(tape).strip(BLANK)

print(turing_machine(
        input("Enter two unary numbers separated by a '0': "), EUC))

When I enter the codes for 2 and 6, 110111111 , the returned result is 11 which is the unary code for 2, and the entire printout is:

  0 110111111
    ^
  1 0110111111
    ^
  2 1110111111
     ^
  3 1010111111
      ^
  3 1010111111
       ^
  4 1010111111
        ^
  5 1010011111
         ^
  6 1010011111
        ^
  6 1010011111
       ^
  6 1010011111
      ^
  1 1010011111
     ^
  2 1110011111
      ^
  3 1100011111
       ^
  4 1100011111
        ^
  4 1100011111
         ^
  5 1100001111
          ^
  6 1100001111
         ^
  6 1100001111
        ^
  6 1100001111
       ^
  6 1100001111
      ^
  6 1100001111
     ^
  1 1100001111
    ^
  1 01100001111
    ^
  2 11100001111
     ^
  3 10100001111
      ^
  3 10100001111
       ^
  4 10100001111
        ^
  4 10100001111
         ^
  4 10100001111
          ^
  4 10100001111
           ^
  5 10100000111
            ^
  6 10100000111
           ^
  6 10100000111
          ^
  6 10100000111
         ^
  6 10100000111
        ^
  6 10100000111
       ^
  6 10100000111
      ^
  1 10100000111
     ^
  2 11100000111
      ^
  3 11000000111
       ^
  4 11000000111
        ^
  4 11000000111
         ^
  4 11000000111
          ^
  4 11000000111
           ^
  4 11000000111
            ^
  5 11000000011
             ^
  6 11000000011
            ^
  6 11000000011
           ^
  6 11000000011
          ^
  6 11000000011
         ^
  6 11000000011
        ^
  6 11000000011
       ^
  6 11000000011
      ^
  6 11000000011
     ^
  1 11000000011
    ^
  1 011000000011
    ^
  2 111000000011
     ^
  3 101000000011
      ^
  3 101000000011
       ^
  4 101000000011
        ^
  4 101000000011
         ^
  4 101000000011
          ^
  4 101000000011
           ^
  4 101000000011
            ^
  4 101000000011
             ^
  4 101000000011
              ^
  5 101000000001
               ^
  6 101000000001
              ^
  6 101000000001
             ^
  6 101000000001
            ^
  6 101000000001
           ^
  6 101000000001
          ^
  6 101000000001
         ^
  6 101000000001
        ^
  6 101000000001
       ^
  6 101000000001
      ^
  1 101000000001
     ^
  2 111000000001
      ^
  3 110000000001
       ^
  4 110000000001
        ^
  4 110000000001
         ^
  4 110000000001
          ^
  4 110000000001
           ^
  4 110000000001
            ^
  4 110000000001
             ^
  4 110000000001
              ^
  4 110000000001
               ^
  5 1100000000000
                ^
  7 1100000000000
               ^
  7 1100000000000
              ^
  7 1100000000000
             ^
  7 1100000000000
            ^
  7 1100000000000
           ^
  7 1100000000000
          ^
  7 1100000000000
         ^
  7 1100000000000
        ^
  7 1100000000000
       ^
  7 1100000000000
      ^
  7 1100000000000
     ^
  8 1100000000000
    ^
  8 01100000000000
    ^
  9 001100000000000
    ^
  2 001100000000000
     ^
 10 001100000000000
      ^
 10 001100000000000
       ^
 10 001100000000000
        ^
  0 001100000000000
         ^
11

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM