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 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.