Informatica Teorica Seconda prova in itinere e appello del corso del Vecchio ordinamento 29 Giugno 2004 Coloro che sostengono la seconda prova in itinere svolgano gli esercizi 1,2,3 in un’ora e un quarto. Chi sostiene l’appello completo (o la parte di Informatica teorica del corso integrato Algebra + Inf. Teorica) svolga gli esercizi 1, 3 e 4 nello stesso tempo. NB I punteggi assegnati agli esercizi 1,2,3 hanno valore solo con riferimento alla II prova in itinere. Si suggerisce di affrontare per primo l’esercizio 3. Esercizio 1 (Punti 6) Si dica, giustificando brevemente la risposta, se le seguenti affermazioni sono vere o false: a) Il problema di stabilire se un generico programma P, codificato in C, eseguito su un generico dato di ingresso x, non terminerà mai la sua esecuzione è semidecidibile. b) Il problema di stabilire se un generico programma P, codificato in C, eseguito su un generico dato di ingresso x, “andrà in loop”, nel senso stretto del termine, ossia ripeterà indefinitamente una stessa sequenza di “mosse” ritornando ogni volta nello stesso stato di memoria, è semidecidibile. Esercizio 2 (Punti 4) Il signor Furbetti sta realizzando un archivio mediante una tabella hash. I record dell’archivio hanno una chiave costituita da sequenze di al più 30 caratteri e la tabella ha una dimensione di 5 MB. Furbetti è particolarmente soddisfatto perché ha trovato una funzione di hash h “perfetta” (ossia è riuscito a dimostrare che la sua funzione h è tale che x y implica h(x) h(y)). Accingendosi però a implementare un algoritmo per il calcolo di h non riesce a trovarne uno. Egli viene allora assalito dal dubbio che la sua h non sia calcolabile. Potete aiutare Furbetti a risolvere il suo dubbio? Esercizio 3 (Punti 8) a) Si descriva sinteticamente –senza necessariamente codificarlo in modo completo- un algoritmo per la macchina RAM per riconoscere il linguaggio L = {anbncn | n >=1}. Se ne valutino complessità spaziale e temporale –a meno della relazione -mediante il criterio di costo logaritmico. b) E’ possibile ottenere le stesse complessità (sia spaziale che temporale) mediante una macchina di Turing? Giustificare brevemente la risposta. Esercizio 4 Si scriva una grammatica che generi il linguaggio L = {anw | w {b,c}* #(b,w) = #(c,w) = n, n >=1}, dove la funzione #(i,x) denota il numero di occorrenze del carattere i nella stringa x. La grammatica così ottenuta è a potenza minima, ossia non esiste una grammatica ad essa equivalente appartenente ad una classe di minor potenza generativa? Giustificare brevemente la risposta. Soluzioni Esercizio 1 a) Falsa. Infatti il problema complementare è notoriamente non decidibile ma semidecidibile. Quindi non può essere semidecidibile anche il problema della non-terminazione. b) Vera. E’ concettualmente possibile registrare ogni stato dell’esecuzione del programma e verificare se lo stato attuale è identico a uno già attraversato. Se ciò accade, da quel momento in poi l’esecuzione si ripeterà identicamente all’infinito. Esercizio 2 h è certamente calcolabile perché ha un dominio finito. Ciò però aiuta solo in parte Furbetti perché non fornisce indicazioni su come trovare l’algoritmo di calcolo di h. Esercizio 3 a) La RAM aggiorna un contatore per ogni a letto (costo (i), i = 1, …, n). Salva il valore del contatore al termine della lettura degli a in due celle diverse. Decrementa la prima copia per ogni b letto e la seconda copia per ogni c letto successivamente. Al termine entrambi i contatori devono contenere esattamente 0. Ne deriva una complessità spaziale, a criterio logaritmico, (log(n)) e una temporale (n.log(n)) b) Sì. Una MdT può simulare il comportamento della RAM esattamente allo stesso modo, usando un nastro per ogni contatore e codificandone il contenuto in numerazione binaria. Per ogni carattere letto l’incremento o il decremento del nastro contatore richiede un numero di mosse al più proporzionale alla lunghezza del nastro, ossia (log(n)). Perciò complessità spaziale e temporale coincidono con quelle della RAM. Si noti che un MdT potrebbe riconoscere lo stesso linguaggio con complessità (n) sia spaziale che temporale. Esercizio 4 S aSH | aH H BC BC CB CB BC Bb Cc La grammatica di cui sopra non è non-contestuale (appartiene però alla classe delle grammatiche contestuali, una classe non considerata in questo corso di minor potenza delle grammatiche generali e di maggior potenza di quelle non-contestuali; questa classe genera linguaggi decidibili al contrario delle grammatiche generali). Non è possibile generare lo stesso linguaggio mediante una grammatica non-contestuale perché per riconoscere L occorre tenere aggiornati i conteggi sia delle b che delle c per confrontarli con il numero di a letto inizialmente. Informatica Teorica Sezione Mandrioli Appello del 20 Luglio 2004 Coloro che recuperano la I prova risolvano gli esercizi 1 e 2 tra quelli indicati qui sotto entro un’ora. Coloro che recuperano la II prova risolvano gli esercizi 3 e 4 tra quelli indicati qui sotto entro un’ora. Coloro che recuperano entrambe le prove o che sostengono l’appello della semiunità di Informatica Teorica VO risolvano tutti gli esercizi entro due ore. Coloro che sostengono l’esame del corso integrato con Algebra risolvano uno a scelta tra gli esercizi 1, 2, e l’esercizio 3 entro un’ora. NB: i punteggi indicati per i vari esercizi fanno riferimento esclusivamente al corso di Informatica Teorica; non hanno valore per il corso integrato. Attenzione!!! I voti proposti verranno pubblicati sul sito seguente (e affissi nella bacheca del Dip. di Elettronica e Informazione in forma cartacea): http://www.elet.polimi.it/upload/mandriol/Didattica/sitoinfteor1.html Aggiornando il file originariamente esistente dopo le prove in itinere. Gli studenti avranno tempo due giorni (48 ore, per la precisione) dalla data della pubblicazione per rifiutare il voto proposto, se sufficiente. L’eventuale rifiuto deve essere comunicato via email, facendo uso dell’indirizzo ufficiale del Poliself, non di indirizzo privato! Trascorsi i due giorni, i voti verranno registrati e trasmessi alla segreteria. La rinuncia al voto proposto è definitiva e totale: chi rinuncerà dovrà sostenere il recupero dell’intero esame a settembre. Così pure, chi risulterà insufficiente dopo il recupero di luglio dovrà sostenere a settembre il recupero dell’intero esame. Esercizio 1 (punti 9/15) Si specifichi, mediante una formula del prim’ordine un apparato che funziona nel modo seguente: All’istante 0 esso emette un segnale s, che può essere uno 0 o un 1. Se, dopo l’emissione di s e prima dello scadere di 3 secondi, viene ricevuto lo stesso segnale in risposta, allora allo scadere del terzo secondo viene emesso un nuovo segnale invertendone il valore (0 se prima si era emesso 1 e viceversa); in caso contrario viene riemesso lo stesso segnale inviato in precedenza. Il comportamento dell’apparato si ripete poi periodicamente con periodo di 3 secondi applicando sempre la stessa regola. L’apparato emette un segnale soltanto in istanti che sono multipli di 3 secondi. Si suggerisce di usare i predicati emette(s,t) e riceve(s,t) per indicare, rispettivamente l’emissione e la ricezione del segnale s all’istante t. NB: il domino temporale può essere sia discreto (ad esempio, l’insieme dei naturali) che continuo (ad esempio, l’insieme dei reali). Esercizio 2 (punti 8/15) Con riferimento all’esercizio precedente, si assuma un tempo discreto (la cui unità sia il secondo. Si costruisca un’opportuna macchina astratta, preferibilmente a potenza minima, che abbia come alfabeto di ingresso (rispettivamente, di uscita) la ricezione (risp., emissione) di 0, la ricezione (risp., emissione) di 1, oppure l’assenza di segnale e si comporti come specificato nell’esercizio 1. NB: essendo il comportamento dell’apparato periodico, senza che sia prevista una sua terminazione, la macchina astratta, di conseguenza, non dovrà prevedere una situazione di arresto, a meno che non debba bloccarsi a causa di errori. Esercizio 3 (punti 7/15) Si dica, giustificando brevemente la risposta, quali di queste affermazioni sono vere e quali false: 1. La funzione g(y,x) = (1 se fy(x) è pari, 0 altrimenti) è calcolabile. 2. La funzione g(y,x) = (1 se fy(x) è pari, altrimenti) è calcolabile 3. La funzione g(y) = (1 se fy(x) è pari x, 0 altrimenti) è calcolabile 4. La funzione g(y) = (1 se fy(x) è pari x, altrimenti) è calcolabile NB: Nel caso la risposta a qualcuna delle domande precedenti fosse “Falsa” e se ne fornisse una dimostrazione mediante tecnica diagonale, il punteggio acquisito verrebbe maggiorato di punti 3. Esercizio 4 (punti 8/15) Si descriva con sufficiente precisione, ma senza necessariamente specificare ogni dettaglio, come una Macchina di Turing a nastro singolo deterministica (si ricordi che una Macchina “a nastro singolo” è diversa da una macchina a k nastri con k = 1) possa riconoscere il linguaggio L = {ww, w {a,b}*} analizzandone la complessità spaziale e temporale (a meno dell’ordine di grandezza determinato dalla –equivalenza). Soluzioni Esercizio 1 ts(emette( s, t ) ( ( s 0 s 1) (k (k N t 3k )) t1 (t t1 t 3 riceve( s, t1 )) emette(neg( s), t 3) t1 (t t1 t 3 riceve( s, t1 )) emette( s, t 3) ))) (emette(0,0) emette(1,0)) dove la lettera funzionale neg, che inverte i valori 0 e 1, è definita così: neg(s) (s 1) mod 2 . (mod è il ben noto operatore “resto della divisione intera”). Esercizio 2 La figura sottostante descrive parzialmente un automa a stati finiti che si comporta secondo le specifiche. La parte omessa, cui si accede attraverso la freccia tratteggiata, tratta il caso dell’emissione iniziale di uno 0 in modo simmetrico. */1 */1 _,0/_ _,0/_ */0 1/_ 1/_ */_ */0 Legenda: * indica un qualsiasi simbolo; _ indica assenza di segnale; a, b/ etichetta una transizione che avviene in conseguenza dll’input a o dell’input b. Esercizio 3 1. Falsa. E’ possibile ridurre il problema della terminazione al problema dato assegnando al risultato della funzione il valore 2 a valle del calcolo di una funzione generica fz(w)di cui si voglia stabilire la terminazione. Si può sfruttare per la dimostrazione anche il teorema di Rice nel seguente modo: si fissi ad arbitrio un valore intero k, e si definisca la funzione h(y) = (1 se g(y,k) è pari, 0 altrimenti). h(x) è la funzione caratteristica dell'insieme delle macchine di Turing che calcolano funzioni con valore pari nel punto k. Questo insieme non è né l'insieme vuoto, né l'insieme universo, e non è dunque decidibile, quindi la sua funzione caratteristica non è calcolabile. Se g(y,x) fosse calcolabile, lo sarebbe anche h(y), il che porterebbe a una contraddizione. La dimostrazione può anche essere costruita in forma diretta usando la tecnica diagonale nel modo seguente: Si definisca h(x) = Se fx(x) non è pari allora 2, altrimenti. Se g fosse calcolabile lo sarebbe anche h. Quindi h dovrebbe essere = fx0 per qualche x0. Ma h(x0) non pari implicherebbe h(x0) = 2 e h(x0) = 2 implicherebbe h(x0) non pari. 2. Vera: basta fare il run di fy(x). 3. Falsa grazie al teorema di Rice: infatti la g(y) è la funzione caratteristica dell'insieme di tutte (e sole) le macchine di Turing che computano funzioni totali con valore sempre pari. Questo insieme non è né l'insieme vuoto, né l'insieme universo, non è quindi decidibile, e la sua funzione caratteristica non è computabile. 4. Falsa. Infatti questa è la funzione semicaratteristica dell'insieme di tutte (e sole) le macchine di Turing che computano funzioni totali con valore sempre pari. Se tale funzione fosse calcolabile, ciò vorrebbe dire che tale insieme di funzioni è RE. Questo è tuttavia impossibile. Si prenda infatti una funzione calcolabile f(x) generica; si può facilmente calcolare la funzione f’(x) = 2f(x), la quale ha lo stesso dominio di f(x) ed ha, laddove è definita, valore pari. Di conseguenza, a partire dall’insieme di tutte le funzioni computabili a valori solo pari è possibile costruire l’insieme di tutte le funzioni computabili semplicemente dividendo per 2 le immagini. Da questo deriva che se l’insieme di tutte e sole le funzioni totali a valori pari fosse RE, anche l’insieme di tutte e sole le funzioni totali lo sarebbe. E’ tuttavia ben noto (da lezione) che l’insieme di tutte e sole le funzioni totali non è RE, di conseguenza non lo è neanche l’insieme di funzioni di partenza. Esercizio 4 La macchina M deve in primo luogo individuare la metà della stringa in ingresso. Per ottenere ciò, mediante una prima passata memorizza – ad esempio in unario – la lunghezza della stringa, alla sua destra (durante questa passata la macchina dovrà tenere traccia del carattere fino a dove si è contato, per esempio cambiandolo da a ad a', e da b a b', e riconvertendolo nel carattere originale prima di passare a contare il prossimo carattere). Ciò richiede un tempo (n) per ogni carattere letto e quindi (n2) per l’intera stringa. Indi, per ogni coppia di caratteri della stringa che memorizza la lunghezza dell’input, sposta di una posizione un’opportuna marca all’interno della stringa di input (ad esempio sostituendo il carattere a con il carattere a’ e b con b’). Al termine la marca si troverà a metà della stringa di ingresso. Anche questa macro-operazione richiede un tempo (n2) ((n) per ogni coppia di caratteri). A questo punto M può procedere a confrontare, uno per uno il primo carattere dell’input con il carattere in corrispondenza della marca che segna la metà; il secondo con il successivo. Anche questo confronto richiede un tempo (n) per ogni carattere e quindi (n2) per l’intera stringa. In conclusione l’intero procedimento ha una complessità temporale (n2) e spaziale (n). Informatica Teorica Sezione Mandrioli Appello del 15 Settembre 2004 Attenzione!!! I voti proposti verranno pubblicati sul sito seguente: http://www.elet.polimi.it/upload/mandriol/Didattica/sitoinfteor1.html Aggiornando il file originariamente esistente dopo le prove in itinere. Gli studenti avranno tempo due giorni (48 ore, per la precisione) dalla data della pubblicazione per rifiutare il voto proposto, se sufficiente. L’eventuale rifiuto deve essere comunicato via email, facendo uso dell’indirizzo ufficiale del Poliself, non di indirizzo privato! Trascorsi i due giorni, i voti verranno registrati e trasmessi alla segreteria. Per evitare il ripetersi di recenti disguidi, probabilmente dovuti a malfunzionamenti del servizio di posta elettronica, il docente spedirà a ogni studente “rinunciatario” un esplicito messaggio di “ricevuta”. In caso di mancata ricezione di tale ricevuta si consiglia di contattare il docente telefonicamente o di avvisare la segreteria didattica del DEI. Chi risulterà insufficiente dopo il recupero di settembre o rinuncerà al voto proposto dovrà sostenere il recupero dell’intero esame nella sessione invernale, oppure ri-iscriversi al corso per l’anno accademico 2004/05. Esercizio 1 (punti 8) Si specifichi, mediante una formula del prim’ordine il ripetersi periodico di un segnale istantaneo (ossia che si verifica in un istante di tempo isolato) con periodo 2 unità di tempo a partire dall’istante 5. Prima dell’istante 5 e in tutti gli altri istanti il segnale non si verifica. Esercizio 2 (punti 9) Si costruisca un automa a pila equivalente alla grammatica seguente (ossia che riconosca il linguaggio da essa generato): S aAB A aAA | bAB | c B bBB | aBA | c L’automa così costruito è deterministico? In caso negativo, è possibile costruirne uno equivalente deterministico? Esercizio 3 (punti 7) Si dica, giustificando brevemente la risposta, quali delle seguenti affermazioni sono vere e quali false: 1. L’insieme dei programmi C la cui terminazione è garantita a priori per ogni valore dei dati in ingresso è ricorsivamente enumerabile. 2. L’insieme dei programmi C la cui terminazione è garantita a priori per ogni valore dei dati in ingresso è ricorsivo. Esercizio 4 (punti 7) In passato alcuni studenti, nello svolgimento di prove d’esame, hanno costruito una valutazione di complessità per macchine di Turing dichiarando di utilizzare il criterio di costo logaritmico. Si spieghi brevemente perché ciò è un errore e perché invece tale criterio è utile e spesso necessario nella valutazione di complessità relativa a un modello di calcolo come la RAM. Soluzioni Esercizio 1 Codificando l’occorrenza del segnale all’istante t mediante il predicato s(t), la formula seguente specifica il comportamento desiderato: s(5) t ((t 5) s(t ) (t 5 ( s(t ) (k (k N t 5 2k ))))) Si noti che i primi termini possono essere omessi, dal momento che sono implicati dall’ultimo, ottenendo così la formula equivalente e più sintetica: t (s(t) (k (k N t = 2k + 5))) Esercizio 2 La figura sottostante descrive un automa a pila (deterministico) equivalente alla grammatica fornita. b,A/AB a,A/AA , Z0/SZ0 a,S/AB c,B/ a,B/BA c,A/ , Z0/ b,B/BB Legenda: la stringa a destra del carattere / viene depositata sulla pila mettendo il carattere più a sinistra in alto. Esercizio 3 Entrambe le affermazioni sono false. Infatti è noto (Teorema 2.10 del testo) che un insieme di indici di Macchine di Turing che calcolino tutte e sole le funzioni calcolabili e totali non è ricorsivamente enumerabile. Se perciò l’insieme suddetto di programmi C fosse ricorsivamente enumerabile, potremmo automaticamente calcolare per ogni tale programma un corrispondente indice di MT che calcola la stessa funzione del programma, e quindi ricavare da una enumerazione ricorsiva dell’insieme dei programmi una corrispondente enumerazione ricorsiva di un insieme di indici di MT che calcolano tutte e sole le funzioni calcolabili e totali. A maggior ragione, se tale insieme non è ricorsivamente enumerabile, non può essere ricorsivo. Esercizio 4 Le operazioni astratte della MT (transizioni) sono effettivamente elementari e possono essere realizzate a “risorse costanti” con qualunque tecnologia di base. Al contrario le operazioni astratte della RAM, più di alto livello, sono realizzate mediante opportuno HW la cui complessità, intermini di circuiteria e utilizzata e tempo impiegato è funzione –appunto logaritmica- della dimensione dei dati in ingresso. Informatica Teorica Sezione Mandrioli Appello del 5 Febbraio 2005 Attenzione!!! I voti proposti verranno pubblicati sul sito seguente: http://www.elet.polimi.it/upload/mandriol/Didattica/sitoinfteor1.html Gli studenti avranno tempo due giorni (48 ore, per la precisione) dalla data della pubblicazione per rifiutare il voto proposto, se sufficiente. L’eventuale rifiuto deve essere comunicato via email, facendo uso dell’indirizzo ufficiale del Poliself, non di indirizzo privato! Trascorsi i due giorni, i voti verranno registrati e trasmessi alla segreteria. Per evitare il ripetersi di recenti disguidi, probabilmente dovuti a malfunzionamenti del servizio di posta elettronica, il docente spedirà a ogni studente “rinunciatario” un esplicito messaggio di “ricevuta”. In caso di mancata ricezione di tale ricevuta si consiglia di contattare il docente telefonicamente o di avvisare la segreteria didattica del DEI. Chi risulterà insufficiente dopo il recupero di febbraio o rinuncerà al voto proposto dovrà ri-iscriversi al corso per l’anno accademico 2004/05. _______________________________________________________________________________ Esercizio 1 (punti 8) Si specifichi, mediante una formula del prim’ordine il seguente comportamento di un ipotetico sistema: Tutte le volte che, in un certo istante, si verifica l’evento A, dopo esattamente k unità di tempo si verifica l’evento B, a meno che, contemporaneamente ad A, non si verifichi anche l’evento C. In tal caso, B non si verifica dopo k unità di tempo, bensì dopo k+1. Esercizio 2 (punti 8) Si considerino i seguenti linguaggi: L1 = {anb2m| n, m >= 1}, L2 = {anb3n| n >= 0} Si costruisca una grammatica G che generi il linguaggio L = L1 L2. E’ preferibile una grammatica a potenza minima, ossia regolare se ne esiste una, non contestuale se ne esiste una ma non ne esiste una regolare, ecc. Nel caso, si spieghi brevemente perché non esstono grammatiche appartenenti a classi inferiori a quella proposta. Esercizio 3 (punti 6) Si dica, giustificando brevemente la risposta, se è decidibile il problema di stabilire se il linguaggio L di cui all’esercizio 2 è vuoto o no. Esercizio 4 (punti 8) Si dica, giustificando brevemente la risposta, qual è l’ordine di grandezza minimo per il riconoscimento del linguaggio L di cui all’esercizio 2 nei due casi in cui si usi a) Una macchina di Turing. b) Una RAM, assumendo il criterio di costo logaritmico. Soluzioni Esercizio 1 Codificando l’occorrenza di un generico evento E all’istante t mediante il predicato E(t), la formula seguente specifica il comportamento desiderato: t (( A(t ) C (t )) B(t k )) (( A(t ) C (t )) (B(t k ) B(t k 1))) Si noti che la formula di cui sopra porta ad una contraddizione se non solo all'istante t, ma anche all'istante t-1 accadono sia A che C (cosa che la specifica a parole in principio non vieta). In questo caso, infatti, il secondo congiunto applicato a t-1 vincola B ad accadere a t+k, mentre lo stesso congiunto riferito all'istante t proibisce che B accada a t+k. Una formula che evita questo fenomeno, reinterpretando la specifica a parole è la seguente: t (( A(t ) C (t )) B(t k )) (( A(t ) C (t )) B(t k 1)) Esercizio 2 Il linguaggio L = L1 L2 è l’insieme {a2nb6n| n >= 1}. Infatti, L1 è il linguaggio delle stringhe con un numero pari di ‘b’ che seguono un numero qualunque di ‘a’. Tra le stringhe di L2, del tipo ‘anb3n’, quelle che appartengono anche a L1 sono esattamente quelle con un numero pari di ‘b’, ossia quelle nella forma ‘a2nb3(2n) = a2nb6n’. L è generato dalla seguente grammatica non contestuale (e da nessuna grammatica regolare essendo necessaria una pila per il suo riconoscimento): S AB | ASB A aa B bbbbbb Esercizio 3 L non è vuoto: contiene aabbbbbb, ecc. Quindi il problema L = è deciso e perciò decidibile. Esercizio 4 Una MT che simuli un automa a pila deterministico può facilmente riconoscere L in tempo lineare. Una RAM deve necessariamente aggiornare un contatore (il cui contenuto è un numero proporzionale ad n) per ogni carattere letto. Perciò, a criterio di costo logaritmico, la sua complessità è necessariamente (n.log(n)). Informatica Teorica Prima prova in itinere - 5 Maggio 2005 Esercizio 1 (5/13 punti) Si consideri il linguaggio: L {a,b,c}* costituito dalle stringhe in cui il numero di a sia uguale al numero di b + 5 e il numero di c sia pari. Si costruisca una macchina astratta che riconosca L. Tra le diverse macchine astratte che riconoscono L sono preferite macchine “a potenza minima” ossia appartenenti alla categoria di automi a minor potenza riconoscitiva possibile. Esercizio 2 (4/13 punti) E’ noto che le due seguenti definizioni di grammatica regolare sono equivalenti, ossia generano la stessa classe di linguaggi: 1) P, || = 1, VN .VT VT 2) P, || = 1, VT.VN VT La seguente ulteriore modifica della definizione è anch’essa equivalente alle precedenti? 3) P, || = 1, VT.VN VN .VT VT Giustificare brevemente la risposta. Esercizio 3 (5/13 punti) Si definisca in maniera matematicamente precisa la seguente versione arricchita di automa a pila. L’automa, oltre a tutte le caratteristiche dei normali automi a pila (nondeterministici), può anche, ad ogni mossa, esaminare il simbolo contenuto nel fondo della pila e sostituirlo con un altro simbolo. Se ne formalizzino anche le regole di funzionamento (per esempio mediante le normali nozioni di configurazione e transizione tra configurazioni) e di riconoscimento di stringhe. NB: nel caso la precedente definizione informale non risulti sufficientemente precisa in alcuni dettagli, si operino opportune scelte, spiegandone le ragioni, per giungere ad una formalizzazione precisa. Si dica poi, giustificando brevemente la risposta, se l’automa, così arricchito aumenta la potenza riconoscitiva rispetto agli automi a pila tradizionali. In caso positivo, raggiunge la potenza delle macchine di Turing? Soluzioni Esercizio1 Il linguaggio L è riconosciuto dal seguente automa a pila deterministico: a,H/ b,P/ b, H/H a,M/ , Z0/HHHHMZ0 a, P/PP b, N/ a, Z0/NZ0 b, Z0/MZ0 a, N/P b, M/M c, Q/ Q c, Q/ Q a,H/ c, Q/ Q c, Q/ Q c, Q/ Q b,P/ b, H/H a,M/ c, Q/ Q a, P/PP b, N/ a, Z0/NZ0 b, Z0/MZ0 b, M/M a, N/P Legenda: il simbolo Q indica un qualsiasi simbolo Evidentemente non è possibile riconoscere L con una macchina a stati finiti, a causa della necessità di conteggio illimitato sul numero di a e b. Esercizio2 No La grammatica seguente soddisfa la nuova definizione ma genera il linguaggio {anbn | n >= 1} che notoriamente non è regolare. S aA A Sb | b Esercizio 3 Un automa riconoscitore nondeterministico a pila, che possa accedere e modificare anche il fondo della pila può essere formalizzato mediante una 7-pla <Q, I, , , q0, Z0 , F >in cui tutti i simboli hanno lo stesso significato di quelli relativi agli automi a pila tradizionali, con l’unica differenza che la funzione viene estesa nel modo seguente: : Q ( I { }) F (Q * ) dove (q, i, A, B) = {<q’, , C>} significa che l’automa, trovandosi nello stato q, leggendo i dal nastro di ingresso (oppure nel caso di –mossa), A dalla cima della pila, B dal fondo della medesima, in maniera nondeterministica tra le diverse terne possibili, si porta in q’, scrive sulla cima della pila al posto di A e C sul fondo al posto di B. Una configurazione c dell’automa è una 3-pla c = <q, x, >, come per l’automa a pila tradizionale; la relazione di transizione è, parzialmente, definita dalle regole seguentise | 2 < q, i.y, A> |-- <q’, y, > se e solo se <q’, , M> (q, i, A, H) se | = 1 <q, i.y, A> |-- <q’, y, > se e solo se <q’, , M> (q, i, A, A) NB: se <q’, , M> (q, i, A, A) con M, la transizione non è applicabile. Sono però possibili anche altre definizioni: ad esempio che la macchina dia priorità alla riscrittura sulla cima della pila rispetto a quella sul fondo; oppure che comunque la transizione sia possibile solo se il contenuto della pila contiene almeno due caratteri. (la parte rimanente della definizione della relazione di transizione viene data per scontata). Infine x è accettata dall’automa se e solo se < q0, x, Z0 > |-- <q’, , >, per qualche con q’ F, come nel caso dell’automa a pila tradizionale. La potenza dell’automa non aumenta rispetto all’automa a pila tradizionale, poiché l’informazione aggiuntiva che esso può trattare è un’informazione finita (il simbolo in fondo alla pila) e può quindi essere memorizzata attraverso gli stati finiti dell’organo di controllo. Informatica Teorica Seconda prova in itinere - 29 Giugno 2005 Esercizio 1 (punti 6/17-esimi) Si specifichi, mediante opportune pre- e post-condizioni il seguente requisito per un frammento di programma FP: Sia dato un array a di n < NMAX interi positivi; gli n interi sono memorizzati nelle prime posizioni di a, a partire da a[0]; dopo di essi si trova il valore convenzionale 0 usato come “terminatore”. FP deve produrre un nuovo array b, che sia il risultato dell’ordinamento di a in ordine crescente e dell’eliminazione di eventuali ripetizioni. FP usa a come variabile “read-only”. Anche la sequenza dei valori di b deve essere terminata da uno 0. Suggerimento: si consiglia di introdurre la funzione lungh(z) definita su array di NMAX interi che fornisce il numero di valori di z diversi da 0 che precedono il primo 0 (in caso di assenza di uno 0, lungh(z) = -1 per convenzione). Esercizio 2 (punti 7/17-esimi) Si consideri il programma seguente, codificato in un ipotetico linguaggio ispirato al C. int g(int p); int f(char t); main () { char a[20]; int i, z; scanf(a); z = 0 while (i = 0; g(i) != 20; i++) do z = z + f(a[i]); printf(z); } Si assuma che f e g siano due sottoprogrammi “esterni” la cui terminazione sia garantita per ogni valore dei parametri di ingresso. Si dica, motivando brevemente la risposta, se è decidibile il problema di stabilire se il programma main di cui sopra terminerà o meno la sua esecuzione in corrispondenza di un generico –non fissato!- valore del dato di input a. Esercizio 3 (punti 7/17-esimi) Si consideri una sequenza S di elementi che contengano informazione codificabile in un numero limitato a priori di celle di memoria. Si assuma che S si trovi già memorizzata nella memoria di una macchina RAM secondo una delle due tradizionali tecniche: a) come array di celle consecutive b) come lista di elementi collegati tra loro mediante puntatori Si valuti la complessità asintotica sia spaziale che temporale, a meno della relazione , di un algoritmo di ricerca sequenziale nei due casi, facendo uso sia del criterio di costo costante che del criterio di costo logaritmico; si spieghi brevemente come si giunge ai risultati proposti, senza bisogno peraltro di codificare in dettaglio l’algoritmo. Si indichi con precisione il parametro rispetto al quale viene misurata la dimensione dei dati di ingresso, in funzione della quale viene fornita la funzione di complessità. Esercizio 3-bis, Facoltativo (punti 4/17-esimi, valido solo se preceduto da soluzione corretta della parte obbligatoria) Come cambiano le valutazioni di complessità di cui sopra immaginando che il medesimo algoritmo venga eseguito da una Macchina di Turing? Soluzioni Esercizio 1 In primo luogo si definisca la funzione lungh(z) mediante una formula del tipo lungh(z) = n ( (0 n < NMAX z[n]=0 i(0 i < n z[i] = 0)) (n = -1 i(0 i < NMAX z[i] = 0)) ) A questo punto il requisito richiesto può essere specificato dalla seguente coppia per-post-condizione:s {n (lungh (a) n i (0 i n ai 0))} FP {m (lungh (b) m i (0 i m 1 b[i ] b[i 1]) i (0 i lungh (a) j ((0 j m) (a[i] b[ j ]))) j (0 j m i ((0 i lungh (a)) (a[i] b[ j ]))))} Esercizio 2 La risposta è positiva Premessa. Perché il quesito sia significativo occorre ovviamente assumere una macchina astratta che presupponga un dominio totale di dati infinito: in questo caso, il tipo int deve essere l’insieme matematico degli interi. Altrimenti, come noto, la macchina astratta diventa automaticamente un automa a stati finiti e quindi la sua terminazione decidibile. Il dominio dei dati di ingresso del programma in oggetto è però finito, essendo l’insieme degli array di 20 caratteri. Per ognuno dei possibili valori di ingresso la risposta al quesito è semplicemente un sì o un no; esiste quindi una macchina di Turing che fornisce tale risposta, per ogni valore del dato di ingresso a; di conseguenza esiste un numero finito di macchine di Turing, che, opportunamente combinate tra loro, forniscono la risposta corretta per ogni valore del dato di ingresso a; la combinazione di tali macchine può dar luogo ad un’unica macchina che, sul dominio finito dei possibili valori di a, fornisce l’insieme finito delle risposte corrette. Ovviamente, ciò non garantisce la conoscenza di tale macchina; ne garantisce esclusivamente l’esistenza. Equivalentemente e più sinteticamente si può osservare che il problema posto (la decidibilità dell’halt del programma rispetto ai diversi valori di ingresso) è formalizzato da una funzione a dominio finito (l’insieme degli array di 20 caratteri) e codominio {T, F}. Tale funzione è quindi riducibile a una tabella finita, e quindi calcolabile. Si noti anche che la terminazione del programma, essendo garantita la terminazione di una singola esecuzione del corpo del ciclo, dipende solo dalla valutazione della funzione g, che, o non produce mai 20, oppure prima o poi deve produrre il valore 20 per qualche valore di i. Ciò è indipendente dal valore del dato di ingresso a. Quindi la tabella di cui sopra, non dipendendo dai dati di ingresso sarà costituita da tutti T o tutti F. Esercizio 3 Si indichi con n il numero di elementi della sequenza. Poiché ogni elemento contiene informazione codificabile in un numero limitato a priori di celle di memoria, ossia in un numero fissato di byte, è del tutto indifferente assumere come parametro di dimensione dei dati in ingresso il numero n di elementi di S o le celle di memoria utilizzate per memorizzare S. La memorizzazione mediante array richiede una quantità di memoria (n) sia a criterio di costo costante che a criterio logaritmico. La memorizzazione mediante puntatori invece richiede di memorizzare un intero come puntatore per ogni elemento di S. Essendo il numero di elementi di S illimitato, una quantità di memoria richiesta sarà (n) a criterio di costo costante ma (n·log(n)) a criterio logaritmico. La complessità temporale risulterà invece (n) a criterio di costo costante e (n·log(n)) a criterio logaritmico per entrambi i tipi di memorizzazione. Esercizio 3 bis (parte facoltativa) Simulare un array mediante un nastro di macchina di Turing richiede ovviamente uno spazio (n). (n) risulta pure la complessità temporale di un algoritmo di ricerca sequenziale. La memorizzazione di un puntatore in un nastro di macchina di Turing richiede la codifica (ad esempio in binario) di un numero i e quindi un numero (log(i)) di celle. La complessità spaziale risulta perciò (n·log(n)) e l’accesso a un generico elemento richiede pure (n·log(n)), rendendo perciò la complessità totale (n2·log(n)) Informatica Teorica Recupero della prima prova in itinere - 29 Giugno 2005 Esercizio 1 (punti 6+3/13-esimi) Si scrivano degli automi che riconoscano i seguenti linguaggi (k è fissato e > 1): L1 = { x {a,b}* | x = anbkn, n > 0} k L2 = { x {a,b}* | x = anbn , n > 0} Parte facoltativa. Si scriva un automa che riconosca il seguente linguaggio (k è fissato e > 1): L3 = { x {a,b}* | x = anblogk(n), n > 0} NB: non è necessario che gli automi vengano disegnati completamente. Essi devono però essere descritti con sufficiente dettaglio da poter capire quali sono i loro stati e le loro transizioni. Esercizio 2 (punti 6/13-esimi) Si scriva una grammatica che generi il seguente linguaggio: L = { x {a,b,c}* | #xa = 2n, #xb = 4, #xc = n, n > 0} dove con la scrittura #x si intende il numero di occorrenze del carattere nella stringa x. La grammatica scritta è a potenza minima tra quelle che riconoscono L? Si giustifichi la risposta. Soluzioni Esercizio 1 Per riconoscere il linguaggio L1 è sufficiente un automa a pila deterministico che funziona in questa maniera: per ogni a letta, esso mette k A sulla pila. Quando poi arriva a leggere le b, per ogni b letta cancella una B dalla pila. Se l'automa arriva in fondo alla stringa con solo il carattere Z0 sulla pila, la stringa viene accettata, altrimenti viene rifiutata. Per riconoscere il linguaggio L2, invece, è necessaria una MT. Una MT (a 2 nastri) che riconosce L2 può essere fatta in questa maniera. Essa innanzi tutto legge le a e memorizza nel primo nastro un numero di A pari al numero di a lette, mette nel secondo nastro altrettante B. Quindi ripete le seguenti operazioni k-1 volte: ad ogni B del secondo nastro sostituisce un numero di B pari al numero di A nel primo nastro (creando per ogni B da "moltiplicare" ogni volta lo spazio necessario nel secondo nastro, spostando le celle di n posti a partire dal fondo). A questo punto legge le b dal nastro di ingresso, cancellando una B dal terzo nastro per ogni b letta. Se alla fine, quando si è letta l'ultima b, il terzo nastro è vuoto, la MT accetta la stringa, portandosi in uno stato finale. Parte facoltativa. Anche per riconoscere il linguaggio L3 è necessaria una MT. La MT (a 2 nastri) può essere fatta in questa maniera. Essa innanzi tutto legge le a e memorizza nel primo nastro un numero di A pari al numero di a lette. Quindi esegue passate successive sul primo nastro fino a che il primo nastro rimane vuoto, e ad ogni passata fa quanto segue: ad ogni k A del primo nastro sostituisce una sola A; se in fondo al nastro rimane un numero di A minore di k, le ultime A vengono eliminate e basta (di fatto ciò corrisponde a dividere il numero di A per k); scrive una B nel secondo nastro (a meno che nel primo nastro ci fossero meno di k A). A questo punto legge le b dal nastro di ingresso, cancellando una B dal terzo nastro per ogni b letta. Se alla fine, quando si è letta l'ultima b, il terzo nastro è vuoto, la MT accetta la stringa, portandosi in uno stato finale. Una maniera alternativa di risolvere il problema poteva essere di memorizzare sul primo nastro il numero di a lette codificando il numero in base k. logk(n) a questo punto è banalmente il numero di cifre necessarie per codificare n in base k (meno uno), e quindi per verificare che ci siano logk(n) b basta cancellare una cifra della codifica in base k per ogni b letta. Esercizio 2 Una grammatica che genera il linguaggio L è la seguente: S AACS | X X BBBB AC CA CA AC AB BA BA AB CB BC BC CB Aa Bb Cc Tale grammatica non è a potenza minima. Il linguaggio può essere riconosciuto da un automa a pila (deterministico), per cui la grammatica a potenza minima che lo genera è una grammatica non contestuale. Una possibile grammatica non contestuale che genera il linguaggio L è la seguente: S Saac | Saca | Scaa | aSac | aSca | cSaa | aaSc | acSa | caSa | aacS | acaS | caaS | bS 1 S1 S1aac | S1aca | S1caa | aS1ac | aS1ca | cS1aa | aaS1c | acS1a | caS1a | aacS1 | acaS1 | caaS1 | bS2 S2 S2aac | S2aca | S2caa | aS2ac | aS2ca | cS2aa | aaS2c | acS2a | caS2a | aacS2 | acaS2 | caaS2 | bS3 S3 S3aac | S3aca | S3caa | aS3ac | aS3ca | cS3aa | aaS3c | acS3a | caS3a | aacS3 | acaS3 | caaS3 | b Informatica Teorica Appello del 7 – 7 2005 Esercizio 1 (punti 15) Si consideri il seguente linguaggio Lstud formato dalle parole p così formate: {p = N6Vk | N 0..9, V {a, b, c, d}, k <= 30} (cioè composte da 6 cifre, seguite da al massimo 30 caratteri, in cui ogni carattere è o a, o b, o c, o d), in cui le 6 cifre rappresentato i numeri di matricola degli studenti immatricolati al Politecnico di Milano nell'anno 2001/2002, e i caratteri seguenti i voti conseguiti negli esami superati (d per un voto da 18 a 21, c per uno da 22 a 24, b per uno da 25 a 27, a per uno da 28 a 30). Si dica, giustificando brevemente la risposta: a. quale è l'automa a potenza minima in grado di riconoscere il linguaggio Lstud; b. se è decidibile il problema di stabilire se ci sono 2 studenti diversi con gli stessi voti; c. quale è la complessità minima per risolvere il problema di appartenenza di una stringa al linguaggio Lstud. Esercizio 2 (punti 8) Si specifichi mediante opportune formule del prim’ordine il seguente comportamento di un ipotetico sistema. Tutte le volte che, in un certo istante, si riceve il segnale Start, per i 10 istanti istanti successivi viene emesso un segnale intermittente (con intermittenza di 1 istante) Blink (per esempio, se viene ricevuto il segnale Start all'istante 6, il segnale Blink viene emesso agli istanti 8, 10, 12, 14 e 16). Due segnali di Start successivi sono a distanza l'uno dall'altro di almeno 15 istanti di tempo. Esercizio 3 (punti 7) Si costruisca una grammatica G che generi il seguente linguaggio L: L = {an(bc)m| n, m >= 1, m < n/2} E’ preferibile una grammatica a potenza minima, ossia regolare se ne esiste una, non contestuale se ne esiste una ma non ne esiste una regolare, ecc. Nel caso, si spieghi brevemente perché non esistono grammatiche appartenenti a classi inferiori a quella proposta. Soluzioni Esercizio 1 a. Il inguaggio è formato da un numero finito di parole, quindi può essere riconosciuto da un automa a stati finiti (addirittura, da un automa senza cicli). b. Essendo il linguaggio finito, il problema è decidibile. c. Il problema del riconoscimento di può risolvere con complessità O(1) (cioè costante) in quanto il linguaggio è finito. Esercizio 2 Codificando la ricezione/emissione di un segnale S all'istante t con il predicato S(t), le formule seguenti specificano il comportamento desiderato: t ( Start(t ) t1 (1 t1 5 Blink (t 2t1 ))) t 2 , t 3 ( Start(t 2 ) Start(t 3 ) t 2 t 3 15) Esercizio 3 L è generato dalla seguente grammatica non contestuale (e da nessuna grammatica regolare essendo necessaria una pila per il suo riconoscimento): S aaaabc | ASB A aa B bc | Informatica Teorica Prova d'esame - 13 Luglio 2005 Esercizio 1 (punti 8/30-esimi) Si scriva un automa che riconosca il linguaggio L le cui stringhe sono costruite sull'alfabeto A={0, 1} e sono fatte nella seguente maniera: le stringhe hanno lunghezza dispari; se il primo e l'ultimo carattere della stringa sono entrambi uguali ad '1', il carattere di centro è anch'esso uguale ad '1', altrimenti il carattere di centro è uguale a '0'. NB: il punteggio massimo verrà assegnato solo se l'automa ideato sarà a potenza riconoscitiva minima tra quelli che riconoscono il linguaggio desiderato. Esercizio 2 (punti 8/30-esimi) Descrivere (senza necessariamente codificarla nei dettagli) una macchina RAM che riconosce il linguaggio L descritto nell'esercizio 1, e se ne dia la complessità spaziale e temporale a costo costante e a costo logaritmico. Esercizio 3 (punti 8/30-esimi) Scriva una formula logica che descrive un segnale fatto nella seguente maniera: dal momento in cui il segnale viene emesso la prima volta (che potrebbe anche non essere l'istante 0), esso viene emesso ad intervalli che si raddoppiano continuamente. L'intervallo tra i primi due istanti di emissione può essere qualunque. In altre parole, se la distanza fra la (k-1)-esima emissione e la k-esima emissione è d, la distanza tra la k-esima e la (k+1)-esima emissione è 2d. Un esempio possibile tra i tanti di evoluzione temporale del segnale è la seguente (vengono indicati gli istanti in cui il segnale viene emesso; si noti che l'intervallo tra le prime due emissioni è pari a 3 istanti di tempo): 2, 5, 11, 23, 47, 95, 191, ... Esercizio 4 (punti 8/30-esimi) parte a. Siano date le seguenti pre- e post- condizioni di un metodo Java che ha un parametro in ingresso arg di tipo String, ritorna un int, e può sollevare un'eccezione ComputationException: Pre: arg null 1 length(arg) 50 i, j(1 i < j length(arg) arg[i] arg[j]) Post: result > 0 raise ComputationException laddove result indica il valore ritornato dal metodo (se questo ritorna senza sollevare eccezioni) e raise ComputationException indica il fatto che viene sollevata un'eccezione ComputationException; inoltre, length(arg) indica la lunghezza della stringa arg, e arg[i] indica l'i-esimo carattere della stringa. E' decidibile il problema di stabilire se un'implementazione I soddisfa la specifica data sopra? Si motivi adeguatamente la risposta. parte b. Sia data la seguente implementazione int myImpl(String arg) throws ComputationException { int sum = 0, i = 1; try { while(sum < (int)Math.pow(23.5, 4.21)){ int diff = (int)(arg.charAt(i-1)-arg.charAt(0)); sum += (int)(diff*Math.pow(4.67, 2.9)); if (i == arg.length()) i = 1; else i++; } } catch (Exception e) { throw new ComputationException(); } return sum; } E' decidibile il problema di stabilire se myImpl soddisfa la specifica descritta sopra? Soluzioni Esercizio 1 Il linguaggio L è riconosciuto dal seguente automa a pila nondeterministico: 1,Z0/Z0 0,Z0/Z0 1,A/ 0,A/ 1,A/ 0,A/ , Z0/AZ0 q0 0,A/ q1 q2 , Z0/Z0 qF 1,A/ 0,A/ 1,Z0/ 1,A/ q4 q3 1,A/ q6 ,Z0/Z0 0,A/ 0,A/ 1,A/ 0,A/ q5 0,A/ 1,A/ Evidentemente non è possibile riconoscere L con una macchina a stati finiti, visto che le stringhe di L possono essere arbitrariamente lunghe, nè con un automa a pila deterministico, che non e’ in grado di “indovinare” il punto centrale della stringa. Esercizio 2 Una semplice macchina RAM che riconosce il linguaggio è fatta nella seguente maniera. Innanzi tutto, essa legge una volta i caratteri in ingresso; ogni carattere letto viene memorizzato, e contemporaneamente si incrementa un contatore che mi dice quanti caratteri ho letto fino a quel momento. Alla fine della lettura, se ho contato un numero di caratteri pari, segnalo su nastro di uscita che la stringa non è accettata. Se invece ho contato un numero di caratteri dispari, vado a leggere il primo carattere, l'ultimo, e quello di mezzo (per recuperare l'offset del quale rispetto al primo carattere basta dividere per 2 il numero di caratteri letti). Se questi sono tutti uguali ad 1, oppure se quello di centro ed almeno uno tra il primo e l'ultimo sono uguali a 0, accetto la stringa, segnalandolo sul nastro di uscita, altrimenti rifiuto. A costo costante, sia la complessità spaziale che quella temporale sono (n). A costo logaritmico, la complessità spaziale è ancora (n), mentre quella temporale è (n·log(n)). Esercizio 3 Indicando, come al solito, col predicato e(t) che il segnale viene emesso al tempo t, una possibile soluzione è: t1, t2 ( t1 < t2 e(t1) e(t2) t’ ( t1 < t’ < t2 e(t’) ) e(t2 + 2 (t2 t1)) t’ ( t2 < t’ < t2 + 2 (t2 t1) e(t’) ) ) Esercizio 4 parte a. Non è decidibile. Una maniera per dimostrarlo potrebbe essere tramite il Teorema di Rice: l'insieme delle implementazioni (cioè delle MT, visto che si può tradurre un programma Java in una MT equivalente) che soddisfano la specifica non è certamente l'insieme vuoto (esiste almeno una funzione che soddisfa la specifica), e non è certamente neanche l'insieme universo (è banale pensare ad una funzione che non soddisfa la specifica), quindi il problema di stabilire se una data MT appartiene all'insieme non è decidibile. Una maniera alternativa potrebbe riducendo il problema della terminazione al problema del soddisfacimento della specifica. Preso un programma qualunque P (facendo attenzione che in P non compaia il parametro arg) basta in effetti costruire un metodo siffatto: int Pridotto(String arg) throws ComputationException { P return 1; } Tale metodo soddisfa la specifica se e solo se P termina. Se sapessi risolvere il problema di partenza, saprei anche risolvere il problema della terminazione di un programma qualunque, che è un assurdo. parte b. In questo caso, il problema è banalmente decidibile. Infatti, l'implementazione è in questo caso fissata a myImpl, quindi si danno 2 soli casi: o myImpl soddisfa le specifiche, oppure non le soddisfa. La risposta è quindi in questo caso binaria, o sì o no, e la MT che risolve il problema o è quella costante uguale ad 1, oppure è quella costante uguale a 0. In entrambi i casi essa è banalmente calcolabile. Informatica Teorica (Sez. Mandrioli) Appello del 13 Settembre 2005 Esercizio 1 (punti 10/30-esimi) Si scrivano un automa e una grammatica che, rispettivamente, riconosca e generi il linguaggio L = {anamaman | n, m >= 1, n pari, m dispari}. NB: il punteggio massimo verrà assegnato solo se l'automa ideato sarà a potenza riconoscitiva minima tra quelli che riconoscono il linguaggio desiderato e la grammatica avrà il minimo numero di produzioni. Esercizio 2 (punti 10/30-esimi) Si scriva una formula logica che descrive la seguente regola per controllare atterraggi e decolli in un aeroporto: Se c’è un aereo in fase di decollo nessun altro aereo può decollare entro 3 minuti dall’inizio del decollo e nessun altro aereo può atterrare entro 5 minuti dall’inizio del decollo dell’aereo precedente; Se c’è un aereo in fase di atterraggio nessun altro aereo può atterrare entro 3 minuti dall’inizio dell’atterraggio e nessun altro aereo può decollare entro 5 minuti dall’inizio dell’atterraggio dell’aereo precedente. Esercizio 3 (punti 10/30-esimi) Dire, giustificando brevemente la risposta, se la seguente funzione f: N N è: a) Computabile b) Totale. f(n) = n-esimo numero primo. Per convenzione, si assuma f(0) = 1, e, di conseguenza, f(1) = 2, f(2) = 3, f(3) = 5, … Soluzioni Esercizio 1 La definizione di L equivale a L = {a2n| n dispari e >= 2}, ossia L = {a6 , a10, a14, a18, …}, ossia, detto in altra maniera L = { a2(2l+1) | l 1 } = { a4l+2 | l 1 }. Quindi L può essere riconosciuto mediante il seguente semplice automa a stati finiti: a a a a a a a a a a Da esso si può ricavare immediatamente una grammatica regolare equivalente, che può essere “compattata” nella seguente grammatica (non contestuale!) per minimizzare il numero di produzioni: S a4A A a4A| a2 Esercizio 2 Si definscano i predicati StartTakeOff (x, t) e StartLand(x, t) per indicare, rispettivamente, che l’aereo x ha iniziato il decollo o l’atterraggio all’istante t. Il requisito richiesto è allora formalizzato dalla formula seguente: t , x( StartTakeOff ( x, t ) y, t1 ( y x (t t1 t 3) StartTakeOff ( y, t1 )) y, t1 ( y x (t t1 t 5) StartLand ( y, t1 )) ) t , x( StartLand ( x, t ) y, t1 ( y x (t t1 t 3) StartLand ( y, t1 )) y, t1 ( y x (t t1 t 5) StartTakeOff ( y, t1 )) ) Altri predicati e formule, non strettamente necessari ai fini della formalizzazione del requisito ma utili a chiarire il significato dei termini potrebbero definire la fase di atterraggio/decollo dell’aereo x come quella compresa tra i relativi inizio (Start) e fine (End). Esercizio 3 La funzione f è computabile: essendo infatti decidibile se un numero sia primo o no, dopo aver costruito l’n-esimo numero primo si può ottenere l’n+1-esimo enumerando tutti i numeri ad esso successivi fino ad ottenere il prossimo numero primo. f è anche totale perché i numeri primi sono infiniti. Quindi, per ogni n, esiste l’n+1-esimo numero primo che verrà individuato dall’algoritmo suddetto. Informatica Teorica (Nuovo e Vecchio Ordinamento) Appello del 6 Febbraio 2006 Esercizio 1 (Punti 15) Si formalizzino mediante formule logiche del prim’ordine le regole del gioco “Sudoku”. Informalmente le regole sono le seguenti: E’ dato un quadrato di 9 * 9 caselle, ognuna delle quali deve contenere un numero intero compreso tra 1 e 9. Il quadrato è suddiviso in 9 “sottoquadrati” di 3 * 3 caselle (il primo “copre” le caselle [1..3 * 1..3]; il secondo [4..6* 1..3], ecc.) Occorre riempire le caselle del quadrato in modo che: Ogni riga e ogni colonna contenga tutti i numeri tra 1 e 9 Ogni “sottoquadrato” contenga tutti i numeri tra 1 e 9. Facoltativamente (ulteriori punti 1): potrebbe il problema essere generalizzato rispetto alle dimensioni del quadrato? Se sì, come? Esercizio 2 (punti 7) Si dica, giustificando brevemente la risposta, se il suddetto problema del Sudoku, ossia stabilire se, assegnati alcuni valori ad alcune caselle esiste un modo di riempire le altre in modo da soddisfare le regole, è decidibile o no. Come cambia la risposta (se cambia), se il problema è espresso nella sua forma generalizzata? Esercizio 3 (punti 8) Si descrivano brevemente (senza necessariamente "codificarli" in dettaglio) algoritmi per il riconoscimento del linguaggio {anbn | n >= 1} con le seguenti caratteristiche: Una macchina di Turing che minimizzi la complessità temporale Una macchina di Turing che minimizzi la complessità spaziale Una RAM che minimizzi la complessità temporale Una RAM che minimizzi la complessità spaziale E si confrontino le funzioni di complessità così ottenute. Soluzioni Esercizio 1 Si formalizzi la tabella del Sudoku mediante un array (si ricordi che, in termini matematici, un array altro non è che una funzione). Le regole del gioco sono allora formalizzate dalla formula seguente: i, j (1 i, j 9 1 a i, j 9) i, j, k (1 i, j, k 9 a i, j a i, k i, j, k (1 i, j, k 9 a i, j a k , j i, j, k , h((1 i, j, k , h 9 i / 3 k / 3 j / 3 h / 3 i k j h ) a i, j a k , h NB. il simbolo '/' indica la divisione a risultato intero. La generalizzazione al caso di un quadrato k*k è banale se si ha l'accortezza di scegliere un valore di k che sia un quadrato perfetto. In tal caso k rimpiazza il numero 9 e k rimpiazza il numero 3 nella formula precedente. Esercizio 2 Il problema è chiaramente decidibile in quanto è riconducibile del tutto a un problema finito. Infatti, ogni griglia 9 * 9 può essere riempita con numeri da 1 a 9 (rispettando le regole) in un numero finito di modi diversi. (Contare il numero esatto di schemi diversi non è banale, ma è sufficiente capire che esso è finito. Per curiosità, tale numero è stato calcolato essere uguale a 6 670 903 752 021 072 936 960). Pertanto un algoritmo che provi esaustivamente tutte le possibili soluzioni termina sicuramente. Anche nal caso generalizzato, il problema rimane decidibile. Per ogni n fissato, ogni schema di n2 * n2 celle ha un numero finito di possibili completamenti (sicuramente meno di n2n^4), per cui possono essere provati esaustivamente tutti. Il problema è però computazionalmente oneroso, NP-completo per la precisione, come mostrato in: T. Yato, "Complexity and completeness of finding another solution and its application to puzzles". Master's thesis, University of Tokyo, Department of Information Sciences, 2003. Esercizio 3 1. Macchina di Turing che minimizzi la complessità temporale. E' sufficiente "simulare" con la macchina di Turing un automa a pila, usando un nastro di memoria come una pila. La complessità temporale risultante sarebbe (n), che è facile capire essere il meglio ottenibile. 2. Macchina di Turing che minimizzi la complessità spaziale. In questo caso conviene contare in codifica binaria (o equivalentemente, in altra base > 1) il numero di 'a' ricevute e poi decrementare il contatore binario per ogni 'b' ricevuta. La complessità spaziale sarebbe così (log n), ottenuta però al prezzo di un peggioramento di un fattore logaritmico della complessità temporale. 3. RAM che minimizzi la complessità temporale. Si può replicare la soluzione della macchina di Turing al punto 1 con una RAM, scrivendo un marker in n celle adiacenti. La complessità temporale risultante è la stessa (n), con criterio di costo costante. Con criterio di costo logaritmico essa sale invece a (n log n), dal momento che anche se scrivo un valore costante (il marker) nelle celle adiacenti, ad ogni accesso devo manipolare un puntatore all'elemento corrente, che è un numero maggiorato da n. 4. RAM che minimizzi la complessità spaziale. In questo caso conviene utilizzare un singolo contatore intero in una singola cella di memoria. In questo modo il costo a criterio di costo costante è semplicemente (1) (uso di un numero costante di celle di memoria), mentre a costo logaritmico diventa (log n), che è una caratterizzazione del fatto che la RAM di fatto "implementa" una codifica binaria del dato. Informatica Teorica Prima prova in itinere - 12 Maggio 2006 Si svolgano i seguenti esercizi. Il tempo complessivo a disposizione è di 1h e 30 minuti. Esercizio 1 (Punti 6/13-esimi senza la parte opzionale c), che comporta ulteriori 3 punti) Si consideri la seguente variante di automa a pila, detto automa a pila visibile (APV). L’alfabeto di ingresso I dell’automa è partizionato in tre sottoinsiemi Ipush, Ipop, Ilocal, che determinano indirettamente come la pila viene gestita durante il riconoscimento: se il carattere letto appartiene a Ipush, allora l’automa deve effettuare una push (ossia aggiungere esattamente un carattere alla cima della pila, senza rimuoverne alcuno); se il carattere letto appartiene a Ipop, allora l’automa deve effettuare una pop (ossia rimuovere il carattere in cima alla pila, senza aggiungerne altri); se infine il carattere appartiene a Ilocal, l’automa non deve modificare il contenuto della pila. Si noti che ad ogni mossa è possibile modificare al più un carattere della pila. Per il resto l’automa si comporta come un normale automa a pila. a) Si formalizzi l’automa a pila visibile in versione nondeterministica, nonché le regole di funzionamento e di riconoscimento di stringhe (mediante le usuali nozioni di configurazione, transizione, accettazione, ecc.). Per semplicità non si considerino le mosse. b) Si confronti poi la potenza riconoscitiva degli APV con quella degli automi a stati finiti. c) Opzionale: si confronti la potenza riconoscitiva degli APV con quella degli automi a pila standard. (E’ sufficiente una argomentazione non pienamente formale) Esercizio 2 (Punti 4/13-esimi) Si consideri il linguaggio L su alfabeto = {a,b,c,p,q, z}, composto da tutte e sole le stringhe che: se iniziano per ‘a’, hanno ‘z’ come penultimo carattere (in questo caso sono lunghe almeno 3 caratteri), e se hanno ‘c’ come terzo carattere, allora hanno ogni occorrenza di ‘p’, successiva al terzo carattere, seguita immediatamente da una occorrenza di ‘q’. Si scriva un automa a potenza minima tra quelli noti che accetta il linguaggio L. Esercizio 3 (Punti 4/13-esimi) Si scriva una grammatica che genera il linguaggio L1 definito sull’alfabeto = {(, ),*}; le stringhe di L1 o contengono esclusivamente parentesi tonde, e, in tal caso, devono essere ben parentetizzate, oppure, se contengono almeno un *, sono del tutto libere, cioè sono sequenze arbitrarie di (, ),*. Anche in questo caso è preferibile una grammatica a potenza minima tra quelle che generano L1. Soluzioni Esercizio 1 Un automa riconoscitore nondeterministico a pila visibile (APV) è definito come una 7-pla < Q, I, , , q0, Z0, F > con tutti i simboli col significato degli automi a pila tradizionali. In più I è partizionato nei tre sottoinsiemi Ipush, Ipop, Ilocal, ossia I = Ipush Ipop Ilocal e Ipush Ipop = Ipop Ilocal = Ipush Ilocal = La funzione di transizione è definita : Q I (Q Q ) Transizione di configurazione: c = (q, a.x, c' = (q', x', '), con a I, x I*, se a Ipush e <q', > (q, a, ), allora ' = se a Ipop e q' (q, a, ), allora ' = se a Ilocal e q' (q, a, ), allora ' = La configurazione dell’automa, le relazione di transizione e la condizione di accettazione sono definite in maniera del tutto analoga al caso degli automi a pila standard (senza mosse . La potenza espressiva degli APV è strettamente maggiore di quella degli automi a stati finiti; infatti, il linguaggio non regolare {anbn | n > 0} è accettato da un APV con Ipush = {a}, Ipop = {b}, Ilocal = , con l’accorgimento di avere un carattere extra di pila per poter accettare a pila non vuota. D’altro canto è evidente che ogni automa a stati finiti può essere espresso come un banale automa APV. Il confronto con gli automi a pila standard è più complesso. Consideriamo il linguaggio {wcwR | w{a,b}*}, riconosciuto da un automa a pila deterministico standard (e dunque a maggior ragione da uno nondeterministico), mediante la seguente tecnica: si impilano i caratteri letti finchè si incontra il carattere c; a questo punto verifica che i rimanenti caratteri letti (ossia quelli di wR) siano esattamente quelli che sono in pila, togliendoli dalla cima. Siccome ciascun carattere viene incontrato due volte – uno in w e uno in wR – e per la prima occorrenza è necessario fare una push, mentre per la seconda una pop, non è possibile partizionare l’alfabeto di pila secondo quanto richiesto dagli APV per effettuare il riconoscimento richiesto. In conclusione gli APV sono meno espressivi degli automi a pila standard (anche solo deterministici). Gli APV (in inglese, visibly pushdown automata), sono stati introdotti in: Alur e Madhusadan: “Visibly pushdown languages”, Proceedings of the 36th ACM Symposium on Theory of Computing (STOC’04), pp. 202-211, 2004. Esercizio 2 Un automa a stati finiti è sufficiente per accettare L; eccone una versione nondeterministica (gli stati in grigio sono di accettazione). \{p} a c p q \{c} z z \{p} z \{a} \{p} p c q \{c} Si noti che la definizione informale del linguaggio poteva ammettere anche un’interpretazione più complicata ma comunque corretta, ossia che la condizione “e se hanno ‘c’ come terzo carattere, allora hanno ogni occorrenza di ‘p’, successiva al terzo carattere, seguita immediatamente da una occorrenza di ‘q’.” si applicasse alle sole stringhe che iniziano per ‘a’. Esercizio 3 La seguente grammatica noncontestuale genera L1. S → B | Q B → BB | (B) | Q → A*A A → *A | (A | )A | Anche in questo caso, sono ammissibili interpretazioni leggermente diverse, in particolare se la stringa nulla appartenga a L1 e se una stringa ben parentetizzata debba comunque avere un’unica coppia di parentesi più esterna. Informatica Teorica Seconda prova in itinere 5 Luglio 2006, Sezione Mandrioli Il problema della Torre di Hanoi è così definito. Vi sono n dischi simili ma di dimensioni diverse inseriti in un piolo, in modo tale che il disco più grande sia nel punto più basso e tutti gli altri siano sopra di esso in ordine decrescente. Esistono altri due pioli inizialmente liberi (si veda la Figura (a)). Si vogliono trasportare tutti i dischi su un altro piolo, spostandoli uno alla volta da un piolo all’altro, e operando in modo tale che mai un disco sia appoggiato sopra uno più piccolo (ovviamente, per spostare un disco da un piolo all’altro occorre aver rimosso quelli sovrastanti, sempre rispettando le regole precedenti). Le Figure (b) e (c) completano l’illustrazione del problema. Figure (a), (b), (c) Il problema della torre di Hanoi: (a) situazione iniziale, (b) situazione finale richiesta, (c) situazione inammissibile. Esercizio 1 (punti 8/17-esimi) Si formalizzi mediante formule del prim’ordine una generica situazione ammissibile della posizione dei dischi nei pioli: ad esempio le figure (a) e (b) rappresentano due situazioni ammissibili al contrario della figura (c). Esercizio 1.bis(da svolgere facoltativamente solo dopo aver svolto tutti gli altri esercizi. L’esercizio vale ulteriori punti 3/17-esimi) Si formalizzi, sempre mediante formule del prim’ordine, la relazione che deve sussistere tra due diverse situazioni ammissibili perché l’una sia ottenibile dall’altra mediante una mossa lecita. Esercizio 2 (punti 4/17-esimi) Si dica se il seguente problema è decidibile: Dato un algoritmo A qualsiasi, stabilire se A risolve correttamente il problema della Torre di Hanoi. Giustificare brevemente la risposta. Esercizio 3 (punti 5/17-esimi) Dovendo valutare la complessità di un algoritmo per la soluzione del problema della Torre di Hanoi da eseguire mediante un normale calcolatore basato sulla classica architettura di von Neumann (macchina RAM), quale criterio di costo risulterebbe più adeguato e conveniente? Giustificare brevemente la risposta. Esercizio 3bis, facoltativo (ulteriori punti 2/17-esimi) Che relazione è “naturale” aspettarsi tra complessità (sia spaziale che temporale) di un algoritmo per la soluzione del problema, valutata a criterio costante e a criterio logaritmico? NB. Non si chiede di descrivere un algoritmo né di valutarne le complessità; bensì di stabilire come cambia la valutazione di complessità cambiando il criterio di costo. Avvisi importanti 1. Il tempo disponibile per lo svolgimento della prova è 1 ora e 30 minuti. 2. L’eventuale soluzione dell’Esercizio 1.bis sarà presa in considerazione e valutata solo se tutti gli altri esercizi saranno stati risolti in maniera ritenuta soddisfacente. 3. Si ricorda che possono svolgere questa prova in itinere solo coloro che abbiano ottenuto almeno 5 punti nella prima prova. Eccezionalmente sono ammessi anche gli studenti laureandi, che devono indicare esplicitamente la loro situazione nella testata del loro elaborato. Come già comunicato, in caso di esito positivo nella presente prova, verranno loro comunicate le modalità di recupero della prima prova. 4. Come in altre occasioni i risultati e le successive comunicazioni (in particolare le modalità di accettazione/rifiuto del voto proposto) saranno pubblicati nella pagina personale di Dino Mandrioli sul sito ufficiale del Dipartimento. Verrà data precedenza alla correzione dei compiti dei laureandi (che risultino tali dall’archivio ufficiale del CEDA) Soluzioni Esercizio 1 Si indichi d) con Di l’i-esimo disco: 1 <= i <= n; e) con dim(Di) la dimensione del disco i-esimo; (i ((1 <= i <= n ) (1 <= dim(Di) <= n))) (i,j (((1 <= i, j <= n ) (i j)) (dim(Di) dim(Dj)))) f) con pos(Di) la posizione del disco i-esimo: pos(Di) = <h,p>; 1 <= h <= n; 1 <= p <= 3; che indica che il disco si trova ad altezza h nel piolo p. g) la funzione pos deve sottostare ai seguenti vincoli: h) i,j (pos(Di) = pos(Dj) Di = Dj) i) i,h, k, p ((pos(Di) = <h,p> k < h) j (pos(Dj) = <k,p>)) j) i,j, h, k, p ((pos(Di) = <h,p> pos(Dj) = <k,p> k < h) (dim(Dj) > dim(Di))) Esercizio 1.Bis Si indichino con pos1 e pos2, rispettivamente, due funzioni che definiscono la posizione del disco i-esimo prima e dopo l’esecuzione di una mossa. Ovviamente sia pos1 che pos2 devono soggiacere ai vincoli formalizzati precedentemente. Inoltre esse soddisfare la relazione espressa dalle formule seguenti: Se un disco qualsiasi non si trova in cima a un piolo, la sua posizione rimane invariata nel passaggio da pos1 a pos2: i,h, p ((pos1(Di) = <h,p> k, j (k > h pos1(Dj) = <k,p>)) (pos2(Di) = <h,p>)) Se (per ogni tripla di dischi Di1, Di2, Di3 e posizioni): i1,i2, i3, h1, h2, h3, p1, p2, p3 o il disco Di1 si trova in cima al piolo p1: ( (pos1(Di1) = <h1,p1> k, j (k > h1 pos1(Dj) = <k,p1>)) o e il disco Di2 si trova in cima al piolo p2: (pos1(Di2) = <h2,p2> k, j (k > h2 pos1(Dj) = <k,p2>)) o e il disco Di3 si trova in cima al piolo p3: (pos1(Di3) = <h3,p3> k, j (k > h3 pos1(Dj) = <k,p3>)) o e i tre dischi Di1 sono diversi tra loro, e stanno sui tre pioli diversi (i1 i2 i2 i3 i1 i3 p1 p2 p2 p3 p1 p3) ) allora: o uno (e uno solo) tra Di1, Di2, e Di3 cambia piolo in pos2 (e, necessariamente per i vincoli su pos, viene a trovarsi in cima al nuovo piolo) h, p ( (pos2(Di1) = <h,p> p p1 pos2(Di2) = pos1(Di2) pos2(Di3) = pos1(Di3)) (pos2(Di2) = <h,p> p p2 pos2(Di1) = pos1(Di1) pos2(Di3) = pos1(Di3)) (pos2(Di3) = <h,p> p p3 pos2(Di1) = pos1(Di1) pos2(Di2) = pos1(Di2)) ) Soluzione alternativa Definiamo che la differenza tra pos1 e pos2 riguarda un solo disco, che deve essere in cima ad un piolo in pos1 (e che sarà in cima ad un piolo in pos2 per i vincoli sui pioli): Di, h, p ( pos1(Di) = <h,p> pos2(Di) <h,p> j (pos1(Dj) = <h+1,p>) j ( j i pos1(Dj) = pos2(Dj) ) ) /* Di cambia posizione */ /* Di è in cima ad un piolo in pos1 */ /* tutti gli altri dischi rimangono fermi */ Si noti che potremmo semplificare la condizione eliminando il vincolo che Di in pos1 sia in cima ad un piolo, in quanto ciò è garantito dal fatto che in pos2 non ci possono essere "buchi", e dal fatto che l'unico disco ad essere spostato è D i: Di, h, p ( pos1(Di) = <h,p> pos2(Di) <h,p> j ( j i pos1(Dj) = pos2(Dj) ) ) /* Di cambia posizione */ /* tutti gli altri dischi rimangono fermi */ Se invece volessimo specificare, per maggiore chiarezza, che nella nuova posizione D i deve essere in cima ad un piolo, potremmo modificare la condizione come segue: Di, h, p ( pos1(Di) = <h,p> pos2(Di) <h,p> j (pos1(Dj) = <h+1,p>) h', p' ( pos1(Di) = <h',p'>) j (pos2(Dj) = <h'+1,p'>) ) j ( j i pos1(Dj) = pos2(Dj) ) ) /* Di cambia posizione */ /* Di è in cima ad un piolo in pos1 */ /* Di è in cima ad un piolo anche in pos2 */ /* tutti gli altri dischi rimangono fermi */ Le due seguenti ulteriori soluzioni alternative descrivono in maniera completa non solo i vincoli sul posizionamento dei dischi nei pioli e sul loro movimento, ma anche l’obiettivo del gioco. Esercizio 1 + 1.Bis, alio modo Si introduca la seguente funzione: piolo(p, h, t) = d se e solo se d è la dimensione del disco che si trova ad altezza h sul piolo p al tempo t Una possibile formalizzazione del problema della Torre di Hanoi è la seguente (con implicite quantificazioni universali esterne): vincoli sui domini: piolo(p, h, t) = d 1 p 3 1 h n 1 d n unicità del disco: piolo(p1, h1, t) = piolo(p2, h2, t) p1 = p2 h1 = h2 assenza di "buchi" sul piolo: piolo(p, h, t) = d h > 1 d1(piolo(p, h-1, t) = d1) vincolo sull'ordinamento dei dischi sul piolo: piolo(p, h1, t) > piolo(p, h2, t) h1 < h2 Si introducano poi i seguenti predicati e funzioni: altezza(p, t) = h se e solo se h è l'altezza del piolo p al tempo t muovi(p1, p2, t) se e solo se all'istante t il disco che si trova in cima al piolo p 1 è spostato in cima al piolo p2 Una possibile formalizzazione dell'evoluzione del gioco della Torre di Hanoi è la seguente (con implicite quantificazioni universali esterne): definizione della funzione "altezza", che deriva da "piolo": altezza(p, t) = h (h > 0 d(piolo(p, h, t) = d) d(piolo(p, h+1, t) = d)) (h = 0 d(piolo(p, 1, t) = d))) una è mossa possibile solo se il piolo di partenza non è vuoto e se il piolo di arrivo è diverso da quello di partenza: muovi(p1, p2, t) altezza(p1, t) > 0 p1 p2 non è possibile effettuare 2 mosse contemporaneamente: muovi(p1, p2, t) muovi(p3, p4, t) p1 = p3 p2 = p4 effetto di una mossa sullo stato di un piolo: piolo(p, h, t) = d (p = 1 h = n - d +1 t1, p1, p2(t1 < t muovi(p1, p2, t1))) t1 (t1 < t altezza(p, t1) = h-1 p1( muovi(p1, p, t1) piolo(p1, altezza(p1, t1), t1) = d t2 (t1 < t2 < t altezza(p, t2) = h p1 (muovi(p, p1, t2)) ))) stato iniziale del gioco: i(1 i n piolo(1, i, 0) = n - i + 1) altezza(2, 0) = 0 altezza(3, 0) = 0 o si noti che la seconda e terza condizione sono superflue, in quanto se tutti i dischi sono sul primo piolo, sugli altri non ci può essere nulla stato finale del gioco: t (i(1 i n piolo(3, i, t) = n - i + 1) altezza(1, t) = 0 altezza(2, t) = 0) Esercizio 1 + 1.Bis, yet another Insiemi: D = {1,2,..,n} dischi; P = {1,2,3} pioli; tempo N. Variabili: t N; d,d',d" D; p,p',p" P. Predicati: piolo(p,d,t): il disco d è sul piolo p al tempo t mossa(p,p',t): si muove dal piolo k a k' al tempo t on(d,d',t): il disco d è immediatamente sopra d' al tempo t (serve solo per descrivere la situazione iniziale) Formule: unicità dischi su pioli: piolo(p,d,t) p' (p' p piolo(p',d,t)) definizione di disco più in alto: top(p,d,t) (piolo(p,d,t) d' (d' < d piolo(p,d',t)) d = n+1 d' piolo(p,d',t)) situazione iniziale: init(t) (1 =< d < n on(d,d+1,t)) (on(d,d',t) piolo(1,d,t) piolo(1,d,t')) situazione finale: end(t) d piolo(3,d,t) mossa: mossa(p,p',t) top(p,d,t) top(p',d',t) d' > d piolo(p',d,t+1) d",p" (d" d piolo(p",d",t) piolo(p",d",t+1)) partita: init(0) t (end(t) p,p' mossa(p,p',t)) Esercizio 2 Si tratta di un classico caso di applicazione del teorema di Rice. Infatti, il problema può essere visto come una specifica funzione (il cui valore, per una data configurazione iniziale, potrebbe essere la sequenza di mosse, se esiste, che porta alla desiderata configurazione finale). Tale funzione è ovviamente calcolabile. Quindi considerando l’insieme costituito esattamente da tale funzione, non è decidibile, in base al teorema di Rice, se un generico algoritmo calcola esattamente la funzione considerata. Esercizi 3 e 3 bis Ovviamente il criterio di costo logaritmico fornisce sempre la garanzia di risultati realistici. In questo caso, tuttavia esso risulterebbe superfluo e quindi inutilmente oneroso da applicare. Si osservi infatti che una quantità di memoria limitata linearmente dal numero n di dischi è sufficiente per rappresentare qualsiasi configurazione del sistema (ad esempio un array che indichi la posizione di ogni disco costerebbe (n) a criterio di costo costante e (n.log(n)) a criterio logaritmico). L’applicazione di ogni mossa richiederebbe perciò un tempo costante a criterio di costo costante e al più (log(n)) a criterio di costo logaritmico. Ne consegue che qualsiasi sia la complessità T(n) di un algoritmo (ovviamente che non usi la memoria in modo scioccamente inefficiente) calcolata a criterio di costo costante, la corrispondente complessità calcolata a criterio di costo logaritmico sarebbe automaticamente (T(n).log(n)). Si noti tuttavia che la funzione T(n) invece sarà probabilmente di un ordine di grandezza molto elevato data la natura “a ricorsione fortemente nidificata” dei normali algoritmi per risolvere il problema. Informatica Teorica Appello del 19 Luglio 2006 Esercizio 1 (Punti 10) Si consideri il linguaggio seguente: L = {wcW | w, W {a, b}*; W essendo una stringa che differisce dalla stringa riflessa, wR, di w per al più 3 caratteri} Si scrivano una grammatica e un automa, preferibilmente a potenza minima (ossia appartenenti a una categoria di grammatiche e automi tale che una categoria di minor potenza generativa non possa definire L) che generi e riconosca L, rispettivamente. Esercizio 2 (Punti 13) Si consideri il seguente problema: data una f(x) qualsiasi (con dominio e codominio l’insieme N) di cui sia noto a priori che è computabile, stabilire se esistono un polinomio P a coefficienti interi non negativi e un valore x N tali che P( x) f ( x) . Si dica, giustificando brevemente la risposta, se il problema è decidibile, semidecidibile, o neanche semidecidibile. Come cambia, se cambia, la risposta assumendo di sapere a priori che f non è totalmente indefinita (ossia indefinita per ogni valore del suo dominio)? Esercizio 3 (Punti 10) Si consideri il linguaggio L presentato nell'esercizio 1. Si descriva nel dettaglio un algoritmo per una macchina basata sull’architettura di Von Neumann (ad es. la macchina RAM), che restituisca in uscita la stringa wcwR, se la stringa in ingresso x = wcW appartiene a L, cc altrimenti. Si supponga che la stringa in ingresso NON sia già disponibile in memoria. Se ne valuti la complessità (spaziale e temporale, con entrambi i criteri di costo). Soluzioni Esercizio 1 L è evidentemente un linguaggio non contestuale. Una G che genera L è la seguente: S c | aSa | bSb | aAb | bAa A c | aAa | bAb | aBb | bBa B c | aBa | bBb | aCb | bCa C c | aCa | bCb Similmente, un automa a pila che riconosca L può operare nel modo seguente: Inizialmente impila i caratteri di w fino ad incontrare c. Dopo aver letto c inizia a svuotare la pila rimanendo nello stesso stato finché il simbolo letto corrisponde al simbolo in cima alla pila. Se la pila si svuota quando si giunge a fine stringa in questo stato l’ingresso viene accettato. Non appena viene letto un carattere no corrispondente al carattere in pila si cambia stato una prima volta; indi si prosegue lo svuotamento della pila nel modo usuale. Sono possibili al più 3 cambiamenti di stato durante la lettura di W. Esercizio 2 E’ noto che per qualsiasi valore y esistono un polinomio P e un valore z tale che P(z) = y (ad esempio il polinomio costante y). Quindi il fatto che esistano un polinomio P a coefficienti interi non negativi e un valore x N tali che P( x) f ( x) è equivalente a stabilire se esiste un x N tale che f (x) sia definito, ossia se f sia totalmente indefinita o meno. Questo è un problema notoriamente indecidibile (tra i tanti modi di dimostrarlo si può utilizzare il teorema di Rice); tuttavia esso è semidecidibile: infatti se un tale x esiste, mediante una tipica enumerazione diagonale (simulo x mosse di una macchina che calcola f sul valore y, ecc.) esso viene individuato. Se invece si sapesse a priori che f non è totalmente indefinita, allora l’esistenza di x sarebbe già garantita e quindi anche il problema di partenza sarebbe risolto. Esercizio 3 Un semplice algoritmo che risolve il problema utilizza una lista di caratteri la cui lunghezza massima sarà pari alla lunghezza di w, una struttura dati LIFO (cioè una pila) ed un contatore che memorizza il numero di “errori” commessi dalla stringa W rispetto alla wR (quest’ultimo è inizializzato a zero). Ogni volta che un carattere viene letto dall’input, si procede in questa maniera: 1. se non si è ancora letto il separatore ‘c’, si copia il carattere letto in coda alla lista e si impila lo stesso carattere sulla pila 2. se si legge il carattere ‘c’, si procede al carattere successivo 3. se si è già letto il separatore ‘c’, allora a. se il carattere appena letto corrisponde a quello in cima alla pila, si elimina quest’ultimo dalla pila e si procede alla lettura del carattere successivo b. altrimenti, si incrementa il contatore degli errori e i. se il contatore errori è maggiore di 3, si scrive ‘cc’ in output e si termina, ii. altrimenti, si procede con la lettura del carattere successivo 4. se la stringa è stata letta completamente dall’input e la pila è vuota, si utilizza la lista riempita al passo 1. per scrivere in output wcwR. Per fare ciò, si scrive prima w scorrendo la lista a partire dalla testa, si inserisce ‘c’ , e si ripercorre la lista in direzione opposta, ottenendo quindi wR in output. Altrimenti, si scrive ‘cc’ in output. Chiamando n la lunghezza della stringa in ingresso, l’occupazione in memoria dell’algoritmo proposto è proporzionale a questa lunghezza. Infatti, per ciascun carattere letto, è necessario un numero costante di celle di memoria (nel caso peggiore, una posizione nella lista e una posizione sulla pila). Per cui, la complessità spaziale dell’algoritmo sarà (n) sia a costo costante che a costo logaritmico. Per quanto riguarda la complessità temporale, i passi 1., 2. e 3. hanno un costo costante per singola esecuzione. Nel caso peggiore, 1. e 3. vengono eseguiti n volte. Analogamente, il passo 4. richiede un numero di operazioni direttamente proporzionale ad n nel caso peggiore. Di conseguenza, la complessità temporale dell’algoritmo valutata a costo costante sarà (n), mentre valutata a costo logaritmico sarà (n log(n)). Informatica Teorica Sezione Mandrioli Appello del 13 Settembre 2006 Attenzione I voti proposti verranno pubblicati sul sito seguente: http://www.elet.polimi.it/upload/mandriol/Didattica/sitoinfteor1.html Verrà data precedenza ai laureandi, che devono indicare questa loro qualifica nel proprio elaborato. Gli studenti avranno tempo due giorni (48 ore, per la precisione) dalla data della pubblicazione per rifiutare il voto proposto, se sufficiente. L’eventuale rifiuto deve essere comunicato via email, facendo uso dell’indirizzo ufficiale del Poliself, non di indirizzo privato! Trascorsi i due giorni, i voti verranno registrati e trasmessi alla segreteria. Il docente spedirà a ogni studente “rinunciatario” un esplicito messaggio di “ricevuta”. In caso di mancata ricezione di tale ricevuta si consiglia di contattare il docente telefonicamente o di avvisare la segreteria didattica del DEI. Il tempo a disposizione per lo svolgimento del tema d’esame è 1h e 30 minuti. Esercizio 1 (punti 12) Si considerino le seguenti regole di attraversamento di un incrocio regolato da un semaforo. Il semaforo è verde per 4 unità di tempo; poi passa a giallo per un’unità di tempo e rosso per 4 ulteriori unità. Se un veicolo attraversa l’incrocio con semaforo verde o giallo nessuna azione viene eseguite nei suoi confronti. Se un veicolo attraversa l’incrocio con semaforo rosso entro 1 unità di tempo da quando è diventato rosso, viene elevata contravvenzione per Euro 50. Se un veicolo attraversa l’incrocio con semaforo rosso dopo 1 unità di tempo da quando è diventato rosso, viene elevata contravvenzione per Euro 200. Per semplicità si consideri un solo veicolo alla volta; si può anche assumere che la contravvenzione sia contemporanea all’infrazione. Si formalizzino le suddette regole in una sola delle versioni proposte nel seguito. Versione A Si utilizzi un’opportuna macchina astratta assumendo un tempo discreto in cui l’unità corrisponde all’unità di tempo indicata sopra. Versione B Si utilizzino formule del primo ordine. In tal caso si può adottare un dominio temporale sia discreto che continuo. NB E’ vietato consegnare entrambe le soluzioni che in tal caso non sarebbero valutate. Esercizio 2 (punti 10) Si consideri il sottoinsieme del linguaggio C in cui siano escluse tutte le istruzioni di controllo del flusso dell’esecuzione ad eccezione dell’istruzione condizionale if e dell’istruzione ciclica for. Si dica, giustificando brevemente la risposta, se è decidibile o no il problema di stabilire se un generico programma scritto in tale sottoinsieme del C terminerà sempre la sua esecuzione (ossia per ogni valore dei dati di ingresso) o no. Esercizio 3 (punti 10) Si supponga di implementare un algoritmo di merge-sort mediante una macchina RAM (non è necessario scrivere effettivamente il codice!). Quale sarebbe la sua complessità temporale valutata a criterio di costo costante e a criterio di costo logaritmico? Giustificare brevemente la risposta. Per semplicità si può assumere che i dati da ordinare occupino singolarmente una quantità limitata di memoria (ad esempio, 32 bit). Parte facoltativa (ulteriori punti 5) Si valutino anche la complessità spaziale dell’implementazione mediante RAM e la complessità sia spaziale che temporale di una possibile implementazione mediante macchina di Turing, assumendo la stessa ipotesi semplificativa della parte precedente. Soluzioni Esercizio 1 Versione A (traccia per la costruzione di un automa) Assumendo un dominio temporale discreto, conviene associare ogni scatto di transizione a un’unità di tempo. Quindi si può costruire un automa a 9 stati per descrivere l’evoluzione del semaforo. Ogni transizione è etichettata da un input attr (“il veicolo attraversa durante l’unità di tempo corrente”) oppure n_attr (“il veicolo non attraversa durante l’unità di tempo corrente”). La transizione etichettata attr uscente dal primo stato rosso comporta l’uscita multa50 e le successive transizioni uscenti dagli stati rossi comportano l’uscita multa200. Versione B Si introducano i seguenti predicati: v(t), (g(t), r(t), s(t)) Il semaforo è verde (rispettivamente, giallo, rosso, spento) all’istante t attr(t) Il veicolo attraversa l’incrocio all’istante t multa50(t) Viene elevata contravvenzione per 50 euro all’istante t multa200(t) Viene elevata contravvenzione per 200 euro all’istante t La formula seguente formalizza le regole richieste, assumendo che il semaforo inizi a funzionare all’istante 0 (con il verde) e che la multa venga notificata immediatamente. t (t 0 s(t )) (0 mod 9 t 4 mod 9 v(t )) (4 mod 9 t 5 mod 9 g (t )) (5 mod 9 t 9 mod 9 v(t )) ((attr (t ) 0 mod 9 t 4 mod 9) (multa 50(t ) multa 200 (t )) ((attr (t ) 4 mod 9 t 5 mod 9) (multa 50(t ) multa 200 (t )) ((attr (t ) 5 mod 9 t 6 mod 9) (multa 50(t ) multa 200 (t )) ((attr (t ) 6 mod 9 t 9 mod 9) (multa 50(t ) multa 200 (t )) Commento Si noti che le formule di cui sopra, semplici e sistematiche, in realtà non formalizzano esattamente le regole enunciate; bensì formalizzano un insieme di “comportamenti” che garantiscono la soddisfazione delle regole: da queste formule, usate come assiomi, è possibile derivare come teorema, ad esempio, il fatto che Se un veicolo attraversa l’incrocio con semaforo rosso dopo 1 unità di tempo da quando è diventato rosso, viene elevata contravvenzione per Euro 200. Esercizio 2 In C, diversamente da altri linguaggi, come il Pascal, il ciclo for ha sufficiente generalità da permettere di simulare anche il ciclo while. E’ noto che istruzione if e ciclo while (oppure l’istruzione if e la possibilità di usare la ricorsione nella chiamata di sottorpogrammi) permettono a un normale linguaggio di programmazione di avere la stessa potenza delle Macchine di Turing. Quindi il problema posto è equivalente a stabilire se una generica MT calcola una funzione totale o no. Questo problema è notoriamente indecidibile. Esercizio 3 La normale analisi di complessità temporale dell’algoritmo di merge-sort assume implicitamente un criterio di costo costante. E’ noto che essa produce un risultato (n.log(n)). Assumendo il criterio di costo logaritmico occorre tener presente che ogni accesso a un singolo elemento costa un fattore log(n) (in questa valutazione interviene solo il costo dell’indirizzamento, poiché la memorizzazione dei singoli dati richiede un numero di bit limitato a priori). Quindi la complessità temporale valutata a criterio di costo logaritmico è (n.log2(n)). Parte facoltativa Per valutare la complessità spaziale dell’implementazione mediante RAM occorre tener presente che sono possibili diverse realizzazioni –ricorsive e non- dell’algoritmo di merge-sort. La più efficiente dal punto di vista della complessità spaziale fa uso alternato di due array (o file) e risulta quindi (n) in entrambi i criteri. Un’analoga implementazione mediante MT richiederebbe anch’essa una quantità di memoria (n), mentre avrebbe una complessità temprale (n.log(n)) grazie alla natura tipicamente sequenziale sia dell’algoritmo di merge-sort che della MT (risparmiando così il fattore log(n) per l’accesso al singolo dato). Informatica Teorica Appello dell’8 Febbraio 2007 Il tempo a disposizione per lo svolgimento del tema d’esame è 1h e 30’. Esercizio 1 (punti 10) Sia dato il linguaggio L sull'alfabeto {a, b, c} contenenti tutte e sole le stringhe che hanno le seguenti caratteristiche: k) la stringa inizia e termina con esattamente lo stesso numero di 'a' l) la stringa contiene almeno un carattere diverso da 'a' Per esempio, le seguenti stringhe appartengono a L: aabcaa, aca, aacabbabaa, aaaacaaaa, ... Le seguenti stringhe, invece, non appartengono ad L: aaabaa, aaaa, aaacaccaaaaaa, ecc. Si scriva un automa oppure una grammatica che riconosca o generi il linguaggio L. NB1: il punteggio massimo verrà dato se il formalismo scelto è a potenza minima tra quelli che riconoscono/generano L. NB2: si scelga una sola tra le due possibilità: si scriva o un automa, oppure una grammatica, ma non entrambi. Esercizio 2 (11) L'algoritmo di ordinamento per conteggio serve ad ordinare un array di valori interi fornito in ingresso. Esso per funzionare si basa sulla ipotesi fondamentale che i valori da ordinare siano degli interi appartenenti all'insieme [0..k], con k prefissato. L'algoritmo sfrutta per funzionare un array ausiliario C di k+1 elementi, che serve a contenere il conteggio effettuato dall'algoritmo: in pratica C[j] contiene il numero di elementi presenti nell'array in ingresso con valore pari a j. Si implementi un algoritmo di ordinamento per conteggio, sapendo che ogni singolo dato da ordinare è sempre un intero non negativo memorizzabile in 8 bit. Quali sono le sue complessità temporale e spaziale valutate a criterio di costo costante e a criterio di costo logaritmico? Giustificare brevemente la risposta. NB: Si consiglia per comodità di descrivere l’algoritmo in pseudocodice, o mediante un linguaggio di alto livello. Esercizio 3 (punti 11) Il professor Touring ha preparato, per il prossimo appello del suo esame di Informatica 1, i 3 seguenti esercizi: Sia dato il seguente frammento di codice C: 1. void DivisoreComune (int i1, int i2){ 2. int min, max; 3. 4. if(i1 <= i2){ 5. min = i1; 6. max = i2; 7. } else { 8. min = i2; 9. max = i1; 10. } 11. 12. for(d = 1; d <= min; d++){ 13. if(min % d == 0 && max % d == 0) 14. return d; 15. } 16. 17. return 0; 18. } Dire se ci sono errori di sintassi e, se ce ne sono, indicare quali. Si scriva un sottoprogramma che prende in ingresso due parole p1 e p2 di al massimo 20 caratteri l'una, e ritorna true se sono una l'anagramma dell'altra, false altrimenti. Siano P, Q, R, tre puntatori a interi e x, y due variabili intere. Si dica quanto valgono rispettivamente x, y, *P, *Q, *R dopo l’esecuzione della seguente sequenza di istruzioni. x = 3; y = 5; P = &x; Q = &y; R = P; *R = 10; y = x + *Q; x = x + *P; Q = R; P = Q Per ognuno di questi esercizi dire, motivando adeguatamente la risposta, se è decidibile il problema di stabilire se la soluzione proposta da uno studente è corretta oppure no. Soluzioni Esercizio 1 La seguente grammatica noncontestuale genera il linguaggio L. S → aSa | BXB | B X → aX | bX | cX | B → b|c Esercizio 2 L’algoritmo puo’ operare come segue. Si mantengono due puntatori a, c rispettivamente all’elemento corrente dell’array A da ordinare e all’elemento corrente dell’array C dei contatori. 1. Fase di input, che supponiamo venga terminata dalla lettura di -1, e di scrittura dei contatori: for (c = 0 to 255) C[c] := 0 c := read(); a := 0; while( c ≠ -1 ) { A[a] := c; C[c] := C[c]+1; c := read(); a := a+1; } A[a] := -1; 2. Fase di scrittura dell’output, che scandisce C e sovrascrive A: a := 0 for (c = 0 to 255) { while ( C[c] > 0 ) { A[a] := c; C[c] := C[c]-1; a := a+1; }} Sia n il numero di elementi dell’array da ordinare. A costo costante, la complessita’ spaziale e’ (n) in quanto memorizzo un array di dimensione n e uno di dimensione costante (infatti considero interi a 8 bit, quindi 256 possibili valori). La complessita’ temporale e’ pure (n). Infatti il passo 1 consta di 1 ciclo eseguito (n) volte. Nel passo 2, invece, il ciclo piu’ interno e’ eseguito un numero costante di volte, mentre quello esterno e’ eseguito al piu’ n volte. Quindi tutti i passi sono di complessita’ temporale (n), e lo stesso e’ la loro composizione sequenziale. A costo logaritmico, il costo di memorizzazione dell’array da ordinare e’ sempre (n), in quanto in ogni cella ho un valore limitato da 256. L’array di contatori consta invece di 256 celle, ognuna delle quali costa (log(n)). Quindi in tutto la complessita’ spaziale e’ ancora limitata superiormente da (n). Per quanto riguarda la complessita’ temporale, si manipolano dei contatori che sono limitati superiormente da n. Dunque, in costo logaritmico, questo implica in fattore log(n) in ciascuna esecuzione dei cicli, che si traduce in una complessita’ temporale complessiva di (n log(n)). Esercizio 3 1. La risposta si riduce a una lista, sicuramente finita visto che il frammento di programma e’ finito, di potenziali errori di sintassi. Pertanto verificare la risposta corrisponde semplicemente a confrontare due liste di dimensioni finita, problema chiaramente decidibile. 2. Verificare la correttezza della risposta corrisponde a decidere se il programma/soluzione fornito dallo studente implementa la funzione richiesta oppure no. Come noto, decidere se un dato programma implementa una certa funzione e’ un problema non decidibile. Si noti che il fatto che l’input del programma e’ ristretto ad un numero finito di elementi (le stringhe di 20 caratteri) non cambia la risposta, dal momento che il formalismo usato per descrivere la soluzione (il codice) e’ comunque Turing-completo. 3. In questo caso la risposta consiste semplicemente in 3 valori interi per *P, *Q, e *R. Controllare la validita’ della risposta e’ pertanto decidibile, in quanto si riduce al confrontro tra 3 coppie di interi. Informatica Teorica Prima prova in itinere - 11 Maggio 2007 Tempo a disposizione: 1h 45’ Esercizio 1 (punti 5/13) Scrivere una grammatica che genera il linguaggio costruito sull'alfabeto {a,b,c} fatto di tutte e sole le stringhe x tali che esistano 2 sottostringhe disgiunte w e w', di lunghezza multiplo di 3, e w' = wR (es. w = ccacbb, w’ = bbcacc). NB: Il punteggio massimo verrà dato se la grammatica scritta sarà a potenza minima tra quelle che generano il linguaggio desiderato. Esercizio 2 (punti 5/13) Si abbia un impianto manifatturiero che produce 2 tipi di prodotti, p1 e p2, tali che ogni pezzo di tipo p1 vale 20000 euro, ed ogni pezzo di tipo p2 vale 30000 euro. L'impianto può produrre pezzi p1 e p2 in qualunque sequenza, fatto salvo che, ad ogni punto della sequenza di produzione, il valore totale dei pezzi p2 prodotti deve essere maggiore o uguale del valore totale dei pezzi p1 prodotti, e comunque la differenza tra i 2 valori totali non deve essere mai superiore ai 90000 euro. Si scriva un automa che accetta tutte e sole le sequenze di produzione ammissibili dell'impianto sopracitato. NB: Il punteggio massimo verrà dato se l’automa scritto sarà a potenza minima tra quelli che riconoscono le sequenze desiderate. Esercizio 3 (punti 6/13) E’ noto che ogni automa trasduttore definisce una traduzione : I* → O*. Per ogni famiglia di automi trasduttori (a stati finiti, a pila –deterministici e non–, di Turing) si dica, giustificando brevemente la risposta, se essa è chiusa rispetto alla composizione di traduzioni, ossia se, dati due automi A1 e A2 che definiscano rispettivamente le traduzioni 1 e 2, esista nella stessa famiglia un automa A che definisca la traduzione (x) = 2(1(x)). Soluzioni Esercizio1 Una grammatica (non-contestuale) che genera il linguaggio desiderato è la seguente. S QR1Q Q aQ | bQ | cQ | R1 aR2a | bR2b | cR2c R2 aR3a | bR3b | cR3c R3 aR1a | bR1b | cR1c | aQa | bQb | cQc Esercizio2 Un automa a stati finiti che accetta tutte e sole le sequenze di produzione desiderate è il seguente (laddove ogni stato rappresenta la differenza fino ad ora accumulata tra il totale del valore dei pezzi p2 ed il totale del valore dei pezzi p1): p2 p1 D10k D20k D0k p1 D30k D90k p1 p1 p2 p2 D80k p2 D40k p1 p1 D70k D50k p2 p1 p2 p1 D60k p2 Esercizio 3 1. Le traduzioni a stati finiti sono chiuse rispetto alla composizione: un procedimento che, dati due traduttori T1 = <Q1, I1, 1, q01, F1, 1, O1> e T2 = <Q2, I2, , q02, F2, , O2> (con O1 = I2) produca un traduttore T che definisca (x) = 2(1(x)) può essere intuitivamente descritto con la seguente costruzione, derivata dalla costruzione per l’intersezione di automi. T è una tupla <Q, I1, , q0, F, , O2> in cui Q = Q1 Q2 e le funzioni di transizione e output di T, <, >, sono definite secondo la seguente regola: se in T1 esiste una coppia <1, 1>(q1, a) = <q1’, w1>, con a I1 e w1 O1*, e per T2 si ha <2*, 2*>(q2, w1) = <q2’, w2>, con w2 O2* si definisca la coppia <, >(<q1,q2>, a) = <<q1’ q2’>, w2>. L’insieme di stati di accettazione F di T sono tutti e soli quelli nella forma < q1, q2 > tali che q1 F1 e q2 F2. Lo stato iniziale di T è infine lo stato <q01, q02>. 2. Le traduzioni a pila (sia deterministiche che non) non sono chiuse rispetto alla composizione. Infatti la traduzione (w·c) = w·c·w, può essere ottenuta componendo le due traduzioni 1(w·c) = w·c·wR·d e 2(w1·c·w2·d) = w1·c·w2R. Essa però non può essere ottenuta da un solo automa a pila, rigorosamente legato alla disciplina LIFO nella gestione del proprio input. Un altro controesempio possibile è il seguente: la traduzione (an·bn·cn) = d può essere ottenuta componendo le due traduzioni 1(an·bn·c*) = bn·c* e 2(bn·cn) = d. Anche in questo caso la traduzione, che necessita dell’accettazione del linguaggio {an·bn·cn}, non può essere effettuata da un automa a pila semplice. Più in generale, si osserva che componendo “in serie” due trasduttori a pila è possibile fare in modo che la composizione dei due accetti un linguaggio uguale all’intersezione dei due linguaggi accettati da ognuno dei due trasduttori di partenza. Poiché è noto che la classe dei linguaggi accettati dagli automi a pila non è chiusa rispetto all’intersezione, in generale non esiste quindi un automa a pila equivalente alla composizione dei due di partenza. 3. La composizione di due traduzioni effettuate da macchine di Turing può essere banalmente ottenuta da una macchina che memorizzi in un nastro di memoria l’output della prima e poi lo usi come fosse l’input della seconda. Informatica Teorica Seconda prova in itinere - 3 Luglio 2007 Avvisi importanti Il tempo disponibile per lo svolgimento della prova è 1 ora e 30 minuti. Gli studenti laureandi devono indicare esplicitamente la loro situazione nella testata del loro elaborato. Come in altre occasioni i risultati e le successive comunicazioni (in particolare le modalità di accettazione/rifiuto del voto proposto) saranno pubblicati nella pagina personale del docente sul sito ufficiale del Dipartimento. Verrà data precedenza alla correzione dei compiti dei laureandi (che risultino tali dall’archivio ufficiale del CEDA) Esercizio 1 (punti 4/17) La successione 2 1 , per n numero naturale, è detta dei numeri di Fermat. Il matematico Pierre de Fermat fu il primo a notare come i primi termini della successione (per n=0, 1, 2, 3) siano primi, dunque congetturò che lo siano tutti. 2n Si risponda alle seguenti domande, fornendo delle brevi, ma esaurienti, spiegazioni: 1.1. E’ decidibile il problema “tutti i numeri di Fermat sono primi?”? 1.2. E’ decidibile il problema “dato un numero naturale n, il numero 22 1 è primo?”? n 1.3. (nel caso si sia risposto positivamente alla domanda 1.2) E’ decidibile l’insieme delle macchine di Turing che risolve il problema della domanda 1.2? Esercizio 2 (punti 6/17) 2.1 Si descriva un algoritmo che, dato un numero naturale n, determini se l’n-esimo numero di Fermat è primo. Si noti che: m) non è necessario che l’algoritmo sia efficiente o elegante, l’importante è che sia semplice; n) per descrivere l'algoritmo è possibile usare pseudocodice oppure un linguaggio ad alto livello. 2.2. Se l'algoritmo definito al punto 2.1 viene eseguito su una macchina RAM, quale è il criterio di costo più opportuno per valutare la complessità di tale macchina RAM? Si motivi la risposta. 2.3. Si usi il criterio individuato al punto 2.2 per valutare la complessità spaziale e temporale di una macchina RAM che esegue l'algoritmo definito. Esercizio 3 (punti 9/17) Si vuole usare la logica del prim'ordine (con il predicato di uguaglianza) per descrivere giocatori e squadre di uno sport a squadre (per esempio il calcio). Si assuma quanto segue: le variabili (x, y, w, ...) denotano giocatori; viene introdotto il predicato SameTeam(x,y) il quale è vero se i giocatori x e y sono nella stessa squadra (laddove “essere nella stessa squadra” è una relazione di equivalenza). 3.1. Si scrivano, usando esclusivamente i predicati di uguaglianza (=), disuguaglianza () e SameTeam, delle formule logiche che formalizzano i seguenti vincoli: a) tutte le squadre hanno almeno 3 giocatori; b) esistono almeno 3 squadre. 3.2. Si consideri una relazione di “rivalità personale” tra alcuni dei giocatori. A questo scopo si introduca il predicato PersRivalry(x,y), il quale rappresenta il fatto che i giocatori x e y sono rivali (si assuma pure che PersRivalry sia simmetrica). Si scriva una formula che formalizzi il fatto che non ci possono essere rivalità all’interno di una stessa squadra. 3.3. Si assuma che periodicamente (per esempio ogni mese) si svolga un torneo tra le squadre, e che sia le squadre che le rivalità personali possano cambiare da un torneo all’altro. Si assuma inoltre quanto segue: le variabili t, t’, t’’ denotano i momenti di svolgimento dei tornei, rappresentati come numeri interi. per descrivere squadre e rivalità si usano delle varianti temporizzate dei predicati introdotti in precedenza, SameTeam(x,y,t) e PersRivalry(x,y,t), che indicano appartenenza alla stessa squadra / rivalità di x e y al momento del torneo t. Si scrivano delle formule che formalizzino i seguenti vincoli: a) due giocatori sono nella stessa squadra durante un torneo solo se non erano rivali in alcuno dei precedenti k tornei; b) se, per un certo torneo, due giocatori della stessa squadra sono rivali, essi non saranno nella stessa squadra per i prossimi h tornei. Soluzioni Esercizio 1 1.1. Sì, si tratta di una domanda “chiusa” (la risposta è sì oppure no). Tra l’altro si conosce anche la risposta: Eulero dimostrò che per n=5 si ottiene un numero non primo. 1.2. Sì, basta scrivere una semplice procedura che, dato n, calcoli 22 1 e poi ne controlli la primalità. n 1.3. No, è una conseguenza del teorema di Rice (l'insieme delle MT che risolvono il problema 1.2 non è l'insieme vuoto, né tantomeno quello universo). Esercizio 2 2.1 boolean primeNthFermat(int n){ 1. x = 2 2. for i from 1 to n do x = x*x 3. x = x+1 4. for i from 2 to squareRootOf(x) do 5. if (x/i)*i==x then return false 6. return true 2.2-2.3. Per il calcolo del numero di Fermat (righe 1-3) è necessario usare il criterio di costo logaritmico, per ottenere una valutazione di complessità realistica. Quindi si ottiene: ∑k=1, ..., n 2k =(2n) per il tempo e (2n) anche per lo spazio. Il fattore di complessità dominante è però il secondo ciclo (righe 4-5): la complessità temporale che si ottiene per esso (naturalmente sempre a costo logaritmico) è: ( 2n 22 n ) = ( 2 n 2 2 n1 ) = ( 2 2 n 1 n ). Infatti la singola iterazione costa log (22n) ed il calcolo della radice quadrata non impatta sul comportamento asintotico della complessità. Esercizio 3 3.1. a) xyz(xy yz xz SameTeam(x,y) SameTeam(y,z)) b) xyz(xy yz xz SameTeam(x,y) SameTeam(y,z) SameTeam(x,z)) 3.2. xy(xy SameTeam(x,y) PersRivalry(x,y)) 3.3. a) xyt(SameTeam(x,y,t) t’(t-kt’<t PersRivalry(x,y,t’))) b) xyt(PersRivalry(x,y,t) SameTeam(x,y,t) t’(t<t’t+h SameTeam(x,y,t’))) Informatica Teorica Appello del 17 Luglio 2007 Avvisi importanti Il tempo disponibile per lo svolgimento della prova è 2 ore. Come in altre occasioni i risultati e le successive comunicazioni (in particolare le modalità di accettazione/rifiuto del voto proposto) saranno pubblicati nella pagina personale del docente sul sito ufficiale del Dipartimento. Esercizio 1 (punti 12) Parte A Si considerino le grammatiche seguenti: G1: S SS | ASB | BSA | Aa Bb G2: S SBA | BA AB AB BA Aa Bb G3: S ABCS | e tutte le permutazioni della stringa ABCS | Aa Bb Cc G4: S ABCS | BA AB AB BA CB BC BC CB AC CA CA AC Aa Bb Cc Si dica, motivando brevemente la risposta, se G1 e G2, e G3 e G4 sono tra loro equivalenti. Parte B Si dica, motivando brevemente la risposta, se i linguaggi generati da G1, G2, G3 e G4 sono riconoscibili da automi a pila (anche nondeterministici). (continua sul retro) Esercizio 2 (Punti 12) Per una funzione F:NN, un elemento x del suo dominio di definizione è detto mimimo globale di F se F(x) è definita e, per ogni valore y in cui F(y) è definita, F(x) F(y), dove definisce l’usuale relazione di “minore o uguale” tra numeri naturali. 1. Si determini se il problema di trovare se una generica funzione computabile f ha un minimo globale è decidibile. 2. Si determini se lo stesso problema è semidecidibile. 3. Come cambia, se cambia, la risposta ai quesiti precedenti se si considerano solo funzioni totali e computabili? Esercizio 3 (Punti 10) Si consideri il problema della ricerca di un elemento x in un array S di lunghezza n. In tutto l’esercizio, consideriamo solo la complessità temporale e il criterio di costo costante. Come noto, l’algoritmo più immediato per risolvere il problema è quello della ricerca sequenziale, che scandisce tutto l’array sequenzialmente alla ricerca dell’elemento x, e raggiunge una complessità di (n) nel caso pessimo. Si consideri ora il problema di trovare un algoritmo per risolvere lo stesso problema che sia asintoticamente peggiore della ricerca sequenziale, ossia raggiunga una qualche complessità n 0. (p(n)), con p(n) funzione totale e computabile, tale che lim n p ( n) 1. Si descriva un algoritmo di ricerca asintoticamente peggiore della ricerca sequenziale, e se ne valuti la complessità temporale, mostrando che è effettivamente asintoticamente peggiore. 2. Un algoritmo A che risolve un problema P con complessità TA(n) è detto pessimo se ogni altro algoritmo B che risolve P con complessità TB(n) è tale che: o A è asintoticamente peggiore di B, oppure TA(n) (TB(n)). Per un generico problema P, esiste sempre un algoritmo pessimo che lo risolve? Esiste un problema P che ammette un algoritmo pessimo per la sua soluzione? Motivare brevemente le risposte. Soluzioni Esercizio 1 Parte A G1 e G2 sono equivalenti. Infatti entrambe generano tutte e sole le stringhe con ugual numero di a e b. G3 e G4 non lo sono. Infatti G3, pur generando stringhe con ugual numero di a, b, c non può generare, ad esempio stringhe del tipo anbncn. Parte B Poiché G1 e G3 sono non contestuali, i linguaggi da esse generati sono certamente riconoscibili da automi a pila. Essendo G2 equivalente a G1, lo stesso vale per L(G2). Invece G4 richiede il riconoscimento di stringhe del tipo anbncn che devono essere distinte, ad esempio, da stringhe come anbnc2n. Ciò richiede una capacità di “conteggio illimitato doppio” che, come ben noto, non rientra tra le possibilità dell’automa a pila. Esercizio 3 1. Il problema non è decidibile, in quanti riducibile al problema di determinare se una generica funzione computabile è definita per almeno un valore del suo dominio, problema che notoriamente non è decidibile. Infatti, sulla base della definizione data, tenendo conto che l’insieme dei numeri naturali è discreto e limitato inferiormente, una funzione computabile f: N N ha minimo globale se e solo se è definita in almeno un punto. 2. Sia f una funzione totale e computabile, e sia I N la sua immagine. Essendo I un insieme limitato inferiormente (da 0), è sicuramente definito l’estremo inferiore i = inf I. Inoltre, essendo I un insieme discreto, i appartiene a I, quindi i = min I. Il valore x tale che f(x) = i è il minimo di f, che dunque esiste sempre per funzioni totali e computabili a valori in N. Dunque il problema è deciso, e quindi a maggior ragione decidibile. Per ripassare un pò di matematica, ecco un’altra giustificazione che I ha sicuramente minimo. Un insieme S è detto ben ordinato (well-ordered) sse ogni suo sottinisieme non vuoto ha un elemento minimo. Per assurdo, sia I non ben ordinato. Allora esiste un suo sottoinsieme J I che non ammette minimo. Sia K il complemento, rispetto a N, di J. Se 0 J, esso è anche minimo; quindi 0 J e dunque 0 K. Per induzione, tutti i naturali appartengono a K e dunque J è vuoto, contrariamente all’ipotesi. Dunque I è ben ordinato, e dunque ha minimo. Esercizio 4 1. n 0 , si può generare un algoritmo p ( n) di ricerca che abbia complessità (p(n)) semplicemente “peggiorando” un normale algoritmo di ricerca sequenziale aggiungendo l’esecuzione di un numero di istruzioni pari a p(n), ove n è la lunghezza dell’array ove si sta cercando. In pseudocodice: Data una qualunque funzione computabile p(n) tale che lim n ricerca_p_peggiore(x, S): 1 n = |S| 2 max = p(n) 3 for i:=1 to max do 4 5 continue; return ricerca_sequenziale(x, S) end La complessità dell’istruzione 5 è chiaramente pari a (n). Sia c(n) la complessità dell’istruzione 2, ossia il costo di calcolare p(n). Infine il ciclo for delle istruzioni 3-4 ha complessità (p(n)). In totale quindi, ricordando che p(n) cresce asintoticamente più di n, si ha una complessità (c(n) + p(n)) che è (p(n)). 2. Nella soluzione di 1. abbiamo mostrato come la complessità si possa “peggiorare” arbitrariamente. Dunque per qualsiasi problema non ha senso cercare la complessità pessima perchè è sempre possibile scegliere una funzione che cresce più velocemente e peggiorare l’algoritmo di quel fattore. Informatica Teorica Appello dell’11 Settembre 2007 Avvisi importanti Il tempo disponibile per lo svolgimento della prova è 2 ore. Come in altre occasioni i risultati e le successive comunicazioni (in particolare le modalità di accettazione/rifiuto del voto proposto) saranno pubblicati nella pagina personale del docente sul sito ufficiale del Dipartimento. Esercizio 1 (punti 14) Si consideri un modello di calcolo consistente in una Macchina di Turing a nastro singolo e dotata di h testine di lettura/scrittura. 1. Si formalizzi tale modello. NB, non è necessario formalizzarne il comportamento, ossia la relazione di transizione; è sufficiente formalizzare la struttura della macchina ed eventualmente la configurazione. 2. Si dica, spiegandone brevemente i motivi, se una tal macchina dotata di k > h testine ha una potenza di calcolo (e.g. capacità di riconoscere linguaggi) maggiore di quella dotata di sole h testine. 3. Si dica, spiegandone brevemente i motivi, se una tal macchina dotata di k > h testine ha la capacità di risolvere problemi (e.g. di riconoscere linguaggi) con complessità strettamente inferiori (secondo la relazione ) rispetto a quella dotata di sole h testine. Esercizio 2 (punti 10) Si considerino le due grammatiche seguenti: G1: G2: S ADaCD | DAbDC S aADCD | DbADC DC CD | AA DC CD | AA A a | SSAD A a | SSAD | C ADC | c C ADC | c SA AS | SA AS | Si dica, giustificando brevemente le risposte, se i seguenti problemi sono decidibili: 1) G1 è equivalente a G2? 2) Data una generica grammatica regolare G, G è equivalente a G1? Esercizio 3 (punti 10) Si formalizzi mediante una formula del prim’ordine il linguaggio L costituito da stringhe del tipo wcu, in cui w e u denotano stringhe non nulle consistenti dei soli caratteri ‘a’ e ‘b’ tali che almeno in una posizione a partire dal loro inizio si trovi lo stesso carattere. Per esempio la stringa ababcaabaaa appartiene a L, aaaaacbb non vi appartiene, ecc. Soluzioni Esercizio 1 1. Partendo dalla normale formalizzazione delle macchina a nastro singolo basta modificare la funzione nel modo seguente: : Q Ah Q Ah Mh | M {R, L, S} La definizione di configurazione dovrà tener conto della posizione delle h testine, ad esempio mediante apposite marche. 2. La potenza di calcolo ovviamente non aumenta, essendo già massima la potenza della macchina con una sola testina. 3. Aumenta invece la capacità di riconoscere linguaggi con minor complessità, come dimostrato dal seguente ragionamento intuitivo: Il linguaggio {wcw | w {a,b}*} non è riconoscibile in tempo lineare da una macchina a nastro singolo con una sola testina ma è facilmente riconoscibile con 2 testine in tempo O(n); con una naturale estrapolazione il linguaggio {wcwcw … | w {a,b}* ripetuto h volte } può essere riconosciuto in tempo lineare mediante h+ 1 testine ma non con sole h testine. Esercizio 2 1) Senza bisogno di rispondere al quesito se le due grammatiche siano equivalenti o meno, si può comunque affermare che il problema di trovare tale risposta è decidibile, dato che la risposta non può che essere SI o NO indipendentemente da qualsiasi altro fattore. Quindi una tra le macchine di Turing che forniscono risposta costante SI e quella che forniscono risposta costante NO risolve il problema di stabilire se le due grammatiche siano equivalenti. 2) Senza analizzare la regolarità del linguaggio di G1, o G1 genera un linguaggio regolare, oppure non lo genera. Se non lo genera, la risposta è sempre negativa, dunque decidibile. Se lo genera, allora il problema si riconduce all’equivalenza tra automi a stati finiti, che è decidibile. Esercizio 3 Seguendo una schema consueto si usino simboli di variabili per indicare generiche stringhe o generici caratteri, a, b, c essendo invece simboli di costanti corrispondenti ai caratteri dell’alfabeto. Usando inoltre le normali abbreviazioni ‘.’ e ‘| |’ per rappresentare la funzione binaria concatenazione e la funzione “lunghezza di una stringa” la cui definizione viene data qui per scontata, la formula seguente caratterizza tutte e sole le strnghe del linguaggio: x L w, u, v, z (x = wfucvfz |w| = |v| (f = a f = b) (w,u,v,z {a,b}*)). Informatica Teorica Prova d'esame - 13 Febbraio 2008 Esercizio 1 (punti 10/30-esimi, 7 se l’automa non è a potenza minima) Si consideri la seguente grammatica G: S AB A | CAC | D D aDa | C cC | Cc | B bbB | b Si scriva un automa, preferibilmente a potenza minima, che riconosca il linguaggio L generato da G. Esercizio 2 (punti 10/30-esimi) Descrivere (senza necessariamente codificarla nei dettagli) una macchina RAM che riconosce il linguaggio L descritto nell'esercizio 1, e se ne dia la complessità spaziale e temporale a costo costante e a costo logaritmico. E’ preferita una macchina che minimizzi entrambe le complessità, a meno della relazione di equivalenza . Esercizio 3 (punti 10/30-esimi) Dire se è decidibile il problema di stabilire se, data una generica macchina RAM, questa riconosce il linguaggio generato dalla grammatica G dell'esercizio 1. Dire se è decidibile il problema di stabilire se la macchina RAM definita nell’esercizio 2 riconosce il linguaggio L generato dalla grammatica G dell’esercizio 1 oppure no. Soluzioni Esercizio 1 Il linguaggio L(G) è l’insieme {c*a2nc*b2m+1 | n, m >= 0 } che è un linguaggio regolare, anche se G non lo è. Quindi un automa a potenza minima che riconosce L(G) è il seguente automa a stati finiti. Esercizio 2 Una macchina RAM può simulare un automa a stati finiti con complessità spaziale (K) e complessità temporale (n) sia a cirterio di costo costante che a criterio di costo logaritmico. Esercizio 3 1. Il problema è indecidibile in quanto è il calassico problema della correttezza. 2. Il problema è decidibile, in quanto la macchina RAM in questione è fissata (e quindi la risposta è chiusa, o SI, o NO). Informatica Teorica Prima prova in itinere - 8 Maggio 2008 NB: il punteggio è espresso in 13-esimi e riflette il peso relativo della prova rispetto all’intero esame il cui punteggio è in 30-esimi. Come già in altre occasioni è tuttavia possibile ottenere un punteggio complessivo superiore a 13/13. Esercizio 1 (10/13 punti) Parte 1 Si formalizzi la nozione di automa trasduttore finito deterministico FT1 che, al contrario del modello di trasduttore finito presentato a lezione (chiamiamolo FT), può anche effettuare -mosse ma può emettere, a ogni transizione, al più un solo simbolo sul nastro di uscita. Dimostrare che il modello FT1 è almeno altrettanto potente del modello FT deterministico (ossia che qualsiasi FT può essere simulato da un opportuno FT1). Parte 2 Formalizzare poi la nozione di automa finito deterministico a due ingressi, 2FA, tratteggiato in figura a sinistra. I1 a, CD a, a I2 2FA può fare -mosse, non facendo avanzare la testina di ingresso su uno o entrambi i nastri di ingresso I1 e I2. L’automa 2FA può essere visto come traduttore nel modo seguente: la stringa di ingresso x viene accettata e tradotta in (x) se e solo se la coppia di stringhe <x, (x)> sui due nastri I1 e I2 è accettata. Per esempio, l’automa 2FA nella figura a destra definisce la traduzione (an)=an/2 per n0 e pari. Mostrare che il modello 2FA è almeno altrettanto potente di FT deterministico, nel senso che se un FT deterministico accetta una stringa x e la traduce nella stringa (x), allora esiste un opportuno 2FA che accetta la coppia di stringhe <x, (x)> sui due nastri I1 e I2. Valutare se il modello 2FA ha esattamente la stessa potenza espressiva di FT, cioè se qualsiasi traduzione definita da un 2FA nel modo sopra indicato può essere calcolata da un opportuno FT. Esercizio 2 (4/13 punti) Scrivere una grammatica G che generi il linguaggio {anbn se n è pari >= 0, ancn se n è dispari} Soluzioni Esercizio 1 Un FT1 è una tupla (Q, I, O, δ, q0, F) dove Q, I, O, q0, e F hanno lo stesso significato che negli automi trasduttori tradizionali. La funzione di transizione δ: Q × I {} Q × O {} definisce, per ogni coppia (q, i) di stato corrente e carattere in input (oppure ) lo stato prossimo q’ e il singolo carattere scritto in output (oppure ), cioè δ(q,i) = (q’, o). Affinchè sia deterministico si richiede che se δ(q,) è definito, allora δ(q,i) è indefinito per tutti gli i I. Conviene poi fornire la definizione di configurazione, transizione tra configurazioni, e trasduzione seguendo la prassi standard usata per automi a pila e macchine di Turing. Dato un FT = (Q, I, O, δ, q0, F) deterministico, è sempre possibile definite un FT1 = (Q’, I, O, δ’, q0, F) che definisce la stessa traduzione facendo in modo che, quando FT emette una stringa di lunghezza >1, l’FT1 corrispondente emetta in sequenza i caratteri della stringa, uno alla volta, mediante una serie di -mosse che lo fanno passare attraverso una serie di stati aggiuntivi, diversi da tutti gli altri, introdotti a questo scopo. Q’ e δ’ sono quindi definiti in questo modo. Q’ contiene tutti gli stati che sono in Q. Inoltre, per ogni δ(q,i) = (q’, s) con s O*, se |s| 1 si ha semplicemente δ’(q,i) = (q’, s); se |s| > 1si aggiungono |s| stati qs1, qs2, ..., qs|s| a Q’ e si pone: (1) δ’(q,i) = (qs1, s[1]); (2) per ogni 2 k |s|: δ’(qsk-1,) = (qsk, s[k]); (3) δ’(qs|s|,) = (q’, );. Un 2FA è una tupla (Q, I1, I2, δ, q0, F) dove I1 e I2 sono gli alfabeti dei due nastri di ingresso, Q, q0, e F hanno il significato convenzionale. La funzione di transizione δ: Q × I1 {} × I2 {} Q definisce per ogni tupla (q, x, y) di stato corrente q, carattere sul primo nastro x (o ), e carattere sul secondo nastro y (o ) lo stato prossimo δ(q, x, y). Si richiede per il determinismo che se δ(q, x, ) (rispettivamente δ(q, , y)) è definito allora δ(q, x, y) è indefinito per ogni y I2 (rispettivamente per ogni x I1). La definizione di configurazione e transizione tra configurazioni sono definite di conseguenza nel solito modo (includendo nella configurazione il contenuto dei due nastri dalla posizione della testina in poi). Il modello 2FA è almeno altrettanto potente del modello FT1 (e quindi, transitivamente, del modello FT): dato un qualsiasi FT1, esiste un 2FA che simula ogni sua transizione, leggendo dal secondo nastro di ingresso lo stesso carattere che l’FT1 emette sul nastro di uscita ed effettuando -mosse sul primo o sul secondo nastro di ingresso quando, rispettivamente, l’FT1 fa una -mossa (i.e., non consuma ingresso) o non emette alcun simbolo in uscita. Formalmente, dato un FT1 = (Q, I, O, δ, q0, F) si definisce il 2FA = (Q, I, O, δ’, q0, F) dove ’(q, x, y) = q’ se e solo se (q, x)=(q’,y), q,q’Q e xI{} e yO{}. Il modello 2FA è strettamente più potente del modello FT, perchè permette di definire una traduzione, accettandola come stringa in ingresso sul secondo nastro, anche nel caso in cui la traduzione dipenda da una proprietà della stringa di ingresso (quella sul primo nastro) che può essere decisa solo al termine della scansione, dopo un numero di passi illimitato a priori. Ciò non può essere fatto dal modello FT, a causa del vincolo di memoria finita che lo obbliga a emettere la traduzione “in tempo reale”, durante la scansione della stringa in ingresso. Come esempio di cìò si consideri la seguente traduzione: (an)=bn se n è pari, (an)=cn se n è dispari. Nessun FT può calcolare questa traduzione, perchè il riconoscimento della stringa come avente lunghezza pari o dispari avviene solo al termine della scansione, mentre l’emissione della traduzione deve avvenire durante la scansione. Il 2FA mostrato in figura invece definisce la traduzione in questione accettando il linguaggio L={( an,bn) | n0, n pari }{( an,cn) | n dispari } . a,b a,b a,c a,b a,c a,c Esercizio 2 SX|Y X aAb | A aXb Y aBc B aYc | Theoretical Computer Science (English version, with slightly more detailed solutions) Midterm exam – May 8th 2008 NB: the total score is 13, reflecting the relative weight of this part of the exam w.r.t. the total of 30 for the whole course. Just like in previous occasions it is possible, however, to get a grade higher than 13. Exercise 1 (10/14 points) Part 1 Please formalize the notion of a deterministic finite transducer FT1 that, unlike the finite transducer model presented at lesson (let us call that one FT), can also have -moves but can emit, at every transition step, at most one symbol on the output tape. Prove that the FT1 model is at least as powerful as the deterministic FT (i.e., any possible deterministic FT can be simulated by a suitable FT1). Part 2 Please formalize the notion of a two-input deterministic finite automaton 2FA, outlined in the figure on the left. I1 a, CD a, a I2 The 2FA may make -moves, i.e., it may leave the scanning head still on one or both of the input tapes I1 and I2. The 2FA automaton can be viewed as a transducer in the following way: the input string x is accepted and translated into (x) if and only if the string pair <x, (x)> is accepted on the two input tapes I1 and I2. For instance, the 2FA automaton in the figure on the right defines the translation (an)=an/2 for n0 and n even. Please show that the 2FA model is at least as powerful as the deterministic FT, i.e., if a deterministic FT accepts a string x and translates it into the string (x), then there exists a suitable 2FA that accepts the string pair <x, (x)> on the two input tapes I1 and I2. Please determine if the 2FA model has exactly the same expressive power as the FT model, i.e., if any translation defined by a 2FA in the manner indicated above can be computed by a suitable FT. Exercise 2 (4/14 points) Write a grammar G that generates the language {anbn if n is even >= 0, ancn if n is odd} Solutions Exercise 1 An FT1 is a tuple (Q, I, O, δ, q0, F) where Q, I, O, q0, and F have the same meaning as in traditional finite transducers. The transition function δ: Q × I {} Q × O {} defines, for each pair (q, i) of current state and input character (or ) the next state q’ and the unique character written on the output (or ), i.e., δ(q, i) = (q’, o). To make the automaton deterministic it is required that, if δ(q, ) is defined, then δ(q, i) is not defined for all i I. Following the usual notations adopted for Stack automata and Turing machines, the configuration of a FT1 is defined as a tuple (q, x, y)Q × I* × O*, q being the current state, x the string still to be read on the input, and y the string output so far. The transition relation |-- among configurations is defined as follows. If (q, )=(q’, o) then (q, x, y)|--(q’, x, y.o); if (q, i)=(q’, o) then (q, i.x, y)|--(q’, x, y.o); the relation |-*- is defined as the reflexive transitive closure of |--; a string xI1 is accepted if and only if, for some qfF and yO*, (q0, x, ) |-*- (qf, , y); in that case the translation performed by FT1 on x is define as (x) = y. Given a deterministic FT = (Q, I, O, δ, q0, F), it is always possible to define a FT1 = (Q’, I, O, δ’, q0, F) that defines the same translation by making sure that, when the FT emits a string of length >1, the corresponding FT1 emits in a sequence the characters composing the string, one at the time, by means of a series of -moves that make it go through a sequence of additional states, different from all the other ones and suitably introduced for this purpose. Q’ and δ’ are hence defined as follows. Q Q’ and besides, for each δ(q,i) = (q’, s) with s O*, if |s| 1 then simply δ’(q,i) = (q’, s); if |s| > 1 the |s| new states are added to Q’, qs1, qs2, ..., qs|s| and: (1) δ’(q,i) = (qs1, s[1]); (2) for each 2 k |s|: δ’(qsk-1,) = (qsk, s[k]); (3) δ’(qs|s|,) = (q’, ). A 2FA is a tuple (Q, I1, I2, δ, q0, F) where I1 and I2 are the alphabets of the two input tapes, Q, q0, and F have the usual meaning. The transition function δ: Q × I1 {} × I2 {} Q defines, for each tuple (q, x, y) of current state q, input character on the first tape x (or ), and input character on the second tape y (or ) the next state δ(q, x, y). To make the device deterministic it is required that if δ(q, x, ) (respectively, δ(q, , y)) is defined, then δ(q, x, y) is not defined for every y I2 (respectively, for every x I1). The configuration of a 2FA is defined as a tuple (q, x, y)Q × I1* × I2*, q being the current state, x and y the strings still to be read on the first and second input. The transition relation |-- among configuration is defined as follows. (q, x, y) |-- (q’, w, z) in the following cases: (q, ) = q’ and w=x and z=y, or (q, i1, )=q’ with i1I1 and x=i1.w and z=y, or (q, , i2)=q’ with i2I2 and w=x and y = i2.z, or (q, i1, i)=q’ with i1I1 and with i2I2 and x=i1.w and y = i2.z. The relation |-*- is defined as the reflexive transitive closure of |--; a pair of strings (x, y) is accepted if and only if, for some qfF, (q0, x, y) |-*- (qf, , ). The 2FA model is at least as powerful as the FT1 model (and hence, transitively, as the FT model): given any FT1, there exists a 2FA that simulates all its transitions, by reading from the second input symbol the same character that the FT1 writes on its output tape, and performs -moves on the first or second input tape when, respectively, the FT1 makes an moves (i.e., it does not consume its input) or it does not emit any output symbol. Formally, given an FT1 = (Q, I, O, δ, q0, F) one can define the 2FA = (Q, I, O, δ’, q0, F) where ’(q, x, y) = q’ if and only if (q, x)=(q’,y), q,q’Q and xI{} and yO{}. The 2FA model is strictly more powerful than the FT model, because it allows one to define a translation, by accepting the string result of the translation as input on the second tape, also in the case when the translation depends on a property of the input string (the string on the first input tape) that can be decided only at the end of its scanning, after a number of steps that is a priori unlimited. This cannot be done by the FT, due to the finite memory constraint that forces it to emit the translation “in real time”, during the scanning of the input string. As an example, let us consider the following translation: (an)=bn if n is even and n0, (an)=cn if n is odd. No FT can compute this translation, because the decision that the string has even or odd length can be taken only at the end of the scanning of the input, while the translation must be written during the scanning of the input. Instead, the 2FA shown in the figure below defines the translation by accepting the language L={( an,bn) | n0, n even }{( an,cn) | n odd}. . a,b a,b a,c a,b a,c a,c Exercise 2 SX|Y X aAb | A aXb Y aBc B aYc | Informatica Teorica Seconda prova in itinere 30 Giugno 2008, Sezione Mandrioli Il tempo a disposizione è di 2 ore e 30 minuti Esercizio 1 (punti 8/17-esimi) Si formalizzi mediante formule del prim’ordine il seguente comportamento di un sistema di allarme a tempo continuo: L’allarme si attiva e disattiva inserendo la chiave nell’apposito alloggiamento; mentre la disattivazione è immediata, l’attivazione avviene dopo 12 secondi dall’introduzione della chiave; un eventuale reinserimento della chiave durante questo periodo non ha effetto; l’estrazione della chiave dall’alloggiamento non ha alcun effetto e può essere trascurata. Ad allarme attivato l’ingresso di un corpo estraneo nel volume sotto controllo determina lo scatto dell’allarme dopo 12 secondi, a meno che durante tale intervallo non venga inserita la chiave nell’alloggiamento per disinserirlo. Si suggerisce di usare i seguenti predicati logici (dall’ovvio significato), tutti quanti aventi un parametro a valori reali: attiva_allarme(t), disattiva_allarme(t), allarme_attivo(t), inserimento_chiave(t), rilevamento_corpo_estraneo(t), scatto_allarme(t). Esercizio 2 (punti 6/17-esimi) Si dica, giustificando brevemente la risposta, se i seguenti problemi sono decidibili o semidecidibili: o) Stabilire se, data una generica macchina di Turing a nastro singolo e due configurazioni della medesima, le due configurazioni sono tra loro in relazione di transizione immediata. p) Stabilire se, data una generica macchina di Turing a nastro singolo e due configurazioni della medesima, le due configurazioni sono tra loro in relazione di transizione non necessariamente immediata. Esercizio 3 (punti 6/17-esimi) Si supponga che una macchina di Turing deterministica simuli il comportamento di un automa a stati finiti nondeterministico nel seguente modo: ricevendo in ingresso una stringa, essa riproduce, una dopo l’altra, tutte le possibili esecuzioni che l’automa nondeterministico può svolgere su tale stringa. Si indichi la complessità minima (col criterio del caso pessimo) che tale simulazione richiede, sia per il tempo che per lo spazio, in funzione della lunghezza n della stringa in ingresso x. Si supponga che una macchina di Turing deterministica abbia in ingresso la descrizione di un automa a stati finiti nondeterministico, e una stringa, da intendere come ingresso per l’automa, e scriva in uscita il valore 1 se la stringa appartiene al linguaggio accettato dall’automa, 0 altrimenti. Si valutino, giustificando brevemente la risposta: o la complessità temporale e quella spaziale minime (col criterio del caso pessimo) come funzione del numero m degli stati dell’automa in ingresso; o la complessità temporale e quella spaziale minime (sempre col criterio del caso pessimo) come funzione della lunghezza n della stringa in ingresso x. Soluzioni schematiche Esercizio 1 inserimento_chiave, attiva_allarme, disattiva_allarme, rilevamento_corpo_estraneo, scatto_allarme sono definiti a priori come eventi, ossia istantanei, allarme_attivo è invece definito a priori come uno stato che ha quindi una durata. La formula seguente esprime i requisiti richiesti mediante la sintassi del calcolo dei predicati. attiva_allarme(t) t inserimento_chiave(t 12)allarme_attivot ( 12) t1(t 12t1 t attiva_allarme(t1)) tdisattiva_allarme(t) inserimento_chiave(t)allarme_attivot ( ) ( ) allarme_attivot t t1 t attiva_allarme(t1) t1 t2(t1 t2 t disattiva_allarme(t2)) scatto_allarme(t) t rilevamento_corpo_estraneot ( 12)allarme_attivot ( 12) t1(t 12t1 t inserimento_chiave(t1)) Esercizio 2 Quesito 1 Il problema è sicuramente decidibile: è infatti immediato costruire un semplice algoritmo che scandisca la configurazione iniziale e determini il simbolo in lettura e lo stato della macchina, individui la mossa definita dalla funzione della macchina e verifichi se la seconda configurazione coincide con quella che si otterrebbe applicando la . Quesito 2 Questo problema è invece non decidibile. Infatti il classico problema dell’HALT è un caso particolare del problema posto: stabilire cioè se da una configurazione iniziale si può giungere a una configurazione di HALT. NB: per la precisione, visto che in generale vi possono essere diverse di configurazioni di HALT, per ricondurre il problema dell’HALT esattamente al problema in questione è necessario modificare la macchina in modo tale che essa abbia un’unica configurazione di HALT (ad esempio, nastro vuoto e stato qF.) Il problema è invece semidecidibile in quanto è sufficiente “far girare” la macchina a partire dalla prima configurazione: se la seconda è raggiungibile, prima o poi la si raggiunge e si risolve il problema. Non vale ovviamente il viceversa. Esercizio 3 Quesito 1 Il meccanismo di simulazione della MT è quello classico di visita dell’albero delle computazioni; quindi la complessità temporale è nel caso pessimo (2n) (per semplicità assumiamo che l’albero sia binario). Se la macchina costruisce l’intero albero delle computazioni anche la complessità spaziale è dello stesso ordine. Tuttavia la macchina potrebbe limitarsi a memorizzare solo l’ultimo cammino visitato, ad esempio, in preordine sinistro; in tal modo potrebbe generarli ed esaminarli tutti in sequenza (ad esempio: S, S, S, S, S - S,S,S,S,D S, S, S, D, S S, S, S, D, D S, S, D, S, S ….) senza costruire l’intero albero. In tal caso la complessità spaziale risulta (n). Quesito 2 Consideriamo una macchina di Turing che costruisce l’automa deterministico equivalente a quello non deterministico di partenza, e quindi effettua il riconoscimento della stringa simulando direttamente l'automa deterministico. a. E’ noto che nel caso pessimo l'automa deterministico, equivalente a quello in input di m stati, ha (2m) stati e quindi la complessità spaziale della macchina è dominata da questo fattore. Allo stesso modo, la complessità temporale è dominata dalla costruzione di tale automa. b. Una volta costruito l’automa deterministico la MT può semplicemente simulare quest’ultimo con la stessa sua complessità, ossia (n) per la complessità temporale e (1) per quella spaziale, tenendo conto ovviamente che la memoria finita costituita dagli (2m) stati non è funzione della lunghezza della stringa di ingresso x. Soluzione alternativa del Quesito 2: Considerando i quesiti a e b come indipendenti, possiamo scegliere un algoritmo diverso in ciascuno dei due casi, puntando unicamente a minimizzare la complessità rispetto al parametri considerato nel punto in questione. Per il punto b la soluzione basata sulla determinizzazione suggerita nella soluzione precedente rimane la migliore dal punto di vista della complessità ottenibile. Per il punto a, invece, possiamo utilizzare di nuovo l'algoritmo di simulazione del punto 1. La complessità spaziale è quella necessaria a memorizzare l'ultimo cammino visitato; essendo un cammino lungo n ed essendo necessari log m bit per memorizzare (sinteticamente in binario) l'informazione su uno degli m stati, abbiamo una complessità spaziale di (log(m)) visto che n non è funzione di m. Similmente, la complessità temporale è quella necessaria ad esplorare l'albero delle 2n computazioni, dove ogni passo costa l'aggiornamento dello stato corrente, ossia log(m). Quindi anche la complessità temporale è (log(m)). Ovviamente questa valutazione di complessità è formalmente corretta ma irrealistica perchè ignora completamente la dimensione di parte dell'input (e i suoi effetti sulla complessità). Informatica Teorica Appello d'esame del 16 luglio 2008, Sezione Mandrioli Si consideri la grammatica G seguente: S BAcB | A aAa | acBa B CcB | C aC | a Esercizio 1 (punti 11) Si fornisca un automa che riconosca il linguaggio L(G) generato da G. L’automa deve appartenere alla classe di minima potenza riconoscitiva possibile per riconoscere L(G). Si spieghi brevemente perché la classe dell’automa scritto è quella a potenza minima possibile. Esercizio 2 (punti 12) q) Si dica, giustificando brevemente la risposta, se è decidibile il problema di stabilire se L(G) intersecato con il linguaggio {(a*c)*} produce il linguaggio vuoto o no. r) Si dica, giustificando brevemente la risposta, se è decidibile il problema di stabilire se, dato un generico automa a stati finiti A, il linguaggio L(A) riconosciuto da A è uguale al linguaggio L(G) oppure no. s) Si dica, giustificando brevemente la risposta, se, fissata una grammatica G', è decidibile il problema di stabilire se, dato un generico automa a stati finiti A, il linguaggio L(A) riconosciuto da A è uguale al linguaggio L(G’) generato da G’ oppure no. t) Si dica, giustificando brevemente la risposta, se è decidibile il problema di stabilire se, dati una generica grammatica G’ ed un generico automa a stati finiti A, il linguaggio L(A) riconosciuto da A è uguale al linguaggio L(G’) generato da G’ oppure no. Esercizio 3 (punti 10) Si descrivano a grandi linee il funzionamento di una macchina di Turing deterministica e di una RAM che riconoscano L(G) e se ne valutino le complessità secondo la classe , usando per la RAM il criterio di costo logaritmico. Soluzioni schematiche Esercizio 1 La grammatica genera il linguaggio: L(G) = { (a+c)*anc(a+c)*anc(a+c)* | n > 0 } , dove x+ = x* – {}. Per riconoscere L(G) è necessario e sufficiente un automa a pila nondeterministico. La pila è necessaria per effettuare il conteggio delle sottostringhe an. Anche il nondeterminsmo è necessario perchè con il solo determinismo non è possibile stabilire in quale punto delle sottostringhe fatte di ‘a’ è necessario iniziare ad usare la pila per contare tali ‘a’. In altre parole, il nondeterminismo serve a discernere le sottostringhe del tipo (a+c)*, per le quali è sufficientemente un riconoscimento a stati finiti senza pile, da quelle del tipo an per le quali la pila è invece ovviamente necessaria. Un possibile ND PDA che riconosce L(G) è il seguente: c,Z0/Z0 a,Z0/Z0 a,Z0/Z0A c,A/A a,Z0/Z0 a,A/A a,Z0/Z0 a,A/AA a,Z0/Z0A a,A/A a,A/ a,A/A a,Z0/Z0 c,Z0/Z0 c,A/A a,A/ c,Z0/Z0 a,Z0/Z0 a,A/ Esercizio 2 Decidibile, la risposta è chiusa (Si/No). Anzi, in questo caso il problema è deciso, in quanto l'intersezione non è vuota. Decidibile: L(G) non è un linguaggio regolare, quindi la risposta sarà sempre No, qualunque sia A. Decidibile: se L(G') non è un linguaggio regolare la risposta sarà sempre No; se invece L(G') è regolare, siccome è decidibile il problema di stabilire se FSA riconoscono lo stesso linguaggio, ci sarà sempre una MT che, fissato un linguaggio regolare, determina se questo è uguale a quello riconosciuto da un FSA in input. Ora, fissato L(G'), non è detto che io sappia esattamente quale è questa MT (i linguaggi regolari sono un'infinità enumerabile, e non è detto che io capisca quale di questi è quello generato da G'), ma essa di certo esiste, rendendo il problema decidibile. Indecidibile, in quanto riconducibile al problema di stabilire se una generica MT calcola una certa funzione (in questo caso, quella corrispondente all'FSA), oppure no. Esercizio 3 Una macchina di Turing (deterministica) che riconosce L(G) può operare nella seguente maniera (al solito indichiamo con n la lunghezza dell'input): In primo luogo effettua una scansione completa dell'input per verificare che sia una stringa del tipo (a+c)k con k > 1. Questa è una condizione necessaria perchè sia in L(G), e può essere verificata in tempo (n). Se il test precedente è passato con successo, l'input appartiene a L(G) se e solo se esistono due sottostringhe (massimali, ossia racchiuse tra due 'c') di sole 'a' della stessa lunghezza. Questa verifica può essere fatta nella seguente maniera: per ogni sottostringa di 'a' incontrata sequenzialmente nell'input: o la sottostringa di 'a' viene ricopiata su un nastro di memoria; o si prosegue la scansione dell'input confrontando ogni successiva sottostringa di 'a' con quella presente sul nastro di memoria. Nel caso pessimo questo comporta una scansione completa dell'input per ogni sottostringa di 'a' incontrata. Possono esservi fino a (n) sottostringhe di questo tipo, quindi la complessità temporale di caso pessimo è (n2), che è anche la complessità complessiva dell'algoritmo. La complessità spaziale è invece chiaramente (n). Una macchina RAM può usare un algoritmo simile a quello descritto per la macchina di Turing, usando ad esempio dei contatori per memorizzare lunghezza delle sottostringhe di 'a' incontrate. Si avrebbero dunque (n) contatori, ciascuno memorizzante un intero (n). Adottando il criterio di costo logaritmico, i (n2) confronti da effettuare porterebbero pertanto a una complessità temporale complessiva di (n2 log n). La complessità spaziale, secondo le stesse considerazioni, sarebbe di (n log n). Informatica Teorica Appello d'esame dell’8 Settembre 2008, Sezione Mandrioli Il tempo a disposizione è di 2 ore Esercizio 1 (Punti 13) Si considerino le seguenti regole relative al funzionamento di un apparecchio per l’uso del Bancomat: 1. L’apparecchio si trova inizialmente in uno stato di riposo 2. L’introduzione della tessera provoca la transizione in uno stato di immissione codice 3. Il codice consta di 5 cifre 4. L’immissione del codice è ultimata se l’utente ha digitato 5 cifre e successivamente premuto il tasto ENTER, oppure dopo che sono trascorsi 5 secondi dall’immissione della quinta cifra. 5. Una volta ultimata l’immissione del codice l’apparecchio passa in uno stato di verifica. 6. Se, nello stato di immissione, trascorrono più di 5 secondi senza che si digiti una cifra e non è stata ancora digitata la quinta cifra, viene espulsa la tessera e l’apparecchio torna nello stato di riposo. Si formalizzino mediante formule del prim’ordine solo le regole 4, 5 e 6 (le altre servono da contesto ma non è necessario che vengano formalizzate esplicitamente). Si suggerisce di utilizzare i seguenti predicati che denotano possibili stati in cui l’apparecchio si trova in un generico istante t: Riposo(t) ImissioneDati(t) Verifica(t) CifreImesse(t, k) indica che all’istante t le cifre immesse sono k; lo stato ha senso solo durante lo stato ImmissioneDati. e i seguenti predicati che denotano possibili eventi che si verificano in un generico istante t: PremiCifra(t) PremiEnter(t) EspulsioneTessera(t) Esercizio 2 (Punti 11) Dire se i seguenti problemi sono decidibili, solo semidecidibili, o né uno né l'altro: 1. Stabilire se, data una generica Macchina di Turing M, il linguaggio riconosciuto da M è vuoto. 2. Stabilire se, data una generica Macchina di Turing M che non ha cicli (cioè il cui grafo corrispondente è aciclico), il linguaggio riconosciuto da M è vuoto. 3. Stabilire se, data una generica Macchina di Turing M che non ha autoanelli (cioè il cui grafo corrispondente non ha archi che puntano al nodo da cui originano; un autoanello è un caso particolare di ciclo), il linguaggio riconosciuto da M non è vuoto. Esercizio 3 (Punti 10) Si consideri la traduzione di una stringa di ingresso w {a,b,c}+ in una stringa an/2bm, dove n è il numero di a nella stringa w e m è il numero di b nella stringa w. 1. Si descriva a parole una Macchina di Turing a k nastri che realizza la traduzione indicata, e se ne diano le complessità spaziale e temporale. 2. Si descriva a parole una Macchina RAM che realizza la traduzione indicata, e se ne diano le complessità spaziale e temporale usando il criterio di costo logaritmico. 3. Si descriva a parole una Macchina di Turing a nastro singolo che realizza la traduzione indicata, e se ne diano le complessità spaziale e temporale. NB: Il punteggio conseguito sarà tanto più alto tanto migliori saranno le complessità delle macchine ideate. Soluzioni Esercizio 1 Come già in altre occasioni, per un generico stato S, Up_to_now_S(t) è una notazione abbreviata per la formula seguente (t1 (t t1 t ) S (t1 )) (sottintes o : 0) Similmente From_now_on_S(t) è una notazione abbreviata per la formula seguente: (t1 (t t1 t ) S (t1 )) Ciò premesso le regole 4 e 6 possono essere formalizzate nel modo seguente, sottintendendo per ognuna la quantificazione universale t, k: Regole 4 e 5 ( Up_to_now_CifreImmesse(t, 5) PremiEnter(t) From_now_on_ImmissioneDati(t) From_now_on_Verifica(t) ) ( Up_to_now_CifreImmesse(t, 5) PremiCifra(t-5) (t1 (t-5 < t1 < t) (PremiEnter(t) PremiCifra(t))) From_now_on_ImmissioneDati(t) From_now_on_Verifica(t) ) Regola 6 Up_to_now_ImmissioneDati(t) Up_to_now_CifreImmesse(t, k) (0 k <5) (t1 (t-5 < t1 < t) (PremiEnter(t) PremiCifra(t))) From_now_on_ImmissioneDati(t) From_now_on_Riposo(t) EspulsioneTessera(t) Esercizio 2 1. Il problema non è né decidibile, né semidecidibile. Non è decidibile per il teorema di Rice (l’insieme delle MT che riconoscono il linguaggio vuoto non è l’insieme vuoto, né è l’insieme universo). Non è neanche semidecidibile, in quanto è semidecidibile il suo complemento: enumerando opportunamente le stringhe in ingresso, con la solita tecnica diagonale è possibile simulare le esecuzioni della MT in modo che, se una stringa viene accettata, prima o poi questa viene trovata; in caso contrario, la computazione prosegue all’infinito. 2. Il problema è decidibile (e quindi anche semidecidibile). Il numero di computazioni di una MT senza cicli è finito ed ognuna di esse è fatta di un numero finito di passi. E’ quindi possibile enumerarle tutte, e determinare se almeno una di queste si porta in stato finale oppure no. 3. Il problema non è decidibile, ma è semidecidibile. Data una MT qualunque (anche con autoanelli) è possibile costruirne in modo algoritmico una che sia invece priva di autoanelli (è sufficiente “sdoppiare” gli stati su cui ci sono autoanelli). Di conseguenza, è facile ridurre il problema della emptiness del linguaggio di una MT generica (cioè il determinare se il linguaggio accettato è vuoto o no) a quello di una MT senza autoanelli. Se quindi fosse decidibile il problema in oggetto, lo sarebbe anche quello della emptiness di una MT generica (che è in effetti il complemento di quello in oggetto), che non è decidibile per quanto detto al punto 1. Il problema è invece semidecidibile, in quanto, sempre per quanto detto al punto 1, per una generica MT (e quindi a maggior ragione per una senza autoanelli) è possibile, enumerando le stringhe in ingresso e le varie computazioni con meccanismo diagonale, determinare se questa accetta almeno una stringa (in caso contrario il procedimento algoritmico non termina). Esercizio 3 1. E’ possibile scrivere una MT che effettua la traduzione desiderata senza fare uso di nastri di memoria, e in tempo (n). Tale macchina deve semplicemente scorrere il nastro di input 2 volte: una per produrre in uscita an/2, ed una per produrre in uscita bm. Più precisamente, nella prima passata, la macchina produce, ogni 2 a incontrate, una a in uscita. Arrivata in fondo al nastro di input, essa lo scorre al contrario, producendo una b per ogni b letta. 2. Una macchina RAM, non potendo scorrere al contrario il nastro di input, dovrà necessariamente ricorrere alla memoria per effettuare la traduzione desiderata. Più precisamente, essa si può comportare nella seguente maniera: legge la stringa in ingresso e, per ogni a (risp. b) letta, incrementa un opportuno contatore memorizzato in M[1] (risp. M[2]). Alla fine della lettura divide M[1] per 2, quindi ripete M[1] volte la scrittura in uscita di a, ed M[2] volte la scrittura in uscita di b. Le complessità (a criterio di costo logaritmico) di una simile macchina sono (n log(n)) per quella temporale, e (log(n)) per quella spaziale. 3. Una Macchina di Turing a nastro singolo può realizzare la traduzione desiderata con un meccanismo simile a quello dell’insertion sort per portare prima tutte le a in testa alla stringa, farle seguire dalle b, e quindi chiudere con le c. Una volta fatto questo, è sufficiente cancellare le c in coda per ottenere la traduzione desiderata. La complessità temporale di una simile macchina di Turing è, come per l’algoritmo di insertion sort, (n2); quella spaziale è (n). Informatica Teorica Appello d’esame del 3 febbraio 2009, Sezioni Mandrioli-Pradella Il tempo a disposizione è di 1h30. Esercizio 1 (punti 8) Sia data la seguente grammatica G1: S AcS | bBS | bac A ba B ac 1) Si dica quale è il linguaggio generato da G1. 2) Si scriva un automa che riconosce il linguaggio generato da G1. L’automa deve appartenere alla classe di potenza riconoscitiva minima tra quelle che riconoscono il linguaggio generato da G1. Esercizio 2 (punti 12) Si dica, giustificando brevemente la risposta, se è decidibile l’equivalenza tra: 1. Un automa a stati finiti e una macchina di Turing. 2. Una grammatica non contestuale e una macchina di Turing. 3. Una macchina di Turing e la grammatica G1 dell’esercizio 1. 4. Due automi a stati finiti. 5. Un automa a stati finiti e un automa a pila determinitico. (Suggerimento: si tenga presente che l’intersezione tra il linguaggio riconosciuto da un automa a stati finiti e quello riconosciuto da un automa a pila deterministico è riconoscibile da un automa a pila deterministico costruibile algoritmicamente sulla base dei due automi dati.) Esercizio 3 (punti 11) Si descriva a grandi linee il funzionamento di una macchina di Turing deterministica che riconosce il linguaggio L = {w4 | w {a, b, c}+} (laddove w4 = wwww). Si valutino le complessità spaziale e temporale della macchina di Turing descritta. La macchina di Turing deve essere tale da minimizzare la complessità spaziale. Soluzioni schematiche Esercizio 1 La grammatica genera il linguaggio: L(G1) = { (bac)+ } L(G1) è un linguaggio regolare, cioè riconoscibile da un automa a stati finiti. Un automa a stati finiti che riconosce il linguaggio è il seguente: b a b c c a Esercizio 2 Le prime 3 domande hanno risposta negativa sulla base di normali ragionamenti in applicazione al teorema di Rice. La domanda 4 ha risposta positiva, grazie alla chiusura del formalismo rispetto alle operazioni booleane: L1 L2 ( L1 L2) = ( L1 L2) = . Alla stessa maniera, sfruttando l’informazione fornita nel suggerimento e il fatto che sia i linguaggi regolari che quelli noncontestuali deterministici sono chiusi rispetto al complemento, si dimostra decidibile anche il quesito 5. Esercizio 3 Una macchina di Turing (deterministica) a 2 nastri che riconosce il linguaggio desiderato può operare nella seguente maniera (al solito indichiamo con n la lunghezza dell'input): 1- conta gli elementi dell'input in binario (usando il nastro T1) 2- se il numero su T1 è divisibile per 4 (deve terminare con 2 zeri), allora elimina gli ultimi 2 zeri per dividere per 4 3- torna all'inizio dell'input 4- copia il contenuto di T1 nel nastro T2, tenendo traccia nello stato del simbolo letto 5- si sposta sul nastro di input decrementando T2 ad ogni mossa 6- quando T2 è a zero, confronta il simbolo sotto la testina con quello memorizzato, se sono diversi, si blocca 7- si sposta di una cella in avanti sul nastro di input; se è in fondo al nastro, stop con successo 8- torna indietro di T1 elementi sul nastro (usando ancora T2 come contatore) 9- ripete dal passo 4 La complessità spaziale della macchina è log(n). La complessità temporale, invece, è n2log(n). Algoritmi e Principi dell'Informatica Prima Prova in Itinere 18 Novembre 2011 Il tempo a disposizione è di 2 ore Esercizio 1 (punti 7/12) Si considerino le seguenti definizioni: 1. Una grammatica si dice lineare a destra se le sue produzioni sono del tipo A ----> Bx, x VT*, oppure, A ----> x, x VT*. 2. Una grammatica si dice lineare a sinistra se le sue produzioni sono del tipo A ----> xB, x VT*, oppure, A ----> x, x VT*. 3. Una grammatica si dice lineare a destra o a sinistra se le sue produzioni sono del tipo A ----> Bx, x VT*, oppure, A ----> xB, x VT*, oppure, A ----> x, x VT*. 4. Una grammatica si dice lineare se le sue produzioni sono del tipo A ----> yBx con y, x VT*, oppure, A ----> x, x VT*. Si confrontino tra loro le potenze generative (le famiglie di linguaggi generati) delle suddette classi di grammatiche tra loro e con quelle dei seguenti formalismi: Nota. a. Automi a stati finiti b. Automi a pila deterministici c. Automi a pila nondeterministici d. Reti di Petri (senza archi inibitori) Ogni relazione tra le diverse potenze generative deve essere accompagnata da una breve giustificazione; non è necessario che essa sia una rigorosa dimostrazione matematica ma deve essere sufficientemente chiara e convincente. Esercizio 2 (punti 6/12) Nel "problema delle 8 regine" si vogliono posizionare 8 regine su una scacchiera 88 (inizialmente vuota) in modo che nessuna regina "attacchi" (ossia si trovi sulla stessa riga, colonna o diagonale di) un'altra regina. Formalizzare tramite logica del prim'ordine una formula che specifichi tutti i requisiti del problema (e quindi sia vera se e solo se i pezzi sulla scacchiera corrispondono a una soluzione). Suggerimento: si consiglia di adottare un predicato relativo al posizionamento di una regina sulla scacchiera, ad esempio il predicato ternario p(N, X, Y) i cui argomenti sono numeri tra 1 e 8 e che indica che la regina numero N si trova alla colonna X e alla riga Y della scacchiera. Soluzione dell'esercizio 1 a. b. d. c. e. f. g. Le grammatiche lineari a sinistra (GLS) sono una sorta di abbreviazione delle grammatiche regolari: infatti, ad esempio la produzione A ----> acB può essere trasformata nella coppia di produzioni regolari equivalenti A ----> aA1; A1 ---> cB con A1 simbolo nuovo. Quindi le GLS sono equipotenti agli automi a stati finiti. Gli automi a stati finiti sono equivalenti non solo alle grammatiche regolari le cui produzioni sono del tipo A ---> aB, ma anche a quelle con produzioni del tipo A ---> Ba (che a loro volta sono equivalenti alle lineari a destra con ragionamento analogo al punto a.), purché esse non contengano contemporaneamente produzioni dei due tipi: Basta infatti associare ad una transizione del tipo (A, a) = B una produzione del tipo B ----> Aa, invece che A ---> aB e "invertire stati finali con assioma: la derivazione parte dalla fine della stringa invece che dall'inizio. Quindi GLS, GLD, grammatiche regolari e automi a stati finiti sono tutti equipotenti. Le grammatiche lineari a destra o a sinistra sono equipotenti alle grammatiche lineari: infatti esse ne sono un caso particolare (quindi non sono più potenti); inoltre ogni produzione del tipo A ----xBy può essere trasformata nella coppia A -----> x A1, A1 ---> by, con A1 simbolo nuovo. La grammatica lineare S ---->aSb|ab genera il linguaggio anbn che non è regolare. Quindi le grammatiche lineari e le lineari a destra o a sinistra sono più potenti di quelle lineari solo a sinistra o solo a destra. Le grammatiche lineari sono un caso particolare di quelle non contestuali. Tuttavia esse non possono generare linguaggi come {anbncmdm}. Questo fatto però, pur avendo una certa evidenza intuitiva non è di facile dimostrazione in termini rigorosi. Di conseguenza esse sono anche strettamente meno potenti degli automa a pila nondeterministici. La seguente G lineare S ---> aAb | aBbb A ---> aAb | ab B ---> aBbb | abb invece genera il linguaggio {anbn} {anb2n} notoriamente nondeterministico. Siccome il precedente linguaggio {anbncmdm} è invece deterministico, se ne deduce che le potenze delle grammatiche lineari e degli automi a pila deterministici non sono confrontabili. E' noto che le PN senza archi inibitori, usate come riconoscitori di linguaggi hanno una potenza non comparabile con quella delle grammatiche non contestuali: accettano ad esempio {a nbncn} ma non sono in grado di riconoscere {wcwR}. Siccome quest'ultimo linguaggio è facilmente generabile mediante una G lineare, se ne conclude che le PN non sono comparabili neanche con le G lineari. Soluzione dell'esercizio 2 Risolviamo l'esercizio imponendo che ogni regina occupi esattamente una posizione sulla scacchiera, ogni riga e ogni colonna contengano al più una regina e che non ci siano due regine sulla stessa diagonale. In questa prima soluzione utilizziamo un predicato ternario p(N, X, Y) che indica che la regina numero N si trova alla colonna X e alla riga Y della scacchiera n(1≤nn≤8 xy(p(n,x,y) 1≤xx≤8 1≤yy≤8) (almeno una posizione sulla scacchiera per la regina n) nx1x2y1y2 (p(n,x1,y1) p(n,x2,y2) x1=x2 y1=y2) (al più una posizione sulla scacchiera per la regina n) xn1n2y1y2 (p(n1,x,y1) p(n2,x,y2) n1=n2 y1=y2) (al più una regina in colonna x) yn1n2x1x2 (p(n1,x1,y) p(n2,x2,y) n1=n2 x1=x2) (al più una regina in riga y) n1n2x1x2y1y2 (p(n1,x1,y1) p(n2,x2,y2) n1n2 x1+y2 x2+y1) (due regine diverse non sono mai sulla stessa diagonale NW-SE) n1n2x1x2y1y2 (p(n1,x1,y1) p(n2,x2,y2) n1n2 x1+y1 x2+y2) (due regine diverse non sono mai sulla stessa diagonale NE-SW) Soluzione alternativa che fa uso di un predicato binario p(X,Y) che indica che c'è una regina in colonna X e riga Y. x(1≤xx≤8 y(p(x,y) 1≤yy≤8) (almeno una regina in colonna x) xy1y2 (p(x,y1) p(x,y2) y1=y2) (al più una regina in colonna x) y(1≤yy≤8 x(p(x,y) 1≤xx≤8) (almeno una regina in riga y) yx1x2 (p(x1,y) p(x2,y) x1=x2) (al più una regina in riga y) x1x2y1y2 (p(x1,y1) p(x2,y2) (x1x2 y1y2) x1+y2 x2+y1) (due regine diverse non sono mai sulla stessa diagonale NW-SE) x1x2y1y2 (p(x1,y1) p(x2,y2) (x1x2 y1y2) x1+y1 x2+y2) (due regine diverse non sono mai sulla stessa diagonale NE-SW) Algoritmi e principi dell’Informatica Seconda prova in itinere 24 Gennaio 2012, Sezione Mandrioli Avvisi importanti I punteggi attribuiti ai singoli esercizi hanno valore solo per chi sostiene la II prova completa del corso integrato. Per chi deve sostenere solo il modulo di Informatica 3 o l’intero appello (riservato ai laureandi) il punteggio sarà diverso e valutato caso per caso. Chi deve sostenere solo l’esame di Informatica 3 deve risolvere gli esercizi 2, 3, 4 in 2 ore. Chi deve sostenere la II prova del corso integrato deve risolvere gli esercizi 1, 2, 3, 4 in 2 ore e 15 minuti. Chi deve sostenere l’intero appello deve risolvere tutti gli esercizi in 3 ore e 30 minuti. Su ogni foglio consegnato devono essere indicati chiaramente: Cognome, nome, numero di matricola Quale dei tre tipi di prova di cui sopra si sta sostenendo Esercizio 1 (punti 4/18-esimi) Si dica, giustificando brevemente ma precisamente la risposta, se la seguente funzione è calcolabile: Per i compreso tra 1 e 1000, j compreso tra 1 e 10000 f(i, j) = 1 se la i-esima MT si ferma computando il dato j, 0 altrimenti. Esercizio 2 (punti 6/18-esimi) Si descrivano, mediante opportuno pseudocodice, due algoritmi che simulino il comportamento di due rispettivi automi a pila che riconoscano i seguenti linguaggi: o L1 = { an bn } { an b2n }| n 1 o L2 = {wwR | w {a,b}*} ( wR indica, al solito, la stringa speculare di w) NB1: gli algoritmi non devono semplicemente decidere se una stringa appartiene al linguaggio dato, ma simulare completamente il comportamento dell’automa, ossia ripercorrere –senza necessariamente fornirle in output- le stesse computazioni che eseguirebbe l’automa. NB2: si può assumere che l’input dell’algoritmo sia una stringa di caratteri seguita da un terminatore di “fine stringa”. NB3: la scelta dello pseudocodice è lasciata allo studente: può essere un linguaggio di tipo “mini-Pascal” o “mini-C” o in stile RAM; o anche in “linguaggio naturale strutturato”. E’ però importante che la descrizione degli algoritmi sia sufficientemente precisa da non lasciare dubbi sulla semantica delle operazioni elementari, sul loro costo e sul fatto che esse corrispondano alle operazioni astratte dei corrispondenti automi a pila. Si valuti la complessità temporale di entrambi gli algoritmi nel caso pessimo, adottando il criterio di costo ritenuto più opportuno (e spiegandone brevemente la scelta) E’ possibile costruire MT deterministiche che riconoscano gli stessi linguaggi con complessità asintotica migliore di quella dei due rispettivi algoritmi? In caso positivo, quali complessità sono ottenibili? Spiegare brevemente le risposte fornite. Esercizio 3 (punti 2/18-esimi) Si consideri una tabella di hash con 18 posizioni. Si vuole gestirla usando il double hashing (h1(n)+i*h2(n)) mod 18 (con n numero da inserire e i numero del tentativo). Dire quale tra queste coppie di funzioni si adotterebbe motivando brevemente la risposta 1) h1=n mod 9 e h2=n mod 3 2) h1=n mod 13 e h2=n mod 7 Esercizio 4 (punti 7/18-esimi) Si ha un array di n liste; ognuna delle quali contenente al più m elementi che descrivono gli stipendi di una società. Ogni lista contiene i dati di uno dei reparti della società. Supponendo che ognuna delle liste contenga gli elementi in ordine crescente di stipendio, si progetti un algoritmo capace di generare un'unica lista ordinata per stipendio di tutti i dipendenti della società cercando di ottenere la miglior complessità temporale possibile e se ne fornisca una valutazione. NB: si noti che n e m sono due parametri indipendenti che determinano la dimensione del problema. Esercizio per il recupero della prima prova 1. Si progetti un automa A1 che riconosca il linguaggio L1 = { an bn | n 3 } L'automa deve appartenere ad una classe C (tra FSA, PDA, TM) di automi a potenza minima tra quelli che riconoscono L1. 2. Si progetti quindi a partire dall'automa A1, un automa A2 a potenza minima che riconosca il linguaggio L2 = L1+. 3. La classe C è chiusa rispetto all'operazione "+" di chiusura transitiva ("più di Kleene")? 4. In caso affermativo, descrivere sinteticamente il procedimento che, dato un automa A appartenente alla classe C, consente di sintetizzare l'automa che riconosce il linguaggio L(A)+. In caso negativo, dire come si può determinare se nessun automa della classe C può riconoscere L(A)+. 5. Si dia la specifica logica del linguaggio L2. 6. (Parte opzionale, da svolgere solo dopo aver completato le precedenti) Costruire una rete di Petri che accetti L1. Soluzioni schematiche Esercizio 1 La funzione proposta ha un dominio finito (o, se la si volesse definire sull’intero N X N , sarebbe decidibile stabilire se una coppia <i,j> appartiene al suo dominio di definizione.). Quindi essa è esprimibile come una matrice 1000 X 10000 in ogni elemento della quale si trova un 1 o uno 0. Esiste un numero finito di tali matrici; ognuna delle quali può essere calcolata da un’opportuna MT; quindi la funzione data è sicuramente calcolabile (anche se il ragionamento suddetto non porta a costruire la MT che la calcola.) Esercizio 2 Entrambi i linguaggi sono nondeterminisitici. a. Nel primo caso l’automa riconoscitore compie una sola scelta nondeterministica (come prima mossa) e successivamente si comporta in modo deterministico. Quindi un algoritmo può simularne il comportamento simulando inizialmente il riconoscimento mediante pila di { an bn } (o viceversa); se questo primo tentativo fallisce –assumendo che la stringa di ingresso sia stata memorizzata preliminarmente- passa alla simulazione dell’automa che riconosce { an b2n }. Ovviamente in tal caso la complessità temporale dell’algoritmo (a costo costante) è (n) (e (n.log(n)) a costo logaritimico). b. Nel caso di L2 invece l’automa a pila “naturale” che lo riconosce decide nondeterministicamente ad ogni passo se impilare il simbolo letto o iniziare a confrontarlo con quello in cima alla pila; ovviamente, una volta deciso di iniziare il confronto il comportmento diventa deterministico e si conclude con successo solo se la pila viene completamente svuotata esattamente in corrispondenza della lettura dell’ultimo carattere. Un algoritmo che simuli tale comportamento può consistere di due cicli: il primo scandisce e mette in pila ogni simbolo letto; un secondo ciclo, interno al primo, per ogni simbolo “impilato”: Copia l’attuale contenuto della pila Riprende la lettura dal simbolo successivo a quello appena impilato e procede verificando deterministicamente l’eguaglianza tra ogni simbolo letto e quello in pila (ovviamente eliminandolo di volta in volta dalla pila). Se la pila viene svuotata esattamente in corrispondenza della lettura dell’ultimo carattere (all’uopo un normale algoritmo può usufruire di un carattere apposito (ETX)) la stringa viene accettata e l’esecuzione interrotta. Altrimenti si esce dal ciclo interno e si riprende l’esecuzione dall’ultimo carattere letto nell’esecuzione del ciclo esterno. Per fare ciò può essere necessario –se l’unità di I/O non lo permette- aver inizialmente memorizzato l’intera stringa. La complessità di un tale algoritmo è quadratica (a criterio di costo costante) perché nel caso pessimo il ciclo esterno viene eseguito n volte e quello interno i volte (più la copiatura della stringa impilata fino all’entrata, a sua volta lunga i) per l’i-esimo carattere letto nel ciclo esterno. Anche in questo caso, l’uso del criterio di costo logaritmico non fa che aggiungere un fattore log(i) a ogni memorizzazione o eliminazione di un carattere dalla pila, producendo quindi una complessità (n2.log(n)) 3. Essendo la complessità asintotica del primo algoritmo lineare essa non è ovviamente migliorabile. Al contrario un semplice macchina di Turing che riconosca L2 in tempo lineare può operare nel modo seguente: Memorizza la stringa di ingresso su due nastri; Pone le due testine, rispettivamente all’inizio e alla fine della stringa; Verifica che i caratteri letti dalle due testine coincidano, spostandole successivamente a destra e sinistra, rispettivamente; NB: ai fini della complessità asintotica non è necessario –ma è possibile per migliorare la costante di proporzionalità- verificare che le testine giungano a metà stringa. Esercizio 3 Nella scelta 1) sia h1 che h2 sono divisori di 18, quindi favoriscono una “clusterizzazione” dei dati con rischio di rapida saturazione di alcune posizioni. E’ quindi preferibile la seconda coppia di funzioni proposta. Si noti tuttavia che anche quest’ultima non offre buoni risultati in termini di distribuzione nelle varie posizioni: ad esempio per n = 9 si ottiene solo una sequenza di numeri dispari: 9, 11, 13, 15, 17, 1, 3, …. Esercizio 4 Un algoritmo “banale” potrebbe costruire incrementalmente l’unica lista globale “fondendo” (operazione di merge) le varie liste ad una ad una. Il merge di due liste lunghe al più h richiede un tempo O(h); quindi la complessità totale di un tale algoritmo sarebbe n O( (i.m m)) O(n 2 .m) i 1 Un algoritmo un po’ meno banale, invece, potrebbe trarre ispirazione dal merge-sort e fondere le liste a due a due in diverse passate: La prima passata produrrebbe quindi n/2 liste di lunghezza (al più) 2.m ciascuna, in tempo O(n.m); la seconda n/4 liste di lunghezza 4.m, sempre in tempo O(n.m), ecc. Il numero di passate, risulterebbe, al solito O(log(n)) per una complessità totale O(n.m.log(n)). Esercizio per il recupero della prima prova Quesito 1 Per riconoscere il linguaggio L1 occorre la capacità di “contare” numeri arbitrariamente grandi. Il formalismo degli automi a stati finiti non è pertanto sufficiente (come si può dimostrare, ad esempio, tramite il pumping lemma). Un semplice automa a pila che riconosce L1 è il seguente. La classe degli automi a pila (deterministici) è pertanto a potenza minima, per il problema dato, tra quelle specificate nel testo. Quesito 2 Mostriamo ora un automa a pila che riconosce L2. Quesiti 3 e 4 La classe dei linguaggi riconosciuti da automi a pila deterministici non è chiusa rispetto all’operazione “+”: si consideri ad esempio il linguaggio { anbn c amb2m | n, m 0} Lo è invece quella riconosciuta da automi a pila nondeterninistici. Il procedimento consiste, generalizzando la costruzione dell’esempio, nel “cortocircuitare” gli stati finali con lo stato iniziale, ripristinando contemporaneamente la situazione di pila iniziale (eventualmente mediante una serie di -mosse. Quesito 5 Specifica di L1: Specifica di L2: x(xL1n(n3x=an.bn)) x(xL2xL1yz(yL1zL2x=y.z)) Soluzione alternativa (senza ricorrere alla specifica intermedia di L1): x(xL2n(n3x=an.bn)zn(zL2n3x=an.bn.z)) Quesito 6 Un esempio di rete di Petri che riconosce il linguaggio L1 è il seguente, in cui la marcatura iniziale è mostrata in figura e l’insieme di marcature finali è F={MF} con MF(P6)=1 e MF(Pi)=0 per i=1,…,5. Si noti che la classe delle reti di Petri è a potenza minimale – non minima – rispetto alle precedenti perché le due classi PDA e PN sono tra loro non confrontabili. A titolo di approfondimento si osservi che non si può costruire una rete di Petri che riconosca L2. L’unica possibilità è di utilizzare archi inibitori, raggiungendo pertanto il potere espressivo delle MT. Una rete di Petri con archi inibitori che riconosce L2 è mostrata di seguito. Più in generale, è stato dimostrato che la classe dei linguaggi riconosciuti da rete di Petri non è chiusa rispetto all’operazione “+”, se non facendo ricorso agli archi inibitori. La dimostrazione formale di questo fatto è complessa. Dal punto di vista intuitivo, con riferimento all’esempio in questione, oltre a spostare il gettone da P6 a P1, occorre anche sincerarsi che il posto P5 sia vuoto, il che richiede un arco inibitore. English version Delivery time: 2 hours and 15 minutes after start. Exercise 1 (max score: 4/18 points) Consider the function f defined as follows: for 1 i 1000, 1 j 10000, f(i, j) = if the i-th Turing machine halts when computing on the input j then 1 else 0 Is f computable? Give a short but precise explanation for your answer. Exercise 2 (max score: 6/18 points) Consider the following languages: o L1 = { an bn } { an b2n }| n 1 o L2 = {wwR | w {a,b}* (as usual, wR denotes the mirror image of w) For each one of L1 and L2, provide an algorithm that simulates the behavior of a pushdown automaton recognizing L. The algorithm should not –only- accept a string iff it is accepted by the corresponding automaton, but should execute a sequence of steps corresponding to the automaton single transitions; in particular it should use its memory as a stack and manage it just as the formal automaton would do, by means of suitable push and pop –abstract- operations. You are free to describe the language in any pseudo-code you feel appropriate: could be a “mini-C” or a RAM, or even “structured natural language”, provided your description is precise enough. Evaluate the asymptotic time complexity of both algorithms by applying the cost criterion you feel more appropriate; briefly explain your answer. Is it possible to build deterministic Turing machines that accept the same languages with a better time complexity? In the positive case, how? Which complexities can you obtain? Briefly explain your answer. Exercise 3 (max score: 2/18 points) Consider a hash table with 18 placeholders. We want to manage it in a double-hashing fashion: (h1(n)+i*h2(n)) mod 18 (where n denotes the value of the key to be inserted and i denotes the iteration of the attempt to insert the element. Which one between the following pairs of functions would you choose? Why? 1) h1=n mod 9 e h2=n mod 3 2) h1=n mod 13 e h2=n mod 7 Exercise 4 (max score: 7/18 points) Assume you have an array consisting of n linked lists. Each list contains at most m elements (say, describing the salaries of the employees of a section of a firm). Assume also that each list is ordered in increasing order. Design an algorithm that, starting from the above data structure produces a single ordered list containing –all and only- the elements of the n original lists; try to optimize the time complexity of your algorithm and evaluate it (with respect to the order of magnitude ). Notice that the complexity function depends on two unrelated parameters, n, and m. Supplement exercise for those who must repeat the first midterm test 1. Build an automaton A1 that recognizes the following language L1 = { an bn | n 3 } A1 must belong to a class C (among FSA, PDA, TM) of automata with minimal power among those that recognize L1. 2. Starting from A1, build a new automaton A2 (with minimal power) that recognizes the language L2 = L1+. 3. Is class C closed under transitive closure (a.k.a. “+” or “Kleene plus”)? 4. If it is, you should sketchily describe the procedure allowing you to build the automaton that recognizes the language L(A)+, given an automaton A belonging to class C. Otherwise you should explain how you can determine whether no automaton of class C can recognize L(A)+. 5. Specify language L2 in first-order logic. 6. Optional part, to be executed only after having completed the previous parts and the other exercises. Build a Petri net that recognizes L1. Algoritmi e Prinicipi dell’Informatica (Sez. Mandrioli) Appello del 20 Febbraio 2012 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 h e 30 minuti Chi deve sostenere solo il modulo di Informatica teorica deve svolgere le parti a), b) e c) dell’Esercizio 1 e l’Esercizio 2 in 1 ora. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere la parte d) dell’esercizo 1 e l’esercizio 3 in 1 h e 30 minuti. Esercizio 1 (punti 12/30-esimi) Si consideri il seguente linguaggio: L1 = { ab, abab, ababab, ..., aabb, aabbaabb, aabbaabbaabb, …, …, an bn, an bn an bn, an bn an bn an bn, …, …} a) Fornire una specifica logica del linguaggio L1. b) Sintetizzare un automa a potenza minima (tra FSA, PDA, TM) in grado di riconoscere L1. c) Si consideri il linguaggio L2={ anbn }+. I linguaggi L1 e L2 sono equivalenti? d) Si valutino le seguenti complessità relative al riconoscimento di L1: 1. Complessità spaziale minima ottenibile mediante una macchina di Turing a k nastri 2. Complessità temporale minima ottenibile mediante una macchina di Turing a k nastri 3. Complessità spaziale minima ottenibile mediante una RAM, a criterio di costo logaritmico 4. Complessità temporale minima ottenibile mediante una RAM, a criterio di costo logaritmico Si giustifichino brevemente le risposte date Esercizio 2 (punti 8/30-esimi) Si considerino le seguenti funzioni: (si rammenta che il simbolo y denota il massimo intero y e y il minimo intero y; |y| denota il valore assoluto di y; Z denota l’insieme dei numeri interi.) f1: Z Z, f1(x) = e|x| f2: Z Z, f2(x) = e x f3: Z Z, f3(x) = x2 + 1 f4: Z Z, f4(x) = log (|x|) Siano poi T l’insieme delle funzioni totali Z Z, e H {f: Z Z | x(f(x) = 0)} Dire, giustificando la risposta, se sia decidibile il problema di stabilire se, dato un generico programma C o Java, esso computi una delle funzioni appartenenti all’insieme F = { f1, f2, f3, f4} T H Esercizio 3 (punti 10/30-esimi) Si abbiano due alberi rosso-neri, rispettivamente di cardinalità m e n, con m << n. Si definisca, mediante opportuno pseudocodice un algoritmo che costruisca una lista (monodirezionale) ordinata in ordine crescente contenente tutti e soli gli elementi appartenenti ad entrambi gli alberi, cercando di ottenerne la miglior complessità temporale possibile. Si valuti tale complessità in funzione dei due parametri m e n. Tracce di Soluzioni Esercizio 1 a) Indichiamo con L(k) il sottolinguaggio { ak bk, ak bk ak bk, ak bk ak bk ak bk, …} Specifica di L(k): xk (xL(k)x=akbk y(yL(k)x= akbk.y)) (si sottintende la definizione di wk per una generica stringa w e un generico intero k) Specifica di L1: x(xL1 k(xL(k))) b) Il linguaggio non può essere riconosciuto da un automa a pila, in quanto richiede la capacità di ricontare lo stesso numero più volte. Una macchina di Turing che riconosce L1 è definita come segue: c) Il linguaggio L1 non è equivalente al linguaggio L2, bensì ne è un sottoinsieme proprio. Un esempio di stringa di L2 che non appartiene a L1 è abaabb. d.1) Una MT può riconoscere L1 con complessità spaziale O(log(n)), n essendo la lunghezza della prima sequenza di a, e quindi della lunghezza dell’intera stringa di ingresso. Essa può infatti memorizzare il valore di n in binario (ad esempio su due nastri); ad ogni successiva scansione di una serie di a o di b usa questo contatore decrementandolo di un’unità per ogni carattere letto; al passaggio alla sequenza successiva lo risetta al valore originario (copiandolo dall’altro nastro. d.2) La MT di cui al precedente punto d.1) ha una complessità O(m.log(n)), dove m è la lunghezza dell’intera stringa. Un’analisi più raffinata potrebbe evidenziare che ogni conteggio di n a o b può essere fatto in O(n) (perché l’aggiornamento del contatore richiede: log(n ) O(n h 0 h ) O(n) 2h ); posto poi k = m/n sono necessarie k copiature di log(n) = log(m/k) bit; in ogni caso la complessità temporale totale sarebbe O(m). Una tale analisi è però superflua perché è sufficiente constatare che la semplice MT di cui al punto b) ha evidentemente complessità temporale (e spaziale) O(m). d.3 e d.4) Una RAM che riconosca L1 deve necssariament memorizzare il valore di n in un contatore (meglio in due) e poi procedere in modo analogo alla precedente MT; ogni aggiornamento del contatore però costa alla RAM O(log(n)). Quindi nel caso pessimo la complessità spaziale è O(log(n)) e quella temporale O(m.log(m)) (quando n è O(m)). Esercizio 2 L’insieme F è vuoto. Infatti l’insieme immagine di f1, f2 e f3 non contiene lo 0 (i loro valori sono tutti > 0) e f4 non è totale. Quindi nessun algoritmo può computare una funzione di F e il problema posto è banalmente decidibile. Esercizio 3 Uno schema di algoritmo per risolvere il problema posto è il seguente: Siano Tm e Tn rispettivamente i due alberi di cardinalità m e n; Si individui il massimo elemento di Tm (Questa operazione, per un albero rosso-nero costa O(log(m))); Si verifichi se questo elemento si trova in Tn (costo O(log(n))); o Se l’elemento corrente si trova anche in Tn lo si inserisca in testa alla lista, inizialmente vuota (costo O(1)); Si ripeta il ciclo precedente per tutti i successivi nodi di Tm in ordine decrescente. Si noti che per fare ciò occorre tenere traccia del nodo esaminato nella precedente iterazione del ciclo: indicando con N tale nodo, occorre quindi individuare il nodo a valore massimo a sinistra di N (assumendo che i nodi a valore minore siano a sinistra), ricerca che può comunque essere eseguite in tempo O(log(m)). La complessità totale è quindi O(m.(log(m)+log(n))), che, essendo m < n è anche O(m.log(n)). Un altro algoritmo a complessità sostanzialmente equivalente potrebbe “linearizzare” Tm in una lista ordinata in ordine crescente (a costo O(m)) e successivamente, per ogni lemento della lista verifcare se si trova in Tn (costo (O(log(n)) e in caso negativo eliminarlo dalla lista con costo O(1). Si noti che la scelta di un tale algoritmo è giustificata dall’ipotesi che m << n. In caso contrario, ad esempio se n ed m fossero sostanzialmente vicini, converrebbe linearizzare entrambi gli alberi in O(n) e poi calcolarne l’intersezione sempre in O(n). Tuttavia, se, ad esempio, m fosse O(log(n)), una complessità O(log2(n)) sarebbe nettamente preferibile. Si noti anche che in caso di ripetizioni entrambi gli algoritmi manterrebbero nella lista risultante il numero di occorrenze in Tm, non quello delle occorrenze in Tn. English version For the complete exam, the candidate must answer to all the exercises in 2h, 30’. For the first module (Informatica Teorica), the candidate must answer to parts a), b) and c) of Exercise 1, and to Exercise 2 in 1h. For the second module (Informatica 3), the candidate must answer to part d) of Exercise 1, and to Exercise 3 in 1h, 30’. Exercise 1 (points 12/30) Consider the following language: L1 = {ab, abab, ababab, ..., aabb, aabbaabb, aabbaabbaabb, …, …, an bn, an bn an bn, an bn an bn an bn, …, …} e) Give a logic specification of L1. f) Define a minimal expressive power automaton (chosen among FSA, PDA, TM) that accepts L1. g) Consider language L2 = { anbn }+. Are languages L1 and L2 equivalent? h) Assess the following complexities for recognizing L1: 5. Minimal space complexity obtainable with a k-tape Turing Machine. 6. Minimal time complexity obtainable with a k-tape Turing Machine. 7. Minimal space complexity obtainable with a RAM machine, considering the logaritmic cost criterion. 8. Minimal time complexity obtainable with a RAM machine, considering the logaritmic cost criterion. Please, give a brief motivation of the given answers. Exercise 2 (points 8/30) Consider the following functions: (Reminders: notation y denotes the maximal integer y, and y the minimum integer y; |y| denotes the absolute value of y; Z is the set of all integer numbers.) f1: Z Z, f1(x) = e|x| f2: Z Z, f2(x) = e x f3: Z Z, f3(x) = x2 + 1 f4: Z Z, f4(x) = log (|x|) Let then T be the set of all total functions Z Z, and H {f: Z Z | x(f(x) = 0)} Is it decidable the problem of stating if, given a generic program written in C or Java, it computes one of the functions in the following set? F = {f1, f2, f3, f4} T H Exercise 3 (points 10/30) Consider two red-black trees, having cardinality m and n, respectively, with m << n. Define an algorithm in pseudo-code that builds a mono-directed list that is ordered in a nondecreasing way. Such list must contain all and only the elements that belong to both the given trees. This algorithm must exhibit a time complexity as good as possible, and it must be provided as a function of the two parameters m and n. Algoritmi e Principi dell’Informatica Appello del 12 Luglio 2012 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 h 30’ Chi deve sostenere solo il modulo di Informatica teorica deve svolgere l’Esercizio 1 e l’Esercizio 2 in 1 ora 15’. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere l’esercizio 3 e l’esercizo 4 in 1 h 15’. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 7/30-esimi) Si consideri la seguente macchina di Turing M, dove q0 è stato iniziale e q4 finale: (q0,a,Z0,Z0) = <q1,Z0,Z0,S,R,S> (q1,a,_,Z0) = <q1,A,Z0,R,R,S> (q1,b,_,Z0) = <q2,_,Z0,S,L,R> (q2,b,A,_) = <q2,A,B,R,S,R> (q2,c,A,_) = <q3,C,_,R,L,L> (q3,c,A,B) = <q3,C,B,R,L,S> (q3,_,Z0,B) = <q4,Z0,B,S,S,S> Si definisca un automa a potenza minima che accetti lo stesso linguaggio di M. Esercizio 2 (punti 9/30-esimi) Siano A e G, rispettivamente una generica famiglia di automi e una di grammatiche; siano poi L(A) e L(G) le rispettive classi di linguaggi definiti da esse. Di esse si sappia che: L(A) è ricorsivamente contenuta in L(G); ossia esiste un algoritmo che dato un automa A in A costruisce una G in G ad esso equivalente, ossia tale che L(A) = L(G). L(A) è ricorsivamente chiusa rispetto al complemento; ossia esiste un algoritmo che dato un automa A in A costruisce un automa A’ in A che accetta il complemento di L(A). L(G) è ricorsivamente chiusa rispetto all’intersezione; ossia esiste un algoritmo che date due grammatiche G e G’ in G costruisce una grammatica G” in G tale che L(G”) = L(G) L(G’). Sulla base di queste e solo queste informazioni è possibile concludere che il segente problema: Dati una generica G in G e un generico A in A, tutte le stringhe generate da G sono accettate da A? è decidibile? Nel caso di risposta positiva si fornisca una breve descrizione di un algoritmo per risolvere il suddetto problema (NB: in un caso estremo si potrebbe anche dimostare la decidibilità del problema senza per questo essere in grado di produrre un tale algoritmo). E’ anche opportuno fornire qualche esempio di famiglie A e G che, soddisfacendo le ipotesi di cui sopra, godano della relativa proprietà di decidibilità. In caso di risposta negativa: Si fornisca una convincente spiegazione per essa; un modo semplice, sempre che ciò sussista, sarebbe fornire un adeguato controesempio, ossia un caso specifico di A e G che soddisfano le ipotesi ma tali per cui il problema indicato non sia decidibile. Sempre in caso di risposta negativa, è possibile individuare una nuova condizione, da aggiungere alle precedenti, che sia sufficiente per rendere decidibile il problema? Anche in questo caso si fornisca qualche giustificazione: uno schema di algoritmo, qualche esempio, … Esercizio 3 (punti 8) Si considerino alberi binari, in cui ciascun nodo contiene come informazione un numero intero. Si progetti un algoritmo che, ricevendo in input un albero e un intero TOT, restituisce 1 se esistono almeno due cammini distinti dalla radice alle foglie in cui la somma dei numeri contenuti nei nodi è uguale a TOT e 0 altrimenti. Due cammini sono distinti se differiscono anche solo per un nodo. Si calcoli l’ordine di grandezza () della complessità temporale dell'algoritmo proposto in funzione del numero n di nodi dell'albero. Esercizio 4 (punti 8) Si consideri il linguaggio L={ uu | u(a, b)+ } 1. Si definisca in maniera sufficientemente precisa e dettagliata una MT deterministica M che riconosca L, preferibilmente con complessità temporale nella classe (n), dove al solito n = |x| è la lunghezza della stringa di ingresso. Si calcoli anche la funzione di complessità temporale TM(n) di M in modo preciso, non solo con riferimento alla sua classe . 2. Si stabilisca se una MT nondeterministica N possa riconoscere lo stessso linguaggio L con una complessità temporale TN(n) tale che TN(n) < TM(n) per ogni n. Nel caso positivo si descriva, anche a grandi linee ma in maniera sufficientemente precisa da poterne ricavare con esattezza la funzione di complessità temporale, una tale macchina N. Altrimenti si spieghi il motivo per cui una tale macchina N non può esistere1. 3. Si delinei poi una macchina RAM che riconosca lo stesso linguaggio e se ne stimi la complessità temporale TR(n) facendo riferimento sia al criterio di costo uniforme che a quello logaritmico. 1 Per comodità si richiama qui la Definizione 9.11. del testo in cui si definisce la funzione di complessità temporale di una MT nondeterministica. Definizione 9.11 Sia M una MT multinastro non deterministica che accetta il linguaggio L. M ha complessità temporale TM (e, rispettivamente, complessità spaziale SM) con dominio I* se, per ogni stringa di ingresso x, x L se e solo se esiste almeno una computazione di M che accetta x in TM(x) mosse (rispettivamente, usando SM(x) celle di memoria) e nessun’altra computazione accetta x in meno di TM(x) mosse (rispettivamente, usando meno di SM(x) celle del nastro di memoria). TM(n) (rispettivamente, SM(n)) viene definita come il massimo di TM(x) (rispettivamente, SM(x)) su tutte le x L di lunghezza n. Tracce di Soluzioni Esercizio 1 Il linguaggio riconosciuto dalla MT è { anb+cn, n>0} Quindi esso è riconosciuto anche da un automa a pila deterministico facilmente costruibile. Esercizio 2 Sulla base delle sole ipotesi indicate il problema non è a priori decidibile. Ad esempio si scelga come A la classe degli automi a stati finiti e come G la classe delle grammatiche non ristrette: le due famiglie soddisfano le ipotesi; tuttavia stabilire se per una generica G in G L(G) L(A), A essendo un generico automa a stati finiti, è evidentemente indecidibile (altrimenti sarebbe decidibile stabilire se un generico L(G) è vuoto). Viceversa è proprio la decidibilità della emptiness per i linguaggi L(G) che, aggiunta alle ipotesi precedenti, rende il problema decidibile. Infatti, dati G e A, L(G) L(A) se e solo se L(G) L(A) = : le due operazioni insiemistiche sono effettive e la nuova ipotesi garantisce la decidibilità dell’uguaglianza. Purtroppo, tra le famiglie di automi e grammatiche di uso più comune le uniche che soddisfano tutte queste ipotesi sono automi e grammatiche regolari, tra l’altro equipotenti tra loro;infatti è su questa classe fondamentale che si appoggiano moderni algoritmi di verifica basati su questa decisione. A meno di non ricorrere a classi decisamente più specialistiche … Esercizio 3 int cerca(Tree t, int totale) { if(t==null) return 0; if(cercaAux(t, totale)>=2) return 1; else return 0; } int cercaAux(Tree t, int totale) { if(t==null) return 0; if(t->left==null && t->right==null) { if(totale==t->info) return 1; else return 0; } else return cercaAux(t->left, totale - t->info) + cercaAux(t->right, totale - t->info); } E’ facile constatare che la complessità temporale dell’algoritmo proposto è (n). Esercizio 4 Punti 1 e 2 (Impostazione) Un MT “naturale” deterministica M che riconosca L può operare nel modo seguente: 1. Scandisce l’intera stringa x: n mosse (+ un numero limitato di eventuali mosse extra per inizializzazione e riconoscimento di fine stringa). Nel fare ciò memorizza contemporaneamente il valore di n/2 in unario in un nastro di memoria e ricopia il valore di x in un altro nastro 2. mediante n/2 mosse; riporta la testina del nastro di ingresso a metà stringa. 3. Mediante ulteriori n/2 mosse da destra a sinistra verifica che la prima metà della stringa nel nastro di ingresso coincida con la seconda metà della stringa nel nastro di memoria. In caso di confronto positivo la stringa è accettata. Il totale delle mosse impiegate da M è dunque 2.n + c (c essendo una costante piccola indipendente da n). Una MT nondeterministica N può invece “indovinare” la metà della stringa di ingresso e operare quindi nel modo seguente: 1. Scandisce e copia la stringa di ingresso in un nastro di memoria, finché nondeterministicamente “indovina” di essere giunta alla sua metà: ciò comporta quindi n/2 mosse. 2. Mediante altre n/2 mosse riporta la testina del nastro di memoria a inizio stringa. 3. Mediante ulteriori n/2 mosse verifica che la parte restante della stringa di ingresso coincida con la stringa contenuta nel nastro di memoria. Il numero di mosse complessivo è perciò 3/2.n + c’. Punto 3 (Impostazione) La RAM, essendo deterministica, deve operare secondo le stesse linee di M (tenendo però presente che la definizione normale della RAM non permette alla macchina di riposizionare la testina di lettura); precisamente: 1. Legge e memorizza la stringa di ingresso, calcolandone la lunghezza mediante un contatore intero; 2. Dimezza il valore del contatore. 3. Per ogni valore di i, 1 <= i <= n/2 verifica che M[i] sia uguale a M[i+n/2]. Il costo complessivo, a criterio uniforme è dunque k1.n + 1 + k2.n/2 + k3, ki essendo costanti piccole che indicano il numero di operazioni elementari (READ, LOAD, STORE, …) all’interno dei vari cicli. A criterio di costo logaritmico l’esporessione precedente diventa k1.n.log(n) + log(n) + k2.n/2.log(n) + k3. Algoritmi e Principi dell’Informatica July 12th 2012 (English version) Exercise 1 (pts 7) Consider the following Turing machine M, where q0 and q4 are the initial and the final state, respectively: (q0,a,Z0,Z0) = <q1,Z0,Z0,S,R,S> (q1,a,_,Z0) = <q1,A,Z0,R,R,S> (q1,b,_,Z0) = <q2,_,Z0,S,L,R> (q2,b,A,_) = <q2,A,B,R,S,R> (q2,c,A,_) = <q3,C,_,R,L,L> (q3,c,A,B) = <q3,C,B,R,L,S> (q3,_, Z0,B) = <q4, Z0,B,S,S,S> Write an automaton of minimum expressive power (among those seen in class) which accepts the same language accepted by M. Exercise 2 (pts 9) Let A and G be a generic family of automata and a generic family of grammars, respectively; let L(A) and L(G) be the classes of languages defined from A and G, respectively, and with the following properties: L(A) is recursively contained in L(G), that is, for each automaton A in A, there exists an algorithm that builds an equivalent grammar G in G (recall that G is equivalent to A if and only if L(A) = L(G)). L(A) is recursively closed under complement, i.e. for each automaton A in A, there exists an algorithm that builds an automaton A’ in A which accepts the complement of L(A). L(G) is recursively closed under intersection, i.e. given two grammars G and G’ in G, there exists an algorithm that builds a grammar G” in G, such that L(G”) = L(G) L(G’). Given the above information, is the following problem decidable? Problem P: Given a generic G in G and a generic A in A, does A accept all the strings generated by G? If the answer is yes, do the following: 1. Sketch an algorithm that solves P. (Note that, even if you cannot provide such algorithm, you can still prove the decidability of P.) 2. Provide some examples of families A and G that satisfy the above properties and, therefore, guarantee the decidability of the problem. If the answer is no, do the following: 1. Provide a convincing explanation of why the problem is not decidable. A simple way to do so is to provide a suitable counterexample, that is, two families A and G that satisfy the hypotheses, but for which the above problem is not decidable. 2. Find, if possible, an additional property that, together with the ones listed above, makes the problem decidable. If such a property exists, also sketch an algorithm that solves P and provide some examples of families A and G that satisfy the above properties plus the additional one you identified. Exercise 3 (pts 8) Consider a binary tree data structure BT, in which each node contains an integer. Design an algorithm, that, given a BT T and an integer TOT, returns: 1 if there are at least two distinct paths, from the root to any leaf, in which the sum of the data in the nodes is equal to TOT; 0, otherwise. Two paths are distinct if they contains at least one different node. Compute the time complexity (according to the class Θ) in terms of n, the number of nodes in T. Exercise 4 (pts 8) Consider the language L={ uu | u(a, b)+ } 4. Define, in a precise and detailed way, a deterministic Turing machine M that recognizes the language with a time complexity preferably in the class (n), where n=|x| is the length of the analyzed string. Provide also a precise evaluation of the time complexity TM(n) of the machine M, still as a function of the string length n=|x|. 5. Determine whether a nondeterministic Turing machine N can recognize the same language with a time complexity function TN(n) such that TN(n)<TM(n). In the positive case describe the nondeterministic Turing machine, preferably in a precise, detailed way; otherwise, explain why the nondeterministic Turing machine cannot be more time efficient than the deterministic one. 6. Sketch a RAM machine that recognizes the language, and estimate its time complexity TR(n) as a function of the analyzed string, using both the uniform and the logarithmic cost criterion. Algoritmi e Principi dell’Informatica Appello del 10 Settembre 2012 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2 e 3 in 1h e 45 min. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3,4 e 5 in 1h e 45 min. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 7/30-esimi) Si considerino le seguenti grammatiche e i linguaggi da esse generati; si indichi, per ognuna di esse, qual è il tipo di automa a potenza minima (all’interno delle “famiglie” tradizionali: a stati finiti, a pila deterministici, a pila nondeterministici, macchine di Turing) che riconosce il linguaggio. 1. S a X b | b X a XaXb|bXa|c 2. S X | Y X a Y b | ab Y b X a | ba 3. S a X b | b Y a X a S b | ab Y b S a | ba 4. S X | Y XaYb|bYa YbXa|aXb Esercizio 2 (punti 8/30-esimi) Dire se le seguenti funzioni sono calcolabili, motivando adeguatamente la risposta: 1) f(x,y) è indefinita, se la y-esima MT (sia essa a nastro singolo) termina e durante tutta la computazione con ingresso x non esce mai dalle celle utilizzate per memorizzare la stringa x e le due celle contenenti blank immediatamente prima e dopo x, altrimenti è pari a 0; 2) g(z) = 1 se la funzione calcolata dalla z-esima MT è diversa dalla f del punto 1, 0 altrimenti. Esercizio 3 (punti 3/30-esimi) Si descriva a grandi linee una MT che accetti il Linguaggio 3 dell’Esercizio 1 e se ne valuti la complessità temporale. La descrizione della macchina può essere anche informale ma sufficientemente precisa da permettere la valutazione della complessità (asintotica) senza dubbi o ambiguità. Esercizio 4 (punti 7/30-esimi) Si considerino gli algoritmi RB-INSERT e RB-DELETE per l’inserimento e la cancellazione di nodi in e da alberi red-black. E' possibile, usando solo tali algoritmi, costruire un albero red-black fatto di esattamente 3 nodi, tutti neri? Se sì, scrivere una sequenza di invocazioni di RB-INSERT e RB-DELETE che crea l’albero desiderato, motivando il perché la sequenza scritta produce la struttura richiesta. Esercizio 5 (punti 8/30-esimi) 1. Definire un algoritmo che, dato in input un array A, restituisce il sottoarray [i,j] di A di lunghezza massima tale che, per ogni i ≤ k ≤ j, si ha A[i] ≤ A[k] ≤ A[j]. Per esempio, nel caso dell’array [5, 18, 2, 12, 4, 7, 13, -2, -5, 12] il sottoarray cercato è [2, 12, 4, 7, 13]. 2. Dire quale è la complessità temporale dell'algoritmo ideato. NB1: L'algoritmo può essere descritto in pesudocodice, oppure anche in modo informale, purchè la descrizione sia sufficientemente precisa per determinare la complessità dell’algoritmo. NB2: Il punteggio dato sarà tanto più alto quanto migliore sarà la complessità dell'algoritmo ideato. Soluzioni (parziali e schematiche) Esercizio 1 1. Il linguaggio è costituito da stringhe di lunghezza dispari, con al centro una c, tali che se in una posizione prima della c si trova una a (rispettivamente, una b) allora dopo la c, in posizione simmetrica, si trova una b (rispettivamente, una a), e viceversa. Il linguaggio è riconoscibile da un semplice automa a pila deterministico, ma non da una automa a stati finiti. 2. Il linguaggio è composto da stringhe di lunghezza pari, con simboli a e b alternati, ed è regolare. 3. Il linguaggio è costituito da stringhe di lunghezza multipla di 4, che sono sequenze di coppie di tipo aa e bb, tali che se in una posizione prima del centro della stringa si trova una a (rispettivamente, una b) allora dopo il centro, in posizione simmetrica, si trova una b (rispettivamente, una a) , e viceversa. Il linguaggio è riconoscibile da un automa a pila non deterministico, perché uno deterministico non avrebbe la possibilità di identificare la posizione centrale. 4. Il linguaggio è vuoto, quindi regolare. Esercizio 2 1) f è calcolabile, infatti il numero di configurazioni da considerare per la MT y è finito, quindi simulando la computazione possiamo controllare se si passa due volte per la stessa configurazione (loop) o se si esce dalla porzione di nastro fissata: in questo caso si restituisce 0. Se si arriva in fondo alla simulazione, si va in loop. 2) Non è calcolabile per il teorema di Rice: g è la funzione caratteristica dell'insieme degli indici di MT che non calcolano f, sicuramente né vuoto né coincidente con N (v. risposta del punto 1). Esercizio 3 Un MT che riconosca L3 può essere ottenuta mediante una semplice modifica della macchina che riconosce {wwR}: un prima scansione copia la stringa di ingresso in un nastro di memoria; durante al scansione la macchina verifica anche che la stringa appartenga a {aa, bb}* e che abbia lunghezza multipla di 4; successivamente una delle due testine viene riposizionata all’inizio della stringa e facendo procedere quest’ultima da sinistra e destra e l’altra da destra a sinistra si verifica che quando una legge ‘a’ l’altra legga ‘b’ e viceversa. La complessità temporale di una tale macchina è evidentemente (n). Esercizio 4 Per ottenere l'albero desiderato è sufficiente inserire 4 valori nell’albero. Questo crea un albero in cui i nodi ai primi 2 livelli sono neri, e sul terzo livello c’è un solo nodo di colore rosso, per esempio l’albero seguente (la posizione del nodo rosso dipende dai valori inseriti, comunque è poco rilevante): Per ottenere l’albero desiderato, è a questo punto sufficiente cancellare, mediante RB-DELETE, il nodo rosso. Esercizio 5 E’ abbastanza facile costruire algoritmi a complessità duadratica per sisolvere il problema. Volendo cercare soluzioni più efficianti si osservi che l’algoritmo seguente ha complessità lineare. MaxSubarray(A) 1 l_max := l := 1 2 u_max := u := 1 3 for i := 2 to A.length 4 if A[i] >= A[u] 5 u := i 6 elsif A[i] < A[l] 7 if u-l > u_max–l_max 8 l_max := l 9 u_max := u 10 l := u := i 11 if u-l > u_max – l_max 12 l_max := l 13 u_max := u 14 return <l_max,u_max> Esso però non sempre produce la soluzine desiderata. Ad esempio, nel caso proposto [5, 18, 2, 12, 4, 7, 13, -2, -5, 12] viene correttamente prodotta la soluzione [2, 12, 4, 7, 13]. Tuttavia se l’array originario fosse [5, 18, 2, 12, 4, 7, 13, 3, 6, 5, 8, 4, 7, 10, 12], l’algoritmo produrrebbe ancora [2, 12, 4, 7, 13] invece della più lunga [3, 6, 5, 8, 4, 7, 10, 12]. Ciò è dovuto al fatto che, dopo il valore 13 l’indice u rimane inalterato perché non vi sono più valori > 13. Si osservi però che, se l’array viene scandito in maniera simmetrica ossia da destra verso sinistra e invertendo i confronti ( e.g., elsif A[i] > A[l],)la sequenza più lunga sarebbe individuata; ovviamente una scansione da destra a sinistra avrebbe il difetto opposto; tuttavia all’accopiata dei due attraversamenti non sfuggirebbe nessuna sequenza, ragion per cui basterebbe fare questa doppia passata nei due sensi e poi scegliere la maggiore delle due sequenze massime. Ad esempio, si consideri la sequenza [3 --- 20] [2 --- 25] [3 ---22] [-1 --- 28] [2 ----20], dove i trattini indicano un numero qualsiasi di valoro compresi tra i due estremie della sottosequenza. La passata <sinistra-destra> non riesce a individuare le sottosequenze [3 ---22] e [2 ----20] mentre quella <destra-sinsitra> non coglie la [3 --- 20], indipendentemente dalla loro lunghezza. Tuttavia i due attraversamenti congiunti prendono in esame tutte le possibili sequenze; quindi non resta che individuare quella di lunghezza masima tra tutte. Si ottiene dunque una soluzione del problema a complessità (n) (e lineare). . Algoritmi e Principi dell’Informatica Appello del 27 Settembre 2012 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere l’Esercizio 1 e l’Esercizio 2 in 1 ora e 30 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere l’Esercizio 3 e l’Esercizio 4 in 1 ora e 30 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 le righe) (punti 7/30-esimi se si compilano solo le prime 3 righe, 9/30 se si compilano tutte Si considerino i seguenti linguaggi: L1 = {anbn| n 1} {anb2n| n 1} L2 = {1anbn| n 1} {2anb2n| n 1} L3 = {an1bn| n 1} {an2b2n| n 1} L4 = {anbn1| n 1} {anb2n2| n 1} e le seguenti famiglie di macchine astratte, usate come riconoscitori di linguaggi: AF: automi a stati finiti APD: automi a pila determinstici APN: automi a pila nondeterministici ARP: reti di Petri Si riempia la seguente tabella indicando in ogni casella se la famiglia indicata nella riga è in grado di riconoscere il linguaggio indicato nella corrispondente colonna; giustificare brevemente le risposte. L1 L2 L3 L4 AF APD APN ARP Esercizio 2 (punti 9/30-esimi) All’inizio di ogni anno accademico ogni studente deve compilare il proprio piano di studi. Si formalizzino mediante formule del prim’ordine le seguenti regole (semplificate) relative alla compilazione del proprio piano di studi da parte degli studenti. Il piano di studi di uno studente consiste in un numero di insegnamenti non inferiore a 3 e non superiore a 10 tra quelli ancora disponibili nel proprio corso di studi (si assuma che esista una tabella con l’elenco degli insegnamenti che ogni studente può ancora scegliere; non si prendano in considerazioni eventuali obbligatorietà e mutue esclusioni; né viene chiesto di specificare come la tabella viene aggiornata ogni anno). Ad ogni insegnamento è associato un numero di crediti. Il totale dei crediti “acquistati” nel piano di studi non deve essere inferiore a 50 e non può essere superiore a 80. NB: la formalizzazione deve specificare anche le regole intrinsecamente connesse con l’uso e il significato delle tabelle utilizzate: ad esempio, un piano di studi non può contenere più occorrenze dello stesso esame; … Suggerimento Si definiscano adeguate variabili per rappresentare studenti, insegnamenti e crediti, nonché opportune funzioni e/o predicati per rappresentare l’elenco degli insegnamenti offerti, il piano di studi, i crediti associati a ogni insegnamento, … NB: potrebbe essere conveniente, anche se non necessario, che le liste degli insegnameti contenute sia nella tabella di quelli disponibili che nel piano di studi siano costituite da elementi “adiacenti”, … Esercizio 3 (punti 8/30) Si consideri un modello di Macchina di Turing a nastro singolo (usato sia come ingresso che come memoria ed eventuale output) ma dotata di due testine di lettura-scrittura (che all’inizio della computazione sono posizionate entrambe sul primo carattere significativo del nastro). Si delineino due MT di tal fatta che riconoscano, rispettivamente il linguaggio L1 ={wwR | w {a.b}+} (al solito wR denota la stringa speculare di w) e il linguaggio L2 = {ww | w {a.b}+}. Se ne forniscano le rispettive funzioni di complessità temporale (a meno dell’ordine di grandezza definito dalla classe ). Non è necessario fornire una definizione completa delle due macchine, ma essa deve essere sufficientemente precisa da permettere una valutazione inequivoca della funzione di complessità. Il punteggio attribuito alla soluzione sarà tanto maggiore quanto migliore la complessità ottenuta. NB: tra i diversi modi, tra loro sostanzialmente equivalenti, per definire la funzione di questo tipo di macchina si propone il seguente, dall’interpretazione ovvia: : Q A Q (A {R, L, S})2; Si noti che ciò potrebbe creare una situazione di conflitto nel caso le due testine si trovassero nella stessa posizione; questo dettaglio è irrilevante ai fini dell’esercizio; si può comunque assumere che in una situazione del genere venga convenzionalmente scelto come simbolo da scrivere sul nastro al posto di quello letto, quello indicato per la testina 1. Esercizio 4 (punti 8/30) Si stabilisca quali sono i rapporti minimo e massimo tra il numero di nodi interni rossi e neri in un generico albero rosso-nero. Si giustifichi brevemente la risposta. Soluzioni (parziali e schematiche) Esercizio 1 L1 AF L2 L3 L4 NO NO NO NO APD NO SI SI NO APN SI SI SI SI ARP SI SI SI SI La ARP seguente riconosce L1assumendo come marcatura iniziale quella indicata in figura e come marcature di accettazione quella con un solo token in B22 e S2 (rispettivamente in B1 e S1) e nessun token in tutti gli altri posti; essa è facilmente modificabile in modo da riconoscere anche gli altri linguaggi. A S2 a B1 B21 A2n An b b S1 B22 b Breve illustrazione Un numero arbitrario n di scatti della transizione etichettata ‘a’ deposita n token nel posto An e 2n token in A2n. Dopo tali scatti in maniera nondeterministica una delle due transizioni uscenti da A ed etichettate inizia il deconteggio dei token accumulati in An e A2n rispettivamente: la transizione ‘b’ uscente da B1 può scattare esattamente n volte lasciando un token in B1 e nessun token in An; simmetricamente per le transizioni uscenti da B21 e B22. Perché la stringa sia riconosciuta è però necessario che alla fine degli scatti tutti i posti diversi da B22 e B1 siano vuoti (e solo uno di essi contenga un token). All’uopo le due transizioni usenti da A innescano anche un “percorso ausiliario” segnato in modo tratteggiato in figura, con il compito di svuotare rispettivamente i posti An e A2n quando diventano irrilevanti ai fini del conteggio. Esercizio 2 Si definiscano i seguenti simboli di variabili, funzioni e di predicati: st: variabile studente es: variabile esame cr: variabile crediti CR(es): numero di crediti dell’esame es Tab(st, i): l’i-esimo esame nella tabella di esami disponibile per lo studente st (NB: la tabelle non contiene ripetizioni). Se per un certo valore di i non esiste un esame nella tabella il valore Tab(st, i) è (indefinito). P_S(st, i): l’i-esimo esame inserito nel piano di studi dello studente st. Se per un certo valore di i non esiste un esame nel piano di studi il valore P_S (st, i) è (indefinito). N_Es(st) Numero di esami nel pianodi studi dello studente st. Le formule seguenti formalizzano le regole specificate dall’esercizio: st, i,j (i j Tab(st, i) Tab(st, j) P_S(st, i) P_S(st, j) st, i , es (es = P_S(st, i) j Tab(st, j) = es) st, i(Tab(st, i) j(j i Tab(st, i) ) /*idem per P_S*/ st i (Tab(st, i) = ) st,i (N_Es(st) = i (P_S(st, i+1) = k( 1 k i P_S(st, i) )) st (3 N_Es(st) 10) st ( 50 /* la formalizzazione della sommatoria può essere omessa in quanto ben nota*/ N _ Es( st) i 1 CR( P_S(st, i)) 80) Esercizio 3 Una macchina a nastro singolo che riconosca L1 può operare nel modo seguente: Inizialmente tiene ferma la testina 1 mentre la 2 si sposta fino alla fine della stringa (al termine di questa fase la seconda testina si riposiziona sull’ultimo carattere della stringa); Successivamente le due testine si spostano una a destra e l’altra sinistra verificando ad ogni passo di leggere lo stesso carattere; ciò finché entrambe non raggiungono contemporaneamente la fine della stringa di ingresso; NB : in questo modo la machina riconosce tutte e sole le stringhe palindrome in {a, b}+; questo insieme però contiene anche stringhe non in L1: precisamente quelle a lunghezza dispari; occorre quindi anche verificare che la lunghezza della stringa sia pari. La complessità di questa macchina è evidentemente (n). Una macchina a nastro singolo che riconosca L2 può operare invece nel modo seguente: Inizialmente le due testine si spostano verso destra, una a “velocità” doppia dell’altra, finché la prima non giunge a fine stringa; alla fine di questa fase –che, en passant, verifica anche che la lunghezza della stringa sia pari- entrambe le testine si spostano di una posizione a sinistra; quella più a sinistra marca anche la sua posizione con un carattere apposito che sarà riconosciuto dall’altra testina. Successivamente le due testine ripercorrono la stringa a ritroso e alla stessa “velocità” verificando di leggere sempre lo stesso carattere finché la testina di sinistra non legge un blank e quella di destra non trova la marca lasciata dall’altra. Anche in questo caso la complessità è evidentemente (n). Esercizio 4 Un albero può essere totalmente nero (si noti che normalmente ciò avviene solo attraverso qualche cancellazione che trasformi un nodo rosso in uno nero, perché ogni nuova inserzione in un albero totalmente nero inserisce un nodo rosso; quindi l’unico modo per avere un albero totalmente nero senza operare cancellazioni è che esso consista della sola radice). In tal caso il rapporto minimo è evidentemente 0. Al contrario, il massimo numero di nodi rossi lo si può ottenere se ogni nodo nero ha entrambi i figli rossi e tutti i nodi “pseudofoglie”, ossia interni ma puntanti al NIL, sono rossi. In tal caso con una semplice induzione si dimostra che il rapporto massimo è 2. Algoritmi e Principi dell'Informatica Prima Prova in Itinere 20 Novembre 2012 Il tempo a disposizione è di 2 ore Esercizio 1 (punti 7/15-esimi) Il funzionamento delle reti di Petri (PN) è normalmente definito attraverso la cosiddetta “semantica interleaving” in cui si assume che una sola transizione per volta, tra quelle abilitate in una certa marcatura, possa scattare. La letteratura però ha proposto anche definizioni diverse della semantica delle PN. Tra queste la semantica “true concurrency”, con lo scopo di evidenziare che alcune attività modellate dalle PN possono avvenire in parallelo, ammette lo scatto contemporaneo di più transizioni, tra quelle abilitate (purché ciò non violi proprietà di mutua esclusione). Un caso particolare di tale semantica è quella a “parallelismo massimo”, che assume che tutte le transizioni abilitate in una certa marcatura scattino contemporaneamente, sempre rispettando eventuali vincoli di mutua esclusione. Esercizio 1.1 Si forniscano definizioni precise, preferibilmente ricorrendo a notazioni formali (abilitazione, scatto delle transizioni, ecc.) della semantica “true concurrency” generale e di quella a “parallelismo massimo”. Per semplicità si assuma che ogni transizione possa scattare una sola volta ad ogni passo, ossia che non siano ammessi scatti multipli e contemporanei della stessa transizione, anche se il numero di token nei posti di ingresso lo permetterebbe. Esercizio 1.2 Si dica, giustificando brevemente la risposta, se le affermazioni seguenti sono vere o false: a) Nella semantica “true concurrency” il comportamento della rete è deterministico b) Nella semantica “a parallelismo massimo” il comportamento della rete è deterministico c) Se una marcatura è raggiungibile da una marcatura iniziale secondo la semantica "interleaving" lo è anche secondo la semantica "true concurrency" e viceversa d) Se una marcatura è raggiungibile da una marcatura iniziale secondo la semantica "interleaving" lo è anche secondo la semantica a “parallelismo massimo” e viceversa. Esercizio 2 (punti 5/15-esimi) Si forniscano opportune pre- e post-condizioni, codificate mediante formule del prim'ordine, per specificare il comportamento desiderato di un (frammento di) programma che, avendo in memoria due array non vuoti di caratteri, A e B di lunghezza rispettivamente n e m, con m < n, stabilisca se tutti i caratteri presenti in B compaiono anche in A con lo stesso numero di ripetizioni. Esercizio 3 (punti 5/15-esimi) Data una classe C di automi, un automa A in C viene detto minimo nella classe C se non esistono altri automi in C che riconoscano il linguaggio L(A) riconosciuto da A e che abbiano un numero inferiore di stati rispetto ad A. Rispondere ai quesiti seguenti fornendo un’opportuna giustificazione: 1. E’ decidibile il problema di stabilire se un generico automa a stati finiti è minimo nella classe degli automi a stati finiti? 2. E’ decidibile il problema di stabilire se, fissati l'alfabeto della pila e la lunghezza massima della stringa che ad ogni mossa l'automa può mettere in cima alla pila, un generico automa a pila deterministico è minimo nella classe degli automi a pila deterministici? Suggerimento: può essere di aiuto tenere presente che il problema dell’equivalenza tra automi a pila deterministici è stato recentemente dimostrato decidibile (si veda la Tabella 8.1 a pagina 352 del testo) 3. E’ decidibile il problema di stabilire se la macchina di Turing mostrata sotto è minima nella classe delle macchine di Turing? a, _ / M, <R, R> a, Z0/Z0, <S, R> q0 q1 b, M / M, <R, L> b, _ / _, <S, L> q2 c, Z0/Z0, <S, R> _, _ / _, <S, S> qF q3 c, M / M, <R, R> !" # $J # Tracce di Soluzioni Esercizio 1.1 In primo luogo si può estendere la definizione di transizione abilitata a un insieme di transizioni abilitate. Escludendo il caso più generale in cui una transizione possa scattare diverse volte in un colpo solo, si definisce, per una marcatura M: Enab(M) = {t1, t2, … tk} se per tutte e sole le transizioni t1, t2, … tk i corrispondenti posti in ingresso (Preset) sono marcati. Successivamente, la true concurrency definisce lo scatto multiplo e nondeterministico di un set di transizioni abilitate nel modo seguente M |---- {ti1 …tir} M’ se e solo se {ti1 …tir} Enab(M) token_sufficienti(ti1 …tir) /* ossia P contiene abbastanza token da far scattare tutte le transizioni in {ti1 …tir} da esso uscenti; ciò evidentemente implica una scelta nondeterministica ma vincolata su quali transizioni possano scattare concorrentemente tra quelle abilitate. */ /* la marcatura di M’ è definita nel modo tradizionale sommando gli effetti di eventuali transizioni concorrenti*/ dove token_sufficienti(ti1 …tir) è definita come P Preset {ti1 …tir} M(P) |{ tj1 … tjk}| dove { tj1 … tjk} = {ti1 …tir} Postset(P) dove Postset(P) indica l’insieme di transizioni uscenti da P. La semantica a parallelismo massimo è un caso particolare di quella true concurrency, per ottenere la quale basta aggiungere la clausola {ti1’ …tir’} tale che ({ti1 …tir} {ti1’ …tir’} Enab(M) token_sufficienti(ti1’ …tir’)) Si noti che anche con questa restrizione il comportamento della rete rimane nondeterministico e sarebbe anzi più corretto parlare di parallelismo massimale piuttosto che massimo. Esercizio 1.2 Da quanto sopra le affermazioni a) e b) sono false. La c) è vera perché la semantica interleaving non fa che mettere in sequenza scatti di transizioni “impacchettati” in un unico scatto globale dalla semantica true concurrency. La d) invece è falsa: la semantica interleaving (vedi anche punto precedente) può “sviluppare” qualsiasi sequenza di scatti multipli, ma obbligando a far scattare sempre in parallelo tutte le transizioni abilitate non è detto che si possano produrre tutte le marcature ottenibili con la semantica interleaving, come mostrato dal controesempio seguente: Nella semantica a parallelismo massimo i due token continuano a "rincorrersi" in modo sincrono senza mai raggiungersi né superarsi; cosa che non avviene nella semantica interleaving. Esercizio 2 Usando la notazione del metodo di Hoare la specifica del programma desiderato può essere espressa nel modo seguente: {n > m > 0} P {OK x (Carattere(x) i (0 < i m B[i] = x) CountB(x) = CountA(x))} dove le funzioni CountA(x) e CountB(x) sono definite nel modo seguente: CountA(x) = Count_Aux_B(x, n) e CountB(x) = Count_Aux_B(x, m). Count_Aux_B(x, y) è a sua volta definita da: Count_Aux_B(x, 0) = 0 y(0 < y m ( B[y] = x Count_Aux_B(x, y) = Count_Aux_B(x, y - 1) + 1) ( B[y] = x Count_Aux_B(x, y) = Count_Aux_B(x, y - 1))) La definizione di Count_Aux_A(x, y) è analoga. Esercizio 3 1. Il primo problema è decidibile, in quanto è sufficiente enumerare tutti gli automi a stati finiti (costruibili sull’alfabeto di simboli di A), in ordine crescente rispetto al numero di stati, fino al primo automa (escluso) con un numero di stati pari al numero di stati in A. Questo tipo di enumerazione è certamente possibile ed è simile a quello utilizzato per enumerare le macchine di Turing. A questo punto, per ciascun automa in questa enumerazione è sufficiente verificarne l’equivalenza con A, proprietà decidibile grazie alle proprietà di chiusura della famiglia e della decidibilità della emptiness di un linguaggio regolare: se l’equivalenza sussiste, A non è minimo, altrimenti lo è. NB: In alternativa e in maniera più immediata il problema può essere dimostrato decidibile facendo ricorso alla procedura di minimizzazione per gli automi a stati finiti e quindi semplicemente confrontando il numero di stati dell'automa di partenza e dell'automa minimo corrispondente. 2. Con un procedimento del tutto simile al precedente (e mantenendo fissato l'alfabeto di pila dell'automa) risulta decidibile anche il secondo problema (tenendo conto, come stabilito nella tabella 8.1, che è decidibile anche l’equivalenza tra automi a pila deterministici e che limitando la lunghezza della stringa depositabile in pila esiste solo un numero finito di automi con un determinato numero di stati, a meno di una irrilevante ridenominazione degli stati). Si noti che se l'alfabeto di pila non fosse fissato sarebbe sempre possibile ridurre il numero di stati (fino a due) memorizzando l'informazione in essi contenuta in opportuni simboli depositati sulla pila. Si noti inoltre che ogni automa a pila può essere trasformato in uno equivalente che non depositi in pila più di k caratteri per ogni mossa, purché k sia > 1 e al prezzo di un aumento del numero di stati. 3. Il quesito del terzo problema è una domanda chiusa, che non dipende da alcun parametro, pertanto il problema è certamente decidibile. Algoritmi e Principi dell'Informatica Seconda Prova in Itinere 8 Febbraio 2013 Il tempo a disposizione è di 2 ore Esercizio 1 (punti 5/15-esimi) Esercizio 1.a Si delinei una macchina di Turing M a nastro singolo che riconosca il linguaggio L {a,b}* consistente di tutte e sole le stringe con un numero di occorrenze di 'a' uguale a quello di 'b'. La descrizione non deve necessariamente scendere in tutti i dettagli ma deve essere sufficientemente chiara e precisa da permettere di calcolare la complessità temporale asintotica della macchina: si spieghi con precisione quale sia tale complessità. E' possibile trovare un altro modello di calcolo a potenza risolutiva minore della macchina a nastro singolo (ossia non in grado di riconoscere tutti i linguaggi riconoscibili dalla MT) che riconosca L con complessità inferiore a quella di M? Si motivi brevemente la risposta. Esercizio 1.b Si risolva lo stesso esercizio del punto 1.a con riferimento al linguaggio L' {a, b, c}* le cui stringhe hanno ugual numero di 'a', 'b' e 'c'. Esercizio 2 (punti 8/15-esimi) Si consideri un array che sia il risultato della visita in post-ordine sinistro di un Binary Search Tree (BST) i cui nodi contengano numeri interi ordinati in ordine crescente (figlio di sinistra < del padre ≤ del figlio di destra; linearizzato in: figlio di sinistra, figlio di destra, padre). Assumendo l'ipotesi che il BST di partenza avesse entrambi i figli per ogni nodo interno, si delinei, mediante opportuno pseudocodice, un algoritmo che, partendo dall'array linearizzato ricostruisca il BST originario. Indi se ne valuti la complessità asintotica. NB: il punteggio attribuito alla soluzione terrà conto della complessità asintotica dell'algoritmo. Esercizio 3 (punti 3/15-esimi) Si vuole progettare una tabella di hashing in cui memorizzare numeri primi, usando gli stessi come chiave. La tabella è lunga 2n elementi, si sceglie di utilizzare la funzione h(x) = x mod 2n come funzione di hash. E' una buona scelta? Motivare brevemente la risposta. Esercizio 4 (punti 2/15-esimi) Si stabilisca l’ordine di grandezza (classe di -equivalenza) della soluzione della seguente equazione alle ricorrenze: T(n) = 7 T(n/5) + (n2) Tracce di soluzioni Esercizio 1 1.a Una M a nastro singolo non può far altro che scorrere l'intero nastro, o una sua porzione ad esso proporzionale, nel caso pessimo, per ogni carattere letto alla ricerca di un suo corrispondente; alternativamente aggiornando un contatore che dovrebbe trovarsi in una diversa porzione di nastro rispetto a quella dove è memorizzata la stringa di ingresso. Quindi la sua complessità temporale deve essere almeno (n2). Un automa a pila deterministico invece può facilmente riconoscere L in (n). 1.b La precedente macchina M può facilmente essere modificata in modo da riconoscere L' con la stessa complessità asintotica. L' però non è riconoscibile da alcun automa a pila; è tuttavia riconoscibile da una rete di Petri, sempre in tempo lineare, che però non ha la potenza computazionale delle MT. Esercizio 2 Un esempio di BST che soddisfi l'ipotesi dell'esercizio e della sua linearizzazione in post-ordine sinistro è fornito in figura. 13 11 8 5 3 15 12 14 18 8 6 (a) esempio di BST (b) array risultante dalla visita in post-odine sinistro del BST in figura (a): 3, 6, 5, 8, 8, 12, 11, 14, 18, 15, 13. Si noti che (per un certo valore) non possono esistere più di due nodi contenenti quel valore, altrimenti si dovrebbe violare l'ipotesi che ogni nodo interno ha entrambi i figli. Un modo semplice di riottenere il BST di partenza consiste nel percorrere l'array da destra a sinistra ed eseguire una serie di inserimenti in ordine dei vari elementi. In questo modo però la complessità risulta (O(n.log(n)) nel caso di BST bilanciato e O(n2) nel caso pessimo. Un algoritmo più efficiente invece può fare uso di una struttura ausiliaria a pila e procedere nel modo seguente, da sinistra a destra, sfruttando la proprietà che gli elementi dell'array sono in ordine crescente tranne quando si passa da figlio (necessariamente di destra) a padre: push a[0]; crea un nodo per a[0] for i := 1, …,n do while a[i-1] < a[i] push a[i]; crea un nodo per a[i] crea un nodo per a[i]; assegna al suo campo figlio di destra il puntatore al nodo creato per l'elemento in cima alla pila e al figlio di sinistra il puntatore al nodo creato per l'elemento sottostante; pop; pop; push a[i]; L'algoritmo visita ogni elemento una sola volta e quindi ha complessità O(n). Esercizio 3 La funzione di hash proposta non è una buona funzione: i numeri primi, fatto salvo 2, sono tutti dispari; quindi i posti di posizione pari verranno utilizzati solo in caso di conflitti e la tabella risulterà fortemente sbilanciata e/o sottooccupata. Esercizio 4 Applicando il teorema dell’esperto (Master theorem) abbiamo: a = 7, b = 5, f(n) = (n2) > (nlogb(a) + ) Quindi la soluzione è (n2). Algoritmi e Principi dell’Informatica Appello del 21 Febbraio 2013 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2, 3 in 1 ora e 30 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4, 5, 6 e in 1 ora e 30 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 5) Si considerino i seguenti linguaggi L1 = abaaabbbabd, … aabbabaaabbbd, …} = {abd, aabbabd, aabbaabbd, abaabbd, … L2 = = {abcad, … aaabbcaad, aaabbbcaaad, aabbbcaaabcad, …} 1. Definire una grammatica non contestuale che generi L1 e un automa a pila deterministico che lo accetti. 2. Definire una grammatica non contestuale che generi L2 e un automa a pila, preferibilmente deterministico, che lo accetti. 3. Definire una grammatica non contestuale che generi L1L2. Se possibile, definire un automa a pila deterministico che lo accetti; altrimenti argomentare in modo informale ma convincente che il linguaggio L1L2 non può essere accettato da un automa a pila deterministico, e definire un automa a pila nondeterministico che accetti L1L2. Esercizio 2 (punti 5) Si specifichi in logica del prim’ordine una funzione f : A* N A, dove A è un alfabeto di simboli e N è l’insieme dei numeri naturali, che, data una stringa costruita sull’alfabeto A e un numero i, restituisce il carattere in posizione (i+1)-esima nella stringa (cioè il carattere con indice i nella stringa, dove 0 è l’indice del primo carattere, 1 del secondo, e così via). Nella specifica, è consentito l’uso delle seguenti funzioni: st (concatenazione delle stringhe s e t) |s| (lunghezza di una stringa s) e del predicato = (uguaglianza). Ovviamente non è consentito l’uso della notazione s[i], che indica l’i-esimo carattere della stringa s. Esercizio 3 (punti 5) Si dica, giustificando brevemente la risposta, se la seguente funzione è calcolabile o no: f : N N N {0, 1} f (0, 0, 0) = 0; f (x, y, z) = se z è pari allora 0 se x è la radice quadrata intera esatta di y, altrimenti ; se z è dispari allora 1 se ( x dispari y pari e k, h N tali che kx = hy, x pari y dispari e k, h N tali che kx = hy ) altrimenti. Esercizio 4 (punti 6) Si risolva la seguente equazione alle ricorrenze (a meno della relazione O): T(n) = 2T(n-4) + O(log(n)) Esercizio 5 (punti 6) Scrivere un algoritmo che, dato un array A, determina se esiste un sottoarray (per sottoarray si intende una sequenza di elementi consecutivi dell’array base) di A che sia a sua volta scomponibile in 2 sottoarray tali che la somma degli elementi nel primo sia uguale alla somma degli elementi del secondo. L'algoritmo deve restituire il sottoarray più lungo tra quelli che soddisfano la condizione di cui sopra, se esiste. Indicare la complessità temporale asintotica dell’algoritmo scritto. Esercizio 6 (punti 5) Si definisca (senza necessariamente codificarne tutti i dettagli) un macchina di Turing a nastro singolo che riconosca il linguaggio delle stringhe del tipo x#y con x,y{a, b}* e (i) |x| |y| e (ii) |x| pari e |y| dispari o viceversa, minimizzando la complessità temporale della macchina; se ne valuti la complessità spaziale e temporale a meno della relazione . Tali complessità cambierebbero se si rimuovesse il vincolo (ii)? Cosa cambierebbe se si usasse una macchina a k nastri invece di una macchina a nastro singolo? Tracce di soluzione Esercizio 1 1. La grammatica seguente, con assioma S1, genera L1 S 1 A S1 | A d AaAb|ab L’automa deterministico seguente accetta L1. 2. La grammatica seguente, con assioma S2, genera L2 S2 a S2 | a X d XCX|C CbCa|bca L’automa deterministico seguente accetta L2. 3. La grammatica, con assioma S, genera L1L2 bZ0/BZ0 aZ0/Z0 aZ0/Z0 S S1 | S2 dZ0/Z0 cB/B bZ0/BZ0 i2 bB/BB aB/ … più le regole per i linguaggi L1ed L2 … L’automa a pila che accetta L1L2 non può essere deterministico: mentre legge il primo gruppo di simboli a, l’automa deve memorizzare nella pila un conteggio unario del numero di a e poi, mentre legge il primo gruppo di b, deve usare la pila per verificare (nel caso che la stringa L1) che il numero delle bsia uguale al numero delle a. Ma facendo ciò il contenuto della pila va perso, quindi la pila non può essere usata per verificare (nel caso la stringa L2) che il numero delle ache seguono la successivaceguagli il numero delle bche la precedono. Un automa nondeterministico che accetti L1L2 può essere ottenuto come semplice composizione dei due automi che accettano L1ed L2. Esercizio 2 x y i ( f(x, i) = y w z (x = w y z |y| = 1 |w| = i) ) Esercizio 3 f è calcolabile perché : è decidibile se z sia pari o dispari nel primo caso è decidibile stabilire se x sia la radice quadrata intera esatta di yo no e produrre 1 o, rispettivamente, nei due casi; nel secondo caso la domanda è chiusa (non importa stabilire se la condizione indicata sia vera o falsa: la funzione di fatto non dipende da x e y in quanto quantificate) e quindi una delle due macchine che per z dispari producono in output 1 oppure non terminano è la macchina che computa questa parte della funzione. Esercizio 4 Mediante il metodo dell’albero di ricorsione si ottiene il guess O(2n/4∙log(n)): il costo di ogni livello è O(2k log(n – 4k)); quindi la profondità dell’albero è k = n/4. Poi si verifica che, con opportune costanti, T(n) ≤ c∙2n/4∙log(n). In effetti, per arrivare a concludere che T(n) ≤ c∙2n/4∙log(n), è utile mostrare un vincolo leggermente più stretto, e cioè che T(n) ≤ c∙2n/4∙log(n) - bn2. Infatti si ha: T(n) = 2∙T(n-4) + d∙log(n) ≤ 2c2((n-4)/4)log(n-4) -2b(n-4)2 + d∙log(n) = = c2n/4log(n-4) - bn2 - bn2 + 16bn -32 + d∙log(n) ≤ ≤ (c2n/4log(n) - bn2) - bn2 + 16bn -32 + d∙log(n) ≤ ≤ c2n/4log(n) - bn2 per b ed n sufficientemente grandi. Esercizio 5 Un modo naturale per risolvere il problema consiste nell’elencare tutti gli n2 sottoarray di A (lungo n), e controllare se questi hanno la proprietàdesiderata;tale verifica si può fare in tempo O(n) per ogni sottoarray. Di conseguenza, la complessità temporale complessiva è (n3). Più precisamente, uno schema algoritmico per risolvere il problema è il seguente: Si calcola la somma di tutti gli elementi dell’array, S; costo O(n); Si inizializzano tre indici, i, j, k che delimitano rispettivamente inizio e fine del sottoarray corrente e la separazione tra i due sottoarray del medesimo: ad esempio, i, k, = 0, j = n-1; di conseguenza, inzialmente il primo sottoarray A1 ha somma A[0] e il secondo, A2 S – A[0]; Per ogni coppia i, j si fa variare k da i a j e per ogni incremento si aggiunge A[k] a A1 e lo si sottrae ad A2; se i due valori coincidono si è risolto il problema. Per ogni valore di k questa operazione costa O(1). Quindi complessivamente l’algoritmo ha complessità temporale O(n3). Esercizio 6 Una MT di Turing a nastro singolo che riconosce il linguaggio descritto opera con complessità temporale e spaziale (n). Il linguaggio descritto è, infatti, un linguaggio regolare e il controllo sulla condizione (ii) (che implica la condizione (i)) può essere fatto usando solo gli stati come nella macchina seguente. #|# <R> a|a <R> b|b <R> a|a <R> b|b <R> a|a <R> b|b <R> a|a <R> b|b <R> -|- <S> #|# <R> a|a <R> b|b <R> #|# <R> a|a <R> b|b <R> a|a <R> b|b <R> -|- <S> a|a <R> b|b <R> -|- <S> La complessità spaziale è data dal fatto che l’unico nastro contiene la stringa di ingresso. Se si rimuovesse il vincolo (ii) il linguaggio non sarebbe più regolare e una macchina che minimizza la complessità temporale potrebbe operare nel seguente modo: a|a <R> b|b <R> #|# <R> a|X <R> b|X <R> X|X <L> -|- <L> #|# <S> a|X <R> b|X <R> a|X <R> b|X <R> X|X <R> #|# <R> a|a <L> b|b <L> #|# <L> a|a <S> b|b <S> #|# <R> La complessità temporale diventerebbe quindi (n2), mentre quella spaziale rimarrebbe pari a (n). Se invece che una macchina a nastro singolo si usasse una macchina a k nastri le complessità cambierebbero nel seguente modo. Nel primo caso la macchina a k nastri opererebbe esattamente come la macchina a nastro singolo, mantenendo quindi una complessità temporale (n), mentre la complessità spaziale diventerebbe (1), poiché i nastri di memoria e ingresso sono distinti e quindi la memoria in questo caso, non viene usata. Rimossa la condizione (ii), una macchina con un nastro di memoria può riconoscere il linguaggio scorrendo la prima parte della stringa e copiandola nel nastro di memoria. Una volta raggiunto il simbolo # legge la seconda parte della stringa, avvolgendo indietro il nastro in cui è stata copiato la prima parte della stringa. Se il nastro raggiunge Z0 prima che la stringa sia finita o la stringa finisce prima di arrivare a Z0 sul nastro, la parola viene accettata. La complessità temporale diventa quindi (n), così come quella spaziale. Algoritmi e Principi dell’Informatica Appello del 25 Giugno 2013 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2, in 1 ora e 30 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3, 4, 5 in 1 ora e 30 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 7) Nel gioco Reversi ci sono due giocatori (“bianco” e “nero”), ciascuno dotato di 32 dischi bicolori (neri da un lato, bianchi dall'altro) da piazzare su una scacchiera di 8x8 caselle inizialmente vuota. Si muove alternativamente (inizia il nero) piazzando ogni volta un nuovo disco (girato dalla parte del proprio colore) in una casella vuota. Se tra il disco appena piazzato e quelli del proprio colore già presenti sulla scacchiera sono presenti orizzontalmente, verticalmente o diagonalmente solo dischi avversari senza caselle vuote nel mezzo, tali dischi vengono rovesciati e diventano del colore di chi ha eseguito la mossa. La figura sottostante mostra un esempio di mossa del nero che produce il rovesciamento di un disco bianco. Per semplicità rispetto alla versione ufficiale del gioco, si assuma che sia sempre possibile muovere, ossia piazzare nuovi dischi, fino a che la scacchiera non sia piena. A fine partita, vince il giocatore con il maggior numero di dischi del proprio colore. Scopo dell’esercizio è specificare alcune (non tutte!) regole del gioco mediante formule del prim’ordine. Si considerino i predicati seguenti, che fanno riferimento al tempo (discreto) in cui avviene una mossa (ossia al numero d’ordine della mossa all’interno della partita, partendo da 1): scacchiera(X,Y,C,T) // c’è un disco di colore C al tempo T in posizione (X,Y) mossa(X,Y,C,T) // il giocatore di colore C piazza un disco del suo colore al tempo T in posizione (X,Y) 1. Si specifichino le condizioni seguenti: a. inizialmente (al tempo 0) la scacchiera è vuota e la prima mossa viene eseguita dal nero al tempo 1. b. in ogni casella c’è sempre al massimo un solo disco. 2. Si specifichi ora la seguente regola, supponendo che sia già stato definito un predicato daRibaltare(X,Y,T) che indica che un disco in posizione (X,Y) in conseguenza di una mossa effettuata al tempo T deve essere ribaltato nello stesso istante T: All’istante T viene eseguita una mossa (se nell’istante precedente esistevano caselle vuote); se la mossa produce l’effetto che qualche casella sia ribaltabile, contestualmente, ossia nello stesso istante T, avvengono tutti i ribaltamenti possibili. NB: non è necessario formalizzare quale sia il giocatore che effettua la mossa. 3. [Opzionale: questa parte, se risolta in maniera corretta comporta 3 punti aggiuntivi; tuttavia essa verrà valuatata solo se le parti precedenti dell’esercizio saranno state risolte correttamente]. Specificare il predicato daRibaltare(X,Y,T) (Suggerimento: si prenda in considerazione questa proprietà a partire dall’istante 1) . In tal caso si consideri inoltre già specificata la seguente definizione di avversario mediante la funzione avv (avversario): avv(bianco) = nero; avv(nero) = bianco NB: Si ribadisce che non è richiesta la specifica di ulteriori regole del gioco (e.g.: una sola mossa per volta, alternanza tra giocatori, …). Esercizio 2 (punti 8) Si risponda ai seguenti quesiti, giustificando brevemente ma con chiarezza la risposta: 1. Si consideri l’insieme S = { y | x ( fy(x)⊥fy(x)=x2) }. S è ricorsivo? S è ricorsivamente enumerabile? 2. Si consideri la funzione seguente: g(x, y) = 1, se z ( fx(z)⊥fy(z)⊥fx(z)= fy(z)), 0 altrimenti g è computabile? 3. Si consideri ora la funzione g’, variazione della precedente g: g’(x, y, z) = 1, se fx(z)⊥fy(z)⊥fx(z)= fy(z), ⊥ altrimenti g’ è computabile? Esercizio 3 (punti 7) Si consideri il linguaggio n m n m n m L = {b 1a 1b 2 a 2… b h a h| (1) k>0, (2) ni ni+1 i=1, …, k-1, (3) 1 ni 10, i=1,…, h (4) mi+1 mi i=1, …, k-1, (5) 1 mi 5, i=1,…, h}. 1) Quale è la complessità di una MT a k nastri che riconosce L? 2) Che cosa cambierebbe con una MT a nastro singolo? 3) È possibile ottenere la stessa complessità con una RAM usando il criterio di costo logaritmico? 4) Le risposte ai punti precedenti cambierebbero se venisse rimosso il vincolo (5)? Se sì, come? Per tutti i punti, si descriva anche solo schematicamente il comportamento della MT o della RAM usata per risolvere il problema, in modo da motivare la complessità fornita. Esercizio 4 (punti 5) a. Dato un albero binario di interi, memorizzato mediante una struttura dati che prevede che ogni nodo punti ai propri figli ma non al padre e che può contenere elementi ripetuti, si vogliono cancellare tutte le foglie che contengono un valore uguale a quello del padre. Si fornisca una breve traccia di un algoritmo per questo scopo e se ne valuti la complessità asintotica; essa è ottima? NB: non è richiesto il codice e neanche lo pseudocodice dell’algoritmo: è sufficiente una sintetica ma precisa descrizione che permetta di valutarne la complessità in modo evidente. b. Si voglia estendere l’algoritmo in modo tale da ottenere un albero in cui non ci siano foglie che contengono il valore del padre. Fornire una traccia e la relativa complessità del nuovo algoritmo. Esercizio 5 (punti 5) Si consideri il seguente problema (versione semplificata di un classico problema per la classificazione di dati): Dato un insieme N di punti in uno spazio m-dimensionale partizionarli in un numero k – assegnato e minore di N – di cluster (sottoinsiemi disgiunti) così che ogni punto appartenga ad un solo cluster, ed ogni cluster contenga almeno un punto. Ogni cluster ha un centroide definito come la media, nello spazio euclideo m-dimensionale, dei punti che appartengono al cluster stesso (ad esempio, se il cluster è costituito da due punti, il suo centroide è il punto di mezzo tra essi). Un semplice metodo greedy (che non garantisce di trovare la migliore separazione possibile fra i cluster, che nella presente versione semplificata non è defintia) consiste nello scegliere casualmente k punti come centroidi iniziali dei k clusters. Quindi ogni altro punto dell’insieme viene assegnato al cluster il cui centroide è il più vicino ad esso e subito dopo viene ricalcolato il centroide di quel cluster per tenere conto del nuovo valore; si procede in tal modo fino ad esaurimento dei punti. Si dettagli la precedente traccia di algoritmo mediante opportuno pseudocodice fino a un livello di dattaglio tale da poterne definire con precisione la complessità asintotica (temporale e spaziale). Informazione di completamento culturale, irrilevante allo scopo di risolvere l’esercizio: l’algoritmo completo procede per iterazioni successive fino a quando il calcolo dei centroidi e la clusterizzazione non raggiungono un opportuno criterio di ottimalità. Tracce delle soluzioni Esercizio 1 1. a. X Y C scacchiera(X,Y,C,0)mossa(X,Y, C, 0) Z,W mossa(Z,W, nero, 1) b. X Y T (scacchiera(X,Y,bianco,T) scacchiera(X,Y,nero,T)) 2. T (T > 0 X,Y(C scacchiera(X,Y,C,T-1)) Z,W,H mossa(Z,W,H,T) (K scacchiera(Z,W,K,T-1) ) scacchiera(Z,W,H,T) (Z W daRibaltare (Z,W,T) scacchiera(Z,W,H,T) ) ) //se c’è almeno una casella libera a T-1, a T si fa una mossa che consiste nel mettere un disco in una della caselle libere (a T-1); di conseguenza tutte le caselle divenute ribaltabili sono ribaltate. Esercizio opzionale X YT daRibaltare (X,Y,T) (T >0 (Z,W,P mossa(Z,W,P,T)N (N>0)M (M>0) // 1° caso: orizzontale: X e Y si trovano sulla stessa linea orizzontale del punto di una mossa e internamente a un “segmento” che parte dal punto della mossa e termina nel primo punto di uguale colore della mossa(alla sua destra); inoltre tutti i punti interni del segmento, inclusi X e Y, sono di colore opposto. scacchiera(Z+M,W,P,T-1) Z<X X<Z+M W = Y (I(Z < I I< Z+M)scacchiera(I,Y,avv(P),T-1)) //analogamente il caso in cui il segmento parta dal punto di uguale colore della mossa (alla sua sinistra) e termini nel punto della mossa …. // analogamente per i casi verticali e diagonali …. )) Formulazione alternativa X YT ribaltabile(X,Y,T) T>0 N N>0 M M>0 P ( // 1° caso: orizzontale (mossa(X-N,Y,P,T) scacchiera(X+M,Y,P,T-1) mossa(X+M,Y,P,T) scacchiera(X-N,Y,P,T-1) ) I (X-N<II<X+M scacchiera(I,Y,avv(P),T-1)) ) // analogamente per i casi verticali e diagonali … ) Esercizio 2 1. S non è ricorsivo: ciò è una diretta conseguenza del toerema di Rice. D’altro canto il complemento di S, S’: S’ = { y | x ( fy(x)⊥fy(x)x2) } è ricorsivamente enumerabile: i suoi elementi possono essere enumerati mediante una classica tecnica “diagonale” (su 3 dimensioni) che consideri nell’ordine tutte le funzioni computabili, per tutti i valori dei dati di ingresso e per numero crescente di passi di computazione individuando quindi i valori di y per i quali la condizione fy(x)x2sussiste. Di conseguenza S non è ricorsiviamente enumerabile altrimenti S e S’ sarebbero entrambi ricorsivi. 2. Sia K il numero di Godel di una MT che calcola la funzione f(x)=x2: risulta allora g(x, K)=p(x), dove p è la funzione caratteristica dell’insieme S di cui al punto 1; quindi g(x, K) non è computabile, ed a maggior ragione non lo è g(x,y). 3. g’ è computabile: una MT può calcolareg’simulandoil calcolo difx(z) efy(z) e, se entrambe le computazioni terminano, verifica sefx(z)= fy(z), altrimenti continua con la sua simulazione indefintamente. Esercizio 3 Il linguaggio L è regolare, grazie ai vincoli (3) e (5); quindi, potendo ognuna delle macchine prese in considerazione simulare il funzionamento di un automa a stati finiti con il proprio organo di controllo, ognuna di esse può riconoscere L con complessità temporale O(n) e spaziale O(1), con l’eccezione della macchina di Turing a nastro singolo che deve usare n celle per la stringa di ingresso. Se si rimuove il vincolo (5) L non è più regolare (e neanche context-free). Una MT a 2 nastri può memorizzare i vari mi su un nastro e mi+1 sull’altro in alternanza, contestualmente verificando che sia soddisfatta la diseguaglianza; ciò richiede evidentemente complessità spaziale e temporale O(n). Una macchina RAM può procedere in maniera analoga usando 2 contatori, ottenendo una complessità temporale O(n log n) col criterio di costo logaritmico. Una macchina a nastro singolo invece deve scandire ogni gruppo di mi ‘a’ mi volte, ciò che comporta una complessità temporale O(n2). Esercizio 4 a. E’ sufficiente una visita in preordine dell’albero. Quando si raggiunge una foglia si verifica se il padre ha lo stesso valore e in tal caso la si elimina. Quindi la complessità è lineare nel numero dei nodi. b. La soluzione più naturale consiste nell’ iterare l’algoritmo precedente. Ogni iterazione ha quindi complessità lineare nel numero dei nodi; il numero di iterazioni al massimo è dato dalla profondità dell’albero. Quindi nel caso pessimo la complessità è O(n2). Tuttavia, un algoritmo più sofisticato può tenere traccia, ovviamente in maniera ricorsiva, durante la visita dell’albero, del fatto che un nodo sia diventato foglia a seguito della cancellazione dei suoi figli: in tal caso esso viene cancellato e, al momento di ritornare il controllo al proprio padre gli notifica il fatto di essere stato cancellato; se un nodo riceve questa ionformazione da ambo i figli sa di essere a sua volta diventato foglia e il meccanismo può essere iterato durante la seuqnze di ritorno alle varie chiamate ricorsive, ottenendo quindi una complessità O(n). Esercizio 5 Complessità temporale: considerando costante il tempo per calcolare la distanza del punto dai k centroidi (in realtà dipenda da m ma non da k né da N), ognuna delle N iterazioni richiede k confronti ed il calcolo del nuovo centroide, quindi O(N) nel caso pessimo dal momento che tutti i punti potrebbero essere assegnati ad un unico cluster. La complessità temporale totale è perciò O(N2).m. Si noti tuttavia che il ricalcolo della media dei punti (centroide) a causa dell’inserimento del nuovo punto potrebbe essere fatto anche in O(1) moltiplicando la media precedente per il numero s di punti precedente; aggiungendo le coordinate del nuovo punto e ridividendo per s+1. In tal modo la complessità diventerebbe O(N.k.m) Complessità spaziale occorre tenere in memoria i punti ed i centroidi, quindi O((N + k)m) Algoritmi e Principi dell’Informatica Appello dell’11 Settembre 2013 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2 e 3, in 1 ora e 30 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4, 5, 6 in 1 ora e 30 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 4) Sia data la seguente grammatica G: S→BSa|C BC → C b b C→c 1. 2. Si dica quale è il linguaggio generato da G. Si scriva un automa che riconosce il linguaggio generato da G. L’automa deve appartenere alla classe di potenza riconoscitiva minima tra quelle che riconoscono il linguaggio generato da G. Esercizio 2 (punti 5) Si consideri il seguente programma (in pseudocodice), il cui scopo è ordinare un generico array A di lunghezza variabile il cui valore è memorizzato nel campo length (si supponga che il campo key dei vari elementi sia un intero in valore assoluto 100): INSERTION-SORT(A) 1 for j := 2 to A.length 2 key := A[j] 3 //Inserisce A[j] nella sequenza ordinata A[1..j−1] 4 i := j − 1 5 while i > 0 and A[i] > key 6 A[i + 1] := A[i] 7 i := i − 1 8 A[i + 1] := key 1. E’ decidibile il problema di stabilire se il programma suddetto ordina correttamente un generico array di lunghezza 100? 2. E’ decidibile il problema di stabilire se il programma suddetto ordina correttamente un generico array di lunghezza qualsiasi? Esercizio 3 Prima parte (obbligatoria:punti 6) Si consideri un sistema costituito da un processo che gestisce una risorsa R utilizzata da due processi utenti U1 e U2. Ognuno dei due utenti richiede di tanto in tanto l’accesso alla risorsa R, in mutua esclusione. Né U1 né U2 possono chiedere nuovamente l’uso di R se la loro precedente richiesta non è stata prima soddisfatta. Il processo gestore assegna R ai richiedenti, in mutua esclusione e in alternanza. Al termine dell’uso di R il processo utente rilascia la risorsa. Si formalizzi questo comportamento del sistema mediante una rete di Petri. Seconda parte (facoltativa: ulteriori punti 4. NB: la parte facoltativa verrà valutata solo se sarà stata svolta correttamente la parte obbligatoria.) La versione precedente ha il difetto di imporre una rigida alternanza tra il servizio di U1 e quello di U2, con l’effetto di bloccare entrambi i processi se uno dei due, pur potendo effettuare una richiesta, non la esegue quando è il proprio turno. Ad esempio non sarebbe possibile la seguente sequenza, assumendo che inizialmente né U1 né U2 abbiano richiesto la risorsa: U1 richiede la risorsa e la ottiene; successivamente la risorsa viene rilasciata e U1 la chiede nuovamente; U2 però nel frattempo non l’ha ancora richiesta e quindi la risorsa viene nuovamente assegnata a U1 (mentre se U2 nel frattempo l’avesse richiesta, essa dovrebbe essere obbligatoriamente assegnata ad U2). Si modifichi la precedente rete di Petri in modo da permettere che la risorsa venga assegnata anche più volte di seguito allo stesso processo ma solo se l’altro non l’ha richiesta. Esercizio 4 (punti 5) Si consideri il problema di cercare un elemento x compreso tra 0 e 9 in una sequenza ordinata S di lunghezza n che contiene solo i numeri fra 0 e 9 (ciascun elemento può apparire più volte in S). Si descriva a grandi linee il comportamento di una macchina di Turing a k nastri che, ricevendo in ingresso la stringa x$S, sia in grado, facendo uso di un algoritmo di ricerca binaria, di stabilire se x appartiene a S e se ne calcolino la complessità temporale e spaziale. Sono preferibili soluzioni che minimizzano la complessità temporale. Esercizio 5 (punti 6) Si descriva un algoritmo, mediante opportuno pseudocodice, che calcoli il determinante del prodotto tra due matrici A e B nn, sotto l’ipotesi che A e B siano entrambe triangolari superiori (ossia abbiano tutti 0 al di sotto della diagonale principale) o, simmetricamente, triangolari inferiori. Si valuti la complessità asintotica dell’algoritmo in funzione della dimensione n delle matrici. Suggerimento (per chi avesse qualche difficoltà a richiamare alla memoria gli elementi basilari di algebra lineare) Ricavare proprietà e algoritmi generali estrapolandoli da esempi relativi a matrici “piccole”: e.g., 22, 33, … Esercizio 6 (punti 5) Si risponda alle seguenti domande, motivando opportunamente le risposte. 1. Si considerino alberi red-black che ammettono l’esistenza di chiavi duplicate: a. è possibile che ci siano due elementi con la stessa chiave che non sono uno il padre dell'altro? b. è possibile che ci siano due elementi con la stessa chiave che non sono uno antenanto dell'altro? 2. Modificare gli algoritmi di RB-INSERT-RB e RB-DELETE visti a lezione in modo da impedire che ci possano essere in un albero chiavi duplicate. Dire come cambia (se cambia) la complessità degli algoritmi modificati rispetto alle versioni originali. Tracce di soluzioni Esercizio 1 Il linguaggio generato dalla grammatica è L(G) = {c b2n an | n >= 0}, che è riconosciuto da un semplice automa a pila deterministico. Esercizio 2 La risposta è positiva in entrambi i casi. Infatti il problema può essere deciso, dimostrando in effetti la correttezza dell’algoritmo codificato dal programma: in letteratura si trovano diverse dimostrazioni matematiche della sua correttezza, ma anche una semplice analisi informale del codice può portare alla decisione che esso effettivamente ordina correttamente un qualsiasi array. Ovviamente, una volta deciso il problema nel caso generale ne consegue la stessa decisione nel caso particolare. Tuttavia nel primo caso è possibile constatare immediatemente la decidibilità del problema posto, anche senza deciderlo: basta infatti constatare che in tal caso il dominio del problema è finito (l’insieme degli array di lunghezza 100 e i cui elementi siano a loro volta interi compresi tra -100 e + 100): di conseguenza il problema può essere risolto alla peggio mediante testing esaustivo – posto che a sua volta il problema di stabilire se un array è ordinato è decidibile-. Esercizio 3 Prima parte (obbligatoria) U2 richiede R U1 richiede R R A1 A2 A1 e A2 impongono l’alternanza tra il servizio di U1 e quello di U2 Seconda parte (opzionale) Aggiungendo alla rete precedente le parti in rosso della rete seguente si ottiene l’effetto che, ad esempio, Gr1a (ossia grant di R a U1 avvenga solo se “è il turno di U1”; ma se fosse il turno di U2 e U2 non avesse richiesto la risorsa – e solo in tal caso!-, essa sarebbe ugualmente assegnata ad U1 tramite la transizione Gr1b. In sostanza il comportamento della rete viene reso deterministico in ambo i casi, ma nel primo caso imponendo un’alternanza obbigatoria, nel secondo determinando la scelta tra la concessione di tipo a e quella di tipo b a seconda che sia il proprio turno oppure no ma in assenza di richiesta da parte dell’altro processo. U2 richiede R U1 richiede R R Gr1a Gr2a A1 A2 Gr1b Gr2b Esercizo 4 Una soluzione banale consiste nel codificare l’algoritmo tradizionale di ricerca binaria che effettua log(n) accessi alla sequenza S. Tale algoritmo può essere codificato dalla MT con complessità temporale O(nlogn); infatti poiché nelle macchine di Turing l’accesso è sequenziale ciascun accesso richiede fino a n passi. È però possibile ottenere una complessità lineare nel seguente modo, con una macchina di Turing con 3 nastri. 1) Copiare x sul nastro 1 e spostare la testina all’inizio di S. 2) Salvare la lunghezza di S sul nastro 2 (alla fine del procedimento la testina sul nastro di ingresso sarà alla fine di S così come la testina sul nastro 2). 3) Scandire il nastro 2 da sinistra verso destra. Ogni due passi sul nastro 2, muovere di una posizione a sinistra la testina sul nastro di ingresso e scrivere un simbolo sul nastro 3. (alla fine la testina sul nastro in ingresso sarà sul simbolo centrale di S, la testina sul nastro 2 sarà all’inizio del nastro e quella sul nastro 3 sarà alla fine del nastro). 4) Confrontare il simbolo centrale con x (salvato nel nastro 1): a. Se coincidono, l’esecuzione termina. b. Se x è maggiore del simbolo centrale, ripetere i passi 3 e 4 usando il nastro 3 al posto del 2 e il 2 al posto del 3 e muovendosi a destra invece che a sinistra sul nastro di ingresso a partire dalla posizione corrente (si considera come S la seconda metà della sequenza corrente). c. Se x è minore del simbolo centrale, ripetere i passi 3 e 4 usando il nastro 3 al posto del 2 e il 2 al posto del 3 (si considera come S la prima metà della sequenza corrente). Con questo procedimento la complessità diventa lineare in quanto la macchina effettua al più log(n) operazioni che costano rispettivamente n, n/2, n/4, … , cioè . In entrambe le soluzioni la complessità spaziale è lineare. Esercizo 5 Si rammenti che il prodotto tra una matrice nm e una matrice mp è una matrice np il cui generico elemento in osizione i, j è datto dalla . Si constata allora facilmente che il prodotto tra due matrici triangolari (ad esempio, superiori) è a sua volta una matrice triangolare superiore i cui elementi sulla diagonale principale sono il prodotto a[i, i]. b[i,i]. Notoriamente il determinante di una matrice triangolare è il prodotto degli elementi sulla diagonale principale; esso è quindi dato dalla formula che evidentemente può essere calcolata in O(n) a criterio di costo costante. NB: allo stesso risultato si giunge anche ricordando che il determinante del prodotto tra due matrici è il prodotto dei due detereminanti. Esercizo 6 1.a E’ possibile, per esempio inserendo le seguenti chiavi: 3, 2, 5, 3 1.b E’ possibile, per esempio inserendo 3 volte la stessa chiave (2 sono foglie) 2. E’ da modificare solo l’algoritmo di RB-NSERT; la modifica può essere fatta in diverse maniere, per esempio ricercando, prima di inserire l’elemento, se c’è già nell’albero la chiave da inserire. La complessità dell’algoritmo modificato non cambia in termini di comportamento asintotico. Si può modificare l’algoritmo in modo anche da controllare se esiste già la chiave da inserire mentre si effettua l’inserimento. Algoritmi e Principi dell’Informatica Appello del 20 Settembre 2013 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 30 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3, 4, e 5 in 1 ora e 30 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 8) Il programma P riceve in ingresso due stringhe x e y costruite sull’alfabeto italiano tali che l’insieme dei caratteri di x coincida con l’insieme dei caratteri di y. Il programma P verifica se una delle due stringhe in ingresso sia una sottostringa dell’altra. In caso positivo, il programma pone a 1 il valore della variabile ESITO, altrimenti a 0. Ecco alcuni esempi. Se x è basso e y è asso, le stringhe x e y non soddisfano le precondizioni. Se x è sasso e y è asso, le precondizioni sono soddisfatte e P pone ESITO=1. Infine, se x è sasso e y è ossa, le precondizioni sono soddisfatte e P pone ESITO=0. Formulare in logica del prim’ordine le precondizioni e postcondizioni di P servendosi esclusivamente dei seguenti predicati e funzioni: il predicato unario char che è vero se e solo se il suo argomento è una stringa costituita da un unico carattere dell’alfabeto italiano; il predicato (binario) = che rappresenta la classica uguaglianza; la funzione binaria che rappresenta la concatenazione di stringhe. Esercizio 2 (punti 8 escludendo la domanda 4.b, 10 includendo anche essa) Si consideri il gioco del "forza 4", in cui ci sono 2 giocatori, uno con pedine rosse ed uno con pedine gialle, in cui vince chi per primo mette in fila (orizzontalmente, verticalmente, o diagonalmente) 4 pedine del proprio colore in uno schema di dimensione 7 colonne per 6 righe. Una mossa del gioco consiste nello scegliere una colonna, e nel fare scendere una pedina lungo la colonna: se la colonna al momento della mossa contiene k pedine, in seguito alla mossa la nuova pedina occuperà la posizione k+1 (assumendo che la prima posizione sia la #1); non si possono depositare pedine in una colonna piena e inzialmentetutte le colonne sono vuote. 1. E' decidibile il problema di stabilire se, data una configurazione del gioco (cioè una distribuzione di pedine nello schema), esiste una sequenza di mosse che portano un giocatore a vincere? 2. E' decidibile il problema del punto 1 se lo schema di gioco, invece che essere 67, è di dimensione arbitraria hk? 3. E' decididibile il problema del punto 1 se lo schema di gioco, invece che essere 67, non ha limiti né nelle righe né nelle colonne? 4. Si consideri di avere a disposizione una funzione che, date 2 configurazioni del gioco ed un colore, dice quale delle 2 è la "migliore" per quel colore (una configurazione potrebbe essere "migliore" perché, per esempio, rende più probabile al giocatore del colore dato di vincere la partita): 4.a E' decidibile il problema di stabilire se, dato un generico programma che prende in ingresso una configurazione del forza 4 (schema 67), ed un colore che deve muovere, questo ritorna sempre la mossa migliore per quel colore? 4.b E' semidecidibile il problema del punto 4.a? Esercizio 3 (punti 8) Si consideri la seguente –inutile!- funzione, definita mediante pseudocodice. void useless (int n) {for (i = 1, i <= n, i++) do aux(i)} dove a sua volta la funzione aux(m) è definita nel modo seguente: void aux(int m) {if(m == 1) return else if(odd (m))aux(m-1) else aux (m/2) } Si valuti la complessità asintotica di useless mediante la notazione O,o, preferibilmente, mediante la notazione . Esercizio 4 (punti 6) 1. Si definisca una struttura dati per rappresentare la rete stadale di una città. La rete stradale è fatta di incroci, collegati da strade, che possono essere a senso unico o a doppio senso; una strada si dice tratto di strada elementare se collega due incroci senza che tra essi ve ne siano altri; è anche possibile che ci siano dei cavalcavia, ossia strade che intersecano i propri tragitti senza per questo dare origine a un incrocio. 2. Si progetti un algoritmo per la struttura dati definita al punto 1 che determini, dato un incrocio della città, un percorso che ritorni al punto di partenza senza passare 2 volte da uno stesso incrocio (ovviamente escluso il primo) o da una stessa strada. Il percorso trovato dovrebbe essere quello di lunghezza minore tra quelli che soddisfano i vincoli, intendendo come lunghezza il numero di tratti di strada elementari che lo compongono. 3. Si valuti la complessità (asintotica) dell'algoritmo progettato. Esercizio 5 (punti 3) Si consideri il problema di stabilire se un numero naturale, codificato in binaro, sia pari o dispari. Si dica, giustificando brevemente la risposta, con quale complessità spaziale e temporale possono risolvere questo problema (ovviamente, lavorando al meglio delle proprie possibilità) le seguenti macchine astratte: 1. Una macchina di Turing a k nastri 2. Una macchina di Turing a nastro singolo 3. Una RAM, con criterio di costo logaritmico. Tracce delle Soluzioni Esercizio 1 Definisco per convenienza il predicato substring: ab (substring(a, b) cd cad = b) Precondizioni c (char( c ) (substring(c, x) substring(c, y) ) ) Postcondizioni ESITO=1 ( substring(x,y) substring(y,x) ) ESITO=0 ESITO=1 Esercizio 2 1. Decidibile: lo schema è finito. 2. Decidibile (è comunque un problema di ricerca in uno spazio limitato). 3. Decidibile, anzi deciso: essendoci un numero illimitato di posizioni, se un giocatore gioca in modo “stupido” è sempre possibile che l’altro vinca. 4.a Indecidibile:anche se la funzioneha un dominio finito, i possibili programmi sono infiniti: sussistono quindi le ipotesi del teorema di Rice. 4.b Semidecidibile: se un programma calcola la funzione in modo corretto, ciò può essere stabilito eseguendo il programma poiché la funzione ha un dominio finito. Esercizio 3 La funzione aux ha una complessità che è soluzione della seguente equazione alle ricorrenze: T(1) = 1; T(n) = if odd(n) then 1 + T(n-1) else 1 + T(n/2) Consideriamo due casi estremi: a) n = 2k: in tal caso, abbiamo T(n) = 1+ T(n/2) = 1 + 1 + T(n/4) = 1+1+1 … 1+ T(1) = 1*k , quindi T(n) è O(log(n)) b) n è dispari, (n-1)/2 è pure dispari e così via finché la ricorsione si chiude: in tal caso: T(n) = 1+ T(n-1) = 1 + 1 + T((n-1)/2) = 1+1+1+ T((n-3)/2) = 1 +1 +1+1+ T((n-3)/4) … che è O(2.log(n)) = O(log(n)). Quindi aux ha una complessità O(log(n)) (e anche (log(n))). useless chiama n volte aux con parametro i che “va da 1 a n”; quindi T(n) per useless è T(n) è anche che è O(n.log(n)). , che è (n.log(n)) Quindi T(n) è (n.log(n)). Esercizio 4 1. La struttura è un tipico esempio di grafo orientato. Si noti anche che la presenza dei cavalcavia non obbliga il grafo ad essere planare. Quindi esso può essere rappresentato in uno dei classici modi della letteratura (matrice delle adiacenze, lista dei nodi adiacenti, …). 2. Il problema è un classico problema di raggiungibilità: si può quindi usare uno dei tanti algoritmi dedicati a questo problema con opportuni, semplici adattamenti; ad esempio l’algoritmo BFS standard –descritto nel testo-potrebbe essere adattato al problema semplicemente verificando se il nodo v coincide con s: non appena questo test dà esito positivo, si è anche trovato il (un) percorso a distanza minima, grazie all’impostazione greadth-first dell’algoritmo di visita. Si noti che è impossibile passare due volte per la stessa strada, in un senso qualsiasi, senza anche passare due volte da uno stesso incrocio. La complessità totale è quindi O(|V| + |E|) (però se si usa la matrice della adiacenze per rappresentare il grafo il ciclo for della linea di codice 10 nell’algoritmo fornito dal testo richiede un tempo O(|V|) e quindi la complessità diventa O(|V|2) indipendentemente da |E|. Esercizio 5 Tutte le macchine non devono fare altro che verificare se l’ultimo bit sia 1 o 0: 1. La MT a k nastri deve solo spostare la testina fino all’ultimo bit: Complessità spaziale O(1) e temporale O(k) dove k è la lunghezza della stringa binaria che codifica il dato di ingresso n; ossia O(log(n)). 2. La MT a nastro singolo fa esattamente le stesse operazioni ma la sua complessità spaziale include sempre l’input (si tratta però di una convenzione) 3. La RAM può: a. leggere il dato di ingresso come intero con un’unica operazione; poi dividerlo per 2 e rimoltiplicare il risultato per due: in tal caso complessità spaziale e temporale sono entrambe O(log(n)). b. leggere il dato di ingresso bit a bit e verificare solo il valore dell’ultimo. In tal caso la complessità temporale è O(log(n)) e quella spaziale O(1) perché non deve memorizare tutta la stringa di ingresso ma solo l’ultimo bit letto; inoltre ogni singola operazione costa O(1) anche a criterio di costo logaritmico. Algoritmi e Principi dell'Informatica Prima Prova in Itinere 25 Novembre 2013 Avvisi importanti Il tempo a disposizione è di 1 ora e 30 minuti. Se non verranno risolti in maniera soddisfacente gli esercizi 1, 2, 3 (ossia ottenendo almeno 2 punti in ognuno di essi) non si procederà alla correzione dell'esercizio 4. Chi otterrà una valutazione inferiore a 6/15-esimi non potrà sostenere la seconda prova e potrà iscriversi soltanto al secondo appello della sessione invernale. Esercizio 1 (punti 3/15-esimi) Dire se esiste un automa a stati finiti che riconosce il seguente linguaggio: L = {anbncn | n > 2} {a*b*c*} Spiegare brevemente la risposta. Esercizio 2 (punti 3/15-esimi) Quale delle seguenti formule del prim’ordine definisce correttamente i numeri di Fibonacci? (si ricorda che l’n-esimo numero di Fibonacci è la somma dell’(n-1)-esimo e dell’(n-2)-esimo, per n > 1, mentre per n = 0 o 1 ha il valore convenzionale 0 e 1, rispettivamente.) ) n((n=0 fib(n) = 0) (n=1 fib(n) = 1) (n > 1 fib(n) = fib(n-1) + fib(n-2))) ) n((n=0 fib(n) = 0) (n=1 fib(n) = 1) (n > 1 fib(n) = fib(n-1) + fib(n-2))) Spiegare brevemente la risposta, preferibilmente fornendo esempi opportuni di valori di n e fib(n) che soddisfino o non soddisfino le formule ) e ): per esempio, se m è l’n-esimo numero di Fibonacci e ) è la formula corretta, la coppia n, m deve soddisfare ) ma non l’altra formula e viceversa. Esercizio 3 (punti 3/15-esimi) Si consideri il seguente (frammento di) programma: while (x >= 0) {x = x*x - 2*x;} E' decidibile il problema di stabilire se la sua esecuzione termina qualsiasi sia il valore iniziale della variabile x all'inizio del ciclo? Spiegare brevemente la risposta. Esercizio 4 (punti 8/15-esimi) Si consideri la seguente macchina astratta MA, descritta informalmente nel modo seguente: MA è dotata di un nastro di ingresso e uno di uscita; è dotata inoltre di un organo di controllo a stati finiti; e di una memoria ausiliaria consistente in una sequenza lineare di celle (come per altre classiche macchine astratte, ogni cella può contenere un carattere di un alfabeto finito) illimitata da ambo le parti; MA può accedere in lettura e scrittura solo ai due estremi della memoria ausiliaria. Una mossa di MA consiste nel: Leggere il simbolo in corrispondenza della testina del nastro di ingresso, oppure effettuare una -mossa nella quale non viene letto nessun carattere; Leggere i due simboli alle estremità della memoria ausiliaria; In base ai valori acquisiti e allo stato dell'organo di controllo, la MA può: Cambiare stato dell'organo di controllo; Scrivere, in sostituzione dei caratteri alle estremità della memoria ausiliaria, due rispettive stringhe; Scrivere una stringa, eventualmente nulla, sul nastro di uscita; Spostare a destra di una posizione o lasciare ferma la testina del nastro di lettura, a seconda che venga eseguita una mossa di lettura o una -mossa; Spostare a destra la testina del nastro di scrittura di un numero di posizioni corrispondente alla lunghezza della stringa scritta. 1. Si formalizzi completamente la descrizione di MA, specificandone i suoi elementi, le sue configurazioni e relative transizioni, il criterio di accettazione. 2. Si confronti la sua potenza con quella delle altre macchine astratte conosciute. Per semplicità il confronto può essere limitato alla capacità di riconoscimento di linguaggi, tralasciando la capacità di traduzione. NB: la precedente descrizione informale, trascura volutamente di precisare alcuni dettagli (ad esempio, il criterio di accettazione, possibili situazioni anomale o di errore): la formalizzazione dovrà quindi risolvere eventuali ambiguità garantendo un funzionamento di MA utile a riconoscere una classe significativa di linguaggi. Tracce di soluzioni Esercizio 1 Siccome {anbncn | n > 2} è contenuto in {a*b*c*}, il linguaggio è ovviamente regolare. Esercizio 2 La formula corretta è la ), che è soddisfatta (solo) dalla serie {0, 1, 1, 2, 3, 5, 8, …}; la ) invece è soddisfatta da qualsiasi coppia n, fib(n) perché qualsiasi valore di n falsifica almeno uno degli antecedenti delle formule in disgiunzione, garantendo quindi che la formula complessiva sia sempre vera. Esercizio 3 Il problema è "chiuso" perché il programma cui ci si riferisce è fissato e si chiede di stabilirne la terminazione per ogni valore iniziale della variabile x. E’ quindi necessariamente decidibile. Inoltre è anche deciso: infatti si può verificare che per x = 0 il programma non termina, pertanto non è vero che il programma termina qualsiasi sia il valore iniziale della variabile x all'inizio del ciclo. Esercizio 4 1. Una possibile formalizzazione della MA (in versione deterministica) è la seguente. Una MA è una tupla (Q, I, , O, q0, Z0, F, , ), dove i vari simboli hanno il tradizionale significato della teoria degli automi –stati dell’organo di controllo, alfabeti, ecc.-. Le funzioni , hanno rispettivamente i domini e codomini seguenti: o : Q (I {}) 2 Q (*)2 /* dato lo stato dell’OC, il simbolo in lettura o eventuale -mossa, i due simboli alle estremità della memoria ausiliaria, la macchina si porta in un nuovo stato e riscrive alle due estremità della memoria le corrispondenti stringhe di caratteri in */. Le usuali restrizioni sulla definizione di vanno applicate per garantire il determinismo. o : Q (I {}) 2 O* /* in corrispondenza della mossa definita dalla viene scritta la stringa in O* sul nastro di uscita.*/ Una configurazione di MA è una tupla c = <q, x, , z> , con q Q, x, I*, *, z O*. La relazione di transizione tra configurazioni c = <q, x, , z> |-- c’ = <q’, x’, ’, z’> è definita nel modo tradizionale, con il seguente aspetto significativo: o se x = i.y , = AB e (q, i, A, B) = (q’, , ), allora x’ = y, ’ = ; z’ è definita analogamente sulla base di . o l’effetto di una -mossa è definito analogamente. Una stringa x è accettata se <q0, x, Z0, > |--* <q, , , z>, con q F. In tal caso z è l’eventuale traduzione (x) definita dal trasduttore. (Si noti però che, anche in caso di MA deterministica la traduzione da essa definita potrebbe essere multipla a causa di possibili mosse a scansione dell’input completata). Si noti che, a causa di quanto verrà precisato in seguito a proposito della potenza della MA, non è decidibile se una tale MA per un generico ingresso x termini o meno la computazione. NB. la definizione precedente espone al rischio di conflitti nel caso || = 1, ossia = A: in tal caso si potrebbe verificare (q, i, A, A) = (q’, , ) con (più precisamente, R, perché viene memorizzato in modo simmetrico rispetto a , ossia in modo che il prossimo carattere letto a sinistra sia il primo di e il prossimo carattere letto a destra sia l’ultimo di ) e la mossa della macchina non potrebbe avvenire in modo coerente. Una possibile soluzione consiste nel “bloccare” la MA qualora si verifichi la condizione suddetta; l’alternativa di imporre = R quando (q, i, A, A) = (q’, , ) sarebbe invece troppo restrittiva perché limiterebbe il comportamento della MA anche in casi in cui = AA. Dovrebbe però fare eccezione il caso iniziale (q0, i (o ) , Z0, Z0) per permettere alla macchina di eseguire la prima mossa senza bloccarsi subito; in alternativa si potrebbe definire come configurazione iniziale <q0, x, Z0Z0, >. 2. La MA può facilmente simulare sia un automa a doppia pila (tenendo un separatore Z0 tra la parte sinistra e la parte destra della memoria in modo che esse possano simulare separatamente le due pile) sia un automa a coda. In entrambi i casi è nota l’equipotenza di queste macchine con la macchina di Turing. Algoritmi e Principi dell'Informatica Seconda Prova in Itinere 14 Febbraio 2014 Avvisi importanti Il tempo a disposizione è di 1 ora e 30 minuti. Se non verranno risolti in maniera soddisfacente gli esercizi 1, 2, (ossia ottenendo almeno 6 punti in totale tra i due) non si procederà alla correzione degli altri esercizi; l’esercizio facoltativo 4, sarà valutato solo se si saranno ottenuti almeno 13 punti nei primi 3. Esercizio 1 (punti 4/15-esimi) Si consideri un albero binario in cui ogni nodo o sia una foglia o abbia entrambi i figli. Quali sono l’altezza minima e massima di un tale albero con n nodi? NB: si richiede il valore preciso della funzione di n, non basta l’ordine di grandezza! Esercizio 2 (punti 3/15-esimi) E’ noto che esistono linguaggi riconoscibili in tempo lineare da automi a pila deterministici e da macchine di Turing a k nastri ma non da macchine di Turing a nastro singolo. Esistono anche linguaggi regolari non riconoscibili in tempo lineare da macchine di Turing a nastro singolo? Giustificare brevemente la risposta. Esercizio 3 (punti 8/15-esimi) Si descriva un algoritmo che, dato un BST (Binary Search Tree) stabilisca se esso possa essere colorato in modo tale da diventare un albero rosso-nero (RB). NB: non si chiede di costruire un algoritmo di colorazione, ma solo di stabilire se ciò sia possibile. Si ricordi inoltre che per convenzione in un albero RB tutte le foglie sono NIL, T.NIL per la precisione, e nere. Si valuti la complessità temporale dell’algoritmo. Esercizio 4, facoltativo (punti 3/15) Si formalizzi la seguente definizione informale di complessità spaziale di una macchina di Turing a nastro bidimensionale: Il nastro della macchina è costituito dal primo quadrante di un piano cartesiano a coordinate intere. La complessità spaziale è data dal numero di celle del nastro visitate dalla testina della macchina durante il suo funzionamento; al solito, essa è espressa come funzione della lunghezza della stringa (lineare) di ingresso. Tracce di soluzioni Esercizio 1 L’altezza massima si ha quando ogni nodo interno ha, ad esempio, un foglia come figlio sinistro, tranne l’ultimo i cui figli sono entrambi foglia. In tal caso, detti h l’altezza dell’albero, (definita come il cammino di lunghezza massima, intesa come il numero di archi del cammino, tra la radice e le foglie) e n il numero di nodi, si ha n = 2.h + 1; quindi h= n 1 2 L’altezza minima si ha invece quando l’albero è bilanciato e completo, ossia = - 1; quindi . Esercizio 2 NO: una MT a nastro singolo, una volta posizionata all’inizio delle stringa di ingresso può comportarsi esattamente come un automa a stati finiti, usando il proprio organo di controllo. Siccome un automa a stati finiti esegue sempre uno spostamento a destra della testina di lettura per ogni mossa, la stessa cosa può fare la MT senza dover utilizzare altre porzioni del nastro. Esercizio 3 Una condizione necessaria e sufficiente perché un BST possa essere colorato in modo da diventare un albero rosso-nero è che, nell’intero albero e in ogni suo sottoalbero il rapporto tra le lunghezze minime e massime dei cammini che dalla radice raggiungono le foglie non superi mai 2. Infatti in tal caso sarà sempre possibile colorare i nodi in modo da evitare due nodi rossi consecutivi sullo stesso cammino e l’altezza di ogni sottoalbero sarà comunque (log(n)). Un semplice algoritmo ricorsivo potrebbe quindi visitare l’albero, ad esempio in preordine sinistro, e calcolare, per ogni nodo, la lunghezza dei cammini minimo e massimo da esso alle foglie (min = min(leftSon.min, rightSon.min) +1; max = max(leftSon.max, rightSon.max) +1; min e max dei nodi foglia sono ovviamente 0). Non appena max/min >2 l’algoritmo ritorna FALSE; se giunge fino alla radice con max/min <= 2, ritorna TRUE. Si noti però che, rispetto a un normale BST in un albero rosso-nero le foglie sono tutte NIL (T.NIL per la precisione) e hanno convenzionalmente altezza (nera) = 0; ogni nodo interno ha quindi entrambi i figli. L’algoritmo ha evidentemente complessità (n). Esercizio 4 Una possible definizione formale della complessità spaziale richiesta può essere fornita nel modo seguente: In primo luogo occorre formalizzare il concetto di configurazione: c = <q, x, contenuto: N N A, <i,j>, h> dove q rappresenta lo stato dell’organo di controllo, x la stringa in ingresso, contenuto indica il simbolo contenuto in ogni cella del nastro (con l’usuale vincolo che solo un numero finito di celle sia diverso da blank), <i,j> indica la posizione della testina del nastro di memoria e h quella del nastro di ingresso. La transizione tra configurazioni è poi definita nel modo tradizionale. La complessità spaziale di M è allora espressa dalla funzione: SM(n) = max|x| = n| |{<i,j> | c <i,j> c c0 = <q0, x, [contenuto(0, 0) = Z0, contenuto(i, j) = blank <i,j> <0,0>], <0,0>, 0] |---* c}| Ossia la massima cardinalità, rispetto a tutte le stringhe di lunghezza n, dell’insieme delle coordinate delle posizioni della testina di memoria raggiunte durante il funzionamento della macchina a partire dalla configurazione iniziale. Algoritmi e principi dell’Informatica Recupero prima prova in itinere 24 Febbraio 2014 Avvisi importanti La prova è riservata ai laureandi che non abbiano superato la prima prova in itinere La durata della prova di recupero è di 1 ora Esercizio 1 (punti 7/15-esimi) Si dica, giustificando brevemente le risposte, se le seguenti affermazioni sono vere o false: 1. Dato un qualsiasi automa a pila A, sia deterministico che nondeterministico, esiste sempre un automa a pila, sia deterministico che nondeterministico, che riconosce il complemento di L(A). 2. Dato un qualsiasi automa a pila A, sia deterministico che nondeterministico, esiste sempre una macchina di Turing, che riconosce il complemento di L(A). Esercizio 2 (punti 8/15-esimi) Si consideri l’alfabeto A = {a,b}. Per una stringa s costruita su A* chiamiamo massima sequenza ciascuna sottostringa non nulla t di s i cui caratteri siano tutti uguali e che non sia né seguita né preceduta da un ulteriore carattere uguale ai precedenti o ai seguenti. Ad esempio, nella stringa abbaaaa le massime sequenze sono a, bb, aaaa. 1) Si specifichi in logica del prim’ordine un predicato ternario same(s,c,n) che è vero se e solo se la stringa s è di n caratteri, tutti uguali al carattere c. (Nota: c è rappresentato come una stringa di un solo carattere.) 2) Si fornisca una specifica in logica del prim’ordine del predicato binario maxSeq(t,s) che è vero se è solo se t è una massima sequenza per s. Nella specifica, si faccia ricorso al predicato same definito al punto precedente. Nota bene: nella scrittura delle formule si può fare ricorso esclusivamente alle seguenti funzioni, predicati e costanti la cui definizione può essere data per scontata e quindi da non specificare ulteriormente: s = t (predicato di uguaglianza: vero se e solo se s è uguale a t) st (funzione che indica la concatenazione delle stringhe s e t) len(s) (funzione “lunghezza” che indica la lunghezza della stringa s) 0, 1, … (costanti che indicano i numeri naturali) a (costante che indica la stringa di un solo carattere “a”) b (costante che indica la stringa di un solo carattere “b”) Tracce di soluzioni Esercizio 1 1. NO: la classe dei linguaggi riconosciuti da APN non è chiusa rispetto al complemento, essendo chiusa rispetto all’unione ma non rispetto all’intersezione. 2. SI: i linguaggi riconosciuti da APN sono ricorsivi, quindi lo sono anche i loro complementi. Esercizio 2 Definizione di same: s n c same(s,c,n) len(s) = n x y z (s=xyz len(y)=1 y=c) Definizione di maxSeq: t s maxSeq(t,s) xyzcn ( t= xyz (c = a c = b) same(y,c,n) (v x = vc) (w z = cw) ) Algoritmi e Principi dell’Informatica Appello del 3 Marzo 2014 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2 e 3 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4 e 5 in 1 ora e 15 minuti. NB1: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. NB2: l’esercizio 5 verrà valutato solo se negli altri esercizi si sarà ottenuto un punteggio di almeno 11. Esercizio 1 (punti 4) Si consideri la seguente grammatica: S S a | a S | b B | b S B B B S S B S a b b a Quale linguaggio genera? Qual è la classe di automi a potenza minima in grado di accettare lo stesso linguaggio? Esercizio 2 (punti 4 senza restrizione; punti 8 se si applica la restrizione) Si specifichi in logica del prim’ordine il seguente linguaggio L: L = {an b2n cn-1, con n>0} Restrizione: nella scrittura delle formule si può fare ricorso esclusivamente alle seguenti funzioni, predicati e costanti la cui definizione può essere data per scontata e quindi da non specificare ulteriormente: x L (predicato di appartenenza: vero se e solo se x appartiene a L) s = t (predicato di uguaglianza: vero se e solo se s è uguale a t) st (funzione che indica la concatenazione delle stringhe s e t) a (costante che indica la stringa di un solo carattere “a”) b (costante che indica la stringa di un solo carattere “b”) c (costante che indica la stringa di un solo carattere “c”) Esercizio 3 (punti 7) E’ decidibile il problema di stabilire se, dato un generico trasduttore a stati finiti T e una stringa y O*, esista una stringa x I*, tale che y = (x), dove: O è l’alfabeto di output di T I è l’alfabeto di input di T : I* O* è la traduzione definita da T ? Giustificare brevemente la risposta. Esercizio 4 (punti 5) Qual è il numero massimo di possibili ordinamenti topologici compatibili con un DAG di n nodi? Esercizio 5 (punti 11) Si scriva un algoritmo che ordini una coda di interi, supposta già in memoria, assumendo che essa sia utilizzabile come una struttura astratta di cui sia nota solo l’interfaccia, a sua volta costituita esclusivamente dalle primitive canoniche ENQUEUE e DEQUEUE (e non altre!). Si valuti la complessità asintotica dell’algoritmo. NB: sono preferite soluzioni che non implichino aumento della lunghezza della coda durante l’esecuzione e usino il minor numero possibile di celle ausiliarie, in ogni caso in quantità indipendente dal numero di elmenti in coda. Per semplicità si può assumere che la coda non contenga elementi ripetuti; questa assunzione però diminuisce il valore della soluzione di 1 punto. Tracce delle Soluzioni Esercizio 1 Il linguaggio generato dalla grammatica è L(G) = a*ba*. Infatti le prime due regole generano stringhe del tipo a*Sa*; quando si applica la regola S b B, si ottiene una stringa del tipo a*bBa* che non potrà derivare nessun’altra stringa perché per riscrivere B occorre che esso compaia vicino a un S; quindi per poter generare una stringa terminale è necessario applicare la regola S b che impedisce ulteriori derivazioni. L(G) è chiaramente regolare anche se G non lo è; di conseguenza esso è riconoscibile da un automa a stati finiti. Esercizio 2 Soluzione senza restrizione Il linguaggio L può essere definito con una formula del prim’ordine nel modo seguente: x (x L n (x = power(a, n) power(b, 2n) power(c, n-1) n > 0)) dove, al solito, il predicato power(x,n) è definito dalla formula x ( (power(x,0) = ) n (n > 0) (power(x,n) = x power(x,n-1) Soluzione con restrizione Se invece sono consentiti solo i costrutti indicati nel testo, conviene definire alcuni linguaggi di supporto: x (x La x = a y (y La x = a y)) (ossia La = a+) x (x Lb x = b y (y Lb x = b y)) (ossia Lb = b+) x (x Lc x = c y (y Lc x = c y)) (ossia Lc = c+) x (x L1 x = a b b y (y L1 x = a y b b)) (ossia L1 = an b2n, n>0) x (x L2 x = a y (y L2 x = a y c)) (ossia L2 = an cn-1, n>0) Infine definisco L: x (x L x = a b b yzw (x = y z w y La z Lb w Lc y z L1 y w L2)) Esercizio 3 Premessa: la lunga storia della teoria degli automi dimostra che molto raramente un problema relativo agli automi a stati finiti è indecidibile; ciò grazie alle sue proprietà essenziali, riassunte nel pumping lemma. Il problema in oggetto non costituisce un’eccezione. Infatti, anche se in generale non è detto che |x| |(x)| a causa di eventuali mosse che non scrivono nulla in output, è possibile enumerare le stringhe di input in modo tale da garantire che l’insieme traduzione di un numero finito di esse contenga tutte le stringhe di output z tali che |z| |y|. Precisamente si potrebbe procedere come segue: Si enumerino tutte le stringhe x I* per lunghezza crescente e se ne calcolino le rispettive (x) finché |(x)| > |y|. Se durante tale enumerazione si individua una sottostringa w di x tale che x = zws, *(q0, z) = q, *(q, w) = q e *(q, w) = , w può essere eliminata dalla stringa x senza evidentemente cambiare il risultato della traduzione. Rimangono quindi da prendere in esame solo stringhe “a traduzione crescente” nel senso che per tali stringhe x ) Enumerando quindi tutte le stringhe di I* ma escludendo quelle che contengono sottostringhe del tipo w di cui sopra è possibile ottenere tutte le stringhe di lunghezza |y| che siano traduzione di qualche x. Se tra esse non figura la stringa y, ciò significa che non può essere ottenuta come risultato della traduzione . Esercizio 4 Se il grafo non ha archi qualsiasi permutazione dei nodi è un ordinamento topologico compatile con esso; quindi se ne possono ottenere n! Esercizio 5 L’impossibilità di usare memoria ausiliaria in quantità arbitraria e la necessità di accedere alla coda solo mediante le primitive canoniche obbliga a far scorrere la coda diverse volte fino ad ottenerne una trasformazione ordinata. Un semplice algoritmo descritto a grandi linee è il seguente: Una prima passata calcola il minimo valore in coda e il numero n di elementi presenti. Per farlo senza aumentare la lunghezza della coda e senza escludere l’esistenza di elementi ripetuti si può agire come segue: o DEQUEUE (x); min = x; ENQUEUE (‘#’); n = 1; o /* per semplicità si omette un test di coda vuota*/ o DEQUEUE (x); o while x != ‘#’ do { if x < min { ENQUEUE(min); min = x} else ENQUEUE(x); DEQUEUE (x); n++; } o ENQUEUE(min); o /* alla fine di questa passata n contiene la lunghezza della coda il cui ultimo elemento è il valore minimo della coda originaria; seguono n -1 passate:*/ for (i = n-1, i >= 1, i--) do o DEQUEUE (x); min = x; o for (k = 1, k < i, k++) do { DEQUEUE (x); if x < min { ENQUEUE(min); min = x} else ENQUEUE(x); }; o ENQUEUE(min); o for (j = i, j < n, j++) do { DEQUEUE (x); ENQUEUE(x)} o /* la parte già ordinata della coda viene ricopiata identica*/ Questo algoritmo non aumenta la lunghezza originaria della coda, usa le variabili ausiliarie min, x, n, oltre ai contatori i, j, k (di cui uno potrebbe essere risparmiato, usando lo stesso k al posto di j) e ha ovviamente complessità O(n2). Appare decisamente difficile, probabilmente impossibile, ottenere complessità asintotiche migliori di O(n2). Qui sotto viene riporata una versione eseguibile dello pseudocodice. function queue_sort(Q) { 'use strict'; var x, min, n, i, j, k; x = dequeue(Q); min = x; enqueue(Q, '#'); n = 1; x = dequeue(Q); while (x !== '#') { if (x < min) { enqueue(Q, min); min = x; } else { enqueue(Q, x); } x = dequeue(Q); n += 1; } enqueue(Q, min); for (i = n - 1; i >= 1; i -= 1) { min = dequeue(Q); for (k = 1; k < i; k += 1) { x = dequeue(Q); if (x < min) { enqueue(Q, min); min = x; } else { enqueue(Q, x); } } enqueue(Q, min); for (j = i; j < n; j += 1) { x = dequeue(Q); enqueue(Q, x); } } } . Algoritmi e Principi dell’Informatica Appello del 7 Luglio 2014 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1a, 1b e 2 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1a (punti 5) Si consideri il linguaggio Lk, dove k è un parametro, costituito da stringhe sull’alfebto {a, b} tali che ogni volta che si trovino k a consecutive ne segua immediatamente almeno una b. Si costruisca una rete di Petri che accetti L3. NB: è preferible che la rete non contenga transizioni che siano sia in ingresso che in uscita al medesimo posto. Esercizio 1b (punti 5) Si scriva una formula del prim’ordine che specifichi un generico linguaggio Lk per un dato valore del parametro k (la formula deve quindi dipendere da k, variabile libera) dell’esercizio 1.a usando variabili intere che indichino la posizione di un carattere nella stringa e i predicati a(i) e b(i) per indicare che il carattere in posizione i-esima è a o b, rispettivamente. Ad esempio la formula a(1) b(2) indica che la stringa deve inziare con ab. NB: qualora fosse utile si può fare uso del predicato (indefinitio) per indicare l’assenza di carattere in posizione i: per convenzione si può assumere che valga (0) e che per una stringa lunga n valga (a(n) b(n)) (n+1). Esercizio 2 (punti 7) Una macchina di Turing Mi (che calcola la funzione fi) è detta riproducibile se esiste un'altra macchina di Turing Mj (che calcola la funzione fj) tale per cui fi=fj. Si consideri l’insieme delle MT definite sull’alfabeto di due caratteri {0, 1}. Al suo interno siano: F l’insieme delle funzioni calcolate da macchine di Turing riproducibili. G l'insieme delle funzioni calcolate da macchine di Turing riproducibili e con meno di 10 stati. H l'insieme delle funzioni calcolate da macchine di Turing riproducibili e con più di 10 stati. Dire se i seguenti problemi sono decidibili: 1) Stabilire se una generica macchina di Turing calcoli una funzione in F. 2) Stabilire se una generica macchina di Turing calcoli una funzione in G. 3) Stabilire se una generica macchina di Turing calcoli una funzione in H. Esercizio 3 (punti 7) Si consideri la traduzione (x) = ak bh, dove x {a,b}+, k è il numero di b in x e h il numero di a in x. Si descriva il funzionamento di un MT a nastro singolo che implementi usando esclusivamente le celle di memoria contenenti x. Se ne valutino la complessità temporale e spaziale. Esercizio 5 (punti 9) Dati: un elenco di attività e di vincoli di precedenza fra esse scrivere un algoritmo che rappresenta queste attività in un grafo di precedenze o fallisce se i vincoli di precedenza sono incoerenti (as esempio, se A precede B e B precede A, sia direttamente che indirettamente, i vincoli sono incoerenti). Indicare la complessità dell’algoritmo Ad esempio: Date le 7 attività A, B, C, D, E, F, G con i seguenti vincoli di precedenza A −> C, B −> C, C −> E, D −> F, B −> D, C −> F, D −> G il grafo di precedenze risultante è Tracce delle Soluzioni Esercizio 1° La rete di Petri seguente, dove è indicata la marcatura iniziale e ogni possibile marcatura seguente viene riconosciuta come finale (un solo token può marcare un solo posto), riconosce il linguaggio L3. b b a b a b a Esercizio 1.b x i (((x i < x+k) a(i))b(x+k)) Esercizio 2 Il problema 1 è decidibile ed è anche deciso. Infatti, ogni macchina di Turing è riproducibile: come è noto, data una funzione calcolabile, esistono infinite macchine di Turing che la calcolano. Quindi F coincide con l’insieme universo di tutte le funzioni calcolabili. Il problema 2 è indecidibile per il teorema di Rice. Infatti, l’insieme delle macchine di Turing con meno di 10 stati e con alfabeto di due caratteri è finito (proprietà che abbiamo anche usato per enumerare le macchine di Turing), pertanto sarà finito (e non vuoto) anche l’insieme di funzioni calcolabili calcolate da dette macchine di Turing. Allora l’insieme G non è né l’insieme vuoto, né l’insieme di tutte le funzioni computabili, da cui l’indecidibilità per il teorema i Rice. Il problema posto nel quesito 3 è decidibile per il teorema di Rice. Infatti, ogni funzione calcolabile è calcolabile (anche) mediante una macchina con più di 10 stati. Come scritto in precedenza, per ogni funzione computabile esistono infinite macchine di Turing che la calcolano, mentre le macchine di Turing con un numero di stati minore o uguale a 10 sono in numero finito, quindi ogni funzione calcolabile dev’essere calcolata anche da macchine con più di 10 stati. Pertanto H è l’insieme di tutte le funzioni computabili e il problema è allora decidibile per il teorema di Rice. Esercizio 3 1) la macchina fa una passata scambiando le a con le b e viceversa: complessità ((n)) 2) la macchina fa una passata cercando coppie ba e scambiando la b con la a (scambio: costo costante; costo della passata: (n)) 3) se alla fine della passata non trova coppie ba, si ferma, altrimenti ripete il passo 2) Al max si fanno n passate, quindi la complessità totale sarà (n2). Esercizio 4 Come suggerito nel testo dell’esercizio, si costruisca un grafo che rappresenti le attività (nodi) e i relativi vincoli di precedenza (archi): i vincoli sono incoerenti se e solo se il grafo contiene cicli. Ciò può essere verificato mediante una opportuna modifica dell’algoritmo di visita Depth-first (costituito da diverse visite ricorsive) che distingua tra i nodi scoperti in una precedente visita e quelli scoperti nella visita corrente; se finisce su uno del primo tipo, la visita corrente termina, e se ne lancia un’altra; nel secondo caso la visita termina restituendo false. Se l’algoritmo ha successo, cioè non trova cicli, il grafo ottenuto è un DAG e ad esso può essre applicato un topological sort. FIND-LOOP(G) /* ritorna flalse se I vincoli sono incoerenti, e quindi se il grafo contiene un ciclo*/ 1 for each u ∊ G.V 2 u.color := 0 3 c := 0 4 for each u ∊ G.V 5 if u.color = 0 6 c := c+1 7 if FIND-LOOP-VISIT(u, c) = false 8 return false 9 return true FIND-LOOP-VISIT(u, c) 1 u.color := c 2 for each v ∊ u.Adj 3 if v.color = c 4 return false 5 if v.color = 0 6 return FIND-LOOP-VISIT(v, c) 7 return true L’algoritmo proposto è quindi O(|V| + |E|) e potrebbe essere incluso come parte integrante in un algoritmo di topological sort senza alterarne la complessità. Algoritmi e Principi dell’Informatica Appello del 17 Luglio 2014 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2 e 3 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4 e 5 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 5) Si considerino la grammatica e l’automa a pila seguenti, e i linguaggi L(G) e L(A) definiti da essi sull’alfabeto {a,b}: G: S ---> | aSb A: b, C/ a, A/AA b, A/ a, C/CA b, A/ a, Z0/Z0C b, C/ b, Z0/Z0B a, A/B aC/CB a, B/BB a, Z0/Z0B b, Z0/Z0B a, B/BB b, B/BB b, B/BB Si costruiscano un automa o una grammatica a potenza minima che riconoscano/generino rispettivamente L(G) L(A) e L(G) L(A). Esercizio 2 (punti 6) Si consideri la seguente formula F: xyz m(x,y,z) t m(x,y,t) 2.a Come noto, una formula può essere intesa in senso puramente sintattico come una sequenza di simboli. Si indichi la categoria sintattica (funzione, predicato, ecc.) di ciascun simbolo utilizzato in F; se pertinente, indicare anche la arietà associata al simbolo. Si dica anche se F è una formula chiusa. 2.b Si consideri poi un’interpretazione in cui m(x,y,z) indica il fatto che la macchina di Turing con indice y e ingresso x produce z in uscita. E’ vera la formula F sotto l’interpretazione data? Esercizio 3 (punti 6) Il signor Giovanni sta cercando di procurarsi un compilatore “open source” o commerciale che traduca codice C nell’assembler del suo hardware xyz. Egli sa che non tutto il SW open-source o disponibile sul mercato è affidabile al 100% (eufemismo). Quindi, prima di procedere all’acquisizione (che intende utilizzare per sviluppare applicazioni altamente critiche) intende anche e preliminarmente acquisire sufficienti “garanzie” (intese in senso tecnico, non semplicemente commerciale (in caso di danni previsione di adeguato risarcimento)). Quindi, prima ancora di mettersi alla caccia del compilatore che faccia al caso suo si mette alla ricerca di uno strumento e/o di un benchmark che gli possa verificare con certezza il corretto funzionamento del compilatore che intende esaminare per l’eventuale acquisizione. Può la ricerca del signor Giovanni (quella dello strumento o del benchmark, non quella successiva del compilatore) avere successo? Si spieghi brevemente il motivo della risposta. Parte opzionale Che cosa consigliereste al signor Giovanni riguardo alla sua ricerca: è preferibile orientarsi verso un opportuno benchmark oppure verso uno strumento che certifichi la correttezza del compilatore? Esercizio 4 (punti 7) Dato il seguente algoritmo che calcola la reverse di una coda di elementi Reverse(P): If queue P is not empty do: Dequeue (P) element Reverse (P) Enqueue (P, element) Ricavare e risolvere in maniera precisa l’equazione alle ricorrenze T(n) = ? (si osservi che il tempo per fare il reverse di una coda di 1 elemento , T(1), è costante) Esercizio 5 (punti 9) Si considerino due alberi binari di ricerca (BST). Si definisca un algoritmo per costruire un BST contenente i dati di entrambi gli alberi e che sia “ragionevolmente” bilanciato, ossia abbia un’altezza dello stesso ordine di grandezza di quella di un albero perfettamente bilanciato. Se ne valutino le complessità spaziale e temporale. Tracce delle Soluzioni Esercizio 1 L(G) è chiaramente il linguaggio {anbn | n 0} A invece accetta tutte le stringhe non in L(G) oltre la stringa nulla. Quindi L(G) L(A) = {a, b}* e L(G) L(A = {}, entrambi linguaggi regolari. Esercizio 2 Parte 2.a: quantificatore universale x variabile quantificatore universale z variabile quantificatore esistenziale y variabile m predicato con arietà 3 ( punteggiatura x variabile , punteggiatura y variabile , punteggiatura z variabile ) punteggiatura connettivo logico (implicazione) quantificatore esistenziale t variabile m predicato con arietà 3 ( punteggiatura x variabile , punteggiatura y variabile , punteggiatura t variabile ) punteggiatura La formula è chiusa in quanto tutte le variabili sono quantificate. Parte 2.b La formula F è vera nell’interpretazione data. Se, data una coppia di valori <x,y>, esiste un valore z tale che <x,y,z> soddisfi m (ossia la funzione calcolata dalla macchina di Turing con indice y per l’ingresso x è definita e restituisce z), tale tripla può essere utilizzata per soddisfare anche la parte a destra dell’implicazione (basta scegliere un valore di t uguale a z). Se invece non esiste un valore di z tale che <x,y,z> soddisfi m (ossia la funzione calcolata dalla macchina di Turing con indice y per l’ingresso x non è definita), l’implicazione è banalmente soddisfatta poiché l’antecedente è falso. Esercizio 3 Il problema della correttezza di un compilatore, come la correttezza di un qualsiasi programma è formalizzabile come il problema di stabilire se un generico algoritmo calcola una funzione data; quindi in tal caso è applicabile il teorema di Rice poiché la compilazione dal C a un linguaggio assembler è formalizzabile come una specifica funzione computabile (diversa dall’insieme vuoto e dall’insieme universo di tutte le funzioni computabili). Nessun benchmark può quindi certificare la correttezza assoluta (assenza di errori) di un programma (a meno di non ridurre il problema a un dominio finito e ipotizzare un testing esaustivo). Tuttavia un benchmark ben congegnato ha buone possibilità, se il programma testato è scorretto, di evidenziarne eventuali errori (semidecidibilità della Scorrettezza di un programma). E’ quindi preferibile consigliare al signor Giovanni la ricerca di un buon benchmark piuttosto che quella di un tool che per motivi teorici non potrà mai garantire la correttezza di un qualsiasi compilatore. Tuttavia, ciò non esclude che il signor Giovanni possa trovare su Internet un compilatore corredato di una specifica certificazione di correttezza che matematicamente DIMOSTRI tale correttezza come risultato di un’adeguata analisi formale eseguita da esperti del settore (certificazione che a sua volta Giovanni potrebbe controllare se fornito di adeguata competenza teorica o fare verificare da un tool automatico per la verifica di correttezza di prove matematiche). Esercizio 4 Condizione iniziale: il tempo per fare il reverse di una coda di un elemento è costante T(1) = O(1) = 1 Relazione alle ricorrenze: il tempo per fare il reverse di una coda di N elementi è il tempo di fare il reverse di una coda dì N-1 elementi più 2 operazioni (dequeue e enqueue). T(N) = T(N-1) + 2 Sostituendo abbiamo T(N-1) = T(N-2) + 2 T(N-2) = T(N-3) + 2 …… T(2) = T(1) + 2 T(1) = 1 sommiamo a sinistra e a destra: T(N) + T(N-1) + T(N-2) + T(N-3) + …. T(3) + T(2) = = T(N-1) + T(N-2) + T(N-3) + …. T(3) + T(2) + T(1) + 2*(N-1) semplificando : T(N) = T(1) + 2*(N-1) = 1 + 2*(N-1) l’algoritmo è quindi O(N) Esercizio 5 1) Si effettua visita "in ordine" dei due alberi T1 e T2, ottenendo due liste ordinate L1 e L2 (complessità (n1+n2), dove n1 = |L1|, n2 = |L2|). 2) Si fondono le due liste in un array ordinato ( (n1+n2)). 3) Si crea un BST partendo dall'elemento centrale dell'array, poi ricorrendo sui due sottoarray ( (n1+n2)). Quindi le complessità risultanti sono entrambe lineari nel numero dei nodi presenti nei sottoalberi: S(n) = T(n) = (n), dove n = n1+n2. Algoritmi e Principi dell’Informatica Appello del 2 Settembre 2014 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2, 3 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4, 5 e 6 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 6) Si consideri il linguaggio L={ ambn | m n, m, n > 0 }. Esempi di stringhe di L sono: aabbb e aaabb, mentre ab, aabb, aba, sono stringhe non appartenenti ad L. 1. Si fornisca una grammatica, preferibilmente a potenza generativa minima tra le classi conosciute, che generi L. 2. Si fornisca un automa, preferibilmente a potenza riconoscitiva minima tra le classi conosciute, che riconosca L. Esercizio 2 (punti 6 senza la parte opzionale, 8, con la parte opzionale) Una procedura P riceve in ingresso un numero naturale n > 1 e due array, in e out, entrambi contenenti 2n numeri naturali (l’indice di entrambi gli array è compreso tra 1 e 2n inclusi). Preliminarmente si specifichino i predicati odd(n) e even(n), facendo uso di formule del prim’ordine contenenti esclusivamente variabili e costanti intere, il predicato di uguaglianza, i simboli delle operazioni di somma e prodotto, in modo tale che i due predicati assumano il loro naturale significato, ossia odd(n) risulti vero se e solo se n è un numero naturale dispari, e even(n) se e solo se n è un numero naturale pari. Successivamente: 1) Si specifichino le precondizioni seguenti che devono quindi valere all’inizio dell’esecuzione di P. a) Ogni elemento dell’array in è diverso da ogni altro elemento dello stesso array in. b) Tutti gli elementi dell’array in in posizioni dispari sono dispari, e tutti quelli in posizione pari sono pari. La procedura copia tutti gli elementi dell’array in nell’array out, piazzando i numeri dispari nelle prime n posizioni e quelli pari nelle n posizioni seguenti. 2) Si specifichino ora le seguenti postcondizioni per la procedura P. a) Tutti gli elementi della parte inferiore (ossia quelli nelle posizioni 1 .. n) dell’array out sono uguali a qualche elemento dispari di in. b) Tutti gli elementi della parte superiore dell’array out sono uguali a qualche elemento pari di in. 3) Opzionalmente si aggiungano ulteriori post-condizioni, se ritenute necessarie, per rendere la specifica della procedura perfettamente coerente con la sua definizione informale fornita qui sopra. NB: la parte opzionale verrà valutata solo se i due punti precedenti saranno risolti in modo soddisfacente. Esercizio 3 (punti 3) E’ decidibile il problema di stabilire se una qualsiasi procedura Q soddisfa la specifica fornita dalle pre- e post-condizioni dell’esercizio precedente (incluse o escluse eventuali post-condizioni opzionali)? Si fornisca una breve ma precisa spiegazione della risposta. Esercizio 4 (punti 8) a) Descrivere a grandi linee ma con precisione una MT che realizzi la procedura dell'esercizio 2 in modo da ottenere la miglior complessità temporale (asintotica) possibile. (Si assuma che gli interi contenuti nell'array siano limitati, in modo che la complessità dipenda solo da n.) b) Descrivere anche una macchina RAM, il cui repertorio istruzioni sia esattamente quello del testo, con lo stesso obiettivo. Quale delle due complessità temporali (la seconda a criterio logaritmico) è migliore? Perché? Esercizio 5 (punti 3) Si risolva la seguente equazione alle ricorrenze: T(n) = 5 T(n/2) + n2log(n) Esercizio 6 (punti 5) Si consideri come struttura dati un albero generale, in cui cioè ogni nodo può avere un numero arbitrario di figli, anche maggiore di 2. a) Dire come si può rappresentare un albero generale con una struttura a puntatori. b) Si sviluppi un algoritmo per verificare, per ogni nodo x diverso dalla radice, se è soddisfatta la proprietà che la chiave del padre di x è > della chiave di x stesso. Si dia la complessità dell’algoritmo scritto. Tracce delle soluzioni Esercizio 1 1. S aCb C aCb | A | B A aA | a B bB | b 2. b, C/ a, A/AA b, A/ a, C/CA a, Z0/Z0C b, A/ b, C/ b, Z0/Z0 b, Z0/Z0 Esercizio 2 x ( odd(x) k ( x = 2k + 1 ) ) x ( even(x) k ( x = 2k ) ) 1) Precondizioni. a) Ogni elemento dell’array in è diverso da ogni altro elemento dello stesso array in. i (1 i 2n j (1 j 2n i j in[i] = in[j] ) ) b) Tutti gli elementi dell’array in in posizioni dispari sono dispari, e tutti quelli in posizione pari sono pari. i (1 i 2n ( ( odd(i) odd(in[i]) ) (even(i) even(in[i]) ) ) 2) Postcondizioni. a) Tutti gli elementi della parte inferiore (ossia quelli nelle posizioni 1 .. n) dell’array out sono uguali a qualche elemento dispari di in. i (1 i n j (1 j 2n odd(in[j]) out[i] = in[j] ) ) c) Tutti gli elementi della parte superiore dell’array out sono uguali a qualche elemento pari di in. i (n+1 i 2n j (1 j 2n even(in[j]) out[i] = in[j] ) ) 3) Parte opzionale. L’array out deve contenere tutti gli elementi dell’array in. i (1 i 2n j (1 j 2n out[i] = in[j] ) ) Esercizio 3 La domanda dell’esercizio è un tipico problema di correttezza: si chiede se un generico algoritmo implementa una particolare funzione o famiglia di funzioni definita mediante le pre- e post-condizioni. In questo caso, evidentemente le funzioni che soddisfano le pre- e post-condizioni, sia includendo che escludendo la parte opzionale, non sono evidentemente né l’insieme vuoto (la specifica non è soddisfacibile) né l’insieme universo (la specifica è soddisfatta da qualsiasi funzione computabile). Quindi per il teorema di Rice il problema è indecidibile. Esercizio 4 Essendo i numeri memorizzati nell’array limitati, ognuno di essi può essere memorizzato in un numero finito e costante di celle della MT. In una prima passata la MT copia nel nastro di uscita solo i numeri in posizione dispari; successivamente si riporta all’inizio bel nastro di ingresso e copia a seguire i numeri in posizione pari. La complessità ottenuta è chiaramente O(n). La RAM invece non ha la possibilità di percorrere a ritroso il nastro di ingresso, né quello di output; essa deve perciò memorizzare preliminarmente il contenuto del nastro di ingresso e procedere poi alla stessa maniera della MT; ogni memorizzazione di un numero però, a criterio di costo logaritmico, costa O(log(n)); quindi la complessità asintotica della RAM è O(n.log(n)). Esercizio 5 La ricorrenza si risolve semplicemente applicando il Master Theorem. In questo caso logb(a) = log2(5), che ha valore un po’ maggiore di 2 (circa 2.3). n2.3 è polinomialmente maggiore di n2log(n), quindi la ricorrenza ha soluzione Θ(nlog2(5)). Esercizio 6 a) Un albero generale può essere rappresentato con una struttura a puntatori in cui ogni nodo x ha 4 attributi: x.key è la chiave, x.p è il puntatore al padre, x.fst è il puntatore al figlio più a sinistra, e x.sibling è il puntatore al fratello a destra. b) test_property(T) x := T.root return test(x) test(x) if x = NIL return true if (x.p = NIL OR x.p.key > x.key) return test(x.fst) AND test(x.sibling) else return false La complessità dell’algoritmo scritto è semplicemente Θ(n), in quanto vengono analizzati tutti i nodi uno ad uno. Algoritmi e Principi dell’Informatica Appello del 18 Settembre 2014 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2, 3 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4, 5 e 6 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 5) Si consideri il linguaggio L delle stringhe anbn, anbnanbn, ... dove anbn può essere ripetuto 1 o più volte, con 0 < n < 4. Esempi di stringhe in L sono: aabb, abab. Esempi di stringhe non in L sono invece: abb, aabbab. Si scrivano un automa e/o una grammatica a potenza minima per L e per L1 = L {(ambm)+, m > 0}. NB: è preferita una soluzione che presenti sia una grammatica che un automa ma è accettabile anche uno solo dei due formalismi. Esercizio 2 (punti 8) Punto a. Specificare in logica del prim’ordine il predicato binario substring(x,y) che indica che il primo argomento x è una sottostringa del secondo argomento y, ossia una sequenza di caratteri consecutivi che compare in y. NB: come caso particolare la stringa nulla è sottostringa di qualsiasi stringa. Ad esempio substring(ac,abcd) è falso substring(bc,abcd) è vero Per la specifica, oltre al predicato di uguaglianza, si può usare solo la funzione binaria concat (concatenazione tra stringhe), che restituisce la concatenazione dei suoi argomenti. Ad esempio: concat(ab,cd) restituisce abcd Punto b. Si specifichi poi il predicato substring2(x,y,i,j) che indica che x è uguale alla sottostringa di y che va dal carattere in posizione i di y al carattere in posizione j i di y (estremi inclusi). Si noti che per una stringa di lunghezza n, le posizioni dei suoi caratteri vanno da 1 a n; si noti anche che questa definizione implica che x non sia la stringa nulla. Per la specifica, in aggiunta a quanto consentito al punto a, si possono usare le 4 operazioni aritmetiche, le costanti intere e la funzione unaria len che restituisce la lunghezza di una stringa. Ad esempio: len(abcd) restituisce 4 Si può evitare, in quanto sottinteso, l’uso di predicati string(x) e integer(i) per specificare che una variabile rappresenta una stringa o un intero, rispettivamente; di conseguenza non è necessario specificare esplicitamente domini e codomini delle funzioni utilizzate. Punto c. Infine, osservando le restrizioni imposte ai punti precedenti, ossia utilizzando esclusivamente predicati e funzioni ivi definiti, si specifichi il predicato binario reverse(x,y) che indica che la stringa x, letta da sinistra a destra, è uguale alla stringa y letta da destra a sinistra. Ad esempio: reverse(abcd,dcba) è vero reverse(abcd,cba) è falso Se utile, è possibile usare anche i predicati definiti ai punti precedenti. Esercizio 3 (punti 3) E’ decidibile il problema di stabilire se, date due qualunque stringhe ed eventualmente due interi, essi soddisfino i predicati definiti nell’Esercizio 2? Esercizio 4 (punti 4) Qual è la complessità migliore ottenibile da MT a nastro singolo che riconoscano, rispettivamente, i linguaggi L e L1 di cui all’esercizio 1? Giustificare brevemente la risposta. Esercizio 5 (punti 4) Si risolva la seguente equazione alle ricorrenze: T(n) = T(n-1) + n2 Esercizio 6 (punti 7) Scrivere lo pseudocodice di una funzione che, dato un albero binario che rappresenta una espressione aritmetica ne calcoli il valore e lo restituisca in output. Nota: la radice ed i nodi intermedi rappresentano gli operatori, le foglie dell'albero rappresentano gli operandi e la loro chiave ne contiene il valore. Le parentesi non sono rappresentate. Si assuma che l'espressione contenga solo gli operatori aritmetici binari: +, -, *, / e numeri interi. Ad esempio l’espressione ((1+2)*5) è rappresentata dall’albero in figura Tracce delle soluzioni Esercizio 1 L è un linguaggio regolare perché n può assumere solo i valori 1, 2, 3 e poi può seguire un’altra stringa con le stesse caratteristiche; non è quindi necessaria una capacità di conteggio illimitata. Una grammatica regolare che genera L è la seguente, facilmente convertibile in un automa a stati finiti: S -> a A1 | a B1 | a C1 A1 -> b A2 | b A2 -> a A1 B1 -> a B2 B2 -> b B3 B3 -> b B4 | b B4 -> a B1 C1 -> a C2 C2 -> a C3 C3 -> b C4 C4 -> b C5 C5 -> b C6 | b C6 -> a C1 L1 coincide con L perché {(ambm)+, m > 0} evidentemente contiene L; quindi la stessa grammatica e lo stesso automa definiscono L e L1. Esercizio 2 Punto a. x y substring(x,y) p q r (r = concat(p,x) y = concat(r,q)) Punto b. x y i j, substring2(x,y,i,j) p q r (r = concat(p,x) y = concat(r,q) len(p) = i-1 len(x) = j-i+1) Punto c. x y reverse(x,y) (len(x) = len(y) = 0) /* x e y sono entrambe la stringa nulla*/ ((c i substring2(c,x,i,i) substring2(c,y,len(y)-i+1,len(y)-i+1) ) (c i substring2(c,y,i,i) substring2(c,x,len(x)-i+1,len(x)-i+1) )) Una formula alternativa ed equivalente è la seguente: x y reverse(x,y) (len(x) = len(y) = 0) /* x e y sono entrambe la stringa nulla*/ len(y) = len(x) = 1 x = y (z, w, r, q, (x = concat(z,w) (y = concat(r,q)) (len(z) = len(q) 1 len(w) = len(r) 1) (reverse(z,q) reverse(w,r))) Esercizio 3 Evidentemente SI: è molto facile scrivere algoritmi che stabiliscano rispettivamente se due stringhe sono una sottostringa dell’altra, se una stringa è la concatenazione di altre due, o calcolino la concatenazione tra due stringhe, ecc. Esercizio 4 Una MT a nastro singolo estende l’automa a stati finiti che costituisce il suo organo di controllo, quindi può eseguire esattamente le mosse che esegue un automa a stati finiti. Essendo L1 = L un linguaggio regolare, anche la complessità di un MT a nastro singolo che lo riconosca sarà O(n), per la precisione T M(n) = n+1. Esercizio 5 E’ facile sviluppare T(n) in n2 + (n-1)2 + (n-2)2 + (n-3)2 ... + c ossia che è Θ(n3), infatti e Esercizio 6 calcola-valore (tree t) { if t è una foglia return key (t) if key(t) = "+" return (calcola-valore (left(t)) + calcola valore (right(t))) /*nodo intermedio: operatore +*/ if key(t) = "- "return (calcola-valore (left(t)) calcola valore (right(t))) /*nodo intermedio: operatore - */ if key(t) = "*" return (calcola-valore (left(t)) * calcola valore (right(t))) /* nodo intermedio: operatore * */ if e key(t) = "/ "return (calcola-valore (left(t)) / calcola valore (right(t))) /*nodo intermedio: operatore /*/ else return errore “espressione mal formata" } . Algoritmi e Principi dell'Informatica Prima Prova in Itinere 25 Novembre 2014 Il tempo a disposizione è di 1 ora e 45 minuti. Esercizio 1 (punti 6/15 senza la parte facoltativa, 9 con la parte facoltativa) Si ricordi che la stringa inversa di una generica stringa w, qui denotata wR, è ottenuta da w scrivendo i suoi caratteri in ordine inverso, ad esempio abaabbR = bbaaba, aaabbbR = bbbaaa. L’operazione di inversione viene estesa dalle stringhe ai linguaggi nel modo naturale: LR = {wR | w L } Si dica, con brevi spiegazioni, quali delle seguenti famiglie di linguaggi sono chiuse rispetto all’operazione di inversione: Il linguaggi regolari I linguaggi non contestuali I linguaggi generati da grammatiche non ristrette (Parte facoltativa) I linguaggi non contestuali deterministici NB: la parte facoltativa verrà valutata solo se nelle restanti parti si saranno ottenuti almeno 5 punti. Esercizio 2 (punti 7/15) Due macchine di Turing (MT) si dicono isomorfe se: hanno lo stesso numero di nastri; ad ogni mossa spostano le rispettive testine del nastro i-esimo alla stessa maniera (entrambe a destra o entrambe a sinistra o lasciano entrambe ferme); Si noti che di conseguenza due MT isomorfe usano esattamente le stesse celle di memoria. E' decidibile il fatto che due qualsiasi MT isomorfe siano equivalenti, ossia calcolino la stessa funzione o riconoscano lo stesso linguaggio? Giustificare brevemente la risposta Esercizio 3 (punti 5/15) Specificare in logica del prim’ordine il linguaggio L1 = { anbncn | n0 }. Nella specifica si possono usare esclusivamente i seguenti predicati e funzioni: il predicato di appartenenza insiemistica: il predicato di uguaglianza: = la funzione di concatenazione: le costanti dei caratteri alfabetici a, b, c e la stringa vuota il simbolo L1 per riferirsi al linguaggio da specificare (più eventuali altri simboli L2, L3, … per eventuali linguaggi intermedi) Non si può quindi utilizzare la funzione di elevamento a potenza. Tracce di soluzioni Esercizio 1 Data una grammatica G non-contestuale che genera il linguaggio L, la grammatica GR ottenuta trasformando ogni produzione di G, A , nella produzione A R, genera evidentemente LR. In particolare, se G è anche regolare, ogni produzione del tipo A Ba viene trasformata in A aB ottenendo quindi una grammatica che genera LR e soddisfa ancora la definizione di grammatica regolare (è noto infatti che le grammatiche lineari a sinistra o lineari a destra sono tra loro equivalenti e generano entrambe tutti e solo i linguaggi regolari). Anche i linguaggi generati da grammatiche non ristrette sono chiusi rispetto all’inversione; infatti queste grammatiche sono equivalenti alle macchine di Turing. Data quindi una MT che riconosca L basta costruirne una che inverta la stringa di ingresso in un nastro ausiliario e successivamente simuli il comportamento della MT originaria usando il nastro ausiliario al posto del nastro di ingresso. (Parte facoltativa) I linguaggi non contestuali deterministici non sono invece chiusi rispetto all’inversione. Ciò si può dedurre ricordando che L = {anbn} {anb2n} è nondeterministico e osservando invece che L1 = {1anbn} {0anb2n} è deterministico (la lettrura del primo simbolo permette di stabilire subito se si dovranno contare 2 b per ogni a oppure un solo b). L1R però non è deterministico perché a inizio stringa non è possibile stabilire quale sarà il rapporto corretto tra il numero di b e quello di a. Esercizio 2 Il problema non è decidibile: ogni coppia di MT può essere trasformata in una coppia equivalente che soddisfi la proprietà indicata: basta arricchire l’una con la memoria e il controllo dell’altra (che poi non verranno utilizzati per la computazione “vera”): quindi, date due MT con k1 e k2 nastri rispettivamente se ne costruiscono altre due, entrambe di k1 + k2 nastri, rispettivamente equivalenti alle originarie. Perciò se fosse possibile decidere l'equivalenza delle due nuove MT sarebbe decidibile anche l’equivalenza tra due MT generiche. Precisazione Occorrerebbe anche precisare che, in conseguenza della definizione data, due MT isomorfe o terninano entrambe per lo stesso input o non terminano entrambe. Perciò, per valutare l’equivalenza tra due MT generiche trasformandole in MT isomorfe, a rigore occorrerebbe cambiare anche la regola che ne definisce l’accettazione di una stringa: la stringa è accettata se la MT raggiunge uno stato di accettazione (o scrive un messaggio di accettazione sul nastro di uscita) anche in caso di eventuale computazione che dopo aver raggiunto tale stato proceda all’infinito. In questo modo Si possono ottenere due MT MT1’ e MT2’ isomorfe a MT1 e MT2 tali che MT1’ accetta tutte e sole le stringhe accettate da MT1 e similmente per MT2. Tuttavia se una tra MT1 e MT2 non termina entrambe MT1’ e MT2’ non terminano ma segnalano in tempo finito l’eventuale accettazione. Si sottolinea che questo tipo di precisazine non è stato considerato parte necessaria della soluzione che invece è ritenuta valida anche in sua assenza. Esercizio 3 x( xL1 x = yzw x = yzw yz L2 zw L3 y L4 z L5 w L6 ) x( xL2 x = y x = ayb y L2 ) x( xL3 x = y x = byc y L3 ) x( xL4 x = y x = ay y L4 ) x( xL5 x = y x = by y L5 ) x( xL6 x = y x = cy y L6 ) Algoritmi e Principi dell'Informatica Seconda Prova in Itinere 13 Febbraio 2015 Avvisi importanti Il tempo a disposizione è di 1 ora e 45 minuti. Esercizio 1 (punti 5/15-esimi) Si calcoli la complessità del seguente frammento di codice che definisce l’“ossatura” di una funzione f applicata a un array A: f(A): n := A.length i := 1 altre eventuali inizializzazioni eseguite in tempo costante while i < n do_something_in_tempo_costante i := i*2 f(A[1..n/3]) f(A[n/3+1..(2/3)*n]) j := 2 while j < n*n do_something_in_tempo_costante j := j*j return result Esercizio 2 (punti 7/15-esimi) Si consideri un albero rosso-nero di altezza nera bh e costituito da soli nodi neri. 1. Quali sono, rispettivamente, il numero minimo e massimo di nodi contenuti nell’albero? (si precisi se nel conto viene incluso il nodo T.NIL o no). 2. E’ possibile ottenere da esso un nuovo albero rosso-nero costituito da soli nodi neri applicandovi esclusivamente operazioni di inserimento di nuovi nodi? In caso positivo in che modo? (eventualmente illustrandolo mediante un semplice esempio). 3. Qual è il numero massimo di nuovi nodi che si possono inserire in esso senza effettuare cancellazioni e senza alterare bh? Si forniscano brevi ma chiare spiegazioni per le risposte date. Esercizio 3 (punti 7/15-esimi) Sia dato un grafo G e due sottoinsiemi dei suoi vertici, V1 e V2. La distanza tra V1 e V2, d(V1, V2), è la distanza minima tra un nodo appartenente a V1 e un nodo appartenente a V2. Se V1 e V2 non sono disgiunti allora la loro distanza è uguale 0. Si specifichi un algoritmo che, a partire da un grafo G e da due suoi sottoinsiemi V1 e V2, calcoli la distanza tra V1 e V2; se ne discuta quindi la complessità. La valutazione dell’algoritmo proposto dipenderà ovviamente dalla sua complessità. N.B.: Si può assumere che esista una funzione che in tempo costante determini l’appartenenza di un vertice a uno dei due insiemi. Tracce di soluzioni Esercizio 1 Lo pseudocodice ricorsivo dell’esercizio ha una funzione di complessità definita da una ricorrenza del tipo T(n) = 2T(n/3) + log(n) + log(log(n)) che si risolve mediante il master theorem ottenendo una funzione (nlog3(2)). Esercizio 2 Risposte 1. Posto che l’altezza nera si calcola contando il numero di nodi neri tra la radice, esclusa, e la foglia T.NIL, compresa e posto che ogni “cammino nero” dalla radice a T.NIL deve avere la stessa lunghezza, un albero rosso-nero di soli nodi neri è necessariamente perfettamente bh1 bilanciato; quindi il numero di nodi interni è 2 i 2 bh 1 cui va aggiunto l’unico T.NIL e i 0 il numero, sia minimo che massimo, di nodi totale è 2bh. 2. Ogni nodo nuovo viene inserito con colore rosso; successivamente la procedura di FIXUP lascia in ogni caso almeno un nodo rosso. Quindi non è possibile ottenere alberi interamente neri esclusivamente mediante inserimenti (a meno che l’albero non consista nella sola radice). 3. Se l’albero è inizialmente costituito da soli nodi neri si possono inserire nuovi nodi senza alterarne la bh, quindi necessariamente rossi, fino al massimo a raddoppiarne l’altezza: h = 2.bh. Ciò può essere ottenuto anche eseguendo solo inserimenti: ad esempio l’albero di figura a può essere trasformato in quello di figura b eseguendo nell’ordine l’inserimento dei nodi 3, 7, 12, 20, 1. 4. 6. 8, 11, 13, 16, 22. 10 10 5 5 15 T.NIL 3 1 4 ….. Figura a 15 7 6 20 12 8 T.NIL 11 ….. Figura b 13 16 22 Legenda: i nodi quadrati rappresentano nodi neri; quelli tondi nodi rossi. Quindi il numero totale di nodi (compreso T.NIL) del nuovo albero di altezza 2.bh è 22bh e il numero massimo di nodi inseribili è 22bh - 2bh . Esercizio 3 È possibile effettuare una visita BFS a partire da ogni nodo in V1. |V1| = O(n); quindi si eseguono O(n) visite, ognuna di costo O(m + n). Tale soluzione ha complessità O(n(m+ n)). Una soluzione migliore consiste nel modificare la BFS in modo che tutti i nodi u in V1 siano inseriti subito nella coda e la loro distanza, u.dist, sia posta a 0. L’algoritmo analizza quindi tutti i nodi adiacenti ai nodi in V1 che non appartengono a V1, li inserisce nella coda e pone la loro distanza uguale a 1. Se tra questi nodi è incluso un nodo di V2, l’algoritmo termina restituendo 1 (la distanza calcolata). Altrimenti, si procede con l’estrazione dalla coda dei nodi a distanza 1 e con l’inserimento di tutti i nodi a distanza 2 da V1. Vengono cosi progressivamente individuati tutti i nodi a distanza crescente dai nodi in V1. Per come è definita la BFS, il primo nodo in V2 che si incontra durante la visita avrà distanza minima e tale distanza potrà essere restituita dall’algoritmo come valore di ritorno. Se la visita non trova alcun nodo dell’insieme V2, allora V2 non è raggiungibile da V1; quindi l’algoritmo restituisce un valore opportuno (per es., ∞). Essendo basto su una visita BFS, l’algoritmo ha complessità O(m + n). Algoritmi e principi dell’Informatica Recupero prima prova in itinere - 13 Febbraio 2015 Avvisi importanti La prova è riservata ai laureandi che non abbiano superato la prima prova in itinere. Chi sostiene questa prova di recupero non potrà iscriversi al II appello di questa sessione. La durata della prova di recupero è di 1 ora Esercizio 1 (punti 6) Si consideri il predicato binario estensionale segment(a,b), da non definirsi ulteriormente, che indica la presenza di un segmento sulla retta reale, dal punto con coordinata a al punto con coordinata b. Si specifichi in logica del prim’ordine il predicato binario coalescedSegment(x,y) che indica che ogni punto sulla retta compreso tra il punto di coordinata x e il punto di coordinata y appartiene a un qualche segmento specificato tramite il predicato segment. A titolo esemplificativo, la figura rappresenta il caso in cui valgano le formule seguenti: segment(t1,t3) segment(t2,t4) segment(t4,t5) segment(t6,t7). Si può allora ad esempio evincere che valga anche la formula: coalescedSegment(t1,t5). Esercizio 2 /punti 5) Si consideri il linguaggio definito sull’alfabeto {a, b, c}dalla formula seguente: L = ({abb}+. (({baba}*- {bababa}+) {c}*.{ab}+.c+) {a}*.{b}*.{cabc}*) Si dica, spiegando berevemente la risposta quale è il formalismo a potenza minima (generativa se trattasi di grammatica, riconoscitiva se trattasi di automa o in generale macchina a stati) in grado di definire il linguaggio L. NB: non è richiesto di costruire la grammatica e/o l’automa che definisce L, bensì solo di indicare a quale famiglia, a potenza minima, esso/a appartenga. Si rammenti che i simboli utilizzati nella formula indicano rispettivamente: *: la chiusura riflessiva e transitiva (operatore “stella di Kleene”) +: la chiusura transitiva, non riflessiva -: la differenza insiemistica : l’unione insiemistica : l’intersezione insiemistica .: la concatenazione tra linguaggi Esercizio 3 (punti 4) Si consideri il linguaggio L definito nell’Esercizio 2: è decidibile il problema di stabilire se una generica macchina di Turing riconosce L? Spiegare brevemente la risposta. Tracce delle soluzioni Esercizio 1 xy coalescedSegment(x,y) wz segment(w,z) wx zx (zy coalescedSegment(z,y)) Esercizio 2 I linguaggi regolari sono chiusi rispetto a tutte le operazioni utilizzate nella formula che definisce L. Siccome esse sono applicate a partire da singoli caratteri dell’alfabeto, che sono casi particolari di linguaggi regolari, l’espressione complessiva definisce un linguaggio regolare, riconoscibile quindi da un automa a stati finiti. Esercizio 3 Il problema di stabilire se una generica MT riconosca L è evidentemente indecidibile, poiché il riconoscimento di L può essere descritto come la funzione fL(x) = 1 se x L, 0 se x L Per il teorema di Rice non è quindi possibile stabilire se una generica MT calcola una funzione fissata, o, equivalentemente, riconosce un linguaggio fissato. Algoritmi e Principi dell’Informatica Appello del 2 Marzo 2015 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 8) Una macchina di Turing si dice n-generatrice se, quando riceve 0 in ingresso, termina entro n+1 passi scrivendo il numero n in uscita (n0). Fissata una qualsiasi enumerazione algoritmica E delle macchine di Turing, il generatore minimo di un numero n, indicato con gm(n), è il più piccolo indice, secondo E, di macchina di Turing ngeneratrice. Si risponda alle seguenti domande fornendo brevi ma chiare spiegazioni per le risposte date: a) La funzione gm è totale? b) La funzione gm è computabile? Esercizio 2 (punti 9) Si consideri il seguente linguaggio: L = {anb3n | n ≥ 0} {an(bbbc)n | n ≥ 0} Si forniscano: a) Una grammatica, preferibilmente a potenza generativa minima, che generi L b) Un automa, preferibilmente a potenza minima tra le famiglie tradizionali a stati finiti, a pila (deterministici o no), macchine di Turing, che riconosca L c) Una rete di Petri che riconosca L Esercizio 3 (punti 9) Si consideri il seguente linguaggio: L={ | 1 ≤ k ≤ 100, ∀ 1 ≤ i ≤ k.(ni ≥ 1), 1 ≤ i < j ≤ k.(ni = nj)} Si descrivano a grandi linee, ma in maniera sufficientemente precisa, una MT e una RAM che riconoscano L e se ne valutino le complessità temporali, nel caso della RAM sia a criterio di costo costante che a criterio logaritmico. Sono ovviamente preferite soluzioni a minor complessità per entrambi i tipi di macchina. Esercizio 4 (punti 8) 1. Si scriva un algoritmo che, data in input una sequenza P contenente i dati anagrafici di diverse persone, determina se nella sequenza ci sono 2 persone che compiono gli anni lo stesso giorno dell’anno. Si assuma pure che i dati di ogni persona siano rappresentati da un oggetto che ha diversi attributi, nome, indirizzo, codice_fiscale, data_nascita, e che la data di nascita a sua volta sia un oggetto con 3 attributi, giorno, mese, anno (per cui se p è il riferimento ad una persona, p.data_nascita è la sua data di nascita, e p.data_nascita.giorno è il giorno del mese in cui la persona è nata). Si dia la complessità temporale asintotica dell’algoritmo scritto nel caso pessimo. 2. Come al punto 1: Come cambia, se cambia, la complessità dell’algoritmo se, sapendo che tutte le persone della sequenza P sono nate nel XX secolo, occorre determinare se nella sequenza P ci sono 2 persone nate esattamente lo stesso giorno? 3. Come cambia, se cambia, la complessità dell’algoritmo se, sapendo che tutte le persone della sequenza P sono viventi, occorre determinare se nella sequenza P ci sono 2 persone nate esattamente lo stesso giorno? NB: Il punteggio dato sarà tanto maggiore quanto migliore è la complessità degli algoritmi scritti. Tracce delle soluzioni Esercizio 1 a) La funzione è certamente totale, in quanto, per qualunque numero n, si può facilmente costruire una macchina di Turing n-generatrice. Basta, infatti, compiere un passo di stampa per ogni cifra di n (per un totale di un passo se n=0 e di log2 n+1 passi se n>0, quindi sempre entro n+1 passi). Tale macchina potrebbe non essere la n-generatrice con l’indice più piccolo, ma la sua esistenza implica che la funzione gm è definita nel punto n. b) Sì. Infatti, per quanto osservato al punto a), si può facilmente trovare un limite superiore al valore di gm(n). A tale scopo, sia i l’indice della macchina esibita al punto a). Basta a questo punto, mediante una macchina di Turing universale, testare, in successione, ciascuna delle macchine di Turing con indice da 0 a i per n+1 passi a fronte dell’ingresso 0: il primo indice per il quale la macchina termina e produce n in uscita è il valore gm(n) cercato. Esercizio 2 Punto a. S→X|Y| X → aXbbb | abbb Y → aYbbbc | abbbc Punto b. Un automa a pila deterministico A che riconosca L può essere costruito secondo le linee seguenti: 1. A impila gli n a (ponendo lo stato iniziale tra quelli finali, accetta anche la stringa vuota); 2. Al ricevimento del primo b ne conta altri due; 3. Dopo aver letto i primi 3 b, si sposta in due stati diversi a seconda che il carattere successivo sia b o c (e ovviamente va in uno stato di errore se non siverifica nessuna delle circostanze previste) 4. Da questo punto in poi verifica che per ogni a impilato si trovino 3 b oppure 3 b seguite da c a seconda dello stato scelto al punto precedente. Punto c. La rete di Petri seguente (con la relativa marcatura iniziale) riconosce L quando viene a trovarsi con tutti i posti vuoti. Esercizio 3 Soluzione mediante MT Grazie al fatto che il parametro k è limitato e ≤ 100 è possibile progettare diverse MT che riconoscano L con complessità temporale O(n). Un primo modo consiste nel costruire una MT con 100 nastri di memoria: ogni sequenza ani viene memorizzata su un nastro diverso; successivamente tutte le testine vengono riposizionate sulla prima cella dei rispettivi nastri e vengono spostate di una posizione a destra contemporaneamente: se due di essere giungono alla fine della propria sottostringa contemporaneamente (ciò può essere verificato mediante la funzione della macchina che produce uno stato di accettazione se due testine leggono contemporaneamente una marca di fine stringa) la stringa originaria viene accettata. Una MT con meno nastri invece memorizza la stringa in ingresso in due nastri di memoria e, per ogni frammento di un nastro verifica se sull’altro nastro ne esiste un altro con lo stesso numero di a. Si noti che per evitare di considerare il caso ni = nj quando i = j può essere opportuno marcare in qualche modo la porzione di nastro sotto esame, e.g. sostituendo la b iniziale con un altro carattere. La MT prende in considerazione il primo gruppo dal primo nastro e scorre il secondo nastro per verificare se esiste un altro gruppo con lo stesso numero di a (per fare questo deve fare k volte andata e ritorno nello scorrimento di impiegando un tempo 2.k.n1+ n; il processo viene ripetuto per tutti gli volte; si ha quindi una complessità quadratica in k ma ancora lineare in O(n). del primo nastro ossia k Una MT più sofisticata potrebbe memorizzare soltanto i numeri ni codificandoli in binario e poi verificare l’esistenza di coppie di valori uguali alla stessa maniera. La prima fase richiede un tempo O(n log(n)) = (un’analisi più attenta però mostra che il tempo necessario è addirittura O(n)); essendo il risultato della prima fase O(log(n)), la seconda può poi essere completata in tempo O(k2log(n)). Soluzione mediante RAM Una RAM può procedere con uno schema algoritmico uguale a quello utilizzato per la terza MT descritta sopra. A criterio di costo costante ciò richiede O(n) per la prima fase e O(k 2) per la seconda; essendo k ≤ 100, il costo totale è O(n). A criterio di costo logaritmico invece la prima fase costa O(n.log(n)) ma la seconda O((k 2.log(n))) ossia ancora O(log(n)), comunque dominata dalla fase precedente. Esercizio 4 1. In alternativa al confronto tra tutti gli elementi della sequenza (complessità Θ(n 2), n = lunghezza della sequenza P) è possibile usare un vettore di appoggio di dimensione pari al numero di giorni dell’anno (365) e conteggiare così la frequenza in P di ogni singolo giorno dell’anno. Questa soluzione avrebbe complessità temporale Θ(n). L’uso del vettore di appoggio comporta un incremento costante, quindi trascurabile, della complessità spaziale. È possibile tuttavia considerare che, poiché al massimo ci sono 356 giorni in un anno (contando la possibilità di anni bisestili), se l’array P è più lungo di 356 elementi di sicuro ci sono almeno 2 persone che compiono gli anni lo stesso giorno. Se ce ne sono meno di 356, è accettabile anche eseguire un doppio ciclo for, in quanto comunque il ciclo è ripetuto un numero limitato di volte. stesso_compleanno (P) 1 if P.length > 356 2 return true 3 for i := 1 to P.length -1 4 for j := i+1 to P.length 5 if P[i].data_nascita.giorno = P[j].data_nascita.giorno and P[i].data_nascita.mese = P[j].data_nascita.mese 6 return true 7 return false Ognuno dei 2 cicli annidati 3-4 viene eseguito al più 356 volte, quindi la complessità dell’algoritmo è Θ(1). 2. Anche in questo caso se P contiene più elementi di un certo numero K costante fissato di sicuro ci sono 2 persone che sono nate lo stesso giorno. In questo caso K = 356*100 (il valore è anche minore, in quanto non tutti gli anni sono bisestili, ma non cambia niente dal punto di vista della complessità), quindi alla riga 1 occorre cambiare 356 in 35600, ma comunque la complessità rimane costante (e aggiungere il controllo sull’anno alla riga 5). 3. In questo caso, considerando che un uomo non vive fino a 130 anni, basta prendere K=356*130, ed il ragionamento del punto 2 rimane invariato. (Si noti che non cambia nulla se, per stare larghi, si prende K=356*200). Algoritmi e Principi dell’Informatica Appello del 6 Luglio 2015 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 9) Punto a) Si scriva una grammatica che generi il linguaggio L1 composto da stringhe sull’alfabeto = {(, ),]}, tali che le parentesi tonde siano bilanciate — ossia ben parentetizzate —, con la variante che la parentesi quadra può bilanciare un numero arbitrario (non nullo) di parentesi tonde aperte. Ad esempio, le stringhe (()()), ((())), ((()(](()] appartengono al linguaggio, mentre le stringhe ((), ((((](, ]()() non vi appartengono. Si scriva una grammatica, preferibilmente a potenza minima che produca il linguaggio L1. In alternativa è possibile costruire un automa, sempre a potenza minima, che riconosca lo stesso linguaggio; ciò però comporta una diminuzione del punteggio ottenibile di 2 punti. Punto b) E' vero che se un linguaggio L non è regolare allora neanche il suo complemento Lc è regolare? Perché? Punto c) E' vero che se un linguaggio L non è libero dal contesto allora neanche il suo complemento Lc è libero dal contesto? Perché? Esercizio 2 (punti 7) Si consideri l’insieme S delle stringhe costituite da caratteri appartenenti a due alfabeti disgiunti, A1 e A2. Si formalizzi, mediante una formula del prim’ordine, il predicato unario proprietà, che indica che il suo argomento appartiene al sottoinsieme di S costituito da stringhe in cui non compaiano due caratteri consecutivi appartenenti ad A1. Ad esempio, se i caratteri di A1 sono lettere maiuscole e quelli di A2 lettere minuscole, le seguenti stringhe soddisfano la proprietà suddetta: AbcDghm, cvHmUnI, , F, … mentre le seguenti non la soddisfano: AA, aGnnHH, … NB: La formula deve far uso esclusivamente dei simboli seguenti: Quantificatori e connettivi logici proposizionali Il simbolo di appartenenza Simboli di variabile i cui domini siano insiemi di stringhe o insiemi di caratteri I simboli di costante A1 e A2 rappresentanti i due alfabeti Il simbolo ‘’ che denota l’operazione di concatenazione, applicabile a stringhe e a caratteri. Esercizio 3 (punti 6) Si immagini di voler ordinare un array di n elementi mediante l’algoritmo Quicksort. Si immagini inoltre che l’array in input sia tale per cui l’operazione di partizione sposti il pivot in posizione n – k, k essendo una costante indipendente da n, e si assuma che lo stesso effetto si ripresenti nella successiva partizione della porzione di array di lunghezza n – k -1; e così via finché la cardinalità della porzione considerata non diventa <= k. Sulla base delle suddette informazioni, è possibile determinare l’ordine di grandezza della complessità temporale dell’esecuzione di Quicksort su un tale array? In caso positivo, quale sarebbe l’ordine di grandezza? Esercizio 4 (punti 11) Sia L una lista semplice (cioè con puntatori solo all’elemento successivo) contenente n interi positivi memorizzati in ordine strettamente crescente. Si consideri il problema di trovare due puntatori a due elementi di L, i, e j, se esistono, tali che la somma degli elementi di L compresi tra i e j, estremi inclusi, sia uguale a un valor dato X. Si descriva un algoritmo, mediante opportuno pseudocodice, per risolvere il problema (ossia stabilire se tali i, j esistono e nel caso produrli in uscita) e se ne valuti la complessità asintotica. NB: la complessità dell’algoritmo, ovviamente, influenza la valutazione della qualità dell’algoritmo prodotto. Soluzioni schematiche Esercizio 1 Punto a) Una grammatica noncontestuale è necessaria e sufficiente per generare L1; ad esempio la seguente: S → BS | N]S | B → BB | (B) | N → NN | (N | (B Punto b) Vero. Supponiamo per assurdo che Lc sia regolare. Allora grazie alla chiusura dei linguaggi regolari rispetto alla complementazione, anche il complemento di Lc dev'essere regolare. Ma il complemento di Lc è L, che per ipotesi non è regolare. Assurdo. Punto c) Falso. Un esempio di linguaggio non libero dal contesto è L={anbncn}, non riconoscibile da nessun (ND)PDA. Il suo complemento è invece libero dal contesto. Si tratta infatti del linguaggio le cui stringhe o sono del tipo anbmcl con n≠m o n≠l oppure non sono del tipo a*b*c*. Chiamiamo L1={ anbmcl | n≠m o n≠l } e L2=a*b*c* e sia L2c il complemento di L2. In sostanza, Lc è dato dall'unione di L1 e L2c, che sono entrambi liberi dal contesto. Infatti, per riconoscere L1 basta un NDPDA, mentre notiamo che L2 è un linguaggio regolare, e quindi anche il suo complemento L2c è regolare (e quindi anche libero dal contesto). Esercizio 2 x proprietà(x) y, z, c1, c2(c1 A1 c2 A1 x = y c1 c2 z) Esercizio 3 L’equazione alle differenze in questo caso è la seguente T(n) = T(k) + T(n-k) + Θ(n) laddove T(k) = O(1), in quanto per ordinare un array di dimensione fissata k serve un tempo costante, quindi la soluzione O(n2) Esercizio 4 FIND_SUM(L,X) 1 j := L.head 2 i := L.head 3 sum := j.key 4 while i ≠ j.next and j ≠ NIL and sum ≠ X 5 if sum < X 6 j := j.next 7 sum := sum + j.key 8 else 9 sum := sum – i.key 10 i := i.next 11 if sum = X 12 return (i, j) 13 else 14 return false La complessità asintotica dell’algoritmo è chiaramente O(n) poiché i e j scorrono la lista una sola volta. Algoritmi e Principi dell’Informatica Appello del 16 Luglio 2015 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (punti 8) Scrivere una grammatica a potenza minima che generi il linguaggio { anbmcl | n≠m o n≠l } In alternativa è possibile costruire un automa, sempre a potenza minima, che riconosca lo stesso linguaggio; ciò però comporta una diminuzione del punteggio ottenibile di 2 punti. Esercizio 2 (punti 8) Parte a È decidibile stabilire se una macchina di Turing M entra più di una volta in un qualche stato dell’organo di controllo quando riceve in input una stringa w? In altre parole: Indicata con <M> la codifica di una MT M e con <w> quella di una stringa sull’alfabeto di input di M, si dica se è computabile la funzione F(<M>, <w>) = 1, se quando M opera su w esistono due configurazioni di M con lo stesso stato dell’organo di controllo 0 altrimenti Parte b È decidibile stabilire se una macchina di Turing M (con un unico stato iniziale dell’organo di controllo) entra più di una volta nello stato iniziale dell'organo di controllo quando riceve in input una stringa w? In altre parole: Indicata con <M> la codifica di una MT M, con <w> quella di una stringa sull'alfabeto di input di M e con q0 lo stato iniziale dell'organo di controllo di M, si dica se è computabile la funzione F(<M>, <w>) = 1, se quando M opera su w esistono due configurazioni di M in cui lo stato dell’organo di controllo è q0 0 altrimenti Giustificare brevemente le risposte date. Esercizio 3 (punti 10) Dato un albero binario di ricerca T, i cui nodi memorizzano una variabile che ne rappresenta il colore, si vuole determinare se T è un albero Rosso-Nero. Si definisca un algoritmo che risolva questo problema e se ne discuta la complessità. Esercizio 4 (punti 5) Parte a Si consideri una tabella hash, con m = 10 posizioni, le cui chiavi sono interi non negativi. La tabella è gestita mediante indirizzamento aperto. Data la funzione hash: h(k ,i) = (k +2×i) mod m si discuta la bontà di h(k,i) rispetto alle sequenze di ispezione che essa genera nella tabella considerata. Parte b Si consideri una generica tabella hash con m posizioni e fattore di carico = 1/2. Si considerino i due casi di tabella con liste concatenate e di tabella aperta: qual è, nel caso pessimo, il tempo necessario (è sufficiente l’ordine di grandezza) per la ricerca e l’inserimento di un elemento in tabella nei due casi? Giustificare brevemente la risposta. Soluzioni schematiche Esercizio 1 S -> A | B (A è il sottolinguaggio con n≠m, B quello con n≠l) A -> A1 A2 C0 | A2 B1 C0 (sottolinguaggio con n≠m. due modi per farlo: 1) ho più a che b e quindi ho un prefisso non vuoto di a (A1) seguito da a e b bilanciate (A2), seguite da c arbitrarie (C0) 2) ho meno a che b e quindi ho a e b bilanciate (A2) seguite da un prefisso non vuoto di b (B1) seguito da c arbitrarie (C0)) A2 -> a A2 b | ε B -> A1 B2 | B2 C1 (sottolinguaggio con n≠l. due modi per farlo: 1) ho più a che c e quindi ho un prefisso non vuoto di a (A1) seguito da a e c bilanciate con in mezzo delle b arbitrarie (B2) 2) ho meno a che c e quindi ho a e c bilanciate con in mezzo delle b arbitrarie (B2) seguite da un prefisso non vuoto di c (C1)) B2 -> aB2c | B0 (a e c bilanciate con in mezzo delle b arbitrarie (B0)) A1 -> a A1 | a B1 -> b B1 | b C1 -> c C1 | c B0 -> B1 | ε C0 -> C1 | ε Esercizio 2 Parte a Il problema è decidibile. Mentre le possibili configurazioni di una MT sono infinite, gli stati dell'organo di controllo sono finiti (indichiamoli con QM). Basta infatti simulare al più |QM| + 1 passi dell'esecuzione di M su w e verificare se uno stato è visitato almeno due volte (NB: l'esecuzione di M su w potrebbe non terminare, e potrebbe anche darsi che la testina di lettura di M non legga alcun carattere di w). Parte b Il problema non è decidibile. Infatti si può ridurre ad esso il problema dell’arresto di una TM nel modo seguente: data M, costruisco una la macchina M' ottenuta aggiungendo a M un nuovo stato iniziale q0’, e una transizione iniziale che porta da q0’ a q0 senza fare nient’altro; aggiungo poi delle transizioni che da ogni stato finale di M portano a q0’ e fermano la macchina; l'unico stato finale di M' è q0’. Chiaramente M e M' riconoscono lo stesso linguaggio e M accetta una stringa, ossia si ferma, se e solo se M’ raggiunge il suo stato iniziale più di una volta. Esercizio 3 L’algoritmo seguente verifica che le proprietà degli alberi Rosso-Neri siano rispettate: verifica che la radice sia nera, quindi richiama una funzione che ricorsivamente analizza i sottolaberi per calcolarne l’altezza nera e controllare che i figli dei nodi rossi siano neri. La complessità è proporzionale al numero di nodi dell’albero. checkRB (Tree T) { if (T.color=RED) return FALSE (bh, RB) <-- checkSubTree(T, 0); /*bh = altezza nera del sottoalbero T; RB = valore di verità per le proprietà RB */ return RB; } checkSubTree(Tree T, int bh) { if (T=NIL) return (bh, TRUE) if ((T.color = RED) AND (T.left.color = RED OR T.right.color = RED)) return (bh, FALSE) if (T.color = BLACK) bh = bh+1 (bh_left, RBleft) = checkSubTree(T.left, bh) (bh_right, RBright) = checkSubTree(T.right, bh) if not (RBleft AND RBright) return (bh, FALSE) if (bh_left != bh_right) return (bh, FALSE) return (bh_left, TRUE) } Esercizio 4 Parte a Visto che m è pari, le sequenze di ispezione generate visitano solo le posizioni pari o solo quelle dispari (dipende dalla prima posizione visitata). Se m fosse dispari, la funzione permetterebbe invece di ispezionare tutti gli elementi della tabella. Parte b In entrambi i tipi di tabella il caso pessimo produce n/2 conflitti sulla stessa posizione determinando quindi un tempo di ricerca O(n) in ambo i tipi di tabella; se si vogliono evitare occorrenze ripetute è necessario comunque anche scandire l’intera lista sia nel caso di tabella aperta che di tabella con liste concatenate. Quindi il tempo di ricerca e inserimento nel caso pessimo è comunque O(n). Algoritmi e Principi dell’Informatica Appello del 2 Settembre 2015 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (Punti 8) Si considerino i linguaggi seguenti: L1 = { z {a,b,c}* | x (y (z = x.y) (#a(x) #b(x) #c(x)) (#a(x) - #b(x) 2) } L2 = { z {a,b,c}* | x (y (z = x.y) (#a(x) #b(x) #c(x)) (#b(x) - #c(x) 2) } L3 = { z {a,b,c}* | x (y (z = x.y) (#a(x) #b(x) #c(x)) (#a(x) - #c(x) 2) } dove, per un carattere e una stringa x, l’espressione #(x) denota il numero di volte in cui il carattere si ripete nella stringa x. Ad es. #a(ababaccc) = 3. Si costruisca una macchina astratta che riconosca L = L1 L2 L3. Tra le diverse macchine astratte che riconoscono L sono preferite macchine “a potenza minima” ossia appartenenti alla categoria di automi a minor potenza riconoscitiva possibile. Esercizio 2 (9 punti) Sia d : N × N N la biiezione tra N e N × N definita come segue: d(x,y) = (x+y)(x+y+1)/2 + x Si considerino i seguenti insiemi: S1 = { d(x,y) | fx(y) } S2 = { x | fx(0) } S3(k) = { x | fk(x) }, dove k è un parametro. Per ciascuno dei predetti insiemi, si dica se esso è ricorsivo, motivando brevemente la risposta. Esercizio 3 (8 punti) Si definisca un algoritmo per determinare se due alberi binari di ricerca T1 e T2 sono uguali sia per il valore delle chiavi sia per la struttura. Valutare la complessità dell’algoritmo definito. Esercizio 4 (punti 8) Si consideri il seguente insieme di numeri interi: {5, 60, 18, 23, 10, 15}. Si individui una sequenza di inserimenti (senza cancellazioni) di questi valori come chiavi di un albero r-b (rosso-nero) inizialmente vuoto in modo che l’albero risultante abbia altezza complessiva doppia dell’altezza nera. Si ricorda che per convenzione la radice di un sottoalbero non viene computata nell’altezza (né nera né complessiva) mentre le foglie ( i nodi T-NIL, neri) vengono computate. Si mostri il risultato finale ottenuto dopo i vari inserimenti e almeno un risultato intermedio, ad esempio dopo l’inserimento dalla prima metà dei dati. Tracce delle soluzioni Esercizio 1 Poiché la differenza tra il numero di a, b e c in ogni prefisso delle stringhe del linguaggio è limitata, un automa a stati finiti è sufficiente per riconoscere il linguaggio: a #a = #b+1 = #c+1 c b #a = #b = #c #a = #b+2 = #c+2 a b #a = #b = #c+1 a c c #a = #b+1 = #c+2 b #a = #b = #c+2 q0 = #a = #b = #c F=Q Esercizio 2 S1 non è ricorsivo. Infatti la funzione d stabilisce banalmente una biiezione tra N e NxN, e se si potesse stabilire l’insieme delle coppie di numeri (x,y) tali per cui fx(y) allora il problema dell’arresto risulterebbe decidibile, il che è assurdo. S2 non è ricorsivo. Sia F l’insieme di funzioni calcolabili definite nel punto 0; tale insieme non è né l’insieme di tutte le funzioni computabili, né l’insieme vuoto. L’insieme S2 di indici delle macchine di Turing che calcolino funzioni in F non è pertanto ricorsivo per il teorema di Rice. La ricorsività di S3(k) dipende da k. Per alcuni valori di k si sa esattamente per quali valori di ingresso x la funzione fk(x) è definita. Ad esempio, se fk(x) fosse la funzione x2, si saprebbe che è definita sempre e quindi il problema sarebbe decidibile (e deciso). Per altri valori di k, invece, il problema è indecidibile. Se, ad esempio, fk(x) fosse la funzione fx(0), tale funzione sarebbe certamente calcolabile, ma, come ad esempio osservato al punto b), non se ne potrebbe stabilire l’insieme di definizione. Esercizio 3 È possibile definire un algoritmo ricorsivo che, dopo aver verificato che le radici degli alberi non sono nulle e che le chiavi sono uguali, visita ricorsivamente il sottoalbero sinistro e quello destro e restituisce valore false se una delle condizioni verificate è falsa. La complessità dell’algoritmo è proporzionale al numero di nodi. boolean compare(Tree T1, Tree T2){ if (T1 return true; == null && T2 == null) if (T1 != null && T2 != null) return((T1.key == T2.key) && compare(T1.left, T2.left) && compare(T1.right, T2.right)); else return(false); } Esercizio 4 Se si inseriscono i dati in ordine crescente o decrescente (e.g. {60, 23, 18, 15,10, 5} si ottiene un albero in cui ogni sottoalbero ha la proprietà che il cammino sinistro alterna nodi rossi e nodi neri mentre il cammino destro ha solo nodi neri ed è quindi lungo la metà del sinistro. La figura seguente mostra lo stato dell’albero dopo l’inserimento di, rispettivamente: 60 T.NIL 60 23 23 18 T.NIL Inserimento di 60, 23, 18 60 T.NIL 23 x 23 18 60 15 y x 18 23 60 15 T.NIL T.NIL Inserimento di 15 23 23 18 15 60 x 18 60 15 10 10 T.NIL y T.NIL 23 y 23 15 60 18 10 T.NIL Inserimento di 10 23 15 60 18 10 5 T.NIL Risultato finale. Algoritmi e Principi dell’Informatica Appello del 21 Settembre 2015 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (Punti 7) Si consideri il linguaggio seguente: L1 = {a,b,c}* - a*.b* dove il – indica la differenza insiemistica. Si costruiscano una macchina astratta che riconosca L1 e una grammatica che lo generi; è fortemente raccomandato che entrambi i formalisimi siano a “potenza minima” ossia appartenenti alla categoria di automi/grammatiche a minor potenza riconoscitiva/generativa possibile. Esercizio 2 (Punti 8) Si consideri, oltre al linguaggio L1 dell’esercizio 1, anche il linguaggio L2 seguente: L2 = {a,b}* - {anbn | n > 0} Si dica, motivando brevemente la risposta, quali dei seguenti problemi sono decidibili e quali no: 1. 2. 3. 4. Stabilire se un generico automa a stati finiti riconosce L1 Stabilire se un generico automa a stati finiti riconosce L2 Stabilire se una generica macchina di Turing riconosce L1 Stabilire se una generica macchina di Turing riconosce L2 Esercizio 3 (Punti 7) Si consideri il linguaggio L = {wcwcw | w {a,b}+}. Si descriva una macchina RAM che riconosca L, minimizzando la complessità spaziale sia a criterio di costo costante che logaritmico. Esercizio 4 (Punti 8) Sia dato un array A di n interi che assumono valori nell'intervallo [0, …, n+1]. L’array non contiene valori duplicati; i valori in esso contenuti saranno quindi tutti quelli compresi nell’intervallo considerato, tranne due. A non è ordinato. Si specifichi un algoritmo che individui e produca in output i due valori mancanti in A e se ne discuta la complessità. La valutazione dell’algoritmo proposto dipenderà dalla sua complessità. Tracce di soluzioni Esercizio 1 L1 è la differenza tra due linguaggi regolari (di cui il primo è il monoide libero sull’alfabeto {a,b,c}. Siccome i linguaggi regolari sono chiusi rispetto alla differenza insiemistica, e in particolare rispetto al complemento, L1 è pure regolare. Un automa a stati finiti e una G regolare che riconosca e generi L1, rispettivamente sono i seguenti: a b c b a, c a, b, c S aS | bB | cC | c B bB | aC | a | cC | c C aC | bC | cC | a | b | c Esercizio 2 1. Il problema è decidibile: in generale è decidibile l’equivalenza tra due automi a stati finiti (L(A 1) = L(A2) se e solo se L(A1) L(A2) e L(A2) L(A1); L(A1) L(A2) se e solo se L(A1) (L(A2)) = , dove L(A2) indica il complemento di L(A2)). Quindi in particolare è decidibile se un generico A riconosce L1. 2. Il problema è non solo decidibile ma anche banalmente deciso sulla base del fatto che L2 è (deterministico) non-contestuale ma non regolare; quindi nessun automa a stati finiti può riconoscerlo. 3. Il problema non è decidibile in base al teorema di Rice; infatti l’insieme delle MT che riconoscono L1 (risolvono il problema rappresentato da L1) palesemente non è né l’insieme vuoto né l’insieme universo. 4. Lo stesso ragionamento vale per L2. Osservazione a latere: essendo decidibile il problema dell’equivalenza tra automi a pila deterministici (risultato relativamente recente e di molto complessa dimostrazione!) il problema di stabilire se un generico automa a pila deterministico riconosca L1 o L2 è decidibile poiché entrambi i linguaggi sono deterministici noncontestuali. Esercizio 3 Basta vedere i fattori w come numeri binari, per comodità con le cifre meno significative a sinistra, dove ad es a=0 e b=1. Si utilizza una cella di memoria per codificare w (es. M[1]), moltiplicando per 2 tutte le volte che si legge una nuova cifra, e sommando 1 se essa è b. Alla lettura della prima c si codifica in maniera analoga il secondo fattore w in M[2]. Alla seconda c si controlla che M[1] sia uguale ad M[2], poi si procede a codificare il fattore w finale in M[1]; l’ultimo controllo M[1]=M[2] avviene a fine stringa. La complessità spaziale risulta pari a (1) a criterio costante e (log(n)) a criterio logaritmico, con n lunghezza della stringa in ingresso. Esercizio 4 E’ possibile ispirarsi all’algoritmo del counting sort e utilizzare un array ausiliario B di n+2 valori booleani (0 e 1), tale che B[i] = 1 se i è presente nell’array; altrimenti B[i] = 0. L’algoritmo risultante (riportato di seguito) ha complessità Θ(n). void mancanti(int A[], int n) { int i, trovati = 0; int B[n+2]; for (i=0; i< n+2; i++) B[i] = 0; for (i=0; i < n; i++) B[A[i]] = 1; i=0; while (i < n+2 && trovati < 2) { if (B[i] == 0) { print(i); trovato++; } } } Algoritmi e Principi dell'Informatica Prima Prova in Itinere (modulo Informatica teorica) 23 Novembre 2015 Il tempo a disposizione è di 1 ora e 45 minuti. Esercizio 1 (punti 7/15 senza la parte c, 8/15 con la parte c) Parte a. Si consideri il gioco della roulette. Un giocatore adotta la seguente strategia: inizialmente punta 1€ sul rosso; a ciascuna estrazione successiva punterà sempre sul rosso; in particolare, se esce il nero, il giocatore perde la posta e al prossimo turno raddoppierà la puntata; altrimenti vince il doppio di quanto ha puntato e al prossimo turno punterà tutta la vincita. Modellare il comportamento del giocatore con un automa a potenza minima (tra le classi FSA, DPDA, NDPDA e TM) che riceva in ingresso una stringa costruita sull’alfabeto {R,N} (dove R indica che è uscito il rosso e N che è uscito il nero) e che la accetti se e solo se il giocatore che abbia puntato secondo la strategia indicata nelle estrazioni corrispondenti ai simboli in ingresso è in attivo (ossia le vincite superano gli importi complessivamente puntati). Parte b. Qual è il linguaggio accettato da tale automa? Parte c. Cambierebbe la classe dell’automa richiesto se la strategia fosse modificata in modo che, quando esce il rosso, al turno successivo il giocatore punti solo 1€? Esercizio 2 (Punti 5/15) Il predicato binario succ indica che i suoi argomenti sono numeri naturali tali per cui il secondo è il successore del primo. Ad esempio, succ(1,2) è vero mentre succ(2,6) è falso. Si specifichi in logica del prim’ordine il predicato ternario somma, che indica che il terzo argomento è la somma dei primi due. Ad esempio, somma(2,3,5) è vero mentre somma(3,6,2) è falso. Nella specifica del predicato somma non si può fare uso di predicati diversi da succ e dal predicato di uguaglianza. Inoltre, non si possono usare funzioni aritmetiche (ad esempio il +…). E’ invece consentito l’uso di costanti che indicano numeri naturali (0, 1, 2, …). Esercizio 3 (punti 5/15) Si consideri il seguente programma P codificato in uno pseudolinguaggio ispirato al C. P: { int x, y, z; read (x, y, z); while (x != y) { x = x - y; z = z + y}; write z; } Sia f(x, y, z) la funzione calcolata da P. Si dica, giustificando brevemente la risposta, se la seguente funzione: g(x, y, z) = 1 se f(x,y,z) ≠, 0 altrimenti è calcolabile o no. Tracce di soluzioni Esercizio 1 Parte a. La strategia delle puntate è fatta in modo tale che, se il giocatore vince, vince necessariamente almeno 1€ in più di quanto può aver perso complessivamente in precedenza; se perde, perde necessariamente almeno 1€ in più di quanto ha vinto in precedenza. E’ sufficiente pertanto un semplice FSA per modellare questo comportamento. Parte b. Il linguaggio riconosciuto dall’automa è composto da tutte e sole le stringhe che terminano con una R. Parte c. Sì, occorre un formalismo più potente. In questo caso non c’è più la garanzia di essere in perdita dopo l’uscita del nero, in quanto ci possono essere state vincite precedenti che compensano largamente la perdita. Occorrerebbe pertanto tenere conto sia di quanti euro sono stati puntati in precedenza, sia dell’entità della puntata corrente, o comunque di poter ricostruire il bilancio attuale del giocatore (negativo o positivo e arbitrariamente grande), il che eccede il potere espressivo di un automa a stati finiti. Esercizio 2 xyz (somma(x,y,z) ((y=0 x=z) (y’z’ succ (y’,y) succ (z’,z) somma(x,y’,z’)))) Esercizio 3 L'esecuzione di P termina se e solo se i dati forniti in ingresso sono tali che x e y siano dello stesso segno, x sia ≥ y se entrambi positivi o viceversa se entrambi negativi, e sia, in modulo, un suo multiplo; più precisamente: g(x, y, z) = 1 se x=y ((x > y > 0 x < y < 0) k (k > 1 |x| = k.|y|)) 0 altrimenti ed è evidentemente calcolabile. Algoritmi e Principi dell'Informatica Prima Prova in Itinere (modulo Informatica teorica) 23 Novembre 2015 English version Total available time: 1h 45'. Exercise 1 (7/15 points without part c, 8/15 with it) Part a. Consider the roulette game. A player adopts the following strategy: She first bids 1€ on the red; All her following bids will be on the red; In particular, if black wins, the player loses all her bid money, and at the next step she will double her bid; otherwise, she wins twice the value of her bid, and the next time she will bid all the money won. Please model the player's behavior with an automaton having minimal accepting power (among the classes FSA, DPDA, NDPDA, and TM). Such automaton gets as input a string on the alphabet {R, B} (where R stands for Red and B for Black), and accepts if and only if the player won more money than she bid. Part b. What is the language of the automaton? Part c. Consider a variant of the strategy where the player, when she wins with the red, at the following step will bid only 1€. In this case, does the automaton class change? Please, explain your answer. Exercise 2 (5/15 points) A binary predicate succ denotes that its arguments are natural numbers such that the second is the successor of the first. For instance, succ(1,2) is true, while succ(2,6) is not. Please write a first-order logic formula that defines the ternary predicate sum, which holds if and only if its third argument is the sum of the previous two arguments. E.g. sum(2,3,5) is true, while sum(3,6,2) is not. In your formula, you cannot use other predicates from succ and =; moreover, you cannot use arithmetic functions such as +, ... It is possible to use constants (e.g. 0, 1,...). Exercise 3 (5/15 points) Consider the following program P, written in a pseudo-C language: P: { int x, y, z; read (x, y, z); while (x != y) { x = x - y; z = z + y}; write z; } Let f(x, y, z) be the function computed by P. Is the following function g computable? g(x, y, z) = 1 if f(x,y,z) ≠, 0 else Please, explain your answer. Algoritmi e Principi dell'Informatica Seconda Prova in Itinere 3 Febbraio 2016 Avvisi importanti Il tempo a disposizione è di 1 ora e 45 minuti. Esercizio 1 (punti 6/15-esimi) Si consideri il linguaggio L = {cm al1 b al2 b ... alm b ... alz b dn | n, m, li, z > 0, lm = n}. Per esempio ccaaabaaaabababdddd L. Si descrivano una macchina di Turing e una macchina RAM che accettano L, calcolandone le complessità spaziali e temporali, sia a criterio di costo costante che logaritmico. Esercizio 2 (punti 11/15-esimi) Si consideri la gestione delle tabelle hash mediante indirizzamento aperto. E’ noto che in tal caso per eliminare un elemento della sequenza di ispezione associata a una chiave k non basta assegnargli il valore NIL, perché altrimenti si “romperebbe la catena”. Un rimedio normalmente utilizzato in questi casi consiste nel marcare l’elemento come Deleted, in modo tale che la ricerca di altri elementi lungo la sequenza non si debba interrompere. In questo modo però, a lungo andare si genera una forma di “garbage” che ovviamente diminuisce la memoria disponibile e peggiora anche le prestazioni temporali. Si progetti un algoritmo di Compattamento il quale, per una data tabella T (per semplicità la si consideri una variabile globale), ricevendo come argomento una chiave k, elimini dalla sequenza associata alla chiave k tutti gli elementi marcati come Deleted ricompattando così la sequenza e recuperando la memoria inutilizzata. NB: se l’algoritmo elimina anche altri elementi Deleted oltre a quelli indicati, il risulato è ugualmente accettabile (anzi, è addirittura preferibile); purché non interrompa alcuna sequenza. Si rammenta che la notazione T[p], data una posizione p della tabella, restituisce NIL, Deleted, o k, ossia la chiave contenuta nella posizione, se questa non è né Deleted né vuota. Si assuma inoltre che la funzione h(k, i) sia del tipo h(k, i) = (f(k) + g(i)) mod m con g(0) = 0 (non si tratta quindi di doppio hashing) con f e g funzioni calcolabili in tempo costante. Si valuti la complessità asintotica dell’algoritmo. Parte opzionale (ulteriori 2punti) L’algoritmo prodotto è applicabile anche al caso in cui la funzione h sia una funzione di tipo doppio hashing? Giustificare brevemente la risposta. Tracce di soluzioni Esercizio 1 Entrambe le macchine devono contare i c in ingresso, la MT in unario e la RAM in una cella es. M[1]. Alla prima a, si contano i gruppi di a separati da b, fino all’arrivo dell’m-esimo. Si può usare M[1] o il nastro della MT a questo punto per contare il numero di a. Si ignorano i successivi a e b, controllando solo che la sequenza finisca con b; fino all’arrivo dei d, che devono essere pari al numero memorizzato in M[1] o nel nastro. Complessità: RAM (costo costante): T(n) = (n), S(n) = (1) RAM (costo logaritmico): T(n) = (n log n), S(n) = (1og n) MT: T(n) = (n), S(n) = (n) Esercizio 2 Descrizione informale dell’algoritmo. L’approccio naturale al problema consiste nello scandire completamente la sequenza associata a una chiave k, ossia fino alla marca NIL; quando si incontra una posizione marcata Deleted si mette al suo posto la posizione corrente marcando questa a sua volta come Deleted; quando la posizione corrente raggiunge il NIL le eventuali posizioni intercorrenti tra l’ultima posizione aggiornata,ormai solo Deleted, e il NIL vengono tutte messe a NIL. In questo modo però si rischia di imbattersi in posizioni occupate da altre sequenze: in tal caso sarebbe un errore spostarne il contenuto; quindi conviene accontonare questi elementi in una lista temporanea e marcarli come Deleted, per poi reinserirli ex-novo a compattamento ultimato. Siccome però la funzione di hash costruisce la stessa sequenza per ogni chiave con ugual valore di f(k), è possibile e opportuno eliminare tutti gli elementi delle sequenze che hanno la stessa origine. Pseudocodice compact(k) /*compattamento della lista associata alla chiave (variabile globale) cui l’algoritmo viene applicato. k; T denota la tabella Sia h(k,i) la funzione di hash; T[p] indica il contenuto di T nella posizione p, ossia NIL, Deleted, oppure la chiave presente in p. In realtà il presente algoritmo “ripulisce” tutte le posizioni Deleted di tutte le sequenze che hanno la stessa origine in h(k,0) mediante un semplice test; poiché tali sequenze coincidono non si rischia di interrompere impropriamente altre sequenze. Per semplicità si assume che la sequenza termini comunque in un elemento NIL, assunzione garantita, ad esempio, segnalando un overflow se in fase di inserimento si giunge a un punto in cui h(k, i) = h(k, 0).*/ { i = 0; PosCorrente = h(k,i); while (T[PosCorrente] != NIL && T[PosCorrente] != Deleted) {i++; PosCorrente = h(k,i); } if (T[PosCorrente] == NIL) return; //non ci sono elementi Deleted else // T[PosCorrente] è Deleted {j = i; ProxDeleted = PosCorrente; while (T[PosCorrente] != NIL) { while (T[PosCorrente] != NIL) if (T[PosCorrente] == Deleted) {j++; PosCorrente = h(k,j)}; else if h(T[PosCorrente],0)!= h(k,0) {inserisci T[PosCorrente] in una lista temporanea TempL; T[PosCorrente] = Deleted; /*in questo modo gli elementi che non fanno parte di una delle sequenze che hanno origine in f(k) vengono accontonati j++; PosCorrente = h(k,j) }; /* si giunge a fine sequenza o al primo elemento non NIL e non Deleted di una sequenza che ha origine in h(k,0)*/ if (T[PosCorrente] != NIL) /*cioè PosCorrente appartiene a una sequenza che ha origine in f(k)*/ {T[ProxDeleted] = T[PosCorrente]; T[PosCorrente] = Deleted; i++; ProxDeleted = h(k, i) } else //l’elemento Deleted era l’ultimo della sequenza {T[ProxDeleted] = NIL;} } /* a questo punto tutti gli elementi tra i e j sono deleted e si possono porre a NIL*/ while (i != j) {T[h(k, i)] = NIL; i++;} } /* a questo punto non resta che reinserire in tabella gli elementi accantonati che appartenevano a sequenze non originanti in f(k)*/ Forall elements k in TempL Insert(T, k) } Si noti che entrambi gli indici, i, e j utilizzati nel programma percorrono tutta la sequenza che parte da h(k, 0), includendo anche gli elementi che non sono stati inserti a partire dalla chiave k ma che si trovano in posizione h(k, i) per qualche i. Quindi la complessità della prima parte dell’algoritmo, fino al reinserimento in T degli elementi di TempL, è O(n), n essendo la lunghezza complessiva della sequenza. La complessità di quest’ultima parte è O(p.m), dove p è la lunghezza di TempL e m la lunghezza dell’intera tabella, poiché ogni inserimento, nel caso pessimo costa O(r), con 1 <= r <= m. E’ però probabile che nel caso medio anche questa parte dell’algoritmo abbia una complessità più vicina a O(p) che a O(p.m) perché i nuovi inserimenti avverranno probabilmente in posizioni rese disponibili dalla passata precedente. Quindi la complessità totale dell’algoritmo è O(n+ p.m). Come sempre nel caso delle tabelle hash nel caso pessimo “teorico” p n m e quindi si ha una complessità O(m2), caso comunque solitamente lontano dal caso medio: normalmente si può ipotizzare p < n << m. Parte opzionale L’algoritmo sfrutta l’ipotesi che, se h(k1, 0) = h(k2, 0) per qualche chiave k1, k2, la sequenza generata a partire da h(k1, 0) coincide con quella generata a partire da h(k2, 0); quindi confrontando semplicemente l’origine della sequenza originata da f(k) con quella originata da f(k’) dove k’ è la chiave contenuta nella posizione corrente, è possibile decidere se eliminare o meno l’elemento contenuto; si noti che in tal modo si eliminano in un colpo solo tutti gli elementi Deleted dell’unica sequenza originata in f(k) per tutte le chiavi con lo stesso valore di f(k), nel caso di clustering secondario. Al contario, se si adotta un doppio hashing è possibile che esistano due chiavi k1, k2, e due indici i1, i2, tali che h(k1, i1) = h(k2, i2), con h(k1, 0) = h(k2, 0) ma appartenenti a sequenze diverse e quindi tali che si debba eliminare l’elemento appartenente all’una ma non all’altra. Osservazione Un algoritmo leggermente meno efficiente potrebbe più semplicemente accantonare in TempL tutti gli elementi non Deleted e poi reinserirli. In questo caso il p della formula precedente sarebbe maggiore e la passata di reinserimento in tabella rischierebbe di avvicinarsi maggiormente a una complessità quadratica. Al solito, però si tatta di considerazioni di tipo “euristico”. Soluzione alternativa Lo pseudocodice seguente è sostanzialmente equivalente a quello precedente anche in termini di complessità, ma fa uso di tre liste separate, ossia gli indici della sequenza, le chiavi delle sequenze con origine in h(k,0), le chiavi delle sequenze non originanti in h(k,0). compact_p(T, k): i = 0 pos = hash(k, i, max) while T[pos] != NIL && i < m list_insert(indexes, pos) if T[pos] != Deleted currk = T[pos] if hash(currk, 0) == hash(k, 0) list_insert(keys, currk) else list_insert(others, currk) T[pos] = NIL i++ pos = hash(k, i, max) curr = last(indexes) i = 0 for x in keys T[curr.value] = x curr = curr.prev for x in others hash_insert(T, x) Algoritmi e Principi dell'Informatica Recupero della I Prova in Itinere (solo per Laureandi) 3 Febbraio 2016 Avvisi importanti Il tempo a disposizione è di 1 ora. Chi partecipa a questa prova, non potrà svolgere il successivo appello di Febbraio. Esercizio 1 (punti 8/15-esimi) Si consideri il linguaggio L = {cm al1 b al2 b ... alm b ... alz b dn | n, m, li, z > 0, lm = n}. Per esempio ccaaabaaaabababdddd L. Si definisca un automa (o grammatica, o rete di Petri) A a potenza minima tale che L(A) = L. Esercizio 2 (punti 8/15-esimi) Si dica, giustificando brevemente la risposta se le seguenti affermazioni sono vere o false: 1. E’ decidibile stabilire se una generica MT riconosce L (il linguaggio definito nell’esercizio 1) 2. E’ decidibile stabilire se il complemento di L è non contestuale. 3. E’ decidibile stabilire se, dati una rete di Petri PN 1-bounded -ossia tale che nelle marcature raggiungibili da una marcatura iniziale non accada mai che un posto contenga più di un token- e un automa a stati finiti A, essi siano equivalenti, ossia riconoscano lo stesso linguaggio. Tracce di soluzioni Esercizio 1 Basta un automa a pila deterministico A. A deve contare i c in ingresso, mettendo C sulla pila. Alla prima a, si contano i gruppi di a separati da b, fino all’arrivo dell’m-esimo, eliminando una C per ogni gruppo dalla pila. A questo punto si impila A per ogni a trovato, fino alla prima b. Si ignorano i successivi a e b, controllando solo che la sequenza finisca con b; all’arrivo dei c si spilano le A, controllando che siano pari alle c. Esercizio 2 1. NO (Teorema di Rice) 2. Sì (Problema chiuso e deciso (L riconosciuto da APD; ling. CF det. Chiusi rispetto al complemento) 3. Sì: Le PN 1-bounded sono equivalenti agli automi a stati finiti e l’equivalenza tra ling. Regolari è decidibile. Algoritmi e Principi dell’Informatica Appello del 25 Febbraio 2016 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (Punti 9) 1) Si definisca formalmente il seguente modello di automa, chiamato macchina di Turing monodirezionale ad un nastro (MTM1). Una MTM1 è un accettore nondeterministico (non effettua quindi traduzioni) dotato di un nastro di ingresso e un nastro di memoria. Il funzionamento è analogo a quello di una MT tradizionale, a parte il movimento delle due testine dei nastri: esso può essere solamente S (stop) o R (right). 2) Si confronti la capacità espressiva delle MTM1 con i modelli visti a lezione. 3) Si consideri una variante “a nastro singolo” e deterministica della MTM1 e se ne valuti l'eventuale differenza di capacità espressiva. Esercizio 2 (Punti 8) Si consideri il seguente insieme. S = { i | La macchina di Turing Mi termina la sua esecuzione in meno di 100 passi per qualche ingresso } S è ricorsivamente enumerabile? S è ricorsivo? Giustificare brevemente le risposte. Esercizio 3 (Punti 7) Sia dato un insieme di n interi distinti. Si descriva un algoritmo che restituisce il k-esimo elemento più piccolo e se ne valuti la complessità; ovviamente la valutazione della soluzione proposta terrà conto della complessità ottenuta. Nella specifica della soluzione è possibile far riferimento ad algoritmi noti, specificandone con precisione funzionalità e complessità. Esercizio 4 (Punti 9) Sia T un albero binario. Sia t un suo nodo e siano t.left e t.right il sottoalbero sinistro e destro di t. Denotiamo con nodi(t) il numero di nodi del sottoalbero radicato in t. Un albero binario si dice perfettamente bilanciato quando per ogni suo nodo t la differenza tra il numero dei nodi dei due sottoalberi di t è in valore assoluto al più 1: | nodi(t.left) - nodi(t.right)| ≤ 1. Si definisca un algoritmo che, dato in input un nodo t, verifica se l’albero radicato in t è perfettamente bilanciato. Si discuta la complessità dell’algoritmo definito. Tracce di soluzioni Esercizio 1 1) A = <Q, , , q0, F, , Z0>, stato iniziale q0 Q, stati finali F Q Funzione di transizione : (Q – F) (Q {S, R}2) Configurazione: per comodità usiamo come seconda componente la stringa in ingresso ancora da leggere (cioè la parte destra della stringa, testina inclusa); per la terza componente, che rappresenta il nastro, indichiamo la parte scritta e visitata dalla macchina (cioè la parte sinistra, testina inclusa). <q, a.x, y.b> |-- <q’, a’.x, y.b’.c>, se (q’, b’, m1, m2) (q,a,b) dove a’ = se m1 = R altrimenti a’ = a c = se m2 = S altrimenti c = _ (blank) x L(A) sse <q0, x, Z0> |-*- <qF, x’, y>, qF F. 2) Una MTM1 accede solo ad una cella di memoria (quella corrente) e non può in alcun modo ritornare sulla parte sinistra del nastro di memoria. Questa informazione è finita ( ) e può essere facilmente codificata nello stato dell’organo di controllo. Per questo motivo le MTM1 definiscono tutti e soli i linguaggi Regolari. 3) L’uso di un unico nastro e del determinismo non cambia nulla. Esercizio 2 S è ricorsivo (e quindi anche ricorsivamente enumerabile). Infatti basta verificare se la macchina si arresta entro 99 passi per qualche stringa di lunghezza <100. Tali stringhe sono in numero finito, quindi la verifica avviene in un numero finito di passi. Non occorre considerare stringhe più lunghe perché, se anche ci fosse una stringa più lunga di 100 caratteri tale per cui la macchina si arresti in meno di 100 mosse, e quindi avendo letto un prefisso di lunghezza minore di 100, necessariamente vi sarebbe anche una stringa con lo stesso prefisso ma lunga meno di 100 che farebbe arrestare la macchina nello stesso numero di mosse. Si noti che in questo caso non è applicabile il teorema di Rice, in quanto la proprietà delle macchine di Turing considerate per l’insieme S (terminare in meno di 100 passi per qualche ingresso) non è una proprietà della funzione calcolata, bensì una proprietà strutturale della macchina. Esercizio 3 Questo problema prevede diverse soluzioni. Ne riportiamo alcune: - è possibile ordinare l’insieme usando uno degli algoritmi classici di ordinamento (O(n log n), non potendo fare alcuna assunzione sui valori dell’insieme), quindi restituire i primi k elementi; - è possibile far uso di una coda di priorità. Si invoca k volte la removeMin(). Si restituisce in output il valore trovato con l’ultima chiamata. Se la coda di priorità è implementata tramite un minheap, allora la costruzione dello heap ha complessità O(n). Il costo delle k invocazioni di removeMin() è O(k log n). Si ottiene quindi complessità totale in O(n + k log n). - è possibile utilizzare algoritmi specifici per la selezione, come il quickselect deterministico (BFPRT), la cui complessità è lineare nel numero di elementi dell’insieme (O(n)). Esercizio 4 Ci sono diverse soluzioni con complessità Θ(n) (n essendo il numero di nodi nel sottoalbero considerato), tutte basate sulla visita in post-ordine del sottoalbero. Riportiamo di seguito una soluzione “intuitiva”, che ha complessità temporale Θ(n) e che: i) fa uso di memoria aggiuntiva per memorizzare in ogni nodo il numero di nodi del suo albero; ii) visita l’albero due volte: una prima volta per calcolare il numero dei nodi (funzione count(t)) e una seconda volta per verificare il bilanciamento. È possibile definire algoritmi più “compatti”, che attraversano l’albero una sola volta, restituendo a ogni chiamata ricorsiva il conteggio dei nodi del sottoalbero visitato e il risultato della verifica di bilanciamento per il sottoalbero. Per tale classe di soluzioni è necessario fare attenzione al conteggio dei nodi nei vari sottoalberi, per evitare di considerare più volte gli stessi nodi. Questo, infatti, comporterebbe un numero maggiore di chiamate ricorsive e il conseguente incremento della complessità. boolean checkBalance(TREE t) { count(t); return checkBalanceRic(t); } integer count(TREE t) { if t = nil return 0 t.count = count(t.left) + count(t.right) + 1 return t.count } boolean checkBalanceRic(TREE t) { integer nodiL = 0, nodiR = 0 boolean balancedL = true, balancedR = true if t.left != nil { nodiL = t.left.count balancedL = checkBalanceRic(t.left) } if t.right != nil { nodiR = t.right.count balancedR = checkBalanceRic(t.right) } return (balancedL AND balancedR AND (|nodiL – nodiR| <= 1) } Algoritmi e Principi dell’Informatica Appello del 30 Giugno 2016 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (Punti 8) Scriva una formula logica del prim’ordine che formalizzi la frase seguente: Tutte le volte che mangio del salame entro 24 ore mi viene mal di pancia, a meno che, prima che sopraggiunga il mal di pancia, non prenda una pillola gastroprotettrice. Si supponga, per semplicità, che mangiare salame sia un evento isolato nel tempo e che non possa ripetersi più di una volta nell’arco di 24 ore. Suggerimento (non imposizione!) Si consiglia di far uso, non necessariemtne esclusivo, dei seguenti predicati, tutti parametrici rispetto alla variabile t: Salame(t): mangio del salame al tempo t MalPancia(t): mi viene mal di pancia Pillola(t): assumo una pillola La variabile t può essere interpretata indifferentemente in un dominio discreto o continuo. Esercizio 2 (Punti 7) Siano L1, L2, .. Lk, k > 1 linguaggi definiti su un alfabeto , tali che valgano le seguenti proprietà: i ≠ j, Li Lj = , L1 L2 … Lk = *, i, Li è semidecidibile. Si dica, giustificando brevemente la risposta se le seguenti affermazioni sono vere o false: Tutti i linguaggi L1, L2, .. Lk sono ricorsivi E’ possibile che alcuni di essi siano regolari Tutti i linguaggi L1, L2, .. Lk sono necessariamente regolari Esercizio 3 (Punti 7) Si definisca una MT a k nastri che riconosca il linguaggio L = {www | w {0,1}+} e se ne valutino le complessità spaziale e temporale. Esercizio 4 (Punti 8) In un albero binario, il grado di sbilanciamento di un nodo può essere calcolato come valore assoluto della differenza fra il numero di foglie presenti nei suoi due sottoalberi. A partire da tale valore calcolato per ogni nodo, è possibile ricavare un grado di sbilanciamento di un albero come il massimo tra i gradi di sbilanciamento calcolati per tutti i suoi nodi. Per esempio, dato il seguente albero binario, per il quale si riportano anche i gradi di sbilanciamento (gs) dei singoli nodi: il grado di sbilanciamento per l’albero radicato in A è 2, poiché questa è la differenza massima del numero di foglie nei due sottoalberi di A (quella cioè calcolata per il sottoalbero radicato in C). Si definisca un algoritmo per il calcolo del grado di sbilanciamento di un albero binario; se ne discuta quindi la complessità. Tracce di soluzioni Esercizio 1 Soluzione A I seguenti predicati salame(t), malPancia(t), pillola(t) sono usati con l’ovvio significato. La frase dell’esercizio è allora formalizzata come segue: t (salame(t) t1( t < t1 <= t +24 salame(t1)) ( ( t1 ((pillola(t1) ( t2 ( t < t2 < t1 malPancia(t2))) t1( t <= t1 <= t +24 malPancia (t)) ( t3 (t <= t3 <= t +24 (( t2 ( t < t2 < t3 pillola(t2)) malPancia(t3)) ) ) Soluzione B t (salame(t) t1( t < t1 <= t +24 salame(t1)) ( t1 (t ≤ t1 ≤ t +24 pillola(t1) t2 ( t ≤ t2 ≤ t+24 malPancia(t2))) t1 (t ≤ t1 ≤ t +24 malPancia(t1) t2 ( t ≤ t2 ≤ t1 pillola(t2))) ) ) Esercizio 2 Poiché i linguaggi sono tra loro disgiunti e la loro unione è l’intero *, enumerando tutte stringhe di L1, L2, .. Lk nell’ordine 1, 2, …k, (ossia, una stringa di L1, una stringa di L2, …) prima o poi una qualsiasi string x deve comparire in una e una sola delle sequenze Li, e quindi si può decidere a quale linguaggio appartiene. E’ certamente possibile che qualche o anche tutti gli Li, siano regolari, ma non necessario. Esercizio 3 1) La MT fa una prima passata sulla stringa in ingresso (sia essa x) e sul nastro 1 memorizza un simbolo X ogni 3 caratteri letti – in questo modo viene calcolata la lunghezza del fattore w in unario. 2) Alla seconda passata la macchina copia il fattore w sul nastro 2, sfruttando il nastro 1 per vedere quando esso termina. Continua poi la lettura, controllando che il secondo e il terzo fattore w siano identici a quanto salvato nel nastro 2. Complessità spaziale: vengono memorizzate 2 stringhe di lunghezza n/3, S(n) = (n), con n = |x|. Complessità temporale: la macchina effettua 2 scansioni lineari di x, T(n) = (n). Esercizio 4 È possibile definire una funzione ricorsiva che usa una visita in post-ordine per calcolare, per ogni nodo dell’albero, il numero di foglie e il massimo grado di sbilanciamento del sottoalbero radicato nel nodo. Facciamo uso di una struttura per memorizzare i due valori calcolati in ogni chiamata ricorsiva; restituiamo la struttura come valore di ritorno della funzione ricorsiva. typedef struct{ int leafs; int maxUnbalance; }Result; Result unbalanceFactor(TREE T) { Result Res, L, R; if (T == nil) { Res.leafs=0; Res.maxUnbalance=0; return Res; } if ((T.left == nil) and (T.right == nil )) { Res.leafs = 1; Res.maxUnbalance=0; return Res; } L = unbalanceFactor(T.left); R = unbalanceFactor(T.right); Res.leafs = L.leafs + R.leafs; Res.maxUnbalance = max(L.maxUnbalance, R.maxUnbalance, abs(L.leafs − R.leafs)); return Res; } La complessità dell’algoritmo è la stessa di una visita di un albero, cioè O(n). Algoritmi e Principi dell’Informatica Appello del 1 Settembre 2016 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (9 punti) 1. Si costruisca un automa, preferibilmente a minima potenza riconoscitiva, che accetti il linguaggio L1 {a,b}* costituito da tutte e sole le stringhe w tali che, se w contiene la sottostringa aa, allora la sua lunghezza è dispari. 2. Si determini la famiglia di automi a potenza riconoscitiva minima -o minimale- tale che un suo membro riconosca il linguaggio L2 {a,b,c}*, costituito da tutte e sole le stringhe w tali che w includa la stringa canc (per qualche n > 0) e, successivamente, la stringa ba2nb (la stringa w può contenere altre sottostringhe oltre alle suddette canc e ba2nb). a. Si costruisca un automa in tale famiglia che riconosca L2; b. Si costruisca una grammatica, preferibilmente a minima potenza generativa, che generi L2. Esercizio 2 (8 punti) Per entrambi i punti seguenti si assuma che L sia un linguaggio infinito costruito su un alfabeto A. 1. Sia L un linguaggio ricorsivo. Esiste necessariamente una enumerazione algoritmica E che enumera tutte le stringhe di L in ordine lessicografico? Motivare brevemente la risposta. 2. Sia E una enumerazione algoritmica E che enumera tutte le stringhe di un linguaggio L in ordine lessicografico. L è necessariamente ricorsivo? Motivare brevemente la risposta. Esercizio 3 (7 punti) Si descriva una MT a k nastri che, dato in input un valore n naturale maggiore di 0 codificato in unario, produce in output le prime n potenze di 4, cioè 40, 41, 42, ... 4n-1, ognuna codificata in binario e seguita dal simbolo #. Dare le complessità temporale e spaziale della MT ideata. Esercizio 4 (8 punti) E’ noto che il Quicksort ha un comportamento nel caso pessimo O(n2); ad esempio la versione presentata nel corso (e fornita dal testo) ha complessità O(n2) quando l’array in input è già totalmente ordinato. 1. Si modifichi il codice della versione suddetta, riportata qui sotto per comodità, in modo che la complessità di esecuzione, se A è già ordinato, risulti O(n⋅log(n)). NB: la nuova versione deve essere esclusivamente una modifica dell’algoritmo originario, non includere altri (sotto)algoritmi più adatti al caso specifico. 2. Qual è la complessità asintotica della nuova versione nel caso pessimo? Descrivere come è fatto il caso pessimo, illustrandolo con un esempio. QUICKSORT(A, p, r) 1 if p < r 2 q := PARTITION(A, p, r) 3 QUICKSORT(A, p, q−1) 4 QUICKSORT(A, q+1, r) PARTITION(A, p, r) 1 x := A[r] 2 i := p − 1 3 for j := p to r − 1 4 if A[j] ≤ x 5 i := i + 1 6 swap A[i] ↔ A[j] 7 swap A[i+1] ↔ A[r] 8 return i + 1 Tracce delle soluzioni Esercizio 1 1. Il seguente automa a stati finite riconosce L1. 2. Un automa a stati finiti non è evidentemente in grado di riconoscere L2 a causa della necessità di un conteggio illimitato. Neanche un automa a pila deterministico è in grado di operare il riconoscimento perché una stringa del linguaggio può contenere diverse sottostringhe del tipo canc, di cui solo una abbia una corrispondente sottostringa ba2nb come ad esempio nella stringa acaaacbbcaccbaabc. E’ anche possibile costruire una rete di Petri che riconosca L2; quindi, siccome PDA e reti di Petri hanno potenza riconoscitiva incomparabile, vi sono almeno due famiglie di automi, tra quelle classiche, a potenza riconoscitiva minimale, in grado di formalizzare L2. a. b. S → XDX D → caEaab E → aEaa | aXb X → aX | bX | cX | Esercizio 2 1) L è ricorsivo, quindi esiste un “decisore” per L, cioè una macchina di Turing M che termina sempre e scrive 1 in uscita se la stringa in ingresso appartiene a L, 0 altrimenti. L’enumerazione algoritmica E richiesta si ottiene come segue: basta enumerare tutte le stringhe di A* in ordine lessicografico (cosa sempre possibile) e, per ciascuna di esse, testarne l’appartenenza ad L tramite M (che è disponibile per ipotesi), stampandola in uscita solo se appartiene a L. 2) L è enumerabile algoritmicamente mediante E in ordine lessicografico. Si può quindi costruire un decider M per L come segue: quando riceve una stringa x in ingresso, M esegue l’enumerazione E e legge la lista di tutte le stringhe di L in ordine lessicografico fino a che non compare una stringa che lessicograficamente stia dopo x (tale stringa deve necessariamente esistere, perché L è infinito). Se x è apparso nell’enumerazione, allora M stampa 1 in uscita, altrimenti stampa 0. Esercizio 3 Per produrre i valori desiderati è sufficiente una MT a 1 nastro di memoria, che funziona nel seguente modo: Legge un simbolo dal nastro in ingresso. Scrive 1 sul santro di output. Copia tutti gli 0 (leggendoli da sinistra a destra) dal nastro di memoria al nastro di output, ed aggiunge in fondo al nastro di output un #. Mette due 0 sul nastro di memoria (la testina è ora in fondo al nastro di memoria). Torna all’inizio del nastro di memoria, leggendo gli 0 da destra a sinistra, e poi ricomincia da capo. Per il calcolo della complessità spaziale conta solo il nastro di memoria, non il nastro di input, né quello di output, quindi la complessità è Θ(n). Per il calcolo della complessità temporale, il costo della i-esima iterazione del ciclo è Θ(2i), quindi il costo totale è ∑i={1..n} 2i, che è Θ(n2). Esercizio 4 1. Il comportamento dell’algoritmo è determinato dalla scelta del “pivot” che nel nostro caso è l’ultimo elemento dell’array. Perciò se l’array è già ordinato la partizione è totalmente sbilanciata. In questo caso perciò conviene scegliere come pivot l’elemento mediano, in modo che la partizione lasci inalterato l’array e così via ricorsivamente ottenendo una complessità O(n⋅log(n)). La modifica dell’algoritmo in tal senso può semplicemente consistere nel premettere al codice di PARTITION l’istruzione k = (r + p)/2 e usare A[k] come pivot, ossia scambiare A[k] con A[r]. Alla fine della partizione, l’array tornerà nella permutazione originaria già ordinata e così via ricorsivamente. 2. Ovviamente anche la versione così modificata ha un comprtamento O(n2) nel caso pessimo che si verifica quando l’array è tale che il pivot è sempre il massimo dell’array che rimane da ordinare. Quindi, prendendo come esempio un array di lunghezza pari, l’elemento di mezzo è il massimo, il secondo elemento più grande è l’ultimo, ecc. Un esempio di tale array è [2, 4, 6, 8, 10, 5, 3, 7, 1, 9], che dà luogo alla seguente sequenza di chiamate (la parte non in grassetto è l’array di sinistra in ogni successiva chiamata di Quicksort, la parte in grassetto sono i pivot, e l’array di destra è sempre vuoto): [2, 4, 6, 8, 10, 5, 3, 7, 1, 9] [2, 4, 6, 8, 9, 5, 3, 7, 1, 10] [2, 4, 6, 8, 1, 5, 3, 7, 9, 10] [2, 4, 6, 7, 1, 5, 3, 8, 9, 10] [2, 4, 6, 3, 1, 5, 7, 8, 9, 10] [2, 4, 5, 3, 1, 6, 7, 8, 9, 10] [2, 4, 1, 3, 5, 6, 7, 8, 9, 10] [2, 3, 1, 4, 5, 6, 7, 8, 9, 10] [2, 1, 3, 4, 5, 6, 7, 8, 9, 10] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Algoritmi e Principi dell’Informatica Appello del 15 Settembre 2016 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (8 punti) In matematica, si definiscono numeri primi gemelli due numeri primi che differiscano tra loro di 2. La congettura dei numeri primi gemelli afferma che esistono infinite coppie di numeri primi gemelli. Specificare tale congettura mediante una formula di logica del prim’ordine. Nella specifica è consentito utilizzare: come funzioni, le usuali quattro operazioni aritmetiche; come costanti, i numeri naturali 0, 1, 2, …; come predicati, il predicato di uguaglianza (=), i comparatori (<, >, , ) e un predicato unario nat che indica che il suo argomento è un numero naturale. È inoltre possibile, e consigliabile, specificare dei predicati ausiliari per render più agevole la scrittura e la comprensione della formula; tuttavia la semantica di tali predicati dovrà essere esplicitamente definita mediante opportune formule che facciano riferimento ai simboli base di cui sopra. Esercizio 2 (9 punti) Punto a) Ad oggi, la più grande coppia di numeri primi gemelli trovata è 3756801695685 · 2666669 ± 1. Si tratta di numeri con ben 200700 cifre, ma non è ancora stato dimostrato l’enunciato della congettura, che potrebbe quindi anche essere falsa. Che cosa si può concludere in merito alla decidibilità dell’enunciato della congettura? Punto b) Sia f una funzione definita come segue: f(x) = 1 se esiste una coppia di numeri primi gemelli maggiori di x; f(x) = 0 altrimenti. La funzione f è calcolabile? Esercizio 3 (9 punti) Si consideri il linguaggio Lq di figure definito sull’ alfabeto {a, b}, composto da tutte e sole le figure quadrate fatte da righe di soli simboli 'a' alternate a righe di soli simboli 'b', partendo con le 'a'. Es. aaaa bbbb aaaa bbbb Si descrivano esaurientemente due macchine di Turing che accettino Lq, una a k-nastri e una a nastro singolo, sapendo che la figura è fornita sul nastro in ingresso riga per riga e senza separatori, e se ne studino le complessità spaziali e temporali. Esercizio 4 (7 punti) Sia dato un vettore di interi, A, ordinato in ordine non decrescente. Sia dato inoltre un valore intero v. Si definisca un algoritmo che verifichi se A contiene due elementi ai e aj tali che ai – aj = v. Il punteggio dell’esercizio sarà commisurato alla complessità temporale dell’algoritmo. Tracce delle soluzioni Esercizio 1 Definisco per comodità un predicato che cattura il concetto di numero primo: x (primo(x) nat(x) ¬yz x = yz nat(y) nat(z) y>1 z>1) La congettura è quindi specificata come segue: x (nat(x) yz y>x primo(y) z=y+2 primo(z)) Esercizio 2 Punto a) Si tratta di una questione certamente decidibile poiché la formula che la specifica è chiusa. Punto b) Se la congettura dei numeri primi gemelli è vera, allora la funzione f vale costantemente 1, ed è pertanto calcolabile. Se la congettura è falsa, allora esiste un numero k oltre il quale non è più vero che esistono due numeri primi gemelli (e prima del quale esistono). Pertanto la funzione f sarà fatta a “scalino”, e sarà pari a 1 per ingressi minori di k, e pari a 0 per ingressi maggiori o uguali a k. Anche in questo caso la funzione è certamente calcolabile. Esercizio 3 Macchina a k-nastri: si legge la prima sequenza di ‘a’ copiandole su 2 nastri di memoria; poi il primo nastro viene utilizzato per contare il numero di elementi di ogni riga, mentre il secondo serve per contare il numero di righe. Chiaramente basta una passata sulla stringa in ingresso. Siano m gli elementi di una riga, la stringa è lunga n = m2, mentre la memoria occupata risulta 2m. Quindi: S(n) = ( ), T(n) = (n). Macchina a nastro singolo: l’idea è controllare la lunghezza di ogni riga, cambiando di volta in volta le ‘a’ in ‘A’ e le ‘b’ in ‘B’ riga per riga, da sinistra verso destra, a parte i primi elementi di ogni riga che verranno cambiati in ‘X’. In questo modo possiamo controllare che tutte le righe siano lunghe uguali, facendo (nm) mosse. Per controllare che il numero di righe sia corretto, la macchina può controllare che il numero delle ‘X’ sia uguale al numero di ‘A’ della prima riga + 1, facendo ulteriori (nm) mosse (ad esempio cambiandoli uno alla volta in altri simboli). Quindi: S(n) = (n), T(n) = (n ). Esercizio 4 Una soluzione banale, ma poco efficiente, controlla tutte le coppie, A[i], A[j], con 1 ≤ i < j ≤ A.lenght, per verificare se A[j] - A[i] = v. La complessità di tale soluzione è O(n2). È possibile poi definire una soluzione con complessità O(n log n). Per ognuno degli n elementi dell’array, A[i], si applica una ricerca binaria agli elementi successivi per cercare un elemento pari a v+A[i]. CercaCoppia-RicercaBinaria (A, v) { for i = 1 to A.length if (RicercaBinaria(A[i + 1 . . . A.length], v + A[i])) return true; return false; } È infine possibile ottenere una soluzione più efficiente, di complessità O(n), scandendo gli elementi in modo lineare tramite un opportuno incremento di due indici, i e j: CercaCoppia-Lineare (A, v) { i = 1; j = 2; while (j ≤ A.length) if ((A[j] − A[i]) < v) j = j + 1; else if ((A[j] − A[i]) > v) i = i + 1; else return true; return false; } A ogni iterazione, si incrementa j oppure i A ogni iterazione j ≥ i; si eseguono quindi O(n) iterazioni. oppure si esce dalla funzione. Algoritmi e Principi dell’Informatica Prova in itinere del 24 novembre 2016 Il tempo per completare la prova è 1 h e 45 minuti. Esercizio 1 (punti 7/15) Si consideri un semplice linguaggio di programmazione LP1 che tratta solo interi (NB: l’insieme matematico degli interi, non quello limitato del C) e array (non limitati a compile-time) di interi, ed è dotato delle normali istruzioni di assegnamento (variabile = espressione), dell’istruzione condizionale if-then-else e del ciclo while. Si consideri poi un linguaggio LP2 che differisce da LP1 in quanto invece del ciclo while ha il costrutto for definito da questa sintassi: for <variabile di tipo intero> = <costante intera1> to <costante intera2> do {<corpo del ciclo>} in cui <costante intera2> <costante intera1> e la cui semantica consiste in: Inizializzare la variabile intera, diciamo i, con il valore <costante intera1>, eseguire il corpo del ciclo, incrementare di un’unità i, uscire dal ciclo quando i è maggiore di <costante intera2> NB1: il corpo del ciclo non può contenere assegnamenti ad i. E’ decidibile il problema di stabilire se, dato un generico programma scritto in LP1 ne esiste un altro ad esso equivalente in LP2? Spiegare brevemente la risposta. Esercizio 2 (punti 5/15) Specificare in logica del prim’ordine un predicato unario pal che indica che il suo argomento è una stringa palindroma (cioè che non cambia se letta da sinistra verso destra o da destra verso sinistra) servendosi esclusivamente dei seguenti predicati, funzioni e costanti: • • • • il predicato unario char che è vero se e solo se il suo argomento è una stringa di lunghezza 1; il predicato (binario) = che rappresenta l’uguaglianza tra stringhe; la funzione binaria • che rappresenta la concatenazione di stringhe; la costante ε, che rappresenta la stringa vuota. Esercizio 3 (punti 4/15 per le parti a) e b), + 2 per la parte c); NB: la parte c) verrà valutata solo per chi abbia svolto correttamente le due parti precedenti). Si consideri il linguaggio L delle stringhe palindrome costruite sull’alfabeto {a,b} (per la definizione di “palindromo” si veda l’esercizio precedente). a) Definire una grammatica, a potenza generativa minima, che generi L. b) Costruire un automa, a potenza riconoscitiva minima, che riconosca L. c) Definire una grammatica, a potenza generativa minima, che riconosca il complemento di L. Soluzioni Esercizio 1 E’ ben noto che i costrutti base di LP1 sono sufficienti per dare al linguaggio la potenza della MT (è un facile esercizio codificare una qualsiasi MT in LP1). Al contrario LP2 non ha tutta la potenza della MT (tra l’altro i suoi programmi terminano sempre). Quindi i problemi (in questo caso funzioni definite su numeri interi) risolvibili da LP2 sono un sottoinsieme proprio non vuoto dei problemi ricorsivamente enumerabili. Se fosse possibille decidere il problema suddetto sarebbe perciò anche possibile decidere se una generica MT risolve un problema della famiglia dei problemi risolvibili con LP2, violando il teorema di Rice. Esercizio 2 ∀x (pal(x) ↔ x=ε ∨ char(x) ∨ ∃y∃z char(y) ∧ (y • z) • y = x ∧ pal(z)) Esercizio 3 a) S aSa | bSb | a | b | ε b) E’ sufficiente un NDPDA che, nondeterministicamente, individua il punto di mezzo del palindromo (di un carattere, se la stringa è di lunghezza dispari, o di zero caratteri se la stringa è di lunghezza pari). Non è possibile individuare tale punto deterministicamente prima di aver letto interamente la stringa, quando è ormai troppo tardi per determinare se si tratti di un palindromo. a,A/AA a,B/AB a,Z0/AZ0 a,A/ε b,B/ε b,A/BA b,B/BB b,Z0/BZ0 q0 a,A/A a,B/B a,Z0/Z0 b,A/A b,B/B b,Z0/Z0 ε ,A/A ε ,B/B ε ,Z0/Z0 c) S aSa | bSb | aTb | bTa T Ta | Tb | a | b | ε ε ,Z0/Z0 q1 q2 Algoritmi e Principi dell’Informatica Midterm test, November 24th 2016 English version The available time is 1 h and 45 minutes Exercise 1 (score 7/15) Consider a simple programming language LP1 that manages only the Integer data type (unlike languages such as C, Integer is the infinite mathematical set of integers) and (unbounded) arrays of integers. LP1 contains exclusively: Assignment statements (variable = expression) Conditional statements (if-then-else) while loops Then, consider another language LP2 that differs from LP1 in that instead of while loops offers only for loops defined as for <integer variable> = <integer constant1> to <integer constant2> do {<body of the loop>} where < integer constant2> <integer constant1> The execution of the for loop is specified as follows: The integer variable, say i, is initialized with the value <integer constant1> The body is executed The variable i is incremented by 1 The loop is exited when i becomes greater than <integer constant2> NB: the loop body cannot contain any assignment to the variable i. Consider the problem of stating whether, given a generic program P1 coded by means of LP1, there exists another program P2 in LP2 equivalent to P1. Is such a problem decidable? Explain briefly your answer. Exercise 2 (score 5/15) Give a first-order formula that specifies a unary predicat pal(x); pal(x) must be true if and only if x is a palindrome, i.e. a string that is the same whether it is read left-to-right or right-to-left. Your formula can make use exclusively of the following predicates, functions and constants, besides pal: The unary predicate char, which is true if and only if its argument is a string of length 1; The binary predicate ‘=’, which denotes string equality; The binary function •, which denotes string concatenation; The constant ε, which denotes the empty string. Exercise 3 (score 4/15 for parts a) and b), + 2 extra points for part c). Notice however that part c) will be evaluated only if the previous parts are correct.) Let L be the language of palindromes (see previous exercise 2) over the alphabet {a,b}. a) Write a grammar, belonging to the class of minimum possible generating power, that generates L. b) Write an automaton, belonging to the class of minimum possible recognizing power, that recognizes L. c) Write a grammar, belonging to the class of minimum possible generating power, that generates the complement of L. Algoritmi e Principi dell'Informatica Seconda Prova in Itinere 31 Gennaio 2017 Avvisi importanti Il tempo a disposizione è di 1 ora e 45 minuti. Esercizio 1 (punti 7/15-esimi) Si consideri un tipo di macchina di Turing (MT) con nastro di memoria bidimensionale consistente nel primo quadrante del piano cartesiano intero (N N) e nastro di ingresso monodimensionale. Una mossa della MT può gestire il nastro di input come una normale MT a k nastri e spostare la testina del nastro bidimensionale di una posizione in orizzontale o in verticale. Si descriva, con sufficiente precisione, come una RAM possa simulare una tale MT e se ne valuti la complessità temporale (al solito maggiorandone l’ordine di grandezza) in funzione della complessità TM(n) della MT, ossia TR(n) O(f(TM(n))), usando sia il criterio di costo costante sia quello logaritmico. Esercizio 2 (punti 7/15-esimi) Sia dato un vettore di n numeri reali non nulli. Si progetti un algoritmo che modifichi il vettore spostando tutti gli elementi negativi prima di quelli positivi (senza introdurre alcun ordinamento particolare tra i valori negativi e quelli positivi e senza necessariamente preservare l’ordinamento originariamente presente nella sequenza di input). Si specifichi chiaramente l’algoritmo, preferibilmente mediante pseudocodice, e se ne discuta la complessità. La valutazione terrà conto della complessità computazionale della soluzione proposta. Esercizio 3 (punti 4/15-esimi) 1. Si consideri una variante della ricerca binaria, detta "ricerca ternaria", che divide la sequenza di input di n elementi in 3 partizioni di dimensione n/3 (al solito a meno di arrotondamenti). Si determini e si risolva l’equazione alle ricorrenze che esprime la complessità dell’algoritmo ricerca ternaria. 2. Si consideri un’altra variante che divide la sequenza di input in due partizioni di dimensione n/3 e 2n/3. Si determini e si risolva l’equazione alle ricorrenze per questa seconda variante. NB: al solito la soluzione dell’equazione alle ricorrenze va fornita in termini di ordine di grandezza, preferibilmente mediante la notazione . Tracce di soluzioni Esercizio 1 Una prima soluzione potrebbe consistere nel memorizzare il contenuto del nastro bidimensionale “per righe” o “per colonne” come avviene nella memoria di un normale calcolatore per gli array. Tuttavia, come accade quando un linguaggio di programmazione permette di variare le dimensioni dell’array a run-time, ogni volta che la MT “entra in nuova riga o colonna” occorre spostare una quantità di celle della memoria della RAMche è dell’ordine di grandezza dell’intera memoria al momento in uso, con evidente aumento complessivo della complessità temporale. Una soluzione più efficiente consiste invece nello sfruttare una corrispondenza biunivoca N N N di tipo diagonale, ad esempio la classica d ( x, y ) ( x y )( x y 1) x 2 In questo modo la RAM memorizza solo il contenuto delle celle effettivamente utilizzate dalla MT. Più precisamente: Vengono allocate due celle x e y per memorizzare il valore corrente delle coordinate del nastro di memoria della MT e n celle per copiare l’input della MT nella memoria della RAM (richiede O(n)). La posizione della cella della RAM corrispondente a quella di coordinate <x, y> della MT è quella calcolata dalla funzione d di cui sopra (sommato alle (O(n) celle allocate inizialmente). Ogni mossa della MT è simulata dalla RAM nel modo seguente: o Calcola m = d(x.y) (+ l’offset di cui sopra), in tempo costante o O(log(x) + log(y)) O(log(TM(n))) a seconda del criterio di costo adottato; a sua volta m è O(TM(n)). o Sulla base del contenuto di m e dello stato della MT, simula la sua mossa aggiornando il contenuto di m, dello stato e di x e y (in tempo costante o O(log(m)), ossia O(log(TM(n))) a seconda del criterio di costo). In conclusione la complessità temporale della RAM è O((TM(n)) a criterio di costo costante e O(TM(n).log(TM(n))) a criterio logaritmico. Esercizio 2 È possibile prendere spunto dalla procedura perno (o partition) di Quicksort considerando lo 0 come valore in base al quale individuare le due partizioni di valori negativi e positivi. Lo 0 è un valore opportuno, visto che la sequenza iniziale non contiene valori nulli. Così come previsto dalla funzione perno, è necessario scandire il vettore iniziale con due indici: neg, che cresce dalle posizioni più basse a quelle più alte, e pos che decresce nel verso contrario. Quando neg punta a un elemento positivo e pos a uno negativo si effettua uno scambio. Si prosegue fino a quando i due indici non si incrociano (neg > pos), il che indica che il vettore è stato interamente esaminato. La complessità dell’algoritmo è la stessa della funzione perno (O(n)). E’ possibile considerare anche un’altra soluzione di complessità O(n), ispirata al Counting sort. Tale soluzione ricopia gli elementi in un secondo vettore, B, secondo il seguente criterio: gli elementi negativi sono ricopiati in posizioni scandite dall’indice neg (che parte da sinistra ed è incrementato ogni volta che un numero negativo è ricopiato in B); gli elementi positivi sono ricopiati in posizioni scandite dall’indice pos (che parte da destra ed è decrementato ogni volta che un numero positivo viene ricopiato in B). Non è necessario utilizzare un terzo vettore, in quanto non abbiamo necessità di mantenere l’ordinamento dei valori presente nella sequenza di input. Ovviamente, si potrebbe utilizzare un algoritmo di ordinamento qualsiasi; questo tuttavia implicherebbe una complessità Ω(n log (n)) per produrre un ordinamento totale dei valori che non è invece richiesto. Esercizio 3 Ricordiamo che la ricorrenza per la ricerca binaria può essere espressa come T(n) = T(n/2)+1. Questa equazione tiene conto del costo per il confronto con l’elemento in posizione centrale, più il costo per la chiamata ricorsiva della funzione su una delle due partizioni che tale elemento determina. 1. L’algoritmo "ricerca ternaria" esegue due confronti con gli elementi in base ai quali si partiziona la sequenza in tre sotto-sequenze di n/3 elementi. Quindi, si richiama ricorsivamente la funzione su una partizione. Analogamente all’equazione della ricerca binaria, per la variante dell’algoritmo avremo T(n) = T(n/3) + 2. Tale equazione può essere risolta con il Teorema dell’Esperto (secondo caso) e ha soluzione (log n). 2. La seconda variante esegue un solo confronto per individuare le due partizioni di dimensione n/3 e 2n/3. Il caso pessimo si verifica quando la chiamata ricorsiva opera sulla partizione più grande (2n/3 elementi). In questo caso, la ricorrenza è T(n) = T (2n/3) + 1 e si risolve applicando il secondo caso del Teorema dell’Esperto. Quindi, nel caso pessimo T(n) è (log n). Nel caso ottimo (l’ordine di) complessità è lo stesso; quindi è possibile dire che la complessità dell’algoritmo è comunque (log n). Algoritmi e Principi dell'Informatica Second Test January 31, 2017 The time to complete the test is 1 hour and 45 minutes. Exercise 1 (7/15 points) Consider a Turing machine (TM) equipped with a bi-dimensional memory tape, consisting of the first quarter of the integer Cartesian plane (N N) plus the input tape, which is mono-dimensional. A transition of the TM manages the input tape as the usual k-tape machine and moves the memory head by one position either vertically or horizontally. Describe, with sufficient precision, how a RAM can simulate such a TM and evaluate the (order of magnitude of the) complexity of the RAM as a function of the TM complexity, i.e., TR(n) O(f(TM(n))); use both the constant and the logarithmic cost criteria. Exercise 2 (7/15 points) It is given an array of n real numbers other than 0. Design an algorithm that modifies the array by moving all negative numbers before the positive ones. It is not necessary to sort the numbers nor is it requested that the original ordering among them is preserved. The algorithm must be specified in a clear enough way, preferably by including a pseudocode thereof, in such a way that its complexity can be clearly evaluated. As usual, the lower the (asymptotic) algorithm complexity, the better is the solution. Exercise 3 (4/15 points) 1. Consider a variation of the classical (recursive) binary search algorithm, named “ternary search”: the algorithm divides the sorted sequence in 3 partitions of size n/3 (as usual, up to rounding.) Write the recurrence equation defining the algorithm complexity and solve it (in terms of the order of magnitude, preferably through the notation). 2. Then, consider another variation of the same algorithm that divides the original sequence in two parts of size n/3 and 2n/3, respectively, and give the equation and its solution for this version too. Algoritmi e Principi dell’Informatica Appello del 20 febbraio 2017 Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti. Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15 minuti. Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti. NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno valore puramente indicativo. Esercizio 1 (9 punti) Si consideri l’insieme S definito nel modo seguente: S = { i | i è l’indice di una macchina di Turing che accetta almeno una stringa } Si risponda alle seguenti domande, motivando opportunamente le risposte: a) S è ricorsivo? b) S è ricorsivamente enumerabile? c) Il complemento di S è ricorsivamente enumerabile? Si considerino ora gli insiemi seguenti: S1 = { i | i è un numero naturale e non è l’indice di una macchina di Turing che accetta almeno una stringa } S2 = { i | i è l’indice di una macchina di Turing che non accetta alcuna stringa } S3 = { i | i è l’indice di una macchina di Turing in cui almeno una stringa non è accettata } d) Per ognuno degli insiemi S1, S2 e S3, dire se rappresenta il complemento di S. Esercizio 2 (8 punti) Si consideri la grammatica G seguente (con le usuali convenzioni alfabetiche): S aaAbc A aAb | c Sia L il linguaggio generato da G: si fornisca una specifica logica di L. NB: nello scrivere la formula che specifica L si può fare uso esclusivamente dei seguenti elementi, oltre agli usuali connettivi logici proposizionali, quantificatori e punteggiatura: Lettere di “variabili stringhe” x, y, z, … che assumono valori in {a,b,c}* Lettere di “variabili linguaggio” L, L1, L2, … (Il simbolo è L è “riservato” per L(G)) Le costanti a, b, c Il simbolo di concatenazione tra stringhe ‘.’ (usato con notazione infissa; si può darne per scontata l’associatività, se ne può anche omettere la scrittura quando ciò non generi dubbi interpretativi: ad esempio, ab abbrevia a.b) Il simbolo di appartenza ‘’ (di una stringa a un linguaggio) Il simbolo di uguaglianza ‘=’. Esercizio 3 (8 punti se non si sceglie la parte opzionale; 11 punti se si sviluppa correttamente ed esaurintemente la parte opzionale) Siano dati due alberi BST (Binary search tree) bilanciati, ossia tali che le lunghezze dei vari cammini dalla radice alle foglie differiscano al massimo di 1. Si scriva un’algoritmo che determini se i due alberi abbiano intersezione non nulla. Ovviamente la qualità della soluzione dipenderà primariamente dalla sua complessità asintotica. Parte opzionale (da svolgere in alternativa, non in aggiunta alla precedente ma esclusivamente se si è sicuri di poterla portare a termine con sufficiente chiarezza e a complessità non superiore alla soluzione non vincolata.) Si costruisca un algoritmo per risolvere lo stesso problema in modo da non dover utilizzare memoria aggiuntiva, dove per memoria aggiuntiva rispetto ai dati in ingresso si intende memoria di dimensionni dipendenti dai dati, ossia non O(k). NB: un algoritmo che non faccia uso di memoria aggiutiva ma abbia complessità superiore a quello che invece ne fa uso viene considerato di qualità inferiore ad esso. Esercizio 4 (7 punti) Si considerino due insiemi di interi S = {s1, s2, ..., sm} e T = {t1, t2, ..., tn}, m ≤ n. a. Si specifichi un algoritmo che faccia uso di una tabella hash di dimensione m, gestita con il metodo del concatenamento, per verificare se S è un sottoinsieme di T. Se ne discuta la complessità, utilizzando l’analisi del caso medio. N.B. Non è necessario definire la funzione H per l’accesso alla tabella; si supponga che questa sia già definita e che distribuisca le chiavi in tabella in modo abbastanza uniforme, ciò che giustifica l’uso dell’analisi del caso medio. b. Si discuta se l’utilizzo della tabella hash introduce vantaggi in termini di complessità rispetto ad altre possibili soluzioni. Soluzioni Esercizio 1 a) Ricadiamo chiaramente nelle ipotesi di applicazione del teorema di Rice: l’insieme di funzioni considerate non è né l’insieme vuoto (c’è almeno una macchina di Turing che accetta almeno una stringa), né l’insieme di tutte le funzioni computabili (non tutte le macchine di Turing accettano almeno una stringa), pertanto l’insieme S non è ricorsivo. b) Per stabilire che S è ricorsivamente enumerabile si può, ad esempio, mostrare che S è l’insieme di definizione di una funzione f (parziale e) computabile. Tale funzione f è implementata da una macchina di Turing che procede come segue. Per un dato indice i, simula il comportamento di della i-esima macchina di Turing Mi; partendo da n=0 e m=1, verifica, per ogni stringa x di lunghezza n, se in m passi Mi accetta x, e procede enumerando (n,m) con la solita tecnica diagonale (0,1), (1,1), (0,2), (2,1), (1,2), (0,3), … fino a che non trova una stringa accettata da Mi, se esiste. Si noti che, fissato n, è sempre possibile enumerare tutte le stringhe di lunghezza n in tempo finito. Pertanto, se esiste una stringa di lunghezza n’ accettata da Mi in un numero di passi m’, questa viene prima o poi enumerata con il procedimento sopra illustrato; se non esiste, tale procedimento non termina. c) Il complemento di S non può essere ricorsivamente enumerabile. Se lo fosse, sia S sia il suo complemento sarebbero ricorsivamente enumerabili (vedi punto precedente), pertanto si potrebbe concludere che S è ricorsivo, ma al punto a) abbiamo mostrato che non lo è. d) L’insieme S1 è esplicitamente definito come il complemento ℕ - S di S, cioè l’insieme degli indici che non stanno in S. L’insieme S2 è definito come l’insieme degli indici che godono della proprietà opposta (l’opposto di accettare almeno una stringa è non accettare alcuna stringa) di quella goduta dagli indici che stanno in S, e quindi è ancora una volta il complemento di S. L’insieme S3 invece non è il complemento di S, infatti una stessa macchina di Turing può accettare una stringa (e quindi avere l’indice in S) e non accettarne un’altra (e quindi avere l’indice anche in S3). Esercizio 2 L(G) è chiaramente il linguaggio {aa.ancbnbc | n 0}. L’appartenenza di x a L(G) può essere quindi espressa dalla formula seguente: x L ((x = aacbc) y, z, w (y = aazcwbc y L x = aaazcwbbc))) Esercizio 3 Una soluzione banale consiste nel visitare tutti i nodi dell’albero A1, ad esempio mediante una visita in post-ordine e per ognuno di essi fare una ricerca del suo valore su A2. Essendo entrambi gli alberi bilanciati ogni ricerca costa log(n) e quindi la complessità totale è O(n.log(n)), dove n è il masssimo tra le cardinalità dei due alberi; se la differenza tra esse fosse notevole, converrebbe applicare la visita esaustiva all’albero di cardinalità minore. Una soluzione più efficiente, che però richiede l’allocazione di memoria extra consiste nello sviuppare entrambi gli alberi in array ordinati; questo può essere fatto con una visita in-ordine (figlio di sinistra, radice, figlio di destra) e complessità O(n); indi scandire “in parallelo” i due array confrontandoli mediante due rispettivi indici: se si trova una coppia A1[i] = A2[j] la ricerca ha successo altrimenti se A1[i] < A2[j] si incrementa i e viceversa se A1[i] > A2[j], ottenendo così una complessità O(n). Un algoritmo più sofisticato che opera direttamente sugli alberi senza “travasarli” in array è invece descritto a grandi linee nel modo seguente: Esso trae ispirazione dall’algoritmo precedente ma semplicemente esegue la scansione ordinata direttamente sui due alberi: 1. Determino i minimi dei due alberi (le foglie più a sinistra) , con complessità O(log(n)); 2. Proseguo eseguendo gli stessi confronti del precedente algoritmo semplicemente sostituendo l’incremento degli indice degli array con il calcolo del successore. Per valutare la complessità dell’algoritmo, con riferimento alla figura sottostante, si osservi che: 1. Il successore delle foglie che sono figli di sinistra, che sono ≤ n/2, è il loro padre, a distanza 1 = 20 da esse. 2. Il successore successore delle foglie che sono figli di destra, che sono ≤ n/2, è il padre del loro primo antenato che è figlio di sinistra, che per metà di esse si trova a distanza 2, per 1/4 di esse si trova distanza 3, , per 1/8 a distanza 4, … 3. Il successore di un nodo interno si trova a una distanza ≤ dell’altezza del sottoalbero di cui esso è radice. In entambi i casi 2 e 3 il costo complessivo delle varie chiamate alla procedura Successore è maggiorato dalla formula log(n ) h 0 n 2 h1 .O(h) O(n) come mostrato ad esempio nello sviluppo dell’algoritmo heap-sort. Quindi il numero di chiamate al Successore è O(n) e così pure la complessità dell’intero algoritmo. 0 2 1 2 22 3 2 4 2 Esercizio 4 Punto a. H è la tabella hash di dimensione m. Sottoinsieme_Hash (T, S, n, m) per ogni ti in T inserisci(H, ti) //inserimento in testa alla lista per ogni sj in S trovato = ricerca(H, sj) if (!trovato) return False return True Inserire tutti gli elementi di T nella tabella H con il metodo del concatenamento richiede una complessità nΘ(1) = Θ(n) Se S è un sottoinsieme di T, l’algoritmo eseguirà al più m ricerche con successo; quindi la complessità del secondo ciclo for sarà m(1+alfa) = O (m + n) Se S non è un sottoinsieme di T, allora nel caso pessimo tutti gli elementi, tranne l’ultimo in S, sono in T. Saranno quindi eseguite m-1 ricerche con successo e una senza successo. La complessità del ciclo di ricerca è comunque O(m + n). La complessità dell’algoritmo è quindi O(n). Punto b. Una soluzione alternativa, diversa da quella ovvia (ma inefficiente) che confronta ogni elemento di S con gli elementi di T, potrebbe ordinare gli elementi di T e poi usare la ricerca binaria per cercare le occorrenze degli elementi di S in T: Sottoinsieme_RicercaBinaria(T,S,n,m) Ordina (T) per ogni sj in S trovato = RicercaBinaria(T, sj) if (!trovato) return False return True Tale soluzione avrebbe complessità O(n.log(n) + m.log(n)) che è meno vantaggiosa rispetto alla complessità ottenuta con l’uso della tabella Hash. NB: in tal caso si tratterebbe di complessità nel caso pessimo, apparentemente non ben confrontabile con il caso medio utilizzato per l’uso della tabella Hash; tuttavia in gran parte dei casi normali la complessità di algoritmi di sorting a caso pessimo O(n.log(n)) è O(n.log(n)) anche nel caso medio. Algoritmi e Principi dell’Informatica English version February 20, 2017 Total time available is 2h 30'. If you are registered for the first module only (Informatica Teorica), you must solve Exercises 1 and 2 in 1h 15’. If you are registered for the second module only (Informatica 3), you must solve Exercises 3 and 4 in 1h 15’. Exercise 1 (Points 9) Let S be a set of natural numbers defined as: S = { i | i is the index of a Turing machine that accepts at least one word} Answer the following questions and briefly motivate your answers: a) Is S recursive? b) Is S recursively enumerable? c) Is S’s complement recursively enumerable? Then consider the following sets of natural numbers: S1 = { i | i is not the index of a Turing machine that accepts at least one word } S2 = { i | i is the index of a Turing machine that does not accept any word } S3 = { i | i is the index of a Turing machine that does not accept at least one word } Exercise 2 (Points 8) Consider the following grammar G (with the usual alphabetic conventions): S aaAbc A aAb | c Let L be the language generated by G: build a logic formula specifying L. NB: in writing your formula you can use exclusively the following symbols, besides the usual propositional operators, quantifiers, and punctuation markers: Letters denoting “string variables” x, y, z, … which take value in {a,b,c}* Letters denoting “language variables” L, L1, L2, … (Symbol L is “reserved” for L(G)) Constants a, b, c The concatenation symbol ‘.’ (used through the standard infix notation; you can give for granted its associativity and can omit it if no ambiguity may arise e.g., abc is an abbreviation for (a.b).c The symbol ‘’ (for a string belonging to a language) The equality symbol ‘=’. Exercise 3 (Points 8 for the standard version, 11 points for the optional version) Two balanced BST (Binary search trees) are given (remember that in a balanced BST the maximun difference among the length of paths from the root to the leaves is 1). Write an algorithm that states whether the two trees have empty intersection or not. Of course, the lower the complexity of your algorithm, the better your solution. Optional version, to be developed instead of the unconsrained one above, only if you are confident to be able to carry it over to competion in such a way that its complexity is not higher than that of the previous version. Solve the saame problem without using auxiliry memory, possibly excluding few extra variables whose global size is O(k). NB: An algorithm that does not use auxiliary memory but has a higher complexity than one that does it, is evaluated as of lower quality than the other one. Exercise 4 (Points 7) Consider two sets of integers S = {s1, s2, ..., sm} and T = {t1, t2, ..., tn}, m ≤ n. a. Build an algorithm that uses an hash table of size m, managed through the linked list method, that checks whether S is a subset of T or not. Discuss algrithm’s complexity in the average case. NB: It is not necessary to define the H function to access the table: just assume that it maps the set of keys into the m positions of the table with a reasonably uniform distribution (which is a good hypothesis to apply the average case analysis). b. Is the use of a hash table preferable, in terms of complexity, w.r.t. other pssible solutions? Briefly motivate your answer.