Está en la página 1de 17

UNIVERSIDAD NACIONAL MAYOR DE

SAN MARCOS
Universidad del Perú, DECANA DE AMÉRICA

VERIFICACIÓN FORMAL DE HOARE

CURSO : ANÁLISIS Y DISEÑO DE ALGORITMOS

PROFESOR : ESPINOZA DOMÍNGUEZ, Robert

INTEGRANTES :

 AZORSA SALAZAR, Stephanie


 CARHUARICRA MARCELO, Franz 17200317
 RODRIGUEZ LAZO, Carlos Manuel 17200263
 ROJAS CAMARGO, Melinna Victoria 17200118
 TUEROS HUAPAYA, Diego Rafael 17200106
17200099
Ciudad Universitaria, 31 de agosto de 2018
ÍNDICE

INTRODUCCIÓN.......................................................................................................................3
VERIFICACION FORMAL DE ALGORITMOS.......................................................................4
1. DEFINICIÓN...................................................................................................................4
2. TERNAS DE HOARE.....................................................................................................4
2.1 Precondiciones y Postcondiciones:...........................................................................4
3. REGLAS GENERALES RELATIVAS A LAS PRECONDICIONES Y
POSTCONDICIONES.............................................................................................................5
3.1. Fortalecimiento de las precondiciones......................................................................5
3.2. Debilitamiento de postcondiciones...........................................................................5
5.1. Regla de la conjunción.............................................................................................6
5.2. Regla de la disyunción..............................................................................................6
4. CONCEPTOS DE CORRECCIÓN..................................................................................6
5. VERIFICACIÓN DE CÓDIGOS SIN BUCLES..............................................................7
6.1. Verificación..............................................................................................................7
6.2. Regla de Asignación.................................................................................................7
6.3. Regla de Concatenación...........................................................................................8
6.4. Invariante de un código............................................................................................8
6. LA SENTENCIA IF.........................................................................................................9
7.1. Sin cláusula else.......................................................................................................9
7.2. Con cláusula else....................................................................................................10
7. BUCLES........................................................................................................................10
8.1. Variantes e invariantes de un Bucle........................................................................10
8.2. Bucle While............................................................................................................11
8.3. Bucle Repeat...........................................................................................................12
8.4. Determinación de la Corrección-Ejemplo...............................................................12
8. DOCUMENTACIÓN EN PSEUDOCÓDIGO...............................................................13
9. CORRECCIÓN TOTAL................................................................................................14
10. VERIFICACIÓN DE UN ALGORITMO RECURSIVO...............................................14
11.1. Corrección parcial...............................................................................................14
11.2. Corrección total..................................................................................................14
CONCLUSIONES.....................................................................................................................15
INTRODUCCIÓN

La lógica de Hoare es un sistema formal desarrollado por el científico C.A.R. Hoare en


1969. Esta se introdujo para poder verificar formalmente programas imperativos, es
decir para razón sobre la corrección de tales programas. De otra forma, permite
comprobar y demostrar que realmente un programa realizar las acciones para las que ha
sido diseñado. En algunas situaciones esto es de vital importancia, como lo sería en los
sistemas de seguridad presentes en vehículos (coches y aviones). Este propósito lógico
especial se obtiene a través de un lenguaje que contiene comandos básicos para el que
se construyen programas, el lenguaje determinista y una formulación con la que poder
expresar el comportamiento de los programas. Además, es necesario un conjunto de
reglas de cálculo para simplificar expresiones o inferir otras. Siendo así nuestro lenguaje
estaría formado por comandos como el de asignación, condicionales, bucles y una
composición secuencial de instrucciones.

4
VERIFICACION FORMAL DE ALGORITMOS

1. DEFINICIÓN
La verificación formal de programas consiste en un conjunto de técnicas de
comprobación formales que permiten demostrar si un programa funciona
correctamente.

 Programa que funciona correctamente: cumple con unas especificaciones


dadas.
 Técnicas de comprobación: La verificación consiste en un proceso de
inferencia. Por tanto, cada tipo de sentencia ejecutable posee una regla de
inferencia.
 Representación formal: Ternas de Hoare.

2. TERNAS DE HOARE

Si S es una parte del código, entonces cualquier aserción {P } se denomina


precondición de S si {P } sólo implica al estado inicial. Cualquier aserción {Q }
se denomina postcondición si {Q } sólo implica el estado final. Representación:
{P }S {Q }

2.1 Precondiciones y Postcondiciones:

 Las precondiciones indican las condiciones que deben satisfacer los datos de
entrada para que el programa pueda cumplir su tarea.
 Las postcondiciones indican las condiciones de salida que son aceptables
como soluciones correctas del problema en cuestión.
Ejemplo:
Programa que calcula la raíz cuadrada
 Precondición: Que el argumento de la función no sea negativo.
 Postcondición: La raíz cuadrada de ese argumento.

En la mayoría de los códigos el estado final depende del estado inicial. Por
tanto, Precondición y Postcondición no son independientes entre sí.

Si {P }S {Q } es un código con la precondición {P } y la postcondición {Q },


entonces {P }S {Q } es correcto si cada estado inicial posible que satisfaga {P }
da como resultado un estado final que satisface {Q }.

5
3. REGLAS GENERALES RELATIVAS A LAS PRECONDICIONES Y
POSTCONDICIONES
 Si R y S son dos aserciones entonces se dice que R es más fuerte que S si R ⇒ S.
Si R es más fuerte que S entonces se dice que S es más débil que R.
Ejemplo: m>2 es más fuerte que m>0 ya que siempre que m>2 implica que
m>0.(m>2=¿ m> 0).
 Si una aserción R es más fuerte que una aserción S entonces todos los estados
que satisfacen R también satisfacen S pero no viceversa. Un fortalecimiento de
la aserción disminuye el número de estados que la pueden satisfacer.
 Mas fuerte ⇒ más selectivo, más específico.
 Mas débil ⇒ menos selectivo, más general.

3.1.Fortalecimiento de las precondiciones

 Si una parte de un código es correcta bajo la precondición {P }, entonces


permanecerá correcto si se refuerza {P }.
 Si {P }C {Q } es correcto y además P1 ⇒ P entonces se puede afirmar que
{P1 }C {Q} es correcto. Esto conduce a la siguiente regla de inferencia:

P1 ⇒ P

{P }C {Q }

{ P1 } C { Q }
3.2.Debilitamiento de postcondiciones

El principio de debilitamiento de postcondiciones permite concluir que


{P }C {Q 1 } una vez que {P }C {Q } y Q ⇒ Q 1 hayan sido establecidos
formalmente. Esto conduce a la siguiente regla de inferencia:

{P }C {Q }

Q ⇒Q1

{P }C {Q1 }

Como regla general:


Siempre será ventajoso intentar formular la precondición más débil posible
que asegure que se cumple una cierta postcondición dada. De esta forma
cualquier precondición que implique la anterior será satisfecha
automáticamente. Además, los programas deben ser escritos de modo que
resulten lo más versátiles posibles (Generalidad).

6
5.1.Regla de la conjunción

Permite reforzar simultáneamente la precondición y la postcondición. Se define


de la siguiente forma:

 Si C es una parte de un código y se ha establecido que {P1 }C {Q1 } y


{P2 }C {Q2 } se puede afirmar que {P1 ∧ P2 }C {Q1 ∧Q2 }. Si una de las
precondiciones fuera la aserción más fuerte {}, por ejemplo P1, se puede
afirmar que {P2 }C {Q1 ∧Q 2 }.

{ P1 } C { Q 1 }
{ P2 } C { Q 2 }
{ P1 ∧ P2 } C {Q1 ∧ Q2 }
5.2.Regla de la disyunción

Permite debilitar la precondición y postcondición de forma simultánea. Se


define de la siguiente manera:

 Si C es una parte de un código y se ha establecido que {P1} C {Q1} y {P2}


C {Q2} se puede afirmar que {P1 ∨ P2} C {Q1 ∨ Q2}. Si una de las
precondiciones fuera la aserción más fuerte {}, por ejemplo, P1, se puede
afirmar que {P2} C {Q1 ∨ Q2}.
{ P1 } C { Q 1 }
{ P2 } C { Q 2 }
{ P1 ∨ P2 } C {Q1 ∨ Q2 }
4. CONCEPTOS DE CORRECCIÓN
Sea {P }C {Q } un código donde la precondición es {P } y la postcondicion {Q }
entonces será correcto {P }C {Q } si cada estado inicial posible que cumpla con la
precondición {P } dé como resultado un estado final que satisface {Q }.

Se presentan dos tipos de corrección:

 Corrección Parcial:

Se dice que {P} C {Q} es parcialmente correcto si el estado final de C, cuando


termina el programa (opcional), satisface {Q} siempre que el estado inicial
cumple con la precondición {P}.

7
 Corrección Total:

Cuando un código además de ser correcto parcialmente también termina.

Los códigos que no presentan bucles en su interior siempre terminan por lo que la
corrección parcial implica la corrección total. Esta distinción se hace notoria en
códigos con bucles o recursiones, ya que pueden no terminar (loop infinito,
recursión infinita).

5. VERIFICACIÓN DE CÓDIGOS SIN BUCLES


6.1.Verificación

Para demostrar la corrección de las partes de un programa se inicia de la


postcondición final del código, y a partir de ahí se busca deducir la
precondición.

6.2.Regla de Asignación

 Requiere que las variables implicadas no compartan el mismo espacio de


memoria (excluyéndose el uso de punteros y arreglos).
 Las sentencias de asignación tienen la forma V :=E en donde V es una
variable y E es una expresión.

{}V :=E {V =E α }

 Se define como:

Si C es una sentencia de asignación con la postcondición {Q }, entonces la


precondición de C puede hallarse sustituyendo todos los casos de V en Q
por E. Si Q EV es la expresión que se obtiene mediante:

{P }V :=E {Q }
{P }={Q EV }⇒ {V =E α , Q }
{Q EV }V :=E {Q }

8
6.3.Regla de Concatenación

La concatenación significa que las partes del programa se ejecutan


secuencialmente de tal forma que el estado final de la primera parte de un
código se convierte en el estado inicial de la segunda parte del programa.

Se define:

Sean C 1 y C 2 dos partes de un código y sea C 1; C 2 su concatenación. Si


{P }C 1 { R } y {R }C 2 {Q }, son ternas de Hoare correctas entonces se puede
afirmar que:

{P }C 1 { R }

{R }C 2 {Q }

{P }C 1 ; C 2 {Q}

6.4.Invariante de un código

Cualquier aserción que es a la vez precondición y postcondición de una parte del


código se denomina invariante.

Por ejemplo, se busca demostrar que r =2i es un invariante del siguiente código

C=i:=i+1; r=r∗2.

Como una invariante es precondición y postcondición Q={r=2 i} entonces:

Se desarrolla la primera parte del código para hallar la primera precondición

{P }r :=r∗2{r=2i }

P={r=r∗2 , r=2i }=¿ {r∗2=2i }=¿ {r =2i−1 }

{r=2i−1 }r :=r∗2{r=2i }

9
Después esta precondición pasa a ser postcondición del otro código:

{P }i :=i+1 {r =2i−1 }

P={i=i+ 1, r =2i−1 }=¿ {r=2i+1−1}=¿{r=2i }

{r=2i }i :=i+1{r=2i−1 }

Con lo que queda demostrado que r =2i es una invariante.

6. LA SENTENCIA IF
7.1.Sin cláusula else

 Sea C 1 una parte de un programa y B una condición entonces la sentencia “if


B then C 1” se interpreta de la siguiente forma: si B es verdadero se ejecuta
C 1.
 Si se busca demostrar la corrección de una sentencia ‘if’ con una
precondición {P } y una postcondición {Q } tendremos dos posibilidades:
 Si el estado inicial del programa satisface B además de P se ejecuta C 1
lo que equivale a demostrar que {P ∧ B }C 1 {Q } es correcto.
 Si el estado inicial no satisface B entonces esto equivaldrá a demostrar
que {P ∧¬ B }=¿ {Q }.

Regla de Inferencia

{P ∧ B }C 1 {Q }

{P ∧¬ B }=¿ {Q } {P }if B then C 1 {Q }

7.2.Con cláusula else

 Siendo C 1 y C 2 dos partes de un programa y si B es una condición entonces


la sentencia ‘if B then C 1 else C 2’ significa que si B es verdadero se ejecuta
C 1 sino C 2.

10
 Si desea demostrar su corrección con una precondición y una postcondición
tenemos dos posibilidades:
 Si el estado inicial del programa cumple tanto B como P entonces se
ejecutará C 1 lo que equivale a demostrar que {P ∧ B }C 1 {Q } es correcto.
 Si el estado inicial no satisface B entonces se ejecutará C 2 y por tanto la
verificación equivaldrá a demostrar que {P ∧¬ B }C 2 {Q } es correcto.

{P ∧ B }C 1 {Q }

{P ∧¬ B }C 2 {Q } {P } if B then C 1 else C 2
{Q }

7. BUCLES
Mientras que todos los programas sin bucles terminan, un programa con bucle(s) se
ejecuta(n) repetidas veces hasta que la condición asignada a dicho bucle deja de
cumplirse. Como podemos ver que el código no termina entonces la verificación
será con la Corrección parcial; dicha corrección también podemos usarla en una
función recursiva puesto que esta función se llama a sí misma.

8.1.Variantes e invariantes de un Bucle

 Variantes del bucle: Expresión que mide el progreso realizado por el bucle
hasta satisfacer la condición de salida.
 Invariante del bucle: Es un aserto que captura las características que no varía
al ejecutarse un bucle.
Encontrar invariantes requiere cierto ingenio (puede haber muchas y
diferentes, para un mismo bucle). Para ello debemos comenzar modificando
la postcondición del while para hacerla dependiente del índice del bucle (la
variable que crece o decrece en cada iteración).
Las estructuras iterativas que se estudiara son dos, estas son los siguiente: While
y Repeat.

11
8.2.Bucle While

Regla de inferencia para el bucle while.

Si C es un código tal que se cumple {I B }C {I } y entonces se puede inferir lo


siguiente:

{ I ∧ B } C {I }
{ I } while B do C {( I ∧ ¬ B ) }

Se trata de la regla que permite calcular las pre y post condiciones de un bucle
while satisfaciendo la propiedad de corrección parcial.

Si la conjunción de las condiciones I y B es la precondición de C y I es su


postcondición, quiere decir que cuando I y B son ciertas, I será cierto tras la
ejecución de S. Por lo tanto, si B es la condición del bucle while podemos
demostrar que, siendo cierta la precondición I, se cumple la postcondición I ∧¬
B, dado que I era postcondición de la(s) instrucción(es) C del interior del bucle
y ¬ B debe cumplirse para salir del while.

12
8.3.Bucle Repeat

Regla de Inferencia

Si C es un código tal que se cumple {I }C {Q } donde I ={¬ B ∧Q }, entonces se


puede inferir lo siguiente:

{I }C {Q }

{I } repeat C until B {( B∧ Q) }

8.4.Determinación de la Corrección-Ejemplo

Determinar la corrección del siguiente código:

z :=0 ;

u :=x ;

repeat

z :=z + y ;

u :=u−1

until u=0

Se supone que este código halla el producto de dos números enteros.

Si la postcondición ¿ {(z=x∗y )∧(u=0)} y el invariante:

{Q }={( z +u∗ y=x∗y )∧(u ≥ 0)}

{P }u :=u−1; {( z +u∗ y=x∗y )∧(u ≥ 0)}

P={u=u−1 , z +u∗y=x∗y , u ≥ 0 }⇒{z +(u−1)∗y =x∗y ,u−1 ≥0 }

{u−1 ≥0 }⇒ {u ≥ 1}⇒ {u>0 }

{( z+ ( u−1 )∗y=x∗y )∧(u> 0)}u :=u−1{(z +u∗ y=x∗y )∧(u ≥ 0)}

{P }z :=z + y ; {( z+(u−1)∗y=x∗y )∧(u> 0)}

13
P={ z=z + y , z +(u−1)∗y=x∗y ,u> 0 }⇒{z + y +(u−1)∗y =x∗y ,u> 0 }

{z + y +(u−1)∗y =x∗y }⇒ {z + y +u∗y− y =x∗y }⇒ { z+u∗y=x∗y }

{( z+ u∗y =x∗y )∧(u>0) }z :=z + y ; {( z+(u−1)∗ y=x∗y )∧(u>0) }

Con lo que queda demostrado que {¬ B ∧Q }C {Q }

{P }u :=x ; {( z +u∗y=x∗y )∧(u> 0)}

P={u=x , z+u∗y=x∗y ,u> 0 }⇒{z + x∗y =x∗y ,u >0 }⇒{ z=0 , x> 0}

{z=0 , x >0 }u :=x ;{(z +u∗y=x∗ y)∧(u> 0)}

{P }z :=0 {( z=0)∧(x> 0)}

P={ z=0 , z=0 , x> 0 }⇒ {0=0 , x >0 }⇒{ x> 0}

{x >0 }z :=0 {(z =0)∧(x >0)}

{( B∧ Q) }⇒{(u=0)∧(( z+u∗y =x∗y)∧(u ≥0))}⇒

{( z=x∗y )∧(u=0)}50

Si la postcondición ¿ {(z=x∗y )∧(u=0)} y el invariante:

I =¿ {¬ B ∧Q }={( z +u∗ y=x∗y )∧(u> 0) }

Q={(z +u∗y=x∗ y)∧(u ≥ 0) }

{x >0 }z :=0 {(z =0)∧(x >0)}

{z=0 , x >0 }u :=x ;{(z +u∗y=x∗ y)∧(u> 0)}


repeat

{( z+ u∗y =x∗y )∧(u>0) }z :=z + y ; {( z+(u−1)∗ y=x∗y )∧(u>0) }

{( z+(u−1)∗y=x∗ y)∧(u> 0)}u:=u−1; {(z +u∗y=x∗y )∧(u ≥ 0)}

untilu=0

{I }C {Q }

{I } repeat C until B {( B ∧Q)}

{( B∧ Q) }⇒{(u=0)∧(( z+u∗y =x∗y)∧(u ≥0))}⇒

{( z=x∗y )∧(u=0)}

8. DOCUMENTACIÓN EN PSEUDOCÓDIGO
Esta función calcula el producto de dos números enteros:

 Argumentos: x > 0
14
 Resultados: z

15
BEGIN {Pre : x> 0 ; Dec :u−1 }

z :=0 ; u :=x;

REPEAT {z +u∗y=x∗ y Λ u> 0}

z :=z + y ; u:=u−1

UNTIL (u=0);

END {Post : z=x∗y Λ u=0 }

9. CORRECCIÓN TOTAL
Como ya se ha definido un programa es parcialmente correcto si se puede
demostrar que, si el programa termina, lo hace satisfaciendo la postcondición final.
Si a esto añadimos la demostración de que el programa finaliza, entonces se puede
afirmar que es totalmente correcto.

Para el subconjunto de estructuras elegidas sólo es necesario definir la finalización


cuando se trabajan con bucles. En dicho caso para analizar su finalización hay que
estudiar la evolución

a través de las iteraciones de las variables que están involucradas en la condición de


salida.

El vector de todas las variables que aparecen en la condición de salida y que pueden
ver modificados u valor durante la ejecución del bucle se denomina vector variante.

Si cada secuencia de vectores variantes alcanza la condición de salida tras un


número finito de iteraciones entonces el bucle termina.

10. VERIFICACIÓN DE UN ALGORITMO RECURSIVO


11.1. Corrección parcial

Verificación formal de la parte del algoritmo que no contiene la llamada


recursiva (inclusión de las pre y postcondiciones junto con las especificaciones
de dicho algoritmo).

Corrección del caso Base mediante la hipótesis de inducción.

Corrección de los casos recurrentes: Verificación de las llamadas subsidiarias


mediante la comprobación del paso inductivo.

11.2. Corrección total

Las llamadas recursivas se realizan de manera que los parámetros de las


llamadas se acerquen al caso base.

16
CONCLUSIONES

Actualmente, el software desarrolla un rol crítico en diversos aspectos de nuestra


sociedad y por ende es importante escribir software correcto. En este trabajo,
estudiamos el paradigma de desarrollo actual y concluimos que, si bien las
organizaciones de desarrollo realizan rigurosas pruebas, las mismas no pueden asegurar
formalmente la corrección total del software. Luego presentamos herramientas de
verificación formal, la lógica de Hoare, y el método de la variante para luego definir el
concepto de corrección total.

También concluimos que este tipo de verificación no es apta para técnicos ya que
requiere conocimientos de nivel universitario. Enseñar la teoría para poder lograr
derivar algoritmos correctamente, es un verdadero desafío para los docentes ya que los
alumnos, están acostumbrados a utilizar el paradigma actual. Por otro lado, si
comparamos esta herramienta con las existentes hace 5 años, el avance que se está
realizando hace en esta área es destacable. Si herramientas como esta (o similares)
continúan desarrollándose, es probable que, en un futuro, se reduzca aún más la
interacción con los humanos y las verificaciones, derivaciones y generación de código
fuente, se realicen de forma automática.

17