1) Dimostrare che ciascuno dei seguenti insiemi ha la cardinalità di N.

Fondamenti dell’Informatica
a.a. 2004-2005
Esercizi svolti in aula.
La maggior parte degli esercizi sono tratti dal testo:
Kfoury, Moll, Arbib:”A Programming Approach to
Computability”
(gli esercizi del testo riportano la numerazione del testo, gli
altri sono numerati A,B,…)
Notazioni: sia N l’insieme dei numeri naturali. Sia 
l’operazione di prodotto tra naturali e ^ l’operazione di
elevazione a potenza.  denota la composizione di
funzioni, cioè fg(x)=f(g(x)).  denota la sottrazione
tra naturali (nm=se nm allora n-m altrimenti 0).
Sezione 1.1
1)Un’esempio di una sequenza infinita di funzioni
parziali 1, 2,…., i, … tale che i<j per i<j, è il
seguente:
i= - x se xi
-  altrimenti.
A)Dimostrare che ogni numero ha una unica scomposizione
come prodotto di potenze di numeri primi.
Soluzione:
per induzione sul numero n di fattori del prodotto.
Caso base: n=1. Allora il numero dato e’ primo, e
coincide con la sua scomposizione.
Caso induttivo. Per assurdo supponiamo l’assunto non
vero. Allora esiste un numero a, che ha almeno due
scomposizioni, di cui almeno una ha un numero di fattori
n+1. Sia a=p1p2…pn+1=q1q2…qm, dove pi e qj sono primi
(1in+1,1jm. Notare che i fattori possono presentarsi
con ripetizione (esempio: 6=222). Allora a è divisibile
per pn+1; quindi esiste j tale che qj=pn+1. Per ipotesi
induttiva a/pn+1=p1p2…pn ha una scomposizione unica,
quindi ogni pi è identico a un qr, per un dato r.
Ma poiché a= (a/pn+1)pn+1,la nostra supposizione è falsa,
e a ha una unica scomposizione.
1
Sezione 1.3
1) Dimostrare che ciascuno dei seguenti insiemi ha la
cardinalità di N.
1.a)Il prodotto cartesiano NN.
Ricordiamo che (m,n)(p,q) se e solo se np oppure nq.
Sia f: NNN tale che:f((n,m))= 2^n  3^m . f è
iniettiva,per la proprietà della unica scomposizione dei
numeri naturali in fattori primi. Quindi NNN.
Sia g: NNN tale che: g(n)=(0,n). g e’ ovviamente
iniettiva, quindi N NN.
1.b)L’insieme

delle
stringhe
finite
sull’alfabeto
{A,B,…,Z}.
|{A,B,…,Z}|= 21. Quindi possiamo mettere in ordine i
simboli dell’alfabeto (ad esempio in ordine alfabetico) e
interpretarli come cifre in un sistema numerico in base 22.
Definiamo una funzione c che interpreta le lettere
dell’alfabeto nel modo seguente:
c(A)=1,c(B)=2,…, c(Z)=21. Sia b0,…,bn una generica stringa
su  e sia f la funzione tale che f(b0,…,bn)=c(b0)22^0+
c(b1)22^1+…+ c(bn)22^(n). La funzione f è una funzione
iniettiva da  in N, infatti ogni stringa è trasformata da
f in un numero in base 22, scritto senza la cifra 0, e ogni
numero
ha
una
unica
rappresentazione
in
base
22.
L’eliminazione della cifra 0 è necessaria per differenziare
stringhe come, ad esempio, 0 e 00. D’altra parte, sia g:
N la funzione che, dato un numero n, lo trasforma in base
21, sia a0…an,e trasforma a sua volta questo nella stringa
d(a0)…d(an), dove d(0)=A,…,d(20)=Z. d trasforma numeri
diversi in stringhe diverse, e quindi è iniettiva. Si noti
che g non è l’inversa di f!
d)L’insieme Q0 dei numeri razionali compresi tra 0 e 1.
Ogni numero razionale è il rapporto tra due naturali,
quindi un razionale q=num/denum può essere rappresentato
con la coppia di naturali (num,denum). Inoltre 0q1
implica numdenum. Inoltre deve essere denum0.
Si può quindi adattare a questo esercizio la soluzione
dell’esercizio 1.a), definendo:
-f:Q0N tale che:
2
f(n,m)=2^n  3^m
f è iniettiva.
- g: NQ0 tale che:
g(n)=(n,n+1)
g è iniettiva.
Notare che la funzione g: NQ0, definita nell’esercizio
1.a) non può essere usata, perché applicata a 0 restituisce
(0,0) che non codifica un elemento di Q0.
e)L’insieme delle funzioni parziali da N in N con dominio
di definizione finito (sia P(N)).
Dimostriamo prima che l’insieme fin(N) dei sottoinsiemi
finiti di N ha la stessa cardinalità di N.
Sia {n1,…,nmN, e sia h: fin(N)N la funzione tale che
h({n1,…,nm)=2^n1+2^n2+…+2^nm. Poiché, per
definizione di
insieme, ninj quando ij,h è iniettiva e suriettiva, in
quanto ogni naturale ha una unica scomposizione in base 2.
Questo implica che l’insieme dei sottoinsiemi finiti di N
ha la stessa cardinalità di N.
Tornando al problema originale, ogni funzione parziale
unaria con dominio di definizione finito può essere
rappresentata come un insieme finito di coppie di naturali
{(i1,o1),…,(in,on) (dove oj rappresenta il valore della
funzione sull’argomento ij). Allora una funzione iniettiva
da fin(N)in N è hf, e una funzione iniettiva da N in
fin(N)è gh-1 (f e g sono definite nell’esercizio 1.3.1.a)).
2) Dimostrare che i seguenti insiemi sono non numerabili,
cioè hanno cardinalità maggiore di quella di N.
2.b)L’insieme (N)di tutti i sottoinsiemi di N.
La dimostrazione usa il metodo della diagonalizzazione. Per
assurdo, ipotizziamo che (N) e N abbiano la stessa
cardinalità. Quindi deve esistere una iniezione da (N)in N
e una iniezione da N in (N), il che implica (come ha
dimostrato Cantor) l’esistenza di una biiezione tra (N)e N
(sia h). Allora possiamo numerare tutti i sottoinsiemi di
N, e quindi la lista h(0),h(1),…,h(n),… contiene tutti gli
elementi di (N).Possiamo rappresentare (N) mediante la
seguente tabella (infinita):
0
h(0) *
1
*
2
*
3
*
3
h(1) *
h(2) *
h(3) *
*
*
*
*
*
*
dove all’incrocio della colonna i e della riga h(j)
l’elemento * assume valore 1 se ih(j), 0 altrimenti.
Consideriamo ora l’insieme I tale che:
per ogni i in N,iI se e solo se ih(i).
I non può appartenere alla tabella: infatti I differisce da
ogni riga della tabella in almeno un punto (cioè differisce
da ogni h(k) nel punto k, per definizione). Quindi la
tabella non può contenere tutti i sottoinsiemi di N, e
quindi l’ipotesi iniziale è falsa.
Notiamo che la dimostrazione rimane vera anche se ci
limitiamo a considerare i sottoinsiemi di cardinalità
infinita.
2.a)L’insieme delle funzioni totali da N in {0,1}.
Una funzione f totale da N in {0,1} può essere sempre
scritta come insieme di coppie argomento-valore nel modo
seguente:
{(i,*) | i N e *{0,1}}
e questo è un insieme infinito. Possiamo codificare
l’insieme delle coppie (i,*) con una funzione h nel modo
seguente:
- 2i
se *=0
h(i,*)=
- 2i+1
se *=1.
Quindi, tramite la funzione di codifica h, ogni funzione
totale f da N in {0,1} può essere rappresentata con un
insieme infinito di naturali, e conseguentemente numerare
l’insieme di queste funzioni corrisponde a numerare i
sottoinsiemi dei naturali di cardinalità infinita. Ma
questo non è possibile, in quanto è stato dimostrato
nell’esercizio precedente.
2.c)L’insieme delle funzioni parziali da N in N con range
finito.
Una funzione parziale  da N in N può essere rappresentata
da un insieme di coppie di interi, che può essere finito o
infinito, indipendentemente dal fatto che il suo range sia
finito. Ad esempio:
4
- 0 se n è pari
(n)=
-  se n è dispari
è una funzione parziale, tale che RAN()={0}, e l’insieme
di coppie che la rappresenta è: {(n,0)|nN e n pari}.
Poiché ciascuna coppia può essere rappresentata con un
intero, numerare l’insieme delle funzioni parziali con
range finito corrisponde a numerare tutti i sottoinsiemi di
N, ma questo non è’ possibile (esercizio 1.3.2.b)).
Sezione 2.2
3)Scrivere un programma while che computi pred(X), usando
solo
statement
di
assegnazione
della
forma
X:=0
e
X:=succ(X).Il seguente programma restituisce il risultato
come valore della variabile Y.
Begin
T:=0; Y:=0;
while XT then begin
Z:=succ(Y);
while XY do
while XZ do begin
Z:=succ(Z);
Y:=succ(Y)
end
end
end
Sezione 2.3
3.a) Per induzione su numero n di istruzioni del programma
lineare
(per
definizione
di
programma
lineare,
le
istruzioni sono solo assegnazioni).
Caso base:n=0. Ovvio, l’unico programma con 0 istruzioni
e’:
begin end
e termina, per definizione di computazione.
Caso induttivo. Assumiamo, per ipotasi induttiva, che tutti
i programmi con numero di istruzioni minore o uguale a n
terminino. Un programma generico con n+1 assegnaazioni è
della forma:
begin ;Xi:=g(Xj)end
dove  è una sequenza di n istruzioni. Per ogni vettore di
stato (a1,…,ak)la sequenza  termina producendo il vettore
5
(b1,…,bk). Per definizione, l’istruzione Xi:=g(Xj), su
questo vettore di stato, termina restituendo il vettore
(b1,…,bi-1,bj,bi+1,…,bk).
B)Definiamo la seguente macro:
loop X do begin  end
come:
begin Y:=0; while XY do begin ;X:=succ(X)end end
dove Y è una variabile nuova che non occorre in .
I programmi loop, per definizione, sono programmi che non
contengono istruzioni while, ma solo assegnazioni e loop.
Dimostrare che tutti i programmi loop terminano sempre.
Prima definiamo il livello di annidamento dei loop di un
programma P, dove P ha livello di annidamento 0 se non
contiene loop, e livello di annidamento n+1 se contiene
almeno un loop il cui corpo è un programma di livello n.
La dimostrazione del Lemma è per induzione sul livello n di
annidamento del programma.
Caso base:n=0. allora il programma è lineare e termina, per
l’esercizio 2.3.a).
Caso induttivo: assumiamo per ipotesi che un programma di
livello n termini sempre.
Allora il nostro programma P contiene almeno un loop del
tipo:
loop X do begin  end
dove  è programma di livello di annidamento n, quindi
terminante per ipotesi induttiva. Il loop in questione è
equivalente al programma:
begin ,…, end
dove il numero di  è uguale al valore della variabile X.
Allora il loop è equivalente a una sequenza finita di pezzi
terminanti,
e
quindi
termina,
per
definizione
di
computazione. P a sua volta è una sequenza finita di
programmi ciascuno di livello n, e quindi termina anc’esso.
Sezione 3.3
1)Scrivere i programmi while che
head, tail e | (concatenazione).
calcolano
le
funzioni
head:
begin
6
while X12^6 do X1:=div(X1,2^6)
end
tail:
begin
X2:=0; X3:=0;X4:=0;
while X12^6 do begin
X2:=X2+6;
X4:=div(X1,2^6);
X3:=X3+mod(X1,2^6)2^(X2-1);
X1:=X4;
end
X1:=X3;
end
| (le stringhe da concatenare sono in X1 e X2):
begin
X3:=X1;X4:=X2;X5:=6;
while X12^6 do begin
X5:=X5+6;
X3:=div(X3,2^6);
end
X1:=X2+X12^X5;
end
C)Dimostrare che esiste un programma P che effettua un
”interleaving” di due programmi dati Pi e Pj (che calcolano
funzioni unarie) nel modo seguente:
P esegue in parallelo Pi e Pj e restituisce come risultato il
risultato ottenuto dal primo dei due che si ferma.
Questo equivale a dimostrare che la seguente funzione è
calcolabile:
(i,j,k)= - i(k)
se z.step(i,k,z)>step(j,k,z) oppure
z. step(i,k,z)=step(j,k,z)
- j(k) se z.step(j,k,z)> step (i,k,z)
- 
se sia i(k) che j(k)è indefinita.
7
dove step è la funzione definita nell’esempio 4
paragrafo 4.2 (una prima versione nell’esempio 5
paragrafo 4.1) che ha il seguente comportamento:
step(x,y,z)= - 1 se Px sull’input y termina in z passi
- 0 altrimenti.
step è calcolabile.
Il programma cercato e’ il seguente:
del
del
begin X4:=1;
while step(X1,X3,X4)=0 and step(X2,X3,X4)=0
do X4:=succ(X4);
if step(X1,X3,X4)= 1 then (X1,X3) else (X2,X3)
end
8