Anda di halaman 1dari 26

TEMA 6.- VERIFICACION DE PROGRAMAS IMPERATIVOS 6.1.- Lgica de Hoare. o Desarrollada por C.A.R.

Hoare (1969), es una lgica que permite probar la o verdad o falsedad de propiedades de programas imperativos (especialmente correccin y terminacin) sin concurrencia o paralelismo. o o Basada en la idea de diagrama de ujo anotado.

S es una frase de cdigo en un programa de alto nivel, con una unica o entrada y una unica salida normal. Instruccin. o Bloque de instrucciones consecutivas. Un programa o subprograma. Cada frase S denota una relacin entre dos estados en un espacio o de estados denido por el producto cartesiano de los valores de las variables del programa. Es decir, al ejecutar una instruccin o secuencia de o instrucciones S, se modica el valor de una o varias variables, transitando de un estado a otro. P y Q son anotaciones, frmulas de la Lgica de Primer Orden (Lgica o o o de Predicados). P Precondicin (se reere al estado previo a S) o Q Postcondicin (se reere al estado posterior a S) o Notacin : {P }S{Q} o Signicado: Correccin parcial: si la precondicin P es cierta antes de ejecutar la frase o o de programa S, y la ejecucin termina normalmente, la postcondicin Q o o es cierta. |=par {P }S{Q} Correccin total: si la precondicin P es cierta antes de la ejecucin de la o o o frase de programa S, esta termina y la postcondicin Q es cierta. o |=tot {P }S{Q}
1

En la correccin parcial, la frase S debe terminar normalmente. Existen dos o posibles fuentes de terminacin anormal: o Bucle innito. Error de ejecucin (divisin entre cero, overow, . . . ). o o Correccion total implica correccin parcial. Sin embargo, en muchas ocasiones o se demuestra primero la segunda y, a partir de ella la primera. En Lgica de Hoare se utilizan dos lenguajes formales: o Un lenguaje de programacin imperativo (LP) para S. o Un lenguaje de frmula (LF) para P y Q. En LF se usan los tipos (enteros, o booleanos, reales, . . . ), funciones (suma de enteros, suma de reales...) y predicados(<, >, , . . . ) usados en el LP, inclu dos los denidos por el usuario. Para hacer pruebas sobre Lgica de Hoare presentaremos un mtodo de o e prueba sintctico. Primero veremos como demostrar si una tripla {P }S{Q} a es derivable para la condicin de correccin parcial o o par {P }S{Q} y despus presentaremos las condiciones necesarias para tener correccin total. e o tot {P }S{Q} Puede demostrarse (aunque no lo haremos, podeis respirad tranquilos) la coherencia de las pruebas, mientras que la compleccin se cumplir slo en o a o determinadas circunstancias, tanto con correccin parcial como total. o coherencia par {P }S{Q} |=par {P }S{Q} par {P }S{Q}

compleccion |=par {P }S{Q}

Sea S un programa y P su precondicin, {P }S{F also} signica que S nunca o termina cuando se comienza en P . Se trata de un problema indecidible (no se puede demostrar siempre), de modo que la lgica de Hoare no es completa. o

6.1.1.- Reglas para la correccin parcial. o Asignacin: o {P [E/x]} x = E {P } Si el estado inicial es s, entonces el estado s despus de la asignacin es e o igual a s, sustituyendo la variable x por el resultado de evaluar E. Si s satisface P (la hace cierta), la frmula que satisfar s ser P [E/x], o a a el resultado de sustitu todas las ocurrencias libres de x en P por E. r Ejs.- {y + 5 = 10} y = y + 5 {y = 10} {y + y < z} x = y {x + y < z} {2 (y + 5) > 20} y = 2 (y + 5) {y > 20} Composicin: o {P }S1 {Q} {Q}S2 {R} {P }S1 ; S2 {R} Aplica la transitividad sobre dos frases para poder obtener la pre y postcondiciones de la concatenacin de ambas. o Instruccin if: o {P B}S1 {Q} {P B}S2 {Q} {P }if B then S1 else S2 {Q} Si ambos bloques S1 y S2 tienen la misma postcondicin Q, mientras que o la conjuncin de la frmula P con la condicin B y, respectivamente, con o o o su negacin B, son sus precondiciones, P aparece como precondicin de o o la bifurcacin y Q como su postcondicin. o o Las condiciones del LP (normalmente expresiones booleanas) deben ser importadas como parte de las frmulas lgicas de las anotaciones (en este o o caso precondiciones). While parcial: {P B}S{P } {P }while B do S{P B} Se trata de la regla que permite calcular las pre y post condiciones de un bucle while satisfaciendo la propiedad de correccin parcial. o Si la conjuncin de las condiciones P y B es la precondicin de S y P es su o o postcondicin, quiere decir que cuando P y B son ciertas, P ser cierto tras o a la ejecucin de S. Por lo tanto, si B es la ondicin del bucle while podemos o o demostrar que, siendo cierta la precondicin P , se cumple la postcondicin o o P B, dado que P era postcondicin de la(s) instruccion(es) S del interior o del bucle y B debe cumplirse para salir del while.
3

Reforzamiento de la precondicin (implicacin izda.): o o R P {P }S{Q} {R}S{Q} Esta regla permite asumir una precondicin ms fuerte que la existente, o a de ser necesario, sin perder la correccin de la demostracin del programa o o anotado. Permite importar pruebas de la lgica de predicados (concretamente o R P ). Debilitamiento de la postcondicin (implicacin dcha.): o o {P }S{Q} Q R {P }S{R} Esta regla permite asumir una postcondicin ms dbil que la existente, o a e de ser necesario, sin perder la correccin de la demostracin del programa o o anotado. Permite importar pruebas de la lgica de predicados (concretamente o Q R). Otras: (conjuncin) o conjuncin o inversa {P }S{Q1 } {P }S{Q2 } {P }S{Q1 Q2 } {P }S{Q1 Q2 } {P }S{Qi } (disyuncin) o {P1 }S{Q} {P2 }S{Q} {P1 P2 }S{Q}

disyuncin o inversa

{P1 P2 }S{Q} i {1, 2} {Pi }S{Q}

6.1.2.- Correccin parcial. o Partiendo de una especicacin (una postcondicin y posiblemente alguna o o precondicin), se trata de demostrar, utilizando las reglas anteriores (y algunas o otras que no hemos visto) que el programa verica dicha especicacin. o Generalmente, tras unas pocas l neas de cdigo, la prueba se hace demasiado o compleja para poder representarla en forma de inferencias encadenadas. Para resolver este problema se intercalan las anotaciones del LF entre las l neas del LP. Dado S S1 ; S2 ; . . . ; Sn , si queremos demostrar que {P0 }S{Pn }, basta demostrar que: {P0 }S1 {P1 } {P1 }S2 {P2 }
4

...

{Pn1 }Sn {Pn }

y usar la regla de la composicin n 1 veces. o De este modo, podemos representar la prueba de {P0 }S{Pn } como: {P0 } S1 {P1 } S2 ... {Pn1 } Sn {Pn } anotacin o anotacin o anotacin o anotacin o

Las frmulas P1 , . . . , Pn1 sern condiciones intermedias y cada paso o a {Pi1 } Si {Pi } ser obtenido a travs de alguna de las reglas anteriores. a e El proceso de prueba para un bloque o programa S S1 ; S2 ; . . . ; Sn se produce de abajo a arriba (desde el n hacia el principio del bloque o programa) debido a la naturaleza de la regla de la asignacin. En general, comenzamos con la o postcondicin Pn y se utiliza Sn para obtener Pn1 . o Obtener Pi1 a partir de Pi y Si es mecnico para las asignaciones y las a instrucciones if. La Pi1 obtenida de esa manera se denomina la precondicin o ms dbil para Si y Pi , lo que quiere decir que que Pi1 es la frmula lgica a e o o ms dbil que siendo verdadera al principio de la ejecucin de Si garantiza la a e o veracidad de la postcondicin Pi . o
Al nal del proceso, obtenemos una frmula P0 al principio de la secuencia, que o garantiza que al ejecutar S se verica la postcondicin Pn . Debemos chequear o si P0 puede obtenerse a partir de la precondicin P0 mediante la regla de o reforzamiento de la precondicin. o En este caso, deber amos demostrar que P0 P0 , usando cualquiera de los sistemas deductivos de lgica de predicados. En general, ese tipo de o demostraciones, que aparecen al usar las dos reglas de la implicacin, suelen o omitirse en la secuencia de anotaciones e instrucciones. Si se demuestra que P R, la prctica habitual es simplemente escribir la segunda condicin a o debajo de la primera. {P } {R} S {Q}

Para la calcular la precondicin ms dbil P para un if a partir de una o a e prostcondicin Q o {P } if B then S1 else S2 {Q} suele precederse del siguiente modo: 1. Se obtiene la precondicin P1 a partir de Q y S1 . o 2. Se obtiene la precondicin P2 a partir de Q y S2 . o 3. P (B P1 ) ( B P2 ) Recordemos el while parcial: {P B}S{P } {P }while B do S{P B} Si tenemos una precondicin R y una postcondicin Q, y queremos demostrar: o o |=par {R}while B do S{Q} Debemos encontrar una frmula P del LF que verique: o 1. R P (para el reforzamiento de la precondicin) o 2. P B Q (para el debilitamiento de la postcondicin) o 3. |=par {P }while B do S{P B} (regla while parcial) A la frmula P vericando lo anterior se le denomina invariante. o Encontrar invariantes requiere cierto ingenio (puede haber muchas diferentes para un mismo bucle), aunque hay reglas heur sticas: 1. Comenzar modicando la postcondicin del while para hacerla o dependiente del ndice del bucle (la variable que crece o decrece en cada iteracin). o 2. Si la invariante P an no verica P B Q, debemos reforzar P para u que se cumpla. 6.1.3.- Correccin total. o Lo anterior slo prueba la correccin parcial de las triplas {P }S{Q}, es decir, o o slo es cierto cuando S termina normalmente. o Hab amos visto dos posibles razones para la no terminacin: error de ejecucin o o y bucle innito. La primera est cubierta por el sistema de clculo que ya a a hemos descrito.
6

Por lo tanto, asegurar la correccin total implica asegurar la correccin parcial o o y la terminacin de los bucles while. o Podemos obtener la prueba de terminacin si podemos, a partir de las variables o de los estados del bucle, encontrar una expresin entera que disminuya en cada o iteracin del bucle mantenindose no negativa (0 o positiva). o e Si tal expresin existe, en bucle termina despus de un nmero nito de o e u iteraciones, ya que no hay cadenas descendentes innitas de enteros positivos (lgebra bsica). a a A la expresin entera mencionada se le denomina variante. o De este modo obtenemos una regla del while total: {P B (0 E = E0 )} S {P (0 E < E0 )} {P (0 E)} while B do S {P B} E es la variante, que decrece en cada iteracin. Si E = E0 antes de cada o iteracin del bucle, es estrictamente menor despus. Si existen instrucciones o e antes del bucle y queremos calcular sus anotaciones a partir de la precondicin o del while, debemos utilizar la precondicin del while. o La aplicacin de esta regla es equivalente a la utilizacin de la regla del while o o parcial y la demostracin de las siguientes frmulas: o o P B E >0 y {P B E = E0 }S{E < E0 }

6.1.4.- Compleccin relativa. o Para una frmula P y una frase S, sea post(P, S), la frmula ms fuerte para o o a la cual {P }S{post(P, S)}, tenemos que: Si {P }S{Q} entonces post(P, S) Q Para una frmula Q y una frase S, sea pre(S, Q), la frmula ms dbil para la o o a e cual {pre(S, Q)}S{Q}, tenemos que: Si {P }S{Q} entonces P pre(S, Q) Supongamos que: 1. post(P, S) existe para cada P y S. 2. pre(S, Q) existe para cada S y Q. 3. Las implicaciones post(P, S) Q o P pre(S, Q) pueden demostrarse.
7

Entonces cualquier tripla {P }S{Q} podr ser demostrada, es decir, se a vericar la propiedad de compleccin: a o |=par {P }S{Q} par {P }S{Q} Pero sabemos que no es el caso. Por lo tanto, la no compleccin de la lgica o o de Hoare no surge de ella misma, sino de la indecidibilidad de la lgica de o predicados ms los axiomas de la aritmtica (teorema de Gdel). a e o 6.1.5.- Arrays y Procedimientos El uso de arrays en anotaciones presenta complicaciones extra, debido al hecho de que las condiciones involucran tanto a los ndices como al contenido de los arrays. En el siguiente ejemplo podemos ver como una tripla supuestamente correcta no lo es: {x[1] = 1 x[2] = 3}x[x[1]] = 2{x[x[1]] = 2} Al cambiar el valor de x[1] la asignacin cambia tambin el valor de x[x[1]]. o e La solucin es hacer una regla anloga a la de la asignacin pero tratando a o a o los arrays como elementos completos. Para ello, primero hacemos la denicin de la asignacin en arrays. El array o o resultante de hacer la asignacin x[e1 ] = e2 se dene como: o (x; e1 : e2 )[e3 ] = Regla de asignacin sobre arrays o {P [(x; e1 : e2 )/x]} x[e1 ] = e2 {P } En cuanto a las llamadas a procedimientos, si estos son no recursivos, las precondiciones y postcondiciones deducidas para el cdigo del procedimiento o son heredadas en cada llamada. Sea h(x1 , . . . , xm ; y1 , . . . , yn ) = S, donde xi son las variables libres en P y asignadas en en el cdigo S del procedimiento, mientras que yj son las variables o libres no asignadas en S. {P } S {Q} {P } h(x1 , . . . , xm ; y1 , . . . , yn ) {Q}
8

e2 si e1 = e3 x[e3 ] en otro caso

En el caso de procedimientos recursivos, para demostrar la correccin o parcial, podemos utilizar la precondicin y postcondicin esperadas para o o el procedimiento en la demostracin. Esto es, denimos tales condiciones o previamente a la prueba de correccin, utilizndolas en dicha prueba para las o a llamadas recursivas. {P } h(x1 , . . . , xm ; y1 , . . . , yn ) {Q} . . . {P } S {Q} {P } h(x1 , . . . , xm ; y1 , . . . , yn ) {Q} 6.1.6.- Ejemplos I.- Divisin Entera o {x 0 y 0} a = 0; b = x; while b y do b = b y; a = a + 1; od {x = a y + b b 0 b < y} 1) El programa consta de dos asignaciones y un bucle. Calcularemos las anotaciones de abajo a arriba utilizando las reglas de la asignacin y de la o composicin. Por lo tanto, el primer paso ser calcular la invariante del bucle. o a Se trata de una frmula P que verica: o {P }while B do S{P B} Una buena heur stica es partir de la postcondicin del programa. As la o , invariante podr ser x = a y + b b 0. a 2) Vamos a intentar demostrar dicha invariante. Para ello, con el objetivo de poder utilizar la regla del while parcial, intentamos demostrar {P B}S{P } donde P es la invariante y B es la condicin del bucle. El primer paso es aplicar la o regla de la asignacin: o {x = (a + 1) y + b b 0} a = a + 1; {x = a y + b b 0} 3) Seguimos aplicando la asignacin a la instruccin inmediatamente anterior: o o {x = (a + 1) y + b y b y 0} b = b y; {x = (a + 1) y + b b 0}
9

4) Composicin de 2) y 3): o {x = (a + 1) y + b y b y 0} b = b y; a = a + 1; {x = a y + b b 0} 5) Utilizando las reglas del while parcial y del reforzamiento de la precondicin, o podemos demostrar que {P B}S{P } si demostramos que: (x = a y + b b 0 b y) (x = (a + 1) y + b y b y 0) lo que es fcil si tenemos en cuenta que si b y entonces b y 0 y, adems: a a x = (a + 1) y + b y = a y + y + b y = a y + b 6) Ahora estamos en condiciones de utilizar la regla del while parcial para demostrar: {x = a y + b b 0} while b y do b = b y; a = a + 1; od {x = a y + b b 0 b < y} 7) Partiendo de la invariante, podemos seguir ascendiendo en el programa usando la regla de la asignacin: o {x = a y + x x 0} b = x; {x = a y + b b 0} 8) Aplicamos la regla de la asignacin otra vez: o {x = 0 y + x x 0} a = 0; {x = a y + x x 0} 9) Composicin sobre 7) y 8): o {x = 0 y + x x 0} a = 0; b = x; {x = a y + b b 0} 10) Composicin sobre 6) y 9): o {x = 0 y + x x 0} a = 0; b = x; while b y do b = b y; a = a + 1; od {x = a y + b b 0 b < y}
10

11) Como la postcondicin del bucle coincide con la del programa unicamente nos o queda por demostrar la precondicin gracias a la regla de reforzamiento de la o precondicin. En particular, debemos demostrar que: o (x 0 y 0) (x = 0 y + x x 0)} lo que resulta obvio. Con ello, habr amos demostrado la correccin parcial o (debido a la regla que hemos utilizado en el while) de este programa. Demostrar la correccin total es imposible, a no ser que incorporemos y > 0 como o precondicin del programa. o Al nal, podemos resumir la demostracin intercalando las anotaciones en el o programa: {x 0 y 0} {x = 0 y + x x 0} a = 0; {x = a y + x x 0} b = x; {x = a y + b b 0} while b y do {x = (a + 1) y + b y b y 0} b = b y; {x = (a + 1) y + b b 0} a = a + 1; {x = a y + b b 0} od {x = a y + b b 0 b < y} II.- Potencia de enteros {m 0 n > 0} // con n > 0 evitamos el caso 00 r = 1; i = 0; while i < m do r = r n; i = i + 1; od {r = nm } 1) De nuevo, el programa consta de dos asignaciones y un bucle. Calcularemos las anotaciones de abajo a arriba utilizando las reglas de la asignacin y de o la composicin, de modo que el primer paso ser calcular una invariante P , o a

11

vericando la regla del while parcial: {P B}S{P } {P }while B do S{P B} Una buena heur stica es partir de la postcondicin del programa, hacindola o e depender del ndice i del bucle. Teniendo en cuenta que i var de 0 a m, a una posibilidad es sustitu m por i en la postcondicin. As sabemos que la r o , invariante debe contener la condicin r = ni . Ahora bien, sabemos que al nal o la conjuncin entre la invariante y la negacin de la condicin del bucle (i m) o o o deben implicar a la postcondicin del programa para poder aplicar la regla o de debilitamiento de la postcondicin. Para poder demostrar esa implicacin, o o debemos demostrar que i = m a la salida del bucle. Dado que la negacin de la o condicin del while (que forma parte de su postcondicin) es m i, debemos o o inclu la frmula i m en la invariante del bucle. De este modo, la frmula r o o de la invariante ser a. {r = ni i m} 2) Adems, para probar la correccin total, necesitaremos una variante que se a o mantenga positiva y pero decrezca en cada iteracin del bucle. La eleccin ms o o a inmediata es m i. 3) Primero vamos a intentar demostrar la correccin del bucle. Aplicamos la regla o de la asignacin sobre {P (0 E < E0 )} donde P es la postcondicin y E o o es la variante. {r = ni+1 i + 1 m 0 m (i + 1) < E0 } i = i + 1; {r = ni i m 0 m i < E0 } 4) Aplicamos la regla de la asignacin sobre la instruccin inmediatamente o o anterior: {r n = ni+1 i + 1 m 0 m (i + 1) < E0 } r = r n; {r = ni+1 i + 1 m 0 m (i + 1) < E0 } 5) Composicin de 3) y 4): o {r n = ni+1 i + 1 m 0 m (i + 1) < E0 } r = r n; i = i + 1; {r = ni i m 0 m i < E0 }

12

6) Debemos demostrar que que se cumple la precondicin {P B(0 E = E0 )}. o Lo hacemos mediante la regla de reforzamiento de la precondicin aplicada o sobre la anotacin que hemos calculado en 5). Para ello, debemos demostrar: o (r = ni i m i < m 0 m i = E0 ) (r n = ni+1 i + 1 m 0 m (i + 1) < E0 ) Lo cual es fcil si tenemos en cuenta que: a 1. r n = ni n = ni+1 , lo que puede demostrarse a partir de r = ni . 2. i + 1 m se demuestra partiendo de i < m. 3. 0 m (i + 1) < E0 es inmediato a partir de 0 m i = E0 e i < m. 7) Ahora debemos propagar la precondicin del bucle hacia las intrucciones o precedentes aplicando la regla de la asignacin: o {r = n0 0 m 0 m} i = 0; {r = ni i m 0 m i} como 0 m est repetida en la reescritura de la variante y en la de la a invariante, la escribimos slo una vez a partir de ahora. o 8) Volvemos a aplicar la regla de asignacin: o {1 = n0 0 m} r = 1; {r = n0 0 m} 9) Aplicando la composicin sobre 7) y 8), obtenemos: o {1 = n0 0 m} r = 1; i = 0; {r = ni i m 0 m i} 10) Aplicamos la composicin sobre 6) y 9): o {1 = n0 0 m} P rograma {r = ni i m i m} 11) Ahora debemos demostrar que la precondicin del programa que jamos al o principio implica a la precondicin que hemos obtenido en 10), para poder o aplicar la regla de reforzamiento de la precondicin. Hay que demostrar que: o (m 0 n > 0) (1 = n0 0 m)} lo que podr hacer hasta un chimpanc no muy listo. a e

13

12) Lo unico que queda por demostrar es la postcondicin del programa, y podemos o hacerlo aplicando la regla de debilitamiento de la postcondicin: o {P }S{Q} Q R {P }S{R} donde Q ser la postcondicin del while, es decir, la conjuncin entre la a o o invariante y la negacin de la condicin del bucle, y R la postcondicin del o o o programa. Para que el antecedente de la regla se cumpla, debemos demostrar que: (r = ni i m i m) (r = nm ) A partir de i m y i m, demostramos que i = m y r = nm . En la demostracin anterior hemos optado por demostrar la correccin de la o o invariante y la variante del bucle while antes de constru las anotaciones de las r instrucciones del programa y demostrar su concordancia con la precondicin o de este. Podr fcilmente, sin menoscabo de la correccin en la demostracin, a a o o haber seguido el camino opuesto: vericar primero si la variante y la invariante de bucle permiten demostrar la precondicin y postcondicin del programa o o para comprobar despus que son correctas en el bucle while. e Otra opcin para demostrar la correccin total en el bucle hubiera sido o o demostrar primero el cumplimiento de la regla del while parcial y asegurar la correccin total del bucle. En este caso, necesitaremos una invariante algo o ms reforzada: a r = ni 0 i m 1) Propagamos la invariante de bucle hacia arriba mediante la regla de la asignacin en cada una de las instrucciones del bucle: o {r = ni+1 0 i + 1 m} i = i + 1; {r = ni 0 i m} {r n = ni+1 0 i + 1 m} r = r n; {r = ni+1 0 i + 1 m} Y aplicamos la regla de la composicin para obtener: o {r n = ni+1 0 i + 1 m} r = r n; i = i + 1; {r = ni 0 i m} 2) Demostraremos la correccin parcial utilizando la regla de reforzamiento de la o precondicin con P B (siendo P la invariante y B la condicin del bucle) o o y la precondicin que hemos calculado para las dos instrucciones del bucle. o Debemos ver si se verica: (r = ni 0 i m i < m) (r n = ni+1 0 i + 1 m) lo que, en efecto, es cierto (ver paso 6 en la demostracin anterior) o
14

3) Para vericar la correccin total, debemos demostrar lo siguiente: o P B E >0 y {P B E = E0 } S {E < E0 }

donde E es la variante y E0 una constante entera positiva. La implicacin, que o si es cierta demuestra que la variante es positiva al entrar en el bucle, es fcil a de demostrar: (r = ni 0 i m i < m) (m i > 0) dado que la condicin del bucle nos dice que i < m, y la invariante que o 0 i m. Demostrar esta implicacin es la razn por la cual necesitbamos o o a reforzar la invariante. Sin saber que m e i son positivos, es imposible demostrar que m i tambin lo es. e 4) En cuanto a {P B E = E0 } S {E < E0 } signica que la variante se decrementa en cada iteracin del bucle. Para demostrarlo, aplicamos la regla o de la asignacin en cada una de las instrucciones del bucle, ms la regla de la o a composicin. o {m (i + 1) < E0 } r = r n; i = i + 1; {m i < E0 } 5) Para demostrar que {P B E = E0 } es una precondicin de las instrucciones o del bucle, utilizamos la regla de reforzamiento de la precondicin. Debemos o vericar que: (r = ni 0 i m i < m m i = E0 ) (m (i + 1) < E0 ) lo que resulta obvio: si m i = E0 , entonces m (i + 1) < E0 . Con ello habr amos demostrado la correccin total en el bucle. o III.- Mximo comn divisor a u {x1 > 0 x2 > 0} y1 = x 1 ; y2 = x 2 ; while y1 = y2 do if y1 > y2 then y1 = y1 y2 ; else y2 = y2 y1 ; od {y1 = mcd(x1 , x2 )} 1) En este caso no podemos utilizar la heur stica de hacer la postcondicin o dependiente del ndice del bucle para obtener la invariante. Para empezar, no hay ndice del bucle. Necesitamos una expresin ms o menos concordante o a
15

con la postcondicin del programa pero que sea cierta en cada iteracin del o o bucle. Una buena posibilidad es mcd(y1 , y2 ) = mcd(x1 , x2 ). Como, adems, a tenemos intencin de demostrar la correccin total y la variante ms sencilla o o a posible es y1 + y2 , es buena idea inclu en la invariante y1 > 0 y2 > 0. r P = {mcd(y1 , y2 ) = mcd(x1 , x2 ) y1 > 0 y2 > 0} E = {y1 + y2 } 2) Utilizaremos la regla del while total: {P B (0 E = E0 )} S {P (0 E < E0 )} {P (0 E)} while B do S {P B} La postcondicin ser: o a {mcd(y1 , y2 ) = mcd(x1 , x2 ) y1 > 0 y2 > 0 0 y1 + y2 < E0 } Propagamos la variante a travs de ambas opciones del bucle, usando la regla e de la asignacin: o {mcd(y1 y2 , y2 ) = mcd(x1 , x2 ) y1 y2 > 0 y2 > 0 0 y1 < E0 } y1 = y1 y2 ; {mcd(y1 , y2 ) = mcd(x1 , x2 ) y1 > 0 y2 > 0 0 y1 + y2 < E0 } {mcd(y1 , y2 y1 ) = mcd(x1 , x2 ) y2 y1 > 0 y2 > 0 0 y2 < E0 } y2 = y2 y1 ; {mcd(y1 , y2 ) = mcd(x1 , x2 ) y1 > 0 y2 > 0 0 y1 + y2 < E0 } 3) Utilizamos la regla del if: {R Bif }S1 {Q} {R Bif }S2 {Q} {R}if Bif then S1 else S2 {Q} donde R ser la precondicin de las sentencias del bucle en la regla del while a o total: {P B (0 E = E0 )}, siendo P la invariante y E la variante del bucle while. Utilizamos la regla del reforzamiento de la precondicin, con lo o que debemos demostrar dos implicaciones: Para el then: (P B (0 E = E0 ) Bif ) Precondicin para S1 o (mcd(y1 , y2 ) = mcd(x1 , x2 ) y1 > 0 y2 > 0 y1 = y2 0 y1 + y2 = E0 y1 > y2 ) (mcd(y1 y2 , y2 ) = mcd(x1 , x2 ) y1 y2 > 0 y2 > 0 0 y1 < E0 ) mcd(y1 y2 , y2 ) = mcd(x1 , x2 ) se demuestra a partir de y1 > y2 y mcd(y1 , y2 ) = mcd(x1 , x2 ).
16

y1 y2 > 0 se demuestra teniendo en cuenta que y1 > 0, y2 > 0 y y1 < y2 . y2 > 0 est presente en al antecedente de la implicacin. a o 0 y1 < E0 dado que 0 y1 + y2 = E0 e y2 > 0. Para el else: (P B (0 E = E0 ) Bif ) Precondicin para S2 o (mcd(y1 , y2 ) = mcd(x1 , x2 ) y1 > 0 y2 > 0 y1 = y2 0 y1 + y2 = E0 y1 y2 ) (mcd(y1 , y2 y1 ) = mcd(x1 , x2 ) y1 > 0 y2 y1 > 0 0 y2 < E0 ) mcd(y1 , y2 y1 ) = mcd(x1 , x2 ) se demuestra a partir de y1 < y2 (dado que y1 y2 e y1 = y2 ) y mcd(y1 , y2 ) = mcd(x1 , x2 ). y2 y1 > 0 se demuestra teniendo en cuenta que y1 > 0, y2 > 0 e y1 < y2 , dado que y1 y2 e y1 = y2 . y1 > 0 est presente en al antecedente de la implicacin. a o 0 y2 < E0 dado que 0 y1 + y2 = E0 e y1 > 0. 4) Con lo anterior hemos demostrado el antecedente de la regla del while total. Propagamos la precondicin en el consecuente (P (0 E)) hacia arriba, o siendo P la invariante y E la variante. Para ello, utilizaremos la regla de la asignacin: o {mcd(y1 , x2 ) = mcd(x1 , x2 ) y1 > 0 x2 > 0 0 y1 + x2 } y2 = x 2 ; {mcd(y1 , y2 ) = mcd(x1 , x2 ) y1 > 0 y2 > 0 0 y1 + y2 } 5) Otra vez la regla de la asignacin: o {mcd(x1 , x2 ) = mcd(x1 , x2 ) x1 > 0 x2 > 0 0 x1 + x2 } y1 = x1 ; {mcd(y1 , x2 ) = mcd(x1 , x2 ) y1 > 0 x2 > 0 0 y1 + x2 } 6) Y la regla de la composicin: o {mcd(x1 , x2 ) = mcd(x1 , x2 ) x1 > 0 x2 > 0 0 x1 + x2 } y1 = x1 ; y2 = x2 ; {mcd(y1 , y2 ) = mcd(x1 , x2 ) y1 > 0 y2 > 0 0 y1 + y2 } 7) La regla de la composicin otra vez, para 6) y 4). o {mcd(x1 , x2 ) = mcd(x1 , x2 ) x1 > 0 x2 > 0 0 x1 + x2 } P rograma {mcd(y1 , y2 ) = mcd(x1 , x2 ) y1 > 0 y2 > 0 y1 = y2 }
17

8) Demostramos la precondicin del programa usando la regla de reforzamiento o de la precondicin: o (x1 > 0x2 > 0) (mcd(x1 , x2 ) = mcd(x1 , x2 )x1 > 0x2 > 00 x1 +x2 ) lo que resulta evidente. 9) Finalmente, demostramos la postcondicin del programa a partir de la o postcondicin del while {P B}, donde P es la invariante y B la condicin o o del while, (mcd(y1 , y2 ) = mcd(x1 , x2 ) y1 > 0 y2 > 0 y1 = y2 ) (y1 = mcd(x1 , x2 )) fcilmente demostrable, dado que si y1 = y2 entonces y1 = mcd(y1 , y2 ). a

18

6.2.- La herramienta why Herramienta que demuestra la adecuacin entre un programa con su o especicacin, basada en lgica de Hoare. o o El LP es un dialecto del ML (una sintaxis prxima a Caml). o Uso de anotaciones para expresar la especicacin. o La salida es un chero con obligaciones de prueba (objetivos a demostrar) para varios demostradores de teoremas: Coq, PVS, Isabelle/HOL, HOL 4, HOL Light, Mizar, Simplify, haRVey y CVC Lite. El invocacin en l o nea de comandos: why fichero.mlw e da como resultado un chero foo why.v para el intrprete Coq, con los objetivos que deben demostrarse para garantizar la correccin del programa o anotado. Tambin se puede generar cdigo Caml: e o why --ocaml fichero.mlw En este caso, no se generan obligaciones de prueba, sino que se genera cdigo o Caml correspondiente al programa en la salida estndas (o en un chero con a la opcin --output). o La opcin --ocaml-annot permite preservar en el cdigo Caml generado las o o anotaciones presentes en fichero.mlw en forma de comentarios. Tambin se proporciona una herramienta para convertir cheros why a HTML: e why2html [-t titulo] fichero.mlw obteniendo como resultado un chero HTML fichero.mlw.html. 6.2.1.- Lenguaje de programacin o Los cheros de entrada presentan la siguiente sintaxis: let x = programa anotado Declara una expresin de programa con nombres. El programa es aadido al o n contexto actual y se generan las consiguientes en obligaciones de prueba. let c = 1+2 let f = fun (x:int ref) -> x := !x + c

19

parameter x1 , . . . , xn : Declara parmetros que sern convertidos en axiomas en el demostrador de a a teoremas. parameter x,y : int ref parameter N : int parameter t : int array El prejo external indica que x1 , . . . , xn estn ya denidas en el lado del a demostrador. external parameter mean : int -> int -> int external parameter diff : a:int -> b:int -> { b >= 0 } int { a = b + result } exception E [of ] Declara una nueva excepcin E con un argumento de tipo . o logic x1 , . . . , xn : 1 , . . . , m > Permite introducir los s mbolo lgicos x1 , . . . , xn , que son predicados (si es o Prop), constantes (si m = 0) o s mbolos de funciones. logic max : int,int -> int logic is_int : real -> prop El prejo external tambin puede ser usado, con el mismo signicado que en e parameter. predicate p(x1 : 1 , . . . , xn : n ) = predicado Dene un predicado p. predicate ge0(x:int, y:int) = x >= y >= 0 function f (x1 : 1 , . . . , xn : n ) : = term Dene una funcin lgica f . o o function f(x:int, y:int) : int = x + y axiom x : predicado Declara un axioma de nombre x. axiom max_1 : forall x:int. forall y:int. max(x,y) >= x

20

6.2.2.- Anotaciones La anotaciones de escriben con la sintaxis de lgica de predicados que es o independiente el demostrador de teoremas utilizado. Se trata de predicados sobre los valores de las variables del programa visibles en la posicin del o programa en la que se escriben. Las pre y postcondiciones son escritas usando la sintaxis tradicional de la lgica o de Hoare: {predicado} expresion {predicado} Dentro de una tripla, la pre o postcondiciones pueden ser omitidas. Dentro de una postcondicin, el valor de la referencia x antes de la evaluacin (en el o o punto de la precondicin) es referenciado como x@. o { } begin x := !x + 1 end { x > x@ } { x > 0 } begin x := 2 * !x; x := !x - 1 end { x > 0 } En la postcondicin de unn programa o funcin el resultado est contenido en o o a la variable result. { } 1 + 2 { result = 3 } { } begin x := !x + 1; !x end { result <> x@ } La precondicin de un programa o cuerpo de funcin es una hiptesis que se o o o deber demostrar cierta cuando el programa o funcin son llamados, como x=0 a o en: let f (u:unit) = { x = 0 } x := x + 1 { x = 1 } En cambio, las precondiciones ms internas son obligaciones de prueba, que a debern ser demostradas en estado del programa correspondiente. a let f (u:unit) = {} begin x := 0; { x = 0 } x := x + 1 {} end { x = 1 } No todas las anotaciones para las pre y postcondiciones tienen que ser introducidas en el cdigo del programa, muchas de ellas son calculadas por o why. Dentro de una secuencia de instrucciones, aquellas anotaciones necesarias pueden ser introducidas por el comando assert. begin x := 2 * !x; assert { even(x) }; x := !x - 1; end
21

Para probar la correccin de los bucles, se puede asociar a ellos tanto o variantes como invariantes (las primeras son obligatorias y en muchos casos, ser necesario inclu las segundas). La forma de especicar ambas condiciones a r ser mediante una unica anotacin situada despus de la palabra clave do, y a o e las palabras reservadas variant e invariant. while expresion do { invariant predicado variant termino} secuencia done Por ejemplo: while !x > 0 do { invariant x >= 0 variant x } x := !x - 1 done while !x < 10 do { invariant x <= 10 variant 10-x } x := !x + 1 done Mientras que las invariantes son expresiones de la lgica de predicados, las o variantes pueden ser de cualquier tipo y pueden tener asociadas cualquier relacin de orden. Si no se especican, el tipo entero y la relacin de orden o o sobre los enteros se usarn por defecto. a Las funciones recursivas son anotadas con el tipo del resultado y una variante: let rec f91 (n:int) : int { variant max(0,101-n) } = {} if n <= 100 then (f91 (f91 (n + 11))) else n - 10 { (n <= 100 and result = 91) or (n >= 101 and result = n - 10) } Las variantes son como las utilizadas en los bucles. Se pueden insertar etiquetas en cualquier punto del programa usando la palabra clave label. Si se dene una etiqueta L, el valor de la variable x en la posicin o del programa denida por L, ser x@L. a begin x := y; label L; { } begin x := !x + 1 end { x > x@L } end

22

La visibilidad de una etiqueta es la misma que la de una variable local. La construccin absurd se puede utilizar para denotar un punto del cdigo o o inalcanzable. { 0 <= x <= 1 } if x = 0 then ... else if x = 1 then ... else absurd { ... } En estos puntos, el usuario deber demostrar que el contexto en, de hecho, a absurdo, lo que se corresponde con la obligacin de prueba false. o Las expresiones del programa tiene asociadas tipos, incluyendo efectos colaterales y especicacin. Este tipo es inferido por why para cada declaracin o o let, o dado por el usuario en las declaraciones parameter. La sintaxis de estos tipos es la t pica de los lenguajes funcionales, con sintaxis adicional para efectos colaterales y pre y postcondiciones. Tipos simples: int int -> int int -> int ref -> unit Con pre y postcondiciones: x:int -> y:int -> { } int { result = x + y } Con especicacin de efecto colateral: o
unit -> { x >= 0 } unit writes x { x < x@ } a:int ref -> b:int ref -> { } unit reads b writes a { a = a@ + b } n:int -> { } int raises Negative { result = sqrt(n) | Negative => n<0 }

Cambiando el nombre del resultado: x:int -> y:int -> { } returns z:int { z = x + y }

23

6.2.3.- Funciones predenidas Tanto para el LP como el LF. +, , , /, para enteros. add_int, sub_int, mul_int, div_int, mod_int : nat -> nat -> nat unario para enteros. neg_int : int -> int +, , , / para reales. add_real, sub_real, mul_real, div_real : real -> real -> real unario y ra cuadrada para reales. z neg_real, sqrt_real : real -> real Conversin de un entero en un nmero real. o u real_of_int : int -> real Tamao de un array. n array_length : array -> real Exclusivamente para el lenguaje de programacin o <, , >, , =, =, entre enteros. lt_int : x:int -> y:int -> {} bool {if result then le_int : x:int -> y:int -> {} bool {if result then gt_int : x:int -> y:int -> {} bool {if result then ge_int : x:int -> y:int -> {} bool {if result then eq_int : x:int -> y:int -> {} bool {if result then neq_int : x:int -> y:int -> {} bool {if result then
24

x < y else x >= y} x <= y else x > y} x > y else x <= y} x >= y else x < y} x = y else x <> y} x <> y else x = y}

<, , >, , =, =, entre reales, se denen con las mismas postcondiciones que para enteros. lt_real, le_real, gt_real, ge_real, eq_real, neq_real =, = para bool y unit, se denen con las mismas postcondiciones que para enteros y reales. eq_bool, neq_bool, eq_unit, neq_unit

6.2.4.- Predicados predenidos <, , >, , =, =, entre enteros. lt_int, le_int, gt_int, ge_int, eq_int, neq_int: int -> int -> prop <, , >, , =, =, entre reales. lt_real, le_real, gt_real, ge_real, eq_real, neq_real: real -> real -> prop =, =, entre booleanos. eq_bool, neq_bool : bool -> bool -> prop =, =, entre unit. eq_unit, neq_unit : unit -> unit -> prop sorted array(t, i, j) es cierto cuando el subarray t[i..j] est ordenado de forma a ascendente. sorted_array : int array -> int -> int -> prop exchange(t1 , t2 , i, j) es cierto cuando el array t1 es igual al array t2 intercambiando los elemantos con ndice i y j. exchange : int array -> int array -> int -> int -> prop

25

sub permut(t1 , t2 , i, j) es cierto cuando los subarrays t1 [i..j] y t2 [i..j] son permutaciones de uno en otro, siendo el resto de t1 y t2 iguales. sub_permut : int -> int -> int array -> int array -> prop permut(t1 , t2 ) es cierto cuando t1 y t2 son permutaciones de cada uno. permut : int array -> int array -> prop array id(t1 , t2 , i, j) es cierto cuando los subarrays t1 [i..j] y t2 [i..j] son idnticos. e array_id : int -> int -> int array -> int array -> prop

26