aa. 2021-2022: si ringraziano gli studenti R. B. e I. S. per le correzioni e revisioni, M. A. per le immagini degli esercizi LR(0), P. per lâimmagine di Erschev.
Linguaggi e Compilatori
ER: costruire NFA a partire da unâespressione regolare
Ci sono due passi fondamentali:
- Costruire lâalbero astratto. Per farlo basta ârisolvereâ lâespressione regolare in maniera âspezzettataâ, a blocchi di parentesi.
- Disegnare lâautoma NFA a pezzi
Testo dâesempio
Lâespressione Ăš la seguente:
(a|c)*(c|b)*(abc)*
Regole per fare lâalbero astratto
Regole da tenere ben presente:
-
LâassociativitĂ a sinistra
-
OR (a|c):
| / \ a b -
AND (abc)*:
* | ° / \ ° c / \ a b
Passo 1: lâalbero astratto
°
/ \
/ \
/ \
/ \
/ \
° *
/ \ \
/ \ °
* * / \
| | / \
/ \ / \ ° c
a c c b / \
a b
Passo 2: lâautoma
Mi disegno i vari automi e li unisco tra loro.
Regole per disegnare lâautoma
- Disegno prima gli automi semplici (atomici, esempio, automa che riconosce a, automa che riconosce c) e li unisco
- Sebbene possa aver disegnato giĂ un altro automa in precedenza che facesse la stessa cosa, per ogni ramo devo disegnare un automa diverso
Esempio: se ho giĂ disegnato un automa che riconosce a e mi ritrovo a dover disegnare un ramo con un automa che riconosce a devo disegnarlo di nuovo
- Sebbene possa aver disegnato giĂ un altro automa in precedenza che facesse la stessa cosa, per ogni ramo devo disegnare un automa diverso
- Concatenazione (or)
- aggiungo uno stato vuoto iniziale
- faccio due branch con gli automi creati in precedenza
- aggiungo uno stato vuoto alla fine
- i due stati supplementari avranno epsilon nelle frecce
- Unione (and)
- prendo i due sottoautomi e li unisco tra loro andando a creare un nuovo stato
- quest ultimo avrĂ come nome âstato finale sottoautoma1 / stato iniziale sottoautoma2â
- Kleine (*)
- come concatenazione (stati supplementari) ma al primo fai una freccia che va allâultimo e il penultimo va nel secondo. Ovviamente entrambe le frecce hanno epsilon.
Disegno dellâautoma
Guardando lâalbero astratto, parti dallâestrema sinistra e cominci a fare piccoli sottoautomi. Man mano che risali lâalbero unisci a seconda di quello che trovi.

NFA: usare subset construction per costruire un DFA partendo da un NFA
Traccia

Cosa bisogna fare
- Si sceglie uno stato iniziale, 0 nel nostro caso, e si calcola la sua Δ-closure ossia seguendo le frecce con la Δ, bisogna vedere dove si finisce. Questo andrà a formare il nostro stato di partenza. Nel nostro caso: {0,2,4) = A.
- Si calcola la move per lo stato A: per ogni stato in A vedo dove vanno gli stati con tutti gli input dellâautoma, quindi, prima con a, poi con b e poi con c. Devo inoltre calcolare ogni volta la Δ-closure. Ogni volta che trovo un nuovo gruppo âche non ho mai vistoâ creo un nuovo stato. Esempio: se calcolo la move di A, il gruppo di prima, con lâinput a, ottengo Δ-closure({1,2}) = {0,1,2,4}. Siccome non ho mai visto in precedenza questa partizione, posso chiamarla B. In seguito, calcolerĂČ anche le sue move.
- Continuo finché non trovo altri stati
Calcoli e procedimento
Promemoria efficaci:
- dopo il secondo uguale, devo SEMPRE riscrivere gli stati che avevo scritto dopo il primo uguale
- lo stato vuoto Ú uno stato come tutti gli altri. In quanto tale ha un nome. Alla fine, verrà rappresentato come uno stato che non ha frecce entranti verso gli altri stati, e ogni input andrà in sé stesso.
- se non finisco da nessuna parte, scriverĂČ â
- Stato in D: Δ-closure(0) = {0,2,4} (A)
- Δ**-**closure(move(A, a)) = Δ-closure({1,2}) = {0,1,2,4} (B) â dopo il primo uguale: âdove vado con input a da 0,2,4 (A)?â. Dopo il secondo uguale: âdove vado con Δ da 1 e 2?â.
- Δ**-**closure(move(A, b)) = Δ-closure({1}) = {1} (C)
- Δ**-**closure(move(A, c)) = Δ-closure({3}) = {3} (D)
Bene, ora ho come nuovi stati B, C e D. Devo continuare. - Δ**-**closure(move(B, a)) = Δ-closure({1, 2}) = (B) â me lâero giĂ calcolato al passo 2
- Δ**-**closure(move(B, b)) = Δ-closure({1, 2}) = (B)
- Δ**-**closure(move(B, c)) = Δ-closure({3, 4}) = {0,2,3,4} (E)
- Δ**-**closure(move(C, a)) = Δ-closure({â }) = {â } (G)
- Δ**-**closure(move(C, b)) = Δ-closure({2}) = {0,2,4} (A)
- Δ**-**closure(move(C, c)) = Δ-closure({4}) = {0,2,4} (A)
- Δ**-**closure(move(D, a)) = Δ-closure({3}) = (D)
- Δ**-**closure(move(D, b)) = Δ-closure({â }) = {â } (G)
- Δ**-**closure(move(D, c)) = Δ-closure({2}) = (A)
- Δ**-**closure(move(E, a)) = Δ-closure({1, 2, 3}) = {0, 1, 2, 3, 4} (F)
- Δ**-**closure(move(E, b)) = Δ-closure({1}) = (C)
- Δ**-**closure(move(E, c)) = Δ-closure({2, 3}) = {0, 2, 3, 4} (E)
- Δ**-**closure(move(F, a)) = Δ-closure({1, 2, 3}) = (F)
- Δ**-**closure(move(F, b)) = Δ-closure({1, 2}) = (B)
- Δ**-**closure(move(F, c)) = Δ-closure({2, 3, 4}) = (E)
- G Ăš uno stato vuoto. Siccome, tra le altre cose non ha archi uscenti, posso non rappresentarlo.
Va bene, e adesso? Il DFA
Gli stati finali del DFA sono tutti quelli in cui, nel lavoro fatto in precedenza compare almeno uno stato finale dellâNFA.
Ad esempio, E contiene 2 e 4, dunque Ăš sicuramente uno stato finale.
NellâNFA gli stati finali erano 2 e 4.
Posso quindi disegnare lâautoma (va bene anche la forma tabellare, in grassetto gli stati finali):
| stato / input | a | b | c |
|---|---|---|---|
| A | B | C | D |
| B | B | B | E |
| C | G | A | A |
| D | D | G | A |
| E | F | C | E |
| F | F | B | E |
| G | G | G | G |
MIN: minimizzare gli stati di un DFA
Traccia

Risoluzione
- Scrivere fisso le seguenti cose:
- sia Î partizione iniziale
- sia Î new partizione di lavoro
- sia Î f DFA minimizzato
- ÎŁ = {a,b} â in questo caso a e b perchĂ© i simboli usati nellâautoma sono solo questi due
- Î = {{1,3,9}, {0,2,4,5,7,8}} â rispettivamente gli stati finali e i restanti
- Analizza le partizioni che hai creato. Se le dividi, analizza prima quelle divise. Ogni volta che dividi dai un numero a quella partizione, sarĂ piĂč comodo per altri calcoli che verranno fatti dopo. Costruisci la solita tabella âstato/inputâ, avendo cura di segnare non tanto lo stato di destinazione, ma la partizione in cui si trova lo stato di destinazione.\
{1, 3, 9} (1), {0,2,4,5,7,8} (2) â tra parentesi tonde il ânome della partizioneâ\
| stato / input | a | b |
|---|---|---|
| 1 | 5 (2) | 3 (1) |
| 3 | 9 (2) | 0 (2) |
| 9 | 2 (2) | 3 (1) |
Gli stati 1 e 9, a fronte dello stesso input vanno nella stessa partizione di output. Possono rimanere insieme, ma lo stato 3 se ne va per conto suo.\
**Î new = {1, 9}(1) {3}(3) {2, 5, 8, 0, 4, 7} (2)**\
\
Il 3 non ha discrepanze e quindi non verrĂ piĂč analizzato. (quando ho un singleton non lo considero).
3. Analizzo la nuova partizione {1, 9}
| stato / input | a | b |
|---|---|---|
| 1 | 5 (2) | 3 (3) |
| 9 | 2 (2) | 3 (3) |
Tutto ok. Non posso fondere piĂč di cosĂŹ.
4. Analizzo la partizione 2
| stato / input | a | b |
|---|---|---|
| 0 | 9 (1) | 2 (2) |
| 2 | 0 (2) | 1 (1) |
| 4 | 1 (1) | 2 (2) |
| 5 | 4 (2) | 1 (1) |
| 7 | 1 (1) | 8 (2) |
| 8 | 7 (2) | 9 (1) |
Posso quindi staccare sia 0 4 7 che 2 5 8, sempre per il solito motivo che a fronte dello stesso input vanno nelle stesse partizioni di destinazione.\
\
**Î new = {1, 9}(1) {3}(3) {2, 5, 8} (2) {0, 4, 7}(4)**\\
***
5. Analizzo le partizioni rimanenti. Sono irriducibili.
| a | b | |
|---|---|---|
| 0 | 9 (1) | 2 (2) |
| 4 | 1 (1) | 8 (2) |
| 7 | 1 (1) | 8 (2) |
| a | b | |
|---|---|---|
| 2 | 0 (4) | 1 (1) |
| 5 | 4 (4) | 1 (1) |
| 8 | 7 (4) | 9 (1) |
Importantissimo: pure se sono irriducibili devi comunque fare il giro âa vuotoâ. Finisci SOLO quando non cambi piĂč nulla.
FAT: fattorizzare una grammatica
Lâidea
Ricordate i monomi e i polinomi fatti a scuola? Ecco, fattorizzare una grammatica vuol dire fare circa la stessa cosa: trovate i monomi simili, fate raccoglimento e con un poâ di accortezze avrete fattorizzato una grammatica.
Traccia
A â AaBc | AabCa | AaCbA | AaBC | AabCB | AaCbB | AaBa | C
B â BBCB | BcC | BcaA | BCb | BBa | BcaC | C
C â CcBc | CAb | Cc | CCBb | CCC | CAB | CcAa | c
Svolgimento
Identifico i monomi e me li segno in qualche modo nella traccia.
Considero A:
- Ï = AaB, AabC, AaCb â ossia, tutte le parti in comune colorate che ho preso in considerazione quando ho raggruppato i monomi simili
- A â AaBAâ | AabCAâ | AaCbA''' | C â prendo le parti âin comuneâ e per ogni gruppo ci aggiungo un Aâ poi Aâ ecc. Se un monomio sta per conto suo, bisogna metterlo qui.
- le clausole con â, â ecc conterranno i âpezzi diversi non in comuneâ con i monomi raggruppati prima. Esempio: AaBc e AaBC in comune hanno AaB. Le loro parti non in comune sono c e C, che sono quelle che andranno a finire nella prima clausola.
- Aâ â c | C | a
- Aâ â a | B
- A''' â A | B
Considero B:
- Ï = B
- B â BBâ | C
- Bâ â BCB | cC | caA | Cb | Ba | caC
Considero C:
- Ï = Cc, CA, CC
- C â CcCâ | CACâ | CCC''' | c
- Câ â BC | Aa | Δ
- Câ â b | B
- C''' â Bb | C
RIC: eliminare la ricorsione sinistra da una grammatica
Regolette
SEGUIRE IL SACROSANTO ORDINE
- PRIMA sostituisco, se câĂš qualcosa da sostituire: il concetto dei pronomi. Ad esempio ho A â xA | Bc e B â Az | Cy, dovrĂČ dunque modificare B â Az, e quindi avrĂČ B â xAz | Bcz | Cy
- POI elimino eventuali ricorsioni
- nellâesempio di prima: voglio eliminare la ricorsione B â Bcz
- Divido B in due: B â xAzBâ | CyBâ e poi Bâ â czBâ | Δ
- Il primo pezzo si ottiene riscrivendo B di prima, tranne quella che voglio eliminare e ad ogni produzione gli aggiungo Bâ
- Il secondo pezzo si ottiene scrivendo la parte destra della ricorsiva che volevo togliere, tolgo la B, aggiungo la Bâ alla fine ed Δ
- NB: Se dovessi avere dopo la sostituzione, roba che Ăš ancora sostituibile devo sostituire. Esempio: se sostituisco B â Ab | c, e A me lâero giĂ calcolato, devo sostituirlo.
- Non ritorno mai su una cosa che avevo giĂ analizzato. Il procedimento Ăš lineare, e una volta che ho finito con A, basta, non posso piĂč modificarlo.
Traccia
A â xA | By
B â Cy | Bw | Az
C â Aw | Bz | Cz | x
Svolgimento
- Guardo la prima riga. Analizzo A: non ci sono operazioni da effettuare. Non succede nulla. Non ci sono ricorsioni dirette e non possiamo sostituire alcunchĂ©. Infatti A â By, potremmo sostituire B, ma non possiamo farlo adesso perchĂ© B non lo abbiamo ancora analizzato.
Scrivo:
> Analizzo A: non ci sono operazioni da effettuare - Analizzo B: notiamo che B â Az puĂČ essere riscritta: dobbiamo sostituire alla A, la parte destra della produzione di A (che sarebbe xA | By) seguita da z, poichĂ© câĂš Az.
Applico la regola 1 â riscrivo pari pari la produzione di B:
B â Cy | Bw | xA
e aggiungo z
B â Cy | Bw | xAz | Byz
Applico adesso la regoletta 2 â tolgo le ricorrenze immediate: B â Bw e B â Byz.
Riscrivo B con tutte le produzioni meno quelle che voglio togliere:
B â CyBâ | xAzBâ
poi, prendo le parti che mi interessano e ci aggiungo Bâ + simbolo di vuoto come produzione finale:
Bâ â wBâ | yzBâ | e - Riscrivo la grammatica aggiornata:
A â xA | By
B â CyBâ | xAzBâ
Bâ â wBâ | yzBâ | e
C â Aw | Bz | Cz | x - Ho finito con B, ora vado su C.
Analizzo C: notiamo che C â Aw e C â Bz possono essere riscritti
C â xAw | Byw | CyBâz | xAzBâz | Cz | x
Finito il passo 1? No. Possiamo continuare a sostituire!
C â xAw | CyBâyw | xAzBâyw | CyBâz | xAzBâz | Cz | x
Finito il passo 1? SĂŹ.
Posso togliere le ricorrenze immediate: C â CyBâyw, C â CyBâz, C â Cz
Solita cosa: riscrivo tutto C.
C â xAwCâ | xAzBâywCâ | xAzBâzCâ | xCâ
Câ â yBâywCâ | yBâzCâ | zCâ | e - Grammatica finale:
A â xA | By
B â CyBâ | xAzBâ
Bâ â wBâ | yzBâ | e
C â xAwCâ | xAzBâywCâ | xAzBâzCâ | xCâ
Câ â yBâywCâ | yBâzCâ | zCâ | e\
FF: First e follow
First: TODO
Follow
Devo avere ben presente questa tabella:

A seconda della follow che sto facendo, mi vado a vedere dove sta la lettera della follow (in quale âmonomioâ).
Siccome si chiama follow, devo vedere in che forma sta tramite la tabella, e regolarmi di conseguenza.

follow(C): dove compare C? bBCe â aggiungo e, primo caso ecc\
BU: LR(0)
Traccia
- Sâ â S
- S â AB | aA
- A â bB | cAb | a
- B â Bb | BA | b
Regolette
- Prima sposto il pallino di una posizione a destra, poi calcolo la chiusura
- la chiusura si calcola mettendo lâinsieme stesso + tutte le produzioni che hanno a sinistra, il primo simbolo dopo il pallino dellâinsieme originale.
- anche per un discorso di coerenza: quando mi ritrovo in una situazione tipo:
(I0,A) = {SââAâąB} = clos({SââAâąB}) = {SââAâąB, DEVO AGGIUNGERE ANCHE LA ROBA DI B.}
In caso la roba di B abbiamo altra roba che va in altre lettere (ad esempio se ho aggiunto B â âąCx, DEVO AGGIUNGERE ANCHE LA ROBA DI C).
Svolgimento
Inizialmente costruiamo I (Ă© una I di Imola).
Questo insieme si costruisce in questo modo: partiamo da Sâ. Da Sâ vado a S, quindi sicuramente metto Sâ â S. Poi vado a vedere S dove va: S â AB | aA. Possiamo continuare ad aggiungere le produzioni di A, ma poi ci fermiamo.
Formalmente:
Calcoliamo closure di I.
I = { Sâ â S } J = I
- Sâ â âąS â S â âąAB non appartiene a I â add
- â S â âąaA non appartiene a I â add
- I = { Sâ â âąS, S â âąAB, S â âąaA }
Continuo:
- S â âąAB â chi ci sta a destra del pallno? A. Quindi aggiungo tutta la roba di A a quello giĂĄ esistente: I = { Sâ â âąS, S â âąAB, S â âąaA, A â âąbB, A â cAb, A â âąa }
Continuo:
- S â âąaA â non succede niente perchĂ© câĂ© a piccola, che Ă© terminale.
Poi, aggiungiamo un pallino allâestrema sinistra di ogni parte destra di ogni produzione: { Sâ â âąS, S â âąAB, S â âąaA, A â âąbB, A â cAb, A â âąa }
Questo Ă© il mio I0, ovvero il mio insieme di partenza. Da qua, mi calcolo tutti gli altri insiemi, facendomi la goto e la chiusura di ogni produzione.
Prendo tutti i simboli a destra del pallino, e me li metto in colonna quando vado a calcolare goto.
Il ragionamento qua Ă©: chi Ă© che produce âą<simbolo> (nella parte a destra)?
Es. Nel primo caso: chi Ă© che ha S nella parte destra dopo il pallino? Solo Sâ â âąS. Siccome sto facendo la goto, sposto il pallino a destra e poi mi calcolo la closure.
Nella chiusura devo SEMPRE includere lâinsieme originale E le produzioni dopo il pallino.
Ad esempio clos( S â AâąB), mi ritrovo dopo il pallino B, quindi aggiungerĂł B â âąBb ecc ecc
- goto(I0, S) = clos({Sâ â Sâą}) = { Sâ â Sâą} â non abbiamo mai visto questo insieme quindi I1
- goto(I0, A) = clos({S â AâąB}) = { Sâ â AâąB, B â âąBb, B â âąBA, B â âąb }
- goto(I0, a) = clos({S â aâąA, A â aâą})
- goto(I0, b) = clos(A â bâąB)
- goto(I0, c) = clos(A â câąAb)
NB: al passo 1, troviamo un qualcosa che ha giå il pallino alla sua estrema destra. Nonostante si tratti di un insieme che non abbiamo mai analizzato, non dobbiamo analizzarlo proprio perché il pallino é giå tutto a destra.
Poi basta, proprio come lâesercizio sulle chiusure, continuo sino a quando non trovo piu nulla di nuovo.



UN: Unify
Traccia
α1 Ă (α2 â α1) Ă (α1 â α2)
α3 Ă ((α2 â α1) â α3) à α4
Cosa bisogna fare
Anche qui seguiamo la âlogica dei pronomiâ.
Tre passi fondamentali:
- albero astratto: molto semplice, stile âADTâ (vedi ER: passo 1)
- stabilire ordine di visita DFS: la classica visitĂ in profonditĂ , basta solo ricordarsi che i âpronomiâ
- applicare la unify e scegliere i rappresentanti
Regolette
-
Albero astratto
- Per disegnare lâalbero astratto parto sempre da x.
- LâassociativitĂ sta a sinistra, quindi conviene partire da destra verso sinistra
- NORMALMENTE salvo dove specificatamente indicato lâordine di prioritĂ Ăš il seguente:
- PRIMA le x
- Poi i â
- NORMALMENTE salvo dove diversamente specificato, lâassociativitĂ Ăš tutta a SINISTRA DI TUTTO
- vale a dire: se ho âa1 x a2 x a3â devo immaginarmele come â(a1 x a2) x a3â come se a2 fosse in mezzo e decidesse a chi unirsi⊠quindi posso mettere le parentesi
- Quando sto disegnando lâalbero, e noto che α1 lâho giĂ disegnato da qualche parte, devo fare un cerchio che va dallâoriginale alla posizione attuale (dovrei avrei disegnato α1).
-
Ordine DFS
- Quando stabilisco lâordine di visita, non devo contare i âbuchiâ lasciati dai cerchi âal posto di α1â
- NON ESISTE UNA DFS UNICA
-
Unify e scelta del rappresentante - **** presi a coppie, si verificano questi casi:
- non si verifica mai
- 1 e 7 rappresentano lo stesso tipo (esempio, sono due α)
- scelgo uno dei due
- 1 e 7 sono operatori con due figli
- scelgo uno dei due
- 1 e 7, uno dei due Ú una variabile (Ú un α insomma)
- scelgo lâoperatore
-
Scrivo le classi di equivalenza
Passo 1: disegno del type graph
Qui non câĂš molto da spiegare, câĂš bisogno di molta pratica.
Esercizio base ânormaleâ

Esercizio difficile: prioritĂ invertita (primaâ , poi x⊠normalmente Ăš il contrario) e associativitĂ a destra

Passo 2: stabilire lâordine di visita DFS
Lanciare una DFS e segnare lâordine di vista accanto a ogni nodo. Ad esempio, x sarĂ il nodo radice, quindi scriverĂČ 1 ecc
Lâunica cosa da tener presente Ăš che: quando ho un α giĂ referenziata non la conto nella visita.
Questo passo Ăš giĂ segnato nellâimmagine qui sopra.
Passo 3: chiamare la unify e scelta dei rappresentanti
Idealmente i due alberi vanno di pari passo. Devo analizzare i due alberi a coppie a partire dalle radici, e vedere cosa posso unire. Nel caso semplice si inizia dallâalto 1 e 7: sono le radici degli alberi.
Ecco i quattro casi seguiti dal criterio di scelta del rappresentante:
- non si verifica mai
- 1 e 7 rappresentano lo stesso tipo (esempio, sono due α)
- scelgo uno dei due
- 1 e 7 sono operatori con due figli
- scelgo uno dei due
- 1 e 7, uno dei due Ú una variabile (Ú un α insomma)
- scelgo lâoperatore
Nel caso difficile devo prendo 1 e 18.
Risoluzione caso difficile:

****
DEVO USARE lâapproccio grafico, quindi non occorre riscrivere tutto da capo.
Qui sopra, una possibile soluzione con approccio grafico del caso difficile.
Passo 4: scrivere le classi di equivalenza
Per lâesercizio semplice, le classi di equivalenza ottenute sono:
{{1,7}, {2,8}, {3,9}, {4, 10}, {5,11}, {6,12}}
Scrivere in alto, sopra ogni classe, i vari rappresentanti presi prima, per ogni classe di equivalenza (1 2 3 4 11 e 6).
---
Per lâesercizio difficile basta fare la stessa cosa.
DOM
Traccia

Regolette
- DFS, Post-Order, e Reverse PostOrder
- DFS come ti pare. Fai la classica se non sai come farla.
- Post-order
- Come ti pare, fai la visita per livelli a partire dallâultimo se non sai come fare.
- Reverse post-order (RPO)
- Riscrivi questo ordine al contrario
- DOM(nodo partenza) = 1, DOM(2) = ⊠= DOM(9) = {2, âŠ, 9}
- Cominci ad applicare algoritmo DOM: per ogni nodo seguendo la RPO, vedi chi sono i predecessori e:
- se Ăš uno, fai DOM(predecessore) U elemento attuale (es. ordine 2, 3, DOM(3) = PREDS(3) = {2} â devo mettere DOM(2) + 3 â {2, 3}
- se Ăš piĂč di uno, fai intersezione (roba comune) tra gli elementi comuni e poi unisci quello attuale
- Cominci ad applicare algoritmo DOM: per ogni nodo seguendo la RPO, vedi chi sono i predecessori e:
QA
- la DFS mi viene diversa, come faccio?
- NON ESISTE UNA DFS UNICA
- il POST-ORDER mi viene diverso, come faccio?
- NON ESISTE UN POST ORDER UNICO. Di solito si fa la visita per livelli partendo dallâultimo.
Svolgimento

IG: Inference Graph - colorazione grafo
Traccia
Dato il seguente BB in 3AC I costruire lâinterference graph I applicare allâIG lâalgoritmo di colorazione specifico per la register selection con k = 2
- a=1
- b=2
- c=a+1
- d=a+4
- e=b+1
- f=e+d
- g=a+2
- h=f+g
- i=c+6
- l=g+2
Passi
- Disegnare il grafo
- Eliminare i nodi uno ad uno
- Colorare il grafo
Regolette
Dalla traccia k = 2, abbiamo i seguenti casi:
- un nodo ha il minor numero di archi (o nessuno) < k â ottimo, lo elimino
- altrimenti, se ho piĂč nodi che hanno tutti numero di archi >= k â elimino il nodo con il maggior numero di archi in assoluto in tutto il grafo
In altre parole: quando non posso fare nulla (la condizione Ăš MINORE di k, non MINORE UGUALE) tolgo il nodo con piĂč archi in assoluto.
Passo 1: disegno tutto il grafo
Disegnamo tutti gli stati a b c d e f g h i l
Innanzitutto vediamo a: dobbiamo trovare lâultima occorrenza di a: appare in g. Quindi devo collegare a con tutti gli âstatiâ che vengono DOPO sĂš stesso e prima di g (g escluso). Ripeto per tutti gli stati.
ESEMPIO: c lo collegherĂČ con gli âstatiâ d, e, f, g, h perchĂš inizio da d e compare lâultima volta in i.

Passo 2: eliminare i nodi uno ad uno
Adesso: lâobiettivo Ăš quello di eliminare pian piano tutti i nodi. Dalla traccia k = 2.
Iniziamo: chi Ăš che ha il minor numero di archi in assoluto? il nodo l (Ăš una L).
Ridisegnamo il grafo, facendo una bella croce su l.

Rimuoviamo tutti gli archi di l e andiamo a ridisegnare il grafo.
Passo successivo: qual Ú il nodo con il minor numero di archi? i naturalmente, poiché ha solo un arco.
Rimuoviamo allora i. (caso

Passo successivo: qual Ăš il nodo col minor numero di archi? Eh, ma qui câĂš il caso 2: infatti la condizione Ăš MINORE DI 2, NON minore uguale a 2. Quindi stiamo nel caso 2.
Il caso 2 ci dice âprendi quello col maggior numero di archi e toglilo.
In questo caso Ăš C, perchĂ© ne ha 7, e quindi tolgo C. Ci scrivo perĂČ anche un bel âTOSPILLâ a destra. Ă importante!

Proseguo finché non arrivo alla fine.

Qua câĂš un altro TOSPILL da fare!

Finalmente ho finito!
Passo 3: coloro il grafo
Parti dalla fine (G10).
Regolette:
- allâinizio, il primo nodo avrĂ il colore che preferiamo (es. rosso)
- il nodo successivo, dovrĂ avere un colore diverso da quello vicino
- i TOSPILL sono incolori!
Quindi:
- a V10 (e) assegno verde
- a V9 (d) assegno rosso dato che lâadiacente Ăš verde
- a V8 (b) assegno verde, poichĂ© il rosso lâavevo giĂ assegnato
- a V7 (a) non assegno alcun colore: câĂš il tospill
- a V6 (f) assegno rosso
- a V5 (g) assegno verde, poichĂ© il rosso lâavevo giĂ assegnato
- a V4 (h) assegno rosso, poichĂ© il verde lâavevo giĂ assegnato
- a V3 (c) non assegno alcun colore: câĂš il tospill
- a V2 (i) assegno rosso, poichĂ© il verde lâavevo giĂ assegnato
- a V1 (l) assegno verde (ma posso anche assegnare il rosso)
NOTA BENE: per la buona riuscita di questo esercizio, Ăš opportuno segnarsi sul grafo di partenza i colori â questo perchĂ© puĂČ essere utile vedere a colpo dâocchio chi Ăš adiacente a chi.
Non richiesto dallâesercizio, ma riportato comunque per comoditĂ , ecco la colorazione del grafo finale:

ER: Erschev e assembly
Regolette
- prendi il testo dellâesercizio
- costruisci un albero facendo dfs, utilizzando ultima riga. Ignori i valori istantanei.
- fai una dfs e devi seguire lâalgoritmo:

- generi il codice, prendi tutto, lo metti in lista et voilĂ !
Esercizio e albero

Risoluzione


Tracce di esercizi vari
ER
- Costruire NFA per questa espressione
(010)*(11)*- 0 e 1 separati
- 01
- 0 separato
- 010
- 010*
- 1 e 1 separati
- 11
- (11)*
- fare merge di tutto
- Costruire NFA per questa espressione
((a|c)*(cb))* - Costruire NFA per questa espressione
((11|00|11)*(0|1)*)* - Costruire NFA per questa espressione
(x|yx)*(zy|x)* - Costruire NFA per questa espressione
((a|b)c)*|(cb|a)*
NFA
Usare subset construction per costruire DFA a partire da NFA
+-------+---------------------------+
| Stato | Transizioni |
+-------+---------------------------+
| 0 | a â 0 |
| | b â 0 |
| | Δ â 1, 2 |
+-------+---------------------------+
| 1 | a â 1 |
| | Δ â 3 |
+-------+---------------------------+
| 2 | b â 2 |
| | Δ â 3 |
+-------+---------------------------+
| 3 | c â 3 (terminante) |
+-------+---------------------------+
+-------+------------------------------+
| Stato | Transizioni |
+-------+------------------------------+
| 0 | c â 0, 1 |
+-------+------------------------------+
| 1 | (terminante) |
+-------+------------------------------+
| 2 | b â 2 |
| | c â 3 |
+-------+------------------------------+
| 3 | a â 3, 1 |
| | Δ â 0 |
+-------+------------------------------+
+-------+---------------------------------------------+
| Stato | Transizioni |
+-------+---------------------------------------------+
| 0 | a â 0, 2 |
| | b â 0 |
| | Δ â 1 |
+-------+---------------------------------------------+
| 1 | c â 1, 2 |
+-------+---------------------------------------------+
| 2 | b â 2, 0 |
| | Δ â 3 |
+-------+---------------------------------------------+
| 3 | a â 3 |
| | c â 4 |
+-------+---------------------------------------------+
| 4 | b â 4 |
| | Δ â 1 |
| | (terminante) |
+-------+---------------------------------------------+
+-------+----------------------------------+
| Stato | Transizioni |
+-------+----------------------------------+
| 0 | y â 0 |
| | x â 1 |
| | Δ â 3 |
+-------+----------------------------------+
| 1 | z â 2 |
| | x â 0 |
+-------+----------------------------------+
| 2 | x â 1 |
| | Δ â 3 (terminante) |
+-------+----------------------------------+
| 3 | z â 2 |
| | Δ â 0 |
+-------+----------------------------------+
MIN
+-------+-------------------------------+
| Stato | Transizioni |
+-------+-------------------------------+
| 0 | a â 3 |
| | b â 2 |
+-------+-------------------------------+
| 2 | b â 2 |
| | a â 3 |
+-------+-------------------------------+
| 3 | b â 4 |
| | a â 1 |
+-------+-------------------------------+
| 1 | a â 1 |
| | b â 4 |
+-------+-------------------------------+
| 4 | a â 4 |
| | b â 4 |
| | (terminante) |
+-------+-------------------------------+
RIC
A --> Ba|a
B --> Cb|b
C --> Cc|A
A --> BC|Ab|a
B --> Ad|CA|BA
C --> Bc|AC|CA|c
A --> BaA|Ac|a
B --> Ae|CbB|BB|b
C --> BCa|DdA|CCe
D --> DC|epsilon
X --> XaZ|YWc|W
Y --> Yd|WbZ|ZWc|X
W --> WXa|ZZd|YYe|c
Z --> XX|Zc
A --> BC|Ab|a
B --> Ad|CA|BA
C --> Bc|AC|CA|epsilon
FAT
A --> AaCb
AaCa
ABc
BVbB
BAC
BVbC
aa
a
B --> CbC
CAa
CbA
BAc
BAb
epsilon
C --> CBa
AaC
CBC
BaB
BaA
c
A -> AaBC
AaB
AaCC
AaB
a
B --> BbC
BBB
BbB
b
C --> Cc
CCc
CcC
c
BU1 LR(0)
S' --> S
S --> AB
aA
A --> bB
cAb
a
B --> Bb
BA
b
UN
\
\alpha_3 \times ((\alpha_2 \rightarrow \alpha_1) \rightarrow \alpha_3) \times \alpha_4
\alpha_1 \rightarrow \left( \alpha_2 \rightarrow \left( \alpha_2 \times (\alpha_3 \rightarrow \alpha_1) \right) \right)
(\alpha_4 \times \alpha_5) \rightarrow \left( \alpha_4 \rightarrow (\alpha_5 \times \alpha_3) \right)
\alpha_1 \times \left( (\alpha_2 \rightarrow \alpha_3) \rightarrow \text{list}(\alpha_4) \right)
\left( (\text{list}(\alpha_5) \times \text{list}(\alpha_6)) \rightarrow \alpha_7 \right) \rightarrow \text{list}(\alpha_8)
### DOM 1. ``` +-------+-------------------------+ | Stato | Transizioni | +-------+-------------------------+ | 1 | â 3, 2 | +-------+-------------------------+ | 2 | â 5 | | | â 4, 6 | +-------+-------------------------+ | 5 | â 1 | +-------+-------------------------+ | 6 | â 2 | +-------+-------------------------+ ``` ### IG 1. ``` a = 1 b = 2 c = 3 d = a + c e = b + a f = c + d g = b + 3 h = a + 1 ```