contiene il valore e nel range [l, u]. Funziona correttamente solo se 0 l e u a.

Documenti analoghi
Verifica dei programmi

Logica per la Programmazione

Logica per la Programmazione

Logica per la Programmazione

Logica per la Programmazione

Logica per la Programmazione

Logica per la Programmazione

TRIPLE DI HOARE: ESEMPI ED ESERCIZI. Corso di Logica per la Programmazione A.A. 2012/13

Linguaggi di programmazione: sintassi e semantica Sintassi fornita con strumenti formali: Semantica spesso data in modo informale

Verifica di programmi

Specifica, progetto e verifica della correttezza di algoritmi iterativi

INTRODUZIONE ALLA LOGICA DI HOARE. Corso di Logica per la Programmazione

Logica per la Programmazione

Logica per la Programmazione

Logica per la Programmazione

INTRODUZIONE ALLA LOGICA DI HOARE. Corso di Logica per la Programmazione A.A. 2013/14

Un algoritmo realizza una relazione funzionale tra i valori di input e quelli di output

Dati e Algoritmi I (Pietracaprina) Esercizi sulle Nozioni di Base

Verifica dei programmi

ESEMPI DI TRIPLE DI HOARE. Corso di Logica per la Programmazione A.A. 2010/11 Andrea Corradini, Paolo Mancarella

ESEMPI DI TRIPLE DI HOARE. Corso di Logica per la Programmazione A.A. 2010/11 Andrea Corradini, Paolo Mancarella

LA LOGICA DI HOARE. Corso di Logica per la Programmazione A.A. 2010/11 Andrea Corradini, Paolo Mancarella

Calcolare x n = x x x (n volte)

LOGICA PER LA PROGRAMMAZIONE (A,B) - a.a SOLUZIONI PROPOSTE SECONDO APPELLO - 7/02/2012

Dati e Algoritmi I (Pietracaprina) Esercizi sulle Nozioni di Base

Problemi di ricerca in insiemi ordinati

STRUTTURE DI CONTROLLO DEL C++

LOGICA PER LA PROGRAMMAZIONE - a.a Secondo Appello - 11/02/2016 Soluzioni Proposte

come segue: data una collezione C di elementi e una un elemento che verifica la proprietà P

Algoritmi e Strutture Dati

Testing, correttezza e invarianti

Costo di esecuzione e complessità. Modello di costo e complessità di un algoritmo

Algoritmi di ordinamento e ricerca. Classe SelSort.java

Nozioni di base (II Parte)

Linguaggio C - le strutture di controllo: sequenza, selezione, iterazione

Istruzioni di controllo: SEQUENZA

Semantica operazionale e denotazionale

Corso di Fondamenti di Informatica. La ricorsione

Cominciamo con un esempio... Utilizzando un sottoprogramma 16/12/2017

Un problema di programmazione dei lavori

Elementi di Informatica

Introduzione agli algoritmi Prova di esame del 19/9/2016 Prof.sse E. Fachini - R. Petreschi. Parte prima

Laboratorio 09. Programmazione - CdS Matematica. Ivano Lauriola 16 gennaio 2018

LOGICA PER LA PROGRAMMAZIONE - a.a Primo Appello - 20/01/2017 Soluzioni Proposte

Dati e Algoritmi I (Pietracaprina) Esercizi sul Text Processing

Fondamenti di Programmazione - Prof.ssa Gargano Anno Acc Esercitazioni 2009

Complementi di Algoritmi e Strutture Dati. Soluzioni prova scritta 7 giugno 2017

Analisi asintotica. Astrazione: come il tempo di esecuzione cresce in funzione della taglia dell input asintoticamente.

Analisi algoritmi ricorsivi e relazioni di ricorrenza

Informatica Generale Andrea Corradini Algoritmi: ordinamento per inserimento e ricorsione

Algoritmi e Strutture Dati. Capitolo 13 Cammini minimi: Algoritmo di Bellman e Ford

Informatica

Problemi e algoritmi

Esercizi di Algoritmi e Strutture Dati

Laboratorio di Informatica I

Validazione attraverso il TESTING Validazione, verifica, debugging e defensing programming

Nell informatica esistono alcuni problemi particolarmente rilevanti, poiché essi:

Problemi decidibili, semidecidibili, indecidibili

Esercitazione 5. Procedure e Funzioni Il comando condizionale: switch

Corso di Fondamenti di Informatica

Laboratorio di Programmazione Appunti sulla lezione 5: Algoritmi di ordinamento (cont.) Alessandra Raffaetà. Bubblesort

public static boolean occorre (int[] a, int n) { int i = 0; boolean trovato = false;

Laboratorio di Programmazione e Calcolo

Laboratorio di Programmazione Appunti sulla lezione 5: Algoritmi di ordinamento (cont.) Alessandra Raffaetà

Laboratorio di Python

Laboratorio di Programmazione Lezione 2. Cristian Del Fabbro

GLI ALBERI BINARI DI RICERCA. Cosimo Laneve

CENNI MINIMI DI PROGRAMMAZIONE FUNZIONALE IN PYTHON - V. 0.3

Programmare con MATLAB c Parte 5 Cicli: for e while

Dati e Algoritmi 1: A. Pietracaprina. Text Processing

Logica per la Programmazione

SeparationLogic. Tecniche Automatiche per la Correttezza del Software

Informatica

Laboratorio di informatica Ingegneria meccanica

Algoritmi e Strutture di Dati I 1. Algoritmi e Strutture di Dati I Massimo Franceschet francesc

Testing, correttezza e invarianti

Informatica

Introduzione al Linguaggio C

20/10/2014 M. Nappi/FIL 1

ALGORITMI E STRUTTURE DATI

Linguaggi. Claudio Sacerdoti Coen 29,?/10/ : La struttura dei numeri naturali. Universitá di Bologna

Istruzioni Condizionali

Quick Sort. PARTITION(A,p,r) risistema il sottoarray A[p...r] e riporta l indice q:

Linguaggi. Claudio Sacerdoti Coen 04/03/ : La struttura dei numeri naturali. Universitá di Bologna

Lo sviluppo di un semplice programma e la dimostrazione della sua correttezza

Collaudo del software

Algoritmi e Strutture Dati. Capitolo 4 Ordinamento

QUICKSORT. Basato sul paradigma divide-et-impera (come MERGE-SORT)

Laboratorio di Python

Algoritmi di Ricerca. Esempi di programmi Java

Le strutture di controllo

Strutture di Controllo

Transcript:

Linear search @pre @post bool LinearSearch(int [] a, int l, int u, int e) { for @ (int i := l;i u;i := i+1){ if (a[i] = e) return true; return false; LinearSearch ricerca il valore e all interno del range [l, u] di un array a. Restituisce true sse l array dato contiene il valore e fra il lower bound l e l upper bound u. Si comporta correttamente solo se 0 l ed u < a. 1

Binary search @pre @post bool BinarySearch(int [] a, int l, int u, int e) { if (l > u) return false; else { int m := (l+u) div 2; if (a[m] = e) return true; else if (a[m] < e) return BinarySearch(a, m+1, u, e); else return BinarySearch(a, l, m 1, e); BinarySearch è una funzione ricorsiva che ricerca il valore e nel range [l,u] di un array ordinato a di interi. Restituisce true sse a 2

contiene il valore e nel range [l, u]. Funziona correttamente solo se 0 l e u a. Un livello di ricorsione opera come segue: Se l > u allora il sottoarray (vuoto) non può contenere e e si restituisce false; Altrimenti si esamina l elemento di mezzo a[m] (a div b = Def a b ); Se a[m] = e allora si restituisce true; Altrimenti si effettua la ricorsione sulla metà destra se a[m] < e, sulla metà sinistra se a[m] > e. 3

Annotazioni di programma Un annotazione è una formula della logica del I ordine le cui variabili libere includono soltanto le variabili del programma. Un annotazione F posta accanto ad un istruzione asserisce che F è vera tutte le volte che il controllo del programma raggiunge quella istruzione. La specifica di funzione è una coppia di annotazioni: Precondizione di funzione: formula le cui variabili libere includono solo i parametri formali. Specifica sotto quali input deve essere eseguita la funzione. Postcondizione di funzione: è una formula G le cui variabili libere includono solo i parametri formali e la variabile speciale rv che rappresenta il valore di output della funzione. 4

Linear search con specifica di funzione @pre 0 l u < a @post rv ( i.l i u a[i] = e) bool LinearSearch(int [] a, int l, int u, int e) { for @ (int i := l;i u;i := i+1){ if (a[i] = e) return true; return false; La precondizione asserisce che il lower bound l deve essere non più piccolo di 0 e che l upper bound u deve essere più piccolo della lunghezza dell array. La post condizione asserisce che il valore di ritorno rv è true sse a[i] = e per qualche indice i [l,u] di a. 5

Linear search con specifica di funzione 2. @pre @post rv ( i.0 l i u < a a[i] = e) bool LinearSearch(int [] a, int l, int u, int e) { for @ (int i := l;i u;i := i+1){ if (a[i] = e) return true; return false; 6

Binary search con specifica di funzione @pre 0 l u < a sorted(a,l,u) @post rv ( i.l i u a[i] = e) bool BinarySearch(int [] a, int l, int u, int e) { if (l > u) return false; else { int m := (l+u) div 2; if (a[m] = e) return true; else if (a[m] < e) return BinarySearch(a, m+1, u, e); else return BinarySearch(a, l, m 1, e); La postcondizione è identica a quella di LinearSearch ma la precondizione dichiede anche che l array sia ordinato. 7

Loop invariant Ad ogni ciclo for e while viene associata un annotazione detta loop invariant. Un ciclo while while @F ( condition ) { body Dice: eseguire body finché vale condition. L asserzione F deve valere all inizio di ogni iterazione. Viene valutata prima di condition e quindi deve valere anche sull iterazione finale, quando condition è false. 8

Loop invariant for @F ( initialize ; condition ; increment ) { body può essere tradotto nel ciclo equivalente initialize ; while @F ( condition ) { body increment 9

F deve valere dopo che initialize è stato valutato e, su ogni iterazione, prima che condition venga valutata. 10

Linear search con loop invariant @pre 0 l u < a @post rv ( i.l i u a[i] = e) bool LinearSearch(int [] a, int l, int u, int e) { for @L : l i ( j.l j < i a[j] e) (int i := l;i u;i := i+1){ if (a[i] = e) return true; return false; 11

Asserzioni Le annotazioni possono essere aggiunte in qualunque parte del programma. Quando un annotazione non è una precondizione di funzione, una postcondizione, o un loop invariant, la chiamiamo asserzione. Le asserzioni permettono ai programmatori di fornire un commento formale. Ad esempio, se all istruzione i := i+k; il programmatore pensa che k debba essere positivo, si può aggiungere un asserzione che afferma la supposizione: @ k > 0; i := i+k; 12

Correttezza parziale Useremo il metodo delle asserzioni induttive. Questa volta i cammini sono sequenze di istruzioni di programma. Un cammino di base (semplice, elementare) è una sequenza di istruzioni che comincia dalla precondizione di funzione, o da un loop invariant e finisce in un loop invariant, in un asserzione, o nella postcondizione di funzione. Inoltre, un loop invariant può occorrere solo all inizio o alla fine di un cammino di base. Tratteremo anche il caso delle funzioni ricorsive. 13

Cammino 1: Cammini di base di LinearSearch annotato @pre 0 l u < a i := l; @L : l i ( j.l j < i a[j] e) Cammino 2: @L : l i ( j.l j < i a[j] e) assume i u; assume a[i] = e; rv := true; @post rv ( i.l i u a[i] = e) 14

Cammino 3: Cammini di base di LinearSearch annotato @L : l i ( j.l j < i a[j] e) assume i u; assume a[i] e; i := i+1; @L : l i ( j.l j < i a[j] e) Cammino 4: @L : l i ( j.l j < i a[j] e) assume i > u; rv := false; @post rv ( i.l i u a[i] = e) 15

Chiamate di funzione Come i cicli, anche le chiamate di funzione ricorsive creano un numero non limitato di cammini. Come gli invarianti di loop tagliano (cut) i cicli per produrre un numero finito di cammini base, le specifiche di funzione tagliano le chiamate di funzione. 16

Binary search con asserzioni di chiamata di funzione @pre 0 l u < a sorted(a,l,u) @post rv ( i.l i u a[i] = e) bool BinarySearch(int [] a, int l, int u, int e) { if (l > u) return false; else { int m := (l+u) div 2; if (a[m] = e) return true; else if (a[m] < e) { @ R 1 : 0 m+1 u < a sorted(a,m+1,u); return BinarySearch(a, m+1, u, e); else { @ R 2 : 0 l m 1 < a sorted(a,l,m 1); return BinarySearch(a, l, m 1, e); 17

Cammino 1: Cammini di base @pre 0 l u < a sorted(a,l,u) assume l > u; rv := false; @post rv ( i.l i u a[i] = e); Cammino 2: @pre 0 l u < a sorted(a,l,u) assume l u; m := (l+u) div 2; assume a[m] = e; rv := true; @post rv ( i.l i u a[i] = e); 18

Cammino 3: Cammini di base @pre 0 l u < a sorted(a,l,u) assume l u; m := (l+u) div 2; assume a[m] e; assume a[m] < e; @R 1 : 0 m+1 u < a sorted(a,m+1,u); 19

Cammino 5: Cammini di base @pre 0 l u < a sorted(a,l,u) assume l u; m := (l+u) div 2; assume a[m] e; assume a[m] e; @ R 2 : 0 l m 1 < a sorted(a,l,m 1); 20

Cammino 4: Cammini di base @pre 0 l u < a sorted(a,l,u) assume l u; m := (l+u) div 2; assume a[m] e; assume a[m] < e; assume v 1 i.m+1 i u a[i] = e; rv := v 1 ; @post rv ( i.l i u a[i] = e); 21

Cammino 6: Cammini di base @pre 0 l u < a sorted(a,l,u) assume l u; m := (l+u) div 2; assume a[m] e; assume a[m] e; assume v 2 i.l i m 1 a[i] = e; rv := v 2 ; @post rv ( i.l i u a[i] = e); 22

Le linee: Spiegazioni assume v 1 i.m+1 i u a[i] = e; rv := v 1 ; sono ottenute come segue: Si traduca lo statement: return BinarySearch(a, m+1, u, e); in un assegnamento a rv: rv := BinarySearch(a, m+1, u, e); Poi, poichè la precondizione vale (dal cammino 3), supponiamo che valga anche la postcondizione. Quindi descriviamo la chiamata di funzione con una relazione basata sulla postcondizione: 23

G[a,l,u,e,rv] : rv i.l i u a[i] = e. In questo caso specifico la relazione è G[a,m+1,u,e,v 1 ], dove v 1 è una variabile nuova che cattura il valore restituito. Nel cammino base si assuma tale relazione e si usi il valore di ritorno v 1 nell assegnamento: assume G[a,m+1,u,e,v 1 ]; rv := v 1 ; 24

Condizioni di verifica Il nostro obiettivo è quello di ridurre una formula annotata ad un insieme finito di formule della logica del I ordine chiamate condizioni di verifica. La riduzione da cammini di base a vc viene eseguita attraverso la costruzione della wlp. La wlp(f,s) è definita così: Assunzione: cosa deve valere prima che l istruzione assume c venga eseguita per assicurare che F valga dopo? Se c F vale prima, allora soddisfacendo c in assume c si garantisce che F valga dopo. wlp(f,assume c) c F. Assegnamento: cosa deve valere prima che l istruzione v := e 25

venga eseguita per assicurare che F[v] valga dopo? Se F[e] vale prima, allora assegnando e a v con v := e si garantisce che F[v] valga dopo.: wlp(f[v],v := e) F[e]. per una sequenza di istruzioni S 1 ;...;S n, definiamo: wlp(f,s 1 ;...;S n ) wlp(wlp(f,s n ),S 1 ;...;S n 1 ) Quindi: perchè F possa valere dopo aver eseguito una sequenza di istruzioni S 1 ;...;S n, wlp(f,s 1 ;...;S n ) deve valere prima di eseguire le istruzioni La condizione di verifica vc su un cammino base @ F S 1 ;.; S n ; @ G 26

è F wlp(g,s 1 ;...;S n ) La sua validità implica che quando F vale prima delle istruzioni del cammino eseguito, allora G vale dopo. Tradizionalmente questa condizione di verifica viene denotata dalla tripla di Hoare: {FS 1 ;...;S n {G 27

Esempio: cammino 2 BinarySearch @pre F : 0 l u < a sorted(a,l,u) S 1 : assume l u; S 2 : m := (l+u) div 2; S 3 : assume a[m] = e; S 4 : rv := true; @post G: rv ( i.l i u a[i] = e); La vc è F wlp(g,s 1 ;S 2 ;S 3 ;S 4 ) 28

wlp(g,s 1 ;S 2 ;S 3 ;S 4 ) Esempio: cammino 2 BinarySearch wlp(wlp(g,rv := true),s 1 ;S 2 ;S 3 ) wlp(wlp(g{rv true, assume a[m] = e),s 1 ;S 2 ) wlp(a[m] = e G{rv true,s 1 ;S 2 ) wlp(wlp(a[m] = e G{rv true,m := (l+u) div 2),S 1 ) wlp((a[m] = e G{rv true){m (l+u) div 2,S 1 ) wlp((a[m] = e G{rv true){m (l+u) div 2, assume l u) l u (a[m] = e G{rv true){m (l+u) div 2 29

Esempio: cammino 2 BinarySearch Applicare le sostituzioni produce l u (a[(l+u) div 2] = e G{rv true,m (l+u) div 2) Semplificando la vc di conseguenza: 0 l u < a sorted(a,l,u) l u a[(l+u) div 2] = e i.l i u a[i] = e che è valida nella teoria dei numeri e degli array. 30

Esempio di correttezza totale: cammino BinarySearch @pre u l+1 0 @post u l+1 bool BinarySearch(int [] a, int l, int u, int e) { if (l > u) return false; else { int m := (l+u) div 2; if (a[m] = e) return true; else if (a[m] < e) return BinarySearch(a, m+1, u, e); else return BinarySearch(a, l, m 1, e); 31

Esempio di correttezza totale: cammino BinarySearch u l+1 mappa i parametri formali di BinarySearch nell insieme dei numeri naturali N con la relazione ben fondata <. Questa scelta è intuitivamente corretta perché l intervallo [l, u] si riduce ad ogni livello di ricorsione. Tuttavia potrebbe accadere che l > u così che u l+1 non viene mappato in N. proprietà di u l+1: 1.Poiché, u l+1 ha tipo int, dobbiamo dimostrare che u l+1 viene di fatto mappato in N 2.Dobbiamo provare che u l+1 decresce ad ogni chiamata ricorsiva 32

Esempio di correttezza totale: cammino BinarySearch È la precondizione della funzione stessa ad asserire la prima proprietà. Per dimostrare la seconda proprietà riduciamo l argomento ai cammini di base: attraverso ogni cammino di base u l+1 deve decrementare. Prendiamo in considerazione i cammini significativi. 33

Esempio di correttezza totale: cammino BinarySearch Cammino 1: @pre u l+1 0 u l+1 assume l u; m := (l+u) div 2; assume a[m] e; assume a[m] < e; u (m+1)+1 34

Esempio di correttezza totale: cammino BinarySearch Cammino 2: @pre u l+1 0 u l+1 assume l u; m := (l+u) div 2; assume a[m] e; assume a[m] e; u (m+1)+1 Esistono altri cammini di base dall entrata nella funzione fino all uscita (return statement). Tuttavia, poiché entrambi portano alla fine della ricorsione, sono irrilevanti per l argomento di terminazione. 35

Esempio di correttezza totale: cammino BinarySearch I cammini di base che abbiamo mostrato inducono due condizioni di verifica: 1.u l+1 0 l u... u (((l+u) div 2)+1)+1 < u l+1, 2.u l+1 0 l u... (((l+u) div 2) 1) l+1 < u l+1, dove... elide i letterali che coinvolgono a[m] e che sono irrilevanti per l argomento di terminazione. 36