Salta al contenuto
Note per Studenti Dimostrazioni, induzione e invarianti

Dimostrazioni, induzione e invarianti

In questa pagina 4

Servono per le analisi di complessità e di correttezza (l'algoritmo termina e risolve il problema computazionale, vedi Problemi computazionali e algoritmiProblema computazionale come insieme di coppie (istanza, soluzione); algoritmo e modello di calcolo RAM; pseudocodice; taglia di un'istanza; ADT e struttura dati concreta; esempio svolto con ricerca lineare e binaria in un array ordinato.Problemi computazionali e algoritmi →).

Esempio, controesempio, assurdo

Induzione

Per provare che Q(n)Q(n) vale per ogni n≥n0n \ge n_0:

  1. si sceglie k≥0k \ge 0 (di solito k=0k = 0);
  2. base: si dimostra Q(n0),Q(n0+1),…,Q(n0+k)Q(n_0), Q(n_0+1), \dots, Q(n_0+k);
  3. passo: si fissa n≥n0+kn \ge n_0 + k arbitrario e, assumendo Q(m)Q(m) vera per ogni mm con n0≤m≤nn_0 \le m \le n (ipotesi induttiva), si dimostra Q(n+1)Q(n+1).

Il passo deve valere per ogni n≥n0+kn \ge n_0 + k. Servono più casi base quando il passo usa più valori precedenti (Fibonacci usa i due precedenti: k=1k = 1).

Esempio 1. ∑i=0ni=n(n+1)2\sum_{i=0}^{n} i = \frac{n(n+1)}{2} per n≥0n \ge 0. Base n=0n = 0: 0=00 = 0. Passo: ∑i=0n+1i=n(n+1)2+(n+1)=(n+1)(n+2)2\sum_{i=0}^{n+1} i = \frac{n(n+1)}{2} + (n+1) = \frac{(n+1)(n+2)}{2}. ✓

Esempio 2 (Fibonacci). F(0)=0F(0) = 0, F(1)=1F(1) = 1, F(n+1)=F(n)+F(n−1)F(n+1) = F(n) + F(n-1). Si prova F(n)=15(Φn−Φ^n)F(n) = \frac{1}{\sqrt 5}(\Phi^n - \hat\Phi^n) con Φ=1+52\Phi = \frac{1+\sqrt5}{2}, Φ^=1−52\hat\Phi = \frac{1-\sqrt5}{2}. Base: n=0,1n = 0, 1 (verifica diretta). Passo (n≥1n \ge 1): F(n+1)=F(n)+F(n−1)=15[(Φn+Φn−1)−(Φ^n+Φ^n−1)]F(n+1) = F(n) + F(n-1) = \frac{1}{\sqrt5}\big[(\Phi^n + \Phi^{n-1}) - (\hat\Phi^n + \hat\Phi^{n-1})\big]. Si osserva Φn+Φn−1=Φn−1(Φ+1)=Φn−1Φ2=Φn+1\Phi^n + \Phi^{n-1} = \Phi^{n-1}(\Phi + 1) = \Phi^{n-1}\Phi^2 = \Phi^{n+1}, perché Φ+1=3+52=Φ2\Phi + 1 = \frac{3+\sqrt5}{2} = \Phi^2; allo stesso modo per Φ^\hat\Phi. Quindi F(n+1)=15(Φn+1−Φ^n+1)F(n+1) = \frac{1}{\sqrt5}(\Phi^{n+1} - \hat\Phi^{n+1}). ✓ (Verificato numericamente: 0,1,1,2,3,5,8,13,21,340, 1, 1, 2, 3, 5, 8, 13, 21, 34.)

Esempio 3. Q(n)Q(n): ∑i=0ni2=n(n+1)(2n+1)6∈Θ(n3)\sum_{i=0}^{n} i^2 = \frac{n(n+1)(2n+1)}{6} \in \Theta(n^3). Passo: n(n+1)(2n+1)6+(n+1)2=(n+1) [ n(2n+1)+6(n+1) ]6=(n+1)(2n2+7n+6)6=(n+1)(n+2)(2n+3)6\frac{n(n+1)(2n+1)}{6} + (n+1)^2 = \frac{(n+1)\,[\,n(2n+1) + 6(n+1)\,]}{6} = \frac{(n+1)(2n^2 + 7n + 6)}{6} = \frac{(n+1)(n+2)(2n+3)}{6}. ✓

Correttezza di un algoritmo

Schema generale: si individuano lo stato iniziale e quello finale desiderato, si scompone l'algoritmo in segmenti con uno stato atteso a fine segmento (checkpoint) e si prova che dallo stato iniziale si raggiungono in successione tutti i checkpoint; l'ultimo deve implicare lo stato finale. I segmenti notevoli sono i cicli. La terminazione si prova assicurandosi che cicli e ricorsione abbiano fine.

Invarianti di ciclo

Un invarianteProprietà sulle variabili del ciclo che descrive lo stato a ogni iterazione. è una proprietà delle variabili usate nel ciclo che:

  1. vale all'inizio del ciclo, come conseguenza dello stato iniziale (inizializzazione);
  2. vale alla fine di ogni iterazione, assumendo che valesse all'inizio di quella iterazione (conservazione);
  3. alla fine dell'ultima iterazione, insieme alla condizione di uscita, implica la correttezza del ciclo (uso).

Un ciclo esegue ≥0\ge 0 iterazioni del corpo; for i <- 1 to n ne fa sempre nn.

arrayMax. currMax <- A[0]; for i <- 1 to n-1 do currMax <- max(currMax, A[i]). Invariante: alla fine dell'iterazione ii, currMax=max⁡{A[0],…,A[i]}currMax = \max\{A[0], \dots, A[i]\}. All'inizio (ii prima del ciclo) currMax=A[0]currMax = A[0] = massimo di A[0..0]A[0..0]. Conservazione: il massimo di A[0..i]A[0..i] è il massimo tra il massimo di A[0..i−1]A[0..i-1] e A[i]A[i]. Alla fine (i=n−1i = n-1) currMaxcurrMax è il massimo di tutto l'array.

Il più lungo segmento di 1 in una sequenza di bit S[1..n]S[1..n]:

max <- 0; curr <- 0
for i <- 1 to n do
    if S[i] = 1 then
        curr <- curr + 1
        if curr > max then max <- curr
    else curr <- 0
return max

Invariante alla fine dell'iterazione ii: (a) currcurr è la lunghezza del segmento di 1 che termina in S[i]S[i] (zero se S[i]=0S[i] = 0) e (b) maxmax è la lunghezza massima di un segmento di 1 in S[1..i]S[1..i]. Inizio (i=0i = 0): sequenza vuota, entrambi 00. Conservazione: se S[i]=1S[i] = 1 il segmento che termina in ii estende quello che terminava in i−1i-1, quindi currcurr cresce di 1 e maxmax viene aggiornato se lo supera; se S[i]=0S[i] = 0 il segmento si interrompe e curr=0curr = 0, mentre maxmax non cambia. Fine: per i=ni = n la (b) dà la risposta. (Controllato con un test casuale su sequenze di lunghezza ≤15\le 15.)

Cicli con due indici (esempio d'esame): in while (i < n) AND (j < m) su una matrice con colonne decrescenti, l'invariante lega il valore corrente a ii e jj; si veda l'esercizio Esercizio 3 · invariante su matrice a colonne decrescenti.

Errori comuni

  • Un invariante che vale solo alla fine (non è un invariante): deve valere anche all'inizio e dopo ogni iterazione.
  • Un invariante troppo debole: non basta a concludere la correttezza all'uscita (es. "currMax∈AcurrMax \in A" non dice che sia il massimo).
  • Nell'induzione: provare il passo solo per un nn specifico, o dimenticare uno dei casi base quando il passo usa due valori precedenti.
  • Confondere ipotesi induttiva e tesi: nel passo si assume Q(m)Q(m) per m≤nm \le n e si prova Q(n+1)Q(n+1).

Versione ripasso

  • Tecniche: esempio (per un Ω\Omega: basta un' istanza cattiva), controesempio, assurdo (nego la tesi e trovo una contraddizione).
  • Induzione su n≥n0n \ge n_0: base Q(n0..n0+k)Q(n_0..n_0+k); passo: ipotesi Q(m)Q(m) per n0≤m≤nn_0 \le m \le n, tesi Q(n+1)Q(n+1), per ogni n≥n0+kn \ge n_0+k. Fibonacci: k=1k=1, F(n)=15(Φn−Φ^n)F(n) = \tfrac{1}{\sqrt5}(\Phi^n - \hat\Phi^n), passo con Φ+1=Φ2\Phi + 1 = \Phi^2. Gauss: ∑i=n(n+1)2\sum i = \tfrac{n(n+1)}{2}; ∑i2=n(n+1)(2n+1)6\sum i^2 = \tfrac{n(n+1)(2n+1)}{6}.
  • Correttezza: stato iniziale →\to checkpoint →\to stato finale; cicli e ricorsione devono terminare (vedi Problemi computazionali e algoritmiProblema computazionale come insieme di coppie (istanza, soluzione); algoritmo e modello di calcolo RAM; pseudocodice; taglia di un'istanza; ADT e struttura dati concreta; esempio svolto con ricerca lineare e binaria in un array ordinato.Problemi computazionali e algoritmi →).
  • Invariante di ciclo: (1) vale prima del ciclo; (2) se vale prima di un'iterazione, vale dopo; (3) a fine ciclo implica la tesi. arrayMax: dopo l'iterazione ii, currMax=max⁡A[0..i]currMax = \max A[0..i]. Segmento di 1: currcurr = lunghezza del segmento che termina in ii, maxmax = massima lunghezza in S[1..i]S[1..i].
  • Schema per i cicli: (1) inizializzazione: l'invariante vale prima della prima iterazione; (2) conservazione: se vale all'inizio di un'iterazione, vale alla fine; (3) uso: alla fine, con la condizione di uscita, implica la tesi. for i <- 1 to n fa sempre nn iterazioni.
  • Esempi di invariante: arrayMax: dopo l'iterazione ii, currMax=max⁡A[0..i]currMax = \max A[0..i]; segmento di 1: currcurr = segmento che termina in ii, maxmax = massimo in S[1..i]S[1..i].
  • Induzione di Gauss: ∑i=0n+1i=n(n+1)2+(n+1)=(n+1)(n+2)2\sum_{i=0}^{n+1} i = \frac{n(n+1)}{2} + (n+1) = \frac{(n+1)(n+2)}{2}.
  • Errori: invariante vero solo a fine ciclo o troppo debole; passo induttivo non per ogni nn; casi base mancanti; confondere ipotesi e tesi.

Esercizi su questo argomento

Teoria collegata