Alri guys, let's start. Ok,
facciamo un velocissimo recap della
lezione scorsa
e poi introdurremo i concetti di oggi.
Quindi su richiesta e quindi penso di
fare così. Oggi faremo, ok, per gran
parte di voi l'avete già visti, però per
i nostri colleghi di matematica
e per aver comune. Vedremo automi a
stati finiti deterministici. Al prossimo
giro faremo automi a stati finiti non
deterministici. Ok? Beh, immagino che
chi ha seguito il corso di linguaggi lo
conosca. Dopodiché da settimana prossima
manteremo nel vivo e iniziamo con Ok?
Ok. Decido di far così perché in maniera
tale che facciamo una gentle
introduction al concetto di automa
eccetera così. Per chi non l'ha mai
visto prima si può adattare più
velocemente.
Quanto è stato fuori dal mondo? Quanto
abbiamo detto la scorsa volta?
Alrgri, cioè era a posto. Ok. M quello
che facciamo oggi quindi è
rintroduciamo, ripetiamo il concetto di
problema,
così ce l'abbiamo sotto gli occhi,
dopodiché mostreremo che il problema per
l'arresto è indecidibile, ok? cosa che
avete già visto, noi sottolineeremo una
particolare caratteristica della
dimostrazione che ehm
è quello è quello che ci permette di
dire che il risultato è stabile. Uno dei
vostri colleghi ci aveva chiesto la
scorsa volta: "Ma i risultati di
indecidibilità che otteniamo valgono per
la tecnologia di cui disponiamo ora o
varranno per sempre?"
Nella dimostrazione che faremo oggi vi
indicherò qual è il punto della
dimostrazione che ci permette di dire
che questa questo risultato è stabile e
varrà per sempre. Ok?
Ok. Allora, noi siamo partiti
da eh dalla nozione di problema. Vi
ricordo che un problema per noi è una
relazione, cioè è un sottieme di tutte
le possibili coppie
fatte da una certa stringa di input e
una certa stringa di output. Ok? Per noi
è tutto stringhe, però poi ad alto
livello diremo "Ah, qua questa stringa è
un grafo" eccetera. però poi alla fine
queste cose vanno rappresentate. Noi
sappiamo che all'interno della memoria
di un computer ci serve una
rappresentazione. Può essere
multisimbolica o binaria come una
opportunica. Ok?
tutte cose che sapete. Allora, noi
abbiamo quindi che
una relazione di un problema
è caratterizzata da tre elementi.
Abbiamo l'input, adesso lo tirare di
qua. Ok, where is it? abbiamo l'input e
l'output, quindi ogni volta che
specifichiamo un problema dobbiamo dire
che cos'è l'input, come lo
rappresentiamo, qual è il suo
significato, eccetera. Dobbiamo dire che
cos'è l'output
avendo le stesse identiche
caratteristiche, quindi come è
rappresentato, che cosa significa, che
cos'è, eccetera. Dopodiché la cosa più
importante, ma non meno, cioè non molto
più importante del resto, questi qua
sono importanti, noi avremo la relazione
che lega l'output all'input, ok? Cioè,
quindi ogni volta che noi dobbiamo
andare ad analizzare un problema, no,
nella nostra testa devono essere chiari
tre elementi, altrimenti ci perdiamo.
Quindi, primo trucco che io uso quando
inizio a ragionare su problemi del
genere, quando dobbiamo fare riduzioni
che sono un po' incasinate. Una cosa che
è indispensabile capire, altrimenti ci
perdiamo, è chiarire di ogni problema
che analizziamo queste tre
caratteristiche. cos'è l'input, cos'è
l'output e qual è la relazione che lega
l'output all'input, ok? Sennò poi
diventa veramente un casino, ok? È
importantissimo fare questa cosa. Come
faccio? Così, domande interne. Tutti voi
sentite la vostra voce, ok? Dialogo
interno. Che cos'è l'input? Mi faccio la
domanda, mi rispondo. Che cos'è
l'output? Ok, mi faccio la domanda, mi
rispondo. Che relazione c'è fra l'output
e l'input? e mi rispondo. Ok? Quindi mi
pongo, quindi cosa faccio nella mia
testa? Mi pongo in maniera esplicita
queste domande. Molto semplice. Ok? Ve
le potete segnare da qualche parte. Io
vi devo chiedere questo, questo e
questo. Questo qua vi aiuta a fare
chiarezza. Ok?
Quindi la prima cosa che vedremo oggi
prima di buttarci sul resto è il
problema dell'arresto. Ok? Adesso ve lo
descrivo informalmente, così poi insieme
descriviamo cos'è l'input, cos'è output
e cos'è la relazione. Ok?
Il problema che noi vogliamo modellare
al momento è
se un particolare programma,
ok,
ricevendo un certo input
si arresta o meno mentre gira su
quell'input. Ok? Tutto qui è è il
problema dell'arresto.
Ok? È chiaro intuitivamente il
significato di questo problema?
Alrgri. Dobbiamo adesso modellarlo un
minimo. Ok? Quindi ci chiediamo che
cos'è l'input. Ve lo ripeto, in questo
problema noi vogliamo stabilire per un
certo programma se si ferma o meno
mentre processa un certo input dato. Ok?
Allora, cos'è l'input?
la descrizione del programma. Ok, ci
serve la descrizione del programma.
Intuitivamente oggi eh che facciamo le
cose un po' più così leggere, poi
vedremo. Assumiamo che il programma per
noi è scritto in un certo linguaggio di
programmazione. La buttiamo là Python.
Ok? Quindi abbiamo che nell'input c'è un
certo programma P che che cos'è? è una
stringa, una stringa che codifica che
cosa? Il codice Python di questo
programma. Ok?
Dopodiché cosa altro c'è nell'input del
problema dell'ALT?
Un input per il per il programma dato
input. Un input per il programma dato in
input. Ok. E lo mettiamo qua. Ok. C'è
altro in input?
No. Ok. Quindi l'input
del problema dell'arresto halt è una
coppia di stringhe P I. P è una stringa
che rappresenta il codice Python di un
programma
che riceve in input, una stringa
e I è una stringa che noi vorremmo dare
impasto a P. Ok?
Cos'è l'output per questo programma?
Soltanto che cos'è? Non come relativo
all'input, ok? Che cos'è l'output?
È un buleano, quindi abbiamo una una
risposta di tipo yes no. Ok?
Com'è legato l'output all'input?
Se PD termina, allora risponde yes. Se
PD non termina allora risponde no. Ok,
posso far le punci su quello che ha
detto, così impariamo. Ok, avete sentito
tutti quello che abbia che aveva detto?
Ok. Secondo voi è preciso a sufficienza?
Cosa manca? Posso scriverlo in termini?
No, non è tanto in linguaggio, manca un
pezzettino che ritorni in tempi primi.
Ritorna che non termina in tempo finit.
Lui la il vostro collega l'ha detto, ha
detto se termina, se non termina, quindi
è qualcosa che l'ha detto. È ovvio che
se termina lo deve fare in tempi finiti.
Termina se termina nell'input che gli ho
dato. Ecco, quello è il pezzettino che
dobbiamo sottolineare, ragazzi. Stiamo
imparando assieme. Se se faccio queste
sottolineature non è per dire non è
stato in grado, no, è per imparare
assieme. Vi ripeto,
fatemi domande se non capite. Non ci
sono domande scene, ok? Qualsiasi
domanda va bene, ok? Non fermatevi
perché, ok, se chiedo questo, chissà ai
miei colleghi che penseranno di me e che
penseranno che state facendo una domanda
che avete avuto il coraggio di fare una
domanda. Ok? Quindi datemi il permesso
di fare domande. Io sono ben lieto di
rispondere e di inventarmi modi nuovi di
rispondere se prima non avete capito.
Ok? Quindi per essere estremamente
precisi, la relazione che comunque
questo estremamente precisi è comunque
legato a a uso del linguaggio naturale,
eh, non è che ci stiamo muovendo su
linguaggio matematico o insiemistico,
cosa che potremmo fare, ma se siamo
sufficientemente precisi nell'uso del
linguaggio naturale per noi va
benissimo.
Allora, la risposta y no
è legata all'input in questo modo.
Rispondiamo y se il programma P
eseguendo su input I e l'input I è
questo qui, eh non è un input a caso.
Quindi abbiamo una coppia P I. Se il
programma P eseguendo sulla stringa I
data input a chi? A si arresta. Allora,
il decisore, cioè l'algoritmo che
risolve il problema alt, deve rispondere
yes, altrimenti risponderà no. Ok? È
chiaro per tutti questo problema?
Allora, questo è un problema che può
sembrare abbastanza zzigocolato, no?
Però in realtà è molto utile, per
esempio, per noi informarci. Se noi
abbiamo un ambiente di sviluppo, no,
stiamo scrivendo un nostro programma in
C++, Java, whatever, sarebbe molto
interessante se il compilatore ci
dicesse fin da principio, ma guarda che
il tuo programma su questo input non si
arresta. Ok? Cioè questa in realtà,
sebbene sembra una questione un po' così
campata per aria, in realtà è utilissima
per i programmatori perché
avremmo un compilatore che è in grado di
fare un controllo semantico del
programma. Dici, guarda, cioè c'è un
problema lì, eh, questo questo programma
non ti si ferma. Ok, quindi questa
questione del risolvere se un programma
si arresta su un certo input in realtà è
molto utile. Ok?
Quello che noi adesso dimostreremo è che
noi possiamo sbattere la testa quanto
vogliamo. Un algoritmo
che risolve sempre, questa è la è la
parte più importante, un algoritmo che
data qualsiasi coppia pi è sempre in
grado di rispondere correttamente, un
tale algoritmo non esiste. magari ne
possiamo scrivere qualcuno approssimato,
cioè un algoritmo che ogni tanto ci dà
la risposta giusta, ogni tanto ci dà la
risposta sbagliata. Ok? Ma un algoritmo
che sempre per qualsiasi coppia pi è
sempre in grado di dare la risposta
corretta, quell'algoritmo non lo
possiamo scrivere. E adesso vedremo come
si fa, come si fa a dimostrare questa
cosa. Come ci dicevamo l'altra volta,
una strategia potrebbe essere provare
tutti i possibili programmi per vedere
se qualcuno di quelli funziona. Ma
questa cosa non va bene perché ci
richiederebbe un tempo infinito, perché
quanti sono i possibili programmi?
possiamo scrivere sono infiniti, ok?
Quindi è una strada che non si può
percorrere. Quello che noi dobbiamo fare
è andare a vedere perché questo problema
è non risolvibile. Ok? Questa
dimostrazione si basa sul
eh sul è una dimostrazione per assurdo.
È chiaro a tutti come funzionano le
dimostrazioni per assurdo. Assumiamo una
certa cosa, vediamo quali sono le
conseguenze,
osserviamo che succede una catastrofe e
allora vuol dire che la strunzione
iniziale era sbagliata. Ok?
Allora, quello che noi facciamo è che
assumiamo
l'esistenza
di una procedura
halt check
in input un programma P e un input I per
P, cioè quindi rispecchia appunto la
definizione e ci restituisce un buleano.
Ok?
Allora, prima cosa importante da
osservare. Ok?
Cosa abbiamo scritto lì? Noi stiamo
assumendo
l'esistenza di questa cosa. Stiamo dando
dei dettagli su come è fatta questa
funzione?
No, stiamo dando dei dettagli su come su
quale tecnologia esegue questa funzione,
no? Quindi noi stiamo dicendo,
supponiamo che abbiamo un modo a noi
ignoto di risolvere questo problema è
che in una fantastica libreria di codice
Python abbiamo una funzione che ci
risolve questa questione. Ok? Supponiamo
che ciò sia possibile. Vi sottolineo, ed
è questa la parte importante della
dimostrazione. Noi non stiamo assumendo
nulla né sul linguaggio utilizzato né
sulla tecnologia utilizzata. Stiamo
dicendo, supponiamo che in questo
universo abbiamo una cavolo di procedura
che è in grado di rispondere a questa
cosa. Ok?
Bene,
se abbiamo questa funzione qui, mamma
comeè scritto male, se abbiamo questa
funzione qui disponibile in una
libreria,
quello che possiamo fare è chiamarla da
un altro programma. Questa è la è la
cosa più sofisticata in programmazione
che vedremo, ok? Quindi, per chi non ha
grossissime basi, c'è basta l'idea che
noi da una funzione ne possiamo
chiamarlo dentro, ok?
Allora, se noi abbiamo halt checker da
qualche parte,
noi la possiamo chiamare
da un'altra funzione, una funzione che
ora scriviamo in Python. Ok?
Definiamo questa funzione che chiamiamo
reverse.
Definition
reverse
che prende in input un programma P. Ok?
L'input è solo uno, ok? A differenza
dell'altro che c'ha P e I, qua ne
abbiamo solo uno. Ok?
Facciamo questa bellissima chiamata. Hal
equals
alt checker
PP. Ok?
Chiaro a tutti che cosa stiamo facendo
qua? Siccome abbiamo Hal Checker nella
libreria, scusatemi, non non sono molto
appous di Geggio, quindi la mia
scrittura è proprio uno sgarby. Allora,
la prima la prima cosa che facciamo in
questo programma è chiamiamo Alt checker
e come parametri passiamo più due volte,
prendiamo il risultato e lo mettiamo in
quella variabile buleana HS. Ok? è
fattibile se Haltaker sta in una
libreria super potente che qualcuno ci
ha dato? è possibile. Ok, quindi fino a
qua abbiamo scritto cose che si possono
fa'
si input
Noi stiamo chiedendo ad Alt checker, per
favore,
tu mi dovresti dire qual è la semantica
di questa funzione. Noi stiamo chiedendo
ad Halche Checker, scusa, mi potresti
dire se il programma P quando ricevi in
input la stringa che codifica il suo
stesso codice
si ferma o non si ferma? Questo gli
stiamo chiedendo. Ok.
Alright. Dopodiché facciamo un test. If
hals
while
true.
Quindi se hals
avvero
noi cicliamo,
ci impalliamo. Ok? Altrimenti
usciamo.
Chiaro cosa fa sto programma? Allora, fa
pochissimi passi.
Chiamiamo la funzione della libreria HT
Checker, ma la chiamiamo in questo modo
un po' strano. Non gli facciamo una
domanda qualsiasi. Mi chiediamo, ma se
io eseguo il programma P sulla stessa
sua codifica, cioè che riceve in P è un
programma che riceve in input una
stringa e tra le stringhe che gli do gli
do la sua stessa codifica. Gli stiamo
chiedendo ad Halchecker, questo
programma si arresta o non si arresta?
Noi stiamo assumendo che Htchecker
magicamente ci darà la risposta e noi la
risposta la infiliamo in quella
variabile HS. Ok? Quindi al termine
della chiamata in Halse ci sarà vero o
false. Dopodiché facciamo questa
stupidaggine. Se in hals c'è vero,
iniziamo a luptare.
Se in hals c'è falso, usciamo e
terminiamo. Ok? Non facciamo
nient'altro. Quindi abbiamo incapsulato
la chiamata di Halt checker in queste
poche linee di codice. Prego. Quindi la
la procedura check è diversa dal check
stessa.
Quale? Questa Hal Checker qua è questa
qui. Eh, un attimo. Questa. Ma se io
faccio così si vede niente? Non si vede
niente. Questa
Alt Shaker qua è la chiamata a questa
procedura qua che richiede in input due
stringhe, un programma codificato con
una stringa P e una stringa che noi è
supposto dare in input a P. Quando
facciamo questa chiamata qua significa
che noi chiamiamo questa funzione qua in
cui come primo parametro gli passiamo
questo qui, ok? E come secondo parametro
gli passiamo lui lo stesso, cioè quindi
gli diciamo, supponiamo che abbiamo il
programma Paperino, no? Che c'ha il suo
codice Python. Quello che noi stiamo
chiedendo ad Alt Checker è: "Ma se io
eseguo Paperino sulla codifica di
Paperino,
l'esecuzione si arresta o non si
arresta?" Questo stiamo stiamo
chiedendo. Ok? E siccome noi stiamo
assumendo l'esistenza di questa
funzione, noi ci aspettiamo che dopo
quella chiamata in hals abbiamo la
risposta.
Ok? Dopodiché facciamo sta operazione un
po' farlocca. Se abbiamo ricevuto vero
andiamo in loop. Se abbiamo ricevuto
falso, usciamo dal programma e e
terminiamo. Ok? Chiaro per tutti la
definizione di questo programma? Adesso,
se assumiamo l'esistenza della funzione
Halker in una libreria, una cosa del
genere, la possiamo scrivere o non la
possiamo scrivere? La possiamo compilare
o non la possiamo compilare? La possiamo
compilare. Ok. E fin qui tutto liscio.
Ah, ok.
Sono
le cose qua. Ok, così si vede. Adesso
quello l'ultimo passaggio che noi
facciamo è che una volta che noi abbiamo
questa cosa compilata, noi la possiamo
eseguire su quello che vogliamo.
Ok?
chiamiamo
la stringa che rappresenta questo codice
code
reverse.
Ok?
Chiaro? Cioè stiamo solo dando un nome.
La stringa che rappresenta quel codice
Python gli stiamo dando un nome, ok? in
maniera tale che ci possiamo riferire ad
essa.
Ok, quindi abbiamo reverse, lo
compiliamo,
dopodiché facciamo questa chiamata.
Ok, qui diventiamo ancora più
incasinati. Noi prendiamo reverse, lo
compiliamo, quindi lo possiamo eseguire
su quello che ci gira, cioè su quello
che ci pare a noi.
Eseguiamo reverse
sul codice di reverse. Ok? Qualcuno ci
rieta di fare una cosa del genere?
Quello è compilato, il codice lo abbiamo
scritto, quindi lo possiamo
rappresentare in una variabile. Quindi
in linea di principio è una cosa che
possiamo fare. Ok?
Compiliamo reverse. Lo eseguiamo su
cosa? Lo eseguiamo sulla stringa che
rappresenta il codice diverso. Ok?
Questo è il passaggio.
Ci siamo quasi. Eh,
fino adesso tutto quello di cui abbiamo
discusso è lecito. Vi faccio notare che
è leito. Luni, abbiamo giusto questa
assunzione un po' vaga dell'esistenza di
Halche Checker. Non abbiamo idea precisa
di come sia fatta. L'unica cosa che
stiamo assumendo è che sia disponibile
in qualche modo. Tutto il resto si basa
su ciò ed è assolutamente fattibile. Ok?
Allora, se eseguiamo reverse sul proprio
stesso codice,
due sono le possibilità
o si arresta, cioè se noi guardiamo il
codice di reverse, no, noi abbiamo detto
che questa funzione è definita e quindi
ci darà sempre il risultato e si
arresterà. Ok? Quindi poi nella
continuazione dell'esecuzione di reverse
due sono le possibilità, o luppiamo qua
o ci arrestiamo qua. Ok? Non non fa
altro, non è che fa somme,
moltiplicazioni strane, no? Fa sta
chiamata, facciamo un test, o luppiamo o
ci fermiamo. Ok?
Quindi, se chiamiamo reverse sul proprio
stesso codice, due sono le opzioni:
o si ferma o luppa. Ok? Cerchiamo di
capire se si fermi o luppi. Ok?
Consideriamo
il caso che si fermi. Ok?
Se si ferma
se reverse, ok?
girando sul proprio stesso codice si
ferma
a quale in quale linea stiamo uscendo?
In quale parte di programma stiamo
uscendo
a pass, ok? Vuol dire che stiamo uscendo
da pass, ok? Perché altrimenti
staremando, però noi stiamo assumendo di
arrestarci, ok? Quindi stiamo uscendo da
passi. Ma se stiamo uscendo da passi, il
valore di Ah, questo era halz.
Il valore di halz qual è?
È false. Ok, ma noi, attenzione qui,
Halz come lo calcoliamo?
Chiamando halt checker su un certo
programma P. Però noi input stiamo
passando code reverse, perciò
per riuscire ad arrivare a pass
quando Reverse riceve in input il
proprio la propria stringa, la propria
codifica, vuol dire che qui ha ricevuto
come risposta falso. Il che significa
che questo programma gli aveva segnalato
che il programma reverse, quando è
eseguito su se stesso, avrebbe dovuto
loppare.
Chiaro? Ok, qui c'è un po' un casino.
Allora, questa opzione non va bene. Vuol
dire che reverse quando esegue su se
stesso non si può fermare perché c'è una
cosa strana. Ok? Quindi, alright, questa
è una opzione che noi escludiamo,
quindi se non si ferma questo programma
deve andare in loop. Ok, consideriamo il
loop.
Allora, se reverse
girando su se stesso lupa, a che punto
del programma ci siamo imballati?
Al, siamo al while true. Ok, ma se siamo
al while true che valore aveva alz
vero?
Il che significa che
Halthecker qui ci aveva risposto vero?
Dicendoci che reverse eseguendo su se
stesso si sarebbe dovuto fermare, ma noi
ora stiamo assumendo che doveva loppare
anche questo caso quindi è incasinato,
non può sostissere. Ok, ma ci sono altre
opzioni per questo programma? No. O si
arresta o luppa.
di arrestarsi non si può arrestare, di
luppare non può luppare. Allora qui
siamo arrivati a una contraddizione,
cioè nel nostro ragionamento ci siamo
andati a scontrare verso qualcosa che
non sta in piedi.
Se ripercorriamo al contrario tutti i
passaggi che abbiamo fatto erano tutti
ragionamenti e costruzioni lecite, solo
il primo passo era un po' fumoso,
l'assunzione dell'esistenza della
funzione di HP.
Allora,
vuol dire che se assumiamo l'esistenza
di questa funzione di questa funzione
arriviamo a una contraddizione logica.
Di conseguenza questa funzione non può
esistere.
Chiaro per tutti? Allora, il passaggio
fondamentale qui è chiaro?
Y Ok. Il passaggio fondamentale di
questa prova è che noi non abbiamo né
detto nulla né su come è codificata
checker né su quale tecnologia viene
eseguita. L'assumere
l'esistenza di di questa abilità per
noi, cioè assumere che noi siamo in
grado di risolvere questo problema
genera delle contraddizioni logiche. Di
conseguenza, noi non saremo mai in grado
di risolvere questo problema, né noi né
i marziani, cioè è una cosa che in
questo universo non si fa. Ok?
Sottolineo qui di nuovo che quando noi
diciamo che questa funzione non esiste,
noi stiamo dicendo che la funzione
perfetta non esiste, cioè non esiste.
L'algoritmo che data qualsiasi coppia pi
è sempre in grado di darci la risposta
corretta, però magari ci possono essere
delle approssimazioni,
ok? Cioè dei programmi che sono in grado
di approssimare la risposta, cioè che in
alcuni casi ci acchiappano, in altri no.
potrebbero esistere dei programmi che
sono in grado di testare la
terminazione,
no, di P su I se P ha una forma
specifica.
Ok?
Quindi se limitiamo il programma P in
input, allora magari siamo in grado di
decidere se il programma si arresta o
no. Quello che non esiste è un programma
che dato un B qualsiasi e un I qualsiasi
è sempre in grado di rispondere se P si
arresta su I. Quindi non c'è il
programma generale, ma ciò non esclude
l'esistenza di programmi che risolvono
sotto parti di questo problema o che
diano delle risposte approssimate. Tipo
il 90% dei casi ci risponde bene, nel
10% dei casi ci dice fesserini. Ok?
Chiaro per tutti questo passaggio
logico. Noi abbiamo dimostrato
l'inesistenza della funzione perfetta,
ma nulla ci vieta di fare delle funzioni
euristiche, fare delle funzioni
approssimate che ogni tanto sbagliano,
oppure risolvere questo problema su
istanze molto particolari. Tipo, il
programma P della coppia P deve essere
un programma molto semplice, no? che ne
so, un programma senza i cicli, eh,
quello è più facile da testare. Ok,
alright.
Benissimo. Mh mh.
Una cosa che voglio sottolineare, così
poi ci spostiamo
al
alla parte successiva è che
nello studio della decidibilità di
questo programma e ci siamo un po'
impelagati in codice Python, chiamate di
funzioni, eccetera, come ci diceva il
nostro collega prima, questa cosa può
essere un po' fumosa, ok? e dici "Ma
perché usiamo Python non usiamo C++
class?" Ok? Allora, in realtà noi
dobbiamo diventare più formali in
maniera tale che non ci perdiamo in
questi zuccheri sintattici, ok? Ci serve
qualcosa di un pelino più formale.
Quindi ora introduciamo quello che ci
permetterà di formalizzare lo studio dei
problemi e lo studio degli algoritmi.
Ok? Perché diciamo studieremo gli
algoritmi, ma perché li scriviamo in
Python? li scriviamo in Java e io li
voglio scrivere in assembler, magari
funzionano meglio le cose. Ok? Quindi
dobbiamo trovare un formalismo che ci
permetta di studiare in maniera più
precisa queste cose. Ok? Allora,
pensiamo nuovamente alla faccenda
del
definizione di un problema. Voglio farvi
porre l'attenzione su classi di problemi
di interesse per noi. Ok? Oplà.
Rivediamo due problemi che abbiamo visto
la volta scorsa. Il problema del
percorso in un grafo è il problema
dell'Hemiltonian cycle. Ok? Lo facciamo
per esercizio assieme, vediamo come
definirli eccetera.
Hamiltoni cycle. ciclooniano.
Ve li ricordate che cos'erano? Il
problema del percorso è dato un grafo,
dato e due nodi dentro questo grafo, un
grafo, un nodo sorgente e un nodo
destinazione,
calcolare
un percorso, cioè restituire un percorso
dal nodo sorgente al nodo destinazione.
Ok?
L'altro problema è cycle, molto simile
sull'input,
è dato un grafo.
È vero o no che esiste un Hamiltonian
cycle all'interno di questo grafo. Vi
ripeto che un Hamiltonian cycle è un
ciclo, c'è un percorso dentro il grafo
che parte da un nodo e ritorna allo
stesso nodo, attraversando tutti i nodi
e passando esattamente una volta per
tutti i nodi. Ok?
Adesso, qual è la caratteristica
peculiare che distingue questi due
problemi?
Eh, un attimo, scusa. Vai. Il problema
del è decidibile
Hamilton è pure decidibile. È un po' più
difficile, ma è indecidibile. Ah, no,
che è facile e quello è difficile. Ok.
Più nello specifico, qual è la
differenza nella definizione di
questione problemi? Prego. E l'output
che differenza c'è eh nel cycle è
giorno, nell'altro invece è un grafo,
quindi una è un grafo, anche l'altro è
un percorso. Ok, questa è una differenza
caratteristica di questi due problemi.
Ok, per path abbiamo che la risposta è
un percorso,
mentre su Emilton Cycle la risposta è un
bule.
La risposta per il problema del halt che
cos'era?
Un buuleano. Quindi, in qualche modo, il
problema dell'arresto e il problema
delle miltonian cycle sono simili,
diciamo, almeno da un punto di vista di
struttura della risposta. Ok?
Definiamo problemi di ricerca
i problemi la cui risposta. Vi ricordo
che un problema è una relazione input
output, ok? Quindi cosa sono i problemi
di ricerca? I problemi di ricerca sono
quei problemi il cui output può essere
vario, ok? Il percorso in un grafo, la
moltiplicazione di due matrici, la
derivata di una funzione. Ok?
chiamiamo problemi di decisione
tutti quei problemi il cui output è un
buule. Ok? Quindi facciamo questa grossa
suddivisione fra famiglie di problemi
che ci ritornerà utile. Quindi da un
lato abbiamo i problemi di decisione,
dall'altro i problemi di cerca, sì.
dall'altro abbiamo i problemi di
decisione. Ok?
Quello che vi voglio far notare è che
questi due classi di problemi non sono
completamente distinte, cioè non sono
completamente slegate.
Pensiamo al problema del percorso. Ad
esempio, dato un grafo, un nodo sorgente
e un nodo destinazione, calcolare un
percorso dalla sorgente alla
destinazione se questa esiste.
Sentite quest'altro problema.
Dato un grafo, un nodo sorgente e un
nodo destinazione. Quindi l'input è lo
stesso eh di quello che ho detto prima,
decidere se esiste un percorso dal nodo
sorgente a un nodo destinazione.
Chiaro? Quindi questi due problemi hanno
lo stesso input, l'output è diverso. Nel
problema di ricerca vogliamo che
l'output sia il percorso. Nel problema
di decisione noi vogliamo sapere
solamente se questo percorso esiste.
Però è evidente che questi due problemi
sono molto simili, ok? Perché
sostanzialmente se siamo in grado di
risolvere uno siamo in grado di
risolvere l'altro. Ok?
Secondo voi è più facile gestire
problemi di decisione? Cioè da un punto
di vista di studio, no? È più facile
analizzare problemi di decisione o
problemi di ricerca?
Di decisione. Problemi di decisione
perché? Perché la loro risposta è solo
una fra due possibili.
Ok? Per questa ragione ci focalizziamo
sui problemi e decisione perché è più
facile. Ok? Quindi questo è un primo
passaggio fondamentale. Eh,
problemi di ricerca, problemi di
decisione non sono
legati in qualche modo, non è che sono
separati. Noi possiamo associare un
problema di decisione a ognuno dei
problemi di ricerca interessati.
Per studiarli noi ci focalizziamo sulla
versione di decisione perché perché è
più facile. Ok? Quindi da adesso in poi,
se non in pochissime circostanze, quando
ve lo dirò, noi staremo sempre parlando
di problemi di decisione, cioè problemi
la cui risposta è sino.
Chiaro?
Allora, la questione è, ok, abbiamo i
nostri bei problemi di decisione da
questo lo facciamo dopo, abbiamo i
nostri bei problemi di decisione da
studiare, no? E in particolare dovremmo
studiare se un dato problema di
decisione è decidibile o meno. Cioè,
ecco perché la parola decidibile, perché
è un problema di decisione. Un problema
di decisione è decidibile se noi abbiamo
un algoritmo che è in grado di
deciderlo, cioè è un algoritmo che è in
grado di darci sempre per ogni input in
tempo finito. Risposta sì e risposta no.
Ok?
Ma quindi se noi vogliamo studiare i
problemi di decisione e quindi per
stabilire se sono decidibili dobbiamo
stabilire se ci stanno degli algoritmi
che sono in grado di risolverli, allora
ci scontriamo con il problema di "Ma noi
che algoritmi andiamo a guardare? E sti
algoritmi su quale macchine sediamo?"
Ok? Quindi abbiamo tutta una questione
di tipo tecnologico che
ci va tra le ruote. Ok? È un po' un
problema. Ci dobbiamo semplificare la
vita pure su questo perché non possiamo
stare lì a pensare se usiamo Python,
usiamo Java, se stiamo inseguendo su una
macchina reale virtu. Dobbiamo
semplificare pure su questo. Allora, il
passaggio che facciamo dai problemi di
decisione
è a Adesso li ridefiniremo per coloro
che non li hanno visti prima, ma per voi
che avete ne avete già sentito parlare
sono i linguaggi.
I linguaggi che avete già visto sono
problemi, cioè decidere un linguaggio,
stabilire se una certa stringa
appartiene a un linguaggio è un problema
con output yes no.
Quindi quelli lì sono problemi, la
decisione dei linguaggi
e in qualche modo legato ai problemi di
decisione. Come vedremo fra un po',
tutti i problemi di decisione possono
essere ricondotti
al problema di decidere i linguaggi.
Ok?
Quindi ritorniamo da capo, vediamo i
passaggi che abbiamo fatto.
A noi ci gradirebbe tanto riuscire a
studiare i problemi di ricerca, ma i
problemi di ricerca sono intrivati. Che
cosa facciamo? Ci focalizziamo sulle
loro varianti di decisione. Perché?
Perché è più facile. Ok? nel momento in
cui noi dobbiamo studiare i problemi di
decisione, ma ce ne sono di tantissime
forme con gli input più strani e poi
dobbiamo capire quali algoritmi usiamo
per risolverli, quale macchine esegue
quegli algoritmi eccetera, cioè ci
sarebbe una ricchezza troppo vasta da
gestire completamente.
Ricorriamo a un trucco. Quale? al trucco
dei linguaggi,
poiché decidere un linguaggio,
intuitivamente, ancora per voi che non
sapete cos'è un linguaggio, decidere un
linguaggio significa, ma data una
parola, questa parola appartiene a
questo linguaggio,
ok? Questo problema ha una struttura
molto più regolare, diciamo, cioè è
molto più facile da maneggiare, decidere
un linguaggio rispetto alla molteplice
varietà dei problemi di decisione.
Poiché noi possiamo sempre mappare
un problema di decisione su un opportuno
linguaggio, quello che noi facciamo è
studiare i linguaggi perché perché gli
algoritmi che studiano che risolvono i
linguaggi sono degli automi e quindi ci
leviamo di torno il problema di decidere
quale quale linguaggio di
programmazione, quale macchina usiamo
per decidere un certo linguaggio.
Ok, quindi questa operazione, problemi
di ricerca, problemi di decisione,
linguaggi, lo facciamo al fine di
semplificarci la vita. Tutto qua. Ok?
Quindi quello che noi faremo nelle
prossime lezioni sarà focalizzarci su
problemi di decisione, di linguaggi
perché perché è paradigmatico per tutti
i problemi di decisione ai quali saremmo
interessati.
Ok?
E direi che qui ci possiamo fare una
pausa di 10 minuti, un quarto
d'isettromo.
M
allora
Allora, eravamo arrivati a diretta.
Va bene, indecisioni perché perché son
più facili, perché noi siamo la Non ci
vogliamo rompere le balle da soli,
quindi andiamo su cose più facili.
Dopodiché il passaggio successivo che
abbiamo abbiamo sottolineato è questo.
Poiché i problemi di decisione, sebbene
siano più semplici dei problemi di
ricerca, hanno forme varie e su grafiche
e su list e su matrici, neural networks,
programmi logici, cose del genere. Ok?
No, è vero, no, che questo programma
analogico implica questa cosa e insomma.
Allora, quello che noi facciamo per
studiare la teoria della presidibilità è
che noi ci focalizziamo su un'altra
cosa. Perché i programmi
i programmi i problemi di decisione sono
i problemi le cui risposte possibili
sono sì. No, e il problema di decidere
un linguaggio che vi ricordo è dato una
stringa è vero o no che appartiene al
linguaggio dell'inglese? E la risposta è
sì. No,
noi ci focalizziamo sui linguaggi perché
tutti i problemi di decisione, adesso
vedremo un dettaglio, tutti i problemi
di decisione possono essere convertiti o
visti dalla prospettiva di decidere
particolari linguaggi. Facciamo questo
perché studiare i linguaggi è più
semplice che eh focalizzarci su una
miriade di forme dei problemi di
decisione. Ok? Questa è la ragione per
cui ci focalizzano sui linguaggi.
Quindi ora definiamo cos'è un
linguaggio.
Linguaggi.
Alri.
Supponiamo di avere un insieme chiamato
sigma
sigma maiuscolo che contiene
un insieme di simboli
A B C. Non devono essere per forza
questi simboli. Possono essere 0 1
quadratino, casetta, cerchietto,
nuvoletta. Ok? simboli.
Quindi sigma è un insieme di simboli.
Chiamiamo sigma alfabeto. Ok? Che cos'è
per noi un alfabeto? Un alfabeto sigma è
semplicemente un insieme di simboli.
Ok?
Che cos'è
una parola
w su sigma?
Una parola
su sigma è semplicemente
una concatenazione
di 0
o più simboli provenienti da sigma.
Tutto qua. Ok. Quindi molto semplice.
Cos'è per noi un alfabeto? È un insieme
di simboli. Possono essere i simboli
della dell'alfabeto italiano, possono
essere i simboli dell'alfabeto inglese,
possono essere cifre, possono essere
disegnini a cavolo. Ok? Sono
semplicemente simboli. Che cos'è una
parola? Una parola è semplicemente
una concatenazione,
una parola su sigma, eh è una
concatenazione
di 0
o più simboli provenienti da sigma. Ok?
indichiamo
con sigma star
l'insieme
di tutte le parole di qualsiasi
lunghezza
che si possono costruire sopra sigma.
Ok? Chiaro per tutti?
No. Sì. Sigma è un insieme di simboli, è
il nostro alfabeto. Le parole sono fatte
dei simboli dell'alfabeto,
no? Tipo,
questa parola qui proviene dall'alfabeto
dei simboli della lingua italiana.
Questa parola qui
proviene dal simbolo degli alfab della
dei dell'alfabeto nei simboli della
italiana, no? Perché c'è un simbolo che
non fa parte. Ok? Quindi, che cos'è una
parola? Una parola è semplicemente una
concatenazione di simboli provenienti da
un alfabeto dato. Ok?
denotiamo è solo un nome. Chiamiamo
sigma star, lo potevamo chiamare pippo.
Decidiamo di chiamarlo sigma star per
una certa ragione. L'insieme di cosa? Di
tutte le stringhe
di una qualsiasi lunghezza, compresa la
stringa di lunghezza zero che si possono
costruire dai simboli provenienti da
sigma. Ok? Tutto questo? Prego. Ogni
stringa lunghezza. Ogni stringa ha
lunghezza. Sì.
Cioè, sigma star un bound sulla
lunghezza delle stringhe, però ogni
stringa ha una lunghezza per Prego. Non
so se questo sigma è unito.
Ehm,
sì, possiamo dire di sì. Sì.
Sigma, l'alfabeto. Una parola su un
alfabeto è semplicemente la
concatenazione di singoli provenienti da
quell'alfabeto. Sigma star è l'insieme
di tutte le parole provenienti
dall'alfabeto sigma. Se l'alfabeto
l'avessimo chiamato p, cioè gre, pi star
è l'insieme di tutte le parole che si
possono costruire provenienti
dall'alfabeto pi. Ok?
linguaggio. Cos'è un linguaggio?
un linguaggio
L
su un alfabeto sigma
è semplicemente
un sottoinsieme
di tutte le parole che si possono
costruire su sigma fino questo è un
linguaggio.
Quindi cos'è un linguaggio su sigma?
semplicemente e prendiamo tutte le
parole che si possono costruire da
sigma.
Ce ne scegliamo un pezzettino, una
piccola porzione. Quello lì è un
linguaggio, ok? Quindi cos'è un
linguaggio? È un sottoinsieme di sigma
start, ok? Un sottoinsieme di tutte le
possibili parole costruibili con i
simboli provenienti da sigma. Cosa
significa decidere un linguaggio?
Decidere L.
L significa
data
una stringa
w V appartenente a tutte quelle
op
a tutte quelle che si possono costruire
su sigma date una stringa doppia V
appartenente ad L a sigma star decidere
se W
appartiene a L o meno. Tutto qua. Questo
è il problema di decisione classico sul
linguaggio.
Date un linguaggio che è semplicemente
un insieme di stringhe costruite su un
certo alfabeto.
Date una stringa W. È vero, no, che W
appartiene ad L? Noi dobbiamo scrivere
un algoritmo che sputa sì o no. Tutto
qua. Ok? Quindi il problema di decidere
un linguaggio è un problema di
decisione.
L decidere decidere Liga, dato una
stringa w appartenente a sigma start,
decidere se W appartiene ad L o meno.
Ok?
Tipo
la parola confetti
appartieno all'insieme delle stringhe
della lingua italiana.
Sì, questo qua. La parola house
appartiene o meno all'insieme delle
stringhe della lingua italiana? No.
Inglese? Sì. Che scodono i confetti in
inglese?
Sono i cori
Ok? Quindi, sostanzialmente, decidere un
linguaggio è questa cosa molto molto
semplice, cioè intuitivamente molto
semplice. Abbiamo un linguaggio, il
linguaggio non fa parte dell'input, eh,
l'input di decidere L è solo w. La
domanda è, quindi l'input è w, l'output
è y no? Rispondiamo y se W appartiene ad
L, rispondiamo no se W non appartiene a
L. Ok?
Decidere il linguaggio L. Questo è
importante. L è fissato, cioè fa parte
della descrizione del problema. L'input
del problema decidere il linguaggio L è
una stringa. È la stringa W B e noi
dobbiamo stabilire se W B appartiene a L
o meno. È chiaro questo passaggio?
Ok.
Allora, perché a noi ci piacciono tanto
i linguaggi? Perché
il problema di decidere un linguaggio,
ok, è molto ben strutturato, si può
affrontare dal punto di vista
eh di capire se esiste o meno uno
specifico automa che è in grado di dare
questa risposta sino al problema di
decidere se W B appartiene a L o men.
Ok? Allora, perché noi facciamo questo?
Perché noi possiamo sempre
ricondurre un problema di decisione a un
problema di decidere un linguaggio.
Supponiamo di avere
il problema pass. Ok?
Qual è l'input per path?
Abbiamo un grafo G, poi
sorgente, un nodo sorgente e un nodo
target. Ok, la risposta è
Le risposte possibili sono sì. No. Ok.
Yes. No.
Su questo problema noi possiamo definire
un particolare linguaggio
che è questo LP.
Che cos'è L di P? È l'insieme
di tutte le stringhe.
Ah, ok. questa cosa
opportunamente codificate
che mi codificano delle triple tale per
cui G è un grafo,
S e T
nodi di G
e esiste
un P
da S a T in G.
Chiaro?
Cioè noi praticamente abbiamo
trasformato il problema di decidere se
dato un grafo, un nodo e un altro nodo,
se ci sta un percorso un percorso da S a
T in G nel problema di dato una stringa
che mi codifica una tripla in cui la
prima parte della codifica mi codifica
un grafo, la seconda parte mi codifica
un nodo S e la terza parte mi codifica
un nodo t, è vero o no che questa scrica
codifica una tripla tale per cui esiste
un path da a nel grafo g e in questo
linguaggio fanno parte solamente queste
stringhe. Le stringhe che non soddisfano
questa proprietà non fanno parte del
linguaggio LP. È chiaro?
Ci siete con me che decidere
l'appartenenza di una tripla a questo
linguaggio è equivalente a stabilire a
risolvere un problema.
Ok? Quindi questa è la ragione per cui
ci focalizziamo sui linguaggi, perché
tutti i problemi di decisioni possono
essere reencoded in specifici linguaggi
da riconoscere e i linguaggi hanno la
praticità per noi di essere studiabili
in quanto decisi da autopi. Tutto qua.
Ecco perché ci focalizziamo sui
linguaggi, quindi per ripercorrere tutto
il percorso, problemi di ricerca e
intrigato, problemi di decisione che
sono legati, ci focalizziamo su questi
perché è più facile. Per semplificarci
la vita ancora di più,
riconduciamo tutti i problemi di
decisione a specifichi specifici
problemi di riconoscimento di linguaggi
perché perché è più strutturato lo
studio e possiamo ridurre il problema,
la questione di decidere se un certo
linguaggio sia decidibile o meno. Quindi
se un certo linguaggio ammette un
algoritmo per la sua soluzione può
essere ricondotta a una cosa ancora più
semplice. Cà ma questo linguaggio ce
l'ha un automa o no che è in grado di
riconoscerlo? E così ci siamo tolti
dall'impiccio di decidere che linguaggio
di programmazione usare, quale
tecnologia considerare. Ok? È chiaro per
tutti il passaggio? Cioè, quindi abbiamo
fatto una serie di astrazioni per
poterci mettere in un contesto nel quale
lo studio dei problemi, perché vorriamo
studiare problemi sia semplificato.
Perché studiamo i problemi di decisione?
Perché è più facile. Perché studiamo i
linguaggi? Perché è più facile. Ok,
tutto qua? Chiaro per tutti? Ok, adesso
noi dobbiamo introdurre il concetto di
automa perché abbiamo più volte detto
che
sti linguaggi noi li vogliamo
considerare perché sono facilmente
riconosci, cioè gli algoritmi che lo che
li decidono. Vi ripeto che decidere un
linguaggio è date una stringa, stabilire
se la stringa sta fuori o dentro il
linguaggio. Tutto qua. Ok? Abbiamo detto
più volte che decidere i linguaggi è
riconducibile
e è modellabile tramite algoritmi che
sono definiti tramite auti. Ok? Adesso
voi che avete fatto i corsi di linguaggi
tutta sta roba la sapete. Quindi
facciamo un veloce recap per coloro che
non hanno mai visto questa cosa qua.
Cos'è un automa? Oggi vedremo quelli
deterministici, domani vedremo quelli
non deterministici prima di iniziare il
lavoro suing machines dalla settimana
prossima. Ok.
Cos'è un automa?
Faremo un esempio un po' fesso e poi ci
focalizziamo su sui linguaggi. Vediamo
un po' lui. Eh, certo, ragazzi, non non
ci sarà l'audio in questi cosi, non so
come fermarlo.
Forse sento più lontano.
Allora,
cos'è un automa? Intuitivamente un
automa è un aggeggio, quindi termine
tecnico aggeggio
che ha varie modalità di funzionamento.
Ok?
E in base alla modalità di funzionamento
nel quale si trova in un certo istante
può reagire in maniera diversa a certi
stimoli dall'esterno o dei segnali. Ok?
Questa è l'intuizione di cos'è un
autonoma. Un autonoma è una macchina, un
aggeggio che ha varie modalità di
funzionamento
e indipendenza del segnale o dell'input
che gli arriva da fuori, fa delle cose
e cambia modalità di funzionamento. Ok?
Si sposta da una modalità di
funzionamento all'altra in base agli
stimoli
ok?
Allora,
mo siete tutti molto giovani. Avete mai
visto
un lettore CD dal vivo?
Quindi sapete come funzionano le scorso
ad altri ho avuto problemi, non
l'avevano mai visto un
quello che facciamo è modelliamo, per
far capire cos'è sto concetto di di
automa. Modelliamo il funzionamento di
un lettore CD con la nozione di automa
così vediamo che fanno sti automa e
dopodiché ci sposteremo sulla nozione di
automi che decidono linguaggi. Ok? Però
partiamo prima da questa cosa più
astratta con cui abbiamo confidenza
tutti. Ok? Allora, ricapitoliamo
velocemente come funziona un lettore CD.
Premiamo il tasto di accensione e questo
si accende. Ok? Supponiamo che sia
attaccato alla corrente,
quindi si trova nello stato di standby,
noi piggiamo il tasto, questo aggeggio
si accende. Ok? Generalmente che cosa fa
il lettore CD? Cerca di capire se ci sta
un CD dentro o meno. Ok? Quindi lì
capisce ci sta, non ci sta. Il laser va
a vedere se ribalza c'è, se non rimbalza
non c'è. Ok?
Dopodiché premiamo eject, esce il
carrello, ci mettiamo il CD, eject,
questo ritorna dentro, premiamo play e
lui va avanti. Premiamo pausa, va in
pausa, ripremiamo pausa, lui riprende,
premiamo stop, lui si ferma, lo
spegniamo e il CP. Ok,
a grandi linee, questo è il modo in cui
funzionano lettore Cri, ok? Chiaro per
tutti? L'avete visto? Ok, modelliamo
questa cosa come un automa per capire
come si fa.
Io mi allontano dal microfono nella
speranza che lui non si arrabbi.
Alri, allora me l'ho schematizzato qua
per occupare poco spazio.
Ok,
modelliamo gli stati di funzionamento
degli automi con dei pallini. Ok?
Quindi abbiamo il primo stato che è lo
stato di stand
in cui arriva la corrente ma la cosa non
è accesa ancora. Ok?
Con questa freccia così
modelliamo il fatto che quando arriva la
corrente quello è lo stato in cui la
macchina si trova alla prima. Ok?
Abbiamo detto che quando premiamo il
pulsante di accensione,
la macchina si accende e testa la
presenza del CD al suo interno. Ok?
Quindi,
allora
con questa freccetta noi
intendiamo che la macchina sta ricevendo
un segnale dall'esterno, in questo caso
sta ricevendo il segnale di power
button. Ok? A quel punto lui si sposta
in uno stato di funzionamento che si
chiama test CD.
Ok,
che no es cio possiamoare
come vogliamo. Ok? A quel punto nello
nello stato test CD noi non modelliamo
di preciso come fa, però c'è sto laser
che va a guardare la presenza del CD.
Quindi a un certo punto
la logica del vettore CD riceverà una
risposta che gli dice il CD c'è, il CD
non c'è. Ok?
Se riceve no,
va nello stato
entro
ed è stopo.
Se riceve S
va nello stato CD in stop. Ok.
Ok.
Doviché o in questo stato,
nello stato che è vuoto, o nello stato
che è pieno, cioè CD dentro, che succede
se prendiamo il tasto?
Che succede? il car il carrello. Ok,
quindi abbiamo lo stato di
open,
quindi se premiamo i jet da entrambe di
queste modalità di funzionamento lui
apre il carrello.
Ok?
Se siamo nello stato di carrello aperto
e premiamo il jet, che succede?
Lui lo chiude e che cosa fa? Testa di
nuovo. Testa di nuovo se c'è CD dentro.
Ok? Quindi nel caso in cui nello stato
open premiamo il tasto, lui lo chiude e
va di nuovo a testare la presenza del
CD. Ok?
Cosa succede se premiamo il tasto power
e siamo nello stato in cui il lettore è
vuoto? Ma è fermo?
M
si spende. Quindi se premiamo power qua
andiamo qui.
Si spende sfigz siamo qua col CD dentro
e premiamo power si spegne.
Che succede se siamo nella fase di test
del CD e gli premiamo Power?
Si spegne.
Ok. Ok. è un modellamento un po' raff,
eh. Alri, allora noi assumiamo adesso
che se siamo nello stato in cui il CD è
dentro e noi premiamo play,
ci spostiamo in quest'altro stato di
play
in cui c'è il play. Se siamo nello stato
in cui lui sta suonando la musica e
premiamo pausa, che succede?
Com'è?
Pausa, non stop.
L'avete visto che succede? Va in pausa,
cioè si ferma al punto dove sta
leggendo. Quindi se premiamo pausa
andiamo nello stato post. Se premiamo
pausa nello stato post che succede?
Mi prende a fare play, quindi è poco
qua.
E se premiamo stop mentre stiamo facendo
play?
Bene, lo stato stop.
E se premiamo stop mentre nello stato
pausa stop.
Ok?
Questo è un automa che regola il
funzionamento
di un lettore CD. Ok? Quindi questa è
una macchina che ha vari stati di
funzionamento, ste ballette, la cui
risposta agli stimoli dipende dallo
stato in cui si trova. Ok? Se premo play
e
il CD estendo, non pagina. Ok?
Chiaro per tutti? Questa cosa, questo
modello noi lo estendiamo a
delle macchine
astratte
che seguono questo principio che sono in
grado di riconoscere
i linguaggi, ok? E partiremo dagli
automi più semplici in assoluto che sono
simili a quello che abbiamo visto, che
sono gli automi deterministici a stati
finiti. Ok? Stati finiti che significa?
Che ha un numero finito di pallente, ok?
Per voi chi ha fatto, non so,
architettura dei calcolatori eccetera,
gli autoni si implementano, immagino
avrete visto, cioè sono reti
sequenziali. Avete un insieme di flip
flop che codificano lo stato e avete i
segnali, leggono nella rond e andate
oltre. Cioè è una macchina veramente
semplice. Ok? E quindi quello che noi
vogliamo fare ora è generalizzare questo
modello perché c'è guardare
generalizzare questo modello al
questione di dato un linguaggio
stabilire deciderlo, cioè quindi data
una stringa stabilire se quella stringa
appartiene a un linguaggio almeno. Ok?
E il linguaggio che noi ci interessa
come esempio è questo qua.
e l'insieme
insieme
delle
stringhe
binarie
che
rappresentano
un numero di
Ok? È chiaro cosa devo fare? Abbiamo un
linguaggio delle stringhe binarie
che rappresentano numeri dispari.
Alr, ragioniamo insieme. Qual è sicabeto
di interesse per noi?
cos'è il sost
tutte le sequenze di 0. Tutte le
sequenze di 0. Quindi vuoto. La vuoto la
facciamo con l'epil
0 1
e così via. Ok? Sono infinite queste.
Sono un numero infinite di stringhe
ognuna delle quali ha unazza finita. Ok?
L il linguaggio dei numeri codificati in
binari o che siano dispari è un
sottoinsieme di questo sigma st. Ok?
Quindi noi abbiamo che L è un
sottoinsieme
di sigma star. Ok?
Alr
cosa caratterizza
le stringhe binare dispar
finiscono tutti. Ok? E quindi noi
dobbiamo ora costruire
un automa che ricevuta una stringa in
input sostanzialmente va a stabilire se
il suo ultimo carattere, se il tuo
ultimo simbolo è 1. Se è 1 dice sì,
questa stringa appartiene a L. Se è zero
ci dice no, questa stringa non
appartiene a L. Ok? Sì. E come viene
trattato il caso vuoto, caso vuoto non è
un numero, quindi non dobbiamo
accettare. Ok,
chiaro per tutti? Quindi adesso con la
metafora dell'automa che codificava un
CD, un lettore CD, vediamo ora come
scrivere un automa quindi un algoritmo
che è in grado di riconoscere le
stringhe appartenenti a questo L dei
numeri dispari. Ok?
Allora, allora
pregherei chi ha seguito il corso di
linguaggi di
mantenersi un attimo, farò una serie di
domande e poi la risposta la sboglio
voglio interagire un po' con gli altri.
Allora, in questa automa noi dobbiamo di
nuovo identificare lo stato di
funzionamento iniziale che è lo stato di
funzionamento nella quale l'automa,
questo oggio si trova nel momento in cui
diamo corrente. Ok?
lo chiamiamo Q0, lo stato iniziale, gli
facciamo la freccetta colorata e questo
però significa che quando la macchina
si attiva
si ritrova in questo stato di
funzionamento in zero. Adesso i segnali
che possono arrivare a questa macchina,
nell'esempio del lettore CD avevamo che
i segnali erano i tasti che noi
premevamo sulla sul lettore. Ok? I
segnali che arrivano alla macchina che
riconosce
le stringhe di un linguaggio, i segnali
che arrivano sono i simboli in sequenza,
uno dopo l'altro. Pa prima c'è zero, poi
ce sta uno, poi ci dà di nuovo zero, poi
uno, poi uno, di nuovo un altro uno, poi
c'è zero, eccetera. Ok? Quindi non
parliamo più di bottoni da premere, però
se è utile per voi pensare a questa
metafora, premi il bottone zero, premo
il bottone 1. Ok, ma funziona lo stesso.
Quindi noi abbiamo che questa macchina
riceve come segnali in input i simboli
di una stringa che riceve input e vuole
capire se fa parte del linguaggio, in
questo caso dei numeri dispari o no. Ok?
Allora,
supponiamo che partiamo, ok? E come
primo simbolo che la macchina vede che
gli arriva è un uno.
Domanda per noi. È possibile che questa
sia una stringa dispari se il primo
simbolo che arriva a noi è uno? Non
sappiamo niente del resto, eh. Cioè la
macchina non sa quanti singoli
arriveranno, lei ripete uno dopo
l'altro.
Lei ha fatto linguaggi? Eh no,
ok.
Cioè noi non lo sappiamo se arrivano in
ordine dalla P e arrivano in sequenza,
cioè una stringa una stringa abbiamo 0 1
0 1 1 0 1 gli arriva prima questa, poi
questa, poi questa, poi questa, ok? G
arrivano in sequenza da sinistra verso
destra, la prima, la seconda, la terza.
Ok? La macchina però non sa cosa gli
arriverà, gli arriva una dopo l'altra,
cioè non sa niente. Quindi supponiamo
che
gli arriva input, come primo segnale, il
primo uno di questa stringa. Ok? La
macchina non sa se è l'ultimo, sa solo
che è un uno. Poi può succedere di
tutto, potrebbe essere l'ultimo,
potrebbe non essere l'ultimo. Ok?
La macchina in linea di principio
potrebbe ipotizzare che questa stringa è
disparo
se gli arriva l'uno e questo è l'ultimo
uno che vedrà perché non gli arriva più
niente, quello lì era un numero di
storia o no? Sì. Ok? Quindi, quando mi
arriva un 1 e sto in Q0,
io mi sposto nello stato di ipotesi,
questa stringa potrebbe essere dispar,
ok? Perché se non mi arriva nient'altro
quella sierà dispar, ok?
Quindi leggo 1
e mi sposto nello stato Q1 che è lo
stato di funzionamento del la stringa
input probabilmente è disparo.
Ok? Quindi possiamo dare un significato
ai due stati. Q0 è probabilmente la
stringa in pari, Q1 probabilmente è la
stringa in dispari. Diciamo
probabilmente perché dal punto di vista
della macchina non so se mi arrivano
altre cose. Ok?
Se sono in V1 e mi arriva un altro uno,
cosa posso dire? Che questa stringa
probabilmente sarà dispari o no?
Sì.
Sì. E ok, quindi se leggo uno rimango
nello stato di funzionamento diviso.
Se sono in uno,
quindi ho già visto uno, per esempio,
no? E ricevo uno zero, posso dire che la
stringa che sto processando potrebbe
essere dispari? No, no, perché se lo
zero che mi arriva ora è l'ultimo
l'ultimo simbolo della stringa, quella è
la certezza che la stringa è pari.
Quindi se vedo uno zero mi sposto nello
stato, forse la stringa finisce con
zero.
Ok?
Quindi q0 è forse la stringa finisce con
0. Q1 è forse la stringa finisce con 1.
Se sono in Q0,
quindi sono nella modalità di
funzionamento, forse la stringa finisce
con zero e mi arriva un altro zero, che
faccio?
Q0 rimaniamo in q0 perché già questo è
un altro. Ok?
Se sono in V0 e leggo un dove me ne
vado?
In V1. Perché cavolo, vedo un uno, la
stringa forse finisce con quest'uno. Ok?
Noi indichiamo con la doppia parete
il fatto che questo stato è accettante.
Questo significa che se la macchina
mentre computa
va a finire in Q1 e i simboli finiscono,
la macchina dice sì, questa stringa che
ho visto era una stringa disparita. Ok?
È chiaro intuitivamente come funziona?
Quindi questa è una macchina molto
semplice che ha due stati di
funzionamento.
Ho visto zero e quindi potrebbe questa
stringa potrebbe finir con zero, oppure
ho visto uno e questa stringa potrebbe
finire con uno. E questa macchina
oscilla, per esempio,
supponiamo di star processando questa
stringa. Alla lettura del primo 1 la
macchina si muove da q0 a Q1, poi legge
lo 0 e si sposta da Q1 a Q0, poi legge 1
e si sposta da Q0 a Q1, poi legge 0, si
sposta da Q1 a Q0, legge di nuovo 0,
rimane Q0 e così via. Fino a quando
arriva l'ultimo uno, non ci sono più
simboli, la macchina si arresta
in questo stato finale. Ok?
E quindi siccome l'input è finito e la
macchina si è bloccata nello stato
accettante, la macchina dice sì.
Se la macchina si blocca in Q0 che non è
uno stato centrante, la macchina dice
no. Questo è una semplicissima macchina
è in grado di stabilire se una stringa
rappresenta un binario dispari o
chiaro?
Quindi questo problema, dato un numero
intero rappresentato in binario,
stabilire se è dispari è una cosa
semplicissima
da fare.
Ok?
E questo è troppo lungo per
Ok, ci fermiamo qua per Grazie Milla la
discussione.