Ok,
iniziamo. Iniziamo per oggi.
Ok. L'ultima cosa che abbiamo introdotto
sono Ma che i Touring non determin
abbiamo visto un po' di esercizi un po'
di roba del finastro. Poi quello che
abbiamo visto è che essenzialmente
eh le macchine di touring non
deterministiche possono essere simulate
da macchine deterministiche
che ci costa un fottio riuscirà a fare
sta cosa costa exponential time. Ok?
E sostanzialmente quello che abbiamo
visto è che noi possiamo simulare queste
macchine con altre macchine, quindi
utilizzeremo utilizziamo il paradigma
non deterministico perché ci torna
comodo in quanto noi possiamo simulare
macchine non deterministiche tramite
macchine deterministiche e per quello di
cui ci occupiamo al momento, che è
soltanto la decidibilità dei problemi,
che ci mettiamo exponentiale. Noi ci
mettiamo double exponential time, a noi
non ce ne importa assolutamente niente,
l'importante è che sia parti, ok?
Dopodiché abbiamo introdotto la classe
R, la classe R dei problemi, i problemi
decidibili, i problemi indecidibili, vi
ricordo che tutto ciò che è in R è
decidibile. Perché lo chiamiamo
decidibile? Perché quello che è in R
ammette un algoritmo, cioè ammette una
procedura finita
che ci risponde sempre sì o no. Ok?
Quindi è decidibile, richiamo decidibili
tutto ciò che ammette un algoritmo.
Al di fuori di R ci stanno i problemi
indecidibili, cioè problemi per i quali
non esiste un algoritmo. Ok?
Abbiamo poi introdotto il re che è
questa piccola
finezza, no? che sono i problemi
semidecidibili, che comunque è una gran
fregatura perché non è che se un
problema è semidecidibile noi ce ne
facciamo un granché perché gli algoritmi
che abbiamo per i problemi
semidecidibili ma non decidibili ci dà
garanzia di risposta in caso di risposta
sì, ma non ci dà garanzia di risposta in
caso di risposta no. Di conseguenza non
è che ci toglie fuori dal limbo se dopo
due mesi di calcolo ancora non abbiamo
una risposta e prima che se ranna ancora
alla fine ci darà una risposta, non lo
sappiamo. Di conseguenza i problemi
semidecidibili in realtà sono per noi
indecidibili, ok? Cioè da un punto di
vista prettamente algoritmico
non è che ci offrono chissà quale
vantaggio rispetto agli altri. Adesso,
se un problema è decidibile, noi siamo
in grado con un algoritmo di dare sempre
una risposta. Quindi avevamo R, re che
sono i problemi semidecidibili. Al di
fuori di R ci sono cose completamente
indecidibili nel quale non abbiamo
nessun tipo di garanzia, né per il sì né
per il no che dipende, vedremo altre.
Ok,
ritorniamo con la mente alla simulazione
della macchina non deterministica. Ok,
noi abbiamo una simulazione
deterministica di una macchina non
deterministica. Preparare la lezione di
oggi è stato interessante perché mi
dovevo inventare una storia e non sapevo
come appiccicarla. Questo è quello che
mi sono inventato. Allora, se ritorniamo
con la mente
alla alle macchine non deterministiche,
noi abbiamo che possiamo fare una
simulazione deterministica.
Ok?
Focalizziamoci sulla simulazione
deterministica.
Il simulante,
ok, che è deterministico,
sa fare altro che non quello che faccia
il simulato.
È chiara la domanda? Cioè la macchina
che noi tiriamo fuori, noi partiamo da
una macchina non deterministica, ok? La
trasformiamo con un'opportuna procedura
in una macchina deterministica che
sappiamo che si può fare. Ok?
Allora, la mia domanda è la macchina
simulante, cioè quello che noi otteniamo
che è deterministico,
fa altro, cioè è in grado di riconoscere
cose diverse rispetto al simulato?
Se dimostriamo che la macchina non
deterministica riesce anche essa a
dimostrare la simulante, ovvero una
macchina deterministica, allora
dimostriamo che entrambi hanno lo stesso
potere espressivo.
Sì. Ok. Questo è da un punto di vista di
potere espressivo, è ovvio. Domanda
domanda è passante. Secondo voi una
macchina non deterministica è in grado
di fare ciò che una macchina
deterministica fa?
Sì. Perché?
Sì, non deterministica di particolare
deterministerministica
può fare quello che una macchina
deterministica fa semplicemente non
usando il non determinismo. Ok? è
standard, proviene da definizione. Poi
noi abbiamo che una macchina
deterministica, cioè se partiamo da una
macchina non deterministica, noi la
possiamo simulare in maniera
deterministica con un approccio
particolare che è l'esplorazione per
livelli delle dell'albero di
computazione eccetera. Ok? Ma la mia
domanda è la macchina deterministica che
si è simulante
la macchina non deterministica che è
simulata?
Fa è una macchina generica il simulante?
Dico o fa solo quello che fa il
simulato?
fa solo quello che fa il simulato, cioè
il simulante
è una macchina la cui funzione di
transizione viene definita apposta, cioè
sa fare quello, sa simulare il simulato,
non è che sa fare altro, ok? Cioè,
quindi partendo da ogni macchina non
deterministica,
la macchina deterministica simulante è
progettata apposta, è tenoro, cioè è
sartoriale. Noi prendiamo la macchina
non deterministica, c'ha quel tipo di
transizioni,
noi li ficchiamo nella funzione di
transizione di una macchina
deterministica simulante e il simulante
fa solo quello. Ok?
A voi risulta che una macchina
deterministica o non deterministica
durante il calcolo può cambiare il
proprio programma di esecuzione?
No, cioè la funzione di transizione è
carded,
cioè la macchina quello fa, non sa fare
altro. Quindi il simulante
deterministico, sebbene in maniera più
lenta, sostanzialmente fa quello che fa
il simulato, ok? Non è una macchina
generica, è una macchina progettata
apposta che fa solamente quella cosa là.
Però questa non è la nostra esperienza
diretta di computer.
La nostra esperienza diretta di computer
è che un computer noi gli diamo un
programma e quello sempre il programma
che gli diamo. Cioè un un computer per
quella che è la nostra esperienza
diretta è qualcosa di programmabile,
cioè qualcosa che la sua funzione di
transizione pare prendersela da un
programma. Ok? È chiaro? Dov'è qui
l'inghippo, cioè fino ora abbiamo visto
modelli di calcolo che fanno una sola
cosa, cioè una volta che fissiamo la
funzione di transizione sulla macchina
di Turing, la macchina quello fa, non è
che sa fare, sa svolgere altri compiti,
quello sa fare un linguaggio sa decidere
o accettare e non fa nient'altro.
Però abbiamo detto che le macchine in
Touring sono potenti quanto i computer
nostri. E com'è sta faccenda, cioè i
computer nostri, a differenza delle
macchine di Touring, pare possano
ricevere in input un programma, ok? e
adattare la loro funzione di transizione
al programma ricevuto, cioè il computer
che noi abbiamo sul nostro tavolo
svolge compiti, svolge programmi vari,
non è come la macchina di Touring che ne
svolge uno solo. Com'è sta questione? E
adesso dobbiamo risolvere questo
mismatch. mostreremo che e poi
introdurremo nella seconda parte altri
altri problemi, mostreremo che i nostri
computer sono in realtà delle macchine
di touring particolari,
macchine di touring che andremo a
definire ora, ok?
Un computer è sostanzialmente
quello che noi chiamiamo una macchina di
touring universale. Ok? Questo è un
computer
macchina
di Turing
Universale.
La macchina di tuning universale è un
tipo di macchina di tuning che è uguale
alle macchine che abbiamo visto finora,
solo che è in grado di eseguire un
programma.
Questa è la differenza. Ok? è questo che
lo rende universale, cioè la ci sono
delle macchine di tuning che adesso
vedremo, la macchina di tuning
universale che è una macchina che è in
grado di comportarsi come altre macchine
se gli diciamo come fare. Ok, questa è
l'idea.
I nostri computer
ricevono un programma e sulla base del
programma pare che iniziano a svolgere
cose differenti, no? E di fatto questa è
la nostra esperienza. Possiamo scrivere
un programma per calcolare una certa
cosa. Possiamo scrivere un programma per
calcolare un'altra cosa, no? Quindi pare
che il tipo di calcolo che loro facciano
dipende che loro fanno, dipende da un
programma che noi passiamo e questo è
diverso dalle macchine di touring viste
finora. Una macchina di Turing che
andremo a vedere ora è una macchina di
Turing che è in grado di comportarsi
come qualsiasi altra macchina di Turing
nel momento in cui gli diciamo come si
fa. Ok? È chiaro? Questo è il nostro
obiettivo. Quindi, in questo primo pezzo
di lezione noi andremo a vedere questo
modello di calcolo che è la macchina di
tingers che praticamente fa da ponte fra
quello che abbiamo visto finora e i
computer che siamo abituati a
utilizzare. Ok?
Allora, quello che ci dobbiamo inventare
però a questo punto è come facciamo a
insegnare una macchina di Turing a
comportarsi come un'altra macchina di
Turing. Questa è la cosa, cioè noi ci
dobbiamo inventare un codice per i
programmi, sostanzialmente come abbiamo
il codice Java, C++, Python, whatever,
ci dobbiamo inventare un codice che ci
permetta di insegnare a questa macchina
universale a fare le cose che fanno le
altre macchine di Turing. È chiaro? Ok?
Per le macchine che abbiamo visto
finora, cos'è il programma di queste
macchine?
E la funzione di transizione, cioè la
funzione di transizione delle macchine è
il loro programma che abbiamo detto è
fissato. Una volta che la macchina è
progettata, costruita, quello non
cambia. Ok? Quindi noi ci dobbiamo
inventare un modo per codificare
una le funzioni di transizione in
maniera tale che queste possono essere
usate come input di un'altra macchina e
questa macchina universale prende il
codice della funzione transizione di
altre macchine e si comporta come
quelle. Ok? Quindi è una macchina che
avrà il potere di comportarsi come tutte
le altre macchine, ok? Per questa
ragione la chiamiamo macchina
universale. Ok?
Allora,
ovviamente uno si può inventare tutti i
modi che vuole per codificare le
funzioni di transizione. Ce ne stanno a
Bizzef,
noi ne prendiamo uno preso dal libro di
eh di Hopcroft. Ok?
Allora, facciamo alcune semplificazioni
su sul tipo di macchine che andremo a a
simulare.
Semplificazioni che non tolgono il
potere esecutivo alle macchine, hanno lo
stesso potere delle macchine che abbiamo
visto finora. Ah, solo per semplificarci
un po' la vita a noi. Se siete
interessati nella dimostrazione di
eguaglianza ci sta sia negli appunti di
Calautti che nel libro di Hccroft. Ok?
La macchina che consideriamo è una
macchina in cui al tabellin input ha
solo due simboli, 0, ok?
E il eh
questo qua e poi invece l'alfabeto di
l'alfabeto
di nastro può essere 01 blank più altra
roba. Ok? Quindi noi dobbiamo codificare
questa cosa. Allora, siccome noi
dobbiamo codificare la funzione di
transizione,
la funzione di transizione ha
generalmente questa forma.
Se siamo in uno stato qui e leggiamo un
simbolo XJ,
allora
andiamo in uno stato QK,
scriviamo un certo simbolo L e ci
muoviamo di una certa direzione di M.
Ok? E questa è la definizione generale
di una di un'istruzione, diciamo, della
funzione di transizione. Ok?
Che ad esempio avremo qualcosa del
genere. Delta di Q3 che leggo blank,
vado in Q5,
scrivo 0 e mi sposto a destra. Ok?
Quindi questo è quello che dobbiamo
codificare. Allora, la codifica che
facciamo
è questa qua.
Noi codifichiamo
questi simboli
cui X con J, QK, X con L e D con M
partendo dai loro perici.
Ok?
Allora, ogni volta che noi, quindi noi
faremo questa cosa qua, la codifica
di Q avverrà tramite una sequenza di I0,
ok? Per dire Q5 metteremo 5 00.
Ok?
La codifica di X noi metteremo J0.
[Musica]
Per la direzione
noi assumiamo che sinistra
sia D1 e destra sia D2.
Quindi facciamo un esempio. Supponiamo
che vogliamo codificare questa questo
pezzo di funzione di transizione, ok?
Questo piccolo codice.
Allora, noi la codificheremo così.
Q3 00
e questo ci codifica Q3.
Dopodiché devo scrivere blank.
L'assunzione che faccio perché
x con 1 è il simbolo 0. Facciamo
scriviamolo da un'altra parte.
X con 1 è il simbolo 0, X con 2 è il
simbolo 1, X con 3 è il simbolo bianco,
X con 4 e altri sono gli altri simboli
di nastro della macchina. Ce li
facciamo, ce li assegniamo come
vogliamo.
Q1
è sempre lo stato iniziale.
[Musica]
Mi state vedendo?
Ok.
Q2
è sempre
il singolo stato accettante.
Ok? Quindi sono semplicemente assunzioni
sui nomi che diamo. Dobbiamo codificare
la funzione di transizione. Allora,
abbiamo che gli stati sono Q1, Q2, Q3,
bla bla bla. Q1 è sempre lo stato
iniziale, Q2 è sempre lo stato
accettante. Gli altri sono altra roba.
Cioè li potevamo chiamare Pippo e
Paperino, li chiamiamo Q1 e Q2. È la
stessima cosa. Ok? Il simbolo X1 è
sempre 0, X2 è sempre 1, X3 è sempre,
tutti gli altri gli diamo il nome che
vogliamo. Direzione uno è sinistra,
direzione 2 è destra. Ok? Sono
convenzioni, possiamo decidere quello
che vogliamo perché dobbiamo
semplicemente trovare il modo di
codificare
i pezzi della funzione di transizione in
una stringa binaria. Questa è la
questione, ok? Perché sennò alla
macchina universale non glielo riusciamo
a dire in nessun modo come comportarsi,
gli serve una stringa input e la stringa
che gli diamo in input deve codificare
la funzione di transizione della
macchina che vogliamo che la macchina
universale simuli. Ok?
Ora, quindi supponiamo di voler
codificare questo pezzo qua. Allora,
facciamo così,
e questo ci codifica Q3.
Dopodiché, per separare Q3 dalla
codifica del bianco,
siccome questo qui sarà un simbolo, sarà
in particolare X3 e sarà codificato come
di nuovo 00, io ci metto un 1 che mi
separa, ok? Quindi io separo questo
pezzo da questo pezzo con un 1,
metto 1 e poi di nuovo blank che sarebbe
x3 00.
Questo è x3.
che è il blanco. Dopodiché un altro uno
in maniera tale che separo qui X5
Q5 1 2 3 4 e 5 e questo è Q5. Dopo c'è
un 1 0 abbiamo detto che è il primo
singolo, quindi c'è un non 0 soltanto.
Questo è x1, poi c'è uno di nuovo destra
che è 2, questo è d
Ok? Allora, cosa abbiamo fatto?
ci siamo inventati fra 1000 modi
possibili
un modo per codificare in binario, una
funzione, un pezzo di funzione di
transizione. È chiaro cosa abbiamo
fatto? Abbiamo semplicemente dato nomi
agli stati, nomi ai simboli, nomi
allezioni
e usiamo un certo numero di zeri per
dire q1, q2, q3, un certo numero di zeri
per dire x2, x5, x1000, un numero di
zeri per dire d1, d bla bla. Le cose le
separiamo con 1 e quella stringa binaria
1
0 secondo la nostra codifica ci sta
codificando quel pezzo di funzione di
transizione.
È chiaro?
Però questo codifica
un sola entry, una sola entry della
funzione di transizione. Noi abbiamo che
la funzione di transizione è definita
per varie coppie.
stato
simbolo. E allora come facciamo? Ne
mettiamo una in fila all'altra.
Quindi avremo un pezzo di codice
di funzione di transizione C1. Questa
qui sarà una stringa di zeri e 1 dove
l'uno non compare mai più di una volta
di fila. Ok? Quindi che faccio? Per
mettere in fila tanti pezzi di codice,
di funzione di transizione, io uso
doppio 1 1 1 e qua scrivo il secondo
pezzo della funzione di transizione 1 c3
1 c4 e così via, ok? E li scrivo tutti.
Sì.
[Musica]
Sì, però pericarci la vita ce ne
mettiamo ok. Si potrebbe fare, però poi
la macchina simulante che deve andare a
contare quanti sono c'è da un pazzien.
Allora, usiamo uno. Si può fare? Sì, si
può fare. Ok,
allora siete ci siete con me che questo
modo ci permette di scrivere in una mega
stringa binaria di codificare cosa fa
una macchina di tuning, cioè il suo
programma è codificato dentro una
stringa binaria.
È chiaro? È chiaro come facciamo? È un
modo. Ci sono infiniti modi. Noi
scegliamo questo, ok? Perché il nostro
obiettivo è poter comunicare
a una macchina di touring come
comportarsi
rispetto a un'altra. Se dici, guarda,
quest'altra macchina in presenza di
questo simbolo e questo stato fa questa
cosa qua, ma io glielo devo dire in
qualche modo. Glielo dico in questo
modo. Ok? È chiaro?
Quindi in qualche modo,
questo poi lo vedremo anche dopo, però
abbiamo una prima intuizione del fatto
che
alcune, cioè che le stringhe binarie
possono mess possono essere messe in
associazione con possibili macchine di
tuning.
Ok?
Adesso ci saranno stringhe binarie che
non codificano macchine di tuning, cioè
per esempio stringhe con 4-1 di fila non
fa parte della nostra codifica. Ok?
Quindi recap, una macchina di Turing può
essere codificata guardando la sua
funzione di transizione. Se ci
inventiamo un modo di codificare la
funzione di transizione, noi siamo in
grado di trascrivere
il programma di una macchina di tuning
in una stringa binaria e ci siamo
inventati quello. A questo punto vuol
dire che c'è un'associazione fra
stringhe binarie e macchine diing. Però
questa associazione non è così forte
perché ci stanno stringhe binarie che
non non seguono quella codifica. Ok?
Allora, assumiamo che le stringhe
binarie che non seguono quella codifica
sono macchine con un solo stato non
accettante, cioè sono macchine che
rifiutano tutto, dicono no su
qualsiasio. Ok? Giusto un'assunzione.
Quindi avremo molti modi di descrivere
una macchina che non fa niente, ok?
solo per convenienza. Chiaro?
Allora, possiamo a questo punto, siccome
ci siamo inventati un modo per
codificare il funzionamento di una
macchina di Turing, possiamo
far riferimento alla
macchina di Turing universale che
chiameremo mu
da ora in poi perché la useremo un po'
di volte. Allora, che fa sta macchina
diuring? Questa macchina di uring riceve
in input una codifica
di una macchina secondo la codifica che
abbiamo visto, più una certa stringa
input per quella macchina.
E la macchina universale è in grado di
dirci se la macchina ricevuta input
tramite la codifica accetti o meno la
strunga input. Ok? Quindi la macchina
universale
sarà
Ok, mo spiego così. Ritorniamo a questa
cosa qua.
Sì. Eh, ok. È utile fare così. Abbiamo
detto che questa è una stringa binaria,
ok? Quindi possiamo associare le
stringhe binarie a macchine di tuning.
Notate che queste stringhe son
particolari perché iniziano con zero.
Vedete che iniziano tutte con zero.
Allora, noi possiamo usare questo
trucchettino.
Se noi infiliamo un bell uno di fronte a
una codifica di una macchina di ting,
quello là sarà un numero intero.
È chiaro? Quindi le macchine di Turing
possiamo in effetti contarle. La prima
macchina di Turing che è uno seguito
dalla stringa vuota, la seconda macchina
di Turing che è uno seguito da Z0, la
terza macchina di Turing che è uno
seguito da 1 e così via. Ok? Quindi noi
possiamo in effetti associare a ogni
numero, possiamo dire la terza macchina
di Touring, la milionesima macchina di
Touring. Come si fa? Si prende la
codifica binaria, si toglie l'uomo
iniziale, quello è il codice di
marketing. Ok? Ci serviva per la
definizione di dopo. Ok? È chiaro?
Le stringhe binari, di nuovo, le
stringhe binari che non seguono quella
codifica, allora sono per noi macchine
di Turing che dicono no su qualsiasi
cosa, cioè il loro linguaggio è vuoto.
Gli diamo un input, no? Gliene diamo un
input, un altro? No, dicono sempre di
no. Allora, la macchina di Turing
Universale
è
una macchina che riceve input una
stringa binaria codificando
che codifica, per esempio, la
iima
stringa,
la iesima macchina
e poi una stringa W.
Ok?
E questa macchina più in generale
possiamo semplificare riceve coppie MW
tale per cui M è una stringa che
codifica la funzione di transizione
della macchina M e W è un input per M.
La macchina MU è una macchina che
ricevuto input il programma M e l'input
w* m è in grado di dirci se M avrebbe
accettato - w. Ok?
Quindi questa macchina universale è una
macchina un po' particolare perché è una
macchina il cui suo programma è fissato.
Vedremo che è fissato, però input è in
grado di ricevere queste coppie.
Macchina M, stringa
binario. La macchina M è codificata con
la codifica che abbiamo visto prima.
L'input è l'input che vogliamo dare
impasto a M. La macchina universale è
cosa è in grado di fare? Sostanzialmente
la macchina universale simula M
su w. Se M accetta W, mu dirà sì.
Se M non accetta W, MV dirà no. Ok?
Quindi è un un decisore universale, cioè
perché è un decisore in grado di
comportarsi come altre macchine che gli
vengono descritte input tramite la
stringa doppia, la stringa M che
codifica una funzione di transizione.
Chiaro per tutti come funziona questa
macchina? Cioè qual è l'obiettivo di
questa macchina? Questa macchina è una
macchina che
prende in input un programma
e un input, un programma che stiamo
chiamando M, che è che cosa? La funzione
di transizione della macchina che
chiamiamo M. E prendo un input per
questo programma.
La macchina universale
è in grado di dirci se il programma M
quando riceve W input risponde sì o
risponde no.
È chiaro? Ok. Come funziona
questa macchina?
Stavolta son venuto senza appunti,
guardo velocemente.
Alri.
Ci sono vari modi in cui sta simulazione
si può fare. Prendo quella di OPCroft.
Ok,
questa 1 2 3 4. È una macchina a quattro
nastri. 1
2
3
e 4.
Questa è MU. Eh,
quindi la macchina MU ha quattro nastri.
Noi sappiamo che una macchina
multinastro può essere convertita in una
macchina monoastro, quindi siamo nel
reame delle cose fattibili. anche
standard. Sì, la Q è o no? È la string è
una stringa binaria perché stiamo
assumendo che m il suo alfabeto di sia
binario, cioè quindi il wio
quello che m prenderebbe input. Sì,
cioè, quindi anche questo
all'inizio. Sì, cioè quello che m dice
input è la codifica binaria di M e la
stringa W che andrebbe in passo ad M.
Quindi la stringa Wien alfabeto
originale di M che è binario per la
funzione. Ah, ok. Perché per
semplificità si può dimostrare che le
macchine con alfabeto binario hanno lo
stesso potere di tutte le altre
macchine. Ok? Quindi lo facciamo per
semplice. Quindi l'alfabeto di input di
M è binario, quindi W è proprio la
stringa che nell'impasto a M. Ok?
Allora,
cosa fa
la macchina U? Riceve input M, che è
quella codifica là,
e w. Vi ricordo che m cioè la codifica
che noi ci siamo inventati per le
macchine di Touring che è una lista di
codici, cioè che per ogni entry della
funzione di transizione abbiamo quello
w1, un altro pezzo W1 eccetera. In m non
compaiono mai 31 di fila, quindi m e w
li dividiamo con 3 uni. Ok? In questo
modo abbiamo doppio input sul nastro di
input.
Allora, come si comporta MU? MU si
comporta seguendo passo passo quello che
fa M sostanzialmente. Come fa a farlo?
Perché nel proprio input su primo nastro
ha la descrizione completa della
funzione di transizione di m. Questo è
il trucco. Ok? Quindi mo che cosa fa?
Come primo passaggio prende W
e lo ricodifica secondo, in questo caso,
i simboli che ci siamo inventati, X1,
X2, ok? e gli mette là, che ne so, se W
era 01,
questo abbiamo detto che è x1, questo è
x2, questo è x3, la sua ricodifica che
va a finire sul secondo nastro è 0 1
Ok,
qua ne mettiamo un altro perché fa così.
Ok, quindi qua c'è il eh ehm nastro
di M ricodificato.
Ok? Dopodiché la macchina U si segna lo
stato iniziale che è un partiamo da Q1.
Ok? A questo punto posiziona
sul secondo nastro la testina sul
simbolo visto da M e posiziona sul terzo
nastro la testina sullo stato corrente
di Mulato.
Ok?
La macchina
guardando il proprio secondo nastro e il
proprio terzo nastro,
sa
in quella fase di simulazione
in quale stato è la macchina M e quale
simbolo la macchina M sta leggendo.
È chiaro? Chiaro? Perché? Perché noi
stiamo simulando sul secondo nastro
quello che sarebbe il contenuto di
nastro di M. Su terzo nastro noi teniamo
traccia di qual è lo stato corrente di
N. Ok? Quindi da terzo nastro noi ci
prendiamo lo stato corrente. Qui sto
descrivendo il funzionamento di MU.
Quindi MU che fa? Va su terzo nastro.
Guardando su terzo nastro può sapere
qual è lo stato simulato di M.
guarda sul secondo nastro e può sapere
qual è il simbolo letto da Mulla
simulazione del nastro di M, che è il
secondo nastro di Mo. Da questa coppia
la macchina che fa? Va sul primo nastro
dove c'è la codifica della funzione di
transizione di M e va alla ricerca di un
pezzo di codice, cioè di un entry per la
funzione di transizione che è
esattamente per la coppia stato simbolo
attualmente simulato. È chiaro?
Quindi leggendo quel pezzo di codice, la
macchina universale che cosa saprà?
Saprà in quale stato transire, cosa
scrivere e dove spostare la destina.
Avete seguito fin qua? Quindi cos'è che
fa sta macchina MU? La macchina MU
simola la macchina M passo passo come
tenendo traccia di due cose,
il nastro della macchina M e lo stato
corrente della macchina M. Il nastro
della macchina M noi lo stiamo simulando
sul secondo nastro di MU. Lo stato
corrente della macchina M lo stiamo
ottenendo traccia sul terzo nastro di
MU. Quindi che facciamo? Andiamo a
leggere il simbolo su secondo nastro, lo
stato su terzo nastro. Andiamo alla
ricerca su primo nastro, dove c'è la
funzione di transizione di m, andiamo
alla ricerca di un entry della funzione
di transizione per la coppia stato
simbolo che abbiamo appena guardato. È
chiaro? Una volta che leggiamo questo,
la macchina universale che può fare?
può
aguornare
lo stato perché sappiamo quale sarà il
nuovo stato di M e può andare a
ritoccare
il nastro simulato di M andando a
sostituire il simbolo. Ok? Adesso i
simboli che noi abbiamo sul secondo
nastro sono dei simboli simulati, sono
hanno questa forma qua, quindi potrebbe
essere necessario che ci serve un po' di
spazio o comprimiamo un po' di cose.
Ecco a che serve il quarto nastro serve
a fare un po' dii lavori di copia
incolla, ok? Per estendere o accorciare
il secondo nastro. È chiaro come
funziona questa macchina? La macchina
universale? Sì, prego. Ma sul secondo
nastro eh viene tradotto sia M che W o
soltanto R? Eh no, su primo nastro
sul secondo nastro c'è la simulazione di
cosa sta facendo M su do. Ma io non
tocco mai il primo nastro? No. Ok?
Perché il primo nastro c'è il programma
e io il programma non lo voglio
cambiare. Io sul primo nastro vado a
guardare le entry della funzione di
transizione per rendermi conto ma m in
questa situazione che farebbe? Ah,
transisce in questo stato, scrive sta
cosa e sposta a destra. E io che faccio?
Aggiorno il terzo nastro per dire qual è
il nuovo stato. Modifico il contenuto
del secondo nastro per simulare il
contenuto della macchina simulata e poi
sposto la testina sul secondo nastro
indipendenza o a destra o a sinistra,
indipendenza di dove m andrebbe,
ma quindi eh io tengo anche traccia di
cosa sta succedendo in input leggendo il
primo nastro, oltre a simulare
certamente sul secondo, no? Quello sul
secondo nastro noi stiamo simulando
quello che la macchina M farebbe sul
proprio nastro, ma non va appunto con lo
scopo di risolvere l'input che gli Sì,
sì, sta facendo lo stesso lavoro di M,
lo sta simulando.
È chiaro?
Perché fa passo dopo passo dice: "Ok, in
che stato si trova la macchina M?" Che
cosa farebbe? Ok, lo replico. Vado a
guardare in che condizioni mi trovo. Ah,
ok, stato singolo. Vado a riguardare la
funzione di transizione. Che farebbe m
in questo caso? Si addormenterebbe. No,
si prende un gelato, no? Fa questa cosa
qua, aggiorno il terzo nastro, aggiorno
il secondo nastro e vado avanti. Cioè,
per ogni passo di m io faccio replico la
stessa cosa sul secondo nastro e tengo
aggiornato il terzo nastro per sapere lo
stato corrente di m.
Il quarto nastro lo uso per
scarabocchi. Ok, scusi se glielo chiedo,
peròamente chiaro. E sul secondo nastro,
cioè io quindi copio, traduco la solo la
parte input, non la macchina di touring.
Sì, solo il W e quindi eh secondo la
codifica che ci serve. Ok. Mentre mi
tengo conto di cosa devo fare mediante
il primo nastro. Mediante il primo
nastro. Sì. Sì, prego. Ma se
la blop input mettiamo che c'è 01 Sì. E
quindi 0 con 10 e quell'altro è 100. Sì.
La magia mi dice quale? M o mu? M M mi
dice trasforma questo 0 in uno. Sì.
Quindi dovrei cambiare 0 e con 00.
Quindi ti serve dello spazio. Ok. Devi
fare spazio. Usi il quarto nastro per
fare scarabocchi, cioè per fare copia
incolla e crearti lo spazio che ti
serve. Ecco a che serve il portonastro.
Chiaro? Chiaro per tutti che questa
macchina MU fa passo passo quello che fa
la macchina M. Quindi se la macchina M a
un certo punto arriverà a uno stato
accettante, la macchina MU se ne accorge
e accetta.
Se la macchina MU se la macchina M si
blocca in uno stato non accettante, pure
la macchina MU si bloccherà da qualche
parte e rifiuta. Se la macchina M non si
ferma mai, la macchina MU andrà avanti
all'infinito e come M non accetta.
Quindi è chiaro che la macchina MU sta
sostanzialmente
eseguendo il programma M.
In questo modo ci siamo creati una
macchina di Turing programmabile, cioè è
una macchina di Turing universale, cioè
una macchina di Turing che è in grado di
simulare il comportamento di altre
macchine di tuning. Domanda la funzione
di questa macchina, questa la chiamiamo
la macchina universale, no? Per
convenzione chiamiamo la transizione, la
funzione di transizione universale il
programma della macchina universale,
cioè il fatto che sta macchina simula le
cose.
È chiaro? Cos'è la funzione di
transizione universale? Ok. La macchina
di Turing universale durante la propria
esecuzione cambia la propria funzione di
transizione universale?
No, è sempre quella, fa sempre quel
lavoro. Ok? Quindi questa macchina,
cioè, non è che cambia la sua funzione
di transizione, ha una funzione di
transizione fissata che è in grado di
simulare il comportamento di macchine
con altre funzioni di transizione. È
chiaro? Cioè, questo deve essere chiaro.
Cioè, quindi questa macchina non è che
veramente caniante. Questa macchina di
nuovo lo sa fare solo una cosa, mette in
atto la funzione di transizione
universale che però è particolare e gli
permette di simulare il comportamento di
ante.
Ultime osservazioni e poi facciamo
pausa. I computer che noi abbiamo sono
computer, sono macchine universali di
più,
chiaro?
Quindi avranno una funzione universale
fissata. Qual è? Sì, il ciclopaspetto
del CPU. È il micro della CPU. Cioè il
microcodice della CPU è la funzione di
transizione universale dei computer che
usiamo. Pure i computer che noi usiamo
in realtà loro non è che eseguono un
programma che noi gli diamo. Loro un
programma eseguono che è il microcodice
della CPU che fanno? prendono da memoria
un istrizione, fetch, la decodificano,
la mettono in atto e vanno a prendere
l'altra e continua così, all'infinito.
Quindi un microprocessore reale è in
effetti una macchina di Turing
universale, la cui funzione di
transizione universale è il micropodice
del processore.
È chiaro? Allora, quindi questo copre il
gap tra Ma com'è che le macchine di
puring non si programmano i computer non
si si programmano, nemmeno quelli si
programmano. Cioè la loro programmazione
è che entrambi hanno una funzione
fissata.
Ok? La ma during ha la funzione di
transizione universale, i processori
hanno il microcodice. Una esegue la
funzione di transizione universale per
simulare altre macchine. I processori
usano il loro microcodice che è fissato
per eseguire programmi generici. Ok, è
chiaro? Pausa. Facciamo qua.
Alr
[Musica]
mi prendi. Ok,
let's start again.
Quindi a un certo punto abbiamo parlato
dellesima macchina M eccetera e avete
visto che poi non l'ho usata perché non
serviva. Serve ora. Ok.
Ah, ok. Quindi io questo lo cancello
proprio così non vi confondete semmai
doveste rivederlo. Questo ci serve dopo.
Alrght, quindi l'input della macchina
universale,
abbiamo detto che una coppia macchina
codificata in un certo modo stringa la
macchina universale è in grado di fare
questo lavoro interessante di simulare
la macchina N su W e darci la stessa
risposta. Ok? Quindi potremmo tra
virgolette dire la macchina universale è
una macchina programmabile, ok? Perché
riceve in input il programma da
eseguire.
Ok?
Allora, abbiamo introdotto
l'altra volta enumerotto
l'altra volta le due classi di
complessità di calcolatità
che sono R ed R
e ci siamo detti che insomma i problemi
possono stare in R, re R e e zone. Ok?
Uno di voi mi ha chiesto "Ma ci stanno
problemi qua?" "Sì, ci stanno problemi
lì" e noi andiamo a vederli, ok? Andiamo
a vedere un problema che non è
ricorsivamente numerabile, ok? E lo
definiamo ora. Poi vedremo un po' di
proprietà di linguaggi e chiudiamo per
oggi.
Alri? Allora,
se noi
adesso entri in ballo la codifica che
abbiamo parl di cui abbiamo parlato
prima, allora riconsideriamo nuovamente
macchine che processano in input
stringhe binari, ok? Quindi da adesso in
poi ci focalizziamo su macchine che il
cui input è 01, ok? Perché comunque
hanno il potere delle macchine che hanno
1000 simboli input, si può tutto
riquare, ok?
Allora,
se noi prendiamo una stringa binaria,
no, 0 1 0 bla bla bla, con quel
trucchetto che vi dicevo prima, che ora
serve prima non tanto, se noi mettiamo
un uno davanti a questa stringa binaria,
noi a quella stringa binaria possiamo
associare un numero intero, ok? Che è il
numero dato da quella codifica con l'uno
davanti. Perché ci mettiamo l'uno
davanti? Perché tante stringhe binarie
possono iniziare con zero e quindi
sarebbero indistinguibili. Allora, ci
mettiamo l'uno in maniera tale che noi
possiamo parlare della prima stringa
binaria che è che è la stringa vuota. La
seconda stringa binaria che è zero
perché sarebbe 1 concatenato 0. La terza
stringa binaria che è 1
perché avremo uno concatenato 1. La
quarta stringa binaria, ok? E così via.
A questo punto noi siamo in grado di
enumerarle e in particolare abbiamo che
le stringhe binarie con un indice più
basso perché a questo punto abbiamo la
prima stringa, la seconda stringa, la
terza stringa, ok? Noi avremo che le
stringhe binarie con indice più basso
sono tendenzialmente più corte,
ok? stringhe binarie della stessa
lunghezza sono ordinate
lessicograficamente, ok? Quindi noi
abbiamo in effetti proprio un ordine di
queste stringhe, le possiamo enumerare 1
2 3 bla bla bla. Ok? Quante sono le
stringhe binari? Quindi
infinite. Ma sono tante quanti i numeri
inferi o più dei numeri interi?
Numerabili. Ok, sono numerabili. Quindi
abbiamo tante quante di numeri interi
perché li possiamo contare la prima, la
seconda, la terza. C'è quindi una
associazione di uniloga fra l'indice e
la stringa. Le possiamo proprio contare,
quindi sono
eh contabili. Ok?
Lo stesso tipo di discorso si può fare
per le macchine diing. Le macchine di
ting, perché siccome ci siamo inventati
con la codifica che abbiamo visto prima
e quindi abbiamo che una macchina di
turing può essere associata a una
stringa binaria, ok? Se noi ci
impacchiamo l'uno davanti, quello lì un
di conseguenza pure le macchine di
Turing possono essere contate. Adesso
avremo macchine di Turing che
riconosceranno lo stesso linguaggio
perché magari hanno funzioni di
transizione differente, però alla fine
fanno la stessa cosa. Ok? Esattamente
come noi possiamo scrivere infiniti
programmi Python per risolvere un certo
problema, ci saranno macchine di touring
differenti con programmi differenti che
accettano e si esano lo stesso identico
linguaggio. Ok? Quindi poi come abbiamo
detto ci stanno tante macchine di tanti
codici di macchine di Turing che in
realtà non
rispecchiano nessuna macchina di tuning
secondo il nostro codice. Lì assumiamo
che la macchina di tuning è qualcosa che
rifleta tutto, dice no su qualsiasi
input. Ok? Quindi esattamente come
possiamo contare le stringhe binarie,
possiamo contare le macchine diingine di
fiori non sono vulnerabili. Abbiamo la
prima, la seconda, la terza, la quarta e
così via. Quante sono? Sono tante quanti
i numeri naturali, ok? Quindi abbiamo
infinite stringhe binarie e infinite
macchine di touring
e la loro numerosità è la stessa, sono
tante quanto i numeri naturali. Ci
inventiamo ora un particolare
linguaggio.
Prima di andare là definiamo cos'è
per un linguaggio L
il vettore caratteristico Q di L del
linguaggio L. Che cos'è il vettore
caratteristico di L?
Il vettore caratteristico del linguaggio
L è una sequenza binaria 0 1 1
bla bla bla infinita
che ci dice siccome noi siamo in grado
di enumerare tutte le possibili
stringhe, la prima, la seconda, la
terza, la quarta, eccetera, Il vettore
caratteristico del linguaggio L denotato
in questo modo Q di L è un vettore
binario in cui in posizione I ci dice se
la stringa iima fa parte del linguaggio
o meno. Ok? Recap Noi possiamo enumerare
le stringhe, possiamo dire questa è la
prima stringa, questa è la seconda
stringa, questa è la terza stringa e
così via, no? Di conseguenza, siccome un
linguaggio,
per definizione
è un sottoinsieme delle stringhe
costruibili su un certo alfabeto e in
questo caso stiamo considerando un
alfabeto binario,
allora il vettore caratteristico di un
certo linguaggio sostanzialmente ci dice
quale stringhe fanno parte di quel
linguaggio. Ci dicono in questo caso, la
prima non fa parte, la seconda fa parte,
la terza fa parte, la quarta no, la
quinta no, la sesta sì, bla bla bla. Ok?
È chiaro?
E un linguaggio sull'alfabeto
binario che cos'è? È un insieme di
stringhe binarie. Ok?
Alcune stanno nel linguaggio, altre
stanno fuori il linguaggio.
Per codificare un linguaggio, cioè per
descrivere un linguaggio, possiamo
inventarci questa lezione di vettore
caratteristico del linguaggio.
Lo possiamo fare
perché siamo in grado di enumerare le
stringhe, siamo in grado di dire qual è
la prima e qual è la seconda. Di
conseguenza, se noi ci mettiamo un bel
vettore dove in prima posizione mettiamo
zero, se la prima stringa fa parte del
linguaggio o in prima posizione mettiamo
uno se la prima stringa fa parte del
linguaggio e così via. Quindi in
posizione i di questo vettore mettiamo 0
se la stringa i possiamo parlare di
stringa iima perché sappiamo come
numerarle, in posizione iesima di questo
vettore ci sta zero se la stringa w con
i che noi assumiamo essereima stringa
non fa parte del linguaggio. ci mettiamo
uno in questo vettore caratteristico se
la stringa i doc parte del linguaggio L.
E chiaro che cos'è il vettore
caratteristico di di un linguaggio L? È
semplicemente una stringa binaria che ci
dice se una certa stringa i fa parte o
non fa parte del linguaggio. Tutto qua.
È chiaro? Chiaro per tutti? Perché ora
dobbiamo giocare su sta cosa e inizia un
po' a girarci la testa. Quindi mi devo
essere sicuro che cos'è un vettore
caratteristico mi sia chiaro. È
l'elenco,
potremmo dire l'elenco
delle stringhe che fanno parte del di un
certo linguaggio. Mettiamo zero se la
stringa i
mettiamo 0 in posizione i se la stringa
i esima non fa parte del linguaggio.
mettiamo uno in posizione i di questo
vettore se la stringa e iima fa parte
del linguaggio. È una lista binaria. Sì,
no, no, sì, sì, no, bla, bla. Ok? Quindi
sostanzialmente il vettore
caratteristico ci dice chi fa parte del
linguaggio e chi non fa parte del
linguaggio. Chiaro? Ok,
ci facciamo una bella tabellina.
Mettiamo sulle colonne le stringhe.
V1,
V2,
V3,
V4,
bla bla bla bla. Quindi prima stringa,
seconda stringa, terza stringa, quarta
stringa,
zone. Possiamo farlo perché le sappiamo
enumerare. Sulle righe mettiamo le
macchine di doing che anche queste
possiamo enumerare perché abbiamo
trovato un codice che associa macchine a
numeri. Quindi mettiamo la prima
macchina, la seconda macchina,
la terza macchina, la quarta macchina e
così via. Ok,
ci siete?
Anche le macchine Touring possono essere
enumerate nel modo in cui abbiamo visto.
Quindi possiamo parlare della prima
macchina, della seconda macchina, della
terza macchina.
Sì.
E nel taso me rigore ci sono particolari
che non vanno bene perché tipo quando si
definisce una funzione di transizione
della psicologica m m eh qual è stata
prima? Cioè, come scusi quali quali
coppia ha stato eh ci sono più
ricodifiche della stessa macchina. Sì,
alcune sono duplicate. Sì, alcune sono
duplicate,
altre sono diverse, ma riconoscono lo
stesso linguaggio, quindi sì, c'è dei
doppioni, ci stanno. Sì, quello sì,
quello è fuorigio. Eh,
al più potremmo farlo, potremmo farlo,
decidere che si codificano quelle prima
con indice più basso. i pezzi di
funzione di transizione che prendono le
coppie con indici più bassi eccetera,
uno se le può inventare, però in line
principio al più ci stanno dei doppioni.
Ok?
Alright. Allora, ogni macchina di
touring abbiamo detto che accetta un
certo linguaggio, no? Quindi ogni
macchina di touring su una certa stringa
ci dirà sì, no, sì, no. Ok? Quindi
supponiamo che la prima macchina di
Turing rifiuta la prima stringa, accetta
la seconda, rifiuta la terza, rifiuta la
quarta e così via. Che la seconda
macchina di Turing accetta la prima,
accetta la seconda, non accetta la
terza, accetta la quarta e così via. La
terza macchina di Touring non accetta la
prima, non accetta la seconda, non
accetta la terza, accetta la quarta e
così via. La quarta macchina di Turing
accetta la prima, non accetta la
seconda, non accetta la terza, accetta
la quarta e così via. No, è giusto un
esempio. Ok?
Allora, nelle righe
di questa tabella, che cosa abbiamo?
Abbiamo il vettore, attenzione qua
perché iniziamo a muoverci su vari
livelli, eh, sulle righe di questa
tabella che cosa compare se prendiamo
una riga? Cioè, se noi prendiamo
un'intera riga, tipo questa qua, bla,
questa riga infinita, che cos'è quello?
Quello è il vettore
caratteristico
del linguaggio accettato da lati.
È chiaro?
È chiaro che cos'è quello? Perché i
vettori caratteristici ci siamo detti
che sono liste di 0 1 che ci dicono
questa stringa sì, questa stringa no,
questa stringa sì, questa stringa no.
Ok? Quindi,
sulle righe di questa
matrice abbiamo i vettori
caratteristici,
ok? I vettori caratteristici dei
linguaggi accettati da queste marche di
Turing.
Ok, ci siete? Adesso iniziamo a fare una
piccola operazione.
Spazio C. Ok, più o meno. Sì, voi
vedete? Yes.
Ci concentriamo
sulla diagonale di questo linguaggio, di
questa matrice. Ok?
Ci prendiamo questa qua, guardate,
e la chiamiamo D.
Ok? I matematici immagino che sappiano
già dove stiamo andando a parare
e quindi abbiamo 0 1 0 1. Ok?
Questo qua che cos'è?
È la diagonale di questa matrice. Ok?
Che cos'è? È una sequenza di
bit, ok? è una sequenza di buleania.
Ok?
Da Deriamo
il suo complemento,
cioè prendiamo
la
sequenza D e la invertiamo. Dove c'è Z0
ci mettiamo uno, dove c'è uno ci
mettiamo Z0, quindi abbiamo
1 0 1 0 bla bla bla e così via. Ok?
di soprasegnato. Che cos'è? È una
sequenza di bule o no?
Siccome di soprasegnato è una sequenza
di buleani,
possiamo interpretarlo come vettore
caratteristico di un certo linguaggio?
Sì. Chi ce lo vieta?
Nessuno. Ok, ripartiamo. Abbiamo fatto
questa matrice, abbiamo preso la
diagonale, l'abbiamo complementata e
otteniamo 10 bla bla. Questo è un
esempio, eh, è giusto per ragionare.
Siccome d complementata è una sequenza
di bit e i vettori caratteristici dei
linguaggi sono sequenze di bit,
questa qui può essere interpretata
come il vettore caratteristico di un
certo linguaggio. Ok?
chiamiamo
LD
il linguaggio
il cui vettore caratteristico è questo
qua. Ok? LDX sta per linguaggio di
diagonalizzazione.
È chiaro finora che abbiamo fatto? Ci
siamo costruiti sta bella matricetta, ci
siamo presi la diagonale, l'abbiamo
complementata. Stiamo interpretando il
complemento della diagonale come un
vettore caratteristico di un linguaggio.
Chiamiamo LD
il linguaggio
il cui vettore caratteristico è questo
qua. Ok?
Possiamo fare questa operazione? Abbiamo
fatto cose strane? Non abbiamo fatto
questa strada. Ok, adesso la domanda è:
esiste o no una macchina di tuning
il cui linguaggio è LD?
Mh.
Ok,
aspetta, qua ho visto un po' di votanti
per il sì. Ok, adesso seguite questo
ragionamento.
Allora, noi in questa in questa matrice,
in questa matriciona, in questa
matriciana, ok, che cosa abbiamo?
Abbiamo la lista di tutte le macchine di
Turing. Perché? Perché le macchine di
Turing possono essere numerate, quindi
noi ne abbiamo infinite, però noi
sappiamo esattamente la 4 miliardesima
qualè. sappiamo qual è la milionesima
perché le possiamo enumerare la prima,
la seconda, la terza e insomma. Quindi
in questa matrice noi riga per riga
sappiamo chi è la macchina diing e lì ce
stanno tutte, eh, non ne stiamo saltando
perché tutte le macchine di tingono
essere codificate secondo la codifica
che abbiamo visto prima della pausa e
quindi tutte le macchine di Turing
possono avere un numero associato. Ok? E
quindi in questa mega lista, in questa
mega matrice, ci sta una riga per ognuna
delle possibili macchine di touring. Non
ne saltiamo nemmeno una, ok? Quindi se
esiste una macchina di tuning che è in
grado di riconoscere LD
deve apparire dentro una alla a una
certa riga. Ok? Per forza, perché là ce
stanno tutte. Ci siete fin qua?
Domanda.
Può essere M1 questa macchina che stiamo
cercando?
No, perché perché differisce perché
differisce il vettore caratteristico di
m1 sicuramente differisce almeno in
posizione 1. Quindi la macchina 1 un può
essere. Andiamo avanti. Può essere la
macchina due.
Matematici già lo sanno, quindi
lasciate la suspense agli altri. La
macchina M2 può essere.
Sì. No, forse no, perché
quale
e poi eh anche
il secondo riferiscono sul secondo bit.
Guardate il pattern. Eh, la prima
macchina ha un vettore caratteristico
che differisce da d soprasegnato in
posizione 1
per definizione, perché abbiamo preso la
diagonale e l'abbiamo rivoltata. Quindi
il vettore caratteristico della macchina
numero uno differisce da di soprasegnato
almeno in posizione 1. Poi può differire
anche in altri posti, ma in posizione
uno differisce. Quindi il vettore
caratteristico della macchina 1 non è di
soprasegnato.
Ok, andiamo a guardare la macchina 2. Il
vettore caratteristico della macchina 2
equivale a di soprasegnato?
No, perché il vettore caratteristico
della macchina 2 differisce da di
soprasegnato, almeno in posizione due.
Poi magari è diverso pure da altre
parti, ma in posizione du è diverso.
Quindi nemmeno la macchina 2 va bene?
Guardiamo la macchina 3. Il vettore
caratteristico della macchina 3 equivale
a di soprasegnato?
No, perché il vettore caratteristico
della macchina numero 3 differisce
rispetto a D soprasegnato in terza
posizione.
Prendiamo la generica macchina I.
È possibile che la macchina I abbia come
vettore caratteristico disoprasegnato?
Mh. No, perché posizione No, perché
miima
posizione il vettore caratteristico
della macchina numero i
differirà da di soprasegnato in
posizione i. Ma allora nessuna di queste
macchine ha come vettore caratteristico
di soprasegnato,
il che significa che non esiste una
macchina di tingetti
il linguaggio il cui vettore
caratteristico è di soprasegnato. Quindi
non esiste una macchina di tuning che
accetti LD.
Ma siccome in questa mega matrice
abbiamo la lista di tutte le macchine di
Turing che noi potremmo mai inventarci,
se non ci sta proprio una macchina di
Touring che accetta, allora vuol dire
che è un linguaggio che sta fuori e re.
È chiaro?
Ma dice, "Ma è un po' artificiale questo
linguaggio? Che cavolo è questo LD?
Perché pare che ce lo siamo inventato
apposta." Sì, ce lo siamo inventati
apposta, però ha un significato. Quindi
LD è qualcosa che sta qua fuori, è un
linguaggio che sta fuori e re. Prego. Ma
noi nello stesso modo in cui stiamo
prendendo tutte le macchine diing
esistenti, non stiamo prendendo anche
tutte le string del corpo esistenti. E
questa diagonale non fa parte di questo
esemp, cioè di questo insieme, di tutte
le Tu non prendi la diagonale, lei
prende la diagonale complementata.
Però anche la diagonale complementata
non fa parte di questo. Eh, ok,
supponiamo che faccia parte. Deve far
parte di una di una linea. Deve essere
uguale a una delle linee di questa
matrice. Mi sa dire quale?
Spari a caso. Eh, non può essere perché
comunque in una cioè in un in un indice
della riga c'è a lungo che differisce
che differisce quindi la diagonale
complementata non apparirà mai come
riga.
in una di queste in una di questa
matrice non apparirà mai come rida
dentro questa matrice la diagonale
complementare.
Di conseguenza, siccome noi abbiamo
tanterie quanto sono tutte le macchine
di tuning che mai potremmo inventarci,
allora vuol dire che non ci sta proprio
una macchina di tuning il cui linguaggio
è LD, perciò LD non è RE, non è
ricorsivamente numerabile, non esiste
una macchina di Turing che è in grado di
accettare MD.
Adesso che cavolo è LD?
Perché è stato definito un po' ad eh
LD
è l'insieme delle stringhe vi
tale che la macchina iesima non accetta
la propria stessa codifica. Ok? Quindi
che contiene LD? LD è l'insieme dei
codici di macchine di Touring che quando
ricevono in input la propria stessa
codifica della funzione di transizione
dicono no.
È chiaro che è questo linguaggio LD? Le
macchine di Turing che fanno? Piano in
input string e rispondono o sì o no.
Ok?
Consideriamo le macchine di Touring che
prendono input stringhe binari, ok?
Perché ci semplifica la vita. Macchina
di touring che prende in input, una
stringa binari.
Gliene possiamo dare tanti input di
string binari. Fra le varie stringhe che
gli possiamo dare input, gli possiamo
dare in input la stringa binaria che
codifica la funzione di transizione di
quella macchina.
Ok?
Se quella macchina ricevendo input la
propria codifica, risponde di no, allora
quella stringa fa parte di LD. Quindi LD
contiene i codici di macchine di Touring
che quando ricevono un input, la propria
stessa codifica, rispondono no. Quella è
l'ID. Sì. Ma quindi con la codifica tr
di altre macchine si può fare oppure no?
Sì, sì. Ma quindi qua per stare nelle D
la macchina I deve rispondere no quando
riceve input w con I. Ma se ho se posso
care un input eh la codifica di un'altra
macchina non si andrebbe un po' come
controsenso al No, no, aspetta, la
definizione del linguaggio è questa la
cioè noi vogliamo definireci il
linguaggio come ci gira l'insieme delle
stringhe che che codificano i grafi
belli. Ok? definiamo cos'è un grafo
bello, lo possiamo fare, ok? Noi
definiamo L in questo modo. È l'insieme
dei codici binari che codificano
macchine per le quali se loro
ricevessero in input la propria stessa
codifica risponderebbero no.
No, qualche cosa facciano sugli altre
non ci importa, ma per stare lì in LD M
con I deve essere una macchina che sulla
propria codifica dice di no, poi sul
resto fa quello che gli gira. Però la
mia domanda se guardo il problema della
fermata, cioè presumo stimata un po' a
parlare su questa cosa qui e più o meno.
Però quest è un'altra cosa. Linguaggio
di diagonalizzazione poi lo facciamo il
problema della fermata o domani o
venerdì, cioè o giovedì o venerdì, ok?
Che poi lo guardiamo più altri tempi.
Però noi volevamo un linguaggio che non
fosse il re. Questo non è R perché
perché non esiste una macchina di
Touring che è in grado di accettare le
Come lo sappiamo? Perché nel momento in
cui le listiamo tutte,
ok? Allora nessuna di loro ha il vettore
caratteristico
della
della diagonale complementata. Ok?
Nessuno ha il vettore caratteristico di
L. Quindi teorema
adesso l'abbiamo
abbiamo dimostrato così a chiacchiere,
ma sostanzialmente si riduce a questa
cosa. Teorema LD
non appartiene ad R.
Come si dimostra? in quel modo facendo
la matriciona, facendo la lista delle
macchine, facendo la lista delle
stringhe e facendo notare che LD ha come
vettore caratteristico la diagonale
complementata. Ma per definizione la
diagonale complementata non può essere
la riga di non può essere nessuna riga
di quella matrice, ok? Tale per cui
quella macchina non c'è sta.
Chiaro per tutti? Ok,
intuizione dietro sta roba perché
esistono i linguaggi
non ricorsivamente numerabili e poi
introduciamo sì alcune proprietà di
linguaggi che ci servono per la prossima
volta, cioè perché ci stanno i linguaggi
non decisibili. Sì, scusi, ma eh per
dimostrare alla fine usiamo nella
matrice prima si usa la matrice, sì,
però prima dimostrare che per come ha
definito adesso
eh coincide con quella regolandita.
Esattamente. Sì, sì, sì, sì, sì. Beh,
poi la dimostrazione è quella e poi eh
scusi mi son perso la e il linguaggio
che i codici binari i codici di macchine
di Touring le quali ricevendo input la
propria bonifica
la rifiutano, quindi non riconoscono la
propria non riconoscono rispondono di no
sulla propria modifica. Ok? Tutto qua. È
un linguaggio un po' strano, però uno si
può inventare il linguaggio che vuole.
Ok?
Allora, giusto un'intuizione, perché ci
stanno i linguaggi indecisibili. Questa
è una cosa che immagino che i matematici
l'avranno già fatta.
Allora,
noi abbiamo detto che le macchine di
Turing sono enumerabili, noi le possiamo
contare, possiamo dire la prima, la
seconda, la terza.
Il che vuol dire che le macchine di
Touring sono tante quante
i numeri interi.
I linguaggi che sono sono sottoinsieme
di quelle stringhe, sotto insieme di V1,
V2, V3, V4. Quindi abbiamo che le
stringhe
sono infinite, tante quante i numeri
interi. I linguaggi sono tutti possibili
sottoinsiemi
di un numero infinito di stringhe.
Quanti sono tutti possibili sottoinsiemi
di un numero infinito di stringhe?
Numeri reali son tanti quanti numeri
reali son molti di più. Quindi i
linguaggi sono tanti quanti i numeri
reali, le macchine di touring sono tante
quanti sono i numeri naturali, quindi
abbiamo molti più linguaggi che
algoritmi. Ecco perché ci sono linguaggi
indecidibili, perché sono tanti di più.
Poi la nostra testa non li partorisce
perché noi siamo abituati a pensare in
maniera tale che le cose riusciamo a
risolverlo, ma in realtà per definizione
siccome i linguaggi sono tanti quanti i
numeri reali e le macchine di curing,
che sono gli algoritmi sono tanti quanti
i numeri interi, i numeri naturali, ci
stanno molti più linguaggi algoritmi.
Ecco perché ci stanno i linguaggi per i
quali non esistono macchine che sono in
grado di leggire. Tutto qua perché sono
tante di più.
Questa è la ragione filosofica che ci
sta dire perché perché son tanti. Sono
tanti di più. Ok. Ok. Introduciamo un
paio di proprietà sui linguaggi e poi
chiudiamo.
Sia l un linguaggio su un certo alfabeto
sigma star. Ok. Su un certo Sì. Su un
certo alfabeto sigma e quindi
L sigma star.
Definiamo
L soprasegnato come il complemento del
linguaggio L. Intuitivamente cos'è il
complemento del linguaggio L? È il
contrario di L. Quello che sta in L non
sta in l sovrasegnato, quello che non
sta in Lassegnato.
Di conseguenza L sovrasegnato viene
definito come sigma start - L. Ok?
è il contrario.
Tutto qua. Questo è il complemento di un
linguaggio.
Prima proprietà
teorema.
Se L appartiene ai linguaggi ricorsivi,
allora
L soprasegnato è quello di ricorsivo.
Chiara la proprietà? Se per L abbiamo un
algoritmo che è sempre in grado di dire
sì o no, allora abbiamo un algoritmo che
è sempre in grado di dire sì o no anche
per il complemento. Dimostrazione.
Siccome L è un linguaggio
ricorsivo,
esisterà una macchina MDL che è sempre
in grado di dirci o sì o no.
Ok?
Per definizione, siccome L è ricorsivo,
c'è una macchina deterministica, come
vogliamo, che su ogni stringa è sempre
in grado di dire sì, la stringa
appartiene a L, no, la stringa non
appartiene L. Ok? Perché esiste tale ML?
perché L e lo stiamo assumendo
ricorsivo. Allora, noi possiamo
costruire
una macchina
ML soprasegnato, cioè una macchina per
questa prende in input qualcosa,
una cosa di questo tipo.
ML
Se questo è sì,
rispondiamo no.
Se questo è no, rispondiamo sì. Cioè,
praticamente noi la macchina per L
soprassegnato
noi semplicemente come la possiamo
ottenere? Prendiamo, siccome stiamo
assumendo che L
sia un linguaggio ricorsivo, quindi una
macchina che decide L ci sta.
Prendiamo la macchina per L e la
rivoltiamo. Praticamente che facciamo?
l'unico stato accettante di Lventa
non accettante
e tutte le transizioni non previste
dalla funzione di transizione di L
inseriamo in questa nuova macchina ML
soprasegnato in maniera tale che tutto
ciò che la macchina ML non si aspetta la
macchina ML soprasegnata le va a far
finire in un nuovo stato accettato.
Ok? Quindi tutto quello che veniva
rifiutato dalla macchina ML verrà
accettato dalla macchina ML soprasegnato
e tutto quello che veniva rifiutato
dalla macchina ML verrà accettato dalla
macchina ML soprasegnata. È chiaro?
L'intizione è questa. Noi cambiamo gli
stati. Quello che è l'accettante per un
diventa non accettante. Tutte le
computazioni, no? Le mosse non previste
da ML verranno previste da ML
sovrasegnato e vanno a finire in uno
stato accettante aggiuntivo che
aggiungiamo. Ok? Giusto per far sì che
ogni volta che ml dice di no, ml
soprassegnato dice di sì e ogni volta
che ml dice di sì, ml soprassegnato dice
di no. Ok? Prego. Un chiarimento. Eh, ML
segnato. Sì. Cioè noi eh facciamo
seguire le cose delle ml e poi
invertiamo il risultato oppure quella è
solo una descrizione intuitiva.
Noi ml sovprasegnato lo possiamo tenere
da ML come
rivoltandogli la funzione di
transizione, cioè la funzione di
transizione di ML prevederà delle
transizioni verso stati accettanti e
prevederà dei punti nel quale ML si
blocca. Ma è solo una definizione
teorica per No, se la definizione di ML.
No, scusi, ero avanti sul perché noi,
appunto, vi sta scrivendo che non
definiamo dei punti di transizione
complementari, cioè tutti quelli che non
esistono, però cioè no, tutte quelle che
non esistono. Si prende la funzione di
transizione di ml e la si modifica per
ottenere la funzione di transizione di
ml soprasegnato. Come facciamo? Lo stato
accettante di ML diventa non accettante.
Aggiungiamo uno stato accettante e
inseriamo tutte le transizioni non
previste da ML.
Per esempio, se in ML sono in Q4, leggo
il simbolo A e mi blocco, in ML
soprasegnato, in Q4, io avrò una
transizione uscente con A e vado in uno
stato accettante, in maniera tale che
accetto quello che è non accettabile.
È chiaro? Prego.
Se la condizione di questo teorema è che
L appartenga R, Sì. Perché non possiamo
fare la stessa cosa su LD di di prima?
LD non appartiene ad R. Eh, però nel
senso LD è la diagonale de Gata di di D.
Poi facciamo, cioè se la diagonale di
quella matrice perché la perché poi lo
vedremo perché quello là il LD
soprasegnato, dimostreremo che sta in R
ma non in R. Ok? Questa è la cosa, lo
vediamo o giovedì o venerdì perché ora
introduco queste proprietà e poi
risolveremo tutte queste questioni
appese. Sì. Ok.
Ok. Quindi questa è la prima proprietà.
Se abbiamo un eh Aspetta, devo finire
qua, dobbiamo fare la seconda. Se
abbiamo un linguaggio decidibile,
ricorsivo, allora il suo complemento è
ricorsivo. Secondo teorema e poi
chiudiamo. Eh,
teorema.
Se
L appartiene ad RE
e L soprasegnato appartiene ad RE,
allora
L appartiene ad R.
Ok?
Quindi, se un linguaggio è
ricorsivamente numerabile e il suo
componente ricorsivamente numerabile,
allora L è un linguaggio ricorsivo.
Ok? Come si fa? Abbiamo l'intuizione.
Se L appartiene ad RE, allora esiste una
macchina di Turing che lo accetta. Ok?
Non siamo in grado di stabilire che la
macchina lo decida, però se L appartiene
a RE esiste una macchina di Turing che
lo accetta, quindi è in grado di dire di
sì in tempo finito. Per il no non
abbiamo garanzie. Ok?
Se L soprassegnato appartiene ad RE,
allora esiste un'altra macchina di
Touring
ML soprasegnato che è in grado di
rispondere. Sì. Ok? In tempo finito per
L soprasegnato. Eh, L soprasegnato però
è il complemento di L. Ok? Allora, noi
facciamo così,
le infiliamo in una macchinona, in una
macchina più grossa che prende l'input e
lo copia in input a questa e input a
questa qua.
Ok?
Questa è l'intuizione. Poi vi spiego
come si fa.
e quindi le randamo allo stesso momento.
Ok? Facciamo partire ML ed ML
soprasegnato e fanno un passo assieme
come si fa comp facendo il prodotto
cartesiano delle funzioni di transizione
così si definisce. Ok? Quindi io riesco
a simulare un passo di ml, un passo di
ml sovrasegnato.
Se la stringa W input
appartiene a L, allora a un certo punto
ML soprassegnato ML si fermerà e dirà di
sì e quindi dico di sì pure io.
Se W non appartiene ad L,
allora appartiene a ML soprasegnato. Di
conseguenza, questa macchina durante la
sua simulazione a un certo punto dirà di
sì. Ci dirà sì, è vero, W appartiene ad
L soprasegnato. Io prendo quella
risposta e la flippo e dico di no.
È chiaro?
Quindi, se un linguaggio è
ricorsivamente numerabile e il suo
complemento è ricorsivamente numerabile,
allora in realtà sono entrambi
ricorsivi, ok? Perché io posso combinare
le macchine e mi piglio la prima
risposta che arriva.
Chiaro? Queste proprietà le utilizzeremo
nelle prossime lezioni per stabilire
dove si colloca Lu, dove si colloca LD,
il complemento di LD, eccetera.
Ok? Vediamo se devo fare altro, ma non
credo. Ma quindi allora nel teorema
quella L che appartiene a a R sarebbe
una insieme tra L e N?
No, L è un linguaggio. Sì, sì, sì. Ok.
Però noi abbiamo che
se L
facciamo un esempio. Ah, no, ok. Qua
c'ho
R e qua c'ho R.
Se io so che L sta qua ed L
soprassegnato sta qua, allora in realtà
stanno qua dentro.
Questo è il senso del teorema. Cioè, se
io ho che un linguaggio e il suo
complemento sono ricorsivamente
numerabili, allora in realtà sono
ricorsivi.
Chiaro?
Ok, possiamo chiudere con questo.
Alrgri, ma ce l'amo fatta.