Cómo lidiar con matrices durante las pruebas de corrección de estilo Hoare

11

En la discusión sobre esta pregunta , Gilles menciona correctamente que cualquier prueba de corrección de un algoritmo que usa matrices tiene que demostrar que no hay accesos de matriz fuera de los límites; dependiendo del modelo de tiempo de ejecución, esto provocaría un error de tiempo de ejecución o acceso a elementos que no sean de matriz.

Una técnica común para realizar tales pruebas de corrección (al menos en estudios de pregrado y probablemente en verificación automática) es mediante el uso de la lógica de Hoare . No soy consciente de que el conjunto estándar de reglas contiene algo relacionado con las matrices; parecen estar restringidos a variables monádicas.

Me imagino agregando axiomas de la forma

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

Sin embargo, no es claro cómo se abordaría un acceso a la matriz en el lado derecho, es decir, si es parte de una expresión compleja de alguna declaración .Ex:=E

¿Cómo se pueden modelar los accesos de matrices en la lógica de Hoare para que la ausencia de accesos no válidos pueda y deba probarse para la corrección del programa?

Las respuestas pueden suponer que no permitimos que los elementos de la matriz se utilicen en declaraciones que no sean o como parte de alguna en ya que esto no restringe la expresividad; siempre podemos asignar a una variable temporal el valor deseado, es decir, escribir lugar de .A[i]:=EEx:=Et:=A[i]; if(t>0)if(A[i]>0)

Rafael
fuente

Respuestas:

8

Su axioma no es realmente un axioma, le faltan hipótesis. Las presentaciones simples de lógica de Hoare manipulan fórmulas de la forma donde y son fórmulas lógicas y es un comando. Es necesario asegurarse de que esté bien formado . En lenguajes simples como los que se usan a menudo para una primera introducción a la lógica de Hoare, la buena formación es sintáctica: generalmente es cuestión de verificar que{P}C{P}PPCCCse ajusta a una gramática libre de contexto y posiblemente a que las variables libres están dentro de un conjunto permitido. Si el lenguaje incluye construcciones que tienen una corrección semántica, como los accesos a los elementos de la matriz, debe agregar hipótesis para expresar esta corrección semántica.

Formalmente, puede agregar juicios para expresar la corrección de expresiones y comandos. Si las expresiones no tienen efectos secundarios, no necesitan condiciones posteriores, solo condiciones previas. Por ejemplo, puede escribir reglas de buena forma, como y solo permite expresiones bien formadas en los comandos:

{P}E wf{P0E<length(A)}A[E] wf{P}E1 wf{P}E2 wf{P}E1+E2 wf
{P[xE]}E wf{P[xE]}x:=E{P}

Un enfoque diferente es tratar todas las expresiones como bien formadas, pero hacer que cualquier expresión que implique un cálculo mal formado tenga un valor especial . En idiomas con comprobación de límites de tiempo de ejecución, significa que "este programa generó una excepción fatal". A continuación, haría un seguimiento de si un programa se equivocó a través de un predicado lógico ; un programa solo es válido si puede probar que su condición posterior implica . errorerrorError¬Error

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

Otro enfoque es considerar un Hoare triple para mantener solo si el programa termina correctamente. Este es el enfoque habitual para los programas que no terminan: la condición posterior se cumple cuando finaliza el comando, lo que puede no ocurrir siempre. Si trata los errores de tiempo de ejecución como no terminación, barre todos los problemas de corrección bajo el capó. Aún tendrá que demostrar la corrección del programa de alguna manera, pero no es necesario que esté en la lógica de Hoare si prefiere algún otro formalismo para esa tarea.

Por cierto, tenga en cuenta que expresar lo que sucede cuando se modifica una variable compuesta, como una matriz, está más involucrado que lo que escribió. Supongamos que era, por ejemplo, : la sustitución no cambiaría , sin embargo, la asignación podría invalidar . Incluso si restringe la sintaxis de los predicados para hablar solo de átomos, considere la asignación bajo la condición previa : no puede hacer una simple sustitución para obtener la condición posterior correcta , necesita evaluarPIsSorted(A)A[i]EPA[i]PPA[A[0]1]:=A[0]A[0]=2A[1]=3A[0]=1A[1]=1A[0](lo que puede ser difícil en general, ya que la condición previa podría no especificar un solo valor posible para ). realizar la sustitución en la matriz: . Las notas de clase de Mike Gordon tienen una buena presentación lógica de Hoare con matrices (pero sin verificación de errores).A[0]AA[iE]

Gilles 'SO- deja de ser malvado'
fuente
0

Como lo mencionó Gilles, hay un axioma de asignación de matriz (ver las notas de Gordon, Sec. 2.1.10 ): En palabras, si tiene una asignación de matriz, reemplace la matriz original por la matriz que tiene en la posición el valor . Tenga en cuenta que si ya tiene en la publicación, y asigne , entonces debe obtener el pre (sí, en este orden: ¡la actualización reciente se ejecuta primero!).

{Q[AA.store(i,expr)]}A[i]=expr{Q}
A.store(i,expr)iexprA.store(i,vi)A[j]=vjA.store(j,vj).store(i,vi)

Además, necesitamos el axioma de acceso a conjunto: A.store(i,v)[i]puede ser sustituido por v( "si tiene acceso a -ésimo elemento que acaba de actualizar, a continuación, devolver el valor asignado").i

Creo que para probar que un programa con matrices es correcto ("sin accesos fuera de límite"), los axiomas anteriores son suficientes. Consideremos el programa:

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

Anotaríamos este programa:

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

donde A_lengthes una variable que especifica la longitud de la matriz. Ahora intente probar la anotación, es decir, trabaje hacia atrás (de abajo hacia arriba, "como de costumbre" en las pruebas de Hoare). Si en la parte superior se obtiene {false}, puede ocurrir el acceso fuera del límite, de lo contrario, la expresión que se obtiene es la condición previa bajo la cual no es posible el acceso fuera del límite. (también, debemos asegurarnos de que cuando se crea una matriz como int A=int[10];entonces en la condición posterior que tenemos {A_length==10}).

Ayrat
fuente
Sus axiomas no modelan el acceso fuera de límites: ¡ni siquiera mencionan la longitud! En el programa de ejemplo, ¿cómo se relaciona lengtha A?
Gilles 'SO- deja de ser malvado'
Correcto, los axiomas no se modelan a partir de accesos vinculados. Primero, para probar que un programa es correcto, agrego anotaciones que requieren que el acceso esté dentro de los límites. ( lengthse renombró A_length). Segundo, necesitamos axiomas de "creación" de matriz como int[] a = int[length] {a_length==length}. Creo que esto debería ser suficiente.
Ayrat