Table des matières
C’est en 1936 qu’apparait pour la première fois le terme de “Machine
de Turing”. Il a été introduit par le chercheur britanique du même nom
dans un article du nom de On
Cumputable Numbers, With An Application To The
Entscheidungsproblem qui répond au problème posé 8 ans
auparavant par le mathématicien David Hilbert. Il s’agit du problème de
la décidabilité (en allemand “Entscheidungsproblem”) soit: existe-t-il
un algorithme qui décide si une proposition énoncée dans un système
logique est valide ou non ?
Mais alors pourquoi sa proposition est-elle si célèbre ? Et bien, lors
de sa découverte, les ordinateurs n’existaient pas. La raison principale
tient à son extrême simplicité qui a permis d’établir des résultats sans
nul doute beaucoup plus difficiles à démontrer avec des modèles moins
rudimentaires. Cette machine est en fait le modèle le plus simple que
l’on puisse concevoir et qui satisfait aux critères informels mais
universels qui caractérisent un algorithme.1
Il faut garder à l’esprit que la machine de Turing est un modèle universel de calcul et qu’elle peut calculer tout ce que n’importe quel ordinateur physique peut calculer
Une machine de Turing est composé de 4 éléments:2
Le fonctionnement de la machine de Turing est alors le suivant : à chaque étape de son calcul, la machine évolue en fonction de l’état dans lequel elle se trouve et du symbole inscrit dans la case du ruban où se trouve la tête de lecture. Ces deux informations permettent la mise à jour de l’état de la machine grâce à la fonction de transition. À l’instant initial, la machine se trouve dans l’état , et le premier symbole du ruban est l’entrée du programme. La machine s’arrête lorsqu’elle rentre dans un état terminal. Le résultat du calcul est alors le mot formé par les symboles successivement lus par la machine.
Voici un code d’une machine de Turing fonctionnel que j’ai réalisée en python.
import time
def open_file(name):
file = open(name + '.txt', 'r')
= file.read()
read_file = []
prgm = read_file.split('\n')
decoupage for i in range(len(decoupage)):
' '))
prgm.append(decoupage[i].split(file.close()
return prgm
class Run:
def __init__(self):
self.head_pos = 0
self.entree = list(input("Initial tape: "))
self.state = input('Initial state: ')
def read(self, letter):
if letter == '_':
if self.entree[self.head_pos] != ' ':
return False
elif letter == '*':
if self.entree[self.head_pos] == ' ':
return False
elif letter != self.entree[self.head_pos]:
return False
return True
def write(self, letter):
if letter == '_':
self.entree[self.head_pos] = ' '
elif letter != '*':
self.entree[self.head_pos] = letter
def move(self, direction):
if direction == 'r':
if self.head_pos < (len(self.entree) - 1):
self.head_pos += 1
else:
self.entree += ' '
self.head_pos += 1
if direction == 'l':
if self.head_pos > 0:
self.head_pos -= 1
else:
self.entree.insert(0, ' ')
def mod_state(self, state):
if state == 'halt':
print("Final tape: {}".format(''.join(self.entree)))
quit()else:
self.state = state
def line(self, prgm):
while 1:
for i in range(len(prgm)):
if prgm[i] != ' ':
if prgm[i][0] == self.state:
= self.read(prgm[i][1])
lecture if lecture:
self.write(prgm[i][2])
self.move(prgm[i][3])
self.mod_state(prgm[i][4])
= open_file('prgm')
program Run().line(program)
Voici un programme pour cette machine.
gauche 0 _ r defile_d0
gauche 1 _ r defile_d1
gauche _ _ * true
droite * * l droite
droite _ _ r gauche
defile_d0 * * r defile_d0
defile_d0 _ _ l is0
defile_d1 * * r defile_d1
defile_d1 _ _ l is1
is0 0 _ l droite
is0 1 _ l false
is0 _ _ * true
is1 1 _ l droite
is1 0 _ l false
is1 _ _ * true
false * _ l false
false _ n r false1
false1 _ o * halt
true _ y r true1
true1 _ e r true2
true2 _ s * halt
Ce programme permet de déterminer si l’entrée fournie est un palindrome binaire 3 ou non.
Examinons l’exécution pas à pas de ce programme de recherche de
palindrome binaire pour le nombre 101 et
l’état initial de gauche.
Les instructions ce lisent de la façon suivante :
gauche | 0 | _ | r | defile_0 |
---|---|---|---|---|
état de départ | si la lecture vaut 0 | on écrit un espace | on bouge à droite | état d’arrivée |
Faisons notre exemple pas à pas :
Execution | Ruban de départ | Commande | Ruban d’arrivée | Etat d’arrivée |
---|---|---|---|---|
1 | “101” | gauche 1 _ r defile_1 | ” 01” | defile_d1 |
2 | ” 01” | defile_d1 * * r defile_d1 | ” 01” | defile_d1 |
3 | ” 01” | defile_d1 * * r defile_d1 | ” 01” | defile_d1 |
4 | ” 01_” | defile_d1 _ _ l is1 | ” 01” | is1 |
5 | ” 01” | is1 1 _ _ l droite | ” 0 ” | droite |
6 | ” 0 ” | droite * * l droite | ” 0 ” | droite |
7 | “_0” | droite _ _ r gauche | ” ” | gauche |
8 | ” 0 ” | gauche _ _ * true | ” ” | true |
9 | ” _ ” | true _ y r true1 | ” y ” | true1 |
10 | ” y_” | true1 _ e r true2 | ” ye” | true2 |
11 | ” ye_” | true2 _ s * halt | ” yes” | halt |
Le mot-clé halt signifie que l’on arrête la machine.
On commence tout d’abord par lire le premier chiffre de gauche qui
est un 1 et on l’efface.
On se dirige donc vers le dernier chiffre pour vérifier s’il s’agit
aussi d’un 1 puis on l’efface.
On continue l’opération jusqu’à ce qu’il ne reste plus aucuns
chiffres.
Ainsi, on affiche le message “yes”.
Voici pour les esprits tordu (dont je fais partie) une version intéressante de la machine de turing cette fois-ci en bash (Pour vous montrer que cette machine peut être codée avec presque n’importe quoi) : 4
#!/bin/bash
#turing.sh V0.21
# This is an turing machine implemented in Bash.
if [ -z "$1" ]; then
echo "You should specify an input file!" 1>&2
exit 1
fi
oldIFS=$IFS
state=0
line=0
endless=1
bandwidth=79
pos=0
alpha[0]=" "
alpha[1]="1"
alpha[2]="0"
alphasize=2
#Init Band
IFS=$'\n'
echo "# opening: $1"
for l in $(cat $1 |sed "s/\#.*//g"|sed "/^\s*$/d"|sed "s/^\s*//g"|sed "s/\s*$//g")
do
p=0
cor=0
((line+=1))
echo -n "$line: "
echo $l>&2
case ${l:0:1} in
"<"|"I")
it=""
for i in `seq 2 ${#l}`; do
c=${l:(($i-1)):1}
cok=0
for j in $(seq 0 $alphasize)
do
if [ "$cok" -eq "0" ]; then
if [ "$c" == "${alpha[$j]}" ]; then
cok=1
fi
fi
done
if [ "$cok" == "1" ]; then
band[(($p-$cor))]=$c
it="$it$c"
else
echo "# Ignoring character '$c' @$line:$pos." >&2
((cor+=1))
fi
((p+=1))
done
echo "# (I@ 0) $it">&2
;;
"!"|"S")
state=${l:1}
echo "# S: $state"
;;
"."|"P")
pos=${l:1}
echo "# P: $pos"
;;
"L")
bandwidth=$((${l:1}-1))
echo "# L: $bandwidth"
;;
"@"|"A")
p=1
al=""
alphasize=$((${#l}-1))
for i in $(seq 2 ${#l})
do
c=${l:(($i-1)):1}
alpha[$p]=$c
al="$al$c"
((p+=1))
done
echo "# A: $al ($alphasize symbols)"
;;
*)
IFS=","
a=($l)
count=0
while [ -n "${a[$count]}" ]
do
((count+=1))
done
if [ "$count" -ne "5" ]; then
echo "# Missformed Statedescription @$line -- ignoring (program will not work properly)" >&2
echo "# Statedescribtion looks like: State,Symbol expected,Symbol to write,Headdirection,Next State">&2
else
stat="${a[0]}"
expect="${a[1]}"
write="${a[2]}"
move="${a[3]}"
next="${a[4]}"
#echo "# State: $stat"
#echo "# expecting: $expect"
#echo "# write: $write"
#echo "# move to: $move"
#echo "# next state: $next"
if [ "$next" == "F" ]; then
endless=0
fi
index=$(($stat*($alphasize+1)))
#case $expect in
# # " "->((index+=0))->dumm
# "0")
# ((index+=1))
# ;;
# "1")
# ((index+=2))
# ;;
#esac
ok=0
off=0
wok=0
#echo $alphasize
IFS=$oldIFS#$"\n"
for i in $(seq 0 $alphasize)
do
#echo "\$i=\"$i\""
#echo "\$alpha[$i]=${alpha[$i]}"
if [ "$ok" -ne "1" ]; then
if [ "$expect" == "" -o "$expect" == "${alpha[$i]}" ]; then
((index+=$off))
ok=1
fi
fi
if [ "$wok" -eq "0" ]; then
if [ "${alpha[$i]}"=="$write" ]; then
wok=1
fi
fi
((off+=1))
done
if [ "$ok" -eq "0" ]; then
echo "# Unspecified symbol '$expect' expected @$line">&2
exit 1
fi
if [ "$wok" -eq "0" ]; then
echo "# Should write unspecified symbol '$write' @$line">&2
exit 1
fi
eval "states_write[$index]=\"$write\""
eval "states_move[$index]=\"$move\""
eval "states_next[$index]=\"$next\""
fi
IFS=$oldIFS
esac
done
echo P: $pos
if [ "$endless" -eq "1" ]; then
echo -n "## This seems to be an endless turing machine. Do you realy want to start it? [y/N] ">&2
read -n 1 ant
echo >&2
if [ "$ant" != "y" ]; then
exit 0
fi
fi
echo $state
cycles=0
until [ "$state" == "F" ]
do
((cycles+=1))
echo -n "# ($state@$(echo $cycles|gawk '{ printf "%5d\n", $1 }')) "
for i in $(seq 0 $bandwidth)
do
if [ "$i" -eq "$pos" ]; then
echo -n "_${band[$i]}_"
else
echo -n "${band[$i]}"
fi
done
echo
#Read
data=${band[$pos]}
#echo "$state*($alphasize+1)"
index=$(($state*($alphasize+1)))
ok=0
off=0
IFS=$oldIFS
#echo "# Data: $data@$pos"
for i in $(seq 0 $alphasize)
do
if [ "$ok" -ne "1" ]; then
#echo "\"$data\"==\"${alpha[$i]}\""
if [ "$data" == "" -o "$data" == "${alpha[$i]}" ]; then
#echo "# Found ${alpha[$i]}@$i+$off"
((index+=$off))
ok=1
fi
fi
((off+=1))
done
if [ "$ok" -eq "0" ]; then
echo "# Unspecified symbol '$data'!">&2
exit 1;
fi
#case $data in
# "0")
# ((index+=1))
# ;;
# "1")
# ((index+=2))
# ;;
#esac
#Write
#echo "## Writing: ${states_write[$index]}@$index"
if [ -z "${states_write[$index]}" ]; then
echo "## State: ($state,$data) is not defined! Halted.">&2
exit 1
fi
band[$pos]=${states_write[$index]}
#Move Head
case ${states_move[$index]} in
"<")
((pos-=1))
;;
">")
((pos+=1))
;;
esac
if [ "$pos" -lt "0" ]; then
#pos=$bandwidth
pos=0
for (( i=bandwidth-1;i>0;i-- ))
do
band[i]="${band[$i-1]}"
done
band[0]=" "
fi
# if [ "$pos" -gt "$bandwidth" ]; then
# pos=0
# fi
#jump to next state
#echo "$index: ${states_next[$index]}"
state=${states_next[$index]}
if [ "$state" == "F" ]; then
((cycles+=1))
echo -n "# ($state@$(echo $cycles|gawk '{printf "%5d",$1}')) ">&2
for i in $(seq 0 $bandwidth)
do
echo -n "${band[$i]}">&2
done
echo>&2
echo "# Reached final state. Needed $cycles cycles">&2
fi
#t=$(($state * ($alphasize+1)))
#for i in $(seq 0 $alphasize)
#do
# if [ -z "${states_write[$(($t+$i))]}" ]; then
# echo "## State '$state' is not well defined!">&2
# exit 1;
# fi
#done
done
echo "### END ###"
exit 0
Je n’ai pas trouvé l’occasion de placer une formule de mathématique dans mon rapport. Voici la formule de Taylor-Young tirée de mon cours de math si jamais: .