Open In Colab

14. Insiemi#

Un insieme (o collezione, classe, gruppo, …) è stato definito da Georg Cantor nel modo seguente: un insieme è una collezione di oggetti, determinati e distinti, della nostra percezione o del nostro pensiero, concepiti come un tutto unico; tali oggetti si dicono elementi dell’insieme.

Mentre non è rilevante la natura degli oggetti che costituiscono l’insieme, ciò che importa è distinguere se un dato oggetto appartenga o meno ad un insieme. Deve essere vera una delle due possibilità: il dato oggetto è un elemento dell’insieme considerato oppure non è elemento dell’insieme considerato. Due insiemi \(A\) e \(B\) si dicono uguali se sono formati dagli stessi elementi, anche se disposti in ordine diverso: \(A=B\). Due insiemi \(A\) e \(B\) si dicono diversi se non contengono gli stessi elementi: \(A \neq B\). Ad esempio, i seguenti insiemi sono uguali:

\[ \{1, 2, 3\} = \{3, 1, 2\} = \{1, 3, 2\}= \{1, 1, 1, 2, 3, 3, 3\}. \]

Gli insiemi sono denotati da una lettera maiuscola, mentre le lettere minuscole, di solito, designano gli elementi di un insieme. Per esempio, un generico insieme \(A\) si indica con

\[ A = \{a_1, a_2, \dots, a_n\}, \quad \text{con } n > 0. \]

La scrittura \(a \in A\) dice che \(a\) è un elemento di \(A\). Per dire che \(b\) non è un elemento di \(A\) si scrive \(b \notin A.\)

Per quegli insiemi i cui elementi soddisfano una certa proprietà che li caratterizza, tale proprietà può essere usata per descrivere più sinteticamente l’insieme:

\[ A = \{x ~\vert~ \text{proprietà posseduta da } x\}, \]

che si legge come “\(A\) è l’insieme degli elementi \(x\) per cui è vera la proprietà indicata.” Per esempio, per indicare l’insieme \(A\) delle coppie di numeri reali \((x,y)\) che appartengono alla parabola \(y = x^2 + 1\) si può scrivere:

\[ A = \{(x,y) ~\vert~ y = x^2 + 1\}. \]

Dati due insiemi \(A\) e \(B\), diremo che \(A\) è un sottoinsieme di \(B\) se e solo se tutti gli elementi di \(A\) sono anche elementi di \(B\):

\[ A \subseteq B \iff (\forall x \in A \Rightarrow x \in B). \]

Se esiste almeno un elemento di \(B\) che non appartiene ad \(A\) allora diremo che \(A\) è un sottoinsieme proprio di \(B\):

\[ A \subset B \iff (A \subseteq B, \exists~ x \in B ~\vert~ x \notin A). \]

Un altro insieme, detto insieme delle parti, o insieme potenza, che si associa all’insieme \(A\) è l’insieme di tutti i sottoinsiemi di \(A\), inclusi l’insieme vuoto e \(A\) stesso. Per esempio, per l’insieme \(A = \{a, b, c\}\), l’insieme delle parti è:

\[ \mathcal{P}(A) = \{ \emptyset, \{a\}, \{b\}, \{c\}, \{a, b\}, \{a, c\}, \{c, b\}, \{a, b, c\} \}. \]

14.1. Diagrammi di Eulero-Venn#

I diagrammi di Venn sono uno strumento grafico molto utile per rappresentare gli insiemi e per verificare le proprietà delle operazioni tra di essi. Questi diagrammi prendono il nome dal matematico inglese del 19° secolo John Venn, anche se rappresentazioni simili erano già state utilizzate in precedenza da Leibniz e Eulero.

I diagrammi di Venn rappresentano gli insiemi come regioni del piano delimitate da una curva chiusa. Nel caso di insiemi finiti, è possibile evidenziare alcuni elementi di un insieme tramite punti, e in alcuni casi possono essere evidenziati tutti gli elementi degli insiemi considerati.

In sostanza, questi diagrammi sono un modo visuale per rappresentare le proprietà degli insiemi e delle operazioni tra di essi. Sono uno strumento molto utile per visualizzare la relazione tra gli insiemi e per capire meglio come si combinano gli elementi all’interno di essi.

14.2. Appartenenza ad un insieme#

Usiamo ora Python.

Set1 = {1, 2}
print(Set1)
print(type(Set1))
{1, 2}
<class 'set'>
my_list = [1, 2, 3, 4]
my_set_from_list = set(my_list)
print(my_set_from_list)
{1, 2, 3, 4}

L’appartenenza ad un insieme si verifica con in e not in.

my_set = set([1, 3, 5])
print("Ecco il mio insieme:", my_set)
print("1 appartiene all'insieme:", 1 in my_set)
print("2 non appartiene all'insieme:", 2 in my_set)
print("4 NON appartiene all'insieme:", 4 not in my_set)
Ecco il mio insieme: {1, 3, 5}
1 appartiene all'insieme: True
2 non appartiene all'insieme: False
4 NON appartiene all'insieme: True

14.3. Relazioni tra insiemi#

Esaminiamo le funzioni Python per descrivere le relazioni tra insiemi. In particolare, dopo avere definito l’insieme universo e l’insieme vuoto, considereremo la relazione di inclusione che conduce al concetto di sottoinsieme. Analogamente si definisce il concetto di sovrainsieme. Mostreremo anche come valutare se due insiemi sono disgiunti (si dicono disgiunti gli insiemi con intersezione vuota).

Univ = set([x for x in range(11)])
Super = set([x for x in range(11) if x % 2 == 0])
Disj = set([x for x in range(11) if x % 2 == 1])
Sub = set([4, 6])
Null = set([x for x in range(11) if x > 10])
print("Insieme Universo (tutti gli interi positivi fino a 10):", Univ)
print("Tutti gli interi positivi pari fino a 10:", Super)
print("Tutti gli interi positivi dispari fino a 10:", Disj)
print("Insieme di due elementi, 4 e 6:", Sub)
print("Un isieme vuoto:", Null)
Insieme Universo (tutti gli interi positivi fino a 10): {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Tutti gli interi positivi pari fino a 10: {0, 2, 4, 6, 8, 10}
Tutti gli interi positivi dispari fino a 10: {1, 3, 5, 7, 9}
Insieme di due elementi, 4 e 6: {4, 6}
Un isieme vuoto: set()
print('È "Super" un sovrainsieme di "Sub"?', Super.issuperset(Sub))
print('È "Super" un sottoinsieme di "Univ"?', Super.issubset(Univ))
print('È "Sub" un sovrainsieme di "Super"?', Sub.issuperset(Super))
print('Sono "Super" e "Disj" insiemi disgiunti?', Sub.isdisjoint(Disj))
È "Super" un sovrainsieme di "Sub"? True
È "Super" un sottoinsieme di "Univ"? True
È "Sub" un sovrainsieme di "Super"? False
Sono "Super" e "Disj" insiemi disgiunti? True

14.4. Operazioni tra insiemi#

Si definisce intersezione di \(A\) e \(B\) l’insieme \(A \cap B\) di tutti gli elementi \(x\) che appartengono ad \(A\) e contemporaneamente a \(B\):

\[ A \cap B = \{x ~\vert~ x \in A \land x \in B\}. \]

Si definisce unione di \(A\) e \(B\) l’insieme \(A \cup B\) di tutti gli elementi \(x\) che appartengono ad \(A\) o a \(B\), cioè

\[ A \cup B = \{x ~\vert~ x \in A \lor x \in B\}. \]

Differenza. Si indica con \(A \setminus B\) l’insieme degli elementi di \(A\) che non appartengono a \(B\):

\[ A \setminus B = \{x ~\vert~ x \in A \land x \notin B\}. \]

Insieme complementare. Nel caso che sia \(B \subseteq A\), l’insieme differenza \(A \setminus B\) è detto insieme complementare di \(B\) in \(A\) e si indica con \(B^C\).

Dato un insieme \(S\), una partizione di \(S\) è una collezione di sottoinsiemi di \(S\), \(S_1, \dots, S_k\), tali che

\[ S = S_1 \cup S_2 \cup \dots S_k \]

e

\[ S_i \cap S_j, \quad \text{con } i \neq j. \]

La relazione tra unione, intersezione e insieme complementare è data dalle leggi di DeMorgan:

\[ (A \cup B)^c = A^c \cap B^c, \]
\[ (A \cap B)^c = A^c \cup B^c. \]

In tutte le seguenti figure, \(S\) è la regione delimitata dal rettangolo, \(L\) è la regione all’interno del cerchio di sinistra e \(R\) è la regione all’interno del cerchio di destra. La regione evidenziata mostra l’insieme indicato sotto ciascuna figura.

Diagrammi di Venn

I diagrammi di Eulero-Venn che illustrano le leggi di DeMorgan sono forniti nella figura seguente.

Leggi di DeMorgan

Vediamo ora come si eseguono le operazioni tra insiemi con Python.

Eguaglianza e differenza.

S1 = {1, 2}
S2 = {2, 2, 1, 1, 2}
print(
    "S1 e S2 sono uguali perché l'ordine o la ripetizione di elementi non importano per gli insiemi\nS1==S2:",
    S1 == S2,
)
S1 e S2 sono uguali perché l'ordine o la ripetizione di elementi non importano per gli insiemi
S1==S2: True
S1 = {1, 2, 3, 4, 5, 6}
S2 = {1, 2, 3, 4, 0, 6}
print(
    "S1 e S2 NON sono uguali perché si differenziano per almeno uno dei loro elementi\nS1==S2:",
    S1 == S2,
)
S1 e S2 NON sono uguali perché si differenziano per almeno uno dei loro elementi
S1==S2: False

Intersezione. Si noti che il connettivo logico & corrisponde all’intersezione.

S1 = set([x for x in range(1, 11) if x % 3 == 0])
print("S1:", S1)
S1: {9, 3, 6}
S2 = set([x for x in range(1, 7)])
print("S2:", S2)
S2: {1, 2, 3, 4, 5, 6}
S_intersection = S1.intersection(S2)
print("Intersezione di S1 e S2:", S_intersection)

S_intersection = S1 & S2
print("Intersezione di S1 e S2:", S_intersection)
Intersezione di S1 e S2: {3, 6}
Intersezione di S1 e S2: {3, 6}
S3 = set([x for x in range(6, 10)])
print("S3:", S3)
S1_S2_S3 = S1.intersection(S2).intersection(S3)
print("Intersection of S1, S2, and S3:", S1_S2_S3)
S3: {8, 9, 6, 7}
Intersection of S1, S2, and S3: {6}

Unione. Si noti che il connettivo logico | corrisponde all’unione.

S1 = set([x for x in range(1, 11) if x % 3 == 0])
print("S1:", S1)
S2 = set([x for x in range(1, 5)])
print("S2:", S2)

S_union = S1.union(S2)
print("Unione di S1 e S2:", S_union)
S_union = S1 | S2
print("Unione di S1 e S2:", S_union)
S1: {9, 3, 6}
S2: {1, 2, 3, 4}
Unione di S1 e S2: {1, 2, 3, 4, 6, 9}
Unione di S1 e S2: {1, 2, 3, 4, 6, 9}

Insieme complementare.

S = set([x for x in range(21) if x % 2 == 0])
print("S è l'insieme dei numeri interi pari tra 0 e 20:", S)
S è l'insieme dei numeri interi pari tra 0 e 20: {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
S_complement = set([x for x in range(21) if x % 2 != 0])
print("S_complement è l'insieme dei numeri interi dispari tra 0 e 20:", S_complement)
S_complement è l'insieme dei numeri interi dispari tra 0 e 20: {1, 3, 5, 7, 9, 11, 13, 15, 17, 19}
print(
    "È l'unione di S e S_complement uguale a tutti i numeri interi tra 0 e 20?",
    S.union(S_complement) == set([x for x in range(21)]),
)
È l'unione di S e S_complement uguale a tutti i numeri interi tra 0 e 20? True

Differenza tra insiemi.

S1 = set([x for x in range(31) if x % 3 == 0])
print("Set S1:", S1)
Set S1: {0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30}
S2 = set([x for x in range(31) if x % 5 == 0])
print("Set S2:", S2)
Set S2: {0, 5, 10, 15, 20, 25, 30}
S_difference = S2 - S1
print("Differenza tra S2 e S1, i.e. S2\S1:", S_difference)

S_difference = S1.difference(S2)
print("Differenza tra S1 e S2, i.e. S1\S2:", S_difference)
Differenza tra S2 e S1, i.e. S2\S1: {25, 10, 20, 5}
Differenza tra S1 e S2, i.e. S1\S2: {3, 6, 9, 12, 18, 21, 24, 27}

Differenza simmetrica. La differenza simmetrica, indicata con il simbolo Δ, è un’operazione insiemistica definita come unione tra la differenza tra il primo e il secondo insieme e la differenza tra il secondo e il primo insieme. In modo equivalente, la differenza simmetrica equivale all’unione tra i due insiemi meno la loro intersezione.

print("S1", S1)
print("S2", S2)
print("Differenza simmetrica", S1 ^ S2)
print("Differenza simmetrica", S2.symmetric_difference(S1))
S1 {0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30}
S2 {0, 5, 10, 15, 20, 25, 30}
Differenza simmetrica {3, 5, 6, 9, 10, 12, 18, 20, 21, 24, 25, 27}
Differenza simmetrica {3, 5, 6, 9, 10, 12, 18, 20, 21, 24, 25, 27}

14.5. Coppie ordinate e prodotto cartesiano#

Una coppia ordinata \((x,y)\) è l’insieme i cui elementi sono \(x \in A\) e \(y \in B\) e nella quale \(x\) è la prima componente (o prima coordinata) e \(y\) la seconda. L’insieme di tutte le coppie ordinate costruite a partire dagli insiemi \(A\) e \(B\) viene detto prodotto cartesiano:

\[ A \times B = \{(x, y) ~\vert~ x \in A \land y \in B\}. \]

Ad esempio, sia \(A = \{1, 2, 3\}\) e \(B = \{a, b\}\). Allora,

\[ \{1, 2\} \times \{a, b, c\} = \{(1, a), (1, b), (1, c), (2, a), (2, b), (2, c)\}. \]

Più in generale, un prodotto cartesiano di \(n\) insiemi può essere rappresentato da un array di \(n\) dimensioni, dove ogni elemento è una ennupla o tupla ordinata (ovvero, una collezione o un elenco ordinato di \(n\) oggetti). Una n-pla ordinata si distingue da un insieme di \(n\) elementi in quanto fra gli elementi di un insieme non è dato alcun ordine. Inoltre gli elementi di una ennupla possono anche essere ripetuti. Essendo la n-pla un elenco ordinato, in generale di ogni suo elemento è possibile dire se sia il primo, il secondo, il terzo, eccetera, fino all’n-esimo. Il prodotto cartesiano prende il nome da René Descartes la cui formulazione della geometria analitica ha dato origine al concetto.

A = set(["a", "b", "c"])
S = {1, 2, 3}
def cartesian_product(S1, S2):
    result = set()
    for i in S1:
        for j in S2:
            result.add(tuple([i, j]))
    return result
C = cartesian_product(A, S)
print(f"Prodotto cartesiano di A e S\n{A} x {S} = {C}")
Prodotto cartesiano di A e S
{'b', 'a', 'c'} x {1, 2, 3} = {('c', 2), ('a', 3), ('b', 3), ('c', 1), ('a', 2), ('b', 2), ('c', 3), ('a', 1), ('b', 1)}

Si definisce cardinalità (o potenza) di un insieme finito il numero degli elementi dell’insieme. Viene indicata con \(\vert A\vert, \#(A)\) o \(\text{c}(A)\).

print("La cardinalità dell'insieme prodotto cartesiano è:", len(C))
La cardinalità dell'insieme prodotto cartesiano è: 9

Invece di scrivere funzioni noi stessi, è possibile usare la libreria itertools di Python. Si ricordi di trasformare l’oggetto risultante in una lista per la visualizzazione e la successiva elaborazione.

from itertools import product as prod
A = set([x for x in range(1, 7)])
B = set([x for x in range(1, 7)])
p = list(prod(A, B))

print("A è l'insieme di tutti i possibili lanci di un dado:", A)
print("B è l'insieme di tutti i possibili lanci di un dado:", B)
print(
    "\nIl prodotto di A e B è l'insieme dei risultati che si possono ottenere lanciando due dadi:\n",
    p,
)
A è l'insieme di tutti i possibili lanci di un dado: {1, 2, 3, 4, 5, 6}
B è l'insieme di tutti i possibili lanci di un dado: {1, 2, 3, 4, 5, 6}

Il prodotto di A e B è l'insieme dei risultati che si possono ottenere lanciando due dadi:
 [(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6)]

La cardinalità (cioè il numero di elementi) del prodotto cartesiano tra due o più insiemi è uguale al prodotto delle cardinalità degli insiemi considerati: card(A × B) = card(A) · card(B).

Usando itertools è facile calcolare la cardinalità del prodotto cartesiano di un insieme per se stesso. Consideriamo il quadrato dell’insieme costituito dai risultati del lancio di una moneta. L’insieme risultante avrà cardinalità \(2 \cdot 2 = 4\).

A = {"Head", "Tail"} 
p2 = list(prod(A, repeat=2))  
print(f"Il quadrato dell'insieme A è un insieme che contiene {len(p2)} elementi: {p2}")
Il quadrato dell'insieme A è un insieme che contiene 4 elementi: [('Head', 'Head'), ('Head', 'Tail'), ('Tail', 'Head'), ('Tail', 'Tail')]

L’insieme \(A\) elevato alla terza potenza produce un insieme la cui cardinalità è

p3 = list(prod(A, repeat=3))  
print(f"L'insieme A elevato alla terza potenza è costituito da {len(p3)} elementi: {p3}")
L'insieme A elevato alla terza potenza è costituito da 8 elementi: [('Head', 'Head', 'Head'), ('Head', 'Head', 'Tail'), ('Head', 'Tail', 'Head'), ('Head', 'Tail', 'Tail'), ('Tail', 'Head', 'Head'), ('Tail', 'Head', 'Tail'), ('Tail', 'Tail', 'Head'), ('Tail', 'Tail', 'Tail')]

14.6. Watermark#

%load_ext watermark
%watermark -n -u -v -iv -w
Last updated: Sat Jun 17 2023

Python implementation: CPython
Python version       : 3.11.3
IPython version      : 8.12.0

Watermark: 2.3.1