Quindi lezione scorsa di una settimana fa che abbiamo fatto? Abbiamo fatto macchine, esercitazione su macchine multinastro. Ok, quindi avevamo visto sto modello di macchine multinastro, abbiamo visto che sono equivalenti alle macchine mononast, no? e che quindi possiamo usarle invece delle macchine mononastri, ok? Quindi tutto ciò che è calcolabile da una macchina multinastro è anche calcolabile da una macchina monastro. Quindi noi usiamo le macchine multilastro perché perché sono più facili da programmare. Ok? Perché adesso dovremmo iniziare a vedere un po' di cose e sapere di avere una macchina a più nastri ci semplifica un po' anche Ok? Che altro? Ma questo abbiamo visto che la simulazione, questo qua è importante, la simulazione di una macchina antinastro su una macchina mononastro ci costa quadratico, il che significa che rallentiamo sì, ma non è così sconvolgente, ok? Non cambiamo ordine di complessità. Per voi che avete fatto algoritmi e strutture dati, sapete, insomma, che ci sono algoritmi polinomiali, algoritmi esponenziali. Non so se vi è mai capitato di vedere algoritmi doppiamente esponenziali, triplamente esponenziali, no? Doppiamente esponenziale non è 2^ 2 * n, doppiamente esponenziale è 2^ 2^ n, cioè è è una cosa mastodontica. Adesso, se noi facciamo il quadrato di queste funzioni, un quadrato di un polinomio rimane un un polinomio, il quadrato di un esponenziale rimane esponenziale, il quadrato di un doppiamente esponenziale rimane nella famiglia dei doppiamenti esponenziali. Cioè, quindi avere più una strone che ci fa ci sconvolge così la vita al punto tale per cui se noi siamo interessati raff sulla complessità di alcuni algoritmi sapere è polinomiale, è esponenziale, è doppiamente esponenziale, una cosa del genere, lavorare su macchine multinastro non ci modifica sostanzialmente il risultato, di conseguenza le usiamo perché perché è pratico. Ok, tutto qua. Quello che andiamo a introdurre oggi è il modello che useremo per il resto del nostro corso. Perché? Perché è pratico. Allora, vi faccio un primo esempio e cerchiamo di capire che ha di strano questa macchina. Ok, assumiamo di avere questa macchina qua. Quello sta registrando. Y no. Ok, alloraamo qui 0 come primo stato. Leggiamo zero, scriviamo uno e andiamo avanti. Qua ci sta uno, leggiamo uno, scriviamo zero e andiamo indietro. Qua c'è un altro. C'è uno. Lasciamo uno e andiamo indietro. C'è zero, lasciamo zero e andiamo indietro. Questa è una semplicissima macchina monastro. Eh, c'è zero, lascio zero e vado avanti. C'è uno, lascio uno e vado avanti. C'è blank, lascio blank e vado avanti. E andiamo in Q2. Ok, questa è una semplicissima macchina monastro. C'ha tre stati, il solito stato iniziale, stato finale, bla, etichette, archi, eccetera, cose che abbiamo sempre visto. Ok. Che ha di strano questa macchina? Chi chi? Ok. Dove? In Q1. In cosa? Perché se legge zero può ciclare zero, può ciclare esattamente. Questa macchina ha la peculiarità di essere non deterministica, cioè questa macchina per una particolare coppia, simbolo, letto, stato in cui sono, abbiamo più di una scelta, ok? Cioè questa macchina potrebbe transire o, come dice il nostro collega, rimanere in Q1 o muoversi in Q0. Ok? Questi questa macchina è sostanzialmente differente dalle altre macchine che abbiamo visto finora, perché ora ne abbiamo viste di varie varianti, mononastro, multitraccia, multinastro, eccetera, ma tutte quelle macchine erano tutte deterministiche, cioè per qualsiasi coppia, simbolo in input o simboli input, se era multitraccia o multinastro, è stato in cui mi trovo Nuovo. La macchina ha una sola un solo possibile next step, cioè la macchina sa che fare. Questa macchina qua è un po' peculiar perché qui ha un del non determinismo, cioè in quel punto se la macchina legge 0 e sta in Q1 potrebbe andare in Q0 o potrebbe rimanere in Q1. Ok? il fatto che questo ve lo sottolineo, guardate queste label, questa qua e questa qua, ok? Il fatto che qui leggiamo 0 e scriviamo zero e qui leggiamo 0 e qui scriviamo zero sia lo stesso da tutte e due le parti, è semplicemente un caso. Qui potevamo trovare leggo 0 e scrivo 1 e qui leggo 0 e scrivo 0. Ok? c'è completamente scorrelato, ci può essere qualsiasi cosa. L'unica cosa che le accomuna è questo stato simbolo letto che è lo stesso. E quando la macchina si trova qua e legge zero in linea di principio può fare due mosse. Ok? Adesso, prima di buttarci a capire che faccia questa macchina su una stringa di esempio, a questo punto, siccome noi sicuramente ci ricordiamo le definizioni formali di macchina di Touring, deterministica, introduciamo quella non deterministica, ok? Rivediamola assieme. Allora, N è una macchina di touring non deterministica. È una tupla caratterizzata da, vi ricordate da cosa è caratterizzata una macchina di Touring deterministica? Alfabeti. Ok. Abbiamo sigma che è l'alfabeto di dei simboli leggere input dei simboli input è l'alfabeto dei simboli che possiamo trovare sul nastro quando la macchina viene accesa. Ok? Però la macchina a parte leggere e scrivere quella roba, può leggere e scrivere altro, cioè c'ha i suoi simboli, le X, i cancelletti, le casette, ok? Quindi ha la possibilità di accedere a un altro alfabeto che noi chiamiamo gamma che è l'alfabeto di nastro, cioè è l'insieme di tutti i simboli che la macchina può maneggiare sul nastro. Ok? Ovviamente eh sigma è un sottinsieme di gamma, un sottinsieme stretto perché tra i simboli che ci stanno in gamma abbiamo blank, il simbolo di bianco che è eh identifica quando una cella del nastro della nostra del nostro nastro è vuoto. Ok? Alright. Quindi due alfabeti, un simbolo di bianco. Poi cosa c'avevamo nelle definizioni? Abbiamo l'insieme degli stati. Ok, quindi ci stanno. Ma guardiamo la il disegno. C'abbiamo i palletti. I palletti che sono i palletti? Sono sono gli stati. Quindi abbiamo Q. Lo chiamiamo Q per convenzione, lo potevamo chiamare pure Pippo. Ok? L'importante è che ci sia un insieme degli stati. Q lo chiamiamo Q. Fra tutti gli stati ce n'è uno che identifichiamo come stato iniziale che è Q0. Nella nostra grafica lo scato iniziale c'ha la freccetta entra in quel modo e quello ci identifica con lo stato iniziale. Tra tutti gli stati Q abbiamo l'insieme degli stati finali che possono essere in linea di principio Q1. Ok? Non abbiamo, a differenza di altre definizioni, voi le troverete su altri libri, gli stati rejecting noi non li abbiamo. Abbiamo definito il reject in un altro modo, è totalmente equivalente, cioè queste definizioni si intertraducono. Una cosa che può fare la macchina lo può fare anche l'altra. Ok? E dopodiché c'era un'ultima cosa, la funzione di transizione, cioè il programma di questa macchina che è sostanzialmente gli archi e le etichette di questo grafo. E l'avevamo chiamato delta. Ok? Questa cosa qua, la funzione di transizione per una macchina non deterministica è una cosa un po' particolare. Ok? Vi ricordate? deterministica. Vi ricordate per una macchina deterministica com'era definita la funzione di transizione? Delta è una funzione che va che mappa che cosa? Ok, siamo in uno stato, leggiamo un simbolo e ce ne andiamo dove? in uno stato. In uno stato scriviamo scriviamo un certo simbolo e e ce ne andiamo o a sinistra o a destra. Ok? Questa era la definizione per macchine deterministiche. Ok. Sì. Cal Ah, sì, sì, sì, sì, giusto, giusto. Corret. Alri, primo, no, perché in linea di principio noi potremmo aver letto cose che abbiamo scritto prima e quindi c'abbiamo simboli strani su cui processare. Ok? Se in passato vi ho scritto sigma era sbagliato e e gamma. Ok? Quindi questa è la definizione di funzione di transizione, cioè è il programma di una macchina deterministica, il programma di una macchina non deterministica, cioè quindi la definizione per una macchina non deterministica finora è praticamente la stessa cosa. Abbiamo sigma, abbiamo gamma, abbiamo il simbolo di bianco, abbiamo Q, abbiamo Q0, abbiamo l'insieme degli stati finali e abbiamo delta. Delta per una macchina non deterministica è una cosa un po' più sofisticata perché data una coppia stato simbolo noi possiamo avere un insieme di di prossimi passi, ok? E questa cosa va modellata per una macchina non deterministica. Noi abbiamo che delta è una funzione così fatta, è una funzione che mappa le coppie stato simbolo verso l'insieme delle parti delle triple stato simbolo direzione. Che simbolo? 2^ Q 2^ Q lo usiamo per indicare tutti i possibili sottoinsiemi da quel dominio. Ok? Questa è la differenza. Cioè questa funzione alcuni preferiscono definirla come una relazione o si può definire in questo modo, cioè che mappiamo da uno stato e un simbolo a un insieme di prossime mosse oppure mettiamo una relazione è la stessissima cosa tale per cui su alcuni testi troverete che delta per le macchine non deterministiche è una relazione di transizione e non una funzione di transizione, ma il senso è quello, cioè quindi il programma per una macchina non deterministica è la stessa cosa di una macchina deterministica. Quello che cambia è che in alcune circostanze, ok, questa funzione può specificare più possibili next steps. Ok? Questa è l'unica differenza. Prima cosa da sottolineare, è necessario che la funzione di transizione di una macchina non deterministica sia non deterministica su tutte le possibili coppie, no? Come possiamo vedere nell'esempio che ci siamo fatti, il non deteriorerminismo sta solo qua, fra l'altro solamente su un simbolo soltanto, no? Anche qui, eh, pure su uno, uno, eccetera. Ok? Quindi la macchina non è necessaria che sia tutta non deterministica, basta che abbia parte della funzione o della relazione di transizione che mappi verso un insieme di cardinalità maggiore di uno. Ok? In quel momento la macchina diventa non deterministica. altre definizioni equivalenti di questa macchina che potreste trovare in giro su altri testi se li se li consultate. Dico il testo di Aurora le definisce in un modo un po' differente, però sono equivalenti, eh non cambia assolutamente niente. Io preferisco questa perché è più semplice. Nel testo di Aurora la macchina non deterministica è definita con due funzioni di transizione, una che chiama delta 0 e l'altra che chiama delta 1. E non determinismo deriva dal fatto che ogni volta che la macchina si trova in un certo stato e un certo simbolo, potrebbe prendere la prossima prossimo passo o da delta 0 o da delta 1. Ok? si può dimostrare che è la stessissima cosa. Noi facciamo riferimento a questo perché è più semplice, anche perché il testo, il primo che vi ho consigliato, è quello di Opcroft. Usa questa qua, è quello classico, continuiamo a usare questo, va benissimo. Ok. Alright. Quindi mh mh cosa vedete? Vedete, ad esempio, per l'esempio qua, quello lo vedete? Sì, lo vedete? Ad esempio, se noi abbiamo, per l'esempio che ci siamo scritti in alto delta di Q10, che cos'è? è un insieme. È un insieme, quindi ci pacchiamo una bella parentesi che raffa, ok? Un insieme che contiene cosa? Contiene triple, ok? Un insieme di triple. Triple che ci dicono che dobbiamo fare. Ok? La prima tripla è com'è? Q0 Q0 wait again. Un uno. Ah, ok. Stai andando su quello. No, no, no, no. Attenzione, sono in Q1 e leggo zero. Ok. Ah, sì, sì. Zero. E poi sinistra. Sinistra. Ok? E questa è la prima tripla. L'altra tripla Q1, eh Q1 0 destra. Ok? Quindi la funzione di transizione per quella coppia specifica ci sta dando due possibilità. Ok? Quindi è questo. Quando noi diciamo che mappiamo verso l'insieme delle parti è perché noi abbiamo che questa funzione Qua c'è spazio. Sì. che questa funzione, ok, applicata su degli input particolari può dare origine a due risultati, ok? Cioè che sono gli insiemi che fanno parte di questa cosa qua. Ok? Avete ricopiato la macchina? Ok, perché ci dobbiamo spostare per farvi un esempio. Alri. Vi ricordate quello che ci interessa ora vedere come questa macchina computa su un particolare input che gli diamo impasto, ok? Per vedere che genere di giri inizia a fare. Chiaro? Vi ricordate che concetto abbiamo utilizzato sulle macchine deterministiche per catturare lo stato di avanzamento della della computazione e configurazioni, ok? Le avevamo chiamate configurazioni o descrizioni istantanea, instantaneous description. Ehm Ok. E vi ricordate com'erano fatte? erano delle stringhe che contenevano che cosa? Attenzione, attenzione. Lei stava. Supponiamo che la macchina Ok, riarriviamoci assieme. Supponiamo che la macchina sta girando. Tr tra tr. Arriva a un certo punto la corrente se ne va. Supponiamo che vogliamo farla ripartire, cioè si dimentica tutto. Vogliamo farla ripartire da uno stesso punto. Che informazioni ci servono? Lo stato in cui era. Ok, e questa è un'informazione che ci serve. Quello che ci stava sul nastro, ok? La parte non blanca del nastro, perché ovviamente senò serve una cosa infinita, ok? Quindi la parte non blanca del nastro e poi e dov'è la testino? E dov'era la testina? Ok? Quindi noi abbiamo questo genere di informazioni ci permettono di far ripartire la macchina da dove è rimasta. Ok? Questa è una metafora. Ovviamente per noi una configurazione sono le informazioni per capire fin dove è arrivata la macchina. Ok? Noi non memorizziamo nella configurazione la sua funzione di transizione, ok? È solo una questione di dove sta computando in quel momento. E vi ricordo che praticamente la configurazione era la stringa del contenuto del nastro. più il simbolo dello Stato che appariva in mezzo agli altri per dirci dov'è che stava la testina. Questa è la configurazione. Ok? E noi avevamo detto che la computazione per una macchina deterministica, ok? era praticamente la sequenza di configurazioni, cioè la sequenza di fotografie che la macchina attraversa nel momento in cui viene avviata e arriva fino in fondo. Ok? Poi c'era se era parziale, non era parziale, se arriva in fondo, se non arriva in fondo, avevamo fatto tutto quel gran casino, insomma, per dare un po' di definizione. Ok? Quello che vogliamo fare ora è vedere la sequenza delle configurazioni di questa macchina non deterministica su un particolare input. Supponiamo di avere input la stringa 01. Ok? Qua c'abbiamo spazio. Sì, qua vedete più o meno. Alr Ok. Allora, configurazione iniziale della macchina. Qual è? Vi ricordo che la configurazione in cui la macchina viene accesa, quindi la macchina è nello stato iniziale che è Q0. Cosa ci sta sul nastro? La string input che è 01 perché abbiamo deciso così. Ok, quindi noi vogliamo vedere adesso che succede. Ok? Alri, qual è la configurazione successiva? Quindi siamo, prendete il grafo della vostra macchina, indisiamo in Q0, leggiamo zero che dobbiamo fare? Mh. Scriviamo 1, andiamo avanti e rimaniamo in Q0. Quindi questo 0 qua deve diventare 1. Quindi la configurazione successiva è 1. Stiamo andando avanti, quindi la testina apparirà qua e poi qui avrò zero. Ok? Il nuovo stato è Q1, quindi lo Q0, cioè Q0 e qui abbiamo 1. Ok? Quindi questa è la nuova configurazione. Ok. Prossimo passo. Mh. Fare Q. Andiamo in Q1. E che facciamo? Ok, quindi andiamo in Q1 1 0. Ok, questo uno qui è diventato zero qua perché ci abbiamo scritto di Ok, siamo in Q1 0 dopo. Che succede là? Come? Scus. Ok, quindi lì la macchina ha due scelte e noi mettiamo e noi lì mettiamo due branch, uno di qua e uno di qua. Ok. Primo branch. Quale volete considerare? Mh. Quello che va in zero. Quello che vengo zero. Ok. Allora, siamo in uno, leggiamo zero, scriviamo zero e andiamo dietro. Eh, no, leggiamo uno. Siamo in Q1, leggiamo uno e andiamo dietro. Allora, andiamo in questa configurazione qui. Q0 blank Dov'era questo? Questo uno viene sovrascritto da questo stesso uno. Poi, siccome stiamo spostando la testina dietro, qui introduciamo blank per sottolineare che la testina sta leggendo il primo blank prima del degli altri. Ok? Dall'altro lato invece eh sì Q1 0. Ok. Alright. Focalizziamoci sulla configuration di sinistra. Prossimo passo. Non c'è non c'è. Ok, quindi questa è una configurazione finale o no? Sì, secondo la nostra definizione una configurazione finale quando non c'è un prossimo passo. Quindi questa è una configurazione finale. Ok, sto riutilizzando un po' di definizioni. Poi questa configurazione finale è accettante o rigettante? Non è accettante, quindi ci mettiamo una bella X. Ok? Quindi vuol dire che se la macchina processa dall si va a bloccare da una parte dove risponde di no. Ok? Andiamo avanti. Vediamo questo ora. Ok. Siamo in Q1 e leggiamo 0. Quali sono Qual è la possibile mossa successiva? Mh, scusi, ma quante ce ne stanno? Uno o due? Ce ne stanno due. Ok. Ok. Quindi mettiamo doppio branch. Ok. Facciamo quella di Q0, ad esempio. Quindi leggiamo 0, lasciamo 0 e andiamo indietro e ci muoviamo in Q0. Quindi è Q0 1 0. Dall'altro lato è che leggiamo 0, lasciamo Z0, rimaniamo in Q1 e stiamo leggendo il primo blank dopo il testo, cioè dopo la stringa che sta su nastro. Ok, di nuovo focalizziamoci ora su questa qua. Siamo in Q0, leggiamo quindi sovrascriviamo l'uno con lo 0 e andiamo in Q1, ci muoviamo a sinistra, quindi è q1 blank 0. Dall'altro lato abbiamo eh dove siamo in Q1 e leggiamo blank. Lasciamo il blank lì dov'è, andiamo avanti e ci spostiamo in Q2. Quindi abbiamo 1 0 blank Q2 blank. Ok, consideriamo questo. Siamo in Q1. Leggiamo blank. Che facciamo? Ci scriviamo blank di sopra, spostiamo la testina avanti e transiamo verso Q2, quindi è Q2 0. Focalizziamoci su questa. Siamo in Q2 e leggiamo blank. Che facciamo? Mamo, ci fermiamo, ci fermiamo. Quindi è una configurazione finale. Questa configurazione ha uno stato accettante o no? Sì, di conseguenza questa è una configurazione accettante per noi. Ok, andiamo a guardare quest'altra che era rimasta appesa. Q2 00. Siamo in Q2 e leggiamo zero. Che facciamo? Ci blocchiamo. È una configurazione finale. Sì. Lo stato Q2 è uno stato accettante. Sì. Quindi questa è una configurazione accettante. Ok? Quindi questa macchina Ok, ha un modo per rifiutare e due modi per accettare. Ok? intuitivamente, poi diamo la definizione più precisa dopo, una macchina non deterministica accetta il suo input se ha un modo per farlo. Ok? Questa è la definizione di macchina, di condizione di accettazione di macchina in tuning. Poi la rivediamo un attimo più ritoccata. Ok? Alright. Quindi in questo esempio specifico, siccome c'è una sequenza di passi che la macchina può compiere al fine di rispondere sì, questa macchina risponde sì. Ok? Supponiamo quindi che abbiamo questa bella macchina sul tavolo qua, gli diamo 01 input. Questa macchina deve accettare, ok? Perché per definizione questa macchina deve accettare. Abbiamo scritto 01 sul nastro, glielo stiamo dando input. La prima macchina la i primi passi della macchina. Primo passo, la macchina fa questo. Secondo passo, la macchina fa questo. Ok. Terzo passo, la macchina deve fa qualcosa. Ok. Cosa ci aspettiamo di osservare sulla macchina che sta computando? Mh. Eh, quale conta che deve accettare? Eh, potrebbe scegliere una delle due per fare backing. Potrebbe scegliere una delle due e fare backtracking. Quindi, come terzo passo la macchina noi potremmo osservare che la macchina fa uno dei due passi, poi in caso di problemi torna dietro e e fa l'altra strada. Ok, questa è una possibilità. altre un'altra è ha una palla di cristallo e sceglie direttamente quella giusta. Ok, gli abbiamo inserito questa scheda magic. Ok, arrivato là la macchina non sa che fare, consulta l'oracolo, gli dice "Vai da quel lato è meglio". E la macchina segue questa cosa. Ok. Altro? La macchina potrebbe tirare la monetina, la butta al cazzo, tira la monetina in base a quello che esce la macchina fa una strada l'altra e se poi arriva da una cosa sbagliata, eh, torna dietro, fixa tutto e continua. Oppure potrebbe rimanere incastrato in uno stato piùante. Altro, l'altro è la macchina si sdoppia. Da un lato prova una strada, da un lato prova l'altra. Ok? Queste sono tutte cose che la macchina potrebbe fare. Ok? Ma quale di questa fis come non esiste. Sei accogli? No, non esiste. Cioè non può esistere una macchina che la macchina non così non esiste la macchina non fa niente di tutto ciò. Ok. Non fate ritrar. Quelle che abbiamo detto sono tutte metafore che nei libri potreste trovare. La macchina va a casa, la macchina le prove tutte contemporaneamente, la macchina va in backtracking fino a trovare la strada. La macchina sente da dove deve andare e si butta di là. Ok. La macchina sa che fare, so tutte metafore. Niente di tutto ciò è ciò che la macchina fa, perché una macchina del genere fisicamente non esiste. Ok? Quindi tutto il discorso che è partito era fallace dall'inizio quando vi ho detto supponiamo di avere la macchina su questo tavo. No, questa macchina sul tavolo non la possiamo avere. Questo genere di macchine, così come sono definite non esistono. Allora, perché mai ci dovremmo occupare di studiare roba che non esiste? Perché è più facile e cioè quella è sempre quella la ragione perché è più semplice. Le macchine inuring non deterministiche sono state introdotte come modello astratto di calcolo, no? Perché a quel tempo si cercava di capire quali sono le funzioni calcolabili, quali sono le funzioni non calcolabili e si vide che se si utilizzava questo stratagemma della macchina non deterministica si potevano semplificare tutta una serie di cose, ok? Tale per cui conveniva usarla. Quindi noi che facciamo? Noi utilizziamo il modello della macchina di touring non detergico, sebbene non esista perché è più semplice ragionarci sopra. Ok? Vedremo dopo la pausa o prima della pausa, no, dopo la pausa vedremo che in realtà, cioè questo non è un salto che facciamo nel vuoto. Noi possiamo fare questa assunzione di lavorare sulle macchine non deterministiche perché abbiamo dei modi per gestirle, per simularle. Ad esempio, tutto quello che avete detto in qualche cioè tutto no, però la strada del back trading è una strada fattibile. Voi che avete fatto algoritmi e strutture, avete visto gli algoritmi in background, non l'avete fatto? E ci metteranno, però di principio se può fa', cioè io ci provo, arrivo, rifiuto m cazzarola. Va, vado al punto di scelta precedente, vediamo che cosa cavolo era successo. Provo ad andare. Ok, esploro questo albero, sbatchiamo la testa contro il muro, non va bene, risaliamo. Che avevo scelto, non va. Proviamo l'altra strada, sbattiamo di nuovo, torniamo indietro. Quindi, insomma, via back trading se può fare, ok? Cioè, quindi è una cosa fattibile. Focalizziamoci per il momento sulle definizioni formali adesso di questo modello di calcolo, poi ci lavoreremo un po' meglio dopo la pausa, però prima formalizziamo tutto. Le configurazioni per le macchine non deterministiche sono equivalenti alle configurazioni delle macchine non deterministiche. Ok? Quindi una configurazione per una macchina non deterministica, come abbiamo visto, è la stessima cosa, una sequenza di simboli che ci dice il corrente contenuto del nastro, qual è lo stato, dove sta la testina e usiamo lo stesso formalismo. Ok? Una configurazione iniziale per una macchina non deterministica è la stessa cosa, Q0 seguito dall dalla sequenza dei simboli della scriv input. Ok? Configurazioni finali per le macchine non deterministiche uguali. Una configurazione per una macchina non deterministica è finale se non ammette configurazioni successive. Ok? Una configurazione finale è accettante, se lo stato che appare è accettante. Una configurazione finale è non accettante, se lo stato che appare è non accettante. Ok? Questo è tutta roba stessa, identica, spiccicata alle macchine deterministiche. Non stiamo cambiando niente. L'unica cosa che cambia sulle macchine non deterministiche è che una data configurazione può avere più legal successo. Questa è è la è l'unica differenza. Ok? Per le macchine deterministiche, data la configurazione, se noi conosciamo la funzione di transizione, abbiamo una sola possibile prossima configurazione sulle macchine non deterministiche. Questo non è detto. Come potete vedere nell'esempio sopra, non è che noi a ogni step non sappiamo dove andare, cioè ci sono pezzi di computazione deterministica, ci sono pezzi di computazione non deterministica e così via. Quindi la differenza è che i legals accessor di una configurazione per una macchina non deterministica possono essere più due. Ok? E come abbiamo visto in questo esempio qua, la sequenza delle configurazioni, più che essere disposte su una lista, come facevamo per una macchina, no, su una macchina deterministica, la sequenza delle configurazioni per una macchina non deterministica noi la possiamo organizzare in un albero, ok? E quindi introduciamo un concetto che non avevamo introdotto per le macchine deterministiche, ma solo perché era farlottocco, eh, non perché non si può fare. Il concetto di computation 3, albero della computazione. Cos'è un computation 3 per una macchina non deterministica? E definiamo la schiena, guardiamo il disegno, è un albero e quindi come gli alberi è costituito da nodi, rami, uno di questi nodi è la radice, ci saranno alcune foglie. Ok? Quindi un computation 3 per una macchina non deterministica su una specifica stringa di input, sostanzialmente deve catturare quali sono tutte le possibili computazioni che la macchina potrebbe in linea di principio fare su una determinata stringa di input. Quindi o computation 3 per una macchina M su una stringa W è un albero i cui nodi sono tutte le possibili configurazioni in cui la macchina M può mai trovarsi mentre processa la stella W. Ok? Quindi quali sono i nodi di questo albero? sono tutte, cioè le possibili configurazioni della macchina in cui la macchina si può mai trovare mentre processa la stringa do B. Ok? Questo caso perché non deve essere a perché se abbiamo per esempio diciamo prima se la macchina ruffa c'è noi laamo di là è l'albero è l'albero Sì, sì. L'albero C. Bene. Se c'è un lupo scrivere e noi abbiamo un rato se c'è un gruppo. Ok. infinito, cioè abbiamo r infinito, abbiamo alberi, sono robe strane queste compri, ok? Tanto non lo dobbiamo, come vedremo, non lo dobbiamo rappresentare è una cosa che ci serve solo a noi per per ragionare. Ok? La radice di questo albero è la configurazione iniziale della macchina M su w, quindi c'è uno solo, cos'è? È Q0 con la W. E c'è dobbiamo definire adesso gli archi. C'è un arco da una configurazione alfa a una configurazione beta, se beta è uno dei successo real. Ah, finito. Questa è la definizione di computation 3 per una macchina di tuning deterministica. Alfa beta. Dati due nodi alfa e beta dentro il configuration il computation 3 alfa è collegato a beta se c quindi c'è un link da alfa verso beta se beta è uno dei legal successo di alfa. Ok? Quindi abbiamo semplicemente formalmente definito quello che ci stava là. Ok? Chiaro? Alri. una macchina di touring, una macchina di touring M non deterministica accetta il proprio input w se all'interno del computation 3 di m su w appare una configurazione accettabilis accetta una stringa B se e solo se nel computation 3 di M su w compare da qualche parte, non ci interessa dove, né ci interessa come arrivare là. Accetta se nel computation 3 compare una configurazione accettante, quindi basta che esiste. La macchina per accettare basta che abbia un modo, ne basta uno. Eh, può avere un milione di miliardi di computazioni diverse e una sola di quelle accettante. La macchina risponde di sì su questo ok? E per rispondere no, che deve fare? Che deve succedere? Non ci devono essere. Cioè tutte le computazioni dentro il computation 3 o vanno a sbattere verso configurazioni finali non accettanti o non terminano mai. Cioè son cose lunghissime. Ok, vediamo se vi devo dire altro prima della pausa. La domanda la domanda ve l'ho fatta. La macchina accetta se c'è un brzo accettante. No, ci possiamo fermare. Facciamo 10 minuti applauso. Ok, cool. Ok, quindi prima abbiamo detto che noi ci interessiamo del modello macchine di touring non deterministiche perché è più semplice. Questo sì è vero, che ci dà più libertà nella programmazione delle macchine. Così è vero, ma questa cosa sarebbe usata solamente se una macchina di touring non deterministica. Meglio questa cosa sarebbe sensata solamente se una macchina di Touring non deterministic se una macchina di Touring deterministica fosse in grado di fare ciò che la macchina non terministi fa. Ok? Cioè, quindi noi c perché ah è bello avere questo modello così potente che però poi non siamo in grado di costruire. Alcuni di voi la volta scorsa mi hanno chiesto "Ma le macchine di Touring non deterministiche sono le macchine quantistiche?" No, una macchina di Touring non deterministica ha un potere particolare che una macchina quantistica non ha. Ok? Allora, perché mai ci dovremmo concentrare, no, su questo modello astratto di calcolo, se poi non lo possiamo costruire, magari tramite una macchina non deterministica siamo in grado di fare cose che una macchina deterministica no, non è in grado di fare e anche con grazie al cioè che facciamo? ci dobbiamo un attimo verificare che non ci stiamo muovendo verso territori che ci portano verso strade che non vorremmo battere. Ok? Allora, la domanda ora è: è vero o no che tutto ciò che siamo in grado di fare meglio, poniamola meglio, è vero, no, che tutti i linguaggi accettati da macchine non deterministiche possono essere accertate da macchine deterministiche, perché se questo è il caso. Allora, il gioco è fatto perché noi, almeno in questa prima parte del corso, ci interesserà studiare la calcolabilità dei problemi, cioè se una cosa ammette un algoritmo o non ammette un algoritmo. Quindi, nel momento in cui noi siamo in grado di dire, guarda che questo, cioè tutto ciò che fai con una macchina non deterministica, lo fai anche con una macchina deterministica. Allora, possiamo usare il modello del non determinismo perché abbiamo degli option anche sulle macchine deterministi che non abbiamo, cioè siamo in grado di definire una computazione tramite una macchina non deterministica in maniera molto più semplice. Però per fare questo ci serve questo passo internello. Dobbiamo stabilire se sia così o meno. Cioè, è vero che se io ho una macchina non deterministica che accetta, guys, sottolineo qua, accetta e non semplicemente decide. Eh, è vero, no, che se io ho una macchina non deterministica che accetta un certo linguaggio L, allora ne esisterà una deterministica che accetta lo stesso linguaggio L. Questa è la questione. Se fa o non se fa? Secondo voi si può fa'? Sì. Sì, è così come Allora, certo. Senò non ti sentono già non ti sento. Ma po io sono mezzo influenzato, quindi vai. Devo scrivere una nuova conzione sopra. Ok. Ok. Così stai scendendo però nel dettaglio sta scendendo nel dettaglio di come fare a livello intuitivo che dobbiamo fare questa macchina deterministica back trading. Ok? Cioè era l'idea che abbiamo avuto prima, la macchina deterministica, se progettata in maniera sensata, magari tramite backtracking, allora noi siamo in grado di progettare una macchina deterministica che accetta lo stesso linguaggio della macchina, non determistico. Magari lo farai in un modo un po' diverso, però l'importante è che dia le stesse risposte che se la macchina non deterministica accetta, la macchina deterministica deve accettare pure. E se la macchina non deterministica non accetta, allora la macchina deterministica deve pure non accettare. Ok? Quindi dobbiamo adesso inventarci, non entreremo troppo nei dettagli, però vedremo il principio che ci sta dietro. Qualche trucco per riuscire a far accettare a una macchina deterministica il lo stesso linguaggio di una macchina non deterministica. Ok? Supponiamo di avere Sì. Supponiamo di avere una macchina non deterministica N. Questa è non deterministica per semplicità è monodonastro. Sappiamo da tutto quello che abbiamo visto nelle lezioni precedenti, che noi possiamo ricondurre tutto a macchine mononastro e la stessa cosa si può fare per le macchine non deterministiche. Quindi, pure che fossimo partiti da una macchina di touring non deterministica multinastro, abbiamo modi per tradurla e farla diventare una macchina non deterministica, mononastro. Quindi supponiamo che N sia una macchina non deterministica mononastro, la trasformiamo in una macchina M deterministica multinastro. Ok? Poi per quello che sappiamo pure la macchina M, essendo multinastro può essere riconvertita a una macchina standard mononas. Ok? Stiamo facendo questa cosa semplicemente perché vogliamo essere certi che da ora in poi noi possiamo utilizzare il modello non deterministico per stabilire se un dato problema è risolvibile o non risolvibile. Ok? Quindi questa, supponiamo che la computazione della macchina n su un certo input sia così. Ha un certo ID0. Da questo c'ha un ID one. Primo. Ah, ID one secondo. Da questi abbiamo ID2 tu primo. L'albero di computazione della macchina. Sì. ID tu. secondo ID 2/3 e questi continuano. Ok? E questo continua, ok? Supponiamo che la macchina sta computando in computerebbe in questo modo su una certa string input, ok? Cioè che quindi può branciare in varie cose. Ok? Adesso quello che noi facciamo utilizzare una macchina di touring deterministica per esplorare l'albero di computazione. Sostanzialmente dobbiamo fare il back train. Ok? La macchina M è una macchina multinastro con due nastri. Primo nastro, secondo nastro. Ok. Ci sono vari modi per simularli, eh questo è uno dei tanti, preso dal libro Opgroft. Ok? Allora, che fa sta macchina? Sta macchina deve sostanzialmente esplorare in maniera sistematica i rami di computazione che stanno qua dentro. Questa è la cosa, ok? E lo dobbiamo fare in maniera sistematica. Perché noi dobbiamo accettare M deve accettare se solo se N accetta. Ok? Quindi dobbiamo stare attenti a non fare fesseria. Alri? Allora, la macchina funziona così. Come prima cosa noi ci scriviamo, siccome noi conosciamo qual è la funzione di transizione della macchina N a partire dalla funzione di transizione della macchina N di Napoli, stiamo producendo il programma della macchina M, quindi noi mentre progettiamo la macchina M noi lo sappiamo com'è fatta la funzione di transizione o la più precisamente la relazione di transizione di n. Quindi quella cosa la possiamo sfruttare. Ok? Quindi come prima cosa questa macchina scrive la macchina M scrive sul primo nastro ID0, cioè la configurazione iniziale. Ok? ci mette un bell'asterisco qua, dopodiché fa questo, ricopia i D0 su secondo nastro. Ok? Dopodiché come senza asterisco. Sì, sì, sì, sì. La copia asterisco è perché ci serve a separare delle cose, eh. Dopodiché qui inizia la parte trucchettosa, ok? M è una macchina che stiamo progettando a valle della conoscenza di N, quindi noi sappiamo n che cosa come si comporta, cioè quali sono i suoi possibili next step in dipendenza del simbolo che legge. Ok? Quindi, se in un particolare per la lettura di un particolare simbolo noi sappiamo che la macchina ha due possibilità, supponiamo che la relazione di transizione abbia due possibilità e questo numero due è fissato perché sta nella relazione di transizione. Eh, vi ricordo che la relazione di transizione di una macchina, cioè il suo programma è hard coded nella macchina, non è che è una cosa che cambia a tempo di computazione. Ok? Allora, se sappiamo che ha due possibilità, noi facciamo due copie di ID0 sul primo nastro ID0. Mettiamo l'asterisco ID0. Ok, chiaro? Scusa, lo sto usando solo per separare. Solo per separare. Sì, sì, sì. Quindi in gamma non lo mettiamo solo Sì, sì. fa parte di gamma. È una cosa che ci serve per separare configurazioni. Eh, quando scrivo D0 là significa che io sto scrivendo dei simboli della configurazione, cioè io mi scrivo proprio la configurazione sul nastro. Ok? Interessanto. Sì, sì, sì. Scrivo configurazione perché stiamo esplorando l'albero. Ok. Al posto dell'asterisco ci metto una bella X, così là mi segno dove sono arrivata. Ok. A quel punto che cosa faccio io? Qui mi ero fatto due copie di di zero perché sapevo che c'erano, è un esempio, eh, potevano essere tre copie, no? Se ci stanno tre passi possibili, vado a modificare le copie che ho fatto in modo da riflettere i possibili passi. Ok? Quindi questo ID0 e quest'altro ID0 verranno cambiati in maniera tale che qua c'ho ID1 primo e qua c'ho ID1 secondo. Chiaro? Fatto ciò, cancello questo. Ritorno sul primo nastro. Vado a vedere dove sta la X. sta qua, quindi vuol dire che mi devo concentrare da questo in poi e faccio la stessima cosa. La prima cosa che mi chiedo è ma non è che ID prim1' è accettante? Se accettante accetto. Senò che faccio? Lo ricopio qua e poi faccio lo stesso giochino. Siccome la funzione di transizione la conosco e so quanti possono essere i possibili next states, next configurations, vi faccio le possibili cose. Quindi qua c'ho ID, ID e ID. Ok? Capito? Quindi questi qua me ne faccio tre copie. Dopodiché queste qui le prendo e le modifico in maniera tale che siano il du primo, il D2 secondo, il D2 terzo. Ok, qua sono fuori il bordo. È chiaro? Quello è il principio? E vado avanti così. Fatto ciò, metto una X qua, così so che fin lì l'ho considerato. Cancello questo e vado avanti. Verifico questo ID primo, ID1 secondo. Mi chiedo è accettante o no? Se è accettante accetto. Se non è accettante lo copio sotto e faccio lo stesso lavoro. Ok? È chiaro? per tutti come funziona? Vi è evidente che stiamo esplorando l'albero? Ok. In che modo stiamo esplorando questo albero? Bread first. Breadf. Questa è una ricerca in ampiezza, ok? E non è a caso. Perché non facciamo una ricerca in profondità? Perché non facciamo un vero e proprio backtracking? Sì, potrebbe andare avanti più. Sì, perché se uno di questi rami è non accettante perché luppa. Se facciamo una ricerca in profondità, la macchina simulante, la macchina M, quella simula e non si ferma mai, quando magari a dei livelli più alti da un'altra parte c'era una configurazione accettante e avrebbe invece dovuto dire sì. Ok? Vedi, questa è la ragione per cui noi facciamo una ricerca in ampiezza. Facciamo la ricerca bread first per essere sicuri che noi non ci perdiamo. Perché la proprietà che noi vogliamo ottenere, un attimo, la proprietà che noi vogliamo ottenere è che m accetta se solo se n accetta. E quindi non possiamo rischiare che nella nostra simulazione ci andiamo a infognare in un branch infinito. Ok? Questa è la ragione per cui noi dobbiamo purtroppo procedere livello per livello. Al primo livello dove la macchina M trova una configurazione accettante lì si ferma e accetta. Se il computation 3n non ha configurazioni accettanti, allora nemmeno la simulazione di M accetterà. Ok? Quindi il linguaggio accettato da M è lo stesso linguaggio accettato da N. Ok? Prego. E se invece sono una strutturazione finale, ma non accettante, cioè il fatto che io ho voglia di non accettare quando n accetta è la stessa cosa, cioè nel momento in cui si arriva a una ID arriviamo lì, questa configurazione è accettante. Ah, è accettante. No, la ricopio sotto. Poi vi dico quali sono i next state, nessuno. finisce là, vado avanti. Quindi in coda io non aggiungo nient'altro. A un certo punto questa coda si esaurisce, non avrò lasciato nulla in coda e lì mi fermo in uno stato non accettante. Ok, chiaro? Ok. La domanda ora per noi è quanto costa questa simulazione? Ok? Perché quando abbiamo simulato con un nastro solo le macchine multinastro avevamo che il costo era all'incirca quadratico. Ok? Ma quanto costa simulare una macchina non deterministica? Ok. Ora, dopo un passo della macchina non deterministica, a che livello siamo nel computation 3? Mh, contiamo la radice zer quindi quello là non ci siamo mossi. Dopo un passo, a che livello siamo nel computation 3? Siamo a livello uno e dopo due passi a livello due e dopo tre passi a livello 3, dopo Lsiello N. Ok? Però quest'albero nel frattempo cresce e cresce e cresce. Ok? Nella peggiore delle ipotesi noi abbiamo un branching factor uguale su ogni configurazione. Ok? Supponiamo che la funzione di transizione per m n abbia, che ne so, m No, abbia C, chiamiamolo C, senò si confonde con l'altro M. Ok? Abbia C figli. Ok? Se vogliamo simulare n passi della macchina di touring non deterministica, dovremmo esplorare n livelli di questo albero di computazione. Quanti sono le configurazioni in questi n livelli? possibile m² o m³? No, attenzione, sono molte di più. Eh, n Allora, noi ci stiamo scendendo di ragioniamoci assieme. Primo livello, ok? Al primo livello c'abbiamo i di 0, ok? È chiaro? Alo zereso livello c'abbiamo il di0. Al primo livello quanti figli ce ne abbiamo? C Ognuno di Andiamo al secondo livello. Ognuno di questi c figli di primo livello, quanti sottofigli avranno? C. Quanti quindi figli abbiamo al secondo livello? C alla seconda. C alla seconda e al terzo livello? c alla terza e al quarto livello c alla quarta e all'ennesimo livello c^ n. La macchina deterministica per simulare la macchina non deterministica ha una crescita di tempo di esecuzione di O * C^ N. C a la M. Ok? C è una costante, può essere 2, può essere 3, può essere 1000. Quindi questa è una funzione polinomiale, no? È una funzione esponenziale, ok? Perché n, il numero dei passi che è legato, insomma, alla taglia dell'input e compare all'esponente. Ok? Quindi, che cosa abbiamo? Abbiamo che una macchina non deterministica, il linguaggio accettato, qualsiasi sia un linguaggio accettato da una macchina non deterministica, può essere accettato da una macchina deterministica, il che questo ci toglie le patate dal fuoco perché fino a quando siamo interessati a stabilire dire se un certo problema sia risolvibile o meno e non ci interessa sapere se efficientemente o no, ma siamo all'inizio semplicemente interessati a stabilire, ma questo problema io sono interessato a capire, ma si risolve o non si risolve siccome tutto quello che è risolvibile, decidibile, accettabili da macchine non deterministiche e anche accettabili da macchine deterministiche Allora, per stabilire se un certo problema, un certo linguaggio può essere accettato in generale, cioè se ammette un algoritmo per la sua soluzione, quello che posso fare è vedere se ci sta un algoritmo non deterministico, perché perché è più facile, perché noi abbiamo a valle di questo teorema la garanzia che se lo so risolvere in maniera non deterministica esisterà sicuramente anche un modo deterministico per risolverlo, ok? E se non lo so risolvere con una macchina non deterministica, può essere risolto da una macchina deterministica, ma qua non lo sappiamo. Qui iniziamo a muoverci in un reame di una cosa che affronteremo fra qualche minuto. Quello che voglio sottolineare prima è questa cosa del costo della simulazione. Ok? Noi abbiamo che il costo di questa simulazione, quindi se noi abbiamo che un certo linguaggio è accettato da una macchina di Touring non deterministica, noi lo possiamo accettare tramite una macchina in touring deterministica. Ragazzi, quando io parlo di macchine di Touring, voi pensate algoritmo non deterministico, algoritmo deterministico, perché al finale quello è. Vedremo che le macchie di di tuning sono compiute. Tra qualche lezione vedremo che hanno il potere dei computer allora se noi riusciamo ad accettare un certo problema, a decidere un certo problema tramite una macchina di due non deterministica, questo teorema ci garantisce che riusciamo a fare la stessa cosa, riusciamo ad accettare lo stesso linguaggio tramite una macchina detistica. La pearità della macchina deterministica è che è fisicamente costruibile, ok? Quindi possiamo costruire un device fisico che esiste che è in grado di risolvere la cosa. Ok? Questo teorema però ci dice anche che il costo della simulazione è di tipo esponenziale. Significa che una macchina deterministica in linea di principio è molto ma molto più lenta di una macchina non deterministica, ok? Cioè c'è un gap esponenziale qua. Non stiamo parlando come la traduzione da multinastro a monastro nel quale abbiamo un gap di tipo poligoniale e il quadrato finisce là. No, qui il g è veramente enorme. Ci stiamo spostando di classe, stiamo andando da un polinomio, ad esempio, a un esponenziale. Oppure se la macchina di non deterministica ci metteva tempo esponenziale, la macchina deterministica simulandola ci mette doppio esponenziale, che sono funzioni che crescono velocissime. Ok? Allora, la domanda che io vi faccio è: esiste o no un modo più furbo di questo di quello che abbiamo visto per simulare il funzionamento della macchina non deterministica? È chiara la domanda? Cioè, noi abbiamo visto che la macchina non deterministica si può simulare in questo modo e che questo modo ci possa esponenziale. Ma abbiamo un modo migliore di questo? C probabilmente dipende dal problema, cioè se fosse un problema in cui una macchina diistica può dipendere dal problema, sì, ma in generale supponiamo, no, che sono di quei problemi proprio tosti, no? Abbiamo un modo migliore di simularla in generale, no? Ok. Altri avevo visto altre mani? Sì. avreiuto quasi un Luca Ed, cioè NCO non si taglia più di tanto in quel modo, ma abbiamo alcuni in generale no, quello non taglia un granché. Allora, questa è il fatto che questa simulazione che abbiamo visto ora, costi esponenziali, ci garantisce che non esistono simulazioni più veloci? No. Ok, questo è uno dei problemi fondamentali dell'informatica teorica che aperto da 80 anni, probabilmente nessuno lo sa, nessuno sa esista una simulazione migliore di questa. Ok? In tutto questo tempo nessuno è mai riuscito a trovare una simulazione più efficiente, ma questo non significa che non esista. Però non abbiamo nemmeno una dimostrazione che una simulazione più efficiente non ci sta. Cioè, quindi da un lato noi non sappiamo meglio di non sappiamo far meglio di così, dall'altro non abbiamo nemmeno la garanzia che meglio di così non si possa fare, cioè semplicemente non si sa, nessuno lo sa, ci hanno sbattuto la testa le menti più grandi che l'informatica teorica abbia visto negli ultimi decenni e nessuno è mai riuscito a risolvere la questione. c'è un premio da 1 milione di dollari per chiunque sia in grado di risolvere questa faccenda in una qualsiasi delle direzioni. Eh, una volta vabbò questo è legato, poi lo vedremo, alle classi versus n dove focalizziamo tutto su classi polinomiali, deterministiche e non deterministiche, ok? lì poi il problema è stanziato là sopra. Però di fatto la questione fondamentale qui è ma per simulare una macchina non deterministica posso far meglio di un gap esponenziale o non posso far meglio di questo? Questa è la questione e nessuno lo sa, nessuno c'è mai riuscito né a ottenere una simulazione più efficiente né a dimostrare che non è possibile una soluzione più efficiente. Ok? Questo da un lato, scusi. Eh sì, un attimo. Posto simulazione. Eh sì, ok. Sì. Una domanda. Eh, ma se riuscismo a risolvere questo gap, siccome i computer seguono comunque un determinismo termino, cioè avremo seguono un determinismo al momento. Sì. Eh, avremo un incremento della concezione di computer che prevetterebbero dei calcoli in maniera molto più veloce. Assolutamente. Se fossimo in grado di simulare in tempo polinomiale una computazione non deterministica, saremmo in grado di risolvere problemi sostanzialmente irrisolibili al momento che sono di un qualità utilità fantastica, che ne so, determinare la forma delle proteine tridimensionali, quello è un problema tostissimo. Se noi riuscissimo a risolvere questa cosa, una macchina non deterministica è in grado di farlo in maniera abbastanza efficiente, però il costo di quella simulazione per noi è esponenziale. Noi non siamo in grado al momento di fare questo genere di calcoli. Ma tecnologie come computer quantistici fanno colmare diciamo questo g in altra maniera? No, allora non è la mia area di ricerca, quindi non le so dire nello specifico. Qui entriamo nel reame di che cos'è efficientemente risolvibile e che cosa non è efficientemente risolvibile. Da macchine quantistiche rendono efficientemente risolvibile qualcosa un po' di più di quello che al momento per noi è efficientemente risolvibile, ma non hanno il potere delle macchine mondeteriche, perché le macchine quantistiche, che io sappia, sono comunque legate ad alcune leggi della fisica, tale per cui la computazione deve avere delle alcune proprietà fisiche specifiche che mi pare siano legate all'entropia. Quindi non è che su una macchina quantistica abbiamo una reale macchina non deterministica, cioè la computazione che può fare in maniera efficiente è di più di quello che riusciamo a fare ora, però non è quello che è efficientemente fattibile una macchina non meteristica, poi lo vedremo quando parleremo di complessità, però uso la sua domanda per muoverci agli ultimi due topic che affrontiamo prima di salutare. oggi che è questo. Ma allora che cosa è in grado di fare una macchina quantistica? Che cosa è in grado di fare una macchina non detergentistica? Quindi abbiamo visto macchine m abbiamo visto macchine multitraccia e le macchine multitraccia non erano più potenti delle macchine standard. Abbiamo viste macchine multinast, quando dico più potenti, qui intendo che sono in grado di calcolare cose incalcolabili dagli altre, ok? A parte l'ospidità, qua stiamo parlando sola solo di feible feasible, ok? Quindi le macchine multitraccia non sanno fare che cosa delle macchine standard. Poi ci siamo spostati sulle macchine multinastro e abbiamo visto che le macchine multinastro non sono in grado di fare più cose delle macchine standard. Possono essere più veloci, però fanno sanno fare le stesse cose. Ora stiamo guardando le macchine non deterministiche. Le macchine non deterministiche sanno fare più cose nelle macchine standard? No, abbiamo appena visto che sì, possono essere più veloci, ma sanno fare le stesse cose. Macchine quantistiche. Le macchine quantistiche possono fare cose più cose delle macchine standard? Ve lo dico io, no? Non sono in grado di fare cose più cose delle macchine di standard. Ma allora che sta succedendo qua? Noi stiamo aggiungendo orpelli su orpelli ai nostri modelli di calcolo L multi moltiracce, L multilastro e eh il noneterminismo, ma non siamo al momento in grado di schiodarci da quello che è in grado di fare una macchina di turn. E qui ci andiamo proprio a posizionare al limite della calcolabilità. A parte questi modelli, altri modelli di calcolo erano noti negli anni 30, cioè le macchine di Turing sono cose venute fuori negli anni 30 per riuscire a risolvere alcune questioni provenienti dal mondo della matematica e a quel tempo c'erano altri modelli di calcolo, c'erano i sistemi di post, si chiamano i lamp da calcolo, eccetera, eppure quelli sono equivalenti a macchine di touring. Quello che si può fare con il lamb da calcolo si fa anche con macchine di touring standard. Quello che si fa con i sistemi di post si fa anche con macchine di touring standard. Di conseguenza la gente ha iniziato a pensare che tutto quello che è possibile calcolare su quell'estaterra è calcolabile da macchine di touring standard. E questa è la tesi di chargeing. Tesi di charge com così. Tesi di Charchy George era Alonso Charch matematico che era l'advisor di dottorato di Alan. Quindi cè tesi di charge theoring è molto semplice. Tutto ciò che è calcolabile è calcolabile da una macchina diing. Ok? Chiara? Tesì. Tutto ciò che è calcolabile è calcolabile da una macchina doing aggiungerei standard, eh, perché abbiamo visto che tutto si riconduce alle macchine standard. Sì, tutto sono standard, cioè sono anche macchine non standard oppure sono tutte tutte le cose che la gente si è inventata non è più potente delle macchine diing monastro deterministica. Nessuno è mai riuscito a inventarsi niente, né a costruire un aggeggio che abbia un potere di calcolo che vada oltre quello di una macchina di deterministica monopast. Da cui hanno iniziato a pensare "Ma vuoi vedere che tutto ciò che è calcolabile si può calcolare sulla maturing normale? Perché la chiamiamo tesi di charge Touring e non teorema di charge touring? Perché purtroppo questa affermazione è un po' self preferencia, ok? Perché non è che stiamo specificando che cos'è calcolabile, non è che noi stiamo definendo la calcolabilità di una funzione o di un problema a prescindere e poi diciamo le macchine di Touring sanno fare quello, no? Stiamo dicendo che ciò che è calcolabile è quello che si calcola tramite macchine, però al momento nessuno è mai riuscito a trovare qualcosa che sia più potente delle macchining, quindi riteniamo che questa cosa sia vera. Ok? E quindi per le domande che ci facevamo all'inizio, no, alle primissime versioni, ma è possibile che da qualche altra parte dell'universo gli alieni abbiano delle macchine di calcolo che facciano cose che le nostre non sanno fare? Per quello che noi riteniamo loro è così, cioè tutto ciò che è calcolabile si calcola con questo con questi modelli. Ok? A questo punto possiamo introdurre e con questo concludiamo due classi di calcolabilità. Ok? Classi di calcolabilità. Ok. Cos'è una classe, in questo caso di calcolabilità? Poi vedremo le classi di complessità. Una classe di calcolabilità è semplicemente un insieme di linguaggi, ok? e un insieme di linguaggi e in particolare ne identifichiamo due. Questa classe qua fuori che denotiamo R è E adesso vi dico che cos'è e questa classe è qua dentro che denotiamo R. La classe, partiamo da quella dentro che è la più semplice, la classe R si chiama R perché là dentro ci stanno i linguaggi o le funzioni ricorsive. Uno potrebbe chiedersi, ma perché mai ricorsive? Perché quando agli albori di questa scienza le persone si occupavano di che cosa fosse calcolabile e che cosa non fosse calcolabile, a quel tempo si riteneva calcolabile ciò che era esprimibile tramite funzioni ricorsive. Quindi il nome viene da lì, è rimasto per questioni storiche, ok? Quindi la classe R, che è la classe dei problemi o dei linguaggi ricorsivi, contiene tutti quei linguaggi per i quali esiste una macchina di Touring che li decide. Ok? Quindi in R ci stanno tutti quei linguaggi per i quali noi possiamo progettare a questo punto macchine di touring non deterministiche, visto che possiamo giocarcela. Però se noi abbiamo macchine di touring, che siano deterministiche, che siano non deterministiche, per noi non fa molta differenza dopo quello che abbiamo visto stamattina. Quindi un linguaggio L sta dentro R. Se esiste una macchina di Touring qualsiasi che lo decide e vi ricordo che una macchina di Touring decide un certo linguaggio L se si arresta ogni volta e ci risponde o sì o no. Ok? Quindi questi sono i ricorsi. R è un sovrainsieme di Redinsieme dei linguaggi o problemi, problemi di decisione. Eh, quando parliamo di linguaggi e problemi, qua ci stiamo riferendo ai problemi di decisione, eh. Il linguaggio re e il lingu e sì, la classe re è la classe dei linguaggi ricorsivamente enumerabili, si chiama così, sempre per ragioni storiche, enumerabili, ricorsivamente enumerabili ed è l'insieme di tutti i linguaggi. Ho problemi di decisione per i quali esiste una macchina di touring di qualsiasi tipo che li accetti. È chiaro? qualche altra nomenclatura e poi chiudiamo. Quindi R sono i problemi che possono essere decisi da qualche macchina di Touring o linguaggi che possono essere decisi da qualche macchina di Touring e reinguaggi che possono essere accettati da qualche macchina di Turing. Vi ricordo la differenza. Eh, accettati significa che rispondiamo sì in tempo finito. Per il no non diamo garanzie, ok? Però non possiamo dire minchiate, nel senso che se la risposta è no, non è che ci fermiamo e diciamo sì, se la risposta è no, o ci fermiamo e rispondiamo no o non ci fermiamo proprio. Ok? La risposta sbagliata non è contemplata. Siccome R è l'insieme dei linguaggi decisi dalle macchine di Touring, noi chiamiamo i linguaggi in R anche i linguaggi o i problemi decidibili per ragioni ovvie. Quello che non sta in R lo chiamiamo indecciibile. Ok? Quindi qualcosa che sta in re ma non in R per noi è indecidibile. Perché è indecidibile? Perché se non c'è un algoritmo che ci dia garanzia di risposta nel caso di risposta negativa è un po' un problema per noi perché se noi gli diamo un input a questo algoritmo, questo inizia a girare, passano 10 giorni e non ci ha ancora dato risposta, che facciamo? Aspettiamo la risposta, ma la risposta potrebbe non arrivare, ok? E quindi siamo lasciati in un limbo per i problemi in R e ma non in R che se la risposta tarda ad arrivare noi non sappiamo che farci con quella cosa. Se invece il linguaggio è decidibile e la macchina du mesi non ha risposto, noi siamo sicuri che prima o poi sta risposta arriva. Ok? Sui problemi non in R questa garanzia non ce l'abbiamo. Ecco perché i problemi fuori da R li chiamiamo indecisibili. A volte introduciamo una differenziazione e chiamiamo linguaggi re che non sono in R, li chiamiamo semidecidibili, giusto per dare un po' di differenziazione, ma sempre indecidis. Ok? Quali sono? Quelli in re che non stanno in R. quelli in R che non stanno in R noi li chiamiamo anche semidecidibili, però i semidecidibili hanno questo problema che l'algoritmo non avendo garanzia di terminazione per noi non è che sia proprio utile, eh cioè perché non sappiamo che farci quando la risposta tarda ad arrivare quella potrebbe non arrivare mai. Quindi e che facciamo? Aspettiamo ancora. Chiaro? No, ma quindi quelli indecidibili sono fuori che stanno in R e non in R perché stanno fuori? No, in R ci stanno indecidibili. Quello che non è in R è indecisibile. Quello che non è in R, ma è in re, qualcuno li chiama semidecciibili, ma sempre problemi un po' rognosi sono, cioè è molto meglio che i nostri problemi siano decidibili, cioè nel senso che st'algoritmo prima o poi si arresta e ci dà la risposta. Ok? Chiaro per tutti? E con questo per oggi chiudiamo. Buona serata.