Está en la página 1de 8

Transformación de estados

I Llamamos estado de un programa a los valores de todas sus


variables en un punto de su ejecución:
Correctitud y Teorema del Invariante 1. Antes de ejecutar la primera instrucción,
2. entre dos instrucciones, y
3. después de ejecutar la última instrucción.
I Podemos considerar la ejecución de un programa como una
sucesión de estados.
Algoritmos y Estructuras de Datos I I La asignación es la instrucción que permite pasar de un estado
al siguiente en esta sucesión de estados.
I Las estructuras de control se limitan a especificar el flujo de
ejecución (es decir, el orden de ejecución de las asignaciones).

Afirmaciones sobre estados Afirmaciones sobre estados

I Sea el siguiente programa que se ejecuta con estado inicial


I Sea el siguiente programa que se ejecuta con estado inicial
{True}.
con una variable a ya definida ({a = A0 }).
I {True}
I {a = A0 }
int x = 0;
int b = a + 2;
{x = 0}
{a = A0 ∧ b = A0 + 2}
x = x + 3;
int result = b - 1;
{x = 3}
{a = A0 ∧ b = A0 + 2 ∧ result = (A0 + 2) − 1 = A0 + 1}
x = 2 * x;
{x = 6} I ¿Finaliza siempre el programa? Sı́, porque no hay ciclos
I ¿Cuál es el estado final al finalizar su ejecución?
I ¿Finaliza siempre el programa? Sı́, porque no hay ciclos {a = A0 ∧ b = A0 + 2 ∧ result = A0 + 1} ⇒ {result = a + 1}
I ¿Cuál es el estado final al finalizar su ejecución? {x = 6}
Corrección de un programa Afirmaciones sobre estados

I Sea la siguiente especificación para incrementar en una unidad


el valor de un entero.
I Definición. Decimos que un programa S es correcto respecto
de una especificación dada por una precondición P y una
I proc spec incrementar (in a : Z, out result : Z){
postcondición Q, si siempre que el programa comienza en un Pre {True}
estado que cumple P, el programa termina su ejecución, y Post {result = a + 1}
en el estado final se cumple Q. }

I Notación. Cuando S es correcto respecto de la especificación


I ¿Es el siguiente programa S correcto con respecto a su
(P, Q), lo denotamos con la siguiente tripla de Hoare: especificación?
1 int incrementar(int a) {
{P} S {Q}. 2 int b = a + 2;
3 int result = b − 1;
4 return result;
5 }

Ejemplo Intercambiando los valores de dos variables enteras

I Ejemplo: Intercambiamos los valores de dos variables, pero


I Sea el siguiente programa que se ejecuta con estado inicial sin una variable auxiliar!
con una variable a = A0 .
I {a = A0 ∧ b = B0 }
I {a = A0 }
a = a + b;
int b = a + 2;
{a = A0 + B0 ∧ b = B0 }
{a = A0 ∧ b = A0 + 2}
b = a - b;
int result = b - 1;
{a = A0 + B0 ∧ b = (A0 + B0 ) − B0 }
{a = A0 ∧ b = A0 + 2 ∧ result = (A0 + 2) − 1 = A0 + 1}
≡ {a = A0 + B0 ∧ b = A0 }
Por lo tanto, se deduce que:
a = a - b;
{result = a + 1}
{a = A0 + B0 − A0 ∧ b = A0 }
≡ {a = B0 ∧ b = A0 }
Alternativas Alternativas
I Sea el siguiente programa con una variable a de entrada cuyo I Rama positiva:
valor no se modifica (i.e. podemos asumir a = A0 como Se cumple la condición
constante) {a = A0 ∧ b = 0 ∧ B} ≡ {a = A0 ∧ b = 0 ∧ A0 > 0}
I Cuando tenemos una alternativa, debemos considerar las dos b = a;
ramas por separado. {a = A0 ∧ b = A0 ∧ A0 > 0}
I Por ejemplo: ⇒ {b = |a|}

1 int modulo(int a) {
I Rama negativa:
2 int b =0; No se cumple la condición
3 if( a > 0 ) { {a = A0 ∧ b = 0 ∧ ¬B} ≡ {a = A0 ∧ b = 0 ∧ A0 ≤ 0}
4 b = a;
5 } else {
b = -a;
6 b = −a; {a = A0 ∧ b = −A0 ∧ A0 ≤ 0}
7 } ⇒ {b = |a|}
8 return b;
9 } I En ambos casos vale b = |a|
I Por lo tanto, esta condición vale al salir de la instrucción
I Verificamos ahora que b = |a| después de la alternativa. alternativa.

Ciclos (repaso) Ejemplo

I proc sumar (in n : Z, out result : Z ){


I Recordemos la sintaxis de un ciclo:
Pre {n ≥ 0} P
while (B) { Post {result = ni=1 i}
cuerpo del ciclo }
} I
1 int sumar(int n) {
I Se repite el cuerpo del ciclo mientras la guarda B se cumpla, 2 int i = 1;
cero o más veces. Cada repetición se llama una iteración. 3 int s = 0;
4
I La ejecución del ciclo termina si no se cumple la guarda al 5 while( i <= n ) {
comienzo de su ejecución o bien luego de ejecutar una 6 s = s + i;
iteración. 7 i = i + 1;
8 }
I Si/cuando el ciclo termina, el estado resultante es el estado 9 return s;
posterior a la última instrucción del cuerpo del ciclo. 10 }
Ejemplo Invariante de un ciclo
I Estados al finalizar cada iteración del ciclo, para n = 6:
Iteración i s I Definición. Un predicado I es un invariante de un ciclo si:
0 1 0=0 1. I vale antes de comenzar el ciclo, y
1 2 1=0+1 2. si vale I ∧ B al comenzar una iteración arbitraria, entonces
I
2 3 3=0+1+2 sigue valiendo I al finalizar la ejecución del cuerpo del ciclo.
3 4 6=0+1+2+3
4 5 10 = 0 + 1 + 2 + 3 + 4 I Un invariante describe un estado que se satisface cada vez que
5 6 15 = 0 + 1 + 2 + 3 + 4 + 5 comienza la ejecución del cuerpo de un ciclo y también se
6 7 21 = 0 + 1 + 2 + 3 + 4 + 5 + 6 cumple cuando la ejecución del cuerpo del ciclo concluye.

I Observación: Luego de cada iteración vale que: I Por ejemplo, otros invariantes para este ciclo son:
I I 0 ≡ i 6= 0
i−1
X I I 00 ≡ s ≥ 0
s= k I i ≥1
k=1 I ...etc

I A este tipo de afirmación se denomina un invariante del ciclo.

Ejemplo Ejemplo
El predicado I ≡ s = i−1
P
k=1 k (por sı́ solo) no es un invariante
I

¿La ejecución del cuerpo del ciclo preserva I ≡ s =


Pi−1 de ciclo ya que la ejecución del ciclo no lo preserva.
k=1 k?
I

I Para chequear esto, asumimos que vale I ∧ B ya que se Iteración i s


cumplió la condición para ejecutar el cuerpo del ciclo. 0 1 0=0
I Agregamos metavariables para las variables que cambian. 1 2 1=0+1
I
2 3 3=0+1+2
P 0 −1
{i = I0 ∧ s = S0 ∧ S0 = Ik=1

I k ∧ I0 ≤ n } 3 4 6=0+1+2+3
4 5 10 = 0 + 1 + 2 + 3 + 4
s = s + i;
P 0 −1 5 6 15 = 0 + 1 + 2 + 3 + 4 + 5
{i = I0 ∧ s = S0 + I0 ∧ S0 = Ik=1 k ∧ (I0 ≤ n)} 6 7 21 = 0 + 1 + 2 + 3 + 4 + 5 + 6
PI0 −1
⇒ {s = k=1 k + I0 } I ¿Cómo podemos reforzar I para obtener un auténtico
6⇒ {s = Ik=1
P0
k} invariante para el ciclo?
¿Qué pasa si i0 = −1, −2, etc..? I Nueva propuesta de invariante I :
Sólo vale la implicación si I0 ≥ 0
i = i + 1; i−1
X
i ≥1∧s= k
k=1
Ejemplo Ejemplo
I ¿La ejecución delPcuerpo del ciclo preserva
I
Pi−1
¿Vale I ≡ i ≥ 1 ∧ s = k=1 k al principio del ciclo (i.e., antes I ≡ i ≥ 1 ∧ s = i−1 k=1 k?
de la instrucción while)? I Para chequear esto, asumimos que vale I ∧ B ya que se
I cumplió la condición para ejecutar el cuerpo del ciclo.
1 int i = 1;
2 int s = 0;
I Agregamos metavariables para las variables que cambian.
3 P 0 −1
{i = I0 ∧ s = S0 ∧ I0 ≥ 1 ∧ S0 = Ik=1

4 while( i <= n ) { I k ∧ I0 ≤ n }
5 s = s + i;
s = s + i;
6 i = i + 1; P 0 −1
7 } {i = I0 ∧ s = S0 + I0 ∧ I0 ≥ 1 ∧ S0 = Ik=1 k ∧ (I0 ≤ n)}
PI0 −1
⇒ {s = k=1 k + I0 }
I Antes de ejecutar el ciclo el estado de la ejecución cumple que
⇒ {s = Ik=1
P0
k} Este paso se puede aplicar ya que i0 ≥ 0
n ≥ 0 ∧ i = 1 ∧ s = 0. P 0 −1
{i = I0 ∧ s = k=1 k ∧ I0 ≥ 1 ∧ S0 = Ik=1
PI0
Esto implica que I ≡ i ≥ 1 ∧ s = i−1
P k ∧ (I0 ≤ n)}
k=1 k.
I
i = i + 1;
I Por lo tanto, se cumple I al principio del ciclo. P 0 −1
{i = I0 + 1 ∧ s = Ik=1 k ∧ I0 ≥ 1 ∧ S0 = Ik=1
P0
k ∧ (I0 ≤ n)}
Pi−1
⇒ {i ≥ 1 ∧ s = k=1 k} ≡ {I }

Ejemplo Invariante de un ciclo

I Tenemos entonces: I Los invariantes de un ciclo permiten razonar sobre su


corrección. Llamamos ...
1. I vale justo antes de comenzar el ciclo.
2. Si valı́a la condición B e I , I sigue valiendo luego de la 1. PC : Precondición del ciclo,
ejecución del cuerpo del ciclo. 2. QC : Postcondición del ciclo,
3. B: Guarda del ciclo,
I Esto implica que I también vale cuando el ciclo termina. 4. I : Un invariante del ciclo.

I Si se salió del ciclo fue porque no se cumplió i ≤ n, y entonces I Si se cumplen estas condiciones ...
estamos en un estado que satisface: 1. PC ⇒ I,
2. {I ∧ B} cuerpo del ciclo {I },
i−1
X 3. I ∧ ¬B ⇒ QC ,
n ≥0∧I ∧ i >n ≡ n ≥0∧i ≥1∧s= k ∧ i >n
k=1 I ... entonces el ciclo es parcialmente correcto respecto de su
especificación (si termina, termina en QC ).
Teorema del invariante Ejemplo
I Verifiquemos estas tres condiciones con el ejemplo anterior, y
con ...
I Teorema del invariante. Si existe un predicado I tal que ...
1. PC ≡ n ≥ 0 ∧ i = 1P∧ s = 0
1. PC ⇒ I, 2.
n
QC ≡ n ≥ 0 ∧ s = k=1 k
2. {I ∧ B} S {I }, 3. BC ≡ i ≤ n
3. I ∧ ¬B ⇒ QC , 4.
Pi−1
I ≡ i ≥ 1 ∧ s = k=1 k
entonces el ciclo while(B) S es parcialmente correcto
I En primer lugar, debemos verificar que PC ⇒ I :
respecto de la especificación (PC , QC ).
I Ya probamos anteriormente que:
I Este teorema es la herramienta principal para argumentar la
i−1
corrección de ciclos.  X
n ≥0∧i =1∧s =0 ⇒ i ≥1∧s= k.
I El teorema del invariante se puede demostrar formalmente k=1
(más detalle en las próximas teóricas!).
I Por lo tanto, podemos concluir que se cumple la condición
PC ⇒ I

Ejemplo Ejemplo

I Finalmente, ¿es cierto que I ∧ ¬B ⇒ QC ?

I ¿Es cierto que {I ∧ B}S{I }? i−1


X n
X
i ≥1∧s= k ∧i >n ⇒ s= k ?
I ∧ B : {i ≤ n ∧ i ≥ 1 ∧ s = i−1
P
k=1 k} k=1 k=1
s = s + i;
i = i + P 1; I No! Contraejemplo: Si i = n + 2, entonces la implicación no
I : {i ≥ 1 ∧ s = i−1
k=1 k} vale!
I Esto también lo probamos cuando demostramos que I era un I Sin embargo, sabemos que esto no puede pasar, puesto que
invariante para el ciclo. i ≤ n + 1 a lo largo del ciclo.
I ¿Qué hacemos?
⇒ Reforzamos el invariante!
Ejemplo Ejemplo
I Proponemos el nuevo invariante de ciclo reforzado (i.e. mas
restrictivo):
i−1
I ≡1≤i ≤n+1∧s=
X
k
I ¿Qué pasa con los dos primeros puntos del teorema del
invariante?
k=1
I PC ⇒ I
I {I ∧ B} cuerpo del ciclo {I }
I ¿Vale ahora que tenemos que I ∧ ¬B ⇒ QC ?
I ¿Se siguen verificando estas condiciones con el nuevo
i−1
X invariante?
1≤i ≤n+1∧s= k ∧i >n
k=1 I Hay que demostrarlo nuevamente! Si I 0 ⇒ I no podemos
i−1
X concluir que PC ⇒ I 0 .
⇒ i =n+1∧s= k
k=1
n
X
⇒ s= k ≡ QC
k=1

Para concluir... Para concluir...

I ¿La ejecución del cuerpoPdel ciclo preserva


I ≡ 1 ≤ i ≤ n + 1 ∧ s = i−1 k=1 k?
P 0 −1
{i = I0 ∧ s = S0 ∧ 1 ≤ I0 ≤ n + 1 ∧ S0 = Ik=1

I k ∧ I0 ≤ n }
I ¿PC ⇒ I ? s = s + i;
PI0 −1
 i−1
X {i = I0 ∧s = S0 +I0 ∧1 ≤ I0 ≤ n +1∧S0 = k=1 k ∧(I0 ≤ n)}
PI0 −1
PC ≡ n ≥ 0 ∧ i = 1 ∧ s = 0 ⇒ 1 ≤ i ≤ n + 1 ∧ s = k ⇒ {s = k=1 k + I0 }
k=1
⇒ {s = Ik=1
P0
k} Este paso sólo se puede aplicar si I0 ≥ 0
P 0 −1
{i = I0 ∧s = k=1 k ∧1 ≤ I0 ≤ n+1∧S0 = Ik=1
PI0
k ∧(I0 ≤ n)}
I Por lo tanto, se cumple que PC ⇒ I
i = i + 1;
{i = I0 + 1 ∧ s = Ik=1
P0
k ∧ 1 ≤ I0 ≤ n + 1 ∧ S0 =
PI0 −1
k=1 k ∧ (I 0 ≤ n)}
⇒ {1 ≤ i ≤ n + 1 ∧ s = i−1
P
k=1 k} ≡ {I } Esto lo podemos
hacer ya que I0 ≥ n
Resultado final Algunas observaciones

Pi−1
I Finalmente, Sean: I I ≡1≤i ≤n+1∧s= k=1 k.
1. PC ≡ n ≥ 0 ∧ i = 1P∧ s = 0
n 1. En general, un buen invariante debe incluir el rango de la(s)
2. QC ≡ n ≥ 0 ∧ s = k=1 k
variable(s) de control del ciclo.
3. BC ≡ i ≤ n Pi−1 2. Además, debe incluir alguna afirmación sobre el acumulador
4. I ≡ i ≥ 1 ∧ s = k=1 k
del ciclo.
I Ya que demostramos que se cumplen las siguientes I Cuando tenemos un invariante I que permite demostrar la
condiciones:
corrección parcial del ciclo, nos referimos a I como el
1. PC ⇒ I invariante del ciclo.
2. {I ∧ B} cuerpo del ciclo {I }
3. I ∧ ¬B ⇒ QC 1. El invariante de un ciclo caracteriza las acciones del ciclo, y
representa al algoritmo que el ciclo implementa.
I Entonces, por el Teorema del Invariante podemos concluir que
el ciclo while(B) S es parcialmente correcto respecto de la I En general, es sencillo argumentar informalmente la
especificación PC , QC . terminación del ciclo (más detalles en las próximas teóricas).

Bibliografı́a

I David Gries - The Science of Programming


I Chapter 6 - Using Assertions to Document Programs
I Chapter 6.1 - Program Specifications
I Chapter 6.2 - Representing Initial and Final Values of Variables
I Chapter 6.3 - Proof Outlines (transformación de estados,
alternativas)

También podría gustarte