Metodi Formali dell'Informatica
- Prof: Ugo De' Liguoro
- PDF Version
- Testo:
Teoria
I linguaggi sono definibili come sistemi formali, composti di
- alfabeto di simboli
- espressioni ben formate
- regole di inferenza
Metodi Formali
Derivano dalla logica-matematica
- Chompsky - Teoria delle Grammatiche
- paralleli con gli automi
- Linguaggi di programmazione - Linguaggi formali
- metodo che permette di verificare - Metodi Formale
- descrizioni formali del comportamento dei programmi
- metodo che permette di verificare - Metodi Formale
In computer science formal methods are a particular kind of mathematically based techniques for the specification, development and verification of software and hardware systems - Wikipedia
- Componenti dei metodi formali
- calcoli logici
- sistemi di riscrittura
- semplificazioni
- linguaggi formali
- teoria degli automi
- sistemi di transizione
- algebra dei dati
- algebra dei processi
- esecuzione concorrente
- algebra relazionale
- basi di dati
- semantica dei linguaggi di programmazione
- teoria dei tipi
- analisi statica
- Data Flow
- Control Flow
- Abstract Interpretation
L’utilitá é l’analisi matematica che dimostri la robustezza e la correttezza della progettazione hardware e software
- Tool:
- Infer
- Key
- Viper
Il Problema della Verifica
- In:
- descrizione di un sistema
- specifica del suo comportamento o sua proprietá
- Out:
- evidenza del fatto che il sistema soddisfa la specifica
- controesempio che non funziona
-
Semantica Operazionale
Definisce il significato di un programma come il suo comportamento che, quando termina, trasforma uno stato in un altro
-
Semantica Logica
Pre e Post condizioni che un programma soddisfa
- Floyd
- metodo delle asserzioni - 1967
- controllo del flusso di grafi che descrivono le aspettative sullo stato della memoria
- metodo delle asserzioni - 1967
- Hoare
- formalizza le idee di Floyd
- Logica di Hoare
- \(\{\varphi\} P \{\psi\}\)
- in P out
- \(\{\varphi\} P \{\psi\}\)
- Floyd
-
Verifica Statica
Il programma non viene eseguito - statico Il testing é fatto sull’esecuzione - dinamico
- l’importante é la scelta degli esempi di testing
- G.J.Myers, The Art of Software Testing
- essendo i test infiniti il superamento di qualsiasi test non verifica il programma
- é un metodo di ricerca degli errori, non di verifica
Processo:
- Contratto
- Invariante di Loop
- esistono euristiche per trovarlo ma non algoritmi
- Asserzioni Intermedie
- conducono alla dimostrazione di ció che voglio
- l’importante é la scelta degli esempi di testing
-
Logica di Hoare
HL
Usiamo logica debole, non dimostriamo la terminazione. Se il programma termina allora é il risultato sará corretto.- Rules:
- skip
- assignments
- sequencing
- conditionals
- while loops
- consequence
-
Correttezza di HL
Teorema: Se la tripla é derivabile in HL, allora é valida
-
Limiti teorici
La logica del primo ordine é corretta e completa ma é indecidibile
- Teorema di Church
- non esiste un algoritmo che verifichi che formula logica sia corretta
HL
é corretta, ma completa solo in senso debole; include FOL dunque é indecidibileAllora si utilizzano Truth Assistant, il teorema di
Rice
ci dimostra che i Verificatori non possono esistere.Isabelle
Coq
Agda
- un linguaggio di programmazione funzionale
- VeriFast
- ProofAssistant dedicato a Separation Logic in C e Java
- Rules:
-
Separation Logic
Per trattare linguaggi imperativi con puntatori, gestione dinamica della memoria
- si utilizza per modularizzare
- si guarda una funzione per volta
- poi si uniscono i risultati per dimostrare la correttezza totale
Si estendono le asserzioni con:
- \(s,h \vDash \text{emp}\)
- empty heap
- \(s,h \vDash a \rightarrow a'\)
- singleton heap
- \(s,h \vDash P \star Q\)
- separating conjunction
- \(h_{1} \uplus h_{2}\)
Le triple \((c,s,h)\) sono dette safe se \((c,s,h) \not{\rightarrow_{*}} \text{error}\)
-
Frame Rule
\[\frac{\{P\}\; c\; \{Q\}}{\{P \star R\}\; c\; \{Q\star R\}}\]
- pre-condizione \(P\)
- post-condizione \(Q\)
- contesto \(R\)
Se vale questo allora posso spezzare in moduli il codice e verificare questi sottoinsiemi Lemmi:
-
monotonicitá
- \((c,s,h) \text{safe} \implies \forall h' \perp h : (c,s,h\uplus h') \text{safe}\)
- \((c,s,h_{0}) \rightarrow^{*} (\text{skip},s',h_{0}') \implies \\ \forall h_{1} \perp h_{0}:(c,s,h_{0} \uplus h_{1}) \rightarrow^{*} (\text{skip}, s', h_{0}' \uplus h_{1}')\)
- \((c,s,h_{0})\) riduce all’infinito \(\implies \forall h_{1} \perp h_{0} : (c,s,h_{0} \uplus h_{1})\) riduce all’infinito
-
frame property
- \((c,s,h_{0})\text{safe} \land (c,s,h_{0} \uplus h_{1}) \rightarrow^{*} (\text{skip},s',h') \implies \\
\exists h_{0}' \perp h_{1} : (c,s,h_{0})\rightarrow^{*} (\text{skip},s',h_{0}')\land h' = h_{0}' \uplus h_{1}\)
- \((c,s,h_{0})\text{safe} \land (c,s,h_{0} \uplus h_{1}) \rightarrow^{*} (\text{skip},s',h') \implies \\
-
Heap Simbolici
\(H ::= \exists \vec{x} : (P_{1} \land \cdots \land P_{n}) \land (S_{1} \star \cdots \star S_{m})\)
- \(\vec{x} = \Cup_{i} fv(P_{i}) \cup \Cup_{j} fv(S_{j})\)
- puro e spaziale
Dai comandi atomici, definiti conseguentemente alle rispettive regole della logica. Si eseguono poi sequenze atomiche \[\{H\} A_{1};\cdots ;A_{n} \{H'\}\] \[\frac{\{H\}A_{1}\{H''\} \qquad \{H''\} A_{2} \{H'\}}{\{H\}A_{1};A_{2}\{H'\}}\] \[\frac{H,A_{1} \implies H'}{H,A_{1};A_{2} \implies H',A_{2}}\]
Grammatiche
Concrete
Descrivo Grammatiche Senza Contesti con le Regole di Inferenza
\[\frac{}{n \in Aexp}\] \[\frac{}{x \in Aexp}\] \[\frac{a_1\in Aexp \quad a_2 \in Aexp}{a_1 + a_2 \in Aexp}\]
Astratte
-
Backus Normal Form
Utiliziamo la notazione carrificata
vname ::== String aexp ::== N n | V x | Plus aexp aexp | Times aexp aexp
Semantica
Agda
Set
, insieme o Tipo
data aexp: Set nohere
N: N -> aexp
V: String -> aexp
Plus: aexp -> aexp -> aexp
depth: aexp -> N
depth (Nn) = 0
depth (Vx) = 0
depth (Plus a b) = 1 + max (depth a) (depth b)
Dim. per induzione strutturale:
depth (Plus a b) <= size (Plus a b)
La semantica di \(a \in aexp\) é un numero \(n \in N\) Per def il valore di \(V x\) usiamo gli stati
- \(s \in state = vname \rightarrow val\)
aval: aexp -> state -> val
aval (N n) s = n
aval (V x) s = sx
aval (Plus a_1 a_2) s = (aval a_1 s) + (aval a_2 s)
\(FVa\): l’insieme delle variabili libere in \(a \in aexp\)
FV (N n) = nil
FV (V x) = { n }
FV (Plus a_1 a_2) = (FVa_1) U (FVa_2)
-
Lemma FVa
Se per ogni \(x \in FVa\) gli stati \(s, s^{'} \mid sx = s^{'}x\) allora \(aval \: as = aval \: as^{'}\)
- dim su ind. strutturale su \(a\)
Sostituzione
\(a[a^{'}/x]\) intendiama la sostituzione di x con a' in a
(N n)[a'/x] = N n
(V x)[a'/x] = a'
(V y)[a'/x] = V y
(Plus a_1 a_2)[a'/x] = Plus a_1[a'/x] a_2[a'/x]
Modifica delle variabili Se \(s\in state, x\in vname, n \in val \mid s[x \rightarrow n] \in state\)
-
Lemma di Sostituzione
\[aval \: (a[a^{'}/x])s = aval \: a \: s [x\rightarrow aval \: a^{'}\: s]\]
Booleani
bexp ::= B bval
| Not bexp | And bexp bexp
| Less aexp aexp -- a < a'
bval ::= tt | ff
Comandi
Espressioni generate dalla grammatica (BNF)
Sintassi
com ::= SKIP -- noop
| vname := aexp -- assegnazione
| com ; com -- composizione sequenziale
| IF bexp THEN com ELSE com -- selezione
| WHILE bexp DO com -- iterazione
Con queste caratteristiche il nostro linguaggio IMP
é Touring completo:
- Arbib, A programming approach to computability
Semantica di com
cval : com -> state -> state
Se questa funzione esiste deve essere parziale
- definita solo in alcuni casi
cval (WHILE b DO c) s = ??
cval (WHILE b DO c) s = s -- bval b s = ff
cval (WHILE b DO c) s = -- bval b s = tt
= cval (c; WHILE b DO c) s
= cval (WHILE b DO c) (cval c s)
In questo caso la definizione é circolare
Semantica Naturale - Big-step
Usiamo la relazione \((c,s) \implies t\) su \(com \times state \times state\) \(\iff\) l’esecuzione di \(c\) in \(s\) termina in \(t\)
\((c,s,t) \rightarrow (c,s) \implies t \in bool\)
- true se in un stato finale, false altrimenti
- questa funzione é definibile in
Agda
Sistema formale: \[\frac{(c_{1},s_{1}) \implies t_{1}\cdots (c_{n},s_{n})\implies t_{n}}{(c_{n+1},s_{n+1})\implies t_{n+1}}\]
-
Regole
Skip
\[\frac{}{(SKIP,s)\implies s}\]Ass
\[\frac{aval \: a \: s = n}{(n:= a,s)\implies s[x\rightarrow n]\]Comp
\[frac{(c_{1},s)\implies s' \quad (c_{2},s')\implies t}{(c_{1};c_{2},s)\implies t}\]
IF b THEN c_1 ELSE c_2
- \[\frac{bval \: b\: s = tt \:\: (c_{1},s)\implies t }{(IF \: b \: THEN \: c_{1} \: ELSE \:c_{2},s)}\]
- \[\frac{bval \: b\: s = ff \:\: (c_{2},s)\implies t }{(IF \: b \: THEN \: c_{1} \: ELSE \:c_{2},s)}\]
WHILE
- \[\frac{ bval \: b\: s = ff}{(WHILE \: b\:DO \: c, s)\implies s}\]
- \[\frac{ bval \: b\: s = tt \:\: (c,s)\implies s^{'} \:\: (W,s^{'})\implies t}{(WHILE \: b\:DO \: c, s)\implies t}\]
- \(W\) abbrevia \((WHILE \: b \: DO \: c, s)\implies t\)
Con queste si studia la convergenza
-
Proposizione SKIP
\(\forall s,t \nvdash (WHILE \: true \: DO \: SKIP,s) \Rightarrow t\) Dim
- per assurdo sia \(D\) una dimostrazione (derivazione chiusa) t.c. la sua conclusione sia \((WHILE \: true \: DO \: SKIP,s) \Rightarrow t\)
- poiché
bval true s = tt
per ognis
,D
deve terminare con:- \(\frac{(SKIP,s)\Rightarrow s^{'} \:\: (W,s^{'})\Rightarrow t}{(W,s)\Rightarrow t}\)
- ma
s'=s
per SKIP, dunque la des.D'
ha la stessa forma diD
, essendo propriamente inclusa inD
, cioé é infinita
- dunque
D
non é una dimostrazione
-
Equivalenza di Programmi
I comandi \(c_{1},c_{2}\) sono equivalenti [\(c_{1} \sim c_{2}\)]
- \(\forall s,t \in state . (c_{1},s)\Rightarrow t \iff (c_{2},s)\Rightarrow t\)
Lemma
WHILE b DO c ~ IF b THEN (c;WHILE b DO c) ELSE SKIP
-
Determinismo della semantica naturale
Teorema:
- Per ogni \(c \in com\) , per ogni \(st,,t' \in state\)
- \((c,s)\Rightarrow t \land (c,s)\Rightarrow t^{'} \implies t=t^{'}\)
-
Funzione parziale
\([\![ \cdot ]\!]: com \rightarrow state \rightharpoonup state\) \([\![c]\!]s = \begin{cases}t & \mbox{se} \vdash (c,s) \Rightarrow t\\perp & \mbox{altrimenti}\end{cases}\)
Semantica SOS - Small Step
Singolo passo di calcolo \((c,s) \rightarrow (c^{'},s^{'})\)
- Lemma - determinismo
- \((c,s)\rightarrow(c^{'},s^{'}) \land (c,s)\rightarrow(c^{''},s^{''}) \implies c^{'}=c^{''}\land s^{'}=s^{''}\)
- Corollario
- \((c,s)\) termina se \(\exists t \mid (c,s) \rightarrow^{*}(\textsc{skip},t)\), cicla se esiste una sequenza infinita
Assegnazione
- \((x := a,s) \rightarrow (\textsc{skip}, s[x \mapsto aval \: as])\)
SKIP
- \((\textsc{skip};c,s) \rightarrow (c,s)\)
IF
- \[\frac{bval \: b \: s = tt}{(\textsc{if}\: b\: \textsc{then}\:c_{1}\: \textsc{else}\: c_{2},s)\rightarrow (c_{1},s)}\]
- \(ff\) speculare
WHILE
- $(\textsc{while}\; b\: \textsc{do}\: c,s) →
(\textsc{if}\: b\: \textsc{then}\; (c;\: \textsc{while}\; b\: \textsc{do}\: c)\: \textsc{else}\; \textsc{skip}, s$
\([\![c]\!]_{\textsc{sos}}s = \begin{cases}t & \mbox{se} \vdash (c,s) \rightarrow^{*}(\textsc{skip},t)\\perp & \mbox{se}\:(c,s)\:\mbox{cicla}\end{cases}\)
- Teorema di equivalenza delle Semantiche
\(\forall c\in \mbox{com}\: \forall s,t\in\mbox{state}\mid[\![c]\!]_{\textsc{nat}}s=[\![c]\!]_{\textsc{sos}}s\)
Teoria dei Tipi
Il quantificatore universale si traduce, nella teoria dei tipi dipendenti, in
\[\frac{A : \text{Set} \qquad x : A \vdash B[x] : \text{Set}}{\pi[x : A] B[x] : \text{Set}}\] dove
\(\pi [x:A] \: B[x] \equiv B[a_{1}] \times B[a_{2}] \times \cdots\) per \(a_{i}\in A\) corrisponde a \(\forall x \: . \: B[x] \iff B[a_{1}] \land B[a_{2}] \land \cdots\)
Il \(\pi\) sta per il concetto di indicizzazione:
- forma famiglie secondo i suoi indici
\(\forall (\lambda \: x \: \rightarrow B\: x): \text{Set}\)
- il quantificatore é un operatore che viene applicata al lambda
Logica Classica e Intuizionistica
In Gilbert and Sullivan’s The Gondoliers, Casilda is told that as an infant she was married to the heir of the King of Batavia, but that due to a mix-up no one knows which of two individuals, Marco or Giuseppe, is the heir. Alarmed, she wails “Then do you mean to say that I am married to one of two gondoliers, but it is impossible to say which?” To which the response is “Without any doubt of any kind whatever.”
Logic comes in many varieties, and one distinction is between classical and intuitionistic. Intuitionists, concerned by assumptions made by some logicians about the nature of infinity, insist upon a constructionist notion of truth. In particular, they insist that a proof of A ⊎ B must show which of A or B holds, and hence they would reject the claim that Casilda is married to Marco or Giuseppe until one of the two was identified as her husband. Perhaps Gilbert and Sullivan anticipated intuitionism, for their story’s outcome is that the heir turns out to be a third individual, Luiz, with whom Casilda is, conveniently, already in love.
Intuitionists also reject the law of the excluded middle, which asserts A ⊎ ¬ A for every A, since the law gives no clue as to which of A or ¬ A holds. Heyting formalised a variant of Hilbert’s classical logic that captures the intuitionistic notion of provability. In particular, the law of the excluded middle is provable in Hilbert’s logic, but not in Heyting’s. Further, if the law of the excluded middle is added as an axiom to Heyting’s logic, then it becomes equivalent to Hilbert’s. Kolmogorov showed the two logics were closely related: he gave a double-negation translation, such that a formula is provable in classical logic if and only if its translation is provable in intuitionistic logic.
Propositions as Types was first formulated for intuitionistic logic. It is a perfect fit, because in the intuitionist interpretation the formula A ⊎ B is provable exactly when one exhibits either a proof of A or a proof of B, so the type corresponding to disjunction is a disjoint sum.
(Parts of the above are adopted from “Propositions as Types”, Philip Wadler, Communications of the ACM, December 2015.) ~ Philip Wadler #cit
- Propositions as Types è un paradigma che pone le proposizioni e tipi come equivalenti.
- in Type Theory
- una proposizione è identificata come il tipo (collezione) delle sue prove
- un tipo è identificato come la proposizione che contiene i suoi termini
Semantica di Heyting
\[\frac{B[t]}{\exists x \: . \: B[x]}\] \[\langle t, M \rangle \: : \exists x \: . \: B[x]\] dove \[M\: :\: B[t]\]
IMP
Estensione Puntatori
com ::= ...
| x := cons(a_1,...,a_2)
allocation
| n := [a]
lookup
| [a] := a'
mutation
| dispose(a)
deallocation
la notazione [a]
richiama il concetto di heap come array, dove a
ne é l’indice
-
Semantica
store = var_name -> Val
heap = loc -> Val
Per \(h \in \text{heap}, n\ge 0\)
- \(h = \{l_{1} \rightarrow v_{1} \cdots l_{n} \rightarrow v_{n}\}\)
- \(\text{dom}(h | {l_{1}\cdots l_{n}})\)
- le locazioni allocate
Viene aggiunta alla semantica
SOS
lo heaph
-
Indipendenza dello Heap
\(h_{1} \perp h_{2} \iff \text{dom}(h_{1}) \cap \text{dom}(h_{2}) = \emptyset\)
Semantica Operazionale
StackMachine
Basato su <~/Code/Agda/C-List.agda>
Compilatore
Nipkow, cap. 8
Linguaggio IMP
\(\longrightarrow\) istruzioni di una macchina astratta
- c : com \(\mapsto\) p : prog
- \((c,s) \Rightarrow t\)
- correttezza \(\Rightarrow\)
- completezza \(\Leftarrow\)
- \(p \vdash (0,s,[\:]) \rightarrow^* (\text{size }p,t,[\:])\)
- program counter
- memoria
- stack
- \((c,s) \Rightarrow t\)
instr
LOADI int
LOAD vname
ADD
STORE vname
JMP int
JMPLESS int
JMPGE int
Si definisce lookup i P
dove \(0 \le i < \text{size} P\)
- in
Agda
le funzioni parziali non sono ammesse e quindi questo va adattato
\[\frac{0 \le i < \text{size }P \quad \text{iexec }(\text{lookup }i\; P)(i,s,stk) \equiv (i',s',stk')}{P\vdash (i,s,stk) \rightarrow (i',s',stk')}\]
Un singolo passo di esecuzione (programma \(P\) esegue dalla configurazione \(c\) a \(c'\)) \(P \vdash c \rightarrow c'\)
-
bcomp
\(bcomp :: bexp \Rightarrow bool \Rightarrow int \Rightarrow prog\)
\begin{align*} bcomp\;(Bc\;v)\;f\;n &= (if\;v=f\;then\;[\textsc{jmp}\;n]\;else\;[\:]) \\
bcomp\;(Not\;b)\;f\;n &= bcomp\;b\;(\lnot f)\;n \\
bcomp\;(And\;b_1\;b_2)\;f\;n &= \\
\end{align*}\begin{align*} bcomp\;(Less\;a_1\;a_2)\;f\;n =& acomp\;a_1\;@\;acomp\;a_2\;@\;( \\
& if\;f\;then\;[\textsc{jmpless}\;n]\;\\
& else\;[\textsc{jmpge}\;n]) \end{align*}Lemma 8.8
Si definisce il program counter sui salti condizionali:- \(\text{pc'} = \text{size }(\text{bcomp }b \:f \:n) + (\text{ if } f = \text{ bval } b\: s \text{ then } n \text{ else } 0 )\)