Skip to content

Commit

Permalink
ct0006-2: Add last lessons notes
Browse files Browse the repository at this point in the history
  • Loading branch information
alek3y committed Feb 29, 2024
1 parent 8016f4a commit fbbbb16
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 112 deletions.
5 changes: 5 additions & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@

- [Basi di dati (M. 2)](./ct0006-2/README.md)
- [Normalizzazione](./ct0006-2/01/README.md)
- [Dipendenze funzionali](./ct0006-2/01/01/README.md)
- [Chiavi](./ct0006-2/01/02/README.md)
- [Forma e copertura canonica](./ct0006-2/01/03/README.md)
- [Decomposizione di schemi](./ct0006-2/01/04/README.md)
- [Forme normali](./ct0006-2/01/05/README.md)

- [Sistemi operativi (M. 1)](./ct0125-1/README.md)
- [Processi](./ct0125-1/01/README.md)
Expand Down
57 changes: 57 additions & 0 deletions src/ct0006-2/01/01/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Dipendenze funzionali

Dato uno schema $R(T, F)$, sono detti **dipendenze funzionali** quei vincoli:
$$
X \rightarrow Y \in F
$$
dove $X \cup Y \subseteq T$, per cui l'unicità di $Y$ dipende da $X$.

Sono anche dette **derivate** se $F$ le **implica logicamente**, cioè:
$$
F \models X \rightarrow Y \Leftrightarrow F \vdash X \rightarrow Y
$$
che accade sse ogni istanza $r$ **soddisfa** $X \rightarrow Y$, ovvero:
$$
\forall t, u \in r,\ t.X = u.X \Rightarrow t.Y = u.Y
$$

## Assiomi

La **derivazione** di altre _dipendenze_ da $F$ avviene sfruttando gli **assiomi di Armstrong**:
- **Riflessività**, $Y \subseteq X \Rightarrow X \rightarrow Y$
- **Aumento**, $X \rightarrow Y \Rightarrow XW \rightarrow YW$
- **Transitività**, $X \rightarrow Y \land Y \rightarrow Z \Rightarrow X \rightarrow Z$

da cui si possono ricavare le **regole derivate** di:
- **Unione**, $X \rightarrow Y \land X \rightarrow Z \Rightarrow X \rightarrow YZ$
- **Decomposizione**, $X \rightarrow YZ \Rightarrow X \rightarrow Y$
- **Indebolimento**, $X \rightarrow Y \Rightarrow XZ \rightarrow Y$

## Chiusura

Si dice **chiusura** di $F$, l'insieme di tutte le dipendenze derivabili da $F$:
$$
F^+ = \Set{X \rightarrow Y | F \vdash X \rightarrow Y}
$$
che però risulta essere algoritmicamente **inefficiente** da trovare.

La **chiusura** di un attributo $X \subseteq T$ invece, è l'insieme degli attributi la cui dipendenza per $X$ è _derivabile_:
$$
X_F^+ = \Set{A \in T | F \vdash X \rightarrow A}
$$
e semplifica la risoluzione del **problema dell'implicazione**, cioè la verifica che $X \rightarrow Y \in F^+$, perchè:
$$
F \vdash X \rightarrow Y\ \Leftrightarrow\ Y \subseteq X_F^+
$$

Trovare la _chiusura_ di $X$ consiste quindi nel cominciare con $X^+ = X$ e aggiungerci iterativamente gli attributi che dipendono da quelli dentro $X^+$.

### Algoritmo

Trovare la _chiusura_ $X_F^+$ di un insieme di attributi $X$ consiste nel:
1. Iniziare con l'insieme $Z = X$
2. Trovare tutte le dipendenze $W \rightarrow Y \in F$ per cui $W \subseteq Z$
3. Aggiungere a $Z$ gli attributi $Y$ delle dipendenze trovate
4. Ripetere finchè $Z$ viene aggiornato

Per esempio, se $X = AB$ e $F = \{A \rightarrow C, AC \rightarrow D, E \rightarrow F\}$ allora $Z_1 = ABC$ e $Z_2 = ABCD$.
30 changes: 30 additions & 0 deletions src/ct0006-2/01/02/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Chiavi

Degli attributi $X$ di $R(T, F)$ si possono definire come:
- **Superchiave** quando $X_F^+ = T$
- **Chiave** quando $X$ è _superchiave_ e $\forall A \in X,\ (X \setminus \{A\})_F^+ \neq T$
- **Attributi primi** se ognuno appartiene ad almeno una _chiave_

### Algoritmo

Dato il **candidato** $X :: (Y)$, la cui $X$ è una **possibile chiave** mentre $Y$ sono i possibili attributi da aggiungere se non lo fosse, si possono trovare **tutte le chiavi** di $R(T, F)$ attraverso:
1. Iniziare con il candidato $Z :: (T \setminus Z)$, dove $Z = T \setminus \Set{Y | X \rightarrow Y \in F}$ sono attributi indipendenti
2. Estrarre il primo candidato $X :: (Y)$ assicurandosi che $X$ non contenga alcuna chiave già trovata
- Se $X$ è _superchiave_ si può aggiungere alle chiavi trovate
- Altrimenti ai candidati si unisce $\Set{XA :: (W \setminus \{A\}) | A \in W}$, dove $W = Y \setminus X_F^+$
3. Ripetere finchè rimangono candidati validi

Serve anche a **verificare la primalità** degli attributi, dato che altrimenti il processo è molto **inefficiente**.

#### Esempio

Per esempio, se $T = ABCDEF$ e $G = \{AB \rightarrow C, E \rightarrow A, A \rightarrow E, B \rightarrow F\}$ i passaggi sono:
1. Il candidato iniziale è $BD :: (ACEF)$
2. $BD$ non è _superchiave_ quindi si aggiungono i candidati dagli attributi $ACEF \setminus BDF$
3. Il primo candidato $BDA :: (CE)$ tra i rimanenti è valido
4. $BDA$ è _superchiave_ quindi anche **chiave**
5. Il primo candidato $BDC :: (E)$ è valido
6. $BDC$ non è _superchiave_ quindi si aggiungono i candidati
7. Il primo candidato $BDE :: ()$ è valido
8. $BDE$ è _superchiave_ quindi anche **chiave**
9. Il rimanente candidato $BDCE$ contiene la chiave $BDE$ quindi non è valido
22 changes: 22 additions & 0 deletions src/ct0006-2/01/03/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Forma e copertura canonica

Le _dipendenze funzionali_ $F$ sono dette **in forma canonica** sse per ogni $X \rightarrow Y \in F$:
- $|Y| = 1$
- $X$ non ha attributi **estranei**, cioè $\nexists A \in X : X \setminus \{A\} \rightarrow Y \in F^+$
- $X \rightarrow Y$ non è **ridondante**, cioè $X \rightarrow Y \not\in (F \setminus \{X \rightarrow Y\})^+$

Se $G$ è in _forma canonica_ e $F \equiv G$, ovvero **equivalgono** per $F^+ = G^+$, allora è detta **copertura canonica**.

### Algoritmo

Trovare la _copertura canonica_ di $F$ consiste nel:
1. Iniziare con l'insieme di dipendenze _decomposte_ $G = \Set{X \rightarrow A | X \rightarrow Y \in F \land A \in Y}$
2. Rimpiazzare da $G$ le $X \rightarrow A$ per cui $|X| > 1$, con $Z \rightarrow A$ dove $Z$ è $X$ meno gli attributi _estranei_, rimuovendo un $B \in X$ alla volta e verificando che comunque $A \in (Z \setminus \{B\})_G^+$
3. Rimuovere le $X \rightarrow A$ _ridondanti_, verificando che $A \in X_{G \setminus \{X \rightarrow A\}}^+$

#### Esempio

Per esempio, se $F = \{A \rightarrow BC, B \rightarrow C, A \rightarrow B, AB \rightarrow C\}$:
1. Decomponendo si ottiene $G = \{A \rightarrow C, B \rightarrow C, A \rightarrow B, AB \rightarrow C\}$
2. Si rimpiazza $AB \rightarrow C$ con $B \rightarrow C$ perchè $C \in B_G^+ = BC$ finendo senza poter rimuovere $B$
3. Si rimuove $A \rightarrow C$ perchè $C \in A_{\{B \rightarrow C, A \rightarrow B\}}^+ = ABC$
95 changes: 95 additions & 0 deletions src/ct0006-2/01/04/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Decomposizione di schemi

Le [anomalie](../README.md) possono essere risolte attraverso la **decomposizione** dello schema in schemi **più piccoli**.

Dato uno schema $R(T, F)$, si definisce come **proiezione** di $F$ su $Z \subseteq T$ l'insieme:
$$
\pi_Z(F) = \Set{X \rightarrow Y \in F^+ | X \cup Y \subseteq Z}
$$
attraverso cui si trova una **decomposizione** di $R(T, F)$, cioè un insieme di schemi
$$
\rho = \{R_1(T_1, F_1), ..., R_n(T_n, F_n)\}
$$
per cui $\bigcup_i T_i = T$ e $F_i = \pi_{T_i}(F)$ filtrando per ogni $R_i$ le dipendenze con attributi coinvolti in $T_i \neq \emptyset$.

Per esempio su $R(ABCDE, \{AB \rightarrow CD, B \rightarrow E\})$ si risolvono le anomalie decomponendolo in:
- $R_1(ABCD, \{AB \rightarrow CD\})$
- $R_2(BE, \{B \rightarrow E\})$

### Algoritmo

Il calcolo della _proiezione_ $\pi_{T_i}(F)$ avviene dal:
1. Iniziare con l'insieme $P = \emptyset$
2. Per ogni $X \subset T_i$ trovare $Y = X_F^+ \setminus X$
3. Aggiungere a $P$ la dipendenza $X \rightarrow (Y \cap T_i)$

#### Esempio

Per esempio su $\pi_{AB}(\{A \rightarrow B, B \rightarrow C, C \rightarrow A\})$, si ha:
1. L'insieme delle proiezioni iniziale è $P = \emptyset$
2. Si trovano le $X \subset AB$ da usare dall'[insieme delle parti](../../../ct0434/02/README.md#insiemi-delle-parti) di $AB$
3. Per $X = A$ si trova $Y = A_F^+ \setminus A = BC$
4. A $P$ si aggiunge $A \rightarrow (BC \cap AB) = A \rightarrow B$
5. Per $X = B$ si trova $Y = B_F^+ \setminus B = AC$
6. A $P$ si aggiunge $B \rightarrow (AC \cap AB) = B \rightarrow A$

## Preservazione dei dati

Per dire che la _decomposizione_ **preservi i dati**, si deve avere che:
$$
r = \pi_{T_1}(r) \bowtie ... \bowtie \pi_{T_n}(r)
$$
per ogni istanza $r$ di $R(T, F)$, assicurandosi che dalle tabelle decomposte si **ricavino gli stessi dati** di $r$.

Per **verificare** che una decomposizione $\rho = \{R_1(T_1, F_1), R_2(T_2, F_2)\}$ _preservi i dati_ basta verificare che
$$
T_1 \cap T_2 \rightarrow T_1 \in F^+ \lor\ T_1 \cap T_2 \rightarrow T_2 \in F^+
$$
trovando la [chiusura](../01/README.md#algoritmo) $(T_1 \cap T_2)_F^+$ e verificando che contenga $T_1$ o $T_2$.

Per esempio, con $R(ABCD, \{A \rightarrow BC\})$ si trova $T_1 = ABC$, $T_2 = AD$ e $A_F^+ = ABC = T_1$.

## Preservazione delle dipendenze

Per dire che la _decomposizione_ **preservi le dipendenze**, si deve avere che:
$$
G = \bigcup_i \pi_{T_i}(F) \equiv F
$$

### Algoritmo

Per **verificare** che le dipendenze siano _preservate_ basta assicurarsi che $Y \subseteq X_G^+$, per ogni $X \rightarrow Y \in F$.

Mentre $X_G^+ = X_{\bigcup_i \pi_{T_i}(F)}^+$ si può ricavare con:
1. Iniziare con l'insieme $Z = X$
2. Trovare tutti gli schemi $R_i(T_i, F_i) \in \rho$
3. Aggiungere a $Z$ gli attributi $(Z \cap T_i)_F^+ \cap T_i$
4. Ripetere finchè $Z$ viene aggiornato

#### Esempio

Per esempio se $F = \{A \rightarrow B, B \rightarrow C, C \rightarrow A\}$ e $\rho = \{R_1(AB), R_2(BC)\}$, si ha:
1. Verifica che $B \subseteq A_G^+$
1. L'insieme iniziale è $Z = A$ e il primo schema è $R_1(AB)$
2. A $Z$ si aggiunge $(Z \cap T_1)_F^+ \cap T_1 = (A \cap AB)_F^+ \cap AB = ABC \cap AB = AB$
3. Il prossimo schema è $R_2(BC)$
4. A $Z$ si aggiunge $(Z \cap T_2)_F^+ \cap T_2 = (AB \cap BC)_F^+ \cap BC = ABC \cap BC = BC$
5. Quindi è verificato perchè $B \subseteq Z = ABC$
2. Verifica che $C \subseteq B_G^+$
1. L'insieme iniziale è $Z = B$ e il primo schema è $R_1(AB)$
2. A $Z$ si aggiunge $B_F^+ \cap AB = AB$
3. Il prossimo schema è $R_2(BC)$
4. A $Z$ si aggiunge $B_F^+ \cap BC = BC$
5. Quindi è verificato perchè $C \subseteq Z = ABC$
3. Verifica che $A \subseteq C_G^+$
1. L'insieme iniziale è $Z = C$ e il primo schema è $R_1(AB)$
2. A $Z$ si aggiunge $\emptyset_F^+ \cap AB = \emptyset$
3. Il prossimo schema è $R_2(BC)$
4. A $Z$ si aggiunge $C_F^+ \cap BC = BC$
5. Il prossimo schema è $R_1(AB)$ di nuovo
6. A $Z$ si aggiunge $B_F^+ \cap AB = AB$
7. Quindi è verificato perchè $A \subseteq Z = ABC$

## Relazione tra dati e dipendenze

Data una _decomposizione_ $p = \{R_1(T_1), ..., R_n(T_n)\}$ di $R(T, F)$ che **preserva le dipendenze** e per cui esiste un $T_i$ _superchiave_ di $R$ allora $p$ si dice che **preserva anche i dati**.
44 changes: 44 additions & 0 deletions src/ct0006-2/01/05/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Forme normali

Le **forme normali** si possono ottenere attraverso il processo di **normalizzazione**, che coinvolge la [decomposizione](../04/README.md), e che garantisce la qualità dello schema risultante.

## Forma normale di Boyce-Codd

Uno schema $R(T, F)$ è in **BCNF** sse per ogni $X \rightarrow Y \in F$ tale che $Y \nsubseteq X$ si ha che $X$ è una _superchiave_.

Questa forma **preserva i dati**, garantisce l'**assenza di anomalie** ma **non preserva le dipendenze**.

### Algoritmo di analisi

La conversione in _BCNF_ consiste nel _decomporre_ **ricorsivamente** lo schema $R(T, F)$:
1. Per il caso base, se $R(T, F)$ è in _BCNF_ restituire $\{R(T, F)\}$
2. Altrimenti trovare una $X \rightarrow Y \in F$ che viola la _BCNF_
3. Calcolare gli attributi $T_1 = X_F^+$ e $T_2 = X \cup (T \setminus T_1)$
4. Calcolare le proiezioni $F_1 = \pi_{T_1}(F)$ e $F_2 = \pi_{T_2}(F)$
5. Trovare la decomposizione _ricorsiva_ $\rho_1$ di $R_1(T_1, F_1)$ e $\rho_2$ di $R_2(T_2, F_2)$
6. Restituire $\rho_1 \cup \rho_2$

#### Esempio

Per esempio con $R(ABC, \{AB \rightarrow C, C \rightarrow A\})$ la conversione sarebbe:
1. La _BCNF_ è violata da $C \rightarrow A$ perchè $C$ non è _superchiave_, infatti $C_F^+ \neq ABC$
2. Si calcolano $T_1 = C_F^+ = AC$ e $T_2 = BC$
3. Si calcolano $F_1 = \{C \rightarrow A\}$ e $F_2 = \emptyset$
4. Si trovano le decomposizioni $\rho_1 = \{R_1(AC, \{C \rightarrow A\})\}$ e $\rho_2 = \{R_2(BC, \emptyset)\}$

## Terza forma normale

Uno schema $R(T, F)$ è detto in **3NF** sse per ogni $X \rightarrow Y \in F$ tale che $Y \nsubseteq X$ si ha che $X$ è una _superchiave_ oppure tutti gli attributi $Y \setminus X$ sono _attributi primi_.

Conviene quindi prima [trovare le chiavi](../02/README.md#algoritmo) di $R$ e poi verificarne la proprietà.

Questa forma **preserva i dati e le dipendenze**, ma può comunque possedere **anomalie**.

### Algoritmo di sintesi

La conversione in _3NF_ consiste nel:
1. Iniziare con la _copertura canonica_ $G$ di $F$
2. Rimpiazzare da $G$ le $X \rightarrow A_1, ..., X \rightarrow A_n$ con una singola $X \rightarrow A_1, ..., A_n$
3. Creare un $R_i(XY)$ per ogni $X \rightarrow Y \in G$
4. Rimuovere gli schemi i cui attributi fanno parte di un altro schema più grande
5. Se nessun $R_i$ ha attributi _superchiave_ per $R$, aggiungere un $R_{n+1}(Z)$, dove $Z$ è una chiave di $R$
112 changes: 0 additions & 112 deletions src/ct0006-2/01/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,115 +12,3 @@ Nella **teoria della normalizzazione** la notazione di base utilizzata è:
Inoltre, durante la modellazione è usata per eliminare le **anomalie** di:
- **Aggiornamento**: è presente **ridondanza** dei dati
- **Inserimento** e **cancellazione**: i dati **non sono conservabili** senza relazionarli con altri dati autonomi

## Dipendenze

Dato uno schema $R(T, F)$, sono detti **dipendenze funzionali** quei vincoli:
$$
X \rightarrow Y \in F
$$
dove $X \cup Y \subseteq T$, per cui l'unicità di $Y$ dipende da $X$.

Sono anche dette **derivate** se $F$ le **implica logicamente**, cioè:
$$
F \models X \rightarrow Y \Leftrightarrow F \vdash X \rightarrow Y
$$
che accade sse ogni istanza $r$ **soddisfa** $X \rightarrow Y$, ovvero:
$$
\forall t, u \in r,\ t.X = u.X \Rightarrow t.Y = u.Y
$$

## Assiomi

La **derivazione** di altre _dipendenze_ da $F$ avviene sfruttando gli **assiomi di Armstrong**:
- **Riflessività**, $Y \subseteq X \Rightarrow X \rightarrow Y$
- **Aumento**, $X \rightarrow Y \Rightarrow XW \rightarrow YW$
- **Transitività**, $X \rightarrow Y \land Y \rightarrow Z \Rightarrow X \rightarrow Z$

da cui si possono ricavare le **regole derivate** di:
- **Unione**, $X \rightarrow Y \land X \rightarrow Z \Rightarrow X \rightarrow YZ$
- **Decomposizione**, $X \rightarrow YZ \Rightarrow X \rightarrow Y$
- **Indebolimento**, $X \rightarrow Y \Rightarrow XZ \rightarrow Y$

## Chiusura

Si dice **chiusura** di $F$, l'insieme di tutte le dipendenze derivabili da $F$:
$$
F^+ = \Set{X \rightarrow Y | F \vdash X \rightarrow Y}
$$
che però risulta essere algoritmicamente **inefficiente** da trovare.

La **chiusura** di un attributo $X \subseteq T$ invece, è l'insieme degli attributi la cui dipendenza per $X$ è _derivabile_:
$$
X_F^+ = \Set{A \in T | F \vdash X \rightarrow A}
$$
e semplifica la risoluzione del **problema dell'implicazione**, cioè la verifica che $X \rightarrow Y \in F^+$, perchè:
$$
F \vdash X \rightarrow Y\ \Leftrightarrow\ Y \subseteq X_F^+
$$

Trovare la _chiusura_ di $X$ consiste quindi nel cominciare con $X^+ = X$ e aggiungerci iterativamente gli attributi che dipendono da quelli dentro $X^+$.

### Algoritmo

Trovare la _chiusura_ $X_F^+$ di un insieme di attributi $X$ consiste nel:
1. Iniziare con l'insieme $Z = X$
2. Trovare tutte le dipendenze $W \rightarrow Y \in F$ per cui $W \subseteq Z$
3. Aggiungere gli attributi $Y$ delle dipendenze trovate a $Z$
4. Ripetere finchè $Z$ viene aggiornato

Per esempio, se $X = AB$ e $F = \{A \rightarrow C, AC \rightarrow D, E \rightarrow F\}$ allora $Z_1 = ABC$ e $Z_2 = ABCD$.

## Chiavi

Degli attributi $X$ di $R(T, F)$ si possono definire come:
- **Superchiave** quando $X_F^+ = T$
- **Chiave** quando $X$ è _superchiave_ e $\forall A \in X,\ (X \setminus \{A\})_F^+ \neq T$
- **Attributi primi** se ognuno appartiene ad almeno una _chiave_

### Algoritmo

Dato il **candidato** $X :: (Y)$, la cui $X$ è una **possibile chiave** mentre $Y$ sono i possibili attributi da aggiungere se non lo fosse, si possono trovare **tutte le chiavi** di $R(T, F)$ attraverso:
1. Iniziare con il candidato $Z :: (T \setminus Z)$, dove $Z = T \setminus \Set{Y | X \rightarrow Y \in F}$ sono attributi indipendenti
2. Estrarre il primo candidato $X :: (Y)$ assicurandosi che $X$ non contenga alcuna chiave già trovata
- Se $X$ è _superchiave_ si può aggiungere alle chiavi trovate
- Altrimenti ai candidati si unisce $\Set{XA :: (W \setminus \{A\}) | A \in W}$, dove $W = Y \setminus X_F^+$
3. Ripetere finchè rimangono candidati validi

Serve anche a **verificare la primalità** degli attributi, dato che altrimenti il processo è molto **inefficiente**.

#### Esempio

Per esempio, se $T = ABCDEF$ e $G = \{AB \rightarrow C, E \rightarrow A, A \rightarrow E, B \rightarrow F\}$ i passaggi sono:
1. Il candidato iniziale è $BD :: (ACEF)$
2. $BD$ non è _superchiave_ quindi si aggiungono i candidati dagli attributi $ACEF \setminus BDF$
3. Il primo candidato $BDA :: (CE)$ tra i rimanenti è valido
4. $BDA$ è _superchiave_ quindi anche **chiave**
5. Il primo candidato $BDC :: (E)$ è valido
6. $BDC$ non è _superchiave_ quindi si aggiungono i candidati
7. Il primo candidato $BDE :: ()$ è valido
8. $BDE$ è _superchiave_ quindi anche **chiave**
9. Il rimanente candidato $BDCE$ contiene la chiave $BDE$ quindi non è valido

## Forma e copertura canonica

Le _dipendenze funzionali_ $F$ sono dette **in forma canonica** sse per ogni $X \rightarrow Y \in F$:
- $|Y| = 1$
- $X$ non ha attributi **estranei**, cioè $\nexists A \in X : X \setminus \{A\} \rightarrow Y \in F^+$
- $X \rightarrow Y$ non è **ridondante**, cioè $X \rightarrow Y \not\in (F \setminus \{X \rightarrow Y\})^+$

Se $G$ è in _forma canonica_ e $F \equiv G$, ovvero **equivalgono** per $F^+ = G^+$, allora è detta **copertura canonica**.

### Algoritmo

Trovare la _copertura canonica_ di $F$ consiste nel:
1. Iniziare con l'insieme di dipendenze _decomposte_ $G = \Set{X \rightarrow A | X \rightarrow Y \in F \land A \in Y}$
2. Rimpiazzare da $G$ le $X \rightarrow A$ per cui $|X| > 1$, con $Z \rightarrow A$ dove $Z$ è $X$ meno gli attributi _estranei_, rimuovendo un $B \in X$ alla volta e verificando che comunque $A \in (Z \setminus \{B\})_G^+$
3. Rimuovere le $X \rightarrow A$ _ridondanti_, verificando che $A \in X_{G \setminus \{X \rightarrow A\}}^+$

#### Esempio

Per esempio, se $F = \{A \rightarrow BC, B \rightarrow C, A \rightarrow B, AB \rightarrow C\}$:
1. Decomponendo si ottiene $G = \{A \rightarrow C, B \rightarrow C, A \rightarrow B, AB \rightarrow C\}$
2. Si rimpiazza $AB \rightarrow C$ con $B \rightarrow C$ perchè $C \in B_G^+ = BC$ finendo senza poter rimuovere $B$
3. Si rimuove $A \rightarrow C$ perchè $C \in A_{\{B \rightarrow C, A \rightarrow B\}}^+ = ABC$

0 comments on commit fbbbb16

Please sign in to comment.