interpretazione astratta Cosimo Laneve interpretazione astratta una tecnica utilizzata da 30 anni (Patrick e Radhia Cousot nel 1977) per trattare in modo sistematico astrazioni e approssimazioni nata per descrivere analisi statiche di programmi imperativi e provarne la correttezza (poi estesa con successo a varie classi di linguaggi di programmazione) è una tecnica generale per correlare semantiche a diversi livelli di astrazione 2
l idea il punto di partenza è la semantica concreta, ovvero una funzione che assegna significati precisi ai comandi di un programma in un dominio fissato di computazione quindi si individua un dominio astratto, che modella alcune proprietà delle computazioni concrete, tralasciando la rimanente informazione poi si definisce una semantica astratta, che permetta di eseguire astrattamente il programma sul dominio astratto per calcolare la proprietà che il dominio astratto modella il calcolo della semantica astratta tipicamente e` un calcolo di punto fisso infine si dimostra che la semantica astratta è una approssimazione corretta della semantica concreta 3 esempio 1: segni delle espressioni con * consideriamo un semplice linguaggio delle espressioni AExp che definisce prodotti di interi a ::= n a * a la semantica di a si può descrivere mediante una funzione! A : AExp " (Z) definita da: A [n] = { n } A [ a 1 * a 2 ] = A [ a 1 ] # A [ a 2 ] ( # è il prodotto semantico) dove # è il prodotto su insiemi di interi: A # B = {a # b a $ A && b $ B} possiamo considerare un astrazione della semantica concreta (semantica astratta) che calcola solo il segno delle espressioni - se n < 0 A A : AExp! {-,0,+} definita come A A [n] = 0 se n = 0 e A A [a 1 * a 2 ] = A A [a 1 ] # a A A [a 2 ] dove # a - 0 + + se n > 0 - + 0-0 0 0 0 + - 0 + 4
esempio 1: correttezza è possibile dimostrare che questa astrazione è corretta, ovvero che prevede correttamente il segno delle espressioni la dimostrazione è per induzione strutturale sull espressione a, e semplicemente utilizza le proprietà della moltiplicazione tra interi (il prodotto di due positivi è positivo, etc.) per ogni a $ AExp: A [ a ] = { n } ed n< 0 % A A [ a ] = - [ a ] = 0 [ a ] = + A [ a ] = { 0 } % A A A [ a ] > { n } ed n> 0 % A A alternativamente: è possibile associare ad ogni valore astratto l insieme di valori concreti che esso rappresenta: si consideri la funzione definita come & (-) = Z <0 & (0) = { 0 } & (+) = Z >0 & : { -, 0, + }! (Z) 5 esempio 1: correttezza (cont) la correttezza può essere riscritta come: A (Z) per ogni a $ AExp: A [ a ] ' & ( A A [ a ] ) AExp & dove la funzione A : Exp " (Z) è definita come A [ n ] = { n } A [ a 1 * a 2 ] = A [ a 1 ] # A [ a 2 ) dove # è il prodotto su insiemi di interi: X # Y = {x # y x $ X && y $ Y} A A {-,0,+} osservazione: se si prende (Z) con l ordinamento ' è facile dimostrare che # è monotono osservazione: la funzione A è l estensione al dominio (Z) della funzione studiata nella prima parte del corso la funzione di concretizzazione stabilisce la relazione tra il concetto di approssimazione nei due domini concreto ed astratto 6
esempio 1: correttezza (cont) dimostrazione di per ogni a $ AExp: A [ a ] ' & ( A A [ a ] ) per induzione sulla struttura sintattica di a AExp A A A (Z) & {-,0,+} caso di base: a = n. Allora A [ n ] = {n}. Supponiamo che n sia positivo (il caso negativo è simile). Allora & ( A A [ n ] ) = Z >0 e, chiaramente, {n} ' Z >0. Il caso n =0 è lasciato per esercizio. caso induttivo: a = a' * a'' allora A [ a' * a'' ] = A [ a' ] # A [ a'' ] ' & ( A A [ a' ] ) # & ( A A [ a'' ] ) per ipotesi induttive e monotonia di # ' & ( A A [ a' ] # a A A [ a''] ) da provare (si chiama correttezza locale di # a ) = & ( A A [ a' * a''] ) in generale, se op è un operazione n-aria e op a è la sua astratta, la correttezza locale di op a si scrive: op(&(d 1 ),, &(d n )) ' &(op a (d 1,, d n )) 7 esempio 1: la correttezza locale di! a occorre dimostrare che A (Z) AExp & per ogni d,d $ {-,0,+} : &(d) # &(d ) ' & (d # a d ) La prova è una analisi per casi, considerando che il dominio astratto è finito. A A {-,0,+} caso a= -, b= -: quindi " (a # a b) = " (+) = Z >0. Si osservi che "(a) # "(b) = Z <0 # Z <0 = Z >0 caso a= -, b= +: quindi " (a # a b) = " (-) = Z <0. Si osservi che "(a) # "(b) = Z <0 # Z >0 = Z <0 etc. 8
esempio 2: AExp con *, -, + e / estendiamo il linguaggio AExp con gli altri operatori aritmetici (il linguaggio diventa quello visto a lezione in precedenza) a ::= n a * a a + a a - a a / a la semantica concreta A e` definita dalle regole A [a op a ] = A [ a ] op A [ a ] dove op e` l operatore semantico corrispondente ad op e definito su insiemi come segue: X op Y = { x op y x X e y Y } 9 la semantica astratta di AExp (con *, -, + e /) il dominio astratto (A,! A ) è un poset in cui l ordine parziale rappresenta la nozione di approssimazione/precisione - 0 + osservazione: (A,! A ) è un reticolo completo mentre la semantica astratta ( e` estesa con ) A A [a 1 op a 2 ] = A A [a 1 ] op a A A [a 2 ] dove op a è l operatore astratto corrispondente a op (vedi lucido seguente) osservazione: correttezza si dimostra come prima: per ogni a " AExp: A [ a ] # $ ( A A [ a ]) 10
la semantica astratta di *, -, + e / diamo la definizione punto-a-punto poichè il dominio astratto è finito * a - 0 + # - + 0 - # 0 0 0 0 0 # + - 0 + # 0 # # # # # # # - a - 0 + # - - - # 0 + 0 - # + + + # # # # # # # # + a - 0 + # - - - # 0-0 + # + + + # # # # # # # # / a - 0 + # - 0 # 0 # # # # # + 0 # 0 # # # # # # # 11 la prova di correttezza di A [ a ] # $ ( A A [ a ]) osservazione: in alcuni casi c è perdita di informazione A [(1+2) - 3] = 0 A A [(1+2)+ -3] = (+ + a +) + a - = + + a - = in altri casi non c è perdita di informazione A [((5*4) + 6] = 26 A A [(5*4) + 6] = (+ # a +) + a + = + + a + = + ci si riduce a dimostrare la correttezza locale degli operatori $(d) op $(d ) $ (d op a d ) esercizio! 12
il dominio astratto e la funzione di astrazione il dominio astratto (A,! A ) è un poset in cui l ordine parziale rappresenta la nozione di approssimazione/precisione - 0 + osservazione: (A,! A ) è un reticolo completo ) l ordine parziale è coerente con la funzione di concretizzazione: d! A d % &(d)! &(d ) cioè tutti gli oggetti più grandi di a saranno mappati in elementi più grandi osservazione: è possibile definire una funzione * -- detta funzione di astrazione -- che mappa un insieme X di valori concreti nel piu` preciso valore astratto che rappresenta X * : X glb{ d X + C &(d) } dominio concreto &(a) a dominio astratto X *(X) 13 il dominio astratto e la funzione di astrazione nel nostro esempio (A,! A ) è il reticolo completo - 0 + nel nostro esempio *: (Z) " A è definita come ) ) se X =, - se, - X ' Z <0!!!! *(X) = 0 se X = { 0 } + se, - X ' Z >0 altrimenti verificare che &(a) X a *(X) in particolare, quando X = &(d) e d = *(X) verificare che $(X) = glb{ d X % C "(d) } "(d) = lub{ X $(X) % A d } 14
in generale... una interpretazione astratta consta di: un dominio concreto (C, + C ) e un dominio astratto (A, + A ) che sono reticoli completi l ordine riflette la precisione/approssimazione (più piccolo = più preciso) le funzioni di concretizzazione e di astrazione sono monotone, e formano una connessione di Galois (sono inserzioni: vedi in seguito) le operazioni astratte astraggono correttamente su A la semantica concreta su C (per ogni S $ Lang: [ S] + C &(( (S)) ) (C, + C ) Lang & * ( (A, + A ) 15 un altra coppia di concretizzazoni e astrazioni per i segni, se X = )!! ) se X =,! Z <0 se X = - - se X ' Z <0!! {0} se X = 0 0- se X ' Z!0 & sign (X) = Z!0 se X = 0- * sign (X) = 0 se X = { 0 } Z >0 se X = + 0+ se X ' Z "0 0-0+ - 0 + ) Z "0 se X = 0+ + se X ' Z >0 Z se X = se X ' Z esempi: % sign ({0,1,3})= 0+ $ sign (0+). {0,1,3}, {3,5,2},... & $ sign (% sign ({0,1,3})). {0,1,3}& & % sign ($ sign (0+)) = 0+ 16
connessione di Galois (C, *, &, A) e` una connessione di Galois (GC) tra reticoli completi (C, + C ) e (A, + A ) * : C " A (astrazione) e & : A " C (concretizzazione) sono monotone per ogni c $ C. c + C & (*( c )) per ogni a $ A. *(& (a)) + A a una GC (C, *, &, A) e` una inserzione di Galois (GI) se vale una delle seguenti condizioni equivalenti: a. * è surgettiva! b. & è iniettiva prova: c. per ogni a $ A. *(& (a)) = a (c & b) basta provare che " (a) = " (a') implica a = a'. Se " (a) = " (a') allora $(" (a)) = $(" (a')), quindi, per ipotesi a=a'. (b & a) si usa la proprietà che " ($(" (a))) = " (a) [per def. $(" (a))) % A a e per monotonia " ($(" (a))) % C " (a). D altra parte, sempre per definizione, " (a) % C " ($(" (a)))]. Per b, $(" (a)) = a. (a & c) si dimostra che a % A $("(a)). Poichè $ è surgettiva, per ogni a esiste c tale che $(c)=a. Quindi "($(c)) = "(a) e, poichè c % C " ($( c )), c % C "(a). Infine, per monotonia di $, a = $(c) % C $(" (a)). 17 inserzione di Galois: alcune proprietà sia (C, *, &, A) una GI &(a) a X *(X) 1. * determina & e viceversa: *(c) = glb{ a $ A c C &(a) } e!!!!! &(a) = lub{ c $ C *(c) A a } 1. * preserva i lub s e & preserva i glb s se * preserva i lub allora è possibile definire & come sopra che forma con * una GI, stessa cosa per & se preserva i glb s *( C ) = A e &( A ) = C il dominio astratto di una GI (C, *,&, A) induce una partizione del dominio concreto c 1 ~ c 2 se e solo se *(c 1 ) = *(c 2 ) ogni classe di equivalenza [c] ~ ha lub, cioè ogni classe di equivalenza ha un rappresentante canonico 18
correttezza dell interpretazione astratta in una interpretazione astratta ci aspettiamo che il seguente diagramma commuti: (C, + C ) Lang & * A (A, + A ) esempio: nelle espressioni, Lang = Exp e C = (Z) e A [ E ] ' &(((E)) *({/(E)}) A ((E) 19 prova di correttezza (C, + C ) Lang & * per ogni a $ AExp: A [ a ] ' & (A A [ a ]) prova: per induzione sulla struttura di a: caso base. A [ n ] = {n} ' &(A A [ n ]) caso induttivo. A [ a 1 op a 2 ] = A [ a 1 ] op A [ a 2 ] A per definizione di op (A, + A ) ' & (A A [ a 1 ]) op &(A A [ a 2 ]) per ipotesi induttiva su E 1 e E 2 e monotonia di op ' & (A A [ a 1 ] op a A A [ a 2 ]) per correttezza locale di op a [proprieta` da assumere/verificare] = & (A A [ a 1 op a a 2 ]) per definizione di A A 20
la correttezza locale delle operazioni & A n (Z) n op a op A & (Z) op(&(a 1 ),...,&(a n )) &(op a (a 1,...,a n )) è equivalente a (monotonia di *) *( op(&(a 1 ),...,&(a n ))) A *( &(op a (a 1,...,a n ))) = op a (a 1,...,a n ) ponendo *( c i ) = a i, la correttezza di un'operazione astratta op a può essere equivalentemente definita come: per ogni c 1,...,c n $ C : *(op(&(* (c 1 )),..., &(* ( c n ))) A op a (*(c 1 ),...,*(c n )) e poichè c + C & (*( c )) (connessione di Galois), per la monotonia di op otteniamo per ogni c 1,...,c n $ C : *(op(c 1 ),..., c n )) A op a (*(c 1 ),...,*(c n )) osservazione: per ogni operazione concreta op, possiamo sempre definire la cosiddetta migliore approssimmazione corretta di op sul dominio astratto A: op a (a 1,...,a n ) = *(op(&(a 1 ),...,&(a n )) 21 l aggiunta delle variabili sia Var un insieme di variabili, e sia x,y...$ Var allora AExp diventa a ::= n a op a Var la semantica concreta: sia State = Var " (Z) assumendo che ad ogni variabile sia associato un insieme (singoletto oppure vuoto: assumiamo che lo stato sia sempre definito su qualunque variabile) la funzione semantica A : AExp " (State " (Z)) si definisce come : A [ n ](s) = { n } A [ x ](s) = s(x) A [a op a ](s) = A [ a ](s) op A [ a ](s) 22
semantica astratta delle variabili sia (A, + A ) un dominio astratto ( che astrae ( (Z), ' ) ) e sia State A = Var " A la semantica astratta è data dalla funzione A A : AExp " (State A " A)! definita come segue (è sempre una famiglia di funzioni indicizzata sulle espressioni): A A [ n ](s A ) = *({n}) A A [ x ](s A ) = s A (x) A A [a op a ](s A ) = A A [a ](s A ) op a A A [ a ](s A ) definizione: dati s $ State e s A $ State A, s e` &-compatibile con s A, notazione s & s A, quando, per ogni x $ Var, s(x) ' &(s A (x)) 23 prova di correttezza per ogni a $ AExp, s $ State e s A $ State A : s & sa implica A [a ](s) ' &(A A [a ](s A )) prova: per induzione su a $ AExp. casi di base: A [ n ](s)= {n} ' & (*({n})) = & (A A [ n ](s A )) otteniamo A [ x ](s) = s(x) mentre &(A A [ x ](s A )) = &(s A (x)) e da s & sa s(x) ' &(s A (x)) casi induttivi: A [a op a ](s) = A [a ](s) op A [ a ](s); per induzione: A [a](s) ' &(A A [ a ](s A ) per monotonia di op : A [a](s) op A [a ](s) ' &(A A [ a ](s A )) op &(A A [ a ](s A )) per correttezza locale di op A : &(A A [ a ](s A )) op &(A A [ a ](s A )) ' & (A A [ a ](s A ) op A A A [ a ](s A )) per definizione: & (A A [ a ](s A ) op A A A [ a ](s A )) = &(A A [ a op a ](s A )) quindi: A [a op a ](s) ' & (A A [ a op a ](s A )) 24