Ok. Ok. [Musica] Ok. Quello che vedremo oggi sono un po' di eh sprills di optionals che si possono aggiungere a macchine di touring, perché le macchine di touring che abbiamo visto finora sono molto semplici da trattare, molto semplici da definire, però sono difficili da programmare perché, insomma, abbiamo visto è un gran casino. Quello che vedremo oggi sono delle varianti di macchine touring che scopriremo essere equivalenti a quello che abbiamo visto. Ok? Eh, allora consiglio su come studiare, almeno anche torno alla cosa che potreste fare, quindi facciamo un recapissimo stamattina al termine delle lezioni o comunque quando vi rivedete gli appunti cercate di estrapolarvi le domande chiave di quello che abbiamo visto. Ok? Ok. Ma quello che abbiamo spiegato oggi a cosa sta rispondendo? Questa è la cosa è lo stesso gruppo di quilibri, ma questo paragrafo a cosa sta rispondendo? Quindi proviamo a vedere che concetto abbiamo visto finora. Abbiamo visto problemi. Cos'è un problema? Di cosa è caratterizzato un problema? Che cos sono i problemi delle di ricerca? Che sono i problemi di decisione? Qual è il loro rapporto? Che c'entrano i linguaggi con i problemi di decisione? Perché usiamo i linguaggi? Cos'è una macchina di touring? Com'è definita? Qual è la condizione di accettazione per una macchina di touring? Ok, cioè queste sono possibili domande. Che significa che una macchina di Touring decide un linguaggio? Che significa che una macchina di Touring accetta un linguaggio? Che differenza ci sta? Ok, questo, per esempio, sono un po' di cose che abbiamo visto finora. Ok? E quello che introdurremo oggi, quindi, abbiamo delle varianti di macchine. Delle varianti di macchine. Allora, riprendiamo un esercizio che abbiamo visto ieri che era che succido, ok? che era quello VRR, vi ricordate tale che W appartiene a 01. Ok? Allora, chi aveva quella macchina? Quella macchina, praticamente, per come l'abbiamo progettata, il suo principio di funzionamento era becco un carattere all'inizio, vado a cercare lo stesso carattere alla fine. Quindi se leggo zero all'inizio cerco zero alla fine, se leggo uno all'inizio cerco uno alla fine. Quindi avevamo sostanzialmente due parti di macchina. Facciamo uno sketch veloce. Qua avevamo Q0 e avevamo questa parte che si gestiva la lettura dello zero e poi arrivava a un certo punto e questa parte che si gestiva la lettura dell'uno e poi tornavamo indietro. Era una cosa di questo tipo. Ok? Quindi noi avevamo necessità di due branch di computazione della macchina perché la macchina aveva necessità di ricordarsi se l'ultimo carattere, se il carattere che aveva letto all'inizio della steringa, era 0 o 1. Ok? Allora, l'idea è non sarebbe molto più bello se la macchina potesse memorizzare quello che che ha letto in maniera tale che non dobbiamo fare sto gran casino, ok? Ed è quello che facciamo ora. introduciamo un modello di macchina leggermente più sofisticato che la macchina con la memoria nello stato, ok? Cioè è una macchina [Musica] che ha come dei registri di memoria nello stato nel quale può memorizzare dei simboli, ok? Un po' come i processori che hanno i registri, assumiamo che questa macchina abbia un certo numero di registri interni. tipo certo stato O1 c'è uno spazietto. Ok? Nel quale il primo pezzo dello stato ci dice la modalità di funzionamento della macchina e poi quest'altra cosa qui, adesso vedremo come usarla. Sorry guys. [Musica] Allamo. Memoria. Memoria. Ok. Non entreremo nei dettagli delle definizioni, guarderemo giusto un po' come sta macchina funziona. Faremo un esempio di eh di utilizzo. Dopodiché vedremo che questa macchina non aggiunge niente a quello che abbiamo già visto. Ok? Però siccome poi saranno equivalenti, possiamo assumere di poter demonizzare roba, ok? per semplificarci il nostro lavoro. Prima detto, assignamo che la macchina non c'è il tuo di stati di stati e nello stato la macchina può memorizzare delle informazioni, può memorizzare i singoli, ok? Come se avesse delle cellette di memoria insieme nel suo nella fine controllo nel suo nella sua funzione di transizione, cioè nel processore, diciamo, della macchina. È come se la macchina avesse delle cellette di memoria. Ok? Queste cellette possono memorizzare, ogni cella può memorizzare un simbolo soltanto, un simbolo di nastro. Ok? Quante celle può avere la memoria? Per esempio, in questo caso noi potremmo definire, che ne so, uno stato così in cui abbiamo che Q1 è la modalità di funzionamento della macchina e questo spazio qui e che cosa sta memorizzando in quel momento. Con questa notazione noi intendiamo che la macchina può memorizzare un simbolo soltanto. Ok? Quanti simboli può memorizzare la macchina? Ne può memorizzare uno, ne può memorizzare due, ne può memorizzare 10, 100000, ne può memorizzare quanti ne vogliamo. La caratteristica è che il numero di simboli, cioè quanti registri, quanto spazio ha la macchina nello stato per memorizzare, viene deciso al momento della progettazione. Ok? Cioè la memoria non cresce durante l'esecuzione. Non è che la macchina mentre esegue "Oh, dai, qua mi serve più memoria, me la espando." Ok, la memoria è fissata. È fissata nel progetto della macchina non cambia. Nel momento in cui diciamo che ci stanno 10 celle di memoria, 10 celle ci stanno, non più di quelle si possono usare. Ok, chiaro questo? Please, se non siete interessate lasciate seguire i vostri commenti. Allora, come sfruttiamo questa cosa? Supponiamo di voler riconoscere questo linguaggio qui. Cioè, e questa qui è un'espressione regolare, no? linguaggio descritto tramite espressione regolare. Noi vogliamo riconoscere le stringhe binarie che iniziano con un simbolo e tutti gli altri sono differenti, quindi è 1 seguito da zeri o è 0 seguito da 1. Ok? Da uni. Alrght allora quello che noi sostanzialmente facciamo, giusto per vedere come funziona questa macchina è che noi leggiamo il primo simbolo, lo mettiamo nel registro, ok? Dopodiché ci aspettiamo di leggere cose diverse da quello che è in memoria. Tutto qua? Ok? Quindi velocemente noi possiamo descrivere questa cosa così. Q0 blan. Questo è lo stato iniziale che ci dice che iniziamo in q0, abbiamo una cella di memoria e all'inizio nella memoria non ci sta niente, cioè il simbolo vuoto. Ok? Dopodiché leggiamo dopodiché leggiamo il primo carattere e lo induiamo in memoria. Questa cosa la scriviamo così: leggo un generico carattere alfa, lascio lo stesso carattere sul nastro e vado avanti. Ok. Come scrivo che lo memorizzo. Si scrive così: transisco in uno stato Q1 e nella cella di memoria metto alfa che è quello che abbiamo letto prima. Ok? Quindi siamo in Q0, in memoria non ci sta niente. Leggiamo un carattere alfa, un simbolo alfa, dove alfa è generico. Alfa è un simbolo generico che appartiene a 0 1. Ok? Leggo alfa, lascio alfa, vado avanti e alfa lo metto nella memoria disponibile. Ok? Fatto quello, sostanzialmente devo saltare, devo ciclare cose diverse da alfa. Possiamo scrivere una cosa del tipo alfa soprasegnato o alfa negato per dire che è il contrario di alfa. Quindi mi aspetto alfa negato, vado avanti e salto tutto. Ok? Elementi in alfa però bene un elemento alfa. ripetere se fosse alfa avessenti sempre lo so. No, 0 1 e 2. Ah, ok, ho capito. Eh, questo dire potrebbe essere 1 e 2. Se fossero Sì, possiamo scrivere se alfa, come il nostro collega ci suggerisce è 0 1 2, noi potremmo definire un simbolo beta, ok? e poi stabilire che beta che beta è diverso da alfa. Ok? Basta che lo scriviamo che cosa intendiamo e ne va bene. Ok? Cioè deve essere chiaro. Adesso, siccome i simboli di Aon due, mettiamo alfa. Eh, così avremmo potuto scrivere beta con beta che appartiene a 01 e beta diverso l'alfa. È la stessima cosa. Ok? Dopodiché quand'è che ci accorgiamo che abbiamo finito? Quando arriviamo al blend, ok? Blan blan e andiamo avanti. Andiamo nello stato Q2 in cui nella memoria non ci serve più niente. Ok? E a quel punto accettiamo. Ok? È chiaro? Come funziona? Funziona il principio? La definizione richiederebbe il fatto di stabilire stati aggiuntivi eccetera. Non la guardiamo, non ci interessa. Ok? Vogliamo solo vedere come funziona, perché quello a cui noi puntiamo è la macchina che vedremo dopo la base. Stiamo adesso costruendo dei pezzi intermedi per arrivare fin. Ok. Allora, secondo voi questa macchina che può memorizzare l'oppa è più potente? Quando quando dico più potente intendo è in grado di accettare i linguaggi che macchine standard non sono in grado di accettare? Sì. No, che per sì, che per no. Ok. Perché no? che questa cosa della memoria è una cosa sintattica tra virgolette per evitare indicazione. Sì, perché sostanzialmente questa questa descrizione qui questa descrizione qua è semplicemente un modo compatto, ok? di scrivere una macchina più grossa che è sostanzialmente questa qua. Sono in Q0 e non c'ho niente. Ok, leggo 0, lascio 0, vado avanti e vado in Q1,0. Oppure leggo 1, lascio 1 e vado avanti e vado in Q1,1. Poi qui salto i zeri, qui salito gli uni e dopodiché se leggo bianco lascio bianco per vado avanti in entrambi i casi e vado in uno stato accelente V2 bianco. Ok? Cioè, sostanzialmente noi stiamo scrivendo in modo compatto questa macchina qua. Di fatto gli stati di una macchina con memoria nello stato sono gli stati che sono ottenibili tramite il prodotto cartesiano del simbolo di stato e i possibili simboli gamma. Ok? Cioè noi basta che diamo nomi diversi a questo, questo, questo e questo e fatto? Cioè il fatto di avere coppia, stato simbolo è un modo di dare nomi a stati. Questo si poteva chiamare Gigi, Luto, Paperino e Topolino. Ok, prego. Prima ha citato una macchina standard macchina di Turing, quella che abbiamo visto. Sì, ieri. Ahah. Ok. Quindi quello che abbiamo visto finora è una macchina che pare sappia memorizzare, in realtà è semplicemente un modo convenient per noi per pensare che stiamo memorizzando cosa negli stati. è semplicemente un modo per scrivere in maniera compatte macchine e quello e questo tipo di macchine sono riscrivibili macchine standard nel quale semplicemente incrementiamo il numero degli stati e gli stati gli diamo il nome stato simbolo. Ok? Questo lo potevamo chiamare 0 1 2 e 3 e alla fine è la stessa cosa. Ok? Tutto qua. Quindi questo ci semplifica la scrittura delle macchine, però non ci dà più potere. Ok. Alright. Introduciamo ora un altro modello che è il modello della macchina multitraccia. macchine multitracce. Allora, chi sono le macchine multitracce? Di nuovo sono un trucchettino che ci inventiamo per riuscire a gestire più cose contemporaneamente, ok? E semplificarci la la il design di macchine di Ok? Allora, le macchine multitraccia sono macchine che hanno un nastro e questo nastro è diviso in più traccia. Ok? Facciamo un esempino. Quindi abbiamo una macchina con un nastro bello grosso e sul nastro si possono scrivere più simboli inonati. Ok. Quindi, per esempio, abbiamo X, Y a B. Ok? Quindi abbiamo un nastro diviso in più tracce. Sono come le corsie della strada, no? Le corsie dell'autostrada che in autostrada ci stanno 3 4 sette corsie, ok? Non so se siete stati a Las Vegas, c'è l'autostrada di sette corsie che dentro la città. Divertentissimo guidarci. Allora, è tipo quello. Il nastro è come la strada e abbiamo più corsie sul nastro. Ok. Abbiamo una testina bella grossa che è in grado di leggere tutte le corsie, tutte le tracce. Ok? Quindi il nastro è diviso orizzontalmente in tracce. Ogni traccia su ogni cella può contenere un simbolo che non è non è necessariamente legato agli altri. Ok? Abbiamo una testina bella grossa che è in grado di leggere il nastro. Ok? Pecculiarità della testina è che la testina è una. Ok? E quando la spostiamo da un lato o dall'altro, la testina si sposta come monoblocco, ok? Quindi si sposta di una cella e va a leggere tutte le tracce dell'altra cella, ok? Non è che la possiamo piegare o fare cose strane, ok? La testina è un unico blocco, questa tipa si sposta avanti e indietro e si sposta tutta assieme. Ok? Come definiamo il funzionamento della macchina? cioè come programmiamo la funzione di transizione di questa macchina. È una cosa molto simile alle macchine standard e funziona così. La funzione di transizione è determinata da tutti i simboli che vedo su tutte le tracce, ok? Quindi, ad esempio, se io ho due tracce, no? E supponiamo di avere un alfabeto. Scriviamo, supponiamo di avere due tracce. Ok, quindi abbiamo due tracce. Su queste tracce ci possono apparire simboli e la testina legge 0 1 o 1 1. Questi sono due casi distritti per la macchina. Quindi se sono in uno stato Q leggere 01 e leggere 1 per la macchina è una cosa diversa. Ok? Quindi la macchina che fa? Guarda tutti i simboli su tutte le tracce per stabilire che fare. E che cosa può fare la macchina? Può sovrascrivere tutti i simboli di tutte le tracce con i simboli che vuole. Cioè può scrivere una cosa sulla prima traccia, una cosa sulla seconda. Ok? E poi sposta l'unica testina o a destra o a sinistra. Ok? Vi ripeto, la testina non si smonta, non è che andiamo sulla prima traccia da un lato e sull'altra da un altro lato, cioè la testina si piglia e si sposta a blocco. Ok. Sì, ma le singole tracce possono muoversi eh a velocità diverse? No, la traccia tu eh voi non l'avete mai visto un registratore multitraccia, cioè abbiamo un nastro che negli anni 60 quando si andava gli studio li ho visti, però quando si registrava la musica ora ci stanno no digital audio water station quando si fa la registrazione multitraccia della musica e mi servono più tracce degli strumenti, si hanno vari file. Quando non si facevano ste cose, come si faceva? Si usava un nastro magnetico bello grosso, che era diviso in pezzettini, in tracce. Nella prima traccia ci stava il cantato, nella seconda traccia ci stava la batteria, eccetera. Ok? Però la testina era una sola, quindi andava tutto alla stessa velocità perché sto nastro scorreva e la testina leggeva le tracce differenti. Dopodiché uno potrà decidere: "Ok, adesso cancello la voce perché è uscita male" e ci sopra scrivevano sopra, ok? solo su un pezzettino del nastro. Quindi la traccia è una cosa del nastro, cioè il nastro è caratterizzato da queste linee, diciamo. Quindi quando la testina si sposta si sposta sopra il nastro e la traccia non è che io posso, come si dice in italiana, che non schiudo, ma non le posso fare cose strane, ok? Si sposta sempre assieme, ok? e solidare. Poi vedremo dopo la pausa un modello più sofisticato ancora, ok? Chiaro? Quindi proviamo a fare un esempio di utilizzo di una macchina del genere. Ok? Allora, vogliamo riconoscere il linguaggio L. W che è un altro degli esempi tale che W appartieno a o P plus. Ok? Questo è l'ultimo esercizio che abbiamo visto ieri. Adesso utilizziamo una macchina multitraccia per vedere come si può si può fare. La prima traccia. Noi supponiamo che sulla prima traccia ci sia l'input, ok? Sulla prima traccia del nastro, all'accensione della macchina c'è l'input. Le altre tracce all'accensione sono tutte vuote, se c'è blan o. Ok? Adesso il principio di funzionamento della macchina che vediamo ora non è molto differente da quello che abbiamo visto ieri, però mi serve perché poi lo sfrutteremo per una cosa che facciamo dopo la pausa. Ok? Allora, tra i 1000 modi di nuovo, cioè non è che stiamo facendo una cosa molto differente da quella che abbiamo visto ieri, ok? Tra i 1000 modi in cui possiamo progettare una macchina multitraccia per il riconoscimento di questa macchina di questo linguaggio, c'è quello in cui noi abbiamo la testina, la partenza. Sostanzialmente noi dobbiamo matchare il simbolo iniziale col simbolo finale. Sfrutteremo il fatto che possiamo memorizzare roba nello stato e il fatto che possiamo scrivere su più tracce. Ok? Allora, l'idea è questa. Leggo il primo simbolo, metto un marcatore qua per ricordarmi che è il simbolo che ho letto e quel simbolo me lo metto costato, me lo memorizzo. Dopodiché vado in fondo, cerco il primo simbolo non marcato sulla seconda traccia e verifico che è uguale a quello che ho memoria. Dopodiché torno indietro. Ok? Questo è il principio di funzionamento. Non è molto dissimile da quello che abbiamo fatto. Ok. Alri. Quindi partiamo da Q0. Eh, non abbiamo niente in memoria. Allora, scriviamo così. ci dobbiamo inventare una notazione. Qualsiasi notazione. Va bene, adesso la scriviamo. Tanto le macchine multitraccia non le useremo un granché, eh. Ci serve solo, come vi ho detto, come passaggio intermedio per arrivare alla macchina che facciamo al giro di dopo. Ok? Quindi uso questa notazione qua. Parentesi graffa. Leggo un carattere alfa sul primo sulla prima traccia. Leggo blanco sulla seconda traccia. Chiudo la parentesi grave al quadra. Quindi questo è quello che leggo. Quello che scrivo è sulla prima traccia lascio alfa, sulla seconda traccia metto un asterisco e vado avanti. Ok? Quindi metto fra parentesi quadra tutti i simboli che leggo sulle tracce partendo dalla prima, prima, seconda, terza, qua. Quindi andiamo in uno stato Q1 in cui abbiamo memorizzato il simbolo alfa. Ok? Alri, quindi abbiamo messo per esempio qui un asterisco, dobbiamo spostare adesso la testina in avanti, quindi dobbiamo saltare tutto quello che c'è di residuo, arrivare al cancelletto e poi arrivare a cercare il primo il primo simbolo non marcato sulla seconda traccia. Ok? La cosa positiva di utilizzare una macchina multitraccia in questo caso è che non stiamo perdendo il contenuto dell'input semmai dovessimo riutilizzarlo, ok? Perché nella macchina di ieri noi scrivevamo x sul simbolo e quello era andato, cioè l'avevamo perso. Semmai avessimo avuto necessità di rileggerlo, quello lì era perso per sempre perché l'avevamo sovrascritto. In questo caso noi stiamo lasciando l'input sulla prima traccia. Siamo dei marcatori sulla seconda. Sì. Una domanda stupida, ma come mai in questa macchina, anche nella macchina precedente, cercano registri, noi usiamo una generalizzazione dei simboli del nostro alfabeto? Cioè solo per convenzione? Solo per convenzione? Sì, sì, sì, sì. Ok. Alright. Quindi noi saltiamo tutto. Quindi su primo nastro trovo beta, su sul primo traccia trovo beta, sul secondo traccia trovo blan. Lascio beta, lascio blank e vado avanti. Ok. Come beta. Allora, che cosa abbiamo? Scriviamole da qualche parte. Scriviamolo qua. Alfa appartiene ad AB, beta appartiene ad AB e fra alfa e beta non c'è nessuna relazione. Possono essere le stesse, possono essere uguali, possono essere diverse, ok? Perché dobbiamo saltare qualsiasi cosa, ok? Slegata ad alfa. Se noi qui avessimo messo alfa, avrebbe significato che noi ci aspettiamo di trovare simboli uguali a quello che ci sta in memoria. Ok? Siccome noi vogliamo slegare questi simboli dalla memoria, usiamo due nomi diversi. Ok? Quindi salto tutto. Poi a un certo punto, quindi stiamo saltando tutto quello che ci sta qui. A un certo punto arriviamo al cancelletto. Quindi sulla prima traccia leggo cancelletto. Sulla seconda lascio c'è blank. Che cosa faccio? Lascio il cancelletto lì dov'è, lascio il blank lì dov'è e vado avanti e vado in Q2 dove ancora ricordo il simbolo alfa. Ok? Quindi io alfa me lo sto portando dallo stato precedente. Ok? A questo punto noi dobbiamo andare alla ricerca qui del primo simbolo sulla destra che non sia stato marcato sulla seconda traccia. Ok? Quindi io mi salto tutti i simboli che hanno l'asterisco sotto. Vado alla ricerca del primo simbolo che in seconda traccia non c'ha assolutamente nulla. Alri, quindi prima traccia c'è B, seconda traccia ci asterisco, lascio tutto com'è e vado avanti. Qual è la condizione di uscita? Quand'è che sappiamo che ci dobbiamo fermare? Quando leggo alfa e blank. Quando leggo alfa e blend, cioè, noi ci fermiamo quando gli asterischi in seconda traccia finiscono, ok? E il primo simbolo senza l'asterisco sotto è lo stesso di quello che avevo memorizzato prima. Ok? Vado qua, quindi c'è leggo alfa e blank sul secondo sulla seconda traccia. Lascio alfa di dov'è, scrivo, asserisco sulla seconda traccia e torno indietro e vado in Q3 dove non ho più bisogno di ricordarmi il simbolo, quindi cancello la memoria. Adesso noi dobbiamo andare riavvolgere tutto tutto. Quindi, stiamo tornando qui indietro. Questi qua che noi incontreremo saranno stati tutti marcati e quindi c'è sul primo leggo alfa, sul secondo leggo asterisco, lascio alfa lì dov'è, lascio l'asterisco lì dov'è e vado indietro. A un certo punto arriverò al cancelletto. Quindi cancelletto su prima traccia, blank su seconda traccia, lascio tutto lì com'è e vado dietro. E siamo in Q4. Q4 dove non memorizziamo niente. Chiaro che stiamo facendo? Stiamo semplicemente andando indietro. Ok? Arriviamo al cancelletto. A quel punto, una volta che superiamo il cancelletto, arriviamo in questa zona qui e dobbiamo andare alla ricerca del primo simbolo non marcato da unas asterismo, ok? Cioè è esattamente quello che abbiamo fatto la scorsa volta. Ok? Vado un po' veloce perché dobbiamo fare un po' di commenti su questa cosa qua. Allora, questa cosa la spezziamo in due per una ragione che vi risulterà evidente fra un attimo. Quindi abbiamo appena superato il cancelletto, quindi eravamo qua e ci siamo spostati qui. e c'è alfa su prima traccia, blank su seconda traccia. Lascio tutto così com'è alfa blank e mi sposto dietro. Lo scrivo così perché mi serve per Q5 e non memorizzo niente. Dopodiché salto tutti i caratteri alfa blank alfa blank e vado dietro. Dopodiché quando arrivo al simbolo alla all'asterisco so che posso ripartire alfa asterisco e vado avanti. Ok. Allora, questa parte di macchina semplicemente si occupa di leggo un carattere, lo marco, con l'asterisco, lo memorizzo, vado in fondo, mi cerco la prima cosa non marcata, verifico che è la stessa cosa che abbiamo letto all'inizio, torno indietro, quindi mi devo superare prima le cose marcate a destra, poi supero il cancelletto, poi le cose non marcate a sinistra, fino a quando trovo qualcosa di marcato e so che il carattere che mi serve è il primo sulla destra e sposto avanti. e riparto. Ta ta ta. Ok. Quand'è che sappiamo che possiamo fermarci e andare verso un check di accettazione? Quando Sì, quando in questa fase qua, superando il cancelletto nel movimento di ritorno nel carattere dietro, invece di leggere alfa e blank, leggo alfa e asterisco. A quel punto so che ho finito e me ne esco. Ok? Ecco perché ho diviso gli stati. Quindi vado di qua, c'è alfa asterisco, lascio alfa asterisco e vado avanti. E siamo in Q6. Q6 blend. Dopodiché c'è il cancelletto, no, il cancelletto da superare. Complet sulla seconda traccia e vado avanti e sono in Q7. Dopodiché devo saltare che cosa? Tutti i simboli che stanno qua e mi aspetto che siano tutti marcati. Quindi, che c'ho? alfa, asterisco, lascio tutto così com'è e vado avanti. Quand'è che mi posso fermare? Guardate il filmato che succede a un certo punto se è quello blank blank blank blank, mi fermo quando su prima traccia c'è blank, su seconda traccia c'è blank, lascio tutto così com'è. e vado in quotto e accetto. Chiaro per tutti? Ok, ci siete? Perché ora dobbiamo fare un po' di considerazioni prima della pausa perché poi sfrutteremo questo modello per fare un passaggio ex. È chiaro come funziona questa macchina? Cioè, non è molto più sofisticata di quello che facevamo. La differenza è che memorizziamo nello Stato, però abbiamo già detto che memorizzare nello Stato non comporta niente di fantascientifico, si tratta solamente di replicare stati e sfruttiamo la multitraccia. La peculiarità è che possiamo non toccare la traccia dell'input, cioè quindi se per linguaggi più sofisticati a noi l'input serve due volte, ok? Quello ci torna comodo perché le marcature noi le mettiamo sulla seconda traccia, quindi abbiamo più spazio, possiamo fare più cose sostanzialmente. La mia domanda adesso è: una macchina multitraccia è in grado di riconoscere i linguaggi che una macchina monotraccia non è in grado di fare? Pensiamoci un pochino. Mh mh. Vendo di noi per il fatto che alla fine possiamo replicare la session tipo ragionamento col discorso la multitraccia. usiamo un simbolo aggiuntivo nel dove eh nella comunque nella macchina standard. Che simbolo vorreste vorreste aggiungere? Per fare l'esempio in questo caso mi viene da dire m per esempio noi comunque segniamo soltanto m le A B a tilde B tilde e che equivale a questo discorso contatto perché alla fine abbiamo la prima tr se c'è la stistol Ok. Ok, questo è esattamente la l'idea. Allora, ci sono un paio di modi per fare la cosa, ok? In cui potremmo simulare una macchina multiraccia tramite una macchina monotraccia. Uno che è quello su cui si basa la prova formale che queste macchine sono equivalenti, è quello che ci sta suggerendo il nostro collega. Cioè alla fine, siccome noi abbiamo una testina che legge gruppi di simboli, noi potremmo assumere che quella, se le tracce sono K, che quella K tupla di simboli è il nome di un simbolo soltanto, no? Quindi, che ne so, noi potremmo avere altri simboli, come diceva il vostro collega, A blank lo chiamiamo solo A. A asterisco lo chiamiamo Atilde, AB lo possiamo chiamare nuvoletta, AC lo possiamo chiamare casetta. Ok? Noi aggiungiamo simboli. Noi potremmo tirare fuori un simbolo diverso per ognuna delle possibili combinazioni di simboli che la macchina potrà mai vedere sulle tracce. Ok? Quindi, nel primo caso con la memoria nello stato stiamo moltiplicando gli stati. In questo caso stiamo moltiplicando i simboli. Tutto qua. Quindi noi possiamo definire una macchina di Touring monotraccia, ok? Nella quale noi semplicemente utilizziamo un alfabeto più ricco. Un alfabeto più ricco che ci permette di simulare, ok? una eh il fatto che stiamo leggendo cose diverse su tracce diverse. Ok? Questo è un modo. Un altro modo in cui noi possiamo potremmo simulare una macchina multitraccia è che noi ricevut tramite una macchina monotraccia è questa che la macchina monotraccia riceve il proprio input. Ok? che supponiamo che la macchina M' e la macchina monotraccia e la macchina M è la macchina multitraccia. E noi vogliamo essere in grado tramite M' di riconoscere lo stesso linguaggio di M. Allora, che fa M'? m' riceve l'input che riceverebbe M. lo devo un attimo manipolare per riuscirci a a lavorare. Vi ricordo che il numero di tracce sul nastro è fissato al momento della progettazione. Possono essere cinque, possono essere 10, possono essere 1000, ma una volta che lo fissiamo è fissato, non si cambia esattamente come la memoria nello stato. Ok? Non è che la macchina dice "Oh, cavolo, questa stringa è un po' più lunga mo sai, con lo scotch ci attacco un pezzo aggiuntivo, così c'ho due tracce che mi servono." Ok, non si può fa'. Si decide all'inizio tre tracce, quattro tracce, quindi quella è una cosa fissata. Quindi quando m' deve simulare m e supponiamo che m abbia, che ne so, quattro tracce, è un esempio, eh, dico quattro perché senò dovrei dire. Supponiamo che m ha quattro tracce. Cosa fa m primo? prende il suo input e inizia a separare i simboli e mette qua tre spazi tra ognuno dei simboli. Quindi c'ho il simbolo dell'input, tre bianchi, un altro simbolo dell'input, tre bianchi, un altro s un altro simbolo dell'input, tre bianchi. E così, quindi la macchina M'O all'inizio allarga l'input, dopodiché che fa? In queste cellette aggiuntive la macchina simola il contenuto delle tracce della macchina M. Quindi ogni volta che M' deve fare deve simulare una transizione di M, m' si legge quattro simboli dal nastro, cioè l'input più il contenuto delle altre tracce. Che ci fa con sti simboli? si rimette in tre memorie dello Stato, in quattro memorie dello Stato. Noi sappiamo che si può organizzare una cosa così. Una volta che c'ha in memoria tutto fa la stessa transizione di M e poi va avanti. Ovviamente quando deve scrivere deve scrivere i gruppi di quattro, quando deve sovrascrivere deve sovrascrivere i gruppi di quattro, eccetera. Cioè, quindi questi sono due modi distinti di simulare una macchina multitraccia con tramite una macchina monotraccia, magari con uno stato nella memoria. Ok? Possiamo quindi dire che le macchine multitraccia hanno lo stesso potere delle macchine con uno stato nella memoria. Sì. No. Sì. È vero, no, che le macchine con uno stato della memoria hanno lo stesso potere delle macchine standard? Sì. Quindi possiamo concludere che le macchine multitraccia, sebbene sembrino più sofisticate, hanno lo stesso potere di calcolo delle macchine standard. Ok? Quindi ci siamo inventati questa cosa aggiuntiva, ma nemmeno questa cosa aggiuntiva è in grado di darci una macchina più potente. Lo usiamo perché sono più facili da programmare. Sfrutteremo questa cosa dopo la pausa per mettere mano su una macchina ancora più sofisticata che è quelle che poi in realtà andremo a utilizzare gran parte del tempo perché sono quelle più in assoluto facili da programmare. Ok. e facciamo un quarto d'ora di base. [Applauso] Ok, cara, per tutti come funzionano queste macchine? Memoria dello stato, macchina multitraccia, abbiamo visto che tutta roba equivalente a la macchina standard. Questo va ok. Giusto una cosa in caso fosse sfuggito. [Musica] Questo simbolo alfa che leggiamo e alfa sta per una cosa generifica fra A o B, ok? Non è che vediamo alfa. Lì intendiamo leggiamo una cosa che sia A o B, la chiamiamo alfa e alfa la mettiamo nel registro, ok? Ok, quello che facciamo ora è introdurre il modello di marketoring che concuseremo per il resto del corso che è molto molto convenient. Si chiamano macchine, Sì, come no? Macchine multi nastro. Ok? Qual è la differenza fra macchine multitraccia e macchine multinastro? La differenza fra queste due macchine è sostanziale perché una macchina multitraccia è una macchina con un nastro soltanto, mentre le macchine multinastro sono macchine che hanno più nastri completamente indipendenti. Questi nastri non sa una traps in questo caso. Sì, ma non ci serve. Ok, quindi sono macchine che hanno tanti nastri. Ogni nastro ha la propria testina indipendente. Ok? Quindi una macchina con tre nastri e una macchina che ha anche tre testine. Tre testine completamente indipendenti. Ognuna può scrivere quello che vuole. Ognuna si può muovere dove vuole. Ok? Quindi, a differenza della multitraccia, avevamo una testina grossa che andava spostata in blocco. Nelle macchine multinastro abbiamo testine indipendenti che possiamo spostare come ci piace, quindi magari una va a destra, una va a sinistra e una sta ferma. Ok? Quindi introduciamo la possibilità per le testine di una macchina multinastro di stare ferme, ok? Non è nulla di fensi perché possiamo simulare la testina ferma e in maniera tale che faccia un passaggio destra sinistra o sinistra destra. Ok? Quindi non è tutta sta gran cosa che la testina sia ferma, lo facciamo perché ci torna comodo. Ok? Allora, la cosa interessante, quindi, di queste macchine rispetto alle macchine multiccia e che noi possiamo spostare le testine a piacimento. Ok? Noi assumiamo che l'input della macchina si trovi sempre sul primo nastro all'avvio. Quando la macchina si avvia trova il proprio input sul primo nastro. Come al solito assumiamo che la testina del nastro di input sia sul simbolo più a sinistra, quindi sul primo simbolo. Gli altri nastri sono completamente vuoti. Ok. Sì, ma si può prendere l'input e di spezzarlo sui vari nastri oppure non si può fare? In che senso? Per esempio, per fare un check se una stringa è falla, magari potrebbe aver senso ore a priori dividere a metà la stringa e metterla sui due nastri giù. Sì, sì, sì, possiamo fare quello che vogliamo. Adesso, adesso lo vediamo. Ok. I nastri aggiuntivi che noi chiamiamo work tapes, cioè nastri di lavoro. Quindi il primo è input tape, il secondo, gli altri sono work tapes. Li chiamiamo così perché ci servirà poi più avanti quando parleremo di complessità. Sui work tapes possiamo fare quello che vogliamo, leggere, scrivere, spostare le testine come si vuole, ok? La cosa importante è che le testine sono completamente diendenti, cioè io le posso spostare in direzioni differenti, posso tenerne una ferma e spostare le altre, posso fare quello che voglio. Come nei casi precedenti, il numero di nastri che costituisce una macchina di Turing è deciso all'inizio. Ok? Tre nastri, tre nastri, 100 nastri, 100 nastri. Una volta che lo decidiamo al momento della progettazione questo numero di nastri non può cambiare. Non è che la macchina a un certo punto si accorge che la stringa di input è troppo lunga, dice "Ah, mi serve più spazio, ma sai che faccio? Tiro fuori il nastro aggiuntivo." Ok. No, si stabilisce all'inizio questa macchina funziona con due nastri, questa macchina funziona con tre nastri. Ok? E quindi, esattamente come le macchine multitracci e le macchine con la memoria nello stato, noi dobbiamo fissare sin dal principio quanti registri di memoria abbiamo, quante tracce ci stanno, allo stesso modo noi decidiamo quante nastri ci stanno. Ok? Questo modello di macchina è molto conveniente, è molto utile perché abbiamo l'indipendenza delle destine e quindi possiamo spostarle come vogliamo. Per far vedere un po' come possiamo programmare questo tipo di macchina di Touring, riconosciamo, scriviamo una macchina che decida questo linguaggio. Allora, abbiamo il linguaggio L delle stringhe W tali che V w appartiene a 0 or 1 or 2 star. è il numero di zeri e 2 in lo st è lo stesso. Chiaro questo linguaggio? Quindi abbiamo un linguaggio su tre simboli 0 1 2. Gli zeri un due possono apparire come ci gira tipo 0 1 2 1 2 0 bla bla bla. Ah, ok. Sorry. Too much. Ahia. Ok. Quindi abbiamo una cosa tipa, quindi è qui, poi qua. Ok? Eh, quindi abbiamo una cosa del tipo 0 1 2 0 2 2 bla bla bla bla. Sono capiti, non sono in sequenza, come avevamo visto negli esercizi precedenti, possono essere completamente sparsi. Ok? Quello che noi dobbiamo fare è eh andarli a contare. Vogliamo contare il numero degli zeri. Vogliamo contare il numero degli uno, vogliamo contare il numero dei due e vogliamo verificare che siano lo stesso. Ok? Adesso vi faccio notare che se noi dovessimo risolvere questa questo problema, questo linguaggio, dovessimo decidere questo linguaggio su una macchina mononastro, su una macchina standard, allora noi dovremmo iniziare a marcare le cose come abbiamo visto in precedenza, solo che poiché non non è che abbiamo blocchi di zero, blocchi di uno e blocchi di due, ma questi sono sparsi fra di loro e diventa un po' intricato perché che dobbiamo iniziarci a scorrere tutta la stringa per andare alla ricerca. Dov'è che è finito il primo zero? Dov'è che sta il primo uno? Eh, dovremmo cercarli tutti. Sarebbe, insomma, una gran scocciatura, si può fare, eh, non è che non si può fare, però, insomma, sarebbe un po' difficile da programmare. Vogliamo decidere questo linguaggio tramite una macchina multinastro. Ok? Che approccio proponete? Sì, io metterei tutti zero suo nastro, il suo secondo e il due sul terzo e poi però la stringa si mantiene la stessa, qua in mezzo c'è il blank e quindi quando c'è il blank noi passiamo avanti. Eh, il blank di cosa, scusi? Cioè la stringa è la stessa nastro e eh nel punto in cui c'è una mancanza di simbolo che compare in un altro nastro, noi abbiamo degli empi, dei blanket. buchini. Ok, questa è una strategia. Ok, avete sentito altre idee? Questa è già buona. Eh, posso scambire la stringa e mettere uno vicino all'altro sul nastro ugro gli ultimi tre nastri se ho un simbolo simbolo simbolo. Sì, sì, sì, sì, sì, sì, sì. Avete sentito? Questo è un improvement della prima tecnica, cioè invece di ricopiare la stringa di input sugli altri nastri e gli togliamo i pezzi a cui non siamo interessati, il che ci renderebbe le cose un po' complicate perché stiamo iniziando ad inserire degli app. Quello che ci suggerisce la nostra collega è che ogni volta che c'è uno zero lo mettiamo su un nastro, ogni volta che c'è un uno lo mettiamo su un altro nastro, ogni volta che c'è un due lo mettiamo su un altro nastro e iniziamo a sommarli come se fossero le barre di un istogramma. Arrivati alla fine dobbiamo controllare che queste tre barre sono la stessa cosa, quindi le scorriamo indietro tutte uguali, tutti assieme. Facciamo un disegnino. Quindi c'ho 0 1 0 1 2 1 2 2. Ok, sono loro, sono loro. Ok, quindi abbiamo il primo nastro che è l'impul, poi abbiamo un secondo nastro dove raccoglieremo gli zeri. Beh, non si vede quello che vedete, un terzo nastro dove raccoglieremo tutti gli uno e un quarto nastro dove raccoglieremo tutti e due. Ok? Quindi, come funziona questo approccio? Iniziamo. Leggiamo uno 0, quello è zero, lo scriviamo qua. Andiamo avanti. Leggiamo. C'è uno, lo scriviamo qui. Andiamo avanti. C'è un altro zero, lo scriviamo qua. C'è un altro zero, lo scriviamo qua. Poi c'è uno, lo scriviamo qui. Poi c'è un lo scriviamo qui e così via. Ok? Alla fine avremo 00 1 1 1 2 2 2 2. Ok? avremo le testine qui. Alla fine quello che dobbiamo fare a quel punto è riavvolgerle tutti assieme, ok? E verificare che se le spostiamo assieme tutte quante di un passo per volta arriveranno insieme al fondo. Ok? A quel punto noi sappiamo che il numero di zeri letti e il numero di 1 e due eletti era lo stesso identico. Ok? Vediamo un po' come scrivere questa cosa in una notazione. Vedete? Questo bene. In questo caso anche trasferni cancellando ecciando tutta la prima e spostando tutto a destra. cancelliamo a destra dice sulla stringa di input input siamo tre string alla fine di 0, cioè lei vuole praticamente riordinare la prima stringa la prima seconda stringa zero seconda lui sua prima che c ah cioè qualsiasi modo va bene cioè l'importante è che funziona c Ok, Q0. Questo è lo stato iniziale. Allora, usiamo questa notazione. Eh, cosa che ci inventiamo. Noi dobbiamo dire, iniziamo a scrivere l'echichetta che ci dice che se leggiamo zero sul primo nastro lo scriviamo sul secondo. Scrivo così, un due punti. due puntini per dire cosa succede sul primo nastro. Sul primo nastro c'è zero, lascio zero, vado avanti. Cosa dobbiamo fare? Lo dobbiamo ricopiare sul secondo nastro e lo scriviamo così. Sul secondo nastro c'è blank, scrivo zero e vado avanti. Ok? Quindi questa etichetta per convenzione noi stabiliamo che significhi? Che sul primo nastro c'è zero, scrivo zero e vado avanti. Sul secondo nastro c'è blank, scrivo zero e vado avanti. Ok? Siccome non stiamo menzionando i restanti nastri, per convenzione assumiamo che significhi che sugli altri nastri ci può essere qualsiasi cosa, lasciamo quello che c'è e non muoviamo le testine. Ok? Questa è l'assunzione che facciamo sul significato di questa etichetta, ok? Però ovviamente poi dobbiamo fare altre cose. E allora per distinguere questa etichetta dalle altre ci mettiamo una parentesi graffa come per raggruppare questa etichetta perché adesso ne scriviamo altro. Altra etichetta per questo anello. Sul primo nastro c'è uno. Che ci facciamo? Lo lasciamo là. Dov'è la testina? La spostiamo. Dove? Ok. Dove andiamo a scrivere il simicolo un? Sul terzo nastro. Quindi sul terzo nastro cosa leggiamo sul terzo nastro? Len cosa scriviamo su terzo nastro? Uno. Dove spostiamo la testina? A destra. Ok. E questa è una seconda etichetta per lo stesso arma. Ok. Quindi là stiamo dicendo se leggiamo un uno sul primo nastro, lo scriviamo sul secondo nastro, gli sul terzo nastro, gli altri nastri non li tocchiamo, ci può essere qualsiasi cosa. Lasciamo tutto com'è, le testine rimangono per potremmo dare ai nastri un nome che sia uguale a quello del singolo in modo che possiamo scrivere in modo parametrizzato questa cosa. Le facciamo tutti insieme. nome potresti Sì, l'importante, insomma, che ci riconosciamo quello che stiamo facendo. State vedendo? Sì. Ok. Qua altra etichetta. Sul primo nastro c'è un due. Sul secondo nastro, su primo nastro c'è un due. Lascio due e dai. E vado avanti. Su quarto nastro c'è blank. scrivo due e vado avanti. Ok? Quindi in Q0 noi stiamo facendo tutta la processamento iniziale della stia. Ogni zero che compare in input viene scritto sul primo nastro sul secondo nastro. Ogni uno che compare in input viene scritto sul terzo nastro. Ogni due che compare in input viene scritto sul quarto nastro. Ok? E andiamo avanti. Lo facciamo per tutti i simboli che stanno nell'input. Quand'è che ci fermiamo? Legk sul primo nastro. Leggiamo blank sul primo nastro. Quindi sul primo nastro c'è blank. Lascio blank. E siccome il primo nastro non abbiamo necessità di fare chissà che cosa, lo lasciamo fermo. Ok? Quindi quando mettiamo il trattino là significa che su primo, cioè su quel nastro la testina sta ferma, non la spostiamo. Che dobbiamo fare? Guardiamo il nostro filmato che dobbiamo fare sugli altri sugli altri nastri. Dove stanno le testine del secondo, terzo e quarto nastro? Stanno sul primo blank dopo quello che abbiamo scritto. Ok? Quindi, mentre sul primo nastro troviamo un blank e manteniamo la testina ferma, cosa facciamo sugli altri tre nastri? Leggiamo che cosa? Blend. E che facciamo con le testine? Le portiamo un passo dietro. Ok? Quindi sul secondo nastro c'è blank, lascio blank e vado dietro. Sul terzo nastro c'è blank, lascio blank e vado dietro. Sul quarto nastro c'è blank, lascio blank e vado dietro. Ok. E andiamo in uno. Esiste unazione per scrivere se fare la sensazione suas diverso. In questo caso scrivere quanto potresti Sì, sì, sì, sì, sì. Ok. Una volta che siamo in Q1, che dobbiamo fare? Qual era il piano? [Musica] Qual è il piano? Ora miavolgiavolgere 2 3 4 in concomitanza assieme un passo per volta e dobbiamo essere sicuri di arrivare in fondo tutti i pezzi. Ok? Quindi che facciamo? in V1 c'è sul secondo c'è 0 lascio 0 e vado dietro sul terzo c'è uno, lascio uno e vado dietro. Sul quarto c'è due, lascio due e vado dietro. Ok? Chio per tutti? Quindi ora stiamo verificando che il numero di simboli scritti su secondo, terzo e quarto nastro sia lo stesso. Come ci facciamo ad accorgere che il numero è effettivamente lo stesso? Troviamo blank all'inizio su tutti e tre i nastri nello stesso momento. Ok? Perché quella è la cosa importante, c'è la contemporaneità. Quindi sul secondo c'è blank, lascio blank e sto fermo. Sul terzo c'è blank, lascio il blank e sto fermo. Sul quarto c'è blank, lascio blank e sto fermo. Vado Q2 e al centro. Ok, ci devoare la parentesi. Cioè, eh sì, potresti. Allora, io metto la parentesi quando io c'ho più etichette sull'arco perché mi devo rabcare in qualche modo, però sì, dovresti farlo, eh? Dovresti mettere questo così, questo così e questo così. Qui su Quno è indispensabile perché sennò mi perdo. Chi bat cosa? Quando è intendo solo un'etichetta allora posso anche metterlo. Ok? Però io dicevo, cioè se hai che le tre cose si verifichino in contemporanea, uno che questo e questo se devo fare questo o questo o questo possiamo usare questa notazione. Ok? Per dire che sono tre etichette distritte, ok? E quando non metto niente intendo che è un'etichetta o per esempio una parentisona per dire che stanno tutti assieme. Ok. Allora, qui mettiamo com'era. Ok, iniziamo a fare un po' di considerazione su questa macchina. Questo tipo di macchina sono molto interessanti perché sostanzialmente simulano quello che per noi sui computer standard e la memoria, cioè che quindi possiamo avere aree diverse di memoria che usiamo un po' principale. Ok? Da questo punto di vista le macchine multinastro sono molto comode perché riusciamo a fare cose, ok? Poi lo vedremo nelle esercitazioni eccetera, però per esempio WW cancelletto WB, una macchina multinastro come potrebbe riconoscerla? Sì, prendo la prima parte, cioè o la prima o la seconda dopo il cancelletto, la metto sul nastro e poi semplicemente faccio Sì. Cioè una macchina, quindi, che può gestirsi un secondo nastro a piacimento, si prende la prima W, la ricopia, dopodiché va sulla stringa in input dopo il cancelletto e verifica che sono le stesse. Ok? Quindi per una macchina multinastro fare questa cosa è molto più semplice. Bene, la questione a questo punto è: "Ma queste macchine sono più potenti delle macchine standard? Cioè una macchina multinastro è in grado di fare cose che una macchina standard non è in grado di fare? Voi dite di no perché sì è sempre una convenzione, cioè sono dei metodi che ci semplificano la Eh, vabbè, ma questo lo afferma lei. Come facciamo a dire che non posso fare più cose che una macchina standard non possa fare? Sono diverse macchine sinceramente. M No, perché una macchina multinastro la sta muovendo i nastri allo stesso momento, non è che faccio prima una cosa e poi un'altra. Quello sarebbero due cose diverse, cioè se c'ho una macchina e poi gli ne appiccico unaltro in coda, ok, sto riconoscendo due linguaggi, uno attaccato all'altro. No, questa macchina fa robe strane, cioè questa macchina può spostare le testine come vuole, cioè e più che altro son nemmeno macchine e pariero, cioè possiamo fa cose. Sì, forse secondo un po' quello che è stato detto prima per la multitraccia io posso fare tutto questa cosa che faccio qua sui nastri diversi in un unico nastro e poi semplicemente me la devo giocare del tipo io so che il mio terzo nastro parte dopo un simbolo che ho messo io e quindi ogni volta mi devo spostare e fare la computazione in quella parte lì. Ok. Ok. Questa è una buona idea. Cioè, quindi lei sta suggerendo di utilizzare una macchina mononastro ma multitraccia e usare le più tracce per simulare i più nastri. Ok? Questo è essenzialmente quello che andremo a fare. Noi possiamo mostrare che una macchina multinastro può essere simulata da una macchina multitraccia al costo di una certa perdita di tempo. Ok? Perché l'intuizione che ci dà, per esempio, è W, cancelletto W, un conto è una macchina mononastro che deve spostare la testina avanti indietro per match, no, ogni un simbolo con un altro, il primo col primo, il secondo col secondo, il terzo col terzo. Quindi stiamo portando avanti indietro la testina per fare questa cosa. Un conto è una macchina multinastro che prende la prima doppia P, se la copia sul secondo nastro, lo riavvolge, dopodiché fa una scansione assieme e ha finito. Ok? Cioè, sembra che una macchina multinastro può essere in linea di principio più veloce. Ok, ora diamo qualche concetto sul tempo di esecuzione. Non entriamo nei dettagli perché è una cosa che voglio affrontare più di preciso quando faremo lo studio delle complessità, ok? Intuitivamente, cos'è il tempo di esecuzione di una teorema in C su una certa stringa? Ok? Allora, per noi il tempo di esecuzione di una tinguring machine su una certa stringa input è pari al numero di passi che la macchina fa prima di arrestarsi. Ok, quindi il tempo di esecuzione di una turing machine su un certo input W è il numero di passi, cioè quante volte sta testina viene spostato, quante transizioni di stato la macchina performance. Perfetto. Ok. prima di arrestarsi. Ok? Notate come precisa è questa definizione rispetto alla definizione di complessità per gli algoritmi che in genere avete visto, che in che cosa dicevamo? Ah, il numero di operazioni base, no? Però la cosa era un po' vaga perché ad esempio non è che moltiplicare due numeri è più è tanto semplice quando sommarli. Moltiplicare due numeri è più difficile che sommare due numeri. Ok? Cioè, quindi qui andiamo proprio di fino, siccome abbiamo un algoritmo che è semplicissimo, è semplicemente una macchina che si muove da stato in stato esposta a testine, no? E questi passaggi noi li possiamo notare. Per noi la complessità è questa misura basica, è il numero di passi che la macchina fa mentre processa quella stringa prima di arrestarsi e noi questi li possiamo contare. E se noi ci focalizziamo su questo possiamo scoprire che moltiplicare due numeri prende più passi che sommarli. Ok? Quindi possiamo fare proprio questa analisi di fino che in genere sugli algoritmi quando ragioniamo sui linguaggi ad alto livello non riusciamo a fare. Prego. Ma col numero di passi sentite quante volte la testina si muove o quante volte transisci, cioè quante volte tu applichi, più preciso ancora voi quante configurazioni ci stanno nella computazione, cioè quanti passaggi di configurazione, vi ricordate la definizione di configurazione o istantaneous description? Ok? Quanto e qual è il tempo di esecuzione di una macchina su una certa stringa W? è la lunghezza della sua computazione, cioè il numero di configurazioni che compaiono nella sua computazione. Quindi quelle si contano proprio. Ok. Ma incide per caso la complessità della funzione di transizione? Nel senso che in questa macchina noi per ogni transizione dobbiamo leggere su quattro nastri diversi, scrivere su quattro nastri diversi? No, no, no. Noi intendiamo il passaggio a una configurazione, quindi la configurazione di una macchina, cioè non ce ne interesseremo più di tanto perché non ci non ci interessa, però che cosa può essere una configurazione per una macchina multinastro? Non, detto che le configurazioni sono delle foto dello stato di avanzamento dei lavori. Quindi una configurazione per una macchina multinastro potrebbe essere una codifica di tutto quello che c'è su tutti i nastri, dello stato in cui è la macchina e della posizione della testina su tutti i nastri. Ok? Allora, quindi il tempo di esecuzione di una macchina di Touring è una cosa veramente semplice, si definisce in maniera molto pulita rispetto a quella degli algoritmi ad alto livello ed è il numero di passi che la macchina fa prima di fermarsi, ok? Se la macchina non si ferma, il suo tempo di esecuzione è infinito, non si ferma, è altissimo. Ok? È unbounded. Ok? Allora, quello che adesso noi vedremo, noi vogliamo simulare il funzionamento di una macchina multinastro che chiamiamo M. Allora, M è una macchina multi. Leggete? Sì. Multi nastro. Noi la trasformeremo in una macchina S a singolo nastro, però multitraccia. Ok? S è una macchina multitraccia. Ok? Quindi il nostro claim è il seguente. Teorema sia m una macchina multinastro. Allora, esiste una macchina S multipccia tale che il linguaggio riconosciuto da M è uguale al linguaggio riconosciuto da S. Ok? Quindi noi stiamo affermando che data una qualsiasi macchina di touring multinastro, noi siamo sempre in grado di costruirne una equivalente. Per equivalente intendiamo una macchina che è in grado di conoscere lo stesso linguaggio. Ok? Come funziona? Sì, vedete? Sì. [Musica] Ora funziona funziona così. Il principio è esattamente quello che ci ha detto la nostra collega, cioè noi vogliamo usare le tracce della macchina S in un modo furbo tale per cui noi possiamo replicare il funzionamento di m su S. Ok? Quindi vorremo fare un funzionamento simile, non lo stesso un funzionamento simile, però l'importante è che noi accettiamo, rispondiamo sì su tutte le stringhe accettate da m e rispondiamo no su tutte le stringhe rifiutate da m. Ok? Allora, funziona così. Per semplicità questa cosa è generalizzabile, no? Vabbè, facciamo un po' più generale. Supponiamo che la macchina M è una macchina a K nastri. Ok? Noi la simuliamo tramite una macchina S che ha 2* K tracce. Supponiamo di avere le nostre cellette qua e quindi abbiamo A B C Supponiamo che la testina sia leggendo questa a e la testina sia leggendo questo zero. Come la simuliamo su S? Le tracce, ok, qua è una convenzione, eh, ci possiamo inventare quello che vogliamo. Le tracce dispari della macchina S conterranno il contenuto dei nastri della macchina M. Quindi qui che cosa avrò? Qua avrò A B C. Qui avrò 0 1 0 En sono. Ok? Le tracce aggiuntive della macchina S conterranno dei marcatori per dirci dove sta la testina della macchina. nastro che stiamo simulando. Ok? Quindi, per esempio, avremo un asterisco qua e un asterisco qua. Ok? Quindi l'idea è questa. Stiamo vogliamo simulare il comportamento di una macchina con K nastri. Lo vogliamo fare su una macchina a singolo nastro, però assumiamo che siacce. Le tracce della macchina Sono pari al doppio dei nastri della macchina M. Metà dei nastri verranno utilizzati per simulare per memorizzare il contenuto dei nastri della macchina multinastro. Le altre tracce verranno usate in maniera molto banale, giusto per tenere traccia con un marcatore di dove sta dove starebbe la testina della macchina multinastro durante la sua pubblicazione. Ok. Chiaro? Allora, vediamo il la il principio di funzionamento. Supponiamo che questo è uno stato Qi. Ci muoviamo su uno stato QJ della macchina multinastro e abbiamo che su primo nastro leggiamo A, scriviamo B e andiamo avanti. Sul secondo nastro leggiamo 0, scriviamo 1 e andiamo indietà. Ok? Allora, la macchina S funziona in questo modo, cioè simula passo per passo tutto quello che fa la macchina M. Però siccome a differenza della macchina M che ha tanti nastri, la macchina S c'ha solo un nastro, non può fare questa cosa in un in un passo soldato, deve fare che cosa. Allora, il principio di funzionamento è questo. Noi portiamo la testina della macchina Sempre alla sinistra, all'inizio. Ok? Dobbiamo scoprire che cosa sta leggendo la macchina Mentre processo. Quindi prendiamo la mega testina su tutte le tracce, la iniziamo a spostare verso destra. Ogni volta che troviamo un marcatore su una traccia, noi sappiamo qual è il simbolo che la macchina multinastro starebbe leggendo. Chiaro per tutti? Quel simbolo lo prendo e lo metto in memoria. Alla fine la macchina multinastro, è vero che ha cani di nastri, ma la macchina multinastro ha un numero fissato di nastri, quindi io so quanti marcatori devo andarmi a beccare. K. Quindi io prendo la testina, me la sposto verso destra, mi becco K marcatori e mi memorizzo nello stato tutti i simboli che sto leggendo. Una volta che ho letto tutto, posso fare il passo che farebbe la macchina multinastro, cioè so qual è la transizione che farebbe la macchina multinastro. Ovviamente pure questa cosa qui va simulata, non si può fare l'impasto soltanto. Che cosa facciamo? Quindi la macchina è partita con la testina a destra, si è letta tutto quanto. Arriviamo in fondo, dopo che ci siamo letti tutti, inizia tutto, iniziamo ad andare indietro. troviamo i marcatori per sapere dove stanno le testine dei vari nastri e in corrispondenza di quelle posizioni iniziamo a sovrascrivere i nuovi simboli che noi conosciamo perché noi conosciamo qual è la funzione di transizione della macchina. Ok? Stiamo solo ricodificando questa cosa con molti più stati. Prendo la testina, la sposto in avanti, leggo tutto, metto nello stato, dopodiché so che devo fare, torno indietro e vado a modificare le cose con l'accortezza però che dovremo spostare gli asterischi, o un passo in avanti o un passo indietro, indipendenza di dove la macchina multinastro sposterebbe la testina. È chiaro per tutti che facciamo? Sì. Quindi la macchina multraccia, diciamo, deve essere più veloce della macchina multifraccia. Aspetta, aspetta. No, non è che deve essere più veloce, fa più passi. Ok. Fa più fa più step per fare un solo step della macchina multinastro. Però se se io con la macchina multitraccia segno eh la testina di una marca multinastro, però quando già la testina della marca multinastro è dall'altra parte. No, no, no, ma non è che sto facendo la gara con la macchina che io ce l'ho di fianco e gli devo sta appresso, no. Io sto simulando il suo comportamento e io posso prendere il tempo che mi serve. S può prendere il tempo che ne serve per simulare M, non è che la deve rincorrere. Per simulare ogni passo di M però S ha bisogno di tanti di tanti di tanti steps. Ok? Che quali sono? Intuitivamente me testina. Iniziamo a sinistra. Leggiamo tutti i simboli in corrispondenza degli asterischi. Noi sappiamo quanti ne dobbiamo leggere. Dobbiamo leggere esattamente K perché quel K è fissato. Una volta che li abbiamo letti tutti e abbiamo memorizzato tutto nello stato, sappiamo che fare, sappiamo come i simboli vadano cambiati e dove vanno spostati gli asterischi. Quindi da sinistra torniamo indietro e andiamo in corrispondenza degli asteristi ad alterare i simboli e a spostare la posizione degli asterischi. Dopodiché la portiamo all'inizio e continuiamo a fare questa cosa. Ok? capite che questo ci costa del tempo perché ogni passo della macchina multinastro comporta per la macchina a singolo nastro multitracce di andare una volta avanti e una volta indietro. Cerchiamo di stimare quanto è questo costo. È chiaro come funziona questa simulazione? intuitivamente costa del tempo e in effetti costa del tempo. Allora, supponiamo, no, che stiamo simulando una macchina con due nastri. Questa cosa si fa anche col K nastri, è la stessima cosa. Ma diciamo ancora K nastri, va. Allora, qual è la condizione peggiore per la macchina mononastro? La cosa peggiore che può capitare è che la macchina multinastro spara a ovest una testina e a est l'altro, cioè che dopo M passi una testina è a distanza M dall'inizio e l'altra testina è a distanza M dall'inizio. Cioè questa è la cosa peggiore che può capitare, ok? che la macchina multinastro spedisce a Roma una cosa e a Cana l'altra testina. È chiaro l'inizio, quindi lo prendiamo in mezzo. Eh, cioè è normale, tu non hai un punto di riferimento perché sono nastri infiniti, quindi tutto è il centro, tutto è il posto dei diinizi. Ok? Quindi la cosa peggiore è che sul nastro di input ce ne andiamo avanti, sul secondo nastro ce ne andiamo indietro e questi dopo M passi saranno uno M passi avanti e l'altro M passi indietro. Meri avanti ed McDo indietro. Ok? Qual è la loro distanza? 2m. Quindi la loro distanza è 2m. per la macchina mononastro per simulare il funzionamento, quindi un passo dopo M della macchina multinastro, la macchina monostro si deve scansionare tutte le tracce, però siccome avrà le testine una a nord e l'altro a sud, dovrà avrà gli asterischi a distanza 2 m celle, quindi devo andare avanti e mi servono 2 m passi per vedere tutti gli asteristi. È chiaro? Quindi abbiamo 2m più devo tornare indietro, no? Devo tornare indietro e quindi sono altri 2 m passi. 2 N bassi. Dopodiché c'è un altro elemento. Andiamo qua. Ve lo faccio vedere qui. Vedete? Sì. Allora, nel momento in cui la testina l'abbiamo Dov'è questo? Nel momento in cui la testina l'abbiamo spostata qui, noi poi dobbiamo tornare indietro per aggiornare i simboli e per aggiornare la posizione degli asterischi. Allora, se noi stiamo andando indietro e questo asterisco qui va spostato qua, allora lo stiamo spostando nella direzione in cui ci stiamo muovendo. E questo non ci costa niente perché stiamo andando là e stiamo andando in quella direzione è di strada. Il problema è se andando indietro questo asterisco da qui va spostato qua, cioè dobbiamo andare contromano. Quello là ci costa ci costa due passi. Dobbiamo andare avanti e poi indietro nuovamente e poi riprendere a indietreggiare. È chiaro? Quindi nella peggiore delle ipotesi, per simulare l'ennemmesimo passo, la macchina monastro deve fare 2m + 2m + 2k. Ok, abbiamo quasi chiuso, eh. E queste sono 4m + 2k. Vedete? Sì. Ok. Sommiamo. Sommi. Allora, vogliamo vedere, quindi assumiamo che la macchina multinastro faccia N step. Ok? N steps. La macchina mononastro farà per i che va da 0 a n cosa? 4 * i + 2k pas. Ok. Allesimo passo per quello che abbiamo visto facciamo 4i + 2k passi. Adesso facciamo giusto un minimo di rielaborazione. Questo è minore o uguale della sommatoria che va da 0 a n + 2k. E questo è minore o uguale qua mettiamo uno. Stessa cosa n * 4n + 2k. Ok? Cioè alesimo passo la macchina monopomastro deve fare 4 + 2k. Alles + 1 passo dovrà fare 4 * 1 + dk. Alleso + 2 passi passo dovrà fare 4 per i + 2 + dk. Insomma, sono numeri che si sommano sommato tutto, guardate qui, questo è di ordine quadratico, cioè la macchina mononastro per simulare la macchina multinastro ci mette un tempo che è aggiuntivo che è di ordine quadratico. Se la computazione della macchina multinastro era n qu, la macchina mononastro ci mette n^ qu. Ok? Però sempre nel reame della stessa classe di funzioni rimaniamo. Se la macchina multinastro ci mette tempo esponenziale, la macchina mononastro ci mette il quadrato di una funzione esponenziale che è ancora esponenziale, cioè quindi non c'è un grosso C. rallenta che rallenta, però rimaniamo più o meno nella stessa classe di funzioni. Se era polinomiale rimane polinomiale. Se esponenziale rimane esponenziale. Se era doppiamente esponenziale rimane doppiamente esponenziale e così via. Ok? C'erano un paio di domande? Sì. No. Ok. Sopra non riesco a leggere la somatoria. Ah, la prima. No, la secondaoria i s un attimo. Scrivo meglio. Oplà. Oplà. I che va da 1 a N. [Musica] Quindi siamo tardi. Cosa abbiamo mostrato? Abbiamo mostrato che una macchina multinastro può essere simulata da una macchina multitraccia, ma la macchina multitraccia ha lo stesso potere delle macchine standard. Di conseguenza una macchina multinastro, sebbene anche a questa cosa pensi di avere più nastri e più testine, in realtà non è più potente di una macchina non mononastro, può essere più veloce, però non è in grado di fare cose che una macchina standard di fare. Ok? Per questa ragione ci tenderemo a concentrare su macchine multimastro perché sono molto più facilmente gestibili. Ok? E con questo concludiamo per oggi. Grazie mille.