Come gestire le matrici durante le prove di correttezza in stile Hoare


11

Nella discussione intorno a questa domanda , Gilles menziona correttamente che qualsiasi prova di correttezza di un algoritmo che utilizza array deve dimostrare che non vi sono accessi fuori campo fuori campo; a seconda del modello di runtime, ciò provocherebbe un errore di runtime o l'accesso a elementi non array.

Una tecnica comune per eseguire tali prove di correttezza (almeno negli studi universitari e probabilmente nella verifica automatizzata) è utilizzando la logica Hoare . Non sono a conoscenza del fatto che l'insieme standard di regole contenga qualsiasi elemento relativo alle matrici; sembrano essere limitati alle variabili monadiche.

Posso immaginare di aggiungere assiomi del modulo

{0i<A.lengthP[A[i]/E]} A[i]:=E; {P}

Tuttavia, non mi è chiaro come si dovrebbe fare con un accesso agli array sul lato destro della strada, vale a dire se è parte di un complesso di espressione in qualche dichiarazione .x : = EEx:=E

Come si possono modellare gli accessi agli array nella logica Hoare in modo che l'assenza di accessi non validi possa e debba essere dimostrata per la correttezza del programma?

Le risposte possono supporre che non consentiamo l'uso di elementi dell'array in istruzioni diverse da o come parte di alcune in poiché ciò non limita l'espressività; possiamo sempre assegnare a una variabile temporanea il valore desiderato, ovvero scrivere anziché .E x : = E t : = A [ i ] ; io f (A[i]:=EEx:=Ei f ( A [ i ] > 0 ) ...t:=A[i]; if(t>0)if(A[i]>0)

Risposte:


8

Il tuo assioma non è in realtà un assioma, manca di ipotesi. Presentazioni semplici della logica Hoare manipolano le formule della forma dove e sono formule logiche e è un comando. È necessario assicurarsi che sia ben formato . In linguaggi semplici come quelli spesso usati per una prima introduzione alla logica di Hoare, la buona formazione è sintattica: in genere si tratta di verificare cheP P C C C{P}C{P}PPCCCè conforme a una grammatica senza contesto e, possibilmente, che le variabili libere si trovano all'interno di un insieme consentito. Se il linguaggio include costrutti che hanno una correttezza semantica, come gli accessi agli elementi dell'array, è necessario aggiungere ipotesi per esprimere questa correttezza semantica.

Formalmente, puoi aggiungere giudizi per esprimere la correzione di espressioni e comandi. Se le espressioni non hanno effetti collaterali, non hanno bisogno di postcondizioni, solo di precondizioni. Ad esempio, puoi scrivere regole di buona formazione come e consenti solo espressioni ben nei comandi: {P[xE]}

{P}E wf{P0E<length(UN)}UN[E] wf{P}E1 wf{P}E2 wf{P}E1+E2 wf
{P[XE]}E wf{P[XE]}X: =E{P}

Un approccio diverso consiste nel considerare tutte le espressioni come ben formate, ma fare in modo che qualsiasi espressione che coinvolge un calcolo mal formato abbia un valore speciale . Nelle lingue con controllo dei limiti di runtime, significa "questo programma ha sollevato un'eccezione fatale". Tieni quindi traccia se un programma ha commesso un un predicato logico ; un programma è valido solo se si può dimostrare che la sua postcondizione implica . e r r o r E r r o r ¬ E r r o rerrorerrorError¬Error

{P[xE]}x:=E{PError}P[XE]Eerror{P[XE]}X: =E{P}

Ancora un altro approccio è considerare una tripla Hoare da tenere solo se il programma termina correttamente. Questo è il solito approccio per i programmi non terminali: la postcondizione vale quando termina il comando, il che potrebbe non accadere sempre. Se trattate gli errori di runtime come non terminazione, spazzate via tutti i problemi di correttezza. Dovrai comunque dimostrare la correttezza del programma in qualche modo, ma non è necessario che sia nella logica Hoare se preferisci un altro formalismo per quel compito.

A proposito, nota che esprimere ciò che accade quando una variabile composta come una matrice viene modificata è più coinvolto di ciò che hai scritto. Supponiamo era, diciamo, : la sostituzione non cambierebbe , ma l'assegnazione potrebbe invalidare . Anche se si limita la sintassi dei predicati per parlare solo di atomi, considerare l'assegnazione sotto la condizione preliminare : non è possibile effettuare una semplice sostituzione per ottenere la postcondizione corretta , è necessario valutarePioSSorted(UN)UN[io]EPUN[io]PPUN[UN[0]-1]: =UN[0]UN[0]=2UN[1]=3A [ 0 ] A [ 0 ] A A [ i E ]UN[0]=1UN[1]=1UN[0](che può essere difficile in generale, poiché la condizione preliminare potrebbe non specificare un singolo valore possibile per ). È necessario eseguire la sostituzione sull'array stesso: . Gli appunti delle lezioni di Mike Gordon hanno una buona presentazione Logica Hoare con array (ma senza controllo degli errori).UN[0]UNUN[ioE]


0

Come menzionato da Gilles, esiste un assioma di assegnazione di array (vedi le note di Gordon, Sez. 2.1.10 ): In parole, se si dispone di un'assegnazione di array, sostituire l'array originale con l'array che ha in posizione il valore . Nota che se hai già sul post e assegna , allora dovresti ottenere come pre (sì, in questo ordine - l'aggiornamento recente viene eseguito per primo!).

{Q[UNUN.Store(io,eXpr)]}UN[io]=eXpr{Q}
A.store(i,expr)iexprA.store(i,vi)A[j]=vjA.store(j,vj).store(i,vi)

Inoltre, abbiamo bisogno l'assioma di accesso agli array: A.store(i,v)[i]può essere sostituito da v( "se si accede -esimo elemento che appena aggiornato, quindi restituire il valore assegnato").io

Penso che per dimostrare che un programma con array sia corretto ("nessun accesso fuori limite"), gli assiomi sopra sono sufficienti. Consideriamo il programma:

...
A[i] = 12
...

Annotiamo questo programma:

...
@ {0<i<A_length}
A[i] = 12
...

dove A_lengthè una variabile che specifica la lunghezza dell'array. Ora prova a provare l'annotazione - vale a dire, elaborala all'indietro (dal basso verso l'alto, "come al solito" nelle prove Hoare). Se in cima ottieni {false}, allora può succedere l'accesso fuori limite, altrimenti l'espressione che hai è la condizione preliminare in base alla quale non sono possibili accessi fuori limite. (inoltre, dobbiamo assicurarci che quando l'array viene creato come int A=int[10];allora nella post-condizione che abbiamo {A_length==10}).


I tuoi assiomi non modellano l'accesso fuori limite: non menzionano nemmeno la lunghezza! Nel programma di esempio, come ti rapporti lengtha A?
Gilles 'SO- smetti di essere malvagio' il

Giusto, gli assiomi non modellano da accessi limitati. Innanzitutto, per dimostrare che un programma è corretto, aggiungo annotazioni che richiedono che un accesso sia all'interno dei limiti. (è lengthstato rinominato A_length.) In secondo luogo, abbiamo bisogno di assiomi di "creazione" simili int[] a = int[length] {a_length==length}. Penso che questo dovrebbe essere abbastanza.
Ayrat,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.