Appunti di Elementi di Informatica Teorica
Transcript
Appunti di Elementi di Informatica Teorica
Appunti di Elementi di Informatica Teorica by QuaDamge A. A. 2006/2007 <ultima modifica 4 Novembre 2010> si ringrazia Luke Bonham per gli errori segnalati e la realizzazione della dimostrazione del TEOREMA 3.2 (del contapassi) – INDICE – Linguaggi: I Lezione (pag. 1) : Introduzione al Corso – Alfabeti e Stringhe – Automi II Lezione III Lezione (pag. 5): Automi DFA – Linguaggi Regolari – Introduzione Automi NDFA (pag. 8): Automi NDFA – Relazione tra DFA ed NDFA (Teorema 2.1) IV Lezione (pag. 14): fine Teorema 2.1 – Proprietà di chiusura sui Linguaggi regolari V Lezione (pag. 19): Altre Proprietà di chiusura – Teorema di Kleene VI Lezione (pag. 26): Espressioni regolari e teoremi Seconda versione del Teorema di Kleene(prima parte) VII Lezione (pag. 29): Seconda versione del Teorema di Kleene (seconda parte) Pumping Lemma e teoremi conseguenti VIII Lezione (pag. 34): Esercitazione sugli automi e le Espressioni regolari Prima parte Grammatiche: VIII Lezione (pag. 37): Introduzione alle Grammatiche Seconda parte IX Lezione (pag. 39): Grammatiche C.F.: prime nozioni e teorema 1.2 (prima parte) X Lezione (pag. 43): teorema 1.2 (seconda parte) XI Lezione (pag. 46): Alberi di derivazione XII Lezione (pag. 48): toremi sulle Derivazioni e gli Alberi di derivazione Derivazioni estreme (a sx. e a dx.) – Grammatiche Branching XIII Lezione (pag. 52): teoremi sulla grammatica Branching e in Chomsky Normal Form – Pumping Lemma Proprietà di chiusura – Grammatiche Ambigue e Grammatiche Regolari XIV Lezione (pag. 57): Grammatiche Separatrici – teorema sulla Grammatica Regolare – Automi a Pila XV Lezione (pag. 62): Esempi sugli Automi Pushdown e relativi teoremi Prima parte Calcolabilità: XV Lezione (pag. 64): Introduzione ai Linguaggi di Programmazione – S-programmi Seconda parte XVI Lezione (pag. 71): Ricapitolazione e seguito concetti sugli S-programmi Funzioni parzialmente calcolabili – estensione delle Macro Predicati - composizione di Funzioni – Ricorsione XVII Lezione (pag. 79): Classi PRC – Funzioni e Predicati primitivi ricorsivi XVIII Lezione (pag. 86): Operazioni iterate e Quantificatori – Minimalizzazione altre Funzioni e Predicati primitivi ricorsivi XIX Lezione (pag. 98): Codifica numerica dei Programmi Interruzione di un Predicato e problema dell’insolvibilità dell’arresto XX Lezione (pag. 103): Teorema dell’universalità – Programma Universale Insiemi ricorsivi, non ricorsivi e primitivi ricorsivi XXI Lezione (pag. 112): Teorema della Forma Normale – Minimalizzazione propria Insiemi ricorsivamente enumerabili e relativi teoremi Esercitazione finale (pag. 120) Modifiche apportate (pag. 124) Lettere greche utilizzate: D alfa - E beta - J gamma - * gamma in maiuscolo - G delta - ' delta in maiuscolo H epsilon - Q ni - 3 pi in maiuscolo - V sigma - 6 sigma in maiuscolo - W tau ) phi in maiuscolo - \ psi - : omega in maiuscolo Linguaggi Prima Lezione 26/09/2006 Introduzione al Corso – Alfabeti e Stringhe Automi Breve Introduzione Il Corso di Elementi di Informatica Teorica si prefigge il compito di analizzare prevalentemente problemi di: DECISIONE e di GENERAZIONE Al primo caso appartengono ad esempio problemi del tipo: “x è un numero primo ?”, mentre al secondo appartengono problemi del tipo, ad esempio : “qual è l’ennesimo numero primo?”. Nozioni di base – Alfabeti e Stringhe (rif. D.S.W. pag. 4) DEFF.: l’ALFABETO A è un insieme finito e non vuoto di simboli; Dall’alfabeto si generano le parole: la PAROLA o STRINGA su A: è una n-pla di simboli di A Denotata così: a1 , a2 ,! , an o più semplicemente a1 a2 ! an . Se u a1 a2 ! an allora la LUNGHEZZA di u è n e si scrive: u n e può essere vista come la funzione che, avendo come argomento u, restituisce la lunghezza di u. PAROLA NULLA o STRINGA VUOTA: è la parola H o 0, la quale, come vedremo, è importante ad esempio per le definizioni e dimostrazioni per induzione. Risulta: H 0 oppure 0 0 e u0 0u u, u (non bisogna fare confusione tra il simbolo 0, come stringa vuota, e 0, come numero zero). L’insieme di tutte le parole su A è denotato con A e si legge: “A stella”, oppure “A star”. ^a , b` allora A ^0, a , b , ab , ba , aa , bb , aab , bba , bbb ,...` Il linguaggio A è infinito. Se A 2 Con LINGUAGGIO si intende un sottoinsieme L di A : L A , quindi un linguaggio può essere infinito (a differenza dell’alfabeto A). Due linguaggi banali sono: A e L L . CONCATENAZIONE: se due stringhe u, v A , con la scrittura: l o semplicemente uv uv si indica la stringa che si ottiene ponendo (giustapponendo) la stringa v dopo la stringa u. Un’inferenza immediata (conseguenza della definizione appena data) è che: uv vu u v . CONCATENZAZIONE REITERATA: se u A , per convenzione si avrà: u>1@ 0 e u >n @ u , u >0@ uuu ! uu , n t 0 n volte n (le parentesi quadre all’apice [] possono anche essere omesse, avremo quindi u in luogo di u u >n @ Risulta chiaramente: SCRITTURA AL CONTRARIO: se u A , u uR Risulta in particolare: 0R >n @ ). n u . a1a2 ! an 1an , avremo: an an 1 ! a 2 a 1 . 0 e, se u a con a A , u R u. Automi (rif. D.S.W. pag 237) Un AUTOMA finito, detto anche DFA (deterministic finite automaton), è una struttura matematica che rappresenta un dispositivo (non necessariamente realizzabile nella pratica, non avendo infatti limiti, essendo un concetto teorico) che “prende in input” una stringa, un simbolo alla volta, da sinistra a destra e cambia il suo stato interno, ovvero avvengono delle eventuali modifiche della struttura (nella pratica la dimensione dell’input potrebbe essere un problema, data la complessità del problema in termini di spazio e di tempo). L’esempio più semplice (e quello che si utilizzerà per i fini di questo corso) è quello di automa che riconosce o meno un linguaggio, tale automa “riceve in input” parole di un determinato linguaggio e “dà in output” due possibili valori: “SI” oppure “NO” (tali valori corrispondono allo stato in cui perverrà l’automa alla fine della lettura, tale concetto sarà chiaro a breve). L’input è rappresentato da una sequenza finita di simboli che può essere arbitrariamente lunga. EDIT by Qd – Linguaggi – I Lez. 3 Formalmente Q un ^q1 , q2 ,!, qm ` ; AUTOMA FINITO ` sull’alfabeto A ^s1 , s2 ,!, sn ` ; con Stati F Q detto Insieme degli Stati di Accettazione (o stati finali); q1 per convenzione è lo Stato Iniziale; costituito dalla Funzione G detta di Transizione che associa ad ogni coppia qi , s j uno stato qk : G : Q u A o Q , con qi , qk Q e A,Q , F , q1 , G . è la quintupla: ` 1di dm ; 1d j dn Nel caso dell’esempio di automa che riconosce o meno una data stringa u, se alla fine della lettura della stringa (partendo dallo stato iniziale), l’automa si trova in uno stato q F allora diremo che l’automa accetta la stringa u, se invece, alla fine della lettura di tutti i simboli di u, l’automa perviene in uno stato q Q F , vorrà dire che l’automa non ha accettato la stringa. Esempio di automa finito ` : A ^a , b ` , F ^q ` , Q ^q , q , q , q ` 3 1 2 3 4 Dalla tabella di transizione (che rappresenta i possibili valori che assume la funzione di transizione) si evince che se l’automa si trova ad esempio nello stato q2 e riceve in input il simbolo a, non cambia stato, analogamente succede quando si trova nello a b G stato q3 e riceve in input il simbolo b. Lo stato q4 invece rappresenta uno q1 q2 q 4 stato trappola (o pozzo) in quanto, nel momento in cui l’automa perviene q2 q 2 q3 allo stato q4 ci resta per sempre, indipendentemente dal simbolo che legge. q3 q 4 q3 q4 q4 a q4 A destra la rappresentazione grafica dell’automa ` appena descritto, mediante grafi (la freccia sul cerchio dello stato q1 indica che quello è lo stato iniziale, mentre il doppio cerchio indica uno stato di accettazione: a q2 b q1 q3 b b Ora che è stato definito l’automa ` verifichiamo, ad esempio, che sia accettata la stringa baba: q4 a G q1 , b q 4 , G q 4 , a q 4 , G q 4 , b q 4 , G q 4 , a q 4 . Riscontriamo subito che q4 F , quindi baba non è accettata da ` . EDIT by Qd – Linguaggi – I Lez. b a 4 Vediamo invece la stringa aabbb: G q1 , a q 2 , G q 2 , a q 2 , G q 2 , b q 3 , G q 3 , b q 3 , G q 3 , b q 3 . q3 F , quindi la stringa aabbb è accettata dall’automa. Nozione di G * : Rappresenta un’estensione della funzione G alle stringhe. È detta funzione delta stella ( o delta star) e associa alla coppia qi , u lo stato qk Q con qi Q e u A . Il simbolo qk rappresenta lo stato a cui perverrà l’automa su A dopo aver letto (partendo dallo stato qi ) tutta la stringa u simbolo dopo simbolo. G :Q u A o Q da non confondere con G : Q u A o Q A è l’insieme delle stringe, mentre A è l’insieme dei simboli (alfabeto) Definiamo ricorsivamente G : x passo base G qi ,0 qi ; ovviamente se l’automa non riceve nulla in input, cioè la stringa vuota, il suo stato non cambierà, quindi resta in qi x passo ricorsivo G qi , v G G qi , u , s j se v us j . Per definire il passo ricorsivo per una generica stringa di lunghezza arbitraria non nulla, abbiamo spezzettato la stringa in due parti v us j dove u è una stringa (più piccola di v) ed s j è un simbolo (l’ultimo simbolo di v), se v k, u k 1. Poiché G qi , u qk , possiamo benissimo sfruttare la G (che conosciamo) per passarle come argomen- to G qi , u (il cui valore non è altro che uno stato) e il simbolo s j , quindi la scrittura G G qi , u , s j è ben formulata, essa rappresenta in pratica lo stato a cui perverrà l’automa quando avrà letto prima tutta la stringa u e poi il simbolo s j . La definizione ricorsiva è ben posta in quanto ogni stringa può essere passata come argomento a G e, nota la tabella di transizione dell’automa, si sarà in grado di calcolarla ricorsivamente (la presenza di s j ci assicura che G , nel passo ricorsivo, non riceva la stringa vuota). EDIT by Qd – Linguaggi – I Lez. Seconda Lezione 29/09/2006 Automi DFA – Linguaggi Regolari Introduzione Automi NDFA Nell’ambito degli automi, l’aspetto implementativo non ci interessa, è invece importante approfondire l’aspetto teorico, ci interessa studiare il funzionamento degli automi, ma non come potrebbero essere, nella pratica, realizzati. Ricapitolando, un automa ` è costituito dall’insieme A (alfabeto su cui opera), Q (insieme di tutti i possibili stati dell’automa, Q è un insieme finito), F (sottoinsieme -non proprio- di Q, rappresenta l’insieme degli stati di accettazione, o finali, di ` ), uno stato iniziale q1 Q e una funzione G (di transizione): Q u A o Q , q , s p j qk con q p , qk Q e s j A . Ricordiamo che G qi , u (con u stringa di A ) denota lo stato al quale accede un automa finito ` G , q1 , F Q , A se si trova prima nello stato qi all’estremità sinistra di u e poi quando ha completato la scansione di tutta la stringa (simbolo dopo simbolo), abbiamo: G :Q u A o Q x passo base G qi ,0 qi ; x passo ricorsivo G qi , v G G qi , u , s j se v us j ( G qi , u rappresenta lo stato di ` quando è stata letta tutta la stinga u). Esempio sull’uso di G : G qi , v = con v s j , possiamo scrivere v come stringa v G qi ,0s j G G qi ,0 , s j Quindi : 0s j G qi , s j G qi , v G qi , s j . Linguaggi L’insieme L A è detto linguaggio (in generale non è detto che A sia un linguaggio, un linguaggio a differenza del suo alfabeto può anche essere infinito, essendo un sottoinsieme di A ). Si dice che un linguaggio è regolare se esiste un automa ` che lo accetta (cioè che accetta tutti e soltanto i suoi elementi, ovvero tutte e soltanto le sue stringhe), un linguaggio accettato da ` si denota con L ` e formalmente si scrive: 6 L ` ^u A | G q1 , u F ` G , q1 , F Q , A . con ` Ciò significa che il linguaggio L è accettato da ` se è costituito (soltanto) da tutte le stringhe u A per cui ` , partendo dallo stato iniziale q1 , giunge in uno degli stati finali di ` , qk F . Un linguaggio non è regolare se non esiste alcun automa che lo accetta. In pratica L z L ` : u | G q1 , u Q F (quindi se vi è pure solo una stringa non accettata dall’automa, il linguaggio L non è regolare. TEOREMA: La regolarità di un linguaggio non dipende strettamente dall’alfabeto, come mostrato da quanto segue: B A sia L A e A B allora vale la seguente equivalenza: L è regolare, sia ` un automa che opera sull’alfabeto A e che accetta L , abbiamo che L ` c su B: L L ` c . Ad esempio: se A L ` ^a , b` e B ^a, b, c` allora ` (su A): L ` L ` c , con ` c su B; se chiaramente risulta L A , F ^q2 ` abbiamo: ` c: ` : a a q1 q1 q2 q2 c b b c a, b a, b q3 a, b Vediamo un sistema generale per dimostrare la biiezione: DIM. : Vogliamo dimostrare che se ` c su B che accetta L A ` su A che accetta L A (restrizione di G su A). È banale mostrare che ` c accetta L A se e solo se ` c perverrà allo stato finale senza leggere simboli o stringhe che contengono simboli appartenenti a B A , altrimenti L z L ` , o anche L A . EDIT by Qd – Linguaggi – II Lez. 7 DIM. : Vogliamo dimostrare che se ` su A che accetta L A ` c su B che accetta L. Partendo da ` , basta trovare almeno un ` c su B che accetta L (espansione), quindi poniamo: qi di ` G c qi , b q e simbolo b B A : e G c q , s q con q F s B Mentre le altre transizioni restano immutate rispetto a quelle dell’automa ` . q è un nuovo stato di ` c (che non deve essere di accettazione), esso rappresenta lo stato trappola a cui perviene l’automa ` c se prende in input un simbolo b B A , quindi b A (vedere esempio precedente). Di conseguenza ` c accetta lo stesso linguaggio di ` . Automi Non Deterministici (rif. D.S.W. pag. 242) Partiamo con un esempio di Automa Non Deterministico (NDFA – Nondeterministic Finite Automaton) per comprenderne la natura: sia A G q1 q2 a b ^q1 , q2 ` ^q1 , q3 ` ^q ` ^a , b` l’alfabeto ed F ^q ` 4 l’insieme degli stati di ac- cettazione, la funzione di transizione è un po’ particolare ed è così descritta: Quando l’automa NDFA perviene allo stato vuoto vuol dire che non farà nulla, anche nell’eventualità che la stringa venga letq3 ^q4 ` ta fino alla fine, però c’è da dire che l’NDFA ha la particolarità di q4 ^q4 ` ^q4 ` poter pervenire in nessuno, uno o più stati contemporaneamente, cioè, se G è definita in un certo modo, l’NDFA ha il potere di percorrere più strade differenti allo stesso tempo. Quindi se ad un certo punto l’NDFA perviene allo stato è probabile che possa proseguire per un’altra strada. È importante notare che non è da confondere con il cappio visto nella rappresentazione grafica, in quanto l’insieme indica che una determina4 ta strada dell’automa è bloccata. Il cappio invece (ad esempio G ^q4 , a` ^q ` ) indica che l’automa, ri4 cevendo in input il simbolo a, è rimasto sempre nello stesso stato, magari al passo successivo potrebbe transitare in un altro stato, con un input differente. EDIT by Qd – Linguaggi – II Lez. Terza Lezione 3/10/2006 Automi NDFA Relazione tra DFA ed NDFA (teorema 2.1) Gli automi non deterministici sono un concetto teorico non realizzabile nella pratica, ma le sue proprietà sono utili per risolvere dei problemi per i quali percorrendo certe strade lungo gli stati dell’automa, certi percorsi (rami) vengono scartati per prenderne altri (come si vedrà nelle dimostrazioni di alcuni teoremi). Diamo ora una definizione formale di Automa Non Deterministico: su A con Q ed F è dato dalla funzione G (che è una funzione differente da quella utilizzata per gli automi deterministici DFA – deterministic finite automata) definita così: q , s o Q , i j con Qi Q i G : Q u A o X (quindi può essere anche ) X è l’insieme delle parti di Q ^Qi | Qi Q ` X ( X Q , mentre Q X , G qi , s j Q , con Q i X . Se Q ^a , b` allora X ^, ^a` , ^b` , ^a , b`` . Mentre prima, per i DFA, G qi , s j rappresentava uno stato, per gli NDFA G qi , s j rappresenta un insieme di stati. Quindi, in questo caso, una stringa sarà accettata dall’NDFA se esso perverrà in almeno uno degli stati di accettazione. Formalizziamo quest’ultimo concetto definendo prima la funzione G per gli NDFA, sempre ricorsivamente: G : Q u A o Qi x G qi ,0 passo base ^qi ` ricevendo la stringa vuota l’NDFA resta nello stato corrente (come il DFA) solo che dobbiamo sostituire a qi il suo singleton ^qi ` per come abbiamo definito G per l’NDFA; x passo ricorsivo G qi , w * qG qi ,u G q, s j si prende l’unione di tutti gli stati a cui perviene l’NDFA alla fine della lettura di u con w us j ( w k , u k 1 ). Dopodichè viene letto l’ultimo simbolo. Alla fine della lettura di u l’automa non deterministico si troverà in uno o più stati, ecco perché è necessario l’uso del simbolo di unione * , per ogni stato a cui è pervenuto l’NDFA viene letto l’ultimo simbolo s j della stringa w, il risultato finale è un sottoinsieme di Q, Q i Q ( G q ,u Q i ). 9 Analogamente ai DFA , stipuliamo q1 come stato iniziale dell’NDFA. Ora possiamo formalizzare che una stringa è accettata da un automa non deterministico su A se: u A , G q1 , u F z Ciò vuol dire che l’automa non deterministico che accetta la stringa u alla fine della lettura dovrà trovarsi in almeno uno degli stati finali, ecco perché si richiede che l’intersezione tra F e G q1 , u sia non vuota (devono cioè avere almeno un elemento in comune). Il linguaggio accettato da un ` (NDFA). Da sottolineare che un NDFA DFA è l’insieme L ` costituito da tutte le stringhe accettate da non è affatto un particolare tipo di NDFA differente: G DFA : Q u A o Q mentre G NDFA : Q u A o X , con X in quanto la G ha condominio ^Q i | Qi Q` . TEOREMA 2.1 (rif. D.S.W. pag. 244): Un linguaggio L è accettato da un NDFA ` L è accettato da un DFA ` ( L L ` ). Cioè L è accettato da un NDFA se e solo se L è regolare. DIM. : Vogliamo provare che se L è regolare allora L è accettato da un NDFA: ciò è immediato in quanto si può definire la G NDFA ( qi , s j ) ^qk ` in luogo di G DFA ( qi , s j ) qk , possiamo anche scrivere G NDFA ( qi , s j ) ^G DFA ` ( qi , s j ) , l’automa non deterministico avrà gli stessi stati (anche di accettazione) dell’automa deterministico. È chiaro che il linguaggio accettato dall’automa deterministico è lo stesso che accetterà l’automa non deterministico. DIM. : Dimostriamo ora che se L è accettato da ` (dove ` è un NDFA), allora L è regolare, cioè L L(` ) . Dobbiamo costruire un DFA che accetti il linguaggio accettato dal NDFA. G è la funzione di transizione di ` , F è l’insieme degli stati di accettazione Q ^q1 , q2 , ! , qm ` l’insieme dei suoi stati. (F Q ) e Vogliamo provare che L(` ) L(` ) L . Costruiamo un DFA ` sullo stesso alfabeto A di ` . ` avrà 2m stati, tale numero corrisponde a tutte le parti di Q, cioè costruiamo un automa ` con gli stati, ognuno dei quali rappresenta un sot- toinsieme di Q (insieme degli stati di ` ), incluso l’insieme vuoto . Quindi l’insieme degli stati di ` sarà Q ^Q1 ,Q2 ,!,Q2m ` ( Qi X , X è l’insieme delle parti di Q). Definiamo lo stato iniziale di ` ^q1` . Ora scegliamo l’insieme degli stati di accettazione di ` , ^Qi | Qi F z ` ( Y Q ). Y è stato scelto in modo tale da contenere tutti quegli stati di DFA come Q1 Y che contengono almeno un elemento (stato di NDFA) in comune a F (insieme degli stati di accettazione di ` ). Definiamo ora la funzione di transizione di ` , G Q , s G q , s ( G : Q u A o Q , G ( q, s ) è un i * NDFA qQi sottoinsieme di Q che quindi contiene nessuno, uno o più elementi (insieme di stati) di Q, a G(Q i , s ) viene associata l’unione degli stati a cui perviene ` EDIT by Qd – Linguaggi – III Lez. quando questo si trova in uno degli stati q Q i ). 10 A,Q , Y ` Abbiamo dunque definito il seguente automa , G,Q1 : A è l’alfabeto su cui opera anche ` ; Q ^Q ,Q ,!,Q2 ` ; 1 m 2 ^Qi | Qi F z ` ; G Qi , s * G q , s ; Y qQi Q1 ^q1` . Per continuare la dimostrazione è necessario enunciare il seguente LEMMA 1 (il lemma è un teorema di importanza minore, o che comunque è utilizzato prevalentemente per la dimostrazione di teoremi più importanti): Sia R Q (ricordiamo che Q è l’insieme degli stati di `DFA ), si ha: § · Qi , s ¸ * ¨ Q R ¸ © i ¹ G ¨ G Q , s * Q R i i Tale scrittura è corretta per il DFA da noi definito in quanto l’unione di tutti gli elementi di R è ancora un elemento di Q (insieme degli stati di ` ). Il lemma dice che il G dell’unione di tutti gli elementi di R e di s è uguale all’unione di tutti i G di Qi R e di s. DIM.: poniamo: Q * Qi i R Q in pratica scegliamo R in modo tale che unendo J tutti i suoi elementi otteniamo l’insieme Q (R può assumere quindi varie conformazioni) § · Possiamo quindi scrivere: G ¨ * Qi , s ¸ G Q , s ¨ Q R ¸ i © ¹ D Dalla definizione che abbiamo dato per G di ` DFA ( G Q i , s G Q , s * G q, s qQ * G q , s ) possiamo scrivere: qQi stiamo applicando la definizione di G solo che al posto di Q i scriviamo Q EDIT by Qd – Linguaggi – III Lez. 11 Sfruttando J otteniamo: G q, s * G q, s Q*R q* Q qQ i * i * q Qi QiR G q , s (l’unione delle unioni di G q , s con q Q i e Q i R Riutilizzando la definizione di G si ha: * * G q, s Q* G Q , s . Qi R qQi i i R E Concludendo D E ,ovvero: § · Qi , s ¸ * G Qi , s . * ¨ Q R ¸ © i ¹ Qi R G ¨ Passiamo al LEMMA 2: u A , * G q, u . qQ G Qi , u i Dc Ec Il lemma dice che, quando l’automa DFA da noi definito si trova nello stato Qi e legge la parola u, la funzione di transizione su stringhe G definita su ` DFA assumerà il valore corrispondente all’unione di tutti gli stati a cui perverrà l’automa non deterministico ` NDFA quando si troverà in uno degli stati q contenuti in Qi e quando legge la stringa u. DIM.: il lemma si dimostra per induzione sulla lunghezza della parola u: x passo base: u 0 , quindi u 0 , si ha: G ^Qi ,0` Qi Dc questa posizione è vera per la definizione del caso base di ricorsione della funzione G di un generico automa finito (deterministico), si ha infatti; possiamo esprimere Qi così: Qi * ^q` qQi quest’ultima è una banale inferenza, Q i è costituito dall’unione di tutti i singleton degli elementi q appartenenti a Q i , da cui abbiamo: G q ,0 * ^q` q* qQ Q i i Ec EDIT by Qd – Linguaggi – III Lez. 12 questa uguaglianza si ricava ricordando la definizione che si è data per G degli automi non determini > stico G q , 0 ^q`@ , quindi l’unione di tutti i q Q i sarà uguale all’unione di tutte le G q, 0 con q Qi . Quindi per u 0 il lemma 2 è dimostrato: G Qi ,0 * G q,0 . qQ Qi i Dc Ec Ipotizzando che il lemma 2 sia vero per u x passo d’induzione: u l (ipotesi di induzione), eseguiamo il seguente: l 1 , poniamo u vs ( s A ) dove v G Qi , u G Qi , vs l , quindi è immediato scrivere: Dc e G Qi , vs G G Qi , v , s si è applicata semplicemente la definizione di G per gli automi deterministici; § · G q, v , s ¸ * ¨ qQ ¸ © i ¹ G G Qi , v , s G ¨ in quest’ultima uguaglianza non si è fatto altro che sostituire G Q i , v con * q, v , questi due qQi termini sono uguali per l’ipotesi di induzione secondo la quale il lemma 2 è vero per v l (rammentiamo che dimostrare per induzione significa dimostrare il caso base, dopodichè presumendo vero il passo k basta dimostrare che il passo k 1 è vero, quindi la dimostrazione è fatta). Ora applichiamo il lemma 1 alla formula: § · G q, v , s ¸ * ¨ qQ ¸ © i ¹ G ¨ nel lemma 1 abbiamo al posto di G q, v G G q , v , s * qQ i l’insieme Q i , del resto G q, v Q e risulta anche G q , v Q , proprio come Q i Q , quindi Q i e G q , v fanno parte dello stesso insieme e quindi su G q, v è applicabile il lemma 1. Ora, applicando la definizione di G per un DFA data nel teorema 2.1, otteniamo: EDIT by Qd – Linguaggi – III Lez. 13 G G q , v , s * * qQ qQ * i i rG q ,v G r , s r rappresenta uno stato, uno dei possibili stati raggiungibili dall’automa non deterministico; ricordiamo che G q , v Q , G q , v Q e G Q , s G q, s , * i qQi per questo lemma applicare la G invece che a Q i a G q , v è legittimo in quanto G q , v come Q i appartengono allo stesso insieme Q (sono della stessa natura); applichiamo adesso (a ritroso) il passo di induzione della funzione di transizione G degli automi non deterministici ( G q , us j * G q , s j ) si ottiene: qG qi ,u * qQ * i rG q ,v G r , s * G q, vs ; qQ i poiché avevamo posto u vs abbiamo: G q, u . * G q, vs q* qQ Q i i Ec Quindi: G Qi , u Dc * G q, u qQ i Ec avendo dimostrato il lemma per u EDIT by Qd – Linguaggi – III Lez. l 1 , il teorema è dimostrato. Quarta Lezione 10/10/2006 fine teorema 2.1 Proprietà di chiusura sui Linguaggi regolari Al fine di dimostrare il teorema vediamo il terzo e ultimo lemma. L ` LEMMA 3: L ` In base a come abbiamo definito i due automi ` NDFA ed `DFA , il lemma 3 ci dice che il linguaggio accettato da ` è lo stesso che è accettato da ` . DIM.: per come abbiamo definito l’automa deterministico e per la definizione di stringa accetta da un DFA abbiamo: u L ` : G Q1 , u Y Dal lemma 2 otteniamo: G Q1 , u G ^q1` , u G q1 , u D cc per come abbiamo definito lo stato iniziale di ` , Q 1 ^q1 ` , è a D cc che applichiamo il lemma 2: G Q i , u * G q , u , solo che in questo caso Qi Q1 ^q ` 1 qQi che, essendo il singleton di q1 , è un unico elemento, quindi il simbolo * è inutile, q1 Q 1 e q1 è l’unico elemento appartenente a Q 1 . Dobbiamo mostrare che u è accettato anche da ` niamo: in modo biunivoco, dall’ultima uguaglianza otte- u L ` G q1 , u Y , u L ` G q1 , u F z quest’ultima biiezione è valida per come abbiamo definito ` e Y ^Q i | Q i F z ` Dalla precedente biiezione, che è nient’altro che la definizione di stringa accettata da un automa non deterministico, deriva la seguente: u L ` u L ` Ciò vuol dire che L ` rema 2.1. L ` L il risultato che volevamo ottenere per la dimostrazione del teo- 15 Proprietà di chiusura (per i linguaggi) (rif. D.S.W. pag. 249) I linguaggi regolari sono chiusi rispetto a varie operazioni. Al fine di dimostrare alcuni teoremi relativi a queste proprietà definiamo il seguente: DEF.: DFA Non Restarting (NRDFA), che è un automa finito deterministico che ha la seguente proprietà: q , s | G q , s q1 In pratica l’NRDFA non ripassa per lo stato iniziale (non esiste alcun stato q tale che l’automa pervenga nello stato iniziale q1 ). TEOREMA 4.1: Dato un DFA ` si può costruire un NRDFA ` tale che L ` L ` . Il teorema ci dice che un linguaggio regolare è accettato anche da un automa finito deterministico non restarting. DIM.: Costruiamo l’NRDFA ` in modo che accetti L ` . Sia Q ^q1 , q2 ,! , qn ` l’insieme degli stati di ` con q1 lo stato iniziale, F l’insieme degli stati di accettazione ( F Q ) e G la funzione di transizione. Q è l’insieme degli stati di ` (lo costruiamo con uno stato aggiuntivo rispetto a ` ): Q ^qn 1 ` Q con q1 lo stato iniziale, La funzione di transizione di ` è così definita: °G q , s G q , s ® °̄ qn 1 se se q Q e G q , s z q1 e q Q e G q , s q1 G qn 1 , s G q1 , s L’automa appena definito ha una funzione di transizione G che si comporta come la funzione G di ` , tranne che nei casi in cui l’automa dovrebbe eventualmente transitare per lo stato iniziale q1 , infatti se G q , s q la funzione G invece di far transitare ` in q , lo fa andare nel nuovo stato q . 1 1 n 1 Invece, quando ` si trova nello stato qn 1 si comporta come se stesse nello stato q1 , infatti si ha G q , s G q , s . n 1 1 Definiamo ora l’insieme degli stati finali F di ` : F EDIT by Qd – Linguaggi – IV Lez. se q1 F F ® ¯ F ^qn 1 ` se q1 F 16 Nel caso in cui ` ha tra gli stati di accettazione proprio lo stato iniziale q1 allora ` verrà indiriz- zato verso qn 1 (ovviamente se, per ipotesi, abbiamo che ` dimostrato). Da notare che non sarebbe corretto definire F è non restarting, il teorema è banalmente F ^q1 ` ^qn 1 ` in quanto è legittimo che ` pos- sa avere tra gli stati finali proprio ^q1 ` , ad esempio quando viene letta la stringa vuota, nel caso questa appartenga ad un linguaggio regolare, l’automa non transita in alcuno stato e resta nello stato iniziale che sarebbe anche quello di accettazione. L’automa ` così definito accetta lo stesso linguaggio di ` uno stato in più. Quindi L ` L ` c.v.d. NRDFA anche se non ripassa per q1 e ha TEOREMA 4.2 * : se L e L sono due linguaggi regolari lo è anche L L . DIM.: Senza perdere di generalità, per il teorema 4.1 si considerano per la dimostrazione due NRDFA ` ed ` che accettano rispettivamente L e L , tali automi operano sullo stesso alfabeto A, neanche in questo caso si perde di generalità, infatti ricordiamo che il linguaggio riconosciuto da un automa non dipende dall’alfabeto utilizzato: ` NRDFA A, Q , q 1 , F , G e `NRDFA A,Q , q , F , G , 1 imponiamo inoltre che tali automi non abbiano stati in comune cioè (insieme degli stati disgiunti) : Q Q . Senza perdita di generalità (per il teorema 2.1) ora costruiamo un automa non deterministico che accetti il linguaggio L L , `ˆ : `ˆNDFA Qˆ l’automa `ˆ ha gli stessi stati di ` stato iniziale qˆ1 ; Fˆ Qˆ , qˆ , Fˆ ,Gˆ, A 1 Q Q ^qˆ1 ` ^q1 , q1 ` ed ` tranne i loro stati iniziali q1 e q1 , `ˆ possiede un suo ° F F ^qˆ1 ` ^q1 , q1 ` se q1 F o q1 F ® altrimenti °̄ F F ed ` ad eccezione degli stati iniziali se presenti tra gli stati iniziali, questi due vengono rimpiazzati dallo stato iniziale di `ˆ qˆ1 ; l’insieme degli stati finali F̂ di `ˆ è costituito da tutti gli stati finali di ` °^G q , s ` se q Q ^q1 ` Gˆ q , s ® °̄^G q , s ` se q Q ^q1 ` EDIT by Qd – Linguaggi – IV Lez. 17 la funzione Gˆ si comporterà come i due automi finiti non restarting ` ed ` , però essendo `ˆ un automa non deterministico dobbiamo considerare i singleton nel condominio della funzione di transizione. Manca da definire la transizione dallo stato iniziale: Gˆ qˆ1 , s ^G q , s ` ^G q , s ` 1 1 quindi l’automa `ˆ , leggendo s quando si trova nello stato iniziale transita contemporaneamente agli stati in cui transiterebbero ` ed ` alla lettura di s partendo dagli stati iniziali q e q , graficamente 1 1 possiamo rappresentarlo così: ` `ˆ ` ` ` È stato costruito un NDFA che è obbligato a seguire entrambe le strade di ` ed ` . accetta entrambi (e soltanto) i linguaggi L ed L , quindi si può concludere che acL L , c.v.d. cetta il linguaggio L `ˆ L’automa `ˆ NDFA Le condizioni Q Q e il fatto che gli automi da cui siamo partiti sono non restarting ci assicura che `ˆ è obbligato a riconoscere unicamente L L . TEOREMA 4.3: Se L A ed L è regolare allora A L è regolare. A L A L è il complemento di L rispetto ad A. DIM.: Come al solito per dimostrare la regolarità di A L basta trovare un automa finito che riconosca tale insieme. Partendo da un DFA ` su A con Q ed F scegliamo un DFA ` quasi identico a ` . ` accetta tutte le stringhe che ` rifiuta, quindi abbiamo: F Q F (gli stati di accettazione di ` corrispondono a tutti gli stati che non sono di accettazione per ` ), quindi il nuovo automa accetta A L . EDIT by Qd – Linguaggi – IV Lez. A L 18 Ad F ` P Q ,q1 , G , F , A , esempio ^q ` , L ` ^b 3 ^ a , b` , A A ^0, a , b , ab , aab , !` , Q ` >n @ > m @ ^q , q , q ` , 1 2 3 a b | n t 0, m ! 0 ` : a b q1 q3 q2 b a Mentre abbiamo: ` Q , q , G , F , A , 1 Q F F ^q , q ` : 1 2 ` : a b q1 q3 q2 b a ` È evidente che l’automa L ` A L non accetta le stringhe del linguaggio L, ma accetta ^a , b , aa , bb , ba , baa , !` ^b > n @ >m @ a ` , n, m t 0 . TEOREMA 4.4 : Se L1 ed L2 sono linguaggi regolari allora anche L1 L2 è regolare. DIM.: Posto L1 , L2 A , per le leggi di De Morgan vale: L1 L2 (rif.D.S.W. pag. 2) R S quindi, applicando L1 L2 A A R S A A L1 A L2 R S , nel nostro caso R L1 ed S le leggi di De A > A L1 A L2 @ . L2 , R A L1 , S A L2 Morgan abbiamo: L1 e A L2 sono regolari per il teorema precedente (4.3, complemento); quindi, dal teorema 4.2 (unione) si ha che ª¬ A L1 A L2 º¼ è regolare; infine, riapplicando il teorema 4.3 otteniamo che: A ª¬ A L1 A L2 º¼ è regolare. Quindi, essendo L1 L2 A ª¬ A L1 A L2 º¼ si conclude che: L1 L2 L ` , c.v.d. EDIT by Qd – Linguaggi – IV Lez. Quinta Lezione 13/10/2006 altre proprietà di chiusura teorema di Kleene TEOREMA 4.5: e ^0` sono linguaggi regolari. DIM. : Un automa che accetta L non ha stati di accettazione ( > L L ` @ > F @ ), quindi qualsiasi stringa letta da un siffatto automa non verrà accettata perché non esistono stati di accettazione, quindi il linguaggio accettato è L . DIM. ^0` : Per quanto riguarda L proprio lo stato iniziale: F ^0` un automa che lo accetta è quello che ha come stato finale ^q1` , l’automa non ha bisogno di leggere nulla per trovarsi nello stato di accettazione, in quanto lo stato q1 , di partenza, è già di accettazione, quindi se legge la stringa vuota 0 non fa nulla e resta in q1 F . Chiaramente affinché l’automa accetti solo la stringa vuota e nient’altro deve essere non restarting. ^u` è regolare. TEOREMA 4.6: Se u A allora L DIM.: Se u 0 , dal teorema precedente abbiamo la dimostrazione. Per un generico u a1a2 ! al al 1 con a1 , a2 ,! , al , al 1 A costruiamo un la stringa u. Possiamo definire la funzione di transizione così: °G qi , ai ® °̄ G qi , a ^qi 1` G qi , a con i a1 q1 , i z k ^ql 2 ` al 1 a2 q2 che riconosce soltanto 1,2,! , l 1 e a A ^ai ` G qi , a k F NDFA q3 ql 1 ql 2 L’automa “abortisce” la computazione ( o ) se legge un simbolo che non è letto al momento giusto ovvero quando i z k , mentre prosegue la computazione se i k fino allo stato finale ql 2 . L’NDFA appena costruito accetta il linguaggio ^u` , quindi ^u` L ` . COROLLARIO 4.7: Ogni sottoinsieme FINITO di A è un linguaggio regolare. 20 DIM.: Per il teorema 4.5 se L allora L è regolare; se invece L è un qualsiasi sottoinsieme di A non vuoto, L ^u1 , u2 ,!, un ` con u1 , u2 ,!, un A allora, applicando il teorema 4.6 e 4.2, si ottiene la dimostrazione del corollario. Infatti per il teorema 4.6 gli insiemi ^u1 ` , ^u2 ` ,! , ^un ` sono regolari; poi, per il teorema 4.2 si ha che ^u1 ` ^u2 ` ! ^un ` è regolare, quindi il corollario è dimostrato. Teorema di Kleene (rif. D.S.W. pag. 253) Esistono altre proprietà di chiusura di cui godono i linguaggi regolari rispetto ad operazioni nuove che andiamo a definire: DEF. (Concatenazione di linguaggi) < : siano L1 , L2 A , con la scrittura L1 <L2 indichiamo il linguaggio ottenuto dalla giustapposizione delle stringhe di L1 con L2 , quindi: L1 <L2 ^uv | u L1 e v L2 ` Se L1 ed L2 sono insiemi finiti, ovviamente L1 < L2 è un insieme finito. Mentre se L1 h , L2 k al- h k . lora L1 < L2 ^u1u2 !un | n t 0, u1 , u2 ,!, un L` . DEF. L : sia L A scriviamo: L L chiaramente è sempre infinito e 0 L in quanto n può essere anche uguale a 0. Chiaramente se L A risulta L A . TEOREMA 5.1: se L ed L sono linguaggi regolari allora anche L <L è un linguaggio regolare. DIM.: Coma al solito basta costruire un automa che accetti L <L per dimostrare il teorema. Supponiamo che L L ` ed L L ` , quindi avremo due DFA: ` DFA Q , q1 , F , G , A `DFA Q , q , F , G, A e 1 con Q Q , ricordando che la regolarità di un linguaggio non dipende dall’alfabeto su cui opera l’automa riconoscitore possiamo, senza perdere di generalità supporre che i due automi operino sullo stesso alfabeto A. x Sulla base degli automi ` ed ` costruiamo ora un automa non deterministico ` NDFA e facciamo in modo che questo nuovo automa accetti il linguaggio L1 <L2 facendo sì che esso “segua” entrambe le “strade” degli automi ` EDIT by Qd – Linguaggi – V Lez. x ed ` . Definiamo le componenti dell’automa ` : 21 x Q Q , Q x q1 q1 , ^G q , s ` °° ®^G q , s ` G q1 , s ° °̄ G q , s x G q, s ^ ^ ` ` per q Q F per q F per q Q x L’automa ` NDFA in pratica, quando legge un simbolo, transita in altri stati “seguendo il percorso” di ` , nel momento in cui si trova in uno degli stati di accettazione di ` (cioè quando è stata letta tutta una stringa appartenente a L ), il suo percorso si sdoppia, proseguendo eventualmente negli stati finali di ` e iniziando il percorso di ` sino al termine della lettura della stringa appartenente a L . x L’automa ` quindi è stato costruito in modo da leggere prima le stringhe di L e poi quelle di L ; x dobbiamo però definire l’insieme degli stati di accettazione di ` : x F x F F F se 0 L F se 0 L Tale clausola è necessaria in quanto, ad esempio, parole del tipo u 0 con u L e 0 L devono essere x riconosciute da ` , però per la definizione di G un NDFA (ma anche un DFA) non “fa nulla” se legge la x stringa vuota e poiché u 0 u, ` deve accettare anche parole di L, nel caso in cui L contenga la strin- x F F se 0 L . Mentre nel caso in cui 0 L , non ci saranno stringhe del tipo u 0 che l’automa non deterministico do- ga vuota, ecco perché F x vrà accettare, ecco perché è sufficiente imporre F F se 0 L . x ` , per come è stato realizzato accetta il linguaggio L <L che quindi è regolare. TEOREMA 5.2: Se L è un linguaggio regolare allora anche L è regolare. DIM.: Ipotizziamo che L sia accettato da un NRDFA ` (per il teorema 4.1 l’uso di un NRDFA non fa perdere di generalità alla dimostrazione, inoltre l’uso di un automa non restarting facilita la dimostrazione), con Q insieme degli stati, q1 lo stato iniziale, F l’insieme degli stati di accettazione ( F Q ) e G la funzione di transizione, costruiamo un automa non deterministico ` zione di transizione: con Q Q , q1 q1 ed F ^q ` , ora definiamo la fun 1 °^G q , s ` se G q , s F °̄^G q , s ` ^q1 ` se G q , s F Gˆ q , s ® In pratica laddove ` si ferma (quando finisce di leggere una stringa u L ), ` per leggere ancora pezzi di stringa fatti da stringhe di L. EDIT by Qd – Linguaggi – V Lez. riparte d’accapo 22 L’automa ` appena realizzato accetta L , quindi tale linguaggio è regolare. Abbiamo visto molti esempi per concludere che gli automi sono degli strumenti per dimostrare la regolarità dei linguaggi. TEOREMA 5.2 (di Kleene): Un linguaggio L è regolare L può essere ottenuto a partire da lin- guaggi FINITI applicando un numero finito di volte le operazioni: *, <, . DIM. : la dimostrazione in questo senso è immediata. Bisogna infatti dimostrare che: se L è un linguaggio ottenibile da linguaggi finiti applicando un numero finito di volte gli operatori *, <, allora L è un linguaggio regolare. Dal teorema 4.7 si ha che ogni sottoinsieme finito di A è regolare, dai teoremi 4.2, 5.1 e 5.2 abbiamo rispettivamente che l’unione, la concatenazione e la stella sono operazioni che preservano la regolarità di un linguaggio, quindi il teorema in questo verso è dimostrato; DIM. : Ora dobbiamo dimostrare che se L è regolare allora L è ottenibile a partire da linguaggi finiti applicando un numero finito di volte le operazioni *, <, . Supponiamo che L L ` , sia ` un DFA con Q ^q1 , q2 ,! qm ` , stato iniziale q1 , insieme degli stati di accettazione F, operante sull’alfabeto A ^s , s ,!, s ` e G 1 2 p la funzione di transizione. Definiamo il seguente insieme: Rik, j ^x A § i, j ! 0 · | G q1 , x q j e tale che ` non transita attraverso stati ql | l ! k nell'esaminare x , ¨ ¸ ©k t0 ¹ ` Più formalmente possiamo dire che Rik, j è l’insieme delle parole x G qi , si1 q j1 ; si1 si2 ! sir sir 1 tali che: G q j1 , si2 q j2 ; # G q jr 1 , sir q jr ; j1 , j2 ,!, jr d k G q jr , sir 1 q j j ; qi In pratica l’insieme Rik, j definisce tutte le stringhe che fanno transitare un automa dallo stato qi allo stato q j senza mai transitare per gli stati qk 1 , qk 2 ,! e così via. qj ql l dk - Interpretazione grafica del comportamento dell’automa quando legge una stringa di R - EDIT by Qd – Linguaggi – V Lez. Visto ciò possiamo dire che l’insieme Ri0,i è rappresentante di tutte quelle stringhe che fanno transitare l’automa dallo stato qi allo stato qi stesso senza mai transitare attraverso alcuno stato (visto che k 0 ). È chiaro che esiste soltanto una stringa che 23 permette ad un automa di comportarsi in questo modo, la stringa vuota, quindi Ri0,i 0 i ,i l’automa non potrà transitare in alcuno stato, può solo stare in qi ), chiaramente R 0 i , j i z j Invece R ^0` (poiché k 0 è un insieme finito. è l’insieme costituito da tutte quelle stringhe che fanno transitare l’automa dallo stato qi allo stato q j , ma poiché k 0 , l’automa non potrà transitare in alcuno stato se non q j , quindi Ri0, j sarà costituito da stringhe di lunghezza 1, cioè simboli (si ha di conseguenza che se 0 x Ri , j i z j x 1 G q , x G q , s con x s A ), quindi anch’esso finito: K è il q- kappesimo stato R i z j ^a A | G q i , a q j ` . intermedio Sottolineare che gli insiemi mostrati sono finiti è essenziale ai fini della dimostrazione del teorema, come 0 i, j vedremo a breve. Da notare che con questa nuova notazione un automa potrebbe trovarsi, alla fine della lettura di una stringa dell’insieme Ri , j in uno stato q l con l ! k , il vincolo è riferito al fatto che l’automa non deve k transitare durante la lettura dei simboli della stringa di R, ma all’inizio e alla fine della lettura della stringa potrebbe anche trovarsi in uno stato qualsiasi. Possiamo scrivere una formula ricorsiva (avendo già visto il caso base Ri0, j ) che definisce Rik, j 1 in base a insiemi di “ordine minore”, abbiamo: Rik, j 1 Rik, j ª« Rik,k 1 < Rkk 1,k 1 < Rkk 1, j º» ¬ ¼ Tale formula può essere interpretata graficamente in questo modo: qi qj Rkk1, j k i ,k 1 R qk 1 R k k 1,k 1 Rik, j 1 può essere espresso mediante operazioni applicate a Rik, j che a sua volta può essere ricavato da formule simili fino ad arrivare al caso base Ri0, j il cui contenuto è noto. Ribadiamo che Rik, j 1 rappresenta l’insieme di tutte quelle stringhe che fanno transitare ` dallo stato qi allo stato q j , ma che non transita attraverso stati qk 1 , qk 2 ,! È utile sottolineare che non esiste un ordine tra gli stati, quindi j potrebbe benissimo essere minore di i, è k che ci vincola a non scegliere stringhe che facciano transitare ` attraverso stati q k 1 , q k 2 , ! EDIT by Qd – Linguaggi – V Lez. 24 Rik, j invece rappresenta una parte dell’insieme Rik, j 1 , infatti esso è costituito dalle stringhe che fanno transitare ` dallo stato qi allo stato q j senza passare attraverso gli stati qk , qk 1 ,! Quindi Rik, j , a differenza di Rik, j 1 , non farà passare l’automa attraverso lo stato qk , stato invece consentito per Rik, j 1 . Non bisogna fare confusione su quali sono gli strumenti necessari a costruire un insieme R, infatti è dall’automa, con la funzione di transizione, gli stati e l’alfabeto che si parte per costruire l’insieme R e non viceversa. In generale ` transita una volta attraverso qi e q j e un numero arbitrario di volte attraverso ql , con l d k . In quanto, se k i j sicuramente ` dovrà transitare una sola volta per qi q j , mentre po- trà transitare un numero arbitrario di volte attraverso stati ql con l d k . Poiché manca lo stato qk 1 al fine di costruire l’insieme Rik, j 1 , ottenibile mediante Rik, j , dobbiamo aggiungere a Rik, j un altro pezzo costituito da quelle stringhe, anzi da quei pezzi di stringhe che fanno transitare l’automa da qi a q j passando eventualmente anche per qk 1 . Possiamo dunque immaginare la stringa x Rik, j 1 divisa in tre parti: x u v w , dove u rappresenta la sottostringa di x che fa transitare mediante un numero finito di passi ` da qi a qk 1 ; mentre v fa transitare ` da qk 1 in se stesso un numero arbitrario, ma finito, di volte (ecco perché si fa uso della stella); e infine w fa transitare ` da qk 1 a q j sempre mediante un numero finito di passi (letture di simboli di w). Il fatto che non si fa uso della stella nelle altre parti della formula dipende dal fatto che per la definizione k 1 che abbiamo dato di Ri , j , se esistono, le stringhe di tale insieme devono far transitare l’automa necessariamente dallo stato q i allo stato q j , più formalmente, rispettando la formula, da q i a q k 1 e poi da q k 1 k q j , se applicassimo la stella a Ri ,k 1 e a R k k 1, j Rkk1, j sarebbe consentito dire che R k i ,k 1 ^0` e ^0` , ma in questo modo l’automa non potrebbe mai transitare dallo stato qi allo stato q j . Mentre è necessario l’uso del simbolo di unione di Ri , j con Ri ,k 1 < Rk 1, k 1 < Rk 1, j perché potrebbero k 1 k k k esistere stringhe che non passano per q k 1 , facendo transitare l’automa da qi direttamente in q j . Dalla formula ricorsiva vista abbiamo il seguente: LEMMA: Ogni insieme Rik, j può essere ottenuto da linguaggi finiti applicando un numero finito di volte gli operatori *, <, . DIM.: La dimostrazione deriva da quanto affermato poco fa. Procediamo per induzione su k : x k=0 : abbiamo visto prima che l’insieme Ri0, j è finito; x k=r+1, presumendo che il lemma sia vero per k=r : la tesi del lemma è di nuovo data dalla formula che abbiamo visto prima, si ha: Rir,j 1 Rir, j ª« Rir,k 1 < Rkr 1,k 1 < Rkr 1, j º» che è pro¬ ¼ prio la tesi, infatti l’insieme è dato dall’uso di un numero finito di operazioni, ovvero una volta l’unione e la stella e due volta la concatenazione sull’insieme Rir, j , che per ipotesi di induzione è ottenibile da un numero finito di operazioni su linguaggi finiti. EDIT by Qd – Linguaggi – V Lez. 25 Ritornando al teorema di Kleene, ricordiamo che dobbiamo dimostrare che se il linguaggio L è regolare, allora esso è ottenibile da linguaggi finiti applicando su di essi un numero finito di volte le operazioni di unione, stella e concatenazione. Adoperando l’insieme R visto prima, possiamo esprimere un linguaggio regolare L così: L L ` * j !0 | q j F R1,n j Cioè stiamo considerando tutte le stringhe che fanno transitare l’automa ` stati finali q j , n è una quantità che dipende dal numero di stati e risulta n t F . dallo stato iniziale q1 agli Ricorrendo al lemma precedente otteniamo la dimostrazione, infatti R1,n j è ottenibile da linguaggi finiti applicando un numero finito di volte le operazioni di unione, stella e concatenazione, ciò è dato anche dal fatto che l’unione su R1,n j viene applicata un numero finito di volte, in quanto F è un insieme finito. EDIT by Qd – Linguaggi – V Lez. Sesta Lezione 20/10/2006 Espressioni regolari e teoremi seconda versione del teorema di Kleene (prima parte) Espressioni regolari Il teorema di Kleene visto nella lezione precedente mette in relazione i linguaggi regolari con linguaggi finiti e le operazioni *, <, ; è possibile dunque dare, grazie ad esso, dei nomi ai linguaggi regolari. Ogni linguaggio è “nominabile” secondo quanto segue: fissiamo un certo alfabeto A ^s1 , s2 ,!, sk ` ; si vanno a considerare tutti i linguaggi regolari L ` , L A ; s , s ,! , s ,0, , *, <, ,(, ) definiamo il seguente insieme: A ^ 1 2 k ` In pratica abbiamo definito l’insieme A mediante elementi che rappresentano i simboli di A e le varie operazioni, abbiamo dato un nome a tali simboli e a tali operazioni ( s1 si chiama s1 , …, 0 si chiama 0 , ecc …). Definiamo ora la classe delle espressioni regolari (rif. D.S.W. pag. 256): per induzione diciamo che essa è un sottoinsieme di A con le seguenti clausole: x passo base: 1) ,0, s1 , s2 ,!, sk sono espressioni regolari; x passo induttivo: 2) se D e E sono espressioni regolari, allora lo è anche D E ; 3) se D e E sono espressioni regolari, allora lo è anche D < E ; 4) se D è un’espressione regolare, allora lo è anche D ; x passo di chiusura: (serve a escludere tutti gli altri casi) 5) nient’altro è un’espressione regolare se non è stato ottenuto applicando le clausole 1,2,3,4 un numero finito di volte. per praticità omettiamo i trattini posti sotto alle parentesi ‘ ( ‘ e ‘ ) ’ Quella appena data è una definizione sintattica, abbiamo inventato dei nomi (espressioni regolari) adoperando i simboli: s1 , s2 , !, sk , 0, , *, <, , (, ) . Ora diamo una denotazione semantica a quelle che abbiamo battezzato: espressioni regolari: sia J un’espressione regolare, con l’uso delle parentesi angolari ‘<’ e ‘>’ definiamo J ! che rappresenta un linguaggio regolare. Ecco che il simbolo J acquisisce un vero significato mediante l’uso delle parentesi angolari ( J ! viene anche detto valutazione di J ). 27 Ecco alcuni esempi adoperando questa notazione: ^a , b, c` vengono definite mediante l’insieme le espressioni regolari sull’alfabeto A ^a, b, c ,0, , *, <, , (, )` , 0 a < b , c < b . A e sono ad esempio: a < b c Si ha in base alle definizioni date per la classe delle espressioni regolari: si è un’espressione regolare, mentre si è il linguaggio regolare denotato dall’espressione regolare si . se J si ^si ` , se J allora si 0 allora 0 ^0` ; se J allora ^` (si ottengono dalla clausola 1 della definizione di espressioni regolari); D E se J allora D E D E (si ottiene dalla clausola 2 della definizione di espressioni regolari); D < E allora D < E se J D < E (si ottiene dalla clausola 3 della definizione di espressioni regolari); D allora D se J D (si ottiene dalla clausola 4 della definizione di espressioni regolari, in questo caso le parentesi tonde non sono necessarie in quanto la stella è un’operazione unaria); Quando J L , sappiamo che J rappresenta L (cioè L ha il nome J , mentre J L ). Altri esempi (rif. D.S.W. pag. 257): 1) a < b c a < b c ^a` < b c ^a ` < b c ^a` < ^b` ^c` (nell’ultima uguaglianza le parentesi angolari non sono più necessarie in quando non vi è alcuna espressione regolare da denotare) Risulta: ^a` < ^b` ^c` L ` 2) ^ab> @ , n t 0` ^ac > @ , m t 0` ^w | w n m ` ab >n@ , n t 0 ac >m @ , m t 0 ; 0 a < b 0 a < b ^0` a < b ^0` a < b ^a`<^b` (la stringa vuota può essere omessa in quanto è già inclusa nella stella nell’espressione a destra dell’unione) EDIT by Qd – Linguaggi – VI Lez. 28 Risulta: 3) ^a`<^b` L ` ^ ab >n @ ` |n t 0 ; c < b c < b Risulta: ^c` < ^b` c < b L ` ^c` < ^b` ^c > @b> @ , n, m t 0` . n m TEOREMA 5.4 (rif. D.S.W. pag. 257): Se L è un linguaggio finito allora c’è sempre un’espressione regolare per L tale che J L DIM.: Dimostriamo il teorema per induzione sulla cardinalità del linguaggio, per le definizioni semantiche date prima valgono le seguenti biiezioni, rappresentanti i passi base dell’induzione: 1.a) L 1.b) L L ; ^0` L 0 ; 1.c) L ^ x` , x si1 si2 ! sim L §s < s < s ! s ! · . ¨ i1 i2 i3 ¸ im © ¹ Ora, assumendo che il teorema valga per L L k 1. k (ipotesi di induzione), dimostriamo che vale anche per L1 ^ x ` , con x A ( L L1 ^ x` k 1 ), per l’ipotesi d’induzione si ha che per L1 k esiste un’espressione regolare D tale che D L1 , si ha inoltre che, per il passo base (1.c) ^ x ` E , con E espressione regolare. Quindi, poiché L L1 ^ x ` possiamo otD E tenere un’espressione regolare J tale che J L ( J D E L1 ^ x ` L ). Quindi il teorema è dimostrato, infatti mediante il passo induttivo può essere costruito qualsiasi linguaggio regolare finito da cui ottenere un’espressione regolare che lo denota. Posto L1 k , possiamo scrivere L TEOREMA 5.5 (seconda versione del teorema di Kleene – rif. D.S.W. pag. 258): In base alle definizioni sintattiche e semantiche date prima e in base al teorema precedente, il teorema di Kleene può essere scritto in questo modo: Un linguaggio (non necessariamente finito) L A è regolare vi è un’espressione regolare J tale che J L. DIM. : È facile dimostrare il teorema da destra a sinistra, infatti, facendo uso del teorema di Kleene, si ha che se esiste un’espressione regolare J tale che J L allora L è un linguaggio regolare. Infatti J denota un linguaggio regolare ottenibile da linguaggi regolari finiti a cui sono applicate le opera- zioni *, <, un numero finito di volte (è proprio ciò che ci dice il teorema di Kleene). Quindi J guaggio regolare. è un lin- La dimostrazione segue alla lezione successiva EDIT by Qd – Linguaggi – VI Lez. Settima Lezione 24/10/2006 seconda versione del teorema di Kleene (seconda parte) Pumping Lemma e teoremi conseguenti DIM. : Nell’altro senso dobbiamo dimostrare che se L è regolare allora vi è un’espressione regolare J tale che J L . Consideriamo l’implicazione nel caso in cui L sia un insieme finito e poi nel caso in cui sia infinito. Se L è finito, per il teorema precedente esiste un’espressione regolare J , tale che J L , con L regolare. Nel caso in cui L è infinito, si ricorre nuovamente al teorema di Kleene per il quale si ha che ogni linguaggio L (non necessariamente finito) può essere ottenuto dalla costruzione di linguaggi finiti ai quali si applicano le operazioni *, <, un numero finito di volte. Quindi L può essere rappresentato da espressioni regolari e le relative operazioni, da cui deriva la dimostrazione del teorema. Un grosso limite dei linguaggi regolari è che ne esistono vari che sono riconoscibili da un algoritmo, ma non da un automa (in riferimento all’entità di automa finito studiata fino ad ora, infatti esistono altri tipi di automa più potenti che sono capaci di riconoscere una classe più vasta di linguaggi e non solo di quelli regolari visti sino ad ora, come vedremo nella sezione delle grammatiche), quindi non sempre la costruzione di un automa ci aiuta a verificare la regolarità di un linguaggio. Ecco che il PUMPING LEMMA ci viene in aiuto (rif. D.S.W. pag. 260): TEOREMA 6.1: Sia L L ` , dove ` è un DFA con n stati. Posto x L e x t n allora si può scrivere x nella forma uvw, con v z 0 e il linguaggio L conterrà tutte le stringhe della forma: x uv >i @w L, i mo 0,1,2,! . >0@ Da notare che è sì vero che v z 0 ma può succedere che compaia v , questo perché x può essere espresso come uvw, uvvw, uvvvw, ecc …, quindi avremmo u0w, u00w, u000w, ecc … per un i arbitrario, se v >i @ 0 la stringa u 0 w si potrebbe “pompare” all’infinito indipendentemente dal valore assunto da i, ot>i @ tenendo sempre lo stesso risultato e cioè u 0 w uw . Da notare anche che poiché per ipotesi Q n e x t n , ` nella lettura di x transiterà per almeno n 1 stati, non necessariamente distinti, anzi, sicuramente non potrà transitare per n 1 stati tutti distinti, in quanto ne ha solo n a disposizione, quindi ` transiterà almeno due volte per uno stato, questo fatto rappresenta la chiave di volta per dimostrare il lemma. DIM.: Il pumping lemma si basa sul principio della piccionaia (accennato poco fa), cioè, se abbiamo n 1 lettere da distribuire in una piccionaia di n cassette, è ovvio che almeno una cassetta dovrà contenere almeno due lettere. Le n 1 lettere corrispondono ai simboli della stringa x, mentre le n cassette della piccionaia corrispondono agli n stati dell’automa ` . Dire che due lettere saranno poste in una cassetta corrisponde a dire che l’automa ` , nella lettura di x, transiterà almeno due volte in uno dei suoi stati. In base a tale principio possiamo dunque scrivere il comportamento dell’automa ` nella lettura di x: 30 G q1 , u q ° ® G q, v q °G q , w F ¯ w u ` q1 q qF v >i @ qF F L’automa leggerà prima la sottostringa u, che dopo una serie di transizioni, arriverà nello stato q alla fine della lettura di u; nello stato q inizierà a leggere la stringa v, alla fine della lettura di v, l’automa ` si ritroverà nuovamente in q; da q l’automa ` leggerà l’ultima parte di x, cioè la sottostringa w che lo farà transitare dallo stato q in uno degli stati di accettazione. Il teorema è dimostrato mediante tale comportamento, infatti per v >i @ , con i pre in uno stato di accettazione. 0,1,2,! il tragitto di ` nella lettura di x si concluderà sem- Il pumping lemma è uno strumento molto utile a verificare la NON regolarità di un linguaggio, infatti non possiamo affermare che non esiste alcun automa che riconosce il linguaggio (è semplice trovare uno o più automi che riconoscono un dato linguaggio regolare, per la precisione se esiste un automa ne esistono infiniti che riconoscono un dato linguaggio regolare; cosa molto più complicata invece sarebbe quella di esibire gli infiniti automi che NON riconoscono un dato linguaggio, al fine di dimostrare che esso non è regolare; è chiaro quindi che nel dimostrare che un linguaggio non è regolare l’automa non è uno strumento adatto al nostro fine). Per dimostrare che un linguaggio non è regolare lo si fa per assurdo. Se il metodo diretto è il seguente: se (ipotesi) L ^! !` allora L non è regolare (tesi), la dimostrazione per assurdo prevede che neghiamo la tesi, quindi assumiamo che L sia regolare. A questo punto possiamo applicare a tale linguaggio il pumping lemma, esibendo delle stringhe del tipo x uv >i @w con v z 0 e i t 0 . La contraddi- zione si ottiene soltanto quando per tutte le stringhe u, v , w esiste almeno un i tale che uv >i @w L . Da cui si può affermare con certezza che L non è regolare. Tale risultato non può essere confermato nel caso in cui non si riesca a trovare una terna di stringhe u, v , w tali che esista un i tale che uv >i @w L (in tal caso il pumping lemma non è più sufficiente a dimostrare la regolarità o la non regolarità del linguaggio, bisogna dunque ricorrere ad altri metodi). Il metodo appena descritto sarà chiarito più avanti con un esempio molto importante. TEOREMA 6.2 (rif. D.S.W. pag. 261): Sia ` ga x L ` tale che x n . un DFA con n stati, allora se L ` z esiste una strin- Il linguaggio costituito da tutte le stringhe x con x n è ovviamente finito. DIM.: Supponiamo che x sia la parola più piccola (lunghezza minima) accettata da ` ( x L ` | x n ). Dimostriamo il teorema per assurdo, negando la tesi, supponiamo quindi che se L ` z allora esiste una stringa x L ` tale che x t n . Ci sono dunque i presupposti per applicare il pumping lemma, possiamo dunque scrivere x uvw , con v z 0 , e, se i 0 , esiste una stringa uv >0@w uw L ` , segue che uw uvw , cioè uw x e quest’ultima disuguaglianza rappresenta un assurdo in quando avevamo ipotizzato che x fosse la stringa più piccola accettata da ` e invece il pumping lemma ci dice che esiste una parola, più piccola di x, uw che è accettata da ` , cioè appartenente a L ` , quindi il teorema è dimostrato. EDIT by Qd – Linguaggi – VII Lez. 31 È utile mostrare un metodo che ci permetta di stabilire se un linguaggio accettato da un automa ` 1 è incluso nel linguaggio accettato da un automa ` 2 , cioè ci stiamo chiedendo se esiste un metodo che ci permetta di sapere se L ` 1 L ` 2 . Per verificare ciò basta mostrare che un dato linguaggio L ` sia vuoto esprimendolo così: L ` 1 A L ` 2 L ` Graficamente possiamo esprimere L ` A L ` quindi si ha: L ` 1 L ` 2 così: A L ` 2 L ` 2 L ` 1 Come si può osservare A L ` 2 e L ` 1 sono disgiunti quindi L ` L ` 1 L ` 2 . Caso limite è L ` 1 L ` 2 , in questa circostanza abbiamo comunque L ` Al contrario, se avessimo scritto L ` 2 L ` 1 , avremmo avuto L ` dal grafico: A è vuoto, difatti . z , come si può vedere A L ` 2 L ` 1 L ` 2 TEOREMA 6.3 (rif. D.S.W. pag. 261): Se L L ` u, v , w A con v z 0 , tali che uv >i @w L con i è un insieme infinito allora vi sono stringhe 0,1,! A differenza del pumping lemma, ci siamo ora svincolati dal numero di stati di ` e dalla lunghezza di x. Tale teorema è utile per verificare se certi linguaggi infiniti non sono regolari. Infatti basta cercare delle stringhe del tipo x che non appartengono al linguaggio come visto prima. TEOREMA 6.4: Sia ` un DFA con n stati, si ha che L ` contiene parole x (ne contiene almeno una) tali che n d x 2n . EDIT by Qd – Linguaggi – VII Lez. è un insieme infinito L ` 32 DIM. : La dimostrazione in questo senso è banale e si ottiene mediante il pumping lemma. Si deve dimostrare che se L ` contiene parole x, tali che n d x 2n allora L ` è un insieme infinito. Sussistono le ipotesi per applicare il pumping lemma, infatti abbiamo un linguaggio regolare L ` , un DFA con n stati e la stringa x ha lunghezza pari o maggiore di n. Esiste dunque stringhe x uv >i @w , con v z 0 e i 0,1,2,! La non finitezza di L ` è diretta conseguenza del pumping lemma, infatti se esiste una x uv >i @w , con v z 0 e i 0,1,2,! x si può pompare a piacere al variare di i, quindi L ` conterrà stringhe (non sono tutte così) del tipo uw, uvw, uvvw, uvvvw, … quindi L ` è infinito. DIM. : Ora dobbiamo dimostrare che: dato un L ` infinito allora L ` conterrà parole x | n d x 2n . Abbiamo che, poiché L ` per ipotesi è infinito, esisteranno certamente parole x | x t 2n , scegliamo una stringa di lunghezza minima lunga almeno 2n, essendo tale stringa x t 2n la si può certamente scomporre in due pezzi (è chiaro che ` ha almeno uno stato, quindi n t 1 ). Quindi x x 1 x 2 , posto x 1 n abbiamo di conseguenza x 2 t n poiché abbiamo fissato x t 2n , allora, per il principio della piccionaia visto per la dimostrazione del pumping lemma, abbiamo che x 1 uvw . Nel pumping lemma non è specificato, ma u e w possono essere anche stringhe vuote, è soltanto su v che c’è il vincolo di v z 0 . G q1 , u q ° Possiamo dunque scrivere: ®G q , v q °G q , w x F 2 ¯ w x2 u ` q1 q qF con 1 d v d n . Quindi, poiché la lettura di v genera un cappio, possiamo dire che uwx 2 è una stringa accettata da ` , uwx 2 L ` , G q1 , uwx 2 F . Certamente risulterà uwx 2 t x 2 t n , poiché x 2 t n . Inoltre, poiché abbiav mo costruito x x 1 x 2 , con x 1 uvw e 1 d v d n , ovqF F viamente risulterà uwx 2 x (strettamente minore in quanto nella parte sinistra della disuguaglianza, manca la v che certamente non è una stringa vuota). Ricordando che si era ipotizzato x quale stringa più piccola, di lunghezza non minore di 2n ( x t 2n ), risulterà dunque uwx 2 2n e uwx 2 è una parola accettata da ` , ma x avevamo stabilito che fosse la più piccola parola di lunghezza non minore di 2n e di conseguenza una stringa più piccola di x deve necessariamente risultare di lunghezza strettamente minore di 2n e poiché uwx 2 x e uwx 2 t n avremo che n d uwx 2 2n . In definitiva uwx 2 rappresenta la stringa appartenente al linguaggio L che soddisfa la tesi. Il teorema appena mostrato rappresenta un valido metodo (algoritmo) per verificare che un dato linguaggio regolare sia finito o meno, basterà infatti trovare una stringa x tale che, se ` ha n stati, n d x 2n . >i @ Il pumping lemma fornisce come avevamo già detto un metodo per verificare la non regolarità di un linguaggio. Ad esempio (rif. D.S.W. pag. 262) si può dimostrare che il linguaggio L EDIT by Qd – Linguaggi – VII Lez. ^a > @ b> @ | n ! 0` non n n 33 è regolare (cioè non esiste nessun automa che accetta esclusivamente le stringhe di tale linguaggio e null’altro, inoltre a e b devono essere visti come stringhe costituite da un solo simbolo). L ` . Supponiamo che ` abbia m stati. Per il pumping lemma L è infinito, inoltre esiste una stringa x, con x t m , x uvw e v z 0 , abbiamo che DIM.: per assurdo supponiamo che L ^uv > @w | i t 0` L . Posto i che x uvw x a >l @ b >l @ , risulta a >l @ b >l @ 2l e, poiché x t m , 2l t m . Quindi dire a >l @ b >l @ vuol dire che v deve essere della forma a >l1 @ oppure della forma a >l1 @ a >l2 @ oppure ancora b >l2 @ con, necessariamente, l 1 , l 2 d l . In tutti è tre i casi la stringa x L ` , in quanto essa non può avere lo stesso numero di a e di b. Infatti, nel caso in cui v a >l1 @ , per il pumping lemma, avremmo u v w L ` , ma anche u v v w L ` , che non potranno mai avere lo stesso numero di a e di b (se ce l’ha la prima, non può averle la seconda e viceversa); analogamente succede per v invece, nel caso in cui v b >l 2 @ ; a >l1 @ b >l2 @ si avrebbero stringhe del tipo u a >l1 @ b >l2 @ w , ma anche u a >l1 @ b >l2 @ a >l1 @ b >l2 @ w che certamente non sono stringhe accettate da ` . Avendo esibito tutti i possibili casi in cui x può presentarsi e (per ciascun caso) esiste almeno un valore di l per cui x L , si conclude che certamente L ^a > @ b> @ | n ! 0` z L ` n n . È importante ribadire che esistono sì automi che accettano, tra le tante, stringhe del tipo visto poc’anzi, ma non esistono automi che accettano ESCLUSIVAMENTE tutte le stringhe appena viste, questo ci basta per dire che l’automa non accetta il linguaggio. Un automa che riconosce un dato linguaggio L deve appunto riconoscere le stringhe di tale linguaggio e soltanto quelle (non deve riconoscerne altre). EDIT by Qd – Linguaggi – VII Lez. Ottava Lezione – prima parte 27/10/2006 esercitazione sugli Automi e sulle Espressioni regolari Esercizi proposti tratti dal libro di testo: (rif. D.S.W. pag. 241, esercizio 1 b) Mostrare che il linguaggio L è regolare costruendo un automa finito ` ^a , b` , L consiste in tutte le stringhe che terminano per bbab. L ^bbab , a bbab , b bbab , ab bbab , ba bbab , !` A A,Q , q1 , F ,G Costruiamo l’automa in questo modo ` dove Q che lo accetti. ^q , q ,!, q ` , 1 2 5 F ^q ` e la 5 funzione di transizione è la seguente: G a b q1 q1 q2 q2 q3 q1 q4 q3 q4 q1 q5 q5 q1 q3 q3 b a a b b q2 q1 b q4 q3 a q5 b a a (rif. D.S.W. pag. 241, esercizio 1 h) Mostrare che il linguaggio L è regolare costruendo un automa finito ` che lo accetti. ^a , b` , L consiste in tutte le stringhe che contengono 3 a consecutive. L ^aaa , b aaa , aaa b , ab aaa , aaa b aaa aaa , !` A A,Q , q1 , F ,G Costruiamo l’automa in questo modo ` dove Q ^q , q , q , q ` , 1 2 3 F 4 funzione di transizione è la seguente: G a b q1 q2 q1 q2 q3 q3 q1 q4 q1 q4 q4 q4 a b a a a q1 q3 q2 b q4 b b ^q ` e la 4 35 (rif. D.S.W. pag. 241, esercizio 1 i) Mostrare che il linguaggio L è regolare costruendo un automa finito ` che lo accetti. ^a , b` , L consiste in tutte le stringhe che NON contengono 3 a consecutive. L ^a , aa , ba , aab , abaa , aababbba , !` A L’automa ` i è simile a quello visto nell’esercizio precedente (1.h) salvo che per l’insieme Fi che rappresenta il complemento rispetto a Q di F, quindi Fi Q F ^q , q , q ` . In pratica tutte le strin1 2 3 ghe che accettava l’automa ` non saranno accettate dall’automa ` i . Questa soluzione è stata trovata in modo immediato partendo dall’esercizio precedente (ciò è dato dal teorema 4.3, è chiaro che possono esistere anche soluzioni alternative, a patto che il linguaggio sia regolare, e perché sia tale basta mostrare almeno un automa che lo accetti). (rif. D.S.W. pag. 241, esercizio 2.a) Mostrare che il linguaggio L è regolare costruendo un automa finito ` che lo accetti. A ^ A, B,!, Z ,0,1,! 9` , L consiste in tutte le stringhe w con 1 d w d 8 e che cominciano con uno dei simboli A, B,!, Z . L ^w |, w s v , s ^ A, B , ! , Z ` , v A , 0 d v d 7` Costruiamo F l’automa in questo modo A,Q , q1 , F ,G ` ^q , q ,!, q ` e la funzione di transizione 2 3 dove Q ^q1 , q2 ,!, q10` , 9 G A,!, Z 0,!,9 q1 q2 q10 q2 q3 q3 q3 q4 q4 q4 q5 q5 q5 q6 q6 q6 q7 q7 q7 q8 q8 q8 q9 q9 q9 q10 q10 q10 q10 q10 EDIT by Qd – Linguaggi – VIII Lez. - I parte A, ! , Z 0,! , 9 q2 q1 0,! , 9 A, ! , Z 0,! , 9 q10 A, ! , Z 0,! , 9 q4 q3 A, ! , Z 0,! , 9 q9 A, ! , Z A, ! , Z 0,! , 9 A, ! , Z A, ! , Z 0,! , 9 q8 q5 A, ! , Z 0,! , 9 q7 A, ! , Z 0,! , 9 q6 36 (rif. D.S.W. pag. 251, esercizio 3.a) Siano L ed Lc due linguaggi regolari, dimostrare che anche L Lc è regolare. Basta scrivere L Lc L A Lc A Lc Quindi, poiché Lc per ipotesi è regolare, per il teorema 4.3, lo è anche A Lc , mentre per il teorema 4.4 abbiamo che anche L A Lc è rego- A L lare, quindi L Lc è regolare. L Lc L A Lc A Lc (rif. D.S.W. pag. 258, esercizii 2.a, 2.b) Siano D e E due espressioni regolari, con la scrittura D { E indichiamo che D la definizione appena data dimostrare le identità seguenti: E . In base al- 2.a) D D { D Dobbiamo mostrare che 2.b) D D D D , quindi basta scrivere: D D D . E D J { D E J Mostriamo come D E D J Scriviamo: D E D J ^u v | u D Mentre: D D D E J ,v E D E J D E D J ` ^u w | u D D E J Quindi possiamo concludere che EDIT by Qd – Linguaggi – VIII Lez. - I parte D D E D J ,w J D E J ` ^u z | u D ,z E z J ^u z | u D ,z E z J E D J { D E J è vera. `. `. Grammatiche Ottava Lezione – Seconda parte 27/10/2006 Introduzione alle Grammatiche Introduzione alle Grammatiche Gli argomenti trattati fin ora (automi e linguaggi regolari) sono inerenti a quella classe di problemi detti di decisione: abbiamo studiato delle strutture astratte (gli automi) che ci hanno permesso, ad esempio, di stabilire se un certo linguaggio è o non è regolare, ma tale problema si può estendere ad un insieme molto più vasto di argomenti. Nel caso specifico degli automi c’è da dire però x B che essi hanno dei limiti, ad esempio essi non riconoscono linguaggi come: x ` ? ^a > @b > @ | n ! 0` n x B n . B Set Ora ci prestiamo ad affrontare un’altra classe di problemi, quelli inerenti alla GENERAZIONE, studieremo cioè dei metodi che permettono di generare dei linguaggi, regolari e non regolari. Usando due macchine (algoritmi), una per generare degli elementi y B , un’altra per la generazioni di elementi differenti dai precedenti y B . Facendo un confronto tra i due elementi si potrà stabilire di che tipo è il linguaggio generato. Le strutture generative che vedremo a breve permetteranno di generare e quindi di identificare una classe più vasta di linguaggi (non solo regolari). x y B ` Chiameremo tali macchine GRAMMATICHE. Di seguito vengono elencate le prime nozioni riguardanti le grammatiche (rif. x ` c D.S.W. pag. 269). y B Tratteremo esclusivamente grammatiche CONTEXT FREE o anche C.F. (cioè libere Macchine generatrici dal contesto, in seguito si chiarirà tale termine). DEFF.: Dati due alfabeti i e T disgiunti ( i T ), gli elementi di i saranno chiamati variabili, mentre gli elementi di T li chiameremo terminali. Con il termine produzione context-free indichiamo un’espressione su i e T di questa forma: i o i T con X i e h i T X è un simbolo mentre h è una stringa X oh 38 Da sottolineare che in generale h non è un terminale, ovviamente perché è una stringa e i terminali non sono stringhe ma simboli, sebbene h potrebbe in taluni casi contenere terminali o coincidere con un terminale. Ora sia P una produzione X o h e siano u e v due stringhe tali che u, v i T allora con la notazione: u v indichiamo che esistono parole p, q i T P tali che u pXq ev phq i T o i T In altre parole v si ricava partendo da u, sostituendo al simbolo X la parola h. Con la scrittura X o 0 indichiamo la produzione nulla (che equivale ad una contrazione, una sorta di STOP per le grammatiche, e ha una sua utilità come vedremo. X o 0 fa collimare ogni simbolo di V nella stringa vuota). Con il termine grammatica libera dal contesto indichiamo il simbolo * , caratterizzato dalle variabili (simboli) di i e dai terminali (simboli) di T; tale grammatica è data da un insieme FINITO di produzioni libere dal contesto su i e T e da un simbolo designato S i (Start) detto simbolo iniziale o assioma. L’insieme i T viene chiamato alfabeto di * . Una grammatica C.F. * viene detta positiva se nessuna delle sue produzioni è la produzione nulla. EDIT by Qd – Grammatiche – VIII Lez. - II parte Nona Lezione 31/10/2006 Grammatiche C.F.: prime nozioni e teorema 1.2 (prima parte) Ricapitolazione concetti base Grammatiche C.F. Il termine context-free sta a indicare che l’unico vincolo che hanno p e q è che devono essere delle stringhe; a eccezione di questo vincolo, le produzioni C.F. non dipendono da un contesto particolare o non devono sottostare a regole dipendenti dal contesto in cui vengono adoperate (contrariamente a quanto succede ad esempio per grammatiche sensibili al contesto le quali sono costituite da produzioni del tipo D o E e deve ri- sultare D d E ). Se * è una grammatica C.F. con variabili in i e terminali T, se u, v i T , scriveremo u v per indicare che esiste una produzione P di * tale che risulti u v . * P Mentre la scrittura u v rappresenta una sequenza di produzioni arbitrariamente lunga (ma pur * sempre finita). Quindi esiste una successione di stringhe u1 , u2 ,!, um con u1 u , um v e risulta ui ui 1 con 1 d i m (m è arbitrario ma finito; si può dire che * potrebbe pure avere meno regole di produzione del * numero m). La sequenza u1 , u2 ,!, um con u1 u e um v è detta derivazione di v da u in *. Con m si indica la lunghezza della derivazione. È ovvio che la derivazione di lunghezza minima è 2, quindi m t 2 (in alcuni libri di testo la lunghezza si indica con m 1 , quindi la lunghezza minima della derivazione in tal caso sarà pari a 1). Nelle derivazioni del tipo u v o anche u v , eccetto che nei casi ambigui, il simbolo * può esse* * re omesso, quindi in luogo di u v o u v potremo scrivere u v e u v . Inoltre la scrittura * * u v può essere vista come una derivazione di v da u di lunghezza 2, una notazione alternativa a quelm la vista può essere u v , con m la lunghezza della derivazione, che se è pari a 2, il simbolo m può essere * omesso. Diamo la seguente definizione: sia * una grammatica C.F., con la scrittura L * indichiamo il linguaggio generato da * e lo definiamo così: L * : ^u T | S u` e rappresenta l’insieme di tutte le * stringhe u costituite da simboli terminali derivanti da S mediante un numero finito di produzioni. Un linguaggio è detto C.F. se esiste una grammatica C.F. che lo genera (discorso simile a quello fatto per i linguaggi regolari e i rispettivi automi riconoscitori). Esempio di grammatica *es .1 :i T ^S , SN , SV ,Verbo _Transitivo,Verbo _ Intransitivo, Articolo, Nome` ; ^il , un, gatto, topo, rincorre , mangia , dorme , canta` ; SN viene detto sintagma nominale; SV viene detto sintagma verbale. 40 Data u v , con u u1 *es .1 S, v il gatto rincorre un topo , vediamo se esiste una successione di pro- duzioni tali che S il gatto rincorre un topo mediante le seguenti produzioni: *es ,1 S SN SV SV Verbo _ Transitivo Verbo _ Transitivo Verbo _ Intransitivo Verbo _ Intransitivo Articolo Articolo Nome o SN SV ; o Articolo Nome ; o Verbo _Transitivo SN ; o Verbo _ Intransitivo ; o rincorre ; o mangia ; o dorme ; o canta ; o un; o il ; Partendo da u1 S e applicando una sola produzione alla volta si ha: u1 S ; u2 SN SV ; u3 Articolo Nome SV ; o topo ; Nome o gatto u4 il Nome SV ; u5 il gatto SV ; u6 il gatto Verbo _ Transitivo SN ; u7 il gatto rincorre SN ; u8 il gatto rincorre Articolo Nome ; u9 il gatto rincorre un topo (m 10) Altro esempio (rif. D.S.W. pag. 270): * è dato da: i ^S ` , T ^a , b` , con le due produzioni S o a S b e S o a b (es.: S o ab , a S b , aa S bb , aaa S bbb , ! ) da cui segue: TEOREMA 1.1: il linguaggio generato da * è L * ^a > @ b > @ | n ! 0` il quale è C.F. ma non è regon n lare. Questo teorema ci fa comprendere le potenzialità delle grammatiche rispetto agli automi, le grammatiche C.F. possono generare anche linguaggi non regolari. Terzo esempio riguardante le grammatiche è il seguente: dimostrare che la stringa aaabbb appartiene ad un linguaggio generato da una grammatica C.F. : basta scrivere le sequenza: SN 1 aSb N 2 aaSbb N 3 aaabbb . u1 u2 u3 u4 Nel caso delle grammatiche * C.F. positive, 0 L * , in quanto non può contenere produzioni nulle X o 0 e 0 potrebbe essere un terminale se 0 L * e ciò significherebbe che esiste X o 0 e ciò non è permesso per come è stato definito *. TEOREMA 1.2 (rif. D.S.W. pag. 273): L è un linguaggio C.F. esiste una grammatica * C.F. positiva tale che L L * oppure L * ^0` . Questo teorema ci mostra che le produzioni nulle non sono necessarie e adoperando un metodo algoritmico che vedremo a breve ne possiamo fare a meno. EDIT by Qd – Grammatiche – IX Lez. 41 DIM.: La dimostrazione necessita della definizione di un insieme chiamato KERNEL (nocciolo) di * C.F. e lo denotiamo con KER * il quale rappresenta l’insieme dei simboli V i , variabili tali che V 0 . * A titolo di esempio consideriamo la grammatica C.F. *0 che ha le seguenti produzioni: S o XYYX , S o aX , X o 0, Y o 0 In generale più sinteticamente possiamo anche scrivere le produzioni in questo modo (adoperando la barra orizzontale): S o XYYX | aX , X o 0, Y o 0 Il nocciolo di *0 è KER *0 ^S , X ,Y ` . Da ogni variabile dell’insieme, dopo un numero finito di produzioni, si può giungere alla stringa vuota 0, infatti: S o XYYX o XYY 0 o XY 0 o X 0 o 0 , X o0 e Y o0. Esiste un metodo algoritmico generale utile a costruire il KER * di una grammatica * C.F., costituito da un numero finito di passi: 1) Passo base (diretto): definiamo l’insieme: i0 ^V | V o 0 è una produzione di * C.F.` ; 2) Passo induttivo: definiamo l’insieme: i i 1 i i ^V | V o D è una produzione di * e D i i `. Cioè l’insieme i i1 si costruisce in base all’insieme i i unito alle variabili V tali che V o D , dove D i i e per induzione i i contiene tutte le variabili D tali che D 0 . Facciamo un esempio riprendendo la grammatica *0 con le produzioni: S o XYYX | aX , X o 0, Y o 0 Applicando il passo base dell’algoritmo otteniamo: i 0 ^ X ,Y ` ; applicando il passo induttivo abbiamo: i 1 i 0 ^V | V o D , D i 0 ` ^ X ,Y ` ^S ` ^ X ,Y , S ` , si è scelto S in quanto XYYX ^ X ,Y ` quindi V S . Chiaramente in questo caso si ha che i i i 1 , i ! 1 , cioè i i si satura in quanto i 2 i 1 i 1 ,!,i i i 1 i 1 . Quest’ultimo concetto viene mostrato nel seguente: LEMMA 1 (rif. D.S.W. pag. 271): se i k i k1 allora KER * i k . È chiaro che se i inutile proseguire con la costruzione del kernel di *. EDIT by Qd – Grammatiche – IX Lez. k i k1 sarà 42 DIM.: Sotto l’ipotesi che i k i k1 dobbiamo dimostrare che KER * i KER * i k e i k KER * (se A, B Set , A B A B B A ): k e cioè che i k KER * è una conseguenza diretta del fatto che i k è stato definito in un certo modo, infatti i k contiene un certo numero di variabili che mediante le produzioni di * portano alla parola vuota, mentre KER * è stato definito come l’insieme di tutte le variabili tali che mediante l’applicazione di un certo numero di produzioni di * si giunge alla parola vuota, è chiaro quindi che se V i k allora V KER * . Meno banale è dimostrare che KER * i k , sotto le ipotesi che i k i k1 . Ciò equivale a voler dimostrare che ogni elemento V KER * appartiene anche a i k . Adottiamo un approccio induttivo sulla lunghezza delle derivazioni: x Passo base: (lunghezza minima della derivazione ( m 2 ) della parola vuota partendo dalla variabile V in *) scrivere V 0 con m 2 implica scrivere V o 0 (infatti V 0 vuol dire * che p, q i T | V x phq e quindi X o h , per essere corretta la corrispondenza deve ri- . Scrivere V o 0 vuol dire che V KER * e anche ^V | V o 0 è una produzione di *` ). Ovviamente vale anche V i k , k t 0 . sultare necessariamente X V i 0 ( i 0 pXq e 0 V e h 0) Passo induttivo: supponendo vero che, date tutte le derivazioni di lunghezza m r , costituite a sinistra da variabili V, se queste V appartengono a KER * , allora appartengono anche a i k , vogliamo dimostrare che ciò vale anche per le derivazioni di lunghezza m t r . Poniamo V D 1 , D 1 D 2 " D r 1 D r e D r 0 , quindi V KER * e D 1 D 2 ! D r 1 D r è una derivazione di lunghezza r in *. Le stringhe D 1 ,D 2 ,!,D r 1 sono necessariamente costituite da variabili in quanto la stringa finale deve essere D r 0 (ricordiamo che se D 1 D 2 allora esiste una produzione del tipo pXq phq , dove p e q sono stringhe e possono anche essere vuote ma X è una lettera dell’alfabeto i , quindi una variabile; per definizione KER * e i k contengono solo variabili e sicuramente V D 1 è una variabile per come abbiamo impostato la dimostrazione per induzione; il fatto che le stringhe D non debbano contenere terminali è perché se, ad esempio, ci fosse D i D i 1 con D i 1 abc e c simbolo terminale, tale simbolo rimarrebbe fino alla fine delle produzioni e non si otterrebbe quindi la stringa vuota). Dalle ultime osservazioni possiamo dire che D 1 ,D 2 ,!, D r 1 i . Ora, posto D 2 V1V2 "VV , otteniamo che Vi 0 con * successione di variabili i 1,2,! , V (ciò è ovvio poiché abbiamo imposto D 1 D 2 ! D r 0 , e quindi Vi 0 ). * Più formalmente Vi §¨Vi 0 ·¸ , 1 d i d V , 2 d m d r 1 , tali derivazioni, poiché si parte da © ¹ D 2 , avranno lunghezza al più pari a r 1 . Quindi tutte le variabili Vi KER * . Ricordando l’ipotesi di induzione (se derivazioni di lunghezza r 1 alla loro sinistra hanno variabili V, se appartengono a KER * allora appartengono anche a i k ), abbiamo che Vi i k e poiché in * c’è una produzione V o D 2 costruttivo di i i 1 V o V1V2 "VV e V1V2 "VV D 2 i k , ricordando l’algoritmo ( i i ^V | V o D è una produzione di *, D i i `) otteniamo che V i k 1 ( i k ^V | V o D , D i k ` ) , ricordando l’ipotesi del lemma ( i k 1 i k ) si ottiene V i k . EDIT by Qd – Grammatiche – IX Lez. Decima Lezione 3/11/2006 teorema 1.2 (seconda parte) Ricapitolazione teorema 1.2 e lemma 1, segue: LEMMA 2 (rif. D.S.W. pag. 271): Vi è un algoritmo per trasformare una grammatica * C.F. in una grammatica C.F. positiva * tale che risulti: L * L * oppure L * L * ^0` . DIM.: dimostriamo il teorema elencando preliminarmente i passi dell’algoritmo: 1. si calcola il KER * ; 2. all’insieme di produzioni che si ottengono dagli elementi del nocciolo di * si aggiungono tutte le produzioni di * cancellando dal loro lato destro una o più variabili appartenenti al KER * ; 3. dall’insieme ottenuto si eliminano le produzioni del tipo V o 0 . Il seguente esempio chiarisce i tre passi appena descritti: consideriamo la grammatica * 0 presa prima in analisi, costituita dalle produzioni: S o XYYX | aX , X o 0, Y o 0 . Per ottenere *0 applichiamo il passo 1. dell’algoritmo del lemma poc’anzi enunciato, allora l’insieme delle produzioni sarà ^S o XYYX , X o 0, Y o 0` ; passo 2. aggiungiamo tutte le possibili produzioni ottenibili da * 0 cancellando alla destra una o più variabili presenti nel nocciolo, otteniamo: ^S o XYYX , X o 0, Y o 0` ^S o YYX | XYX | XYY | XY | YY , S o YX | XX | X | Y | aX | a `; al passo 3. dobbiamo eliminare dall’insieme ottenuto le produzioni nulle ottenendo: ^S o XYYX , S o YYX , S o XYX , S o XYY , S o XY , S o YY , S o YX , S o XX , S o X , S o Y , S o aX , S o a ` . Riprendendo la dimostrazione del lemma 2, inizialmente dobbiamo far vedere che L * L * , quindi bisogna dimostrare che se una produzione appartiene a L * allora essa appartiene anche a L * . Consideriamo la produzione V o E1 E2 " EV di * ma non di *, E1 , E 2 ,!, EV i T , vogliamo far vedere che V o E1 E2 " EV è stata ottenuta da una produzione di * :V o u0 E1u1 E 2 " EV uV con u0 , u1 ,!, uV KER * , poiché stiamo adoperando l’operatore unario stella, le stringhe u potrebbero essere anche vuote ( u 0 ). Chiaramente essendo ui KER * con 0 d i d V , si ha ui 0 . È facile dedurre che V u0 E1u1 E2 " uV 1 EV uV E1 E2 " EV . Ciò mostra che un * * * elemento appartenente a L * appartiene anche a L * (usando la grammatica C.F. * e le sue produzioni, costituite anche da produzioni nulle, abbiamo costruito una derivazione che genera lo stesso elemento generato dalla gramma- tica C.F. * positiva mediante l’applicazione di una serie di produzioni) quindi L * L * . Ora bisogna dimostrare che se un elemento v L * con v z 0 , allora v L * (ricordando che gli elementi di un linguaggio generato da una grammatica C.F. sono stringhe fatte di terminali), quindi dobbiamo dimo- 44 strare che L * L * oppure (nel caso in cui 0 L * ) L * L * ^0` . Dobbiamo dunque * * provare che: V , se V w, w z 0 e w T allora V w , dimostriamolo per induzione: x passo base: derivazione di lunghezza minima m 2 (quindi senza *) ; se V w allora * * contiene la produzione V o w (poiché m 2 e V è una variabile) che è contenuta anche in * (poiché w è fatta tutta di terminali che necessariamente * produrrà, si vedano i due passi per la costruzione della grammatica positiva della prima parte della dimostrazione di questo lemma) ; x passo di induzione: derivazione di lunghezza maggiore di 2 ( ); se V w tale derivazione * la si può scrivere come V w0V1w1V2 "VV wV w (non si è fatto altro che scomporre la derivazio* * ne) con le variabili V1 ,V2 ,! ,VV i e le stringhe di terminali w0 , w1 , w2 ,! , wV T (com presa 0 per via della stella). A questo punto poniamo w w0v1w1v2 " vV wV dove Vi vi , * 1,2,! , V , allora si può applicare l’ipotesi di induzione, considerando che ogni Vi vi i * ha lunghezza minore di V w * w 0 v 1 w 1v 2 w 2 " v V w V * (infatti V w 0V1w1V2 "VV wV * w 0v 1w1V2 w 2 "VV wV * w , la derivazione V w contiene le derivazioni, più corte, Vi v i ). Per * * * * l’ipotesi di induzione si ha quindi che se Vi vi allora Vi vi di conseguenza anche la de * * rivazione, più lunga, V w esisterà per V w (poiché w w0v1w1v 2 " vV wV dove le stringhe vi con i 1, 2, ! , V , sono prodotte da * e le stringhe w i con i 1, 2, ! , V sono fatte di terminali anch’essi prodotti da * per come abbiamo costruito l’algoritmo (passo 2) nella prima fase di dimostrazione del lemma 2. Dunque il lemma è dimostrato, ma non del tutto, infatti la dimostrazione per induzione, non sod disfa il caso in cui vi 0 . Se vi 0 allora Vi 0 quindi Vi KER * a questo punto definiamo il se* 0 se vi 0; , in questo modo abbiamo escluso da * le produzioni nulle, sosti® ¯Vi altrimenti tuendo ad esse stringhe vuote e ciò basta per concludere la dimostrazione del lemma 2, infatti avremo: V o w0V10w1V20 "VV0wV che è in ogni caso una delle produzioni di * , infatti si ha guente simbol: Vi 0 V w0V10w1V20w2 "VV0wV w0v1w1v2 "vV wV * * w. Ritornando alla dimostrazione del teorema 1.2 (rif. D.S.W. pag. 273) affermiamo che un linguaggio è C.F. se e solo se esiste una grammatica C.F. positiva * tale che L L * L L * ^0` : L ' allora si applica l’algoritmo descritto nel lemma 2 (con l’ausilio del lemma 1 per la costruzione del kernel di *) e si costruisce una grammatica * C.F. positiva che soddisfi il teorema ( L L * L L * ^0` ); DIM. : Se L è C.F. e ' è una grammatica C.F. tale che L EDIT by Qd – Grammatiche – X Lez. 45 DIM. : Viceversa, data una grammatica * C.F. positiva, se L L * allora L è un linguaggio C.F., tale implicazione è ovviamente vera e dimostrata immediatamente in quanto, se L L * , L è chiaramente un linguaggio C.F.; nel caso in cui L L * ^0` si crea un nuovo simbolo (o assioma) S e si aggiungono alla grammatica * (ricavata da *) due nuove produzioni: S o S e S o 0 . Chiaramente si ha che L è un linguaggio C.F.: L * L * ^0` . N N S oS EDIT by Qd – Grammatiche – X Lez. S o0 Decima Prima Lezione 7/11/2006 Aberi di derivazione Ricapitolazione lemma 2 e conclusione teorema 1.2. ALBERI Gli alberi sono delle strutture matematiche che servono a descrivere degli insiemi tra i cui elementi ci sono delle relazioni (gli alberi di cui discuteremo più precisamente sono detti alberi finitari e cioè degli alberi in cui ogni nodo ha un numero finito di successori). Radice DEF. (rif. D.S.W. pag. 273): Un albero è detto *-albero se: Padre 1. la radice (root) è etichettata con una variabile; 2. ogni nodo (vertex o vertice) che non è una foglia (leaf ) è etichettato con una variabile; 3. se un vertice ha etichetta X e i suoi immediati successori hanno etichette D 1 ,D 2 ,!,D k (letti da sinistra a destra) allora questo vertice è una produzione di *. Figlio Foglia Foglia Foglia DEF.: Sia g un *-albero e v un nodo (vertice) di g etichettato con X, allora g v è detto sottoalbero determinato dal nodo v. Tale sottoalbero avrà radice v e i figli della radice saranno gli immediati successori di v e così via sino alle foglie. DEF.: Se g è un albero allora g è la parola che consiste nelle etichette delle foglie di g lette nell’albero da sinistra a destra. S DEF.: Se la radice di g ha etichetta S e w g è detto albero di derivazione per w in * (da S). c w d abcd g g allora Vediamo un altro esempio di albero di derivazione: sia *es ,2 : S o a X bY , X o a X | a , Y o bY | b . Tale grammatica genera il linguaggio L *es ,2 guaggio, nel caso in cui m ^a > @ b > @, n,m ! 0` n n (tale lin- n non è regolare ma risulta pur sempre C.F.). Costruiamo l’albero di derivazione di una stringa generata dalla a b Esempio di albero di derivazione grammatica corrente, ad esempio w aaaabbb a >4 @ b >3@ . Per costruire l’albero dobbiamo seguire le regole di produzione della grammatica. Da notare che non è unica la derivazione di w da S, infatti (rif. D.S.W. pag. 274) si possono avere tre derivazioni differenti che portano allo stesso risultato: 47 1. S 1 a X bY 2 a >2@ X bY 3 a >3@ X bY 4 a >4 @ bY 5 a >4 @ b >2@ Y 6 a > 4 @ b >3@ 2. S 1 a X bY 2 a >2@ X bY 3 a >2@ X b >2@ Y 4 a >3@ X b >2 @ Y 5 a >3@ X b >3@ 6 a >4 @ b >3@ 3. S 1 a X bY 2 a X b >2@ Y 3 a X b >3@ 4 a >2@ X b >3@ 5 a >3@ X b >3@ 6 a >4 @ b >3@ (le variabili sottolineate indicano che su esse avviene la successiva produzione) È importante sottolineare che l’albero di derivazione di w è unico, indipendentemente dalle differenti derivazioni adoperate per ottenere w. L’albero di derivazione risultante è il seguente: S X a a X b a X b a EDIT by Qd – Grammatiche – XI Lez. Y b Y Decima Seconda Lezione 14/11/2006 Tremi sulle Derivazioni e gli Alberi di derivazione Derivazioni estreme (a sx. e a dx.) – Grammatiche Branching TEOREMA 1.3 (rif. D.S.W. pag. 274): Se * è una grammatica C.F. positiva e risulta S w allora vi è un * albero di derivazione per w in *. DIM.: Si dimostra per induzione sulla lunghezza della derivazione di w da S in *. x Passo base: m 1 , ciò corrisponde a dire che S w (per m 1 non ci sono produzioni) e l’albero di derivazione richiesto è rappresentato da un unico vertice etichettato con S; N.B.: A lezione, nel passo base della dimostrazione per induzione, è stato considerato, giustamente, il caso m 2 , si ha quindi S o w , cioè in * ci deve essere una produzione S o D 1 D 2 " D n w e * l’albero sarà fatto cosi: S D1 D2 Dn Seguendo la dimostrazione del libro il passo in cui m 2 può essere visto come passo successivo (secondo caso base) a m 1 , dove le foglie D rappresentano sottoalberi. x Passo induttivo: ipotizzando che per derivazioni di w da S di lunghezza q è noto l’albero di derivazione, dimostriamo che ciò vale anche per derivazioni di w da S di lunghezza q 1 in *, cioè che esiste l’albero di derivazione di w da S in * per derivazioni di lunghezza m q 1 . Si ha quindi: S v w , con v , w V T . Applicando l’ipotesi di induzione su S v si ha che * * * m q m 1 esiste un albero di derivazione di v da S in *. Scrivendo ora v w (ricordando la definizione * data per u v rif. D.S.W. pag. 269) si ha che v * xX y e w x D 1D 2 "D k y ( X V , h h V T ). * contiene la produzione X o D 1D 2 "D k , come già detto l’albero di derivazione di v è noto per l’ipotesi di induzione, mentre l’albero di derivazione di w si costruisce a partire dall’albero di derivazione di v aggiungendo un sottoalbero rappresentante la derivazione v w che sappiamo costruire sempre per l’ipotesi di induzione ( m q 1 , per la precisione * m 2 , che come abbiamo poco fa visto nella nota riguardante il caso m 2 , a fortiori sappiamo costruire). Tale sottoalbero ha chiaramente radice etichettata con X. Il teorema è dunque dimostrato. 49 Graficamente abbiamo: S x X X y " Dk x y v D1 D2 w DEF.: con la scrittura u l v indichiamo che esiste una produzione in * X o z , con u ev xX y x z y , y V T e x T . Mentre la sequenza u1 l u2 l ! l un è detta derivazione estrema a sinistra. Tale tipo di derivazione si ottiene applicando produzioni solo alle variabili che si trovano all’estrema sinistra della stringa del tipo u xXy , abbiamo dunque: x X y l x z y , dove xzy v . Poiché z deriva da X, è ovvio che x non può essere una variabile altrimenti si otterrebbe una derivazione qualsiasi, invece, essendo una derivazione estrema a sinistra, deve essere prodotta la prima variabile a sinistra, che nel nostro caso è X V ( x T e y V T ), se z è un terminale allora le successive derivazioni estreme a sinistra si applicheranno a y che potrebbe contenere variabili. Una derivazione estrema a sinistra è (rif. D.S.W. pag. 274, 1): S l a X bY l aa X bY l aaa X bY l aaaab Y l aaaabb Y l aaaabbb L’archetto identifica la prima variabile alla sinistra della stringa sulla quale si applica la produzione. DEF.: Viceversa la scrittura u r v indica che esiste una produzione in * u X o z , con x X y e v x z y , ma, rispetto alla definizione precedente, risulterà: x V T e y T . Analogamente la sequenza: u1 r u2 r ! r un è detta derivazione estrema a destra. Dualmente rispetto a prima, in questo caso, vengono prodotte le variabili che si trovano all’estrema destra della stringa come si può evincere dall’esempio analogo a quello visto prima: S r aXb Y r aXbb Y r a X bbb r aa X bbb r aaa X bbb r aaaabbb Come si può evincere vengono prodotte soltanto le variabili all’estrema destra. Per completezza vediamo un terzo esempio di derivazione: S l ,r a X bY l aaXb Y r aa X bbY l aaaXbb Y r aaa X bbb l aaaabbb Questa derivazione non è né estrema a sinistra né estrema a destra, essendo costituita sia da derivazioni estreme a sinistra che estreme a destra. Da notare che, come nei due esempi precedenti, la prima derivazione ( S l ,r a X bY ) è estrema sia a sinistra che a destra. TEOREMA (rif. D.S.W. pag. 275) Dato un albero di derivazione g rivazione estrema a sinistra (a destra) di w da S, quindi w g . per w T si può ottenere una de- DIM.: Si costruisce una dimostrazione per induzione sulla lunghezza della derivazione. EDIT by Qd – Grammatiche - XII Lez. 50 v0 X 1v1 X 2 " X r vr Con la stringa: (con v0 , v1 ,!, vr T e X 1 , X 2 ,! , X r V ) (notazioni alternative indicano q in luogo di r) indichiamo la parola che si legge da sinistra a destra lungo l’albero di derivazione nei vertici successori immediati della radice S. Come già definito i simboli v rappresentano stringhe terminali, mentre i simboli X sono le etichette dei vertici Q 1 ,Q 2 , ! ,Q n immediati successori della radice S di g (da non confondere il simbolo v con il simbolo Q ). g S Dn v01 v02 ! v0n v0 v11 v12 ! v1m X1 g1 x X2 v1 g2 Xr vr1 vr2 ! vr p vr gr Passo base: r q 0 , produzione priva di variabili. Stiamo ipotizzando il caso in cui non esistano derivazioni con lunghezza maggiore di 2 e cioè che le derivazioni di lunghezza 2 non generino stringhe che contengano variabili ma soltanto terminali. Ovviamente in questo caso si ha immediatamente S o w , con w T , w v0 e r 0 (è facile evincere ciò osservando l’albero appena mostrato, escludendo i nodi etichettati con le variabili X , in quanto assenti nella produzione del passo base, e chiaramente le stringhe v 0 , v 1 , ! , v r devono essere viste come un’unica stringa che in questo caso è indicata con v 0 ). In questo caso è facile osservare che S l w , ma anche S r w , la derivazione è dunque estrema sia a sinistra che a destra. Il caso base è dunque dimostrato; x Passo induttivo: ipotizzando r q ! 0 , cioè che la produzione contenga almeno una variabile Q X . Consideriamo gli alberi g i g i con i 1, 2,!, r . Con questa notazione indichiamo le grammatiche *i che hanno come assiomi X i , rappresentano in pratica sottoalberi di g le cui radici sono etichettate con X i e le cui foglie sono etichettate con wi0 , wi1 ,!, win ( wi0 wi1 "win w wi ). La parola che si ottiene dalla derivazione dell’albero principale sarà v0w1v1w2 " wr vr . Presupponendo vero il teorema per un certo r ! 0 , partendo da X i si ha X i l wi e X i r wi , con 1 d i d r , ipotizzando vera l’ultima affermazione fatta (ipotesi di induzione) possiamo giun- EDIT by Qd – Grammatiche - XII Lez. 51 gere alla tesi del teorema (su una lunghezza della derivazione maggiore di r) e cioè che S l w e S l vo X 1v1 X 2 " X r vr S r vo X 1v1 X 2 " X r vr S r w , e più esplicitamente che l vo w1v1 X 2 " X r vr e l vo w1v1w2 " X r vr r vo X 1v1 X 2 "wr vr # r vo X 1v1w2 "wr vr # l vo w1v1w2 "wr vr w r vo w1v1w2 "wr vr w Da S si ottiene una derivazione estrema sia a sinistra che a destra. Tale conclusione del teorema si ottiene applicando ricorsivamente i due passi dell’induzione. TEOREMA 1.4 (non dim.): Sia * una grammatica C.F. positiva con simbolo iniziale S e terminali T, allora i seguenti enunciati sono equivalenti: 1. w L * ; 2. esiste un albero di derivazione per w in *; 3. c’è una derivazione estrema a sinistra di w da S in *; 4. c’è una derivazione estrema a destra di w da S in *; DEF.: Una grammatica C.F. positiva è detta branching (ramificata o ramificante di Chomsky) se non ha produzioni della forma X o Y , con X ,Y V . L’albero di derivazione di tale grammatica ha vertici che, se non sono foglie, non sono unici, nel senso che ogni vertice non può avere un solo figlio, ammenoché questo figlio non sia una foglia. TEOREMA 1.5: Vi è un algoritmo per ottenere, da una grammatica * C.F. positiva, una grammatica ' C.F. positiva e ramificante tale che si ha l’invarianza L * L ' . La dimostrazione segue alla lezione successiva. EDIT by Qd – Grammatiche - XII Lez. Decima Terza Lezione 17/11/2006 teoremi sulla grammatica Branching e in Chomsky Normal Form Pumping Lemma – proprietà di chiusura Grammatiche Ambigue e Grammatiche Regolari DIM.: Supponiamo prima il caso in cui * contenga delle produzioni cicliche del tipo: X 1 o X 2 , X 2 o X 3 ,! , X k o X 1 , chiaramente con X 1 , X 2 ,! , X k V , k ! 0 . 1. Il primo passo consiste nell’eliminare le produzioni cicliche, e sostituendo, ad ogni variabile X i rimanente, il nuovo simbolo X V . Da notare che facendo queste sostituzioni il linguaggio generato non cambia, in quanto ad esempio: Y o X 1 e X 1 o X 2 , ! , X k o X 1 , tale sequenza dà gli stessi risultati di Y o X 1 , possiamo dunque eliminare il ciclo e rimpiazzare X 1 con X . Se una variabile X i S (cioè se è un assioma) allora porremo X S. Ora supponiamo il caso in cui * non contenga produzioni cicliche, in tal caso si passa al secondo passo. 2. Per ottenere da * una grammatica branching * non deve contenere produzioni del tipo X o Y tali che Y o Z (cioè Y non deve essere una variabile, ma un terminale ). Là dove risulta Y o x e X o Y con x V T , si eliminano tali produzioni e le si rimpiazza con X o x , si ripete tale procedura fintantoché x 1 e x V , proprio perché si vuole ottenere, non modificando il linguaggio generato, una grammatica branching ( X o Y non ammesse, mentre sono ammesse ad esempio X o YZ ). Ripetendo il passo 2 più volte si otterrà una grammatica C.F. positiva e ramificata. DEF.: con la dicitura Chomsky Normal Form (forma normale di Chomsky) si indica una grammatica C.F. * con variabili V e terminali T e ogni sua produzione ha una delle forme seguenti: X o YZ oppure X o a , con X ,Y , Z V e a T . TEOREMA 3.1: Vi è un algoritmo che permette di trasformare una grammatica C.F. positiva in una grammatica C.N.F. (Chomsky Normal Form) ', tale che il linguaggio generato non cambia, quind L * L ' . DIM.: Per il teorema precedente possiamo supporre che * sia una grammatica branching senza che la dimostrazione perda di generalità. 1.1. Per ogni simbolo a T , si introduce la variabile X a ; 53 1.2. Si modifica * rimpiazzando ogni produzione X o x (dove x non è un singolo terminale) con la produzione X o x c , tale x c si ottiene da x sostituendo ad ogni terminale a la variabile X a ; Quindi se si ha X o x e x aa si ottiene X o x c, x c X a X a . 2. Si aggiungono tutte le produzioni X a o a . Chiaramente il linguaggio generato dalla grammatica ottenuta dai passi appena descritti è la stessa di L * e avrà produzioni del tipo (ma non è ancora una grammatica in C.N.F.): I) II) X o X 1 X 2 " X k con k ! 1 (del resto avevamo ipotizzato * branching) più precisamente si ha X o x c con x c X 1 X 2 " X k , x c non è un singolo terminale per questo k t 2 ; X oa. X , X 1 , X 2 , ! , X k sono variabili mentre a è un terminale. Al fine di ottenere una grammatica in C.N.F. bisogna eliminare tutte le produzioni I) con k ! 2 , infatti la C.N.F. deve avere produzioni con (soltanto) due variabili, a tal fine si introduce un nuovo tipo di variabile: Z che utilizzeremo in questo modo: X o X 1Z1 ; o X 2 Z2 ; Z1 # Z k 3 o X k 2 Z k 2 ; Z k 2 o X k 1 X k Con questo stratagemma otteniamo una grammatica C.N.F. ' tale che L * L ' . DEF. (accenno, rif.: D.S.W. pag. 287, ex. 3): Si dice grammatica C.F. in forma normale di Greibach una grammatica che ha ogni produzione nella forma: X o aY1Y2 "Y k con k t 0 , a T e X , Y 1 , Y 2 ,! , Y k V . TEOREMA 4.1 – Pumping Lemma (non dim.): tale lemma visto per i linguaggi regolari può essere esteso alle grammatiche C.N.F. in questo modo, sia * una grammatica C.N.F. con n variabili e sia L L * , allora x L tale che x 2n si ha che x r1 q1 r q2 r2 dove: mxo 1. q1 r q2 d 2n ; 2. q1 q2 z 0; 3. i t 0 r1 q1>i @ r q2>i @ r2 L TEOREMA 4.2 (rif. D.S.W. pag. 290 – non dim.): Il linguaggio L ^a > @ b > @ c > @ | n ! 0` non è C.F. n n n Chiaramente se n avesse un limite superiore allora L sarebbe C.F., ma qui stiamo considerando il caso in cui n possa assumere qualsiasi (tutti) valore positivo non nullo. EDIT by Qd – Grammatiche - XIII Lez. 54 Risolvendo il seguente esercizio (rif. D.S.W. pag. 290, ex. 1) si scopre che anche le grammatiche C.F. hanno dei limiti: mostrare che L ^a > @ | i i ` è un numero primo non è C.F. Tale fatto si può dimostrare i- potizzando che L sia C.F., possiamo applicare il pumping lemma, si ha che (punto 3. del lemma): k t 0 r1q1>k @rq2>k @r2 L , ma ciò non è possibile k t 0 in quanto non avremmo sempre ripetizioni di a pari ad un numero primo. La contraddizione ci conduce ad affermare che L non è C.F. PROPRIETÀ DI CHIUSURA per i linguaggi C.F. Mostriamo tali proprietà analogamente a come si è fatto per i linguaggi regolari. TEOREMA 5.1: se L1 ed L2 sono due linguaggi C.F. allora L1 L2 è un linguaggio C.F. DIM.: Supponiamo che L1 sia un linguaggio generato dalla grammatica C.F. *1 ed L2 il linguaggio generato dalla grammatica C.F. *2 , si ha quindi L1 L *1 ed L2 L *2 , inoltre supponiamo che *1 e *2 abbiano insiemi di variabili disgiunti fra loro, si ha quindi V1 V2 (con quest’ultima posizione non vi è perdita di generalità della dimostrazione del teorema in quanto ciò che interessa come risultato finale sono i terminali e cioè i linguaggi e non le parti costituenti le grammatiche). Ora supponiamo che S1 ed S2 siano rispettivamente i simboli iniziali di *1 e *2 . Definiamo una grammatica * C.F. che ha come insieme di variabili V1 V2 ^S ` e simbolo iniziale S. Questo modo di dimostrare il teorema si basa sullo stesso approccio utilizzato per i teoremi sui linguaggi regolari, in quel caso cercavamo di costruire automi (riconoscitori) mentre adesso cerchiamo di costruire grammatiche (generatrici). Aggiungiamo due nuove produzioni a *: S o S1 e S o S2 . In conclusione la grammatica costruita è generatrice sia di L1 che di L2 , infatti L * L *1 L *2 da cui L1 L2 L * . Ricordiamo che dire che un dato linguaggio è C.F. vuol dire che esiste una grammatica che la genera, quindi nel caso di questa dimostrazione è bastato trovare un’opportuna grammatica che generasse il linguaggio L *1 L * 2 . TEOREMA 5.2: Ci sono linguaggi C.F. L1 ed L2 tali che L1 L2 non è un linguaggio C.F. In altre parole il teorema ci assicura che la classe dei linguaggi C.F. non è chiusa rispetto all’intersezione. DIM.: la dimostrazione consiste nel trovare (almeno) un esempio di linguaggio che non è C.F. che è stato ottenuto dall’intersezione di due linguaggi C.F., quindi consideriamo: *1 , grammatica C.F. con le produzioni: S o Sc | Xc , X o aXb | ab tale grammatica genera il linguaggio C.F.: L1 *2 , grammatica C.F. con le produzioni: n n m L *1 ; S o aS | aX , X o bXc | bc tale grammatica genera il linguaggio C.F.: L2 EDIT by Qd – Grammatiche - XIII Lez. ^a > @b > @c > @ | n,m ! 0` ^a > @b> @c > @ | n,m ! 0` m n n L *2 . 55 È chiaro che il linguaggio L1 L2 ^a > @b > @c > @ | n ! 0` non è C.F. (teorema 4.2, conseguenza del pumping lemn n n ma), tale risultato ci è sufficiente per ritenere dimostrato il teorema. COROLLARIO 5.3: non vi è chiusura, per la classe dei linguaggi C.F., neanche per l’operazione di complemento, infatti: vi è (almeno) un linguaggio C.F. L A tale che A L non è C.F. DIM.: Si adoperano le leggi di De Morgan (rif. D.S.W. pag. 2 - R S L1 L2 L1 L2 A ª¬ L1 L2 º¼ R S ) e possiamo scrivere: A ª¬ A L1 A L2 º¼ con l’ausilio del teorema 5.1 e del teorema 5.2 se ne deduce che il complemento di un linguaggio C.F. non è C.F. infatti, se (per assurdo) neghiamo la tesi del teorema, cioè assumiamo che A L sia C.F. allora, per il teorema 5.1 potremmo affermare che, posto H A L1 A L2 , H è C.F. Prose- guendo la dimostrazione per assurdo potremmo affermare anche che A H è C.F., ma A H , come visto poco fa è uguale a L1 L2 che, per il teorema 5.2 non è C.F. (contraddizione), quindi il complemento di un linguaggio C.F. non è, in generale, C.F. DEF. (rif. D.S.W. pag. 280): Una grammatica C.F. è detta regolare se ogni sua produzione ha una delle due forme: U o aV oppure U o a , con U e V variabili e a terminale. TEOREMA 2.1. (non dim.): Se L è un linguaggio regolare, allora vi è una grammatica regolare * tale che L L * oppure L L * ^0` . TEOREMA 2.2. (non dim.): Se * è una grammatica regolare allora il linguaggio L * generato da gamma è regolare. COROLLARIO 2.4 (non dim.): Ogni linguaggio regolare è C.F. È chiaro che il contrario non vale (non è vero che ogni linguaggio C.F. è regolare). DEF. (rif. D.S.W. pag. 300): Una grammatica C.F. * è detta ambigua se esiste una parola u L * che ha due derivazioni estreme a sinistra. Una grammatica C.F. che non è ambigua è anche detta non ambigua. Esempio (rif. D.S.W. pag. 303): consideriamo la grammatica * con le seguenti produzioni: S o XY | YX , Y o ZZ , X o a , Z o a consideriamo la parola aaa L * , tale parola ha due derivazioni estreme a sinistra, infatti, si ha: 1. S l XY l aY l aZZ l aaZ l aaa 2. S l YX l aZX l ZZX l aaX l aaa EDIT by Qd – Grammatiche - XIII Lez. 56 Le due derivazioni hanno i seguenti alberi di derivazione: g1 g2 S X Y Y Z a a Z Z a S a X Z a a Tale ambiguità viene risolta mediante l’utilizzo delle parentesi, per mezzo delle quali è possibile risalire in maniera univoca alla derivazione. In effetti i due alberi coincidono. Quindi la stringa prodotta dalla derivazione 1. verrà indicata come a aa , mentre la stringa della derivazione 2. verrà indicata come aa a . In questo modo l’albero di derivazione (unico) può essere utilizzato per risalire univocamente alla derivazione. EDIT by Qd – Grammatiche - XIII Lez. Decima Quarta Lezione 21/11/2006 Grammatiche Separatrici – teorema sulla Grammatica Regolare Automi a Pila Riprendendo dall’esercizio della lezione precedente, possiamo riscrivere le produzioni della grammatica * in questo modo: S o X Y | >Y @ X , Y o ^ Z ` Z , X o a , Z o a . Le produzioni che possono indurre ad ambiguità devono essere provviste di parentesi distinte (differenti tra loro). La stringa aaa si otterrà nei due casi visti prima così: 1. S X Y a Y a ^ Z ` Z a ^a` Z a ^a` a 2. S >Y @ X ª¬^ Z ` Z º¼ X ª¬^a` Z º¼ X ª¬^a` a º¼ X ª¬^a` a º¼a Il risultato è concettualmente identico, ma non è ambiguo, in questo modo ogni stringa può essere prodotta da un’unica derivazione. I relativi alberi di derivazione sono i seguenti: g 1 g 2 S X a ^a ` >Y @ Y ^Z ` Z a S [^Z ` [^a` X Z] a a] L’uso delle parentesi è essenziale per evitare ambiguità, un esempio è dato nell’ambito algebrico dei connettivi logici in cui a b c z a b c . Partendo dal concetto di grammatica ambigua e l’uso delle parentesi si arriva alla seguente: DEF. (rif. D.S.W. pag. 303): Sulla base di una grammatica * C.N.F. con terminali T e produzioni: X i o Yi Z i e V o a con i 1,2,! , n e a T Costruiamo una nuova grammatica *S tale che i suoi terminai siano i terminali di * assieme ad altri 2n simboli ( i e )i , quindi il nuovo insieme ricavato da T è TS T ^ ( i , )i | i 1,2,!, n` . Le produzioni della nuova grammatica *S saranno identiche a quelle di * se della forma V o a , mentre le produzioni di * del tipo X i o Yi Z i , in *S assumeranno la forma: X i o ( i Yi )i Z i per i 1,2,!, n . 58 La grammatica *S appena definita prende il nome di grammatica separatrice (si dice anche che *S è il separatore *, ogni sua produzione ha una coppia distinta di parentesi ). È ovvio comprendere che da una grammatica *S è possibile ricavare la grammatica *, basta, infatti, eliminare dalle sue produzioni i simboli delle parentesi ( i e )i . Ora che conosciamo la nozione di grammatica separatrice. Aggiungendo alla grammatica *es .1 , mostrata nella IX lezione, le produzioni: S o S connettivo S ; connettivo o e ; connettivo o oppure ; connettivo o ma Possiamo ottenere la stringa: v = un gatto corre e un topo canta oppure un gatto canta ottenibili non da un’unica derivazione e trasformando tale grammatica in una grammatica separatrice otterremmo una derivazione univoca. TEOREMA 2.3 (rif. D.S.W. pag. 282 – non dim.): Un linguaggio L è regolare se e solo se vi è una grammatica * regolare tale che L L * oppure L L * ^0` . Tale teorema rappresenta una caratterizzazione dei linguaggi regolari in termini generativi (per gli automi tale caratterizzazione era fatta in termini di riconoscimento). Ora viene mostrato uno schema che illustra e “localizza” gli argomenti studiati sin ora e alcuni non ancora trattati: Algoritmi: Riconoscimento Generazione Automi Finiti Automi a Pila Grammatiche Regolari C.F. Grammatiche C.F. Linguaggi: Regolari Context Free Le grammatiche regolari C.F. generatrici di linguaggi regolari hanno produzioni con una sola variabile e un solo terminale (questo fatto fa intuire come una grammatica di questo tipo riesca a simulare in qualche modo il comportamento dell’automa finito). È dimostrato che la classe dei linguaggi regolari è inclusa propriamente (propriamente perché esiste almeno un linguaggio C.F. che non è regolare) nella classe dei linguaggi C.F.: C R C C.F. . Del resto il corollario 2.4 dice proprio che ogni linguaggio regolare è anche C.F., ma il viceversa non vale come dimostrato dal teorema 1.1 (rif. D.S.W. pag. 270) in cui viene fatto un esempio di linguaggio C.F. che non è regolare. Si introduce ora il concetto di automa a pila (o pushdown) che è un’entità matematica (più potente degli automi finiti) in grado di riconoscere i linguaggi C.F. (quindi anche i linguaggi regolari, per quanto detto poco fa), che, oltre ad avere le proprietà degli automi finiti (tradizionali) possiede una memoria (pila o stack) per memorizzare i dati (push) o eliminarli (pop) durante la lettura dell’ipotetico nastro. Formalmente diamo la seguente: EDIT by Qd – Grammatiche - XIV Lez. 59 DEF.: L’automa a pila è rappresentato da un insieme di stati Q ^q1, q2 ,! qm ` , con q1 stato inizia- le, F Q insieme degli stati finali (o di accettazione), A l’alfabeto usuale (il nastro è costituito da parole di questo alfabeto), un altro alfabeto detto alfabeto pila (pushdown) : . Introduciamo un nuovo simbolo 0 il quale non appartiene né all’insieme A, né all’insieme : , scriveremo quindi 0 A e 0 : con A A ^0` e : : ^0` . DEF. (rif. D.S.W. pag. 310): Per transizione di un automa a pila si intende la quintupla: qi a h :i q j con a A e h ,i : . La transizione si interpreta in questo modo: 1. qi rappresenta lo stato in cui si trova l’automa a pila prima della lettura del simbolo a ; 2. a è il simbolo che viene letto dall’automa se a z 0 , altrimenti non viene letto nulla; 3. h è il simbolo che viene estratto (pop) dalla pila se h z 0 , altrimenti non viene estratto nulla; 4. i è il simbolo che viene inserito (push) nella pila se i z 0 , altrimenti non viene inserito nulla; 5. q j è lo stato in cui transiterà l’automa dopo la transizione. Come detto se a 0 non verrà letto alcun simbolo sul nastro (ovvero l’automa non si sposterà lungo il nastro per leggere il simbolo), il fatto che a 0 non vieta all’automa di eseguire eventuali operazioni di pop e di push e di transitare eventualmente in un altro stato. DEF.: Un automa a pila viene specificato da un numero finito di transizioni. Il simbolo 0 rende, in qualche modo, l’automa a pila non deterministico. Difatti se a 0 l’automa potrebbe comunque transitare in un altro stato, anche più di una volta, imitando, in questo modo, ciò che avviene negli automi finiti non deterministici (i quali possono leggendo un solo simbolo transitare in più stati contemporaneamente). DEF.: Date le seguenti transizioni: qi a h : i q j e qi b j : k qk se distinte tra loro (ovvero se c’è almeno un elemento delle due quintuple che le distingue), esse vengono dette incompatibili se si verifica una delle seguenti condizioni: 1. a b e h j (in questo caso viene letto due volte lo stesso simbolo e viene fatto il pop dello stesso simbolo due volte); 2. a 3. h 4. a b e h j 0 oppure j e a 0 (viene letto due volte lo stesso simbolo e in una delle due transizioni non viene fatto il pop); 0 oppure b 0 oppure b 0 e h 0 (viene fatto il pop due volte dello stesso simbolo e in una delle due transizioni non viene letto alcun simbolo); 0 oppure j 0 (in una delle due transizioni non viene letto alcun simbolo e in una delle due transizioni non viene effettuato il pop); DEF.: Un automa a pila si dice deterministico se non possiede coppie di istruzioni incompatibili. EDIT by Qd – Grammatiche - XIV Lez. 60 La definizione appena data è giustificata dal fatto che con istruzioni incompatibili non è assicurato il determinismo dell’automa. DEF.: Posto u A ed ` un automa pushdown. Con il termine u-configurazione per ` indichiamo la tripla ' k , qi ,D dove k è un intero 1 d k d u 1 , qi uno stato di ` ed D : è una stringa del linguaggio pushdown ( D è una sequenza di simboli contenuti nella pila, che in caso può anche essere vuota, per via della stella), mentre u rappresenta la stringa letta dall’automa. Intuitivamente una u-configurazione rappresenta una situazione nella quale: x x x u è scritto nel nastro di ` ; ` osserva il k-mo simbolo della stringa u; Se k u 1 la computazione di ` è terminata durante la u-configurazione ' ; x x x durante la u-configurazione ' ; D è la stringa di simboli nella pila dell’automa durante la u-configurazione ' ; Se D 0 allora la pila è vuota nella u-configurazione ' . qi è lo stato in cui si trova ` DEF.: Nel caso dell’automa a pila non deterministico, per una coppia di u-configurazioni scrivere- mo: u : k , qi ,D |` l , q j , E se ` contiene una transizione qi a h : i q j , dove D h J e E i J , con J : e: l k e a 0; oppure 2. l k 1 e il k-mo simbolo di u è a . 1. Da notare che il push (pop) viene fatto inserendo (estraendo) nella stringa della pila un simbolo alla volta da sinistra, ad esempio, inserendo B nella pila in cui c’è A, si ha: B A. Chiaramente se h 0 oppure i 0 si avrà rispettivamente D J oppure E J. In effetti il simbolo |` serve a descrivere il “passaggio” da una configurazione all’altra di un automa pushdown nella lettura di un simbolo ( 0 compreso). DEFF.: una successione '1 , ' 2 ,!, 'm è detta u-computazione di ` se valgono le seguenti condizioni: 1. '1 1, q ,0 (per un q Q , lo stack è vuoto e viene letto il primo simbolo di u, lo stato non è necessariamente quello iniziale); 2. 'm u 1, p, J con p Q e J : 3. u : ' i |` ' i 1 con 1 d i m . La prima condizione rappresenta il passo iniziale della u-computazione, la seconda condizione rappresenta il passo finale, mentre la terza condizione rappresenta i passi intermedi della u-computazione. La u-computazione appena vista è detta di accettazione se: 1. lo stato p a 'm è uno stato di accettazione; 2. lo stato q a '1 è lo stato iniziale q1 ; 3. la pila a 'm è vuota. EDIT by Qd – Grammatiche - XIV Lez. 61 Diremo che u è accettata da ` Con L ` ` : L ` se vi è una u-computazione di accettazione di ` . indichiamo l’insieme di stringhe accettate da ` ovvero il linguaggio accettato da ^u | u A , ` accetta u` (rif. D.S.W. pag. 320). Nell’esempio che segue si mostra come gli automi a pila siano capaci di riconoscere linguaggi non regolari. Esempio 1 (rif. D.S.W. pag. 312 – ex.1): sia ` 1 un automa a pila, l’alfabeto dell’automa ^a , b` e quello dello stack è F ^ A` (non confondere A con l’usuale simbolo dell’alfabeto), insieme degli stati Q ^q2 ` , le transizioni sono le seguenti: q1a 0 : Aq1, ^q1, q2 ` , q1bA : 0q2 , q2bA : 0q2 . ` 1 è deterministico infatti non ci sono coppie di istruzioni incompatibili tra loro; fin quando ` 1 legge il simbolo a viene fatto il push nello stack del simbolo A, questo sistema permette all’automa di tenere traccia del numero di a lette, invece quando vengono lette b viene effettuato il pop dallo stack del simbolo A e si transita nello stato q2 . Il linguaggio riconosciuto da questo automa è L ` 1 ^a > @b > @ | n ! 0` e lo si può verificare facenn n do degli esempi (facendo leggere delle stringhe del linguaggio all’automa e verificando che l’automa, alla fine della lettura si trova in uno degli stati, in questo caso q2 , di accettazione). Come si può notare da questo primo esempio di automa a pila, il linguaggio riconosciuto è proprio uno di quei linguaggi non riconoscibili da automi finiti tradizionali (visti nella prima parte del corso), questo per evincere subito la potenza di questo nuovo strumento, quale l’automa pushdown. Proviamo a far leggere all’automa pushdown la stringa u ab da cui si ha la u-computazione: '1 , ' 2 , ' 3 con '1 1, q1 ,0 , ' 2 2, q2 , A e ' 3 3, q2 ,0 , possiamo anche scriverla in questo modo: u : 1, q1 ,0 |` 1 2, q1 , A |` 1 3, q2 ,0 . Come possiamo notare, nella terza u-configurazione, lo stato è di accettazione e lo stack è vuoto, ciò vuol dire che la stringa ab è stata accettata dall’automa pushdown. Inizialmente lo stack è vuoto, alla lettura del simbolo a, l’automa pushdown resta nello stato iniziale q1 , mentre viene caricato il simbolo A nello stack. Alla lettura del simbolo b, l’automa pushdown transita nello stato q2 e viene fatto il pop del simbolo A dallo stack. Adesso facciamo un esempio con la stringa v aab che porta alla u-computazione: '1 1, q1 ,0 , ' 2 2, q1 , A , ' 3 3, q1 , AA , ' 4 4, q2 , A che non è di accettazione in quanto in ' 4 l’automa pushdown è sì pervenuto in uno stato di accettazione ma lo stack non è vuoto. Ultima stringa su cui testare ` 1 è w aabb dalla quale otteniamo la sequenza: w : 1, q1 ,0 |` 1 2, q1 , A |` 1 3, q2 , AA |` 1 4, q2 , A |` 1 5, q2 ,0 Dunque la stringa aabb è accettata da ` 1 . EDIT by Qd – Grammatiche - XIV Lez. Decima Quinta Lezione – prima parte 24/11/2006 esempi sugli Automi Pushdown e relativi teoremi Esempio 2: sia ` 2 con AT phabet), Q ^q1, q2 ` , F ^q2 ` , ^a , b, c` ( AT sta per Tape alphabet), AP ^ A, B` ( AP sta per Pushdown al- le transizioni seguono il seguente schema: q1a 0 : Aq1 , q1b 0 : Bq1 , q1c 0 : 0q2 , q2 aA : 0q2 , q2bB : 0q2 . Anche in questo caso loro. ` 2 è deterministico in quanto non ci sono coppie di istruzioni incompatibili tra Il linguaggio riconosciuto da ` 2 è L ` 2 ^u c u R | u ^a , b` ` (quindi stringhe del tipo, ad esempio, a c a , ab c ba , aab c baa , ! ). Proviamo a far leggere la stringa w abcba , otteniamo la sequenza di u-configurazioni: w : 1, q1 ,0 |` 2 2, q1 , A |` 2 3, q1 , BA |` 2 4, q2 , BA |` 2 5, q2 , A |` 2 6, q2 ,0 . Non è complicato capire il meccanismo di questo automa pushdown, alla lettura di simboli a o b allo stato q1 vengono caricati nello stack rispettivamente i simboli A o B, mentre allo stato q2 vengono tolti dallo stack rispettivamente i simboli A o B. Il cambio di stato avviene soltanto alla lettura del simbolo c. Durante la prima parte nella lettura della stringa lo stack viene caricato, tenendo traccia della stringa u, R una volta letto c viene scaricato lo stack fin quando la stringa u non viene letta tutta. Esempio 3: Sia ` 3 un automa pushdown con AT ^a , b` , AP ^ A, B` , Q ^q1 , q2 ` , F ^q2 ` , le transizioni sono le seguenti: q1a 0 : Aq1 ,. q1b 0 : Bq1 , q1aA : 0q2 , q1bB : 0q2 , q2 aA : 0q2 , q2bB : 0q2 . Questo è il caso di un automa pushdown non deterministico infatti le coppie di transizioni prima-terza e seconda-quarta non sono compatibili tra loro (stesso stato, stesso simbolo letto, ma uno dei pop per ciascuna coppia è 0 , cioè viene fatto un pop e un push contemporaneamente). In tal caso ` 3 ha la capacità di seguire più strade contemporaneamente quando si trova nello stato q1 nel leggere a o b . ` 3 riconosce il linguaggio L ` 3 ^u u R ` | u ^a , b` u z 0 (quindi stringhe del tipo, ad esempio, a a , ab ba , b b , abb bba , …). aa : 1, q1 ,0 o |` Nella lettura della parola aa si ottiene: 2 |` 3 2, q1 , A 2, q2 ,? 3 o |` 2 |` 3 3, q1 , AA 3 3, q2 ,0 . Come si può notare ` 3 in più punti segue contemporaneamente strade differenti, ma, come accadeva per gli automi non deterministici tradizionali, non sempre certe strade vengono prese in considerazione, ma scartate, in questo caso due u-configurazioni vengono scartate, 2, q2 ,? perché non ha senso effettuare il push da uno stack che è vuoto, 3, q1 , AA è sì accettabile come u-configurazione ma non permette all’automa pushdown di accettare la stringa aa, quindi viene anch’essa scartata. I linguaggi riconosciuti dagli automi pushdown ` 1 ` 2 , ` 3 sono tutti e tre C.F. 63 Come abbiamo visto gli automi a pila offrono grosse potenzialità, tuttavia esistono altri tipi di linguaggi che neanche gli automi a pila sono in grado di riconoscere, per cui esistono entità matematiche ancora più potenti. TEOREMA 8.3 (non dim. – rif. D.S.W. pag. 316): Sia * una grammatica in forma normale di Chomsky, al- lora vi è un automa a pila ` che riconosce il linguaggio generato da * , si ha quindi L ` TEOREMA 8.4 (non dim.): Per ogni linguaggio C.F. L, vi è un automa a pila ` linguaggio, si ha quindi L L ` . TEOREMA 8.6 (non dim.): Per ogni automa a pila ` , L ` EDIT by Qd – Grammatiche - XV Lez. - I parte L * . che riconosce tale è un linguaggio C.F. Calcolabilità Decima Quinta Lezione – Seconda parte 24/11/2006 Introduzione ai Linguaggi di Programmazione S-programmi Introduzione ai Linguaggi di Programmazione (rif. D.S.W. pag. 17) Il linguaggio che andiamo a studiare ha istruzioni che operano su un alfabeto con apparenti limitazioni A # !0,1,2,!,9" , come vedremo linguaggi che agiscono su questo alfabeto hanno in realtà grosse potenzialità per la soluzione dei problemi. Attualmente si pensa che se non è possibile risolvere un problema con i mezzi che abbiamo oggi a disposizione (pratici e teorici), allora il problema in questione non potrà mai essere risolto, il problema è di fatto irrisolvibile. Ovviamente tale affermazione non è dimostrata, ma fino ad ora è risultata vera. DEFF.: Il concetto teorico di computabilità si basa su uno specifico linguaggio di programmazione f (o S ). L’alfabeto di tale linguaggio è stato poco fa definito, le variabili avranno valori interi non negativi, in particolare denotiamo con i simboli: X1 X2 X3 ! variabili di input (ingresso); Y è la variabile (unica) di output (uscita); inoltre con i simboli: Z1 Z2 Z3 ! denotiamo le variabili locali. In qualche caso le variabili potranno essere denotate in minuscolo e il pedice 1 è spesso omesso, quindi in luogo di X 1 ad esempio, scriveremo X. A differenza dei linguaggi di programmazione effettivamente utilizzati, il linguaggio S non ha un limite superiore (riferito ai valori che possono assumere le variabili) per via della sua natura teorica, tuttavia lavorare con questi linguaggi è piuttosto semplice, soprattutto per chi ha già un minimo di esperienza con la programmazione. Le istruzioni scritte e riconosciute dal linguaggio f sono sostanzialmente tre: V $V % 1 V $V &1 IF V ' 0 GOTO L incremento della variabile V; decremento di V (se V # 0 il valore di V resta invariato); condizionale (se V # 0 si passa all’istruzione successiva, altrimenti si passa all’istruzione etichettata da L). In aggiunta alle variabili viste fino ad ora utilizziamo i simboli: A1 B1 C 1 D1 E 1 A2 B2 ! (anche in questo caso il pedice 1 può essere omesso). Questi simboli servono ad etichettare le istruzioni, racchiudendo tali simboli tra parentesi quadre [ ] , come mostrato nel seguente esempio: 65 (L) V $ V % 1 Il simbolo V viene considerato come una meta variabile, cioè un simbolo che rappresenta un dato, nel nostro caso un numero intero non negativo. L’uso delle etichette è indispensabile, soprattutto per le istruzioni condizionali. Sulla base e sulla composizione delle istruzioni appena viste possiamo definire gli S-programmi, successioni finite e ordinate di istruzioni (ovviamente, a differenza degli insiemi, qui l’ordine con cui vengono scritte le istruzioni è essenziale). Per convenzione la variabile d’uscita Y e le variabili locali Z i con i * 1 inizialmente hanno valore nullo 0. Vediamo un primo esempio di S-programma (a): ( A) X $ X &1 Y $Y %1 IF X ' 0 GOTO A in questo caso X è l’unica variabile d’ingresso, Y quella di uscita, e come definito, inizialmente Y # 0 . Tale S-programma copia il valore di X in Y, formalmente scriveremo: -1 fa +x , # . /x se x # 0 altrimenti X viene decrementato e Y incrementato fintantoché X ' 0 ad ogni passo del ciclo; se però inizialmente X # 0 , dopo la prima istruzione, X varrà sempre 0, dopodichè Y verrà incrementato diventando 1, poiché X # 0 durante l’istruzione condizionale IF il programma terminerà. Vediamo un altro esempio di S-programma (b): ( A) IF X ' 0 GOTO B 0 1 - Z $ Z %1 1c 3 . IF Z ' 0 GOTO E 1 / 2 &&&&&&&&&&&&&& (B ) X $ X &1 0 1 Y $Y %1 1t 1 Z $ Z %1 1 IF Z ' 0 GOTO A 2 In questo caso risulta: fb + x , # x, 4 x * 0 Se inizialmente X # 0 , Y rimane a 0 e si esce dal programma. La variabile Z viene utilizzata come flag per uscire dal programma al momento opportuno. Le istruzioni denotate con * rappresentano quello che viene chiamato salto incondizionato. Il programma è suddiviso in due parti c e t . Il primo gruppo di istruzioni è di controllo, mentre il secondo gruppo è quello che si occupa del trasferimento vero e proprio dei valori numerici dalla variabile X alla variabile Y. L’etichetta E, non facendo riferimento a nessuna istruzione esistente, fa terminare il programma (E sta per Exit). EDIT by Qd – Calcolabilità – XV Lez. - II parte 66 L’esempio appena visto rappresenta un perfezionamento dell’S-programma precedente, il quale presentava un grave difetto e cioè di non restituire il risultato corretto nell’eventualità che X fosse nulla, infatti con X # 0 in uscita avremmo avuto Y # 1 e non Y # 0 . Nell’esempio corrente invece, per qualsiasi valore non negativo di X avviene la copia di X in Y (in verità non si tratta di una vera e propria copia, ma di un trasferimento in quanto al termine del programma il valore iniziale di X va perduto diventando 0 – una sorta di taglia e incolla quindi). Analizziamo ora le due istruzioni contrassegnate con *: Z $ Z % 1 e IF Z ' 0 GOTO E . Esse rappresentano il salto incondizionato perché indipendentemente dai valori che può assumere Z, l’esecuzione di queste due istruzione porta alla terminazione del programma. Difatti Z non sarà mai non nulla e quindi si salterà all’istruzione etichettata con E che, non esistendo, fa terminare il programma. La prima istruzione ci assicura che, anche se Z fosse nulla, comunque porterebbe alla terminazione del programma, essendo incrementata a 1. Il salto incondizionato è stato realizzato a posta nel caso in cui si volesse far terminare prematuramente il programma. DEFF: Le due istruzioni viste poc’anzi, assieme a tante altre, sono molto utilizzate, è utile quindi raggruppare queste istruzioni in un’unica entità che chiameremo macro (il cui significato è concettualmente simile a quello adoperato per i linguaggi di programmazione effettivamente utilizzati sui calcolatori). È cioè una sequenza di istruzioni che può essere richiamata più volte all’interno di un S-programma indicando semplicemente il nome dato alla macro, senza dover, ogni volta riscrivere tutte le istruzioni di cui è composta la macro. La sequenza di istruzioni costituenti la macro viene chiamata espansione della macro. Nel caso del salto incondizionato utilizzato nel precedente S-programma denotiamo la macro semplicemente così: GOTO L e la sua espansione è: I nomi delle variabili e delle etichette non sono importanti, è necessario però far corrispondere le variabili del programma chiamante con le istruzioni dell’espansione della macro. Z $ Z %1 IF Z ' 0 GOTO L ( A) IF X ' 0 GOTO B &&&&&&&&&&&&&& GOTO C (B ) X $ X & 1 Y $Y %1 Z $ Z %1 &&&&&&&&&&&&&& GOTO A (C ) IF Z ' 0 GOTO D &&&&&&&&&&&&&& GOTO E (D ) Z $ Z & 1 X $ X %1 &&&&&&&&&&&&&& GOTO C Come avevamo già fatto notare i programmi (a) e (b) trasferiscono il contenuto di X in Y , ma distruggendo (azzerando) il valore iniziale di X. Usualmente si vuole che (durante una copia o assegnazione) il valore di X resti intatto, come accade normalmente nelle istruzioni di assegnazione della maggior parte dei linguaggi di programmazione, quindi andiamo ad illustrare, facendo uso delle macro, il seguente S-programma (c): Analizzando le varie istruzioni ci si accorge che se inizialmente X è nullo allora il programma (dopo alcuni controlli e GOTO) restituirà il corretto valore (nullo) di Y (se X # 0 5 GOTO C , se Z # 0 5 GOTO E , X # Y # 0 ); mentre se X ' 0 , prima si trasferisce il suo contenuto in Y e poi si ripristina il valore iniziale di X in modo da ottenere dal programma i risultati desiderati (se X ' 0 5 GOTO B , avviene il trasferimento da X a Y e anche a Z, mediante la reiterazione di alcune istruzioni); si perde però il contenuto di X , il quale viene ripristinato contenuto della variabile d’appoggio Z nuovamente in X . EDIT by Qd – Calcolabilità – XV Lez. - II parte GOTO D - trasferendo il 67 Chiaramente la funzione computata è la stessa del programma precedente: f c + x , # x , 4 x * 0 . Si è fatto uso di macro che snelliscono il codice, è importante far corrispondere i nomi delle variabili e le etichette delle istruzioni, ad esempio, GOTO C ha come espansione le due istruzioni: K $ K % 1 e IF K ' 0 GOTO C (l’uso della variabile K ci assicura, non essendo mai stata utilizzata, che altre variabili del programma chiamante non vengano compromesse, ovviamente la variabile C all’interno dell’espansione della macro corrisponde alla variabile C usata per richiamare la macro, se ci fosse stata un’altra variabile nella chiamata, allora nell’espansione avremmo trovato lo stesso nome della variabile menzionata nella chiamata). Anche se nell’espansione della macro si usassero nomi di variabili uguali a quelli utilizzati esternamente, bisognerebbe distinguere le variabili locali dalle altre variabili e non fare confusione con ambiguità che sporcherebbero il risultato. Abbiamo visto nel terzo esempio di S-programma come una semplice operazione di assegnazione non sia così immediata da realizzare con le operazioni atomiche che abbiamo a disposizione, oltretutto sappiamo che l’assegnazione è un’operazione largamente usata nei linguaggi di programmazione, è molto utile quindi trasformare in macro il programma (c), tuttavia quest’ultima, se utilizzata in un altro programma potrebbe non funzionare correttamente in quanto, per essere sempre corretta, le variabili Y e Z inizialmente devono essere nulle, e non è detto che sia sempre così, in quanto la variabile Y in particolare potrebbe essere stata utilizzata dal programma chiamante e contenere dei valori non nulli al momento della chiamata della macro di assegnazione. Bisogna quindi, prima di richiamare tale macro, azzerare il valore della variabile a cui verrà assegnato il dato. Risolviamo il problema con la seguente macro di inizializzazione V $ 0 la cui espansione è: (L) V $ V & 1 IF V ' 0 GOTO L Con l’ausilio dell’ultima macro vista possiamo riscrivere, in termini di macro, il programma (c) che denoteremo con la scrittura V $ V 6 la cui espansione è la seguente: V $0 ( A) IF V 6 ' 0 GOTO B GOTO C (B ) V 6 $ V 6 & 1 V $V %1 Z $ Z %1 GOTO (C ) IF A Z ' 0 GOTO D GOTO E (D ) Z $ Z & 1 V 6 $V 6%1 GOTO C EDIT by Qd – Calcolabilità – XV Lez. - II parte (rif. D.S.W. pag. 21) Da notare che Z non è stata inizializzata a 0 in quanto è considerata variabile locale (se nel programma chiamante viene utilizzata una variabile con lo stesso nome Z allora questo nome deve essere cambiato), il cui valore iniziale non viene ereditato dal programma chiamante né il suo valore finale verrà restituito al programma chiamante, più precisamente la variabile Z utilizzata nella macro non deve essere la stessa che, eventualmente, verrà utilizzata nel programma chiamante, il discorso è diverso invece per V (il cui nome e valore devono essere ereditati dal programma chiamante, come visto prima nella macro GOTO L ). È dunque buona norma, per evitare confusione, utilizzare per le variabili locali nomi differenti da quelli utilizzati nel programma chiamante, analogo discorso vale per le etichette delle istruzioni. 68 Vediamo ora un altro importante S-programma (d) che, ricevendo in input due valori, computa la funzione f d + x 1 , x 2 , # x1 % x 2 . Viene fatto uso della macro del salto incondizionato e dell’assegnazione. Il programma effettua la somma di X 1 e X 2 ponendo il risultato in Y , ecco le istruzioni: Y $ X1 Z $ X2 (B ) IF Z ' 0 GOTO A E GOTO ( A) L’uso della variabile Z ha lo scopo di preservare il valore di X 2 , il programma infatti funzionerebbe anche senza l’utilizzo della variabile temporanea Z, ma alla fine il valore di X 2 andrebbe perso e, per lo stesso principio per cui è stata progettata la precedente macro di assegnazione, anche in questo caso si vuole che le variabili di entrata restino intatte. Z $ Z &1 Y $Y %1 B GOTO Inizialmente viene posto il valore X 1 in Y; dopodichè, mediante una variabile temporanea Z, Y viene incrementato di una unità X 2 volte. Proseguiamo col mostrare un altro S-programma (e) (rif. D.S.W. pag. 22) che esegue il prodotto di due interi e che computa la funzione f e + x 1 , x 2 , # x1 7 x 2 : Z2 $ X 2 (B ) IF Z 2 ' 0 GOTO A E GOTO La moltiplicazione viene interpretata come una sequenza di somme, vengono infatti eseguite X 2 somme di X 1 : X 1 % X 1 % ! % X 1 "##$## % X2 volte ( A) Z2 $ Z2 & 1 L’uso dell’etichetta E 2 , apparentemente non necessario, verrà spiegato a 3 breve. Come si può notare viene fatto uso della macro Z 1 $ X 1 % Y la cui espansione è, in sostanza, il programma precedente. Ci sono però da fare alcune riflessioni, il programma precedente sommava X 1 e X 2 e poneva il risultato in Y , se volessimo utilizzarlo come macro, così com’è, nel contesto di questo programma avremmo il seguente codice: Z1 $ X 1 % Y (E2 ) Y $ Z 1 B GOTO Y $ X1 Z $Y (B ) IF Z '0 GOTO ( A) GOTO E Z $ Z &1 Y $Y %1 GOTO B A Se osserviamo con attenzione i nomi delle variabili possiamo accorgerci che utilizzando questo codice non otterremo il risultato sperato nel programma chiamante, per via di ambiguità nell’uso delle etichette e delle variabili. L’uso del GOTO E ad esempio porterebbe alla terminazione prematura del programma (e non solo della macro come si potrebbe pensare), invece si vuole che, una volta terminata la macro si ritorni al programma chiamante. Quindi è necessario fare uso di un’altra etichetta ( E 2 ) sia nell’espansione della macro che nel programma chiamante. Altro problema è rappresentato dalla variabile Y che, nel contesto del programma chiamante, è confusa con la variabile Z 1 (abbiamo Z 1 $ X 1 % Y e non Y $ X 1 % X 2 ). Quando nel programma chiamante scriviamo l’istruzione Z 1 $ X 1 % Y ci aspettiamo che i valori di X 1 e di Y, dopo l’esecuzione della ma- cro restino immutati e la loro somma venga memorizzata in Z 1 , ma ciò non avviene nell’espansione qui mostrata, oltre al problema dell’etichetta E. Quindi vanno cambiati i nomi di alcune variabili ed etichette. EDIT by Qd – Calcolabilità – XV Lez. - II parte 69 Vediamo ora la corretta espansione da utilizzare per il programma chiamante con gli accorgimenti appena suggeriti: ( B2 ) Z1 $ X 1 Z3 $ Y IF Z 3 ' 0 GOTO A2 GOTO ( A2 ) E2 Z3 $ Z3 & 1 Z1 $ Z1 % 1 GOTO B2 Vediamo l’ultimo S-programma ( f ) che, seppur con qualche limitazione, effettua la sottrazione di due interi, ponendo il risultato nella variabile di uscita: Y $ X1 (C ) Z $ X2 IF Z ' 0 GOTO A GOTO E ( A) IF Y ' 0 GOTO B GOTO A (B ) Y $Y &1 Z $ Z &1 GOTO C Analizzando il programma si scopre che esso computa la seguente funzione: f f + x1 , x 2 , # x1 & x 2 se x 1 * x 2 mentre dà un risultato indeterminato se x 1 8 x 2 , infatti il programma entra in un ciclo infinito (loop), tale condizione viene indicata mediante il simbolo 9 Il loop avviene quando in A la variabile Y è nulla, in tal caso si ritorna (GOTO A) nuovamente all’istruzione A e questo processo si ripete all’infinito. Formalmente possiamo scrivere la seguente funzione computata - x1 & x 2 se x1 * x 2 . dal programma : f f + x1 , x 2 , # . altrimenti /9 La funzione appena descritta prende il nome di funzione parziale il cui concetto è importante per apprendere che non tutte le funzioni possono essere computate dagli S-programmi. Formalmente abbiamo: DEFF. (rif. D.S.W. pag. 3): Se una funzione f ha come dominio di definizione un sottoinsieme di & (sottoinsieme improprio A : & ) diremo che f è una funzione parziale sull’insieme & dei naturali. Nel caso in cui la funzione parziale & abbia come dominio & stesso ( & : & ), allora tale funzione è detta totale (cioè è sempre definita per tutti i valori di & ). (rif. D.S.W. pag. 25) Con il termine asserzione (statement) indichiamo un’istruzione che può avere una delle seguenti forme: 1. 2. 3. 4. V $V %1 V $V &1 V $V IF V ' 0 GOTO L EDIT by Qd – Calcolabilità – XV Lez. - II parte 70 La terza istruzione è detta istruzione pigra (dummy) in quanto la sua esecuzione all’interno di un programma non porta ad alcun effetto. Formalmente un’istruzione è una delle quattro asserzioni viste, precedute o meno da ( L ) che è un’etichetta generica data all’istruzione. Un S-programma è una successione finita di istruzioni. La lunghezza c di un S-programma c è il numero delle sue istruzioni. Un S-programma di lunghezza 0 è detto programma vuoto (è privo di istruzioni da cui f + x , # 0 4x ). Come abbiamo visto, le variabili di un programma, durante l’esecuzione dello stesso, possono assumere valori differenti, ciò suggerisce la seguente definizione: Lo stato di un problema c è una lista di equazioni nella forma V # m , con V nome della variabile ed m il suo valore, tale che: 1. vi è un’equazione per ogni variabile di c ; 2. non vi sono due equazioni con la stessa variabile. Quindi uno stato indica i valori che possono assumere in certi istanti, non necessariamente iniziali, le variabili del programma. Se ; è uno stato del programma c , il valore di V allo stato ; è il numero q tale che V # q è una delle equazioni di ; . Un’istantanea (snapshot) di un programma c è una coppia ordinata + i , ; , con 1 < i < n % 1 , il simbolo n corrisponde alla lunghezza (numero di istruzioni) del programma, mentre ; e uno stato ad un certo istante dell’esecuzione del programma, in altre parole + i ,; , rappresenta il valore delle variabili nell’istante precedente l’esecuzione della i-ma istruzione di c . EDIT by Qd – Calcolabilità – XV Lez. - II parte Decima Sesta Lezione 01/12/2006 Ricapitolazione e seguito concetti sugli S-programmi funzioni parzialmente calcolabili - estensione delle macro predicati - composizione di funzioni - ricorsione Ricapitolazione concetti preliminari sugli S-programmi. Data l’istantanea + i ,; , di c , i è il numero di istruzione corrente, mentre ; è l’assegnazione corrente di valori delle variabili. DEFF.: Un’istantanea + i , ; , di c è detta terminale se i # c % 1 . + i,; , è detta non terminale se vi è un’istantanea + j ,= , che è successore di + i,; , . Diamo una definizione per casi (in base alle asserzioni) di istantanea successore + j ,= , di + i , ; , : 1. la i-ma istruzione di c è V $ V % 1 e ; contiene tra le equazioni V # m , allora j # i % 1 e = si ottiene da ; rimpiazzando V # m con V # m % 1 ; 2. la i-ma istruzione di c è V $ V & 1 e ; contiene tra le equazioni V # m , allora j # i % 1 e , se m ' 0 , allora = si otterrà da ; rimpiazzando V # m con V # m & 1 , altrimenti (se m # 0 ) = # ; ; 3. la i-ma istruzione di c è V $ V , allora j # i % 1 e = # ; ; è IF V ' 0 GOTO L allora = # ; (essendo un’asserzione di controllo e non di modifica delle variabili, lo stato non cambia, ma il numero di istruzione potrebbe cambiare, se si effettua il salto), distinguiamo due sottocasi: 4. la i-ma istruzione di c 4.1. se V # 0 , ; contiene l’equazione V # 0 , allora j # i % 1 (il salto non avviene e si prosegue con la successiva istruzione); 4.2. se V ' 0 , ; contiene l’equazione V # m e, se l’etichetta L non fa riferimento a nessuna istruzione allora j # n % 1 (il programma termina, in questo caso l’istantanea successore di + i , ; , è un’istantanea terminale + n % 1,= , ). Mentre se fa riferimento a una o più istruzioni, j sarà il più piccolo numero tale che la j-ma istruzione è etichettata con L (ovvero la prima che si incontra dall’alto verso il basso -per evitare diramazioni non deterministiche non facenti parte della natura degli S-programmi). L’ultimo caso visto spiega anche il comportamento del programma in situazioni nelle quali ci sono più istruzioni contrassegnate con la stessa etichetta, in tal caso si fa riferimento sempre alla prima che si incontra (le altre verranno ignorate come se non esistessero). (rif. D.S.W. pag. 29): Un calcolo (computation) di un S-programma tanee s1 , s2 ,! , sk (l’ordine dei pedici non deve essere casuale) tale che si %1 ed sk è un’istantanea terminale. c è una successione finita di istancon i # 1,2,!, k & 1 è successore di si 72 Un processo di calcolo non terminale (da non confondere con l’omonimo stato) di c infinita di istantanee s1 , s2 ,! , tale che si %1 con i # 1,2,! è successore di si . è una successione DEFF. (rif. D.S.W. pag. 28) Sia c un S-programma e siano r1 , r2 ,!rm > & con m * 1 (m indica il numero di variabili della funzione computata da c ), con lo stato ; di c dato dalle equazioni X 1 # r1 , X 2 # r2 , ! , X m # rm , Y # 0 e dalle equazioni V # 0 per ogni altra variabile di c (variabili locali, in ogni e con + 1,; , caso che non siano variabili di ingresso X i ,1 < i < m o di uscita Y ) denotiamo lo stato iniziale di c istantanea iniziale, con tali condizioni possono verificarsi due casi: 1. vi è un calcolo di c : s1 , s2 ,!, sk (non si confonda s con r), allora con la scrittura ?c( m ) + r1 , r2 ,!, rm , indichiamo il valore di Y all’istantanea terminale sk con s1 # + 1,; , ; ? # 0 se il programma è terminante. 2. non vi è un calcolo di c (se l’istantanea iniziale è + 1,; , ) (ciò non vuol dire che il programma non sta girando, ma che entra in un loop infinito). In tal caso ?c( m ) + r1 , r2 ,!, rm , assume un valore indefinito 9 . In effetti con la definizione appena data si è formalizzato il comportamento di c computazione e a partire dall’istantanea iniziale di c . al termine della Esempio 1: prendiamo in analisi il programma (b) che copiava il contenuto della variabile X in Y: ?c + x , # x chiaramente ( m # 1 in quanto la variabile d’ingresso è soltanto X ; X # x ; non dimentichiamo che è im(1) b plicito considerare il valore di ? cb presupponendo l’istantanea iniziale + 1, ; , ). (1) X $ X %1 , la cui istantanea iniziale, con ; stato iniziale, X $ X %1 è: + 1,; , # + 1, ! X # r1 ,Y # 0" , . Dopo l’esecuzione della prima istruzione abbiamo + 2,! X # r1 % 1,Y # 0" , Esempio 2: consideriamo il programma: e, dopo la seconda istruzione abbiamo + 3,! X # r1 % 2,Y # 0" , che è l’istantanea terminale. La variabile Y non viene menzionata nelle istruzioni del programma, quindi il suo valore resta immutato e cioè nullo, abbiamo dunque: ?c(1) + r1 , # 0 . Esempio 3 (rif. D.S.W. pag. 31): consideriamo il programma c con le seguenti istruzioni: ( A) X $ X % 1 IF X ' 0 GOTO A (loop infinito) Abbiamo la seguente istantanea iniziale +1,! X # r % 1,Y 1 +1,! X # r ,Y 1 # 0" , e poi + 2,! X # r % 1,Y 1 # 0" , , + 2,! X # r1 % 2,Y # 0" , , ! da cui chiaramente ?c(1) + r1 , #9 , 4r1 * 0 . # 0" , , DEFF. (rif. D.S.W. pag. 30): Per ogni c e per ogni intero positivo m, la funzione ?c( m ) + x 1 , x 2 ,!, x m , è la funzione di m argomenti calcolata dal programma c . EDIT by Qd – Calcolabilità – XVI Lez. 73 Da notare che m è un numero che si riferisce al numero di argomenti della funzione calcolata dal programma e non dipende (o non si riferisce) al numero di variabili di input del programma, ovvero il numero di argomenti della funzione calcolata dal programma non è legato al numero di variabili di input del programma. Ciò si evince da due casi particolari: abbiamo c con n variabili di input con m 8 n (cioè nella funzione ?c( m ) compaiono meno argomenti del numero di variabili di input dell’S-programma c ), nel calcolo della funzione risulterà: r1 # X 1 , r2 # X 2 ,!, rn # X n , rn %1 # 0,!, rm # 0 , cioè le variabili che non fanno riferimento ad argomenti della funzione calcolata verranno considerati nulli anche se magari non è effettivamente così; viceversa, se m @ n (quindi abbiamo più argomenti della funzione che variabili di input del programma) i valori degli argomenti non facenti riferimento a variabili del programma verranno semplicemente ignorati. Per comprendere meglio i concetti appena descritti facciamo degli esempi di funzioni il cui numero di argomenti non corrisponde al numero di variabili di input del relativo programma. Facciamo riferimento ai programmi (c) e (d ). Come ricordiamo il programma (c) effettuava un’assegnazione, ha una sola variabile di input e abbiamo ?c(1)c + r1 , # r1 , qui abbiamo fatto combaciare il numero di argomenti della funzione con il numero di va- riabili di input che è pari a 1. Mentre se volessimo conoscere il valore della funzione calcolata da (c) che ha però due argomenti avremmo ?c(2)c + r1 , r2 , # r1 , chiaramente il valore r2 viene ignorato non essendo corrispondente di alcun valore di variabile di input. Ora riferiamoci al programma (d ) che effettuava la somma di due interi contenuti nelle due variabili di input e la trasferiva nella variabile di uscita Y, abbiamo ?c(2)c + r1 , r2 , # r1 % r2 , mentre ?c(3) + r1 , r2 , r3 , # r1 % r2 , l’argomento r3 viene ignorato. Vediamo ora il caso opposto ?c(1)c + r1 , # r1 % 0 # r1 , in questo caso lo 0 rimpiazza in qualche modo la va- riabile del programma che non ha corrispondenza con alcuna variabile ( r2 non esiste, mentre X 2 si). DEFF.: Sia g una funzione parziale (con una o più variabili) su & , allora g si dice parzialmente calcolabile se esiste un S-programma c che la calcola e cioè se per ogni m-pla + r1 , r2 ,!, rm , > S m : &m risul- ta g + r1 , r2 ,!, rm , # ?c( m ) + r1 , r2 ,!, rm , . Da sottolineare che nel caso in cui g + r1 , r2 ,!, rm , #9 e ?c( m ) + r1 , r2 ,!, rm , #9 non si può concludere assolutamente che g # ?c( m ) in quanto il simbolo 9 non è numericamente esprimibile. Una funzione è detta calcolabile se è totale ed è parzialmente calcolabile (una funzione totale è definita in tutto il suo dominio, cioè per ogni m-pla di argomenti r1 , r2 ,! , rm ). Le funzioni parzialmente calcolabili vengono chiamate anche ricorsive parziali, analogamente le funzioni calcolabili, cioè sia totali che ricorsive parziali, vengono anche dette ricorsive. Ad esempio, dal programma visto prima: ( A) X $ X % 1 IF X ' 0 GOTO A EDIT by Qd – Calcolabilità – XVI Lez. si ha ?c(1) + x , #9 che è una funzione indefinita per ogni 74 valore di x, possiamo dunque affermare che il dominio della funzione è l’insieme vuoto A che è pur sempre un sottoinsieme di & (rif. D.S.W. pag. 3), quindi possiamo affermare che la funzione del programma suindicato appartiene alla Classe delle funzioni ricorsive parziali è quindi una funzione ricorsiva parziale (o anche parzialmente calcolabile) pur non essendo definita per alcun naturale (è quindi scorretto affermare che la funzione vista nell’esempio non è calcolabile). Estensione delle macro (rif. D.S.W. pag. 32) Facendo riferimento all’uso delle macro, la seguente scrittura W $ f +V1 ,V2 ,!,Vn , Rappresenta il trasferimento del valore di f +V1 ,V2 ,!,Vn , , calcolato da qualche S-programma, nella variabile W. In effetti l’espansione della macro è una sequenza di istruzioni che calcola ?c( n ) +V1 ,V2 ,!,Vn , # f +V1 ,V2 ,!,Vn , , quindi f è una funzione calcolabile o parzialmente calcolabile e W rappresenta una variabile generica (che potrebbe anche essere uno degli argomenti Vi di f ) . Ricorrendo a regole generali per quanto riguarda l’uso appropriato dei nomi delle variabili e delle etichette delle istruzioni, si può ottenere uno schema generale per costruire espansioni di macro inserite in programmi chiamanti (per il dettaglio vedere D.S.W. pagg. 32-33). Un caso particolare si presenta quando risulta W $ f +V1 ,V2 ,!,Vn , e f +V1 ,V2 ,!,Vn , #9 , allora anche la funzione calcolata dal programma chiamante la macro darà luogo ad un valore indeterminato. Ad esempio, il seguente programma fa uso di macro le cui estensioni calcolano funzioni che assumono valori indeterminati per certi elementi del dominio: Z $ X1 & X2 Y $ Z % X3 Poiché la macro Z $ X 1 & X 2 che fa riferimento al programma (f ) - x 1 & x 2 se x 1 * x 2 computa la funzione f f + x 1 , x 2 , # . che per certi valori è indeterminata, questa indealtrimenti /9 terminazione verrà in qualche modo tramandata alla funzione chiamante che infatti computa la funzio-B+ x 1 & x 2 , % x 3 se x 1 * x 2 ne ?c(3) + x 1 , x 2 , x 3 , # . . altrimenti B/9 Per ovviare a questi inconvenienti possiamo arricchire il nostro linguaggio di programmazione, oltre che con l’uso (opportuno) delle macro, anche con l’uso dei predicati (più articolati del tradizionale V ' 0 ) all’interno dei costrutti selettivi IF. DEF.: Un predicato P su un insieme S è una funzione totale tale che 4a > S risulta: EDIT by Qd – Calcolabilità – XVI Lez. 75 - P + a , # 1 + vero , B .oppure C B P + a , # 0 + falso , / (in realtà P può avere anche più di un argomento). Un’osservazione interessante è che l’uso dei predicati non può essere adoperato per realizzare metodi algoritmici capaci di prevedere se un algoritmo andrà in loop oppure no (si può apprendere che un algoritmo è entrato in loop esclusivamente quando entra in loop e non prima, vale ovviamente il contrario e cioè che non si può sapere a priori se un algoritmo non andrà mai in loop o meno, ma ciò non basta per affermare, in generale, che un programma non si arresterà mai, in quanto un programma entrato in un ipotetico loop potrebbe anche fermarsi da un momento all’altro, ammenoché noi non conosciamo le istruzioni del programma. Un’ ipotetica macchina che esegue un programma non può prevedere se questo avrà un calcolo (finito) o meno, tale certezza si ha solo se il programma termina). Conseguenza di que- sto concetto si vedrà più avanti quando si esibirà un predicato che non è calcolabile mediante un Sprogramma. Altro concetto da sottolineare è che facilmente si fa confusione tra predicato e funzione parzialmente calcolabile. Un predicato è una particolare funzione che ha vita propria indipendentemente dagli Sprogrammi, un predicato è una funzione che, per come è stata definita, è sempre totale (e può assumere solo e soltanto i vaori 1 e 0) al di là del fatto che possa o non possa essere calcolata da un S-programma (potrà capitare di incontrare funzioni che a prima vista sembrano predicati per come sono strutturati, ma nel momento in cui ci si accorge che tali presunti predicati assumono valori indeterminati o differenti da 0 o da 1, possiamo subito affermare che non sono predicati, ma funzioni, poi se tali funzioni sono calcolabili o parzialmente calcolabili questo è un altro discorso). Con l’uso delle macro la forma generale che assume il costrutto di selezione è: IF P +V1 ,V2 ,!,Vn , GOTO L D la cui espansione è la seguente: Z $ P +V1 ,V2 ,!,Vn , IF Z ' 0 GOTO L Viene calcolato P è memorizzato il risultato in Z; se P è vero alloro Z ' 0 quindi si va all’istruzione L; altrimenti Z # 0 e la macro termina. Vediamo ora l’esempio con un predicato largamente utilizzato: IF V # 0 GOTO L D ecco la sua espansione (non si è badato all’uso corretto dei nomi delle variabili e delle etichette delle istruzioni): IF X ' 0 GOTO E Y $Y %1 EDIT by Qd – Calcolabilità – XVI Lez. in questo caso il valore del predicato è memorizzato in Y e X corrisponde a V ; si ricordi che Y inizialmente è nullo; se X ' 0 la macro termina (GOTO E) e il valore di Y resta nullo, il programma chiamante passa all’istruzione successiva; se invece X # 0 allora Y # 1 e il programma chiamante passa all’istruzione L; Nell’esempio quindi, se il predicato "V # 0" è vero assumerà un valore non nullo, quindi si passerà all’istruzione L. 76 DEF. (rif. D.S.W. pag.34-35) : Essendo P una particolare funzione, ha senso dire che P è o non è calcolabile, quindi si parla di predicato calcolabile o non calcolabile in base alle definizioni date prima di funzioni calcolabili (essendo i predicati funzioni totali, non ha senso parlare di parziale calcolabilità, abbiamo dunque che se esiste un S-programma che calcola il predicato P, allora P è calcolabile). Mediante una generalizzazione possiamo fornire un esempio di predicato calcolabile che è il seguente: IF V @0 GOTO L Il quale è chiaramente una generalizzazione dell’istruzione IF V '0 GOTO L. Composizione di funzioni (rif. D.S.W. pag. 39) Mostriamo un metodo per combinare l’output di una o più funzioni all’input di un’altra funzione (ad una o più variabili) sulla base delle funzioni composte del tipo: h + x , # f + g + x , , . Diamo pertanto la seguente definizione per formalizzare e generalizzare il concetto: DEF.: Sia f una funzione di k variabili e siano g 1 , g 2 ,!, g k funzioni di n variabili. Se scriviamo 3 h + x 1 , x 2 ,!, x n , # f + g 1 + x 1 , x 2 ,!, x n , , g 2 + x 1 , x 2 ,!, x n , ,!, g k + x 1 , x 2 ,!, x n , , allora si dice che h è ottenuta per composizione da f e g 1 , g 2 ,!, g k . Attenzione a non confondere il numero n di variabili di h con il numero di variabili k di f , si sarebbe portati a pensare che essendoci un’uguaglianza tra h ed f il numero di argomenti di h debba coincidere con quello di f , ma h è una funzione composta i cui argomenti sono x 1 , x 2 ,! , x n e non g 1 , g 2 ,! , g k , quindi l’uguaglianza definita poc’anzi è ben posta. Del resto ha senso scrivere ad esempio che f j + x 1 , # f k + x 1 , x 2 , se si applica la diagonalizzazione dell’argomento, cioè si impone x 1 E + x 1 , x 2 , con x 1 # x 2 , le funzioni sono uguali sebbene f j ha un argomento mentre f k ne ha due. Ovviamente le funzioni f , g 1 , g 2 ,! , g k non sono necessariamente totali e h sarà calcolata quando tutte le funzioni g 1 + x 1 , x 2 ,! , x n , # z1 , g 2 + x 1 , x 2 ,! , x n , # z 2 , … , g k + x 1 , x 2 ,! , x n , # z k ed f + z1 , z 2 ,! , zn , saranno calcolate. Tale imposizione può essere giustificata facendo uso delle macro e verificando la correttezza dell’uguaglianza 3 in questo modo: Z 1 $ g 1 + X 1 , X 2 ,! , X n , Z 2 $ g 2 + X 1 , X 2 ,! , X n , 33 ' Z k $ g k + X 1 , X 2 ,! , X n , &&&&&&&&&&&&& Y $f + Z 1 , Z 2 ,! , Z k , EDIT by Qd – Calcolabilità – XVI Lez. durante la computazione vengono calcolate prima tutte le funzioni g 1 , g 2 ,!, g k e memorizzati i valori rispettivamente in Z 1 , Z 2 ,!, Z k ; dopodichè le variabili Z vengono adoperate per il calcolo di f il cui valore viene memorizzato in Y 77 La macro vista è utile per dimostrare il teorema seguente: TEOREMA 1.1 (banale – rif. D.S.W. pag 39): Se h è ottenuta per composizione delle funzioni (parzialmente) calcolabili f , g 1 , g 2 ,!, g k allora h è (parzialmente) calcolabile. DEF.: dobbiamo dimostrare che se f , g 1 , g 2 ,!, g k sono (parzialmente) calcolabili allora anche h è (parzialmente) calcolabile, ciò è immediato osservando la macro 33 , infatti per dimostrare che h è (parzialmente) calcolabile dobbiamo fornire un S-programma che la calcola utilizzando le funzioni (parzialmente) calcolabili (per ipotesi) f , g 1 , g 2 ,!, g k . È ovvio che se Z i $ g i + X 1, X 2 ,!, X n , , con 1 < i < k , e Y $ f + Z 1, Z 2 ,!, Z k , sono (parzialmente) calcolabili, ne deriva che h è (parzialmente) calcolabile. Ricorsione (rif. D.S.W. pag. 40) h +0, # k h + t % 1, # g + t , h + t , , DEF.: Supponiamo che k sia una costante e h una funzione definita in questo modo: g è una funzione totale di due variabili, allora diremo che h è ottenuta da g per ricorsione primitiva o semplicemente per ricorsione . TEOREMA 2.1: Se h è ottenuto da g per ricorsione primitiva e posto g calcolabile (g per definizione è totale), allora h è anch’essa calcolabile (quindi totale anch’essa). DIM.: È facile provare che una funzione costante del tipo f + x , # k è calcolabile, infatti essa è calcolata ad esempio dall’S-programma: Y $Y %1 F Y $ Y % 1 BB G k volte ' B Y $ Y % 1 BH queste istruzioni rappresentano l’espansione della macro Y $ k . La macro appena vista la utilizziamo per calcolare la funzione h ottenuta da g per ricorsione primitiva: ( A) Y $k si calcola prima k e si memorizza il risultato in Y; IF X # 0 GOTO E se l’argomento di h è 0 allora si esce dal programma e h + 0 , # k # Y ; altrimenti (per hp. g è calcolabile quindi il suo valore viene calcolato e memorizzato in Y ) viene effettuato il calcolo di h + t % 1 , # g + t , h + t , , un passo alla volta incrementando il parametro t partendo da 0, cioè seguendo la sequenza: Y $ g + Z ,Y , Z $ Z %1 X $ X &1 GOTO A EDIT by Qd – Calcolabilità – XVI Lez. 78 h +0, # k # Y h + 1 , # g + 0, h + 0 , , # g + 0, k , h + 2 , # g + 1, h + 1 , , ' h + x & 1 , # g + x & 2, h + x & 2 , , h + x , # g + x & 1, h + x & 1 , , Avendo fornito un S-programma che calcola h abbiamo dimostrato il teorema. Complichiamo un po’ il concetto appena visto in modo da dare una definizione più generale di ricorsione. DEF.: Sia: h + x 1 , x 2 ,!, x n ,0 , # f + x 1 , x 2 ,!, x n , h + x 1 , x 2 ,!, x n , t % 1, # g + t , h + x 1 , x 2 ,!, x n , t , , x 1 , x 2 ,!, x n , allora la funzione h a n % 1 variabili si dice ottenuta per ricorsione primitiva o semplicemente per ricorsione dalle funzioni totali f (di n variabili) e g (di n % 2 variabili). TEOREMA 2.2: Sia h ottenuta dalle funzioni a più variabili f e g per ricorsione primitiva (secondo la definizione appena vista), se f e g sono calcolabili allora h è anch’essa calcolabile. DIM.: Come per il teorema precedente, basta trovare un S-programma che calcola h (questa strategia ricorda quella adoperata per dimostrare teorema sui linguaggi regolare e C.F. per i quali si esibivano rispettivamente automi riconoscitori e grammatiche generatrici). Ricordiamo che per ipotesi g ed f sono calcolabili, il seguente S- programma calcola h, il cui schema è del tutto simile a quello dell’S-programma utilizzato per la dimostrazione del teorema precedente : ( A) Y $ f + X 1 , X 2 ,!, X n , IF X n %1 # 0 GOTO E viene memorizzato il valore di f in Y il parametro t della funzione h è rappresentato dalla variabile X n %1 Y $ g + Z ,Y , X 1 , X 2 ,!, X n , se risulta h + x 1 , x 2 ,! , x n , 0 , il programma termina e il suo valore di Z $ Z %1 X n%1 $ X n%1 & 1 GOTO A EDIT by Qd – Calcolabilità – XVI Lez. uscita sarà Y $ h + x 1 , x 2 , ! , x n , 0 , altrimenti parte il ciclo che calcola la funzione ricorsiva partendo da t # 1, ! , t # X n %1 Decima Settima Lezione 5/12/2006 Classi PRC Funzioni e Predicati primitivi ricorsivi Classi PRC (rif. D.S.W. pag. 42) DEFF.: Sia data una classe V di funzioni totali, si dice che essa è una classe PRC ( primitive recursively clo- sed ) se: 1. V contiene le funzioni iniziali (che definiremo tra poco); 2. V contiene funzioni ottenute da funzioni, che appartengono a V , mediante composizione e ricorsione primitiva. Le seguenti funzioni sono chiamate funzioni iniziali : s +x , # x %1 n+x , # 0 funzione successore ; u + x 1 , x 2 ,!, x n , # x i con 1 < i < n n i funzione nulla ; funzioni di proiezione . TEOREMA 3.1: La classe delle funzioni calcolabili è una classe PRC. DIM.: Dobbiamo dimostrare che le funzioni iniziali e le funzioni ottenute mediante composizione e ricorsione primitiva da funzioni della classe PRC sono calcolabili. I teoremi 1.1 (composizione di funzioni), 2.1 (ricorsione con una variabile) e 2.2 (ricorsione con più variabili) dimostrano parte del teorema, manca da verificare che le funzioni iniziali siano calcolabili, quindi bisogna esibire degli S-programmi che le computino. La funzione successore s + x , # x % 1 è calcolata dal programma Y $ X % 1 , mentre la funzione n+x , # 0 è calcolata dal programma vuoto , infine le (infinite) funzioni di proiezione uin + x 1 , x 2 ,!, x n , # x i sono calcolate dai programmi Y $ X i . Quindi possiamo concludere che la classe delle funzioni calcolabili è una classe PRC. DEF.: Una funzione è detta primitiva ricorsiva (il concetto di funzione primitiva ricorsiva è diverso da quello di funzione appartenente ad una classe PRC sebbene i due concetti siano strettamente connessi fra loro) se può essere ottenuta dalle funzioni iniziali applicando un numero finito di volte composizione e ricorsione primitiva, da cui abbiamo: COROLLARIO 3.2: La classe delle funzioni primitive ricorsive è una classe PRC, la cui dimostrazione è immediata. DEF.: Si distinguono tre sottoclassi: I V1 : classe PRC di funzioni totali calcolabili da S-programmi; I V2 : classe di funzioni primitive ricorsive; I V3 : classe di tutte le funzioni totali su & . 80 TEOREMA 3.3 (rif. D.S.W. pag. 43): Una funzione è primitiva ricorsiva se e solo se J appartiene a tutte le classi PRC (quindi l’insieme delle funzioni primitive ricorsive rappresenta il nucleo di ogni classe PRC, intersezione di tutte le classi PRC). DIM. K : Dimostrare che se una funzione appartiene a tutte le classi PRC allora è una funzione primitiva ricorsiva è una cosa abbastanza semplice, in quanto per il corollario 3.2 la classe delle funzioni primitiva ricorsive è una classe PRC (una funzione che appartiene a tutte le classi PRC per il corollario 3.2 apparterrà anche alla classe PRC delle funzioni primitive ricorsive, quindi deve essere necessariamente una funzione primitiva ricorsiva). DIM. 5 : Vogliamo ora dimostrare che se una funzione è primitiva ricorsiva allora appartiene ad ogni classe PRC (e non solo alla classe PRC delle funzioni primitive ricorsive). Sia f una funzione primitiva ricorsiva e V una classe PRC qualsiasi, vogliamo dimostrare che f >V . Essendo f primitiva ricorsiva essa deriva (è ottenuta) da una serie di funzioni f 1 , f 2 ,!, f n , dove ogni funzione o deriva dalle precedenti mediante composizione o ricorsione, oppure è una funzione iniziale. Le funzioni iniziali (per la definizione data di classe PRC) appartengono alla classe PRC V e (sempre per definizione) vi appartengono anche tutte le funzioni ottenute per ricorsione o per composizione, quindi f >V da cui (avendo considerato V come una qualunque classe PRC) abbiamo che f appartiene alla classe PRC, più precisamente f appartiene a ogni classe PRC. COROLLARIO 3.4: Ogni funzione primitiva ricorsiva è calcolabile (ciò non vuol dire necessariamente che ogni funzione appartenente ad una classe PRC qualsiasi è calcolabile, si ribadisce il fatto che il concetto di funzione primitiva ricorsiva è differente da quello di funzione appartenente ad una classe PRC). Il contrario non è sempre vero, infatti esistono funzioni calcolabili che non sono primitive ricorsive. DIM.: La dimostrazione è immediata, osservando il teorema precedente si ha che ogni funzione primitiva ricorsiva appartiene ad ogni classe PRC e ciascuna classe PRC è costituita da funzioni calcolabili (per la definizione di classe PRC e per il teorema 3.1). Dagli ultimi concetti visti si può affermare che una qualsiasi classe PRC deve contenere almeno le funzioni primitive ricorsive, in più può contenere altre funzioni totali purché soddisfino le proprietà di cui devono godere le funzioni appartenenti ad una classe PRC (si richiede cioè che siano totali e ottenute dalle funzioni iniziali o da altre funzioni appartenenti alla classe mediante composizione e ricorsione, da cui si può intuire che una classe PRC potrebbe contenere anche funzioni iniziali non calcolabili, l’importante è che il gruppo di funzioni iniziali sia almeno rappresentato dalle infinite funzioni successore, nulla e di proiezione, ma ciò non vieta che possano esistere classi PRC costitute da funzioni iniziali aggiuntive). È importante fissare bene i concetti visti fino ad ora, in quanto molto di ciò che seguirà si baserà su questi concetti. Diamo ora un elenco di funzioni primitive ricorsive (e quindi calcolabili): 1) x%y E f1 + x, y , # x % y Vediamo come ricavare la funzione adoperando solo le operazioni di ricorsione e composizione: EDIT by Qd – Calcolabilità – XVII Lez. 81 f 1 + x ,0 , # x , f 1 + x , y % 1, # f 1 + x , y , % 1 f 1 + x ,0 , # u11 + x , , da cui ricaviamo: 3 + con g 1 + x 1 , x 2 , x 3 , # s u23 + x 1 , x 2 , x 3 , , f 1 + x , y % 1, # g 1 + y , f 1 + x , y , , x , # x2 % 1 Per comprendere meglio l’uso della ricorsione primitiva riscriviamo la formula 3 utilizzando le lettere adottate per la definizione di ricorsione primitiva per funzioni a più variabili, abbiamo: h + x 1 ,0 , # u1 + x 1 , , 1 h + x 1 , t % 1, # g + t , h + x 1 , t , , x 1 , dove chiaramente h corrisponde a f 1 , x 1 a x, t ay g a g1 . e Abbiamo ottenuto tali equazioni adoperando le operazioni di composizione (in particolare g 1 è stata ottenuta componendo le funzioni iniziali proiezione e successore) e ricorsione primitiva. La funzione 1) è quindi ricorsiva primitiva dunque calcolabile (sebbene già sapessimo che tale funzione era calcolata dal programma (d) ora sappiamo che è anche primitiva ricorsiva). Vediamo ora un altro esempio di funzione primitiva ricorsiva: 2) x7y h2 + x , y , # x 7 y E ottenibile da: h2 + x ,0 , # 0, h2 + x , y % 1, # h2 + x , y , % x da cui: h2 + x ,0 , # n + x , # 0, h2 + x , y % 1, # g 2 + y , h2 + x , y , , x , + , con g + x 1 , x 2 , x 3 , # f 1 u23 + x 1 , x 2 , x 3 , , u33 + x 1 , x 2 , x 3 , , dove chiaramente f 1 è la funzione somma vista prima. Si ha difatti: + , f 1 u2 + x 1 , x 2 , x 3 , , u3 + x 1 , x 2 , x 3 , # f 1 + x 2 , x 3 , # x 2 % x 3 3 3 # h2 + x , y , % x . Le formule viste, osservando la natura delle funzioni utilizzate, portano ad affermare che la funzione h2 è primitiva ricorsiva. 3) x! (fattoriale) E 0! # 1, + x % 1, ! # x ! 7 s + x , più precisamente se x ! # h3 + x , abbiamo: , h3 + 0 , # 1, h3 + t % 1, # g 3 + t , h3 + t , , con g 3 + x 1 , x 2 , # s + x 1 , 7 x 2 che è primitiva ricorsiva in quanto può essere scritta così: EDIT by Qd – Calcolabilità – XVII Lez. 82 g 3 + x 1 , x 2 , # s + u12 + x 1 , x 2 , , 7 u22 + x 1 , x 2 , (chiaramente il prodotto usato è una funzione primitiva ricorsiva), quindi la funzione fattoriale è una funzione primitiva ricorsiva. Le funzioni che abbiamo visto sono state costruite mediante le funzioni iniziali che possono essere immaginate come dei mattoni, mentre la ricorsione primitiva e la composizione sono il cemento con il quale costruire le funzioni primitive ricorsive; ogni volta che viene aggiunta una funzione al nostro bagaglio di funzioni ricorsive primitive possiamo adoperarla a mo’ di mattone per costruire funzioni primitive ricorsive più complesse, proprio come abbiamo fatto per la funzione g 3 , per costruire la quale abbiamo adoperato il prodotto visto in precedenza, mentre è sottinteso che la funzione h3 + 0 , è ottenuta da s + 0 , . Osservando tale principio si ottengono le seguenti funzioni potenza e predecessore: x 0 # 1, 4) xy E 5) p5 + 0 , # 0, - x & 1 se x ' 0 p5 + x , E p5 + x , # . da cui abbiamo: se x # 0 p5 + t % 1, # t /0 x y %1 (da notare che in questo caso 0 # 1 ); 0 # x 7x y In questo caso la funzione p5 può essere computata dalla singola istruzione: X $ X & 1 , risulta + 1, p5 + x , # ? c5 + x , con c5 : X $ X & 1 . In termini di funzioni iniziali le due funzioni appena viste si ottengono come segue: 4) 5) h4 + x ,0 , # s + n + x , , # 1, h4 + x , t % 1, # g 4 + t , h + x , t , , x , p5 + 0 , # 0, p5 + t % 1, # g 5 + t , p5 + t , , + , con g 4 + x 1 , x 2 , x 3 , # h2 u23 + x 1 , x 2 , x 3 , , u33 + x 1 , x 2 , x 3 , # x 2 7 x 3 ; con g 5 + x 1 , x 2 , # u12 + t , . Proseguiamo la rassegna di funzioni primitive ricorsive: 6) -x & y x &( y (differenza tra x e y) E x &( y # . /0 se x * y se x 8 y il puntino serve a distinguere tale funzione da quella vista in precedenza x & y il cui valore per x 8 y è indefinito, mentre in questo caso non lo è, la funzione 6 è dunque totale (altrimenti non ci sarebbero neanche i presupposti per affermare che essa è primitiva ricorsiva). In termini di ricorsione primitiva la 6 diventa: x &( 0 # x , x &( + t % 1, # p5 + x &( t , EDIT by Qd – Calcolabilità – XVII Lez. e in termini di funzioni iniziali abbiamo: 83 h6 + x ,0 , # u11 + x , # x , h6 + x , y % 1, # g 6 + y , h6 + x , y , , x , + con g 6 + x 1 , x 2 , x 3 , # p5 u23 + x 1 , x 2 , x 3 , , 7) x & y (valore assoluto della differenza tra x e y), tale funzione può essere scritta in termini di funzioni primitive ricorsive precedentemente definite: x & y # + x &( y , % + y &( x , . Se x * y + x &( y , % + y &( x , # + x & y , % 0 # x & y , mentre se x 8 y si ha + x &( y , % + y &( x , # # 0 % + y & x , # y & x . In entrambi i casi otteniamo il valore assoluto della differenza tra x e y . -1 se x # 0 8) L 8 + x , (rivelatore dello 0) E L 8 + x , # . la quale può essere espressa in questo mo/0 se x ' 0 do: L 8 + x , # 1 &( x (se x # 0 , L 8 + x , # 1 & 0 # 1 , mentre se x ' 0 ( * 1) si ha L 8 + x , # 1 & x # 0 ). Alternativamente si può esprimere la funzione 8 in termini di ricorsione primitiva in questo modo: L 8 + 0 , # 1, L 8 + t % 1, # 0 . Oltre alle funzioni primitive ricorsive mostriamo due predicati primitivi ricorsivi (rif. D.S.W. 49): 9) -1 x # y E d9 + x, y , # . /0 x#y la quale si può ottenere così: d 9 + x , y , # L 8 + x & y , se x ' y se Se x # y , si ha d 9 + x , y , # L 8 + x & y , # L 8 + 0 , # 1 , altrimenti si ha d 9 + x , y , # L 8 + x & y , # 0 poiché x & y ' 0 . 10) -1 x < y E h10 + x , y , # . /0 se x<y altrimenti ottenibile da: L 8 + x &( y , . Se x < y , si ha h10 + x , y , # L 8 + x &( y , # L 8 + 0 , # 1 , altrimenti si ha h10 + x , y , # L 8 + x &( y , # # L8 + x & y , # 0 . TEOREMA 5.1: Sia V la classe PRC. Se P e Q sono predicati appartenenti a V , allora lo sono anche ) P , P CQ e P &Q . DIM.: Basta ricondurre tali predicati a equazioni primitive ricorsive, si ha: ) P # L 8 + P , , P & Q # P 7 Q e, utilizzando le leggi di De Morgan, P C Q # ) + ) P & ) Q , # L +L + P , 7 L +Q , , . Il teorema appena visto è importante perché la tesi è uno strumento essenziale per costruire un vastissimo numero di predicati primitivi ricorsivi. EDIT by Qd – Calcolabilità – XVII Lez. 84 COROLLARIO 5.2: Sia V la classe di tutte le funzioni primitive ricorsive. Se P e Q sono predicati primitivi ricorsivi, allora lo sono anche ) P , P C Q e P & Q . COROLLARIO 5.3: Sia V la classe di tutte le funzioni calcolabili. Se P e Q sono predicati calcolabili, allora lo sono anche ) P , P C Q e P & Q . Dagli ultimi risultati visti mostriamo un altro predicato primitivo ricorsivo: 11) -1 x 8 y E h11 + x , y , # . /0 se altrimenti x 8 y J + x < y ,& ) + x # y , x 8 y J ) + y < x, x8y ottenibile così: (minore e non uguale) oppure così: (non maggiore e non uguale). TEOREMA 5.4 (definizione per casi – rif. D.S.W. pag. 50): Sia V una classe PRC, siano g e h funzioni appartenenti a V e sia P un predicato anch’esso appartenente a V . Se: if P # 1 then ! g x , x , , x se P x + , + B 1 2 n 1 , x 2 ,!, x n ,, f + x 1 , x 2 ,!, x n , # . else Bh + x , x ,!, x , altrimenti 1 2 n / allora f è una funzione primitiva ricorsi- va, cioè appartenente anch’essa alla classe PRC V . Ciò che abbiamo appena visto può essere interpretato con un costrutto selettivo, se il predicato P è vero (cioè uguale a 1) allora la funzione f sarà uguale a g altrimenti la funzione f sarà uguale ad h . DIM.: la dimostrazione è ovvia poiché basta scrivere f sottoforma di espressioni contenenti funzioni primitive ricorsive, si ha: f + x 1 , x 2 ,!, x n , # g + x 1 , x 2 ,!, x n , 7 P + x 1 , x 2 ,!, x n , % h + x 1 , x 2 ,!, x n , 7 L 8 + P + x 1 , x 2 ,!, x n , , . Se P è vero risulta: f + x 1 , x 2 ,! , xn , # g + x 1 , x 2 ,! , xn , 7 1 % h + x 1 , x 2 ,! , xn , 7 L 8 + 1, # # g + x1 , x 2 ,! , xn , % h + x1 , x 2 ,! , xn , 7 0 # g + x1 , x 2 ,! , xn , ; se P è falso si ha: f + x1 , x 2 ,! , xn , # g + x1 , x 2 ,! , xn , 7 0 % h + x1 , x 2 ,! , xn , 7 L 8 + 0 , # # 0 % h + x 1 , x 2 ,! , x n , 7 1 # h + x 1 , x 2 ,! , x n , . COROLLARIO 5.5: Sia V una classe PRC, siano g 1 , g 2 ,!, g m , h funzioni ad n variabili appartenenti, assieme ai predicati P1 , P2 ,!, Pm anch’essi ad n variabili, alla classe V , posto: Pi + x 1 , x 2 ,!, x n , & Pj + x 1 , x 2 ,!, x n , # 0 , 4x 1 , x 2 ,!, x n e 41 < i 8 j < m (i predicati possono essere o tutti falsi oppure al più uno solo vero e gli altri falsi) EDIT by Qd – Calcolabilità – XVII Lez. 85 Se: - g 1 + x 1 , x 2 ,!, x n , se P1 + x 1 , x 2 ,!, x n , , B B g 2 + x 1 , x 2 ,!, x n , se P2 + x 1 , x 2 ,! , x n , , B f + x 1 , x 2 ,! , x n , # .' B g x , x ,!, x se Pm + x 1 , x 2 ,! , x n , , n, B m+ 1 2 Bh + x 1 , x 2 ,!, x n , altrimenti / allora f appartiene a V . Il fatto che uno solo dei predicati può essere vero è perché il valore di f deve essere univoco, infatti se fossero veri due predicati, f dovrebbe assumere due valori contemporaneamente e ciò non è consentito. Il corollario può essere interpretato come uno switch (o case, costrutto di selezione esteso dei linguaggi di programmazione). DIM.: La dimostrazione va fatta per induzione su m (numero dei predicati): I I (passo base) m # 1 : il corollario è dimostrato perché si riduce al teorema 5.4; (passo induttivo) m % 1 : presupponendo che il corollario sia vero per m. Basta ricondurre il caso per m % 1 a quello di m in questo modo: - g 1 + x 1 , x 2 ,! , x n , B B g 2 + x 1 , x 2 ,!, x n , B f + x 1 , x 2 ,! , x n , # .' Bg B m %1 + x 1 , x 2 ,!, x n , Bh + x 1 , x 2 ,! , x n , / se P1 + x 1 , x 2 ,! , x n , , se P2 + x 1 , x 2 ,! , x n , , se Pm %1 + x 1 , x 2 ,! , x n , , altrimenti ora se poniamo: -B g m %1 + x 1 , x 2 ,!, x n , se Pm %1 + x 1 , x 2 ,! , x n , , h 6 + x 1 , x 2 ,! , x n , # . altrimenti B/h + x 1 , x 2 ,! , x n , dal teorema 5.4 possiamo affermare che h 6 >V , possiamo allora riscrivere f così: - g 1 + x 1 , x 2 ,!, x n , se P1 + x 1 , x 2 ,!, x n , , B B g 2 + x 1 , x 2 ,!, x n , se P2 + x 1 , x 2 ,! , x n , , B f + x 1 , x 2 ,! , x n , # .' B g x , x ,!, x se Pm + x 1 , x 2 ,! , x n , , n, B m+ 1 2 Bh 6 + x 1 , x 2 ,!, x n , altrimenti / Abbiamo dunque ridotto il problema a dimensione m che per ipotesi di induzione è vero, quindi il corollario è dimostrato. EDIT by Qd – Calcolabilità – XVII Lez. Decima Ottava Lezione 12/12/2006 operazioni iterate e quantificatori limitati minimalizzazione altre funzioni e predicati primitivi ricorsivi Operazioni Iterate e Quantificatori Limitati (rif. D.S.W. pag. 52) TEOREMA 6.1: Sia V una classe PRC. Se f + t , x 1 , x 2 ,!, x n , >V allora appartengono a V anche le funzioni così definite: y y t #0 t #0 g + y , x 1 , x 2 ,! , x n , # M f + t , x 1 , x 2 ,! , x n , e h + y , x 1 , x 2 ,! , x n , # N f + t , x 1 , x 2 ,! , x n , . DIM.: Bisogna dimostrare il teorema adoperando le seguenti equazioni ricorsive: g + 0, x 1 , x 2 ,! , x n , # f + 0, x 1 , x 2 ,!, x n , , e g + t % 1, x 1 , x 2 ,! , x n , # g + t , x 1 , x 2 ,! , x n , % f + t % 1, x 1 , x 2 ,! , x n , h + 0, x 1 , x 2 ,!, x n , # h + 0, x 1 , x 2 ,!, x n , , h + t % 1, x 1 , x 2 ,! , x n , # h + t , x 1 , x 2 ,! , x n , 7 f + t % 1, x 1 , x 2 ,! , x n , Le funzioni g + t , x 1 , x 2 ,!, x n , e h + t , x 1 , x 2 ,!, x n , si ricavano da queste formule di ricorsione finché non si risale a f + 0, x 1 , x 2 ,!, x n , , quindi il teorema è dimostrato. di: Qualche volta la sommatoria o la produttoria cominceranno da t # 1 e non t # 0 , scriveremo quiny y t #1 t #1 g + y , x 1 , x 2 ,! , x n , # M f + t , x 1 , x 2 ,! , x n , e h + y , x 1 , x 2 ,! , x n , # N f + t , x 1 , x 2 ,! , x n , . Per la relativa dimostrazione bisogna sostituire i casi base delle formule ricorsive viste poco fa con queste: g + 0, x 1 , x 2 ,!, x n , # 0 e h + 0, x 1 , x 2 ,!, x n , # 1 da cui, più formalmente, abbiamo il seguente: COROLLARIO 6.2 (rif. D.S.W. pag. 53): Sia V una classe tengono a V anche le due funzioni: PRC, se f + t , x 1 , x 2 ,!, x n , >V allora appar- y y t #1 t #1 g + y , x 1 , x 2 ,! , x n , # M f + t , x 1 , x 2 ,! , x n , e h + y , x 1 , x 2 ,! , x n , # N f + t , x 1 , x 2 ,! , x n , . TEOREMA 6.3 (teorema analogo al precedente, ma relativo ai predicati, rif. D.S.W. pag. 53 – si veda anche, per i quantificatori limitati, D.S.W. pag. 7): Se il predicato P + t , x 1 , x 2 ,! , x n , >V , con V classe PRC, allora appartengono a V anche i predicati: + 4t ,< y P + t , x1 , x 2 ,!, xn , e + Ot ,< y P + t , x1 , x 2 ,!, xn , . 87 Tali scritture indicano rispettivamente i predicati QU e Q E , in particolare le scritture + 4t ,< y e + Ot ,< y vengono chiamate rispettivamente quantificatore universale limitato e quantificatore esistenziale limitato. “Limitato” indica il fatto che hanno significato soltanto per valori minori o uguali di y . Più esplicitamente il predicato QU può essere scritto così: 4t < y | P + t , x 1 , x 2 ,! , x n , QU + y , x 1 , x 2 ,!, x n , per ogni t < y se risultano veri tutti i predicati P allora QU è vero e QU può essere espresso come segue: QU + y , x 1 , x 2 ,!, x n , J P + 0, x 1 , x 2 ,! , x n , & P + 1, x 1 , x 2 ,! , x n , & ! & P + y , x 1 , x 2 ,! , x n , +P, +P, +P, il predicato QU è vero soltanto se sono veri tutti i predicati P ; Mentre il predicato Q E viene così espresso: Ot < y | P + t , x 1 , x 2 ,! , xn , Q E + y , x 1 , x 2 ,!, xn , esiste almeno un t < y per cui è vero il predicato P allora Q E è vero e Q E può essere espresso come segue: Q E + y , x 1 , x 2 ,!, x n , J P + 0, x 1 , x 2 ,!, x n , C P + 1, x 1 , x 2 ,! , x n , C ! C P + y , x 1 , x 2 ,! , x n , +|, +|, +|, il predicato Q E è vero soltanto se almeno uno dei predicati P è vero . Passiamo alla dimostrazione del teorema: DIM.: In modo immediato si giunge a dimostrare il teorema osservando che: QS y 0 R + 4t ,t < y P + t , x1 , x 2 ,!, xn , J TT VN P + t , x1 , x 2 ,!, xn , 1 # 1 UU 2 Y X W t #0 affinché la produttoria valga 1 tutti i predicati devono essere veri e QS y 0 R 2 Y. + Ot ,t < y P + t , x1 , x 2 ,!, x n , J TT V M P + t , x1 , x 2 ,!, xn , 1 ' 0 UU X W t #0 affinché la sia non nulla, almeno un predicato deve essere vero Avendo espresso i predicati mediante espressioni primitive ricorsive appartenenti alla classe teorema è dimostrato. Da notare che il predicato QU può essere anche espresso così: S y 0 t P t , x , x , ! , x 4 # + ,t < y + 1 2 V N P + t , x 1 , x 2 ,! , x n , 1 n, W t #0 2 il predicato è uguale alla produttoria dei predicati P che se risultano tutti veri rende la produttoria pari a 1 che corrisponde a valore vero EDIT by Qd – Calcolabilità – XVIII Lez. PRC il 88 Non si può esprimere in maniera analoga il predicato Q E in quanto il valore della sommatoria potrebbe essere 0, 1 o anche valori maggiori di 1 (non ammessi per desumere il valore di un predicato, vero o falso, non sarebbe quindi più considerato un predicato, ma una funzione), mentre nel caso precedente la produttoria poteva assumere soltanto valori pari a 0 o a 1. Analogamente a quanto succedeva nel teorema 6.1 (in cui esisteva la variante in cui t partiva da 1 e non da 0), nel caso attuale talvolta potremmo utilizzare le seguenti scritture: + 4t ,8 y e + Ot ,8 y ( “ 8 y ” e non “ < y ” ) Il teorema rimarrebbe valido se esprimiamo i quantificatori come segue: + Ot ,t 8 y P + t , x1 , x 2 ,!, x n , J + Ot ,t < y SWt ' y & P + t , x1 , x 2 ,!, xn , 02 esiste almeno una t < y tale che t ' y e P vero e + 4t ,t 8 y P + t , x1 , x 2 ,!, xn , J + 4t ,t < y SWt # y C P + t , x1 , x 2 ,!, xn , 02 per ogni t < y risulta che se t # y allora P può anche essere falso, mentre se t ' y , affinche il predicato QU sia vero, P deve essere necessariamente vero Vediamo ora altri esempi di predicati primitivi ricorsivi: 12) y | x (y è un divisore di x) ( 3 | 12 E vero , mentre 3 | 13 E falso ). Adoperando gli ultimi teoremi visti si scopre che questo predicato è primitivo ricorsivo infatti si può esprimere così: y | x J + Ot ,< x + y 7 t # x , in effetti si cerca il primo valore non maggiore di x per cui y 7 t # x . Lo si cerca non maggiore in quanto se t @ x si avrebbe y # sore (intero) di x ; 13) Primo + x , x t e 0 < y 8 1 che non può essere un divi- (x è un numero primo) È un predicato primitivo ricorsivo anche questo, infatti: Primo + x , J x @1 * un numero primo deve essere >1 & + 4t ,< x !t # 1 C t # x C ) + t | x ," . "### #$#### % EDIT by Qd – Calcolabilità – XVIII Lez. a eccezione dell'1 e di se stesso non deve avere divisori 89 Minimalizzazione (rif. D.S.W. pag 55) Dal teorema 6.1 sappiamo che se il predicato P + t , x 1 , x 2 ,!, x n , >V con V classe funzione: y u g + y , x 1 , x 2 ,! , x n , # M N L + P + t , x 1 , x 2 , ! , x n , , u #0 t #0 PRC, allora la appartiene a V . Analizziamo la funzione supponendo per prima cosa che il predicato P per un valore t 0 < y sia: P + t , x 1 , x 2 ,! , x n , # 0 per t 8 t0 mentre si ha: P + t 0 , x 1 , x 2 ,!, x n , # 1 In altre parole t 0 rappresenta il più piccolo valore che può assumere t che rende vero il predicato P. Per valori di t 8 t 0 il predicato risulta falso, mentre per t # t 0 il predicato è vero (non ci interessa sapere il valore del predicato per valori di t @ t 0 ) . Da ciò possiamo affermare che: 3 u 1 se u 8 t 0 L + P + t , x , x ,!, x , , # . N 0 t #0 1 Se u 8 t 0 abbiamo u / se u * t 0 N L + P + t , x 1 , x 2 ,! , x n , , = t #0 mentre se u # t 0 otteniamo t n 2 &1 t0 u NL +0, = t #0 u N1 = 1 t #0 ; N L + P + t , x1 , x 2 ,! , xn , , # t #0 S0 0 # V N L + P + t 0 & 1, x 1 , x 2 , ! , x n , , 1 7 L + P + t 0 , x 1 , x 2 ,! , x n , , # 1 7 L + 1, # 1 7 0 # 0 ; W t #0 2 chiaramente per valori u @ t 0 il risultato rispetto al caso precedente non cambia, infatti si avrebbe una produttoria in cui compare almeno uno 0, quindi l’espressione varrà sempre 0 da t 0 in poi. Chiaramente, poiché lo 0 non porta contributo alla somma, possiamo riscrivere la funzione g in questo modo: g + y , x 1 , x 2 ,! , x n , # M 1#t u 8t 0 0 sommatoria di tutti i valori assunti dalla produttoria a partire da 0 fino ad arrivare a u 8 t0 y L’espressione u viene fatto il conteggio di tutte le volte che l’espressione 3 risulta vera; quindi la funzione g altro non è che il più piccolo valore t 0 per cui P + t , x 1 , x 2 ,! , x n , è vero MN L + P + t , x 1 , x 2 ,! , xn , , va interpretata come un contatore di predicati falsi. u #0 t #0 EDIT by Qd – Calcolabilità – XVIII Lez. 90 DEF.: Definiamo ora la seguente scrittura: -B g + y , x 1 , x 2 ,!, x n , min P + t , x 1 , x 2 ,!, x n , # . t<y B/0 se + Ot ,< y P + t , x1 , x 2 ,!, x n , , altrimenti In pratica se esiste un minimo questo varrà almeno 1, se non esiste (alcun predicato vero) varrà 0. Quindi min P + t , x 1 , x 2 ,!, x n , rappresenta il più piccolo valore che può assumere t + < y , per il quale il t<y predicato P risulta vero, questo se t esiste; se questo valore t non esiste la funzione assume valore nullo. Utilizzando i teoremi 5.4 (it…then…else) e 6.3 (quantificatori limitati) abbiamo il seguente: TEOREMA 7.1: Sia V una classe PRC, se P + x 1 , x 2 ,!, x n , >V e risulta f + y , x 1 , x 2 ,! , x n , # min P + t , x 1 , x 2 ,! , x n , , allora f + y , x 1 , x 2 ,! , x n , >V . t<y DIM.: Come già anticipato la dimostrazione si ricava adoperando i teoremi 5.4 e 6.3, la quale è immediata. Dal teorema 6.3 si dimostra che + Ot ,< y P + t , x 1 , x 2 , ! , x n , è primitiva ricorsiva, quindi con questa ipotesi, dal teorema 5.4 (definizione per casi) si dimostra anche che min P + t , x 1 , x 2 , ! , x n , è primitiva t<y ricorsiva e che quindi appartiene ad una classe PRC. DEF.: L’operazione min viene chiamata minimalizzazione (limitata). t<y Grazie all’ultima definizione data, possiamo definire un’altra funzione primitiva ricorsiva: 14) WV x y 21 (parte intera –base– del quoziente x y ) ( WV 7 2 21 # 3, VW2 3 21 # 0 ) Mediante la minimalizzazione otteniamo: VW x y 12 # min SW+ t % 1, 7 y @ x 02 t <x da notare che compare min e non min , infatti se comparisse y, ad t <x t<y esempio VW5 121 non darebbe il risultato corretto, in quanto y # 1 e min (+ t % 1 , 7 y @ x ) # 0 . t<y Quindi la 14 è una funzione primitiva ricorsiva. L’uso della minimalizzazione funziona per tentativi, ovvero VW x y 12 è il più piccolo intero t < x tale che + t % 1, 7 y @ x . Facciamo un esempio WV5 2 21 # 2 , partendo da t # 0 , il predicato risulta falso: + t % 1, 7 y @Z x J 1 7 2 @Z 5 ; andiamo avanti con t # 1 , il predicato risulta ancora falso: + t % 1, 7 y @Z x J J 2 7 2 @Z 5 ; proviamo per t # 2 , il predicato in questo caso è vero infatti si ha: + t % 1 , 7 y @ x J J 3 7 2 @ 5 . Quindi VW5 2 12 # t # 2 . Il predicato in questo caso risulta vero 4t * 2 , ma la ricerca si inter- EDIT by Qd – Calcolabilità – XVIII Lez. 91 rompe a 2, che, avendo adoperato la minimalizzazione limitata, rappresenta il minimo valore per cui risulta vero il predicato. Importante notare che per come è stata definita la 14 il caso particolare di VW x 0 12 # 0 , (infatti min (+ t % 1 , 7 y @ x ) # 0 , in quanto per tutti i valori di t < x il predicato risulterà sempre falso, non esistendo alcun valore t <x di t per cui sia vero il predicato, per come è stata definita la minimalizzazione limitata). Dalla 14 ricaviamo la R + x, y , 15) (funzione resto (remainder), della divisione tra x e y) E possiamo esprimerla così: R + x , y , # x &( + y 7 VW x y 12 , che è chiaramente primitiva ricorsiva. La formula si ottiene in quanto x # WV x y 21 7 y % R + x , y , J R + x , y , # x &( + WV x y 21 7 y , . Anche per questa funzione c’è un caso particolare, risulta R + x ,0 , # x (infatti x &( + 0 7 WV x 0 12 , # # x &( 0 # x ). Altra funzione importante è la seguente: pn con n @ 0 (n-mo numero primo) 16) Stabiliamo che p0 # 0 , quindi avremo p1 # 2, p2 # 3, p3 # 5, p4 # 7, p5 # 11,! Per esprimere pn ci serviamo delle equazioni di ricorsione, abbiamo: p0 # 0, pn %1 # min SPrimo + t , & t @ pn 0 t < pn ! %1 W 2 Per verificare la correttezza dell’uguaglianza dobbiamo verificare che valga la disequazione: pn %1 < + pn , ! % 1 . L’ + n % 1,&mo numero primo si ricava utilizzando n & mo numero primo ricorsiva- mente e corrisponde al più piccolo numero + t , che sia primo e sia (ovviamente) maggiore di pn , il valore + t , però non deve essere maggiore di pn ! % 1 . Notiamo che vale l’uguaglianza: Essendo 1 pi + pn , ! %1 pi pi > Z & ( pi * 2 ) ed essendo affermare che pi non divide infatti + pn , ! % 1 # + pn , ! pi % 1 pi #K % + pn , ! pi 1 pi con K intero e 08i <n > & (risulta infatti + pn , ! % 1 , ovvero + pn , ! % 1 . + pn , ! pi # pn 7 + pn & 1 , 7 ! 7 pi 7 ! 7 3 7 2 pZ i > & ) possiamo non è divisibile per nessun numero primo p1 , p2 , ! , pn (risulta che rappresenta la somma di una quantità intera per un’altra non intera, il cui risultato è una quantità non intera). Da quest’ultima affermazione potrebbe risultare che: a) (out) o + pn , ! % 1 è un numero primo (un numero primo non è divisibile per numeri primi minori di es- so e ciò basta per affermare che un numero primo non è divisibile per alcun numero minore di esso, mag- EDIT by Qd – Calcolabilità – XVIII Lez. 92 giore di 1; numeri minori di esso non primi comunque non lo dividono, in quanto costituiti da numeri primi che non lo dividono, insomma credo che ci siamo capiti !); b) (out) oppure + pn , ! % 1 è divisibile per un numero primo maggiore di pn (questa è un’eventualità del tutto possibile). In entrambi i casi quindi possiamo affermare che esiste un numero primo q tale che: pn 8 q < + pn , ! % 1 (infatti se vale a) allora + pn , ! % 1 @ pn e ciò non esclude che tra + pn , ! % 1 e pn ci siano altri numeri primi; se invece vale b) deve esistere un numero primo maggiore di pn che divide + pn , ! % 1 , appunto q). Quindi abbiamo che pn %1 < + pn , ! % 1 (poiché se pn 8 q < + pn , ! % 1 allora pn 8 pn %1 < q < + pn , ! % 1 ), ciò assicura la correttezza dell’uguaglianza pn %1 # min S Primo + t , & t @ pn 0 . t < pn ! %1 W 2 Tale procedimento deriva dalla dimostrazione di Euclide circa l’inesistenza di un estremo superiore dell’insieme dei numeri primi (insieme infinito), la quale si dimostra per assurdo. Abbiamo dato per scontato che pn fosse una funzione primitiva ricorsiva, dimostriamolo: SPrimo + t , & t @ y 02 sia: h + y , z , # min t <z W la quale calcola il più piccolo numero primo t tale che y 8t <z e sia: k + x , # h + x , x ! % 1, che calcola il più piccolo numero primo t tale che x 8 t < x ! % 1 . Le funzioni appena definite sono primitive ricorsive e le possiamo adoperare per riscrivere la formula ricorsiva usata per definire pn , si ha: p0 # 0, pn %1 # k + pn , possiamo quindi concludere che pn è una funzione primitiva ricorsiva. Tale funzione calcolabile è importante per farci capire che, ad esempio, linguaggi con stringhe di lunghezza p, con p numero primo, non sono C.F., mentre gli S-programmi hanno la capacità di generare numeri primi. Inoltre i numeri primi, per le loro proprietà, sono importanti (essenziali) per la numerazione di Gödel che vedremo a breve. Vale la pena notare che, utilizzando i vari teoremi visti e le macro in modo opportuno, possiamo effettivamente costruire un S-programma f che realmente calcoli pn , ma tale programma sarebbe estremamente inefficiente (per calcolare pn bisogna calcolare prima tutti i numeri primi precedenti pi con 0 8 i 8 n ). DEF.: Andiamo ora ad analizzare la minimalizzazione quando questa non è limitata, la rappresentiamo così: min P + x 1 , x 2 ,! , x n , y , y intendendo il più piccolo valore che può assumere y per cui il predicato P + x 1 , x 2 ,! , x n , y , risulta vero. EDIT by Qd – Calcolabilità – XVIII Lez. 93 Mentre nella minimalizzazione limitata veniva rappresentato il più piccolo valore t < y ( $ limite superiore) per cui valeva il predicato P. Non avendo però limiti, in questo caso, se non ci dovesse essere alcun valore di y per cui sia vero il predicato P + x 1 , x 2 ,! , x n , y , allora il valore che assume la minimalizzazione non limitata è indefinito, in quanto non è in grado di stabilire se c’è un valore y per cui valga P ammenoché questo valore non esista. Quindi si capisce bene che la minimalizzazione non limitata può produrre funzioni che non sono totali. Chiaro esempio di questo concetto è il seguente: x & y # min ( y % z # x ) la quale è indefinita se x 8 y (infatti la funzione continuerà a testare all’infinito z y % z # x che sarà sempre falso). Il prossimo teorema formalizza il concetto secondo cui esistono predicati del tipo P + x , y , che sono primitivi ricorsivi tali che min P + x , y , è una funzione che non è primitiva ricorsiva: y TEOREMA 7.2 (rif. D.S.W. pag. 58): Se P + x 1 , x 2 ,! , x n , y , è un predicato calcolabile e g + x 1 , x 2 ,! , x n , # min P + x 1 , x 2 ,! , x n , y , allora g è una funzione parzialmente calcolabile (cioè non è detto y che sia totale). DIM.: È semplice dimostrare il teorema, basta trovare un S-programma che calcola g + x 1 , x 2 ,!, x n , : ( A) IF P + X 1 , X 2 ,! , X n ,Y Y $Y %1 GOTO A , GOTO E il programma cicla finché Y non soddisfa il predicato Tale programma dimostra che g + x 1 , x 2 ,!, x n , è parzialmente calcolabile (ma non è detto che g sia anche totale, in quanto potrebbe assumere un valore indefinito 9 , se il predicato P risultasse falso per qualsiasi valore di Y. Un’osservazione, se volessimo realizzare un predicato mediante composizione di funzioni, del tipo ad e- + , sempio: P0 min P + x 1 , x 2 , ! , x n , y , , questa è di fatto una funzione parzialmente calcolabile, non esseny do totale (poiché min potrebbe assumere valore intederminato 9 ) non può essere considerata un predicato parzialmente calcolabile in quanto per definizione i predicati sono funzioni totali. Quindi P0 non è un predicato. Funzioni di Accoppiamento e Numerazione di Gödel (per la codifica numerica dei programmi – rif. D.S.W. pag. 59) Ora vediamo un metodo di codifica che ci permette di esprimere in modo biunivoco un dato Sprogramma mediante i numeri, tale codifica / decodifica è assicurata dall’utilizzo di particolari funzioni primitive ricorsive, dette di accoppiamento e mediante l’uso dei numeri primi in modo opportuno (esiste EDIT by Qd – Calcolabilità – XVIII Lez. 94 un’unica rappresentazione per fattori di numeri primi per ciascun numero naturale, dal teorema fondamentale dell’aritmetica). DEF.: Andiamo a definire le funzioni di accoppiamento (pairing functions - dette anche di angoletto). Tali funzioni servono a codificare in modo univoco coppie di numeri naturali, mediante la rappresentazione di un intero, come segue: x , y # 2 x 7 + 2 y % 1, &( 1 tale funzione è primitiva ricorsiva. Poiché risulta 2 x 7 + 2 y % 1, ' 0 , l’operazione &( non darà mai come risultato 0, se non quando 2 x 7 + 2 y % 1, # 1 , quindi possiamo trattare &( come una normale sottrazione (cioè le lacune di &( in questo caso non hanno effetto) e ci è consentito spostare l’1 al primo membro dell’uguaglianza: x , y % 1 # 2 x 7 + 2 y % 1, . Sia z un numero intero dato, allora l’equazione x , y # z avrà un’unica soluzione (rif. D.S.W. pagg. 59-60). DEF.: Dalla funzione di accoppiamento posso definire altre due funzioni primitive ricorsive: l +z , e r +z , (dette rispettivamente il sinistro di z e il destro di z) e risulta: l +z , # x e r +z , # y l +z , < z e r +z , < z e dall’equazione di accoppiamento risulta: poiché x , y 8 z % 1 . Possiamo esprimere le due funzioni appena definite mediante funzioni primitive ricorsive, ricordando anche che x # l + z , e y # r + z , sono uniche, così: l + z , # min SW+ Oy ,<z + z # x , y , 02 x <z e r + z , # min SW+ Ox ,<z + z # x , y , 02 y <z . Possiamo interpretare tali funzioni dicendo che l + z , + r + z , , è il più piccolo numero x + y, per cui vale l’equazione z # x , y , se esiste un y < z + x < z , che soddisfa tale uguaglianza. Quindi, se la funzione di accoppiamento ci permette di ricavare z da x e da y, le funzioni sinistro e destro ci permettono di ricavare rispettivamente x e y da z. Di conseguenza la seguente biiezione è vera: x, y # z J x # l +z , & y # r +z , . EDIT by Qd – Calcolabilità – XVIII Lez. 95 Ricapitoliamo le proprietà delle funzioni viste mediante il seguente: TEOREMA 8.1 (sulla funzione di accoppiamento): Le funzioni x , y , l + z , ed r + z , hanno le seguenti proprietà: 1. sono primitive ricorsive ; 2. l + x , y ,#x ed r + x , y ,# y ; l + z ,,r +z , # z ; 3. 4. l + z , , r + z , < z . Ora andiamo a definire una funzione primitiva ricorsiva per la codifica e decodifica di un’arbitraria sequenza di numeri, ovvero definiamo il numero di Gödel: DEF.: Chiamiamo numero di Gödel della sequenza + a1 , a2 ,!, an , la seguente funzione primitiva ricorsiva (indicando in parentesi quadre [ ] la sequenza da codificare): n ( a1 , a2 ,!, an ) # N piai (chiaramente pi sta per l’i-mo numero primo) i #1 Tale funzione (assieme ad un’altra funzione che vedremo a breve) ci permette di effettuare una codifica / decodifica biunivoca della sequenza + a1 , a2 ,!, an , , in quanto viene fatto uso dei numeri primi e si fa leva sul teorema fondamentale dell’aritmetica (ricordiamolo, secondo il quale ogni intero ha una fattorizzazione unica di numeri primi). Esempio di numero di Gödel per la sequenza + 3, 1, 5, 4,6 , , viene così espresso: ( 3,1,5, 4,6 ) ed è uguale 3 1 5 a p17p27p 37p 4 4 7p 6 5 3 1 5 4 6 # 2 7 3 7 5 7 7 7 11 # 319 013 847 075 000 . Trattando con numeri primi e po- tenze è facile ottenere valori spropositati molto facilmente. Per ogni n fissato la funzione ( a1 , a2 ,! , an ) è primitiva ricorsiva. TEOREMA 8.2 (rif. D.S.W. pag. 61): La numerazione di Gödel soddisfa la seguente proprietà: se ( a1 , a2 ,!, an ) # (b1 , b2 ,!, bn ) allora ai # bi , 1 < i < n . Quest’ultima implicazione è proprio conseguenza di quanto detto prima circa l’unicità della fattorizzazione di numeri primi. Però c’è da considerare un caso particolare: ( a1 , a2 ,!, an ) # ( a1 , a2 ,!, an ,0) e più in generale: ( a1 , a2 ,!, an ) # ( a1 , a2 ,!, an ,0,0,!,0) . Ciò accade perché pn0%1 # 1 , tale fattore lascia immutata la produttoria, in pratica, aggiungendo zeri in coda alla sequenza di numeri, il numero di Gödel non cambia. Quindi per convenzione il numero di Gödel pari a 1 corrisponde alla sequenza vuota, sequenza di lunghezza 0. A eccezione di questo caso la biunivocità è comunque assicurata per tutti gli altri casi, infatti se si aggiunge uno o più zeri in testa o in mezzo alla sequenza il numero di Gödel cambia. EDIT by Qd – Calcolabilità – XVIII Lez. 96 Esempi: ( 2, 0, 3) # 2 ( 2, 3) # 2 2 7 33 2 0 # 108 e ( 2, 3, 0) # 2 2 7 33 7 50 # 108 ; ma ( 0, 2, 3) # 2 0 7 32 7 5 3 # 1125 e anche 3 7 3 7 5 # 500 . Ora definiamo una funzione primitiva ricorsiva che ci è utile per la decodifica dei numeri di Gödel: + x ,i e lo chiameremo i-mo componente del numero di Gödel (o anche funzione di proiezione). Se x # ( a1 , a2 ,! , an ) allora + x ,i # ai , 1 < i < n e può essere espresso mediante la seguente funzione primitiva ricorsiva: + x ,i # min + ) pit %1 | x , t <x da cui si possono verificare i casi particolari in cui + x ,0 # 0 e + 0 ,i # 0, 4i . La funzione appena vista cerca il più piccolo intero t + < x , tale che pit %1 non divide x (stiamo dunque cercando un esponente t proprio perché i numeri della sequenza codificati compaiono come esponenti). Più intuitiva sarebbe stata la funzione se avessimo avuto a disposizione una funzione primitiva ricorsiva massimo cosicché avremmo potuto definire l’i-mo componente del numero di Gödel in questo modo: + x ,i # max + pi t | x , t <x più semplicemente. Vediamo un esempio per comprendere come opera la funzione appena vista che fa uso del minimo: rifacciamoci all’esempio visto prima sul numero di Gödel x # 1125 , vogliamo calcolare + x ,2 , quindi dobbiamo cercare il più piccolo intero t + < x , tale che p2 t %1 t %1 mero t partendo da 0, per t # 0 abbiamo che p2 quindi per t %1 p2 t #1 abbiamo t %1 p2 + # 3t %1 , Z| x + # 1125 , . Iniziamo a cercare il nu- + # 3 , | 1125 , quindi andiamo avanti incrementando t, + # 3 , | 1125 ; 2 proseguiamo per t #2 per cui otteniamo + # 3 , Z| 1125 . Quindi ci fermiamo nella ricerca e possiamo concludere che + x ,i # t # 2 . 3 Definiamo un’altra funzione primitiva ricorsiva: + + Lt + x , # min + x ,i ' 0 & + 4j ,< x j < i C + x , j # 0 i<x ,, e la chiameremo lunghezza (length) della sequenza ( a1 , a2 ,! , an ) # x Definiamo tale sequenza in modo tale che an ' 0 (in quanto se così non fosse la sequenza con uno o più 0 in coda differirebbe ma non varierebbe il numero x, quindi non si avrebbe univocità nel risultato). L’uso del quantificatore universale ci assicura che tutto il predicato (min) sia vero se i assume un valore tale che il predicato risulti sempre vero 4j < x (serie di 0 alla coda della sequenza). Cerchiamo di interpretare la funzione: min + + x ,i ' 0 & !, , se la sequenza fosse fatta di tutti 0 allora il i<x predicato + x ,i ' 0 & ! sarebbe sempre falso (da i # 0 a i # x ) quindi il valore che assumerebbe min + + x ,i ' 0 & !, sarebbe pari a 0. i<x Se la sequenza fosse invece priva di zeri, il predicato + x ,i ' 0 (senza considerare il membro a destra di &) sarebbe vero per tutta la lunghezza della sequenza, ciò comprometterebbe la conta di i. Quindi dob- EDIT by Qd – Calcolabilità – XVIII Lez. 97 + , biamo vedere cosa accade all’altro membro del predicato & e cioè + 4j ,< x j < i C + x , j # 0 che deve risultare falso, in modo da rendere falso tutto l’argomento di min. Quindi ci deve essere almeno un valore j < x per cui deve essere falso sia j < i che + x , j # 0 e ciò è assicurato dal fatto che ad esempio, poiché avevamo ipotizzato una sequenza priva di zeri sicuramente si presenterà la condizione in cui j <Z i però j < n e + x , j #Z 0 , ciò si verificherà fintantoché i 8 n . A quel punto min termina la conta e restituisce il risultato corretto. La presenza di uno o più zeri in coda non compromette il risultato che è pari alla lunghezza della sequenza priva di zeri in coda; infatti da un’analisi della funzione, il predicato all’interno del min risulterà vero se dopo l’analisi di uno 0 termina la sequenza o seguono soltanto altri zeri nel caso in cui j, superato i, se ci sono numeri diversi da 0, renderà falso il predicato j < i C + x , j # 0 …meglio, anzi meno peggio di così non so spiegarlo, purtroppo. Da quanto analizzato possiamo affermare che Lt + 0 , # Lt + 1, # 0 (ricordiamo che per convenzione il numero di Gödel pari a 1 rappresenta la sequenza vuota, mentre un numero di Gödel pari a 0 non esiste). Inoltre se ad esempio 2 x # 20 # 2 7 5 # ( 2, 0,1) , allora risulterà, quando verrà effettuata la ricerca + x ,3 # 1 , ma + x ,4 # 0 come ogni + x ,i per i @ 3 , la ricerca avrà termine quando verrà raggiunto il limite superiore e cioè a + x , x # + x ,20 # 0 . Poiché per i @ 3 tutti i + x ,i # 0 , il risultato sarà Lt + 20 , # 3 . Osserviamo infine che se x @ 1 (come del resto deve essere) e risulta Lt + x , # n , allora pn | x e nessun primo più grande di pn divide x. Non sarebbe la stessa cosa se ci fossero zeri in coda alla sequenza. Da ciò affermiamo che: Lt +( a1 , a2 ,! , an ), # n J an ' 0 (altrimenti Lt +( a1 , a2 , ! , an &1 , 0), # n & 1 ). Riassumiamo le funzioni di decodifica viste, mediante il seguente: TEOREMA 8.3 (sulla sequenza numerica – rif. D.S.W. pag. 62): a. +( a , a ,!, a ), 1 2 n i - ai #. /0 se 1 < i < n, altrimenti b. SW+ x ,1 , + x ,2 ,!, + x ,n 02 # x se n * Lt + x , + ( a 1 , a 2 , ! , a n ) ,i # + x ,i # ai (+ x ,1 , + x ,2 ,! , + x ,n ) # ( a1 , a2 ,! , an ) # x n # Lt + x , se non ci sono zeri in coda alla sequenza; n @ Lt + x , se c’è uno o più zeri in coda alla sequenza. EDIT by Qd – Calcolabilità – XVIII Lez. ; Decima Nona Lezione 14/12/2006 Codifica numerica dei programmi Interruzione di un predicato e problema dell’insolvibilità dell’arresto La codifica numerica dei programmi (rif. D.S.W. pag. 65) Vediamo ora come associare ad un programma c , di un linguaggio f , un numero (codifica), che indichiamo così: # +c , , il cui programma (decodifica) potrà essere recuperato mediante questo numero. Per iniziare fissiamo i nomi delle variabili nell’ordine seguente: Y X 1 Z1 X 2 Z2 X 3 Z3 ! (anche in questo caso i pedici 1 possono essere omessi); per le etichette abbiamo: A1 B1 C 1 D1 E 1 A2 B2 C 2 D2 E 2 A3 !. L’ordine delle variabili e delle etichette è importante e non deve cambiare, in tal modo possiamo definire notazioni indicanti la posizione di ogni variabile/etichetta in base al nome: # +V , # +L, posizione variabile; posizione etichetta (label) Esempi: # + X 2 , # 4 ; # +Y , # 1 ; # + Z , # 3 ; # + E , # 5 . Ora poniamo con la lettera I un’istruzione (etichettata o meno) del linguaggio f e scriviamo: # + I , # a, b, c (le parentesi angolari indicano chiaramente funzioni di accoppiamento) dove: 1. se I non ha etichetta, allora a # 0 ; se I ha etichetta L, allora a # # + L , ; 2. se V è la variabile menzionata in I, allora c # # +V , & 1 ; 3. se l’enunciato di I è: allora si ha rispettivamente: V $V o V $V % 1 o V $V &1 b #0 o b #1 o b #2 ; 4. se l’enunciato di I è IF V ' 0 GOTO L6 allora si ha: b # # + L6 , % 2 . Esempio: il numero dell’istruzione non etichettata X $ X % 1 è a , b , c , poiché l’istruzione è senza etichetta a # 0 , mentre c # # + X , & 1 # 2 & 1 # 1 , infine, poiché l’istruzione è V $ V % 1 , si ha b # 1 . Si ha quindi # + I , # 0, 1,1 # 0, 2 7 + 2 7 1 % 1 , & 1 1 # 0,5 # 2 7 + 2 7 5 % 1 , & 1 # 10 . 0 99 Altro esempio: ( A ) X $ X % 1 che è la stessa istruzione dell’esempio precedente ma questa volta è e- tichettata, quindi si ha a # # + A , # 1 , mentre b e c restano immutate, si dunque # + I , # 1, 1,1 # 1, 5 # 2 7 + 2 7 5 % 1 , & 1 # 21 . 1 Da notare che per ogni numero q dato vi è un’unica istruzione I tale che # + I , # q , quindi con qualche stratagemma, da q, possiamo risalire ad a, b e c , quindi all’etichetta (se c’è) dell’istruzione, al tipo di istruzione e alla variabile rispettivamente. Calcoliamo inizialmente a che è uguale a l + q , # l + a , b , c , # a , chiaramente se l + q , # 0 allora l’istruzione I non ha etichetta, altrimenti I avrà come etichetta la l + q , -ma lettera della nostra lista inizialmente definita. Per risalire al nome della variabile + ,, # r r + a, b, c # r + b, c c menzionata in I dobbiamo calcolare r + r + q , , # , # c , il cui valore (precisamente c % 1 ) chiaramente indica la posizione del nome della variabile nella nostra lista. + Per risalire infine all’enunciato di I calcoliamo: l + r + q , , # l r + a , b , c mente se risulta se se se l +r + q , , # 0 l +r + q , , # 1 l +r + q , , # 2 l +r + q , , & 2 # j @ 0 , , # l + b, c , # b e chiara- allora I sarà: V $ V ; allora I sarà: V $ V % 1 ; allora I sarà: V $ V & 1 ; allora I sarà: IF V ' 0 GOTO L ed L corrisponde alla j-ma lettera della lista delle etichette. Infine definiamo # +c , , con c programma costituito dalle istruzioni I 1 , I 2 ,! , I k (facendo riferimento alla numerazione di Gödel), il numero descritto dalla funzione: # +c , # SW # + I 1 , , # + I 2 , ,! , # + I k , 02 & 1 k # N pi + i , & 1 . # I i #1 In particolare il programma vuoto è # + A , # (0) & 1 # 1 & 1 # 0 (viene sottratto un 1 al numero di Gödel per assicurare una corrispondenza tra numero di programma e istruzioni e viceversa, infatti se non ci fosse questa sottrazione il numero di programma 0 non corrisponderebbe ad alcuna sequenza di numeri codificata mediante numerazione di Gödel). È importante notare che l’istruzione senza etichetta Y $ Y ha come numero 0, 0,0 # 0 e, per evitare ambiguità, nella numerazione di Gödel in coda alla sequenza, per convenzione si stabilisce che nessun programma debba avere come ultima istruzione Y $ Y (se così non fosse un qualsiasi # +c , potreb- be corrispondere a più programmi c aventi un numero differente di istruzioni Y $ Y in coda alla sequenza di istruzioni, verrebbe così meno l’univocità della decodifica –programmi differenti potrebbero avere lo stesso numero # +c , ). Chiaramente la decodifica del numero # + I , # 0 , con I non corrispondente all’ultima istruzione del programma, corrisponderà (regolarmente) all’enunciato Y $ Y . EDIT by Qd – Calcolabilità – XIX Lez. 100 Interruzione di un predicato (rif. D.S.W. pag. 68) Introduciamo un predicato particolare: HALT + x , y , , definiamolo: DEF.: per un dato y, posto c HALT + x , y , risulterà vero se ? (1) c un S-programma tale che # +c , # y . Allora il predicato + x , è definita, falso se ? + x , è indefinita. In altre parole possiamo (1) c scrivere che: SW HALT + x , y , J il programma di numero y si ferma sull'ingresso x 02 . TEOREMA 2.1: HALT + x , y , non è un predicato calcolabile. DIM.(a): Si dimostra per assurdo, supponendo cioè che HALT + x , y , sia un predicato calcolabile (chia- ramente mediante un S-programma). Quindi, se HALT + x , y , fosse calcolabile, possiamo utilizzarlo all’interno di un S-programma sottoforma di macro, in questo modo (X contiene un valore qualsiasi): c : ( A) IF HALT + X , X , GOTO A -B9 3 ?c(1) + x , # . B/0 se se e chiaramente risluterà: HALT + x , x , , ) HALT + x , x , Il programma, se HALT + x , x , è vero, ciclerà all’infinito, altrimenti si ferma e il valore di uscita di Y sarà nullo. , # y0 , allora, utilizzando la definizione data per il predicato HALT + x , y , , però in relazione al numero di programma di c , # +c , # y0 otteniamo: Ora poniamo # +c HALT + x , y0 , risulta vero se ?c(1) + x , # D (valore determinato) nel nostro caso l’unico valore determinato che assume il programma c HALT + x , x , è falso (cioè quando ) HALT + x , x , ); viceversa abbiamo che: è 0 e ciò avviene quando HALT + x , y0 , risulta falso se ?c(1) + x , # 9 e ciò avviene quando il predicato HALT + x , x , è vero (per come è stato concepito il programma, inizia a ciclare all’infinito), possiamo quindi affermare che (poiché ) HALT + x , x , 5 HALT + x , y 0 , P HALT + x , x , 5 5 ) HALT + x , y 0 , ): HALT + x , y0 , J ) HALT + x , x , . Siamo giunti a questa conclusione senza che essa dipendesse da particolari valori di x, cioè tale biiezione è valida per qualsiasi valore di x, quindi in particolare è valida anche per x # y0 da cui otterremmo: HALT + y0 , y0 , J ) HALT + y0 , y0 , che è chiaramente una contraddizione. Il teorema è dunque dimostrato. EDIT by Qd – Calcolabilità – XIX Lez. 101 DIM.(b): Il teorema può essere dimostrato anche seguendo un ragionamento differente, basandoci sull’analisi di una particolare matrice (rif. D.S.W. pag. 89) costituita da un insieme di funzioni ? +1, unarie relative a vari set di istruzioni, più precisamente indichiamo con c n , 4n * 0 il programma di numero n, possiamo dunque costruire la matrice infinita dei valori che possono assumere le funzioni unarie ? c+1n, parzialmente calcolabili (che quindi possono assumere valori determinati o indeterminati a seconda di come sono definite le funzioni ? c+1n, calcolate dai relativi programmi, abbiamo: E input E D ?c(1)0 + 0 , ?c(1)0 + 1, ?c(1)0 + 2 , ! ! num. ?c(1)1 + 0 , ?c(1)1 + 1, ?c(1)1 + 2 , ! ! prog. D ?c(1)2 + 0 , ?c(1)2 + 1, ?c(1)2 + 2 , ! ! ' ' ' ' ' ' + + Sulla prima riga sono rappresentati tutti i valori che può assumere la funzione ?c(1)0 + x , calcolata dal programma c 0 di numero 0 al variare di x, ovvero il programma vuoto, quindi la prima riga ha valori tutti uguali in quanto, al variare dell’input, l’output non cambia. Invece le altre righe rappresentano i valori che assumono le funzioni calcolate da programmi non vuoti e quindi possono essere diverse tra loro, chiaramente è anche possibile che alcuni valori possano essere uguali, il caso generale prevede questa possibilità non essendo specificati i programmi che stiamo rappresentando. In particolare però sulla diagonale principale della matrice sono rappresentate le funzioni calcolate da programmi il cui valore di input corrisponde al numero di programma. A questo punto, per dimostrare il teorema basta far vedere che i valori ?c(1) relativi al programma c visto per la precedente dimostrazione non compaiono nella matrice (la matrice rappresenta tutti i possibili valori che possono assumere tutti i programmi che calcolano funzioni parzialmente calcolabili, quindi se in questa matrice non compare una funzione vuol dire che questa funzione non è parzialmente calcolabile, cioè non può essere calcolata). Per assurdo avevamo assunto che HALT + x , y , fosse un predicato calcolabile e avevamo costruito il programma c essendo giunti alla biiezione: ?c(1) + x , #D J ) HALT + x , x , , tale fatto lo possiamo scrivere anche così: ?c(1) + x , #D J ?c(1)x + x , #9 4x (per come è stato definito il predicato HALT) Ciò significa (dando un’interpretazione all’ultima biiezione) che una riga (quella corrispondente al programma c ) è costituita da soli tutti zeri se e soltanto se la diagonale della matrice è costituita da tutti valori indeterminati, ma ciò è una contraddizione perché se si trovassero soltanto valori indeterminati sulla diagonale della matrice allora, in corrispondenza della riga del programma c avremmo almeno EDIT by Qd – Calcolabilità – XIX Lez. 102 un elemento della matrice che assume valore indeterminato andando in contraddizione col fatto che sulla riga del programma c dovremmo trovare soltanto zeri. Quindi il teorema è dimostrato. Tale metodo appena visto fa uso del concetto di diagonalizzazione (sulla diagonale della matrice i due argomenti del predicato HALT coincidono) ed è un metodo utile a dimostrare che certi insiemi non sono ricorsivi come vedremo. Nell’ambito dell’informatica si può operare con numeri o simboli indifferentemente, tale affermazione è provata ad esempio da quanto visto fino ad ora circa la codifica dei programmi. L’ultimo teorema visto ci fa capire una cosa importante e cioè che, non essendo calcolabile HALT + x , y , , non esiste un algoritmo che, dato un programma scritto in un linguaggio f con un da- to input, sia in grado di determinare se tale programma si fermerà + D , o meno + 9 , sull’input dato (in altri termini possiamo dire che la codifica dei programmi non permette di risolvere problemi di riconoscimento–arresto). Quest’ultimo concetto viene chiamato: problema dell’insolvibilità dell’arresto (unsolvability of the halting problem) da cui deriva un altro concetto: TESI di Church-Turing (rif. D.S.W. pag. 69): ogni funzione parzialmente calcolabile mediante un algoritmo è parzialmente calcolabile (da un S-programma). Ciò vuol dire che si presuppone (essendo soltanto una tesi –congettura– non dimostrata) che se non esiste un S-programma che calcola una certa funzione, allora tale funzione non sarà calcolabile da nessun metodo algoritmico. In particolare quindi, se HALT + x , y , non è calcolabile da un S-programma, non sarà calcolabile da nessun altro metodo algoritmico. La suddetta è una tesi in quanto è molto complicato formalizzare un’ipotesi che definisca correttamente il concetto di algoritmo, quindi, sebbene abbia valore da 70 anni e più, potrebbe, in futuro, rivelarsi non sempre vera, in tal caso la tesi si rivelerebbe falsa. Alla luce di questa tesi e del teorema poco fa dimostrato si può affermare che non è affatto possibile stabilire (predire) se un dato programma con un dato input si fermerà o meno dopo un certo numero di passi. In quanto affermarlo vuol dire che il programma prima o poi si fermerà, ma se non si ferma “subito” ciò non vuol dire che non si fermerà mai, né possiamo affermare con certezza che non si fermerà mai. La certezza la possiamo avere soltanto nell’eventualità che il programma termini. Ad esempio, consideriamo una congettura (teorema non dimostrato) della teoria dei numeri secondo cui ogni numero pari * 4 è la somma di due numeri primi. Tale asserzione prende il nome di congettura di Goldbach ed è chiaramente dimostrata per piccoli numeri come 4 # 2 % 2 , 6 # 3 % 3 , 8 # 3 % 5 , … , ma non è stato dimostrato che ogni numero pari * 4 è somma di due numeri primi. È chiaro che con facilità possiamo costruire un S-programma che verifica la veridicità (parziale) di questa congettura, verificando un numero pari alla volta, il programma non termina (se terminasse vorrebbe dire che è stato trovato un numero pari per cui non vale la congettura) , ma ciò non basta per asserire che la congettura è vera, ipoteticamente potrebbe darsi che prima o poi il programma termini, ma se ciò non accade non possiamo affermarlo con certezza matematica. In 250 anni dalla formulazione di questa congettura nessuno ha trovato un programma o comunque un metodo che la dimostri (cosa che al contrario è stata fatta, dopo secoli, circa l’ultimo teorema di Fermat). EDIT by Qd – Calcolabilità – XIX Lez. Ventesima Lezione 19/12/2006 Teorema dell’universalità – programma universale Insiemi ricorsi, non ricorsivi e primitivi ricorsivi Per quanto visto finora si è portati a pensare che non vi è una strada semplice per realizzare in modo generale problemi di calcolo sui numeri, tra poco vedremo che ciò non è vero (rif. D.S.W. pag. 70). DEF.: 4n @ 0 definiamo la seguente notazione: [ +n , + x 1 , x 2 ,!, x n , y , # ? c+n , + x 1 , x 2 ,! , x n , con y # # +c ,. La funzione [ (la cui notazione all’apice non deve essere confusa con quella delle funzioni ? , infatti [ +n , ha n % 1 argomenti e non n) rappresenta una sorta di interprete che prende in input i dati x 1 , x 2 ,! , x n e il numero di programma y # # +c ta da c , cioè ? (n ) c , e restituisce proprio il valore che restituirebbe la funzione (a n variabili) calcola- (che coincide con il valore della variabile Y allo snapshot terminale). TEOREMA 3.1 (dell’universalità): 4n @ 0 la funzione [ +n , + x 1 , x 2 ,! , x n , y , è parzialmente calcola- bile (cioè esiste un S-programma che calcola la funzione corrispondente a [ + , ). n DIM.: la dimostrazione viene fatta mostrando un S-programma h n , detto programma universale, che calcola appunto una funzione ? h( n %n1) + x 1 , x 2 ,!, x n , x n %1 , # [ +n , + x 1 , x 2 ,!, x n , y , . ( n %1) (n ) y Da notare che sebbene la funzione ? h n assuma gli stessi valori della funzione da calcolare ?c con i parametri x 1 , x 2 , ! , x n è chiaro che le due funzioni sono differenti, nel senso che una svolge il compito di calcolare, l’altra invece viene calcolata ma ha un significato legato al programma c , oltretutto le due funzioni hanno un numero di parametri differenti. L’S-programma h n , come anticipato, fungerà da interprete, infatti vengono letti i dati di input corri- spondenti all’S-programma c , dopodichè viene letto il numero y # # +c , del programma c , poi interpretate ed eseguite le varie istruzioni del programma c sui dati x 1 , x 2 ,! , x n in modo tale da ottenere: ? h( n %n1) + x 1 , x 2 ,!, x n , x n %1 , # [ +n , + x 1 , x 2 ,! , x n , x n %1 , # ? c( n ) + x 1 , x 2 ,!, x n , con x n %1 # y # # +c ,. Al fine di costruire il programma universale h n faremo abbondante uso di macro. Si ricorda che le variabili ed etichette omesse corrisponderanno al valore 0 nella codifica di Gödel (ad esempio se volessimo coY X 0 X 0 2 0 1 2 0 dificare lo stato: Y # 0 , X 1 # 2 , X 2 # 1 otterremmo 2 7 3 7 5 7 7 2 # 2 7 3 7 5 7 7 # 3 7 7 # 63 , il fattore 5 corrisponde al valore omesso della variabile Z che nella sequenza stabilita delle etichette delle variabili si trova tra X e X 2 ). Da notare che le variabili di input x 1 , x 2 ,! , x n hanno tutte posizione pari. 104 In primis il programma universale memorizza due valori: K ed S: K corrisponde al numero dell’istruzione che deve essere eseguito; S è il numero di Gödel (0, x 1 ,0, x 2 ,0! 0, x n ) della sequenza di variabili di input (ricordando quanto detto prima circa la posizione pari delle variabili X 1 , X 2 , ! nella codifica numerica del pro- gramma). Vediamo passo passo il funzionamento di h n che darà come risultato finale di output la variabile: Y # [ +n , + X 1 , X 2 ,! X n , X n %1 , con X n %1 chiaramente uguale a # +c ,# y da non confondere la y (minuscola) con Y (maiuscola) essendo due valori con significati differenti. Per rendere più semplice la comprensione del programma universale faremo liberamente uso di nomi ed etichette, senza cioè rispettare in modo rigoroso le regole dettate dal linguaggio f . Iniziamo col descrivere le prime tre righe del programma rappresentate da tre macro: 1 Z $ X n %1 % 1 2 S $ N + p2i , 3 K $1 n i #1 (memorizzazione numero programma); Xi (codifica stato); (memorizzazione primo passo – prima istruzione); 1. In Z viene memorizzato SW # + I 1 , , # + I 2 , ,! , # + I m , 02 cioè il numero di Gödel relativo alla sequenza di m istruzioni dell’S-programma c , con # +c , # X n %1 + # ( # + I 1 , , # + I 2 , , ! , # + I m ,) & 1, ; 2. In S, come già detto, vengono codificate le variabili di input, ricordando che hanno posto pari (ecco perché l’uso di p2i -numeri primi di posto pari), si ha dunque: S # (0, X 1 ,0, X 2 ,! ,0, X n ) 3. Come anticipato anche per K, tale variabile rappresenta il contatore d’istruzione e, ovviamente, quando il programma parte, viene inizializzato a 1. Proseguiamo con la descrizione delle istruzioni seguenti: 4 (C ) IF K # Lt + Z , % 1 C K # 0 GOTO F + or , (controllo numero istruzione); 4. Viene effettuato un controllo sul numero di istruzione corrente, infatti Lt + Z , corrisponde alla lunghezza della sequenza di istruzioni del programma c , come vedremo K verrà incrementato EDIT by Qd – Calcolabilità – XX Lez. 105 di una unità quando verrà eseguita un’istruzione di c . Quando saranno state eseguite tutte le m istruzioni di c , K sarà uguale a m % 1 . Vedremo dopo il significato del predicato K # 0 . Una volta eseguite tutte le istruzioni di c (o se K # 0 ), il programma h n salterà all’ultima istruzione ( F ) + Final , che restituirà l’output Y. Se non sono state ancora eseguite tutte le istruzioni di c , h n passa all’istruzione: U $ r + + Z ,k , 5 (decodifica istruzione corrente); 5. Inizialmente K # 1 , quindi + Z , K # # + I 1 , cioè il numero codificato della prima istruzione di c . In generale + Z ,i corrisponde all’i-ma istruzione di c . Ricordiamoci che il numero di un’istruzione I è # + I , # a , b , c , quindi r + # + I , , # b , c . In c e in b sono contenute rispettivamente le informazioni relative all’eventuale variabile menzionata nell’istruzione e al tipo di istruzione (che può essere una di queste: istruzione pigra, incremento, decremento, salto condizionale). Essendo dunque U # b , c K , U contiene informazioni sulla variabile e sulla Kma istruzione di c ; P $ pr +U ,%1 6 (memorizzazione posizione variabile); 6. Con questa macro stiamo memorizzando in P le informazioni relative all’individuazione della variabile su cui eseguire la K-ma istruzione, infatti r +U , # c , quindi r +U , % 1 # c % 1 corrisponde alla posizione della variabile della K-ma istruzione. Di conseguenza pc %1 rappresenta il + c % 1, –mo numero primo corrispondente alla posizione della variabile codificata in S. Ricordiamoci che c % 1 # # +V , non è il valore della variabile V, bensì la posizione nella lista +Y X Z 1 X 2 !, ; inoltre rammentiamo che la seconda istruzione dell’S-programma h n codifica i valori delle variabili + X , X 2 ,! , X n , assieme alla loro posizione, ogni base + p2 i , della potenza di cia- scun fattore della produttoria corrisponde alla posizione (pari) nella lista dei nomi delle variabili, mentre n all’esponente è menzionato il relativo valore: S # N + pn %1 , i #0 Xi X X X # p2 1 . p4 2 7 ! 7 p2 nn . Di conseguenza, co- noscendo il + c % 1 , –mo numero primo e il suo esponente, risaliamo rispettivamente alla posizione e al valore della variabile corrispondente. l +U , # 0 GOTO N 7 IF 8 IF l +U , # 1 GOTO A (analisi tipo istruzione –pigra); (analisi tipo istruzione –incremento); 7. Ricordando che U # b , c allora l +U , # b che corrisponde al tipo di istruzione associato. Se l +U , # 0 dovrà essere eseguita l’istruzione pigra V $ V , quindi, in pratica, il programma universale non deve fare nulla e passare semplicemente all’istruzione successiva, ciò viene gestito dall’istruzione ( N ) + Null , come vedremo in seguito; EDIT by Qd – Calcolabilità – XX Lez. 106 8. Analogamente, per l’istruzione 8 si controlla il valore di b, il quale se è pari a 1, vorrà dire che deve essere fatto un incremento V $ V % 1 e poi passare all’istruzione successiva, ciò viene gestito dall’istruzione ( A ) + Add , come vedremo in seguito; Se l +U , ' 0,1 ciò vuol dire che l’istruzione da eseguire può essere o un decremento o un salto condizionato (costrutto di selezione), per effettuare il decremento, però è necessario che ci si assicuri che la variabile da decrementare sia non nulla: 9 IF ) + P | S , GOTO N (controllo variabile nulla); 9. Se la variabile da decrementare fosse nulla avremmo pc0%1 # 1 , quindi P Z| S e si passerebbe all’istruzione successiva di c (anche in questo caso l’istruzione ( N ) gestisce il passaggio all’istruzione successiva da eseguire). Ricordiamo che P rappresenta la posizione, nella lista delle variabili, della variabile corrente sottoforma di numero primo, mentre in S è memorizzata la successione di variabili codificate (in qualche modo rappresenta la codifica dello stato corrente del programma c ), quindi se la variabile corrispondente alla poY sizione rappresentata da P fosse nulla avremmo che se P # pk ed S # p1 lora pk Z| Y p1 bili di input 7 Xi X p2 7 Z p3 7 X p4 2 0 7 ! 7 pk 7 ! . + # 1, 7 p2X 7 p3Z 7 p4X 2 7 ! 7 pk0 7 ! , al+ # 1, È chiaro che lo stato iniziale prevede la codifica delle sole varia- , ma con l’esecuzione di varie istruzioni lo stato codificato potrebbe arricchirsi di nuovi fat- tori (corrispondenti alle variabili temporanee Z i e chiaramente Y ). Anche nel caso in cui l’istruzione da eseguire fosse stata del tipo IF V ' 0 GOTO L6 (anziché V $ V & 1 ) essendo nulla la variabile in questione si passerebbe comunque all’istruzione successiva anziché all’istruzione L6 essendo falso il predicato V ' 0 . Nel caso in cui la variabile corrente fosse non nulla allora bisognerebbe verificare se effettuare il suo decremento o il salto condizionato: 10 IF l +U , # 2 GOTO M (controllo istruzione di decremento); 10. se l +U , # 2 allora b # 2 , bisogna dunque effettuare il decremento della variabile corrente, tale operazione viene eseguita dall’istruzione ( M ) + Minus , che vedremo dopo; 11 K $ min SWl + + Z ,i , % 2 # l +U , 02 i <Lt + Z , 12 GOTO C EDIT by Qd – Calcolabilità – XX Lez. (salto condizionato); (prossima istruzione) 107 11. Nel caso in cui l +U , ' 0,1,2 e la variabile su cui operare è non nulla, bisogna effettuare il salto condizionato passando all’istruzione etichettata con L6 il cui valore, riferito alla posizione nella lista delle etichette, è contenuto in b # # + L6 , % 2 . Poiché un programma potrebbe avere più istruzioni con la stessa etichetta per preservare il determiniamo ed evitare ambiguità, si considera l’etichetta di ordine minore (cioè quella che viene prima, leggendo le istruzioni dall’alto verso il basso, come nell’esempio a destra). ! si E (D ) ( A) ! ! ! Ecco perché si fa uso della funzione min. Poiché K rappresenta (B ) ! il valore della prossima istruzione da eseguire, di norma, al ter( A) ! no E mine di ogni istruzione di c , K viene incrementato di una u(C ) ! GOTO A nità, ma in questo caso particolare la prossima istruzione da eseguire è L6 , quindi K deve essere aggiornato in modo da contenere il valore relativo all’etichetta L6 di ordine minore (nell’eventualità ci siano più etichette L6 ). Viene quindi fatta una ricerca per trovare il numero di istruzione che compare, nell’S-programma c , per primo, corrispondente a L6 . Il valore di L6 è contenuto in l +U , , più precisamente l +U , # b # # + L6 , % 2 . Quindi vengono fatti dei confronti tra l +U , ed l + + Z ,i , % 2 fintantoché i confronti danno esito negativo (ricor- diamo che Z contiene la codifica delle istruzioni del programma c e quindi tutte le informazioni relative ad esse e quindi anche alle eventuali etichette, + Z ,i corrisponde dunque al numero codificato della i-ma istruzione ed l + + Z ,i , % 2 corrisponde all’eventuale (posizione) etichetta dell’i-ma istruzione di c ). K assumerà il più piccolo valore di i per cui è verificata l’uguaglianza. Chiaramente, se il salto condizionato fa riferimento ad una etichetta inesistente, K assumerà valore 0. Se L 6 non esiste allora K # 0 in quanto la minimalizzazione è stata definita in modo tale da essere nulla se non viene trovato alcun valore 0 < i < Lt + Z , che soddisfa il predicato, la ricerca in verità dovrebbe partire da i # 1 corrispondente all’analisi dell’etichetta della prima istruzione, ma, per come è stata definita la minimalizzazione, si parte da 0 e ciò non compromette la ricerca. 12. In ogni caso dopo la ricerca dell’etichetta (che sia stata trovata o meno) si salta di nuovo all’istruzione (C ) che contiene il controllo K # 0 a cui si era accennato prima. Tale controllo serve proprio a verificare che l’etichetta del salto condizionato esista o meno, in caso negativo il programma universale termina e viene restituito il valore di uscita Y (istruzione ( F ) ); se invece K ' 0 allora si passerà all’esecuzione della K-ma istruzione; 13 ( M ) S $ WVS / P 21 (decremento) 13. Questa è la macro relativa all’operazione di decremento richiamata dall’istruzione 10. Se viene eseguita l’istruzione 13 vuol dire che il decremento può essere effettuato e ciò vuol dire che P | S . Essendo i valori delle variabili memorizzati in S sottoforma di esponenti dei numeri primi, la sottrazione di una unità da una variabile V, corrisponderà alla divisione di S per il numero primo corrispondente alla posizione assunta dalla variabile, quindi se, ad esempio, S # EDIT by Qd – Calcolabilità – XX Lez. 108 # p2X 1 7 p4X 2 7! 7 pVj 7! 7 p2Xnn , # +V , # j e V # L , per ottenere V & 1 , si ha: S / P # S / p j # # p2X 1 7 p4X 2 7! 7 pLj &1 7! 7 p2Xnn . Anche in questo caso vale l’appunto fatto prima riguardante i pedici pari dei fattori, cioè non è detto che S sia costituito esclusivamente da fattori i cui pedici sono numeri pari per via dell’eventuale utilizzo di variabili Z i o della variabile di output Y . Quindi S verrà aggiornato per contenere la variabile decrementata e si procede con: 14 GOTO N (salto incondizionato di fine istruzione) 14. Questa istruzione sarà descritta a breve; 15 ( A) S $ S 7 P (incremento) 15. Se l’istruzione da eseguire è l’incremento della variabile corrente, se per il decremento si è fatto uso della divisione per P, in modo del tutto equivalente, secondo lo stesso principio delle proprietà delle potenze, viene effettuata la moltiplicazione per P di S e aggiornato il valore di S. Quindi ad esempio, se S # p2X 1 7 p4X 2 7! 7 pVj 7! 7 p2Xnn , # +V , # j e V # L , per ottenere V % 1 , si ha: S 7 P # # S 7 p j # p2X 1 7 p4X 2 7! 7 pLj %1 7! 7 p2Xnn , in questo caso V può anche essere nullo avremmo quindi S # p2X 1 7 p4X 2 7! 7 p2Xnn ed S 7 p j # p2X 1 7 p4X 2 7! 7 p j 7! 7 p2Xnn ; 16 (N ) K $ K %1 (aggiornamento variabile prossima istruzione) 16. Terminata l’operazione di decremento o di incremento, prima di passare alla prossima istruzione di c , si aggiorna K incrementandolo di una unità in modo che h n sia in grado di eseguire le istruzioni successive di c , difatti la variabile K viene utilizzata per fare i controlli (istruzione (C ) ) sulla K-ma istruzione (se esiste); 17 GOTO C (salto alla gestione della prossima istruzione) 17. Conclusa l’istruzione e aggiornato K si ritorna all’istruzione (C ) in modo da eseguire nuovamente tutte le operazioni utili all’esecuzione della prossima istruzione I K di c ; 18 ( F ) Y $ + S ,1 (memorizzazione valore di output) 18. Terminate tutte le operazioni (o nel caso in cui il programma termini prematuramente per un errore), viene memorizzato in Y il valore di output calcolato dal programma che chiaramente si trova nella prima posizione (per convenzione) della sequenza di variabili memorizzate in S , quindi Y $ + S ,1 . Nel caso in cui non venga fatta alcuna assegnazione a Y, tale variabile resterà nulla (sebbene magari siano state effettuate operazioni di incremento, decremento, ecc… su altre variabili). EDIT by Qd – Calcolabilità – XX Lez. 109 Abbiamo concluso la descrizione del programma universale che ora vediamo nel complesso, unendo tutte le macro: hn : Z $ X n %1 % 1 n S $ N + p2n , Xi i #1 (C ) K $1 IF K # Lt + Z , % 1 C K # 0 GOTO F U $ r + + Z ,K , P $ pr U %1 + , IF l +U , # 0 GOTO N IF l +U , # 1 GOTO A IF ) + P | S , GOTO N IF l +U , # 2 GOTO M K $ min SWl + + Z ,i , % 2 # l +U , 02 i <Lt+ Z , GOTO (M ) ( A) (N ) (F ) C S $ VWS / P 12 GOTO N S $ S 7P K $ K %1 GOTO C Y $ + S ,1 È chiaro che h n è la chiave per dimostrare il teorema, infatti grazie ad esso possiamo affermare che se scriviamo [ +n , + x 1 , x 2 ,!, x n ,0 , , [ +n , + x 1 , x 2 ,!, x n ,1, , [ +n , + x 1 , x 2 ,!, x n ,2 , ,! 4n @ 0 (l’ultimo parametro delle funzioni corrisponde al numero di programma), indichiamo la sequenza di tutte le funzioni parzialmente calcolabili, quindi abbiamo dimostrato il teorema. Possiamo anche scrivere: [ +yn , + x 1 , x 2 ,!, x n , # [ +n , + x 1 , x 2 ,!, x n , y , e se n # 1 possiamo anche omettere l’apice: [ y + x , # [ + x , y , # [ + 1, + x , y , . Il programma universale può essere modificato per eseguire un’altra operazione utile e cioè il conteggio dei passi eseguiti dal programma c . Da quest’ultimo risultato si ha: EDIT by Qd – Calcolabilità – XX Lez. 110 +n , DEF. (rif. D.S.W. pag. 74): con la scrittura STP + x 1 , x 2 ,! , xn , y , t , si definisce un predicato tale che: STP+n , + x 1 , x 2 ,! , xn , y , t , J [ Il programma di numero y si ferma in un numero di passi m < t su ingresso x 1 , x 2 ,!, x n ] e STP+n , + x 1 , x 2 ,! , xn , y , t , J [ Vi è un calcolo del programma y di lunghezza l < t % 1 , se parte dagli input x 1 , x 2 ,!, x n ] Quindi il predicato appena definito è vero soltanto se il programma c con # +c , # y e con ingresso x 1 , x 2 ,!, x n si ferma dopo un numero finito di passi m < t e allo stesso tempo se esiste un calcolo (si ricordi la definizione di calcolo, rif. D.S.W. pag. 27 e 29) di lunghezza l < t % 1 (in quanto si parte dallo stato iniziale 1, quando non è stata eseguita ancora alcuna istruzione di c , e si termina con lo stato finale t % 1 , dopo che tutte le istruzioni sono state eseguite. I predicati appena visti (le due biiezioni), essendo conseguenza dell’aggiunta dell’istruzione contatore W $ W % 1 a h n , sono calcolabili. Ciò non vuol dire che il problema dell’arresto sia stato risolto in quanto qui abbiamo un limite dato dal valore t, che ci permette di affermare con certezza che un programma termina o meno entro un numero di passi non superiore a t , ma non che un programma termina a fronte di un numero di passi non stabilito. Inoltre il predicato non calcolabile HALT ha valore soltanto per programmi che ricevono in input un solo valore. Segue un importante risultato: TEOREMA 3.2 (del conta passi): 4n @ 0 il predicato STP+n , + x 1 , x 2 ,! , xn , y , t , è primitivo ricorsi- vo. [ la dimostrazione segue dopo pag. 111 ] Insiemi ricorsivi, non ricorsivi e primitivi ricorsivi (rif. D.S.W. pag. 78) Si può parlare di problemi risolvibili o non risolvibili in termini insiemistici, strettamente connessi ai predicati, a tal proposito definiamo una particolare funzione: DEF. (rif. D.S.W. pag. 6): Con il termine funzione caratteristica intendiamo un predicato P sull’insieme S (dominio), se R : S e risulta: -1 P +x, # . /0 se x > R , e abbiamo: se x \ R R # !a > S | P + a ," . Cioè l’insieme R può essere definito mediante l’uso del predicato P che è la funzione caratteristica dell’insieme R (cioè stabilisce se un elemento appartiene o non appartiene a R a seconda che risulti rispettivamente vero o falso il predicato P). È indifferente adoperare una notazione insiemistica o mediante la funzione caratteristica. -1 Un esempio è il seguente: f + x , # . /0 EDIT by Qd – Calcolabilità – XX Lez. se x è primo, altrimenti chiaramente f + x , rappresenta la funzione 111 caratteristica dell’insieme dei numeri primi: ! p > & | f + p ," e risulta anche f + x , # Primo + x , . Altro esempio è HALT + x , y , il quale può essere visto come la funzione caratteristica dell’insieme: !+ x , y , > & 2 | HALT + x , y ," che rappresenta l’insieme di tutte le coppie ordinate + x , y , tali che l’S-programma di numero y si ferma sull’ingresso x. Più in generale abbiamo: DEF.: Dire che un insieme B : N m è: I I I non calcolabile (non ricorsivo) oppure calcolabile (ricorsivo) oppure primitivo ricorsivo (si sta stabilendo cioè che B appartiene ad una certa classe di funzioni calcolabili o non calcolabili o primitive ricorsive) vuol dire che la funzione caratteristica P + x 1 , x 2 ,!, x m , di B è rispettivamente: I I I non calcolabile calcolabile primitiva ricorsiva Quindi il problema di sapere se una funzione è calcolabile o meno (e se è primitiva ricorsiva o meno) si riconduce al problema di sapere se la relativa funzione caratteristica è calcolabile o meno (e se è primitiva ricorsiva o meno). Analogamente possiamo dire che se esiste l’S-programma che computa la funzione caratteristica allora esiste l’S-programma che computa la funzione data (generatrice). EDIT by Qd – Calcolabilità – XX Lez. Dimostrazione del Teorema Conta-passi Martin Davis, Ron Sigal, Elaine J. Weyuker Teorema 1 ∀n > 0, il predicato ST P (n) (x1 , ..., xn , y, t) è primitivo ricorsivo. Dim. L’idea è dare una versione numerica delle nozioni di successore e istantanea successore e di mostrare che le funzioni implicate sono primitive ricorsive. Iniziamo col definire le funzioni che servono ad estrarre le componenti della i-esima istruzione del programma di numero y: • LABEL(i, y) = l((y + 1)i ) • V AR(i, y) = r(r((y + 1)i )) + 1 • IN ST R(i, y) = l(r((y + 1)i )) • LABEL� (i, y) = l(r((y + 1)i ))−̇2 Definiamo inoltre alcuni predicati che indicano, per il programma di numero y e l’istantanea rappresentata da x, quali sono le possibili istruzioni successive da eseguire. • SKIP (x, y) ⇔ [IN ST R(l(x), y) = 0 ∧ l(x) ≤ Lt(y + 1)]∨[IN ST R(l(x), y)≥ 2 ∧ ∼ (pV AR(l(x),y) | r(x))] • IN CR(x, y) ⇔ IN ST R(l(x), y) = 1 • DECR(x, y) ⇔ IN ST R(l(x), y) = 2 ∧ pV AR(l(x),y) | r(x) • BRAN CH(x, y) ⇔ IN ST R(l(x), y) > 2 ∧ pV AR(l(x),y) | r(x) ∧ (∃i)≤Lt(y+1) LABEL(i, y) = LABEL� (l(x), y) Adesso possiamo costruire la funzione SU CC(x, y) la quale, per il programma di numero y fornisce la rappresentazione del successore dell’istantanea x. SU CC(x, y) = �l(x) + 1, r(x)� �l(x) + 1, r(x) · pV AR(l(x),y) � �l(x) + 1, r(x)/p � V AR(l(x),y) �min [LABEL(i, y) = LABEL� (l(x), y)], r(x)� i≤Lt(y+1) �Lt(y + 1) + 1, r(x)� Abbiamo bisogno anche di IN IT (n) (x1 , ..., xn ) = �1, 1 n � i=1 (p2i )xi �, se SKIP (x, y), se IN CR(x, y), se DECR(x, y), se BRAN CH(x, y), altrimenti. che dà la rappresentazione dell’istantanea iniziale con input x1 , ..., xn , e di T ERM (x, y) ⇔ Z(x) > Lt(y + 1), che determina se x è un’istantanea terminale per il programma di numero y. Ora, mediante l’uso delle funzioni appena definite, definiamo ricorsivamente una funzione che a partire dalle variabili di input x1 , ..., xn , dal numero di programma y e da un indice i, definisce l’istantanea codificata all’ i-esimo passo del programma: passo base: SN AP (n) (x1 , ..., xn , y, 0) = IN IT (n) (x1 , ..., xn ); passo ricorsivo: SN AP (n) (x1 , ..., xn , y, i + 1) = SU CC(SN AP (n) (x1 , ..., xn , y, i), y). Inoltre, ST P (n) (x1 , ..., xn , y, t) ⇔ T ERM (SN AP (n) (x1 , ..., xn , y, t), y) e quindi STP(n) (x1 , ..., xn , y, t) è primitiva ricorsiva. ✷ 2 Ventesima Prima Lezione 21/12/2006 Teorema della forma normale Minimalizzazione propria Insiemi ricorsivamente enumerabili e relativi teoremi Forniamo ora dei concetti (indispensabili a dimostrare il teorema della forma normale che vedremo a breve) secondo cui è possibile effettuare la codifica dello stato ! di un programma (rif. D.S.W. pag. 7475), indichiamo quindi con z lo stato codificato ad un certo istante del programma, quindi s " #Y , X , Z , X 2 ,!$ " p1Y % p2X % p3Z % p4X 2 %! . Quindi possiamo affermare che anche un’istantanea & i,! ' può essere codificata (mediante le funzioni di accoppiamento), se # &! ' " s allora # & & i , ! ' ' " i , s " x e, poiché quest’ultimo è un numero che codifica un’istantanea, da esso possiamo ricavare il suo successore (solo un accenno) che definiamo come segue: DEF.: SUCC & x , y ' " i (, s ( con i (, s ( numero dell’istantanea successore di & i ,! ' e y numero del programma, x è la codifica dello stato ! . Si può dimostrare che tale funzione è primitiva ricorsiva. DEF.: INIT&n ' & x 1 , x 2 ,!, x n ' " 1, n x &p ' ) i "1 2i i questa rappresenta l’istantanea iniziale del programma. Per la quale le variabili Y, Z, Z 2 ,! " 0 , quindi si considerano solo i numeri primi di posto pari corrispondenti alle variabili di input X i . Anche in questo caso la funzione è primitiva ricorsiva. Ora, mediante l’uso delle funzioni appena definite, possiamo definire una funzione che a partire dalle variabili di input x 1 , x 2 ,!, x n , dal numero di programma y e da un indice i, può risalire allo snapshot codificato all’i-mo passo del programma: DEF.: Ricorsivamente diamo la seguente definizione: * passo base: SNAP&n ' & x 1 , x 2 ,!, x n , y ,0 ' " INIT &n ' & x 1 , x 2 ,!, x n ' , * passo ricorsivo: SNAP&n ' & x 1 , x 2 ,!, x n , y , i + 1' " SUCC SNAP&n ' & x 1 , x 2 ,!, x n , y , i ' , y . & ' Essa rappresenta la funzione che restituisce lo snapshot codificato dopo l’esecuzione di un certo numero di istruzioni (ultimo argomento i della funzione). Eruditi delle nozioni appena argomentate passiamo al seguente: TEOREMA 3.3 (della forma normale – rif. D.S.W. pag. 75-76): Sia f & x 1 , x 2 ,!, x n ' una funzione par- zialmente calcolabile. Allora vi è un predicato primitivo ricorsivo R & x 1 , x 2 ,!, x n , y ' tale che: & ' f & x 1 , x 2 ,!, x n ' " l min R & x 1 , x 2 ,!, x n , z ' . z 113 DIM.: Possiamo affermare che esiste un numero y0 di un programma che calcola f & x 1 , x 2 ,!, x n ' , infatti per ipotesi f & x 1 , x 2 ,!, x n ' è parzialmente calcolabile. Dobbiamo dimostrare che vale l’uguaglianza & ' f & x 1 , x 2 ,!, x n ' " l min R & x 1 , x 2 ,!, x n , z ' e che R & x 1 , x 2 ,!, x n , y ' è un predicato primitivo ricorsivo. z Il predicato seguente è utile a dimostrare il teorema: & ' , STP&n ' & x 1 , x 2 ,!, x n , y0 , r & z ' ' & R & x 1 , x 2 ,!, x n , z ' 0 . . r SNAP&n ' x , x ,!, x , y , r z & '' & 1 2 n 0 .1 && & / " l & z ' // 1 2 '' ' che è chiaramente un predicato primitivo ricorsivo. Cerchiamo di interpretarlo. Il predicato R & x 1 , x 2 ,!, x n , z ' è vero se e soltanto se sono entrambi veri i due predicati: a. STP&n ' & x 1 , x 2 ,!, x n , y0 , r & z ' ' b. &r & SNAP &n ' e & x1 , x 2 ,!, xn , y0 , r & z ' ' ' '1 " l & z ' a. è vero quando il programma di numero y0 si ferma dopo al più r & z ' passi (il valore di z deve essere interpretato come il valore 3 , 4 , quindi l & z ' " 3 corrispondente ad un numero che identifica il valore di uscita del programma, mentre r & z ' " 4 rappresenta un valore corrispondente al numero di passi effettuati dal programma); b. spezzettiamo il predicato e interpretiamo le varie parti: SNAP&n ' & x 1 , x 2 ,!, x n , y0 , r & z ' ' rappresenta la codifica dello snapshot del programma di nume- ro y0 al passo r & z ' e per come è stata definita la funzione SNAP, sarà uguale ad un numero del tipo i , k , con i indice dell’istruzione e k pari al numero codificato dello stato prima dell’esecuzione della i-ma istruzione ( k " #Y , X , Z , X 2 ,!$ -non è propriamente corretto utilizzare i nomi delle variabili per indicare la codifica dei valori che essi contengono, ma per comodità e per una maggiore comprensione utilizziamo questa notazione). Dunque risulta: & ' r SNAP&n ' & x 1 , x 2 ,! , x n , y0 , r & z ' ' " k e anche: &r & SNAP &n ' & x1 , x 2 ,!, xn , y0 , r & z ' ' ' '1 " & k '1 e cioè il valore della variabile Y. Di conseguenza il predicato b è vero quando Y " l & z ' , e quindi quando risulta: l & z ' " " f & x 1 , x 2 ,!, x n ' . Dunque il predicato R & x 1 , x 2 ,!, x n , z ' è vero se e soltanto se z assume un valore tale che il programma di numero y0 si ferma dopo al più r & z ' passi e se il valore della variabile Y (relativo allo snapshot finale) è uguale a l & z ' . EDIT by Qd – Calcolabilità – XXI Lez. 114 Ritornando alla tesi del teorema la scrittura min & R & x 1 , x 2 ,! , x n , z ' ' rappresenta il valore minimo z che deve assumere z affinché il predicato R sia vero e ciò avviene nel momento in cui z assume un valore 3 , 4 tale che il programma di numero y0 si ferma dopo al più 4 passi e restituisce il valore & ' 3 " Y " f & x 1 , x 2 ,!, x n ' . Quindi è chiaro che f & x 1 , x 2 ,! , x n ' " l min & R & x 1 , x 2 ,!, x n , z ' ' . z Essendo per ipotesi f parzialmente calcolabile è possibile che per certi valori di input la funzione restituisca un valore indeterminato 5 e che quindi non si fermi, dobbiamo assicurarci che l’uguaglianza & ' f & x 1 , x 2 ,! , x n ' " l min & R & x 1 , x 2 ,!, x n , z ' ' valga anche in questo caso particolare, avendo usato una z minimalizzazione non limitata, essendo il predicato R mai vero (non si ferma), otterremo un valore in- & ' determinato anche per l min & R & x 1 , x 2 ,!, x n , z ' ' . z Abbiamo dunque dimostrato che l’uguaglianza vale e che i predicati usati sono primitivi ricorsivi, il teorema è dunque dimostrato. Grazie al teorema appena dimostrato abbiamo dato una caratterizzazione per le funzioni parzialmente calcolabili che non è più legata agli S-programmi (non è un caso che questo teorema abbia delle analogie molto forti con il teorema di Kleene visto per i linguaggi regolari). Il teorema della forma normale ci è utile per dimostrare il seguente: TEOREMA 3.4: Una funzione è parzialmente calcolabile se e solo se 0 si può ottenere a partire dalle funzioni iniziali applicando un numero finito di volte la composizione, la ricorsione (primitiva) e la minimalizzazione (quest’ultima viene applicata solo una volta). DIM. 6 : Dobbiamo dimostrare che se una funzione si può ottenere dalla funzioni iniziali applicando un numero finito di volte la composizione, la ricorsione e la minimalizzazione allora tale funzione è parzialmente calcolabile. I teoremi 1.1, 2.1, 2.2, 3.1 e 7.2 (risp. rif. D.S.W. pagg. 39,40,41,42,58) dimostrano che se una funzione è ottenuta mediante l’applicazione di un numero finito di volte, a partire dalla funzioni iniziali (teor. 3.1), la composizione (teor. 1.1), la ricorsione (teor. 2.1 e 2.2), la minimalizzazione (teor. 7.2) allora tale funzione è parzialmente calcolabile. Quindi la prima parte del teorema è dimostrata. DIM. 7 : Ora dobbiamo dimostrare che se una funzione è parzialmente calcolabile allora essa si può ottenere a partire dalle funzioni iniziali applicando un numero finito di volte la composizione, la ricorsione e la minimalizzazione e lo facciamo adoperando il teorema della forma normale. Difatti il teorema della forma normale ci permette di esprimere qualsiasi funzione parzialmente calcolabile f come segue: f & x 1 , x 2 ,! , x n ' " l 8: min R & x 1 , x 2 ,! , x n , y ' 9; < y = con R predicato primitivo ricorsivo (per la tesi del teorema della forma normale) Tale funzione è chiaramente ottenuta da un numero finito di operazioni di composizione, ricorsione e minimalizzazione. In particolare si è fatto uso di una sola minimalizzazione e della composizione con la funzione primitiva ricorsiva l (essendo primitiva ricorsiva è ottenibile da funzioni iniziali). Il teorema è dunque dimostrato. EDIT by Qd – Calcolabilità – XXI Lez. 115 DEF. (rif. D.S.W. pag. 77): Quando min y R & x 1 , x 2 ,!, x n , y ' è una funzione totale (cioè quando >x 1 , x 2 ,! , x n vi è almeno un valore di y per cui il predicato R & x 1 , x 2 ,! , x n , y ' è vero) si dice che abbiamo applicato l’operazione di minimalizzazione propria (o regolare) su R. Quindi se l 8: min R & x 1 , x 2 ,! , x n , y ' 9; è totale 7 lo è anche min R & x 1 , x 2 ,!, x n , y ' da cui abbiamo y < y = il seguente: TEOREMA 3.5: Una funzione è calcolabile 0 può essere ottenuta dalle funzioni iniziali mediante un numero finito di operazioni di composizione, ricorsione e minimalizzazione propria. DIM.: La dimostrazione deriva direttamente dal teorema precedente e dalla definizione di minimalizzazione propria. Insiemi Ricorsivamente Enumerabili (rif. D.S.W. pag. 78) Ricordiamo che un insieme si dice: * primitivo ricorsivo se la sua funzione caratteristica è primitiva ricorsiva * ricorsivo (calcolabile) se la sua funzione caratteristica è calcolabile. DEF.: Un insieme B ? " si dice ricorsivamente enumerabile (r.e.) se esiste una funzione parzialmen- te calcolabile unaria g & x ' tale che: B " @ x B " | g & x ' CA . Quindi B è l’insieme di tutti quei valori per cui la funzione unaria (se esiste) g & x ' è definita. In altri termini B è r.e. se coincide con il dominio di definizione di una funzione parzialmente calcolabile g & x ' . Se c è un programma che calcola la funzione g & x ' allora B è l’insieme di tutti gli input su c per cui alla fine c si ferma. Da quest’ultima osservazione andiamo ad analizzare i cosiddetti problemi di semidecisione o di semiriconoscimento secondo cui si può realizzare un programma per stabilire se un dato valore x fa arrestare il programma, da cui x B B (con B r.e.), ma se volessi stabilire se x D B (con B r.e.) ciò non è possibile in quanto è impossibile prevedere se un programma terminerà o meno. Ricorrendo alla tesi di Church ci potrebbero essere algoritmi generali per stabilire se x appartiene o meno ad un insieme r.e. B purché tali algoritmi non siano (necessariamente) scritti nel linguaggio f degli S-programmi (perché per dimostrare la tesi bisogna generalizzare il problema e non specializzarlo al solo linguaggio f ). Tali algoritmi vengono chiamati: procedure di semidecisione. TEOREMA 4.3: Se un insieme B è ricorsivo allora 7 B è anche r.e. Il contrario come vedremo (Teorema 4.7) non vale. DIM.: Per ipotesi abbiamo che (ad esempio) f B & x ' è la funzione caratteristica di B ed è ricorsiva (cioè calcolabile), ciò vuol dire che il predicato x B B è calcolabile. EDIT by Qd – Calcolabilità – XXI Lez. 116 Quindi possiamo costruire un programma c che calcola la funzione (ad esempio) h & x ' : # A$ IF f B & X ' " 0 GOTO A o anche: # A$ IF # & X B B ' GOTO A . Ciò ci assicura che se l’input è un elemento dell’insieme B, per come è stato costruito, il programma termina ( h & x ' C ) altrimenti entra in un loop infinito ( h & x ' "5 ), abbiamo dunque: B " @ x B " | h & x ' CA quindi il teorema è dimostrato. Il passaggio da notazione insiemistica a proposizionale ci permette di dimostrare i seguenti teoremi: TEOREMA 4.1 (rif. D.S.W. pag. 79): Se B e C sono insiemi appartenenti ad una classe PRC V (cioè se possono essere espressi mediante funzioni caratteristiche appartenenti a V ) allora vi appartengono anche: B EC , B FC e B (complemento di B). DIM.: La dimostrazione è un’immediata conseguenza del teorema 5.1 (rif. D.S.W. pag. 49 - P G Q , P & Q e # P ) la cui tesi ci permette di esprimere mediante predicati i tre insiemi B E C , B F C e B . Nell’ambito delle funzioni # x 1 , x 2 ,!, x m $ e & x 'i della numerazione di Gödel possiamo porre la nostra attenzione a sottoinsiemi di "m , abbiamo: TEOREMA 4.2: Posto V classe PRC e B ? "m con m H 1 . Allora B BV se e solo se 0 B ( BV con B ( " @# x 1 , x 2 ,!, x m $ B " | & x 1 , x 2 ,!, x m ' B BA (chiaramente B ( ? " ). DIM. 7 : Dobbiamo dimostrare che se B BV allora B ( BV , dunque se PB & x 1 , x 2 ,!, x m ' è la funzione caratteristica di B (per ipotesi B BV quindi PB & x 1 , x 2 ,! , x m ' è primitivo ricorsivo per il Teorema della forma normale) possiamo costruire la funzione caratteristica di B ( così: PB( & x ' 0 PB & & x '1 , & x '2 ,!, & x 'm ' & Lt & x ' I m & x J 0 Ciò vuol dire che la funzione caratteristica di B( vale 1 se e soltanto se x è un naturale tale che la m-pla & & x ' , & x ' ,!, & x ' ' B B , se la lunghezza della sequenza codificata in x non è maggiore di m e chiara1 2 m mente se x " # x 1 , x 2 ,!, x m $ J 0 (per come è stata definita la numerazione di Gödel). Poiché PB( & x ' è primitiva ricorsiva B ( BV . DIM. 6 : Vogliamo ora dimostrare che se B ( BV allora B BV . Se indichiamo con PB( & x ' la funzione caratteristica di B( allora possiamo scrivere: PB & x 1 , x 2 ,!, x m ' 0 PB( &# x 1 , x 2 ,!, x m $' EDIT by Qd – Calcolabilità – XXI Lez. 117 Cioè la m-pla & x 1 , x 2 ,!, x m ' B B se e soltanto se x " # x 1 , x 2 ,!, x m $ B B ( , poiché abbiamo espresso la funzione caratteristica di B mediante il predicato PB( &# x 1 , x 2 ,!, x m $' che è primitivo ricorsivo, B BV . Conseguenza importante del teorema appena dimostrato è che l’insieme: @# x , y $ B " | HALT & x , y 'A non è calcolabile poiché non lo è la relativa funzione caratteristica e cioè HALT & x , y ' . TEOREMA 4.4: L’insieme B è ricorsivo se e solo se 0 B e B( sono entrambi r.e. DIM. 7 : Se B è ricorsivo, allora dal teorema 4.1, lo è anche B e dal teorema 4.3 ricaviamo che, poiché B e B sono ricorsivi allora B e B sono anche r.e. DIM. 6 : Se B e B sono entrambi r.e. dobbiamo provare che B è ricorsivo, a tal fine possiamo scrivere: B " @ x B " | g & x ' CA e B " @ x B " | h & x ' CA (con g & x ' e h & x ' parzialmente calcolabili per la definizione di insiemi r.e.) Supponendo che g & x ' venga calcolata dal programma c ed h & x ' dal programma d , posto p " # &c ' e q " # &d ' . Allora possiamo scrivere un programma che calcola l’insieme B, cioè che calcola la funzione caratteristica di B (tale metodo prende il nome di incastro (dovetailing) di due algoritmi adoperando il teorema 3.2 del contapassi secondo cui la funzione STP è primitiva ricorsiva): # A$ IF STP&1' & X , p,T ' GOTO C IF STP&1' & X , q ,T ' GOTO E Se il programma c di numero p si ferma su ingresso X dopo al più T passi, il programma a sinistra rappresentato restituisce 1 (istruzione #C $ ), ciò vuol dire che X B B , essendo B l’insieme costituito dai natu- rali tali che la funzione g & x ' calcolata da c sia determinata ( C ). Se invece il programma p non si ferma dopo al più T passi, ciò potrebGOTO A be corrispondere al fatto che X D B , per verificare ciò si esegue il predicato STP sul programma d , in caso negativo si incrementa T e si ripe#C $ Y K 1 tono i controlli sul programma c sempre su ingresso X ma in base ad un numero di passi maggiore ( T + 1 ), in caso positivo si traduce questa cosa in X D B e si esce dal programma descritto a sinistra, il quale ritorna 0 (ricordiamo che STP è un predicato calcolabile). T KT + 1 Il programma descritto è di fatto una funzione caratteristica per B che è ricorsiva, quindi B è ricorsivo. TEOREMA 4.5: Se B e C sono insiemi r.e. allora lo sono anche B E C e B F C . DIM. F : Posto B " @ x B " | g & x ' CA e C " @ x B " | h & x ' CA (chiaramente g e h sono parzialmente calcolabili) Sia f & x ' la funzione calcolata dal programma: EDIT by Qd – Calcolabilità – XXI Lez. 118 Y K g &X ' Y K h&X ' in pratica il programma termina soltanto quando sia g & x ' che h & x ' terminano, possiamo affermare quindi che: B F C " @ x B " | f & x ' CA che rappresenta la definizione di insieme r.e. essendo f & x ' parzialmente calcolabile. DIM. E : Per ottenere la dimostrazione ci serviamo nuovamente dell’algoritmo d’incastro. Posto di nuovo B " @ x B " | g & x ' CA e C " @ x B " | h & x ' CA , posto p " # &c ' e q " # &d ' i numeri dei programmi che calcolano rispettivamente g & x ' e h & x ' , consideriamo ora la funzione k & x ' calcolata dal seguente programma: # A$ & X , p,T ' GOTO E STP&1' & X , q ,T ' GOTO E IF STP IF & 1' T KT + 1 GOTO A Il programma è simile a quello visto prima però in questo caso possiamo affermare che k & x ' C soltanto quando almeno uno dei due programmi p o q termina su ingresso X dopo al più T passi, di conseguenza possiamo concludere che: B E C " @ x B " | k & x ' CA . Il teorema è dunque dimostrato. DEF.: Con il simbolo Wn indichiamo l’insieme: Wn " @ x B " | L & x , n ' CA ( " @ x B " | g & x ' CA con g & x ' parzialmente calcolabile dal programma c e # &c ' "n) Ne segue: TEOREMA 4.6 (dell’enumerazione): Un insieme B è r.e. se e solo se 0 esiste un n tale che B " Wn . DIM.: È un’immediata conseguenza della definizione data per L & x , n ' . Si ha infatti B " Wn 0 B " @ x B " | g & x ' CA " @ x B " | L & x , n ' CA con g & x ' parzialmente calcolabile dal programma c e # &c ' "n. Il teorema deve il suo nome al fatto che la sequenza W0 ,W1 ,W2 ,! rappresenta una enumerazione di tutti gli insiemi r.e., scandisce cioè tali insiemi in base al numero di programma ( # &c ' " 0,1,2,! ). DEF.: Con K indichiamo il seguente insieme: K " @n B " | n BWn A EDIT by Qd – Calcolabilità – XXI Lez. ( " @n B " | L & n, n ' CA con n " # &c ') 119 Esso rappresenta l’insieme di tutti i naturali per cui i programmi di numero n si fermano su ingresso n, tale insieme può essere identificato tra gli elementi della diagonale della matrice delle funzioni unarie M &1' vista prima: N input Mc(1)0 & 0 ' Mc(1)0 & 1' C num. prog. C N Mc(1)0 & 2 ' !! Mc(1)1 & 0 ' Mc(1)1 & 1' Mc(1)1 & 2 ' !! Mc(1)2 & 0 ' Mc(1)2 & 1' Mc(1)2 & 2 ' ! ! $ $ $ $ $ $ Non è detto però che tutti i numeri corrispondenti ai programmi che calcolano le funzioni sulla diagonale siano tutti appartenenti all’insieme K, in quanto alcuni elementi sulla diagonale potrebbero assumere valori indeterminati 5 . % % Da quanto visto possiamo affermare che: n BWn 0 L & n, n ' C0 HALT & n, n ' . Allora K rappresenta l’insieme di tutti gli interi n tali che il programma di numero n si ferma su ingresso n, da cui abbiamo: TEOREMA 4.7: K è un insieme r.e. ma non è ricorsivo. DIM.: Per assurdo supponiamo che K sia ricorsivo, quindi, per il Teorema 4.4, abbiamo che sia K che K sono r.e. Sappiamo per certo che K è r.e. infatti, essendo K " @n B " | L & n, n ' CA , L & n, n ' per il Teorema 3.1 dell’universalità è certamente parzialmente K " @n B " | L & n, n ' CA rispecchia la definizione di insieme r.e. calcolabile, quindi la scrittura Ora, se anche K fosse r.e., per il Teorema 4.6 dell’enumerazione, si avrebbe K " Wi per qualche i. Da ciò conseguirebbe che i BWi 0 i B K (se i B Wi allora i B K e viceversa, essendo uguali), ma si ha anche che (per definzione K " @n B " | n B Wn A ) i B K 0 i BWi (nel caso in cui i " n , cioè effettuando la diagonalizzazione), da cui si avrebbe i B K 0 i B K , ma ciò è assurdo ( K è il complemento di K quindi i B K 0 i D K ). Quindi l’insieme K è r.e. ma non è ricorsivo e inoltre si apprende che K non è r.e. A tale conclusione si può giungere anche mostrando che, poiché K " @n B " | HALT & n, n 'A , HALT rappresenta la funzione caratteristica che definisce K, essendo HALT & x , y ' (in particolare HALT & x , x ' ) un predicato non calcolabile, allora K non è calcolabile (cioè non è ricorsivo, per definizione un insieme si dice non calcolabile o non ricorsivo se la sua funzione caratteristica non è calcolabile). EDIT by Qd – Calcolabilità – XXI Lez. Esercitazione di fine Corso 9/01/2007 Esercizio 1 (rif. D.S.W. pag. 28, ex.1): Sia c il programma (b) (rif. D.S.W. pag. 19), scrivere un calcolo di c iniziando dallo snapshot 1 # A $ IF X O 0 GOTO B 2 Z K Z +1 & 1,! ' con ! " @ X " 2,Y " 0, Z " 0A . 3 IF Z O 0 GOTO E Abbiamo la sequenza: 4 #B $ X K X P 1 s1 " & 1,! ' ; s2 " & 4, @ X " 2,Y " 0, Z " 0A ' ; 5 Y KY +1 s3 " & 5, @ X " 1,Y " 0, Z " 0A ' ; s 4 " & 6, @ X " 1,Y " 1, Z " 0A ' ; 6 Z K Z +1 s5 " & 7, @ X " 1,Y " 1, Z " 1A ' ; s6 " & 1, @ X " 1,Y " 1, Z " 1A ' ; 7 IF Z O 0 GOTO A s7 " & 4, @ X " 1,Y " 1, Z " 1A ' ; s8 " & 5, @ X " 0,Y " 1, Z " 1A ' ; 8 s9 " & 6, @ X " 0,Y " 2, Z " 1A ' ; s10 " & 7, @ X " 0,Y " 2, Z " 2A ' ; s11 " & 1, @ X " 0,Y " 2, Z " 2A ' ; s12 " & 2, @ X " 0,Y " 2, Z " 2A ' ; s13 " & 3,@ X " 0,Y " 2, Z " 3A ' ; s14 " & 8, @ X " 0,Y " 2, Z " 3A ' s14 è l’istantanea terminale. Esercizio 2 (rif. D.S.W. pag. 28, ex.2): Creare un programma c tale che per ogni calcolo s1 , s2 ,! , sk di c con s1 " & 1,! ' risulta k " 5 . Possiamo scrivere il seguente programma che soddisfa la traccia dell’esercizio: 1 X K X +1 2 X K X P1 3 X K X +1 Qualsiasi sia l’input vi sarà sempre un calcolo per cui sk " s5 . 4 X K X P1 5 Esercizio 3 (rif. D.S.W. pag. 31, ex.1): Sia c il seguente programma: IF X O 0 GOTO A # A$ X K X +1 IF X O 0 GOTO A # A$ Y KY +1 calcolare M c&1' & x ' . Sia X " r O 0 : poiché X O 0 si salta all’istruzione etichettata con A (la prima), quindi X " r + 1 ; all’istruzione successiva risulta ancora X O 0 , quindi si salta all’istruzione A (sempre la prima) e X " r + 2 , si capisce bene che questo meccanismo non avrà mai termine, quindi in questo caso la funzione calcolata dal programma assume valore indeterminato. 121 Mentre, se X " 0 , dalla prima istruzione si passa alla seconda, quindi X " 1 , alla terza istruzione risulta X non nulla quindi si salta all’istruzione etichettata con A (sempre la prima); si deduce che anche in questo caso la funzione calcolata dal programma non assumerà mai valori determinati, si ha dunque: M c&1' & x ' "5 >x B " . Esercizio 4 (rif. D.S.W. pag. 36, ex.5): Sia P & x ' un predicato calcolabile. Dimostrare che la seguente funzione è parzialmente calcolabile: QR x 1 + x 2 se P & x 1 + x 2 ' f & x1 , x2 ' " S altrimenti RT5 (il comportamento di P non ci interessa, cioè non ci interessa sapere per quali valori sarà vero o falso). Essendo P & x ' calcolabile per ipotesi possiamo adoperarlo all’interno di un S-programma che calcoli f & x 1 , x 2 ' : # A$ Z K X1 + X2 IF # P & Z ' GOTO A Y KZ Chiaramente tale programma calcola la funzione f & x 1 , x 2 ' , quindi possiamo affermare che essa è parzialmente calcolabile, avendo esibito un S-programma che la calcola. Esercizio 5 (rif. D.S.W. pag. 36, ex.6): Sia P & x ' un predicato calcolabile. Dimostrare che la funzione seguente è parzialmente calcolabile: QR1 EX P & r ' " S RT5 se vi sono almeno r numeri n tali che P & n ' " 1 altrimenti . In pratica EX P & r ' " 1 se r è il numero minimo di predicati P & n ' veri (se ad esempio P & 0 ' " 1 , P & 1' " 1 , P & 2 ' " 0 , P & 3 ' " 1 , P & k ' " 0 >k H 4 allora risulterà: EX P & 0 ' " 1 , EX P & 1 ' " 1 , EX P & 2 ' " 1 , EX P & 3 ' " 1 , EX P & 4 ' "5 , EX P & 5 ' "5 , in quanto il predicato P è vero soltanto per 3 valori di x). Si deve dunque realizzare un programma che verifichi che P & x ' sia vero almeno r volte e quindi che restituisca come output il valore 1, in caso contrario deve entrare in un loop infinito, il programma a destra calcola EX P & r ' . Se avessimo voluto dimostrare invece che EX P & r ' era primitiva ricorsiva non era sufficiente esibire un S-programma che la calcolasse, ma avremmo dovuto esprimere la funzione utilizzando le funzioni iniziali adoperando un numero finito di volte composizione di funzioni e ricorsione primitiva. IF X " 0 GOTO C # A$ IF P & Z ' GOTO B Z K Z +1 GOTO A #B $ X K X P1 Z K Z +1 IF X O 0 GOTO A #C $ Y K1 Esercizio 6 (rif. D.S.W. pag. 43, ex.2): Dimostrare che la classe di tutte le funzioni totali è una classe PRC. Sappiamo che una qualsiasi classe PRC è costituita da funzioni totali. Le funzioni ottenibili dallo schema di ricorsione e composizione di funzioni appartenenti ad una classe PRC sono ancora totali, infatti la classe PRC è chiusa rispetto alla ricorsione e composizione. Quindi possiamo affermare che la classe delle funzioni totali è PRC. EDIT by Qd – Esercitazione 122 Esercizio 7: Dimostrare che la classe di tutte le funzioni totali unarie non è enumerabile. Si può dimostrare esibendo una funzione che non appartiene alla enumerazione, possiamo adoperare il metodo della diagonale. Supponiamo per assurdo che tale classe sia enumerabile, avremo: f 0 & x ' , f 1 & x ' , f 2 & x ' , …, f n & x ' , … >x B " . Ora definiamo la funzione g & x ' " f x & x ' + 1 la quale è chiaramente una funzione totale, quindi deve trovarsi nella enumerazione, cioè deve esiste un indice k tale che g & x ' " f k & x ' . Ma se scegliamo un valore di x uguale proprio a k (diagonalizzazione) avremo: f k &k ' " g &k ' " f k &k ' + 1 Che è chiaramente impossibile, quindi la classe non è enumerabile. Esercizio 8 (rif. D.S.W. pag. 47, ex.2): Dimostrare che >k B " la funzione f & x ' " k è primitiva ricorsiva. Bisogna esprimere la funzione adoperando composizione e ricorsione applicate alle funzioni iniziali un numero finito di volte, si ha quindi: & f & x ' " s s & s ! s & n & x ' ' !' ' La funzione successore s deve essere applicata k volte e la funzione nulla n una sola volta, abbiamo quindi una funzione primitiva ricorsiva. Esercizio 9 (rif. D.S.W. pag. 54, ex.1): Dimostrare che la seguente funzione è primitiva ricorsiva: se x è un quadrato perfetto Q2 x g &x ' " S T2 x + 1 altrimenti Per dimostrare che la funzione è primitiva ricorsiva dobbiamo sostituire all’ipotesi “se x è un quadrato perfetto” un predicato primitivo ricorsivo come il seguente: P & x , y ' 0 & Uy 'I x & x " y 2 ' Non è difficile dimostrare che le due funzioni f & x ' " 2 x e h & x ' " 2 x + 1 sono primitive ricorsive, quindi possiamo riscrivere g & x ' così: QR f & x ' se P & x , y ' g &x ' " S RTh & x ' altrimenti La quale risulta primitiva ricorsiva (rif. teorema 5.4, definizione per casi D.S.W. pag. 50). Esercizio 10 (rif. D.S.W. pag. 58, ex.5): Sia R & x , t ' un predicato primitivo ricorsivo e g & x , y ' " max R & x , t ' tIy cioè g & x , y ' è il più grande valore t I y per cui R & x , t ' è vero, in caso contrario (cioè se non c’è alcun valore per cui il predicato è vero) allora g & x , y ' " 0 , vogliamo dimostrare che tale funzione è primitiva ricorsi- va. EDIT by Qd – Esercitazione 123 Possiamo esprimere la funzione g & x , y ' come segue: @ A g & x , y ' " mint I y R & x , t ' V # Uu I y ,1R & x , u ' V & u J t '-2 Non avendo a disposizione una funzione primitiva ricorsiva max, si simula il suo comportamento assicurando che il massimo valore per cui è vero il predicato R & x , t ' equivale al minimo, ma aggiungendo anche la clausola che non deve esistere alcun valore maggiore di t che rende vero il predicato Esercizio 11 (rif. D.S.W. 77, ex.1): Sia Lu & x ' la funzione universale che calcola il programma di numero u. Si deve dimostrare che per ogni u esistono infiniti numeri v per cui Lu & x ' " Lv & x ' >x B " . Possiamo costruire, a partire dal programma c di numero u con n istruzioni, il nuovo programma c i di numero v, di n + 1 istruzioni, aggiungendo al programma c dopo la sua ultima istruzione l’istruzione pigra: Z i K Z i (se avessimo aggiunto come ultima istruzione Y K Y allora u " v - rif. D.S.W. pag. 67). È chiaro che # &c i ' O # &c ' #, ma i due programmi calcolano la stessa funzione. Tale metodo può es- sere applicato un numero infinito di volte fornendo infiniti valori di v che soddisfano sempre l’uguaglianza: Lu & x ' " Lv & x ' . Ciò ci fa capire che se esiste un programma per una funzione parzialmente calcolabile allora ne esistono infiniti che calcolano la stessa funzione (analogamente a quanto accade per gli automi). Esercizio 12 (rif. D.S.W. 85, ex.7-a): Siano A e B due insiemi. Provare o confutare che: se A E B è r.e. 7 A e B sono entrambi r.e. L’implicazione è falsa, il controesempio è dato dall’insieme " che è r.e. e può essere visto come l’unione di K e K , sappiamo che K è r.e. ma non K . Esercizio 13 (sulle grammatiche C.F. - rif. D.S.W. 287, ex.1-a): Esibire una grammatica C.F. che genera il seguente linguaggio: @ A L & W ' " a # j $b #i $ | j H i J 0 . La grammatica C.F. W ha le seguenti produzioni: S N ab | aSb | aS e chiaramente genera il linguaggio suindicato. N.B.: Questi erano solo alcuni dei tanti (e differenti) esercizi che esistono circa gli argomenti visti, è vivamente consigliato, al fine di superare l’esame, di svolgere un numero consistente di esercizi, prendendo spunto dal libro di testo e dalle indicazioni dei Professori, nonché ovviamente partire da una buona conoscenza dei concetti teorici, senza i quali sarebbe molto difficile risolvere gli esercizi, soprattutto quelli sulla calcolabilità. In bocca al lupo a Tutti EDIT by Qd – Esercitazione Qd 124 Modifiche apportate rispetto alla versione del 29 Settembre 2008 (le pagine indicate in questo elenco si riferiscono alla versione del 29 Settembre 2008): * * * Pag. 23: Nel passo induttivo della formula di Kleene, l'esponente del primo elemento del secondo membro dell'equazione è "k", non "k+1"; Pag. 24: Nella dimostrazione del Lemma a fine pagina, nel passo induttivo, l'esponente del primo elemento del secondo membro dell'equazione è "r", non "r+1"; Pag. 28: Nel teorema 5.4, al punto 1.c, la forma corretta del secondo membro dell’equivalenza è: & & * * * ' ' L " 8: si1 & si2 & si3 ! sim ! 9; < = Pag. 29: Nella dimostrazione del teorema 6.1, al secondo rigo, la frase corretta è "... è ovvio che almeno una cassetta dovrà contenere almeno due lettere"; Pag. 84: Aggiunti i corollari 5.2 e 5.3, (rif.: D.S.W. pag. 50); Pag. 87: Al punto "Mentre il predicato Q E viene così espresso", nella formula dopo dev'essere Q E invece di QU ; * Pag. 109: Al passo # F $ nel programma universale è Y K & S '1 , non Y K & S 'i ; * Pag. 110: Definizioni errate di STP. Tra gli argomenti della funzione, manca y, la versione corretta è: STP&n ' & x 1 , x 2 ,!, xn , y , t ' ; * Pag. 110: Per il nuovo A.A., non basta il solo enunciato del teorema 3.2, recuperare la dimostrazione relativa dal D.S.W. pag. 74; Pag. 110: Nella definizione di funzione caratteristica, la forma corretta è "...e abbiamo: R " @a B S | P & a 'A "; * * Pag. 115: Dopo la DEF. l’implicazione corretta è: “…se l 8: min R & x 1 , x 2 ,! , xn , y ' 9; è totale < y = 7 lo è anche min R & x 1 , x 2 ,! , xn , y ' …”; y * * Pag. 118: Nella dimostrazione di U, all'ultimo rigo è B E C , non B F C ; Infine, spero che Alan mi perdoni dall’aldilà … pag. 102: si scrive Turing , non Touring.