Metodologı́a de la Programación Septiembre de 2005 Ingenierı́a Técnica en Informática de Sistemas/ Ingenierı́a en Informática Facultad de Informática de San Sebastián SOLUCIÓN 1. (1 punto) Escribir una fórmula de primer orden que describa el siguiente estado de computación: “En el array A(1..n) no hay dos elementos contiguos que sean iguales” ∀i(1 ≤ i < n → A(i) 6= A(i + 1)) 2. (2.5 puntos) Documentar, con las aserciones que se marcan, el siguiente programa que decide, en la variable booleana inverso, si el array A(1..n) es el inverso del array B(1..n). Ejemplo: A(1..5) = (2, 5, 6, 8, 3) es el inverso de array B(1..5) = (3, 8, 6, 5, 2). (1) ≡ {n ≥ 1} i := 0; inverso := true; (2) ≡ {0 ≤ i ≤ n ∧ (inverso ↔ ∀j(1 ≤ j ≤ i → A(j) = A(n − j + 1)))} E = n − i while i < n and inverso loop i := i + 1; (3) ≡ {0 ≤ i ≤ n ∧ inverso ∧ ∀j(1 ≤ j < i → A(j) = A(n − j + 1))} if A(i) 6= B(n − i + 1) then (4) ≡ {0 ≤ i ≤ n ∧ ¬∀j(1 ≤ j ≤ i → A(j) = A(n − j + 1))} inverso := false; end if; end loop (5) ≡ {inverso ↔ ∀j(1 ≤ j ≤ n → A(j) = A(n − j + 1))} 3. (2.5 puntos) Derivar formalmente una iteración que decida si en un array A(1..n) dado, cuyos elementos son enteros positivos, hay la misma cantidad de elementos pares que de impares. Pre≡ n ≥ 1 ∧ ∀k(1 ≤ k ≤ n → A(k) > 0) Post≡ EquImP ar ↔ (2 ∗ N j(1 ≤ j ≤ n ∧ A(j)mod2 = 0) = n) Inv≡ k = N j(1 ≤ j ≤ i ∧ A(j)mod2 = 0) ∧ 0 ≤ i ≤ n E≡ n − k INICIALIZACIÓN : {n ≥ 1 ∧ ∀k(1 ≤ k ≤ n → A(k) > 0)} → {n ≥ 0} i := 0; k := 0; {k = N j(1 ≤ j ≤ i∧A(j)mod2 = 0) ∧ 0 ≤ i ≤ n} FINALIZACIÓN : ¬B = i = n Inv ∧ i = n → {k = N j(1 ≤ j ≤ n ∧ A(j)mod2 = 0)} → {(2 ∗ k = n) ↔ 2 ∗ N j(1 ≤ j ≤ n ∧ A(j)mod2 = 0) = n} EquImP ar := (2 ∗ k = n) {EquImP ar ↔ (2 ∗ N j(1 ≤ j ≤ n ∧ A(j)mod2 = 0) = n)} CUERPO DE LA ITERACIÓN : Inv∧i 6= n → {k = N j(1 ≤ j ≤ i∧A(j)mod2 = 0) ∧ 0 ≤ i < n} E = n−i ∈ IN i := i+1; E decrece {k = N j(1 ≤ j < i ∧ A(j)mod2 = 0) ∧ 0 ≤ i ≤ n} = ϕ if A(i)mod2 = 0 then {k + 1 = N j(1 ≤ j ≤ i ∧ A(j)mod2 = 0)} k := k + 1; [(ϕ ∧ A(i)mod2 6= 0) → Inv] end if Inv = {k = N j(1 ≤ j ≤ i ∧ A(j)mod2 = 0) ∧ 0 ≤ i ≤ n} ITERACIÓN DOCUMENTADA : {n ≥ 1 ∧ ∀k(1 ≤ k ≤ n → A(k) > 0)} i := 0; k := 0; {k = N j(1 ≤ j ≤ i ∧ A(j)mod2 = 0) ∧ 0 ≤ i ≤ n} E =n−i while i 6= n loop {k = N j(1 ≤ j ≤ i ∧ A(j)mod2 = 0) ∧ 0 ≤ i < n} i := i + 1; {k = N j(1 ≤ j < i ∧ A(j)mod2 = 0) ∧ 0 ≤ i ≤ n} = ϕ if A(i)mod2 = 0 then {k + 1 = N j(1 ≤ j ≤ i ∧ A(j)mod2 = 0)} k := k + 1; [(ϕ ∧ A(i)mod2 6= 0) → Inv] end if; end loop; {k = N j(1 ≤ j ≤ n ∧ A(j)mod2 = 0)} EquImP ar := (2 ∗ k = n); {EquImP ar ↔ (2 ∗ N j(1 ≤ j ≤ n ∧ A(j)mod2 = 0) = n)} 4. (2 puntos) SÓLO SI HAS ELEGIDO EL APARTADO (a) Especificar ecuacionalmente la función prefijo que, dadas una secuencia s y un número natural n, devuelve la subsecuencia inicial de s con los n primeros elementos. En caso de que s tenga menos de n elementos, la función devuelve s. Ejemplo: prefijo(< 4, 4, 2, 1, 1, 8 >, 3) =< 4, 4, 2 > prefijo(< 4, 4, 2, 1, 1, 8 >, 9) =< 4, 4, 2, 1, 1, 8 > sobre Secuencia(T ), Nat operaciones prefijo : Secuencia(T ) × Nat → Secuencia(T ) ecuaciones (1) prefijo(h i, n) = h i (2) prefijo(x • s, n) = hi si n = 0 x • prefijo(s, n − 1) e.o.c. SÓLO SI HAS ELEGIDO EL APARTADO (b) La función duplicar : secuencia(T ) → secuencia(T ) tiene la siguiente especificación ecuacional: duplicar(h i) = h i duplicar(t • s) = t • (t • duplicar(s)) Escribir un programa iterativo que implemente la función duplicar por medio del método de Burstall. Pre≡ T rue Post≡ r1 = duplicar(s) Inv≡ duplicar(s) = r1 @ duplicar(r2) INICIALIZACIÓN : r1 := h i; r2 := s; Justificación: duplicar(s) = h i @ duplicar(s) FINALIZACIÓN : (duplicar(s) = r1 @ duplicar(r2) ∧ es vacia(r2)) → r1 = duplicar(s) Por tanto B = not es vacia(r2) y el resultado a devolver es r1 CUERPO DE LA ITERACIÓN (DESPLEGADO/PLEGADO): duplicar(s) = r1 @ duplicar(r2) ∧ ¬es vacia(r2)) → duplicar(s) = r1 @ duplicar(prim(r2)•resto(r2)) = r1 @ (prim(r2) • (prim(r2) • duplicar(resto(r2)))) = (r1 @ hprim(r2), prim(r2)i) @ duplicar(resto(r2)) = r10 @ duplicar(r20 ) Por tanto, (r10 , r20 ) = ((r1 @ hprim(r2), prim(r2)i), resto(r2)) FUNCIÓN DOCUMENTADA : function duplicar it(s : Secuencia(T )) return r1 : Secuencia(T ) is r2 : Secuencia(T ); {T rue} r1 := h i; r2 := s; {duplicar(s) = r1 @ duplicar(r2)} while not es vacia(r2) loop r1 := r1 @ hprim(r2), prim(r2)i; r2 := resto(r2); end loop; {r1 = duplicar(s)} 5. (2 puntos) Verificar que la siguiente función recursiva calcula lo que su especificación dice. Para ello, es imprescindible escribir previamente las hipótesis de inducción para las dos llamadas internas. function f rm (n : integer) return r : integer is Pre ≡ {n ≥ 0} if n = 0 then r := 0; elsif n = 1 then r := 1; else r1 := f rm(n − 1); r2 := frm(n − 2); r := (5 ∗ r1) − (6 ∗ r2); end if; Post ≡ {r = 3n − 2n } CASOS SIMPLES: {n ≥ 0 ∧ n = 0} → {0 = 3n − 2n }r := 0; {r = 3n − 2n } {n > 0 ∧ n = 1} → {1 = 3n − 2n }r := 1; {r = 3n − 2n } CASOS INDUCTIVOS: Hipótesis de inducción: {n − 1 ≥ 0} r1 := frm(n − 1); {r1 = 3n−1 − 2n−1 } {n − 2 ≥ 0} r2 := frm(n − 2); {r2 = 3n−2 − 2n−2 } {n ≥ 0 ∧ n 6= 0 ∧ n 6= 1} → {n ≥ 2} → {n − 1 ≥ 0 ∧ n − 2 ≥ 0} r1 := frm(n − 1); r2 := frm(n − 2); {r1 = 3n−1 − 2n−1 ∧ r2 = 3n−2 − 2n−2 } → {(5∗r1)−(6∗r2) = 5∗3n−1 −5∗2n−1 −2∗3n−1 +3∗2n−1 = (5−2)∗3n−1 −(5−3)∗2n−1 = 3n −2n } r := (5 ∗ r1) − (6 ∗ r2); {r = 3n − 2n } VALIDACIÓN DE LA INDUCCIÓN: En ambos casos simples, es obvio que n ∈ IN. En el caso inductivo n ≥ 2, luego n−1, n−2 ∈ IN y ambos son estrictamente menores que n.