Está en la página 1de 33

2.

CORRECCIÓN DE PROGRAMAS

Un programa se especifica mediante su espacio de estados, una precondición y una


poscondición. De esta manera, una especificación de un programa constituye una especie
de ecuación, en el sentido de que programar es la actividad de resolver la incógnita
planteada por una especificación. Esta incógnita es lo que llamamos programa. Por
ejemplo, la siguiente es una especificación de un programa para el cálculo del máximo
común divisor de dos números naturales positivos e  :

con 
 
var  
 "!$#&%('*),+-%('.)0/213#4)6521(+(7
8:9<;=?>@8BA
CEDFEGIH3J KMLBN OQP
RS
El primer renglón expresa que las variables de especificación (o estáticas) T e U no son
variables de programa (o dinámicas), y por tanto, no pueden mencionarse en los comandos
o instrucciones del programa. Por consiguiente, sus valores iniciales coinciden con sus
valores finales. El tercer renglón y quinto renglón contienen respectivamente la
precondición y la poscondición. Las variables de especificación pueden ser mencionadas en
los predicados; por convención, las especificaciones se consideran universalmente
cuantificadas sobre todas las variables de especificación que aparezcan en ella. El segundo
renglón define el espacio de estados VXWYV , en el cual la primera coordenada corresponde a
la variable de programa Z y la segunda a la variable de programa [ . Finalmente el cuarto
renglón enuncia el nombre del programa especificado.

La interpretación operacional de la anterior especificación es la siguiente: el programa


euclides satisface la especificación si para todos los enteros \ e ] , el inicio de la ejecución
de euclides en un estado que satisface  
    termina en un estado
que satisface    
.

EJERCICIOS
0. Especifique un programa que :
(a) Determine la suma de elementos de un arreglo de enteros dado.
(b) Determine el número de ocurrencias de en un arreglo dado.
(c) Dado un arreglo booleano  que contenga un valor verdadero, fije en  el menor 
tal que 
valga.
(d) Dado un arreglo booleano  que contenga un valor verdadero, fije en ! el mayor
tal que 
valga.
(e) Determine el número de valores distintos en arreglo de enteros dado.

(f) Determine una mayoría en el arreglo , dado que haya una. Una mayoría en un arreglo
que contenga "
elementos es un valor que ocurre mas de div veces. " #
(g) Dado que haya uno, determine el segundo valor mas largo de un arreglo de enteros
dado.

2.1 Corrección de Programas Iterativos


Estudiaremos como expresar algoritmos iterativos en el lenguaje de comandos guardados
$ %
de Dijkstra (LCG). En general, si y son predicados (expresiones booleanas) y es un &
programa, ')( *&+'-,
*
es también un predicado que se lee: es totalmente correcto con &
respecto a y ( ,/.
Su interpretación operacional, que inspira nuestro trabajo axiomático,
afirma que

toda ejecución de & termina en un estado que satisface Q cuando se inicia en un estado
que satisface . &
Presentaremos ahora el lenguaje de comandos guardados de Dijkstra mediante una
“semántica axiomática” (es decir, una forma de entender el significado de un programa
basada en axiomas) expresada en términos de axiomas sobre la corrección de sus
comandos.

Axiomas generales de corrección

• 0-1
2/30547698;:=<>2 equivale a 1 ≡ 47698;:=< (ley del milagro excluido)

Diseño de Algoritmos Cap 2 30


Jaime A Bohórquez V
Leyes de debilitamiento y fortalecimiento de pre y poscondiciones:
• Si  
    ⇒  entonces    

•   
  ⇒    entonces 
Si      

Leyes de conjunción de objetivos y disyunción de requisitos:


•   ∧  equivale a   

•  ∨  
 equivale a   
 


La siguiente afirmación es más sutil


• Si !"$#%&"(')!"$#% *
" entonces !"$#%& ∨ *
",+ El converso no es cierto
para programas no determinísticos1).
Ley de monotonía de la implicación (⇒)
-
Si . ⇒ / entonces 01230 .
2 ⇒ 01230/2
Prueba:
01230 .
2 ⇒ 01230/2
≡ 4 axioma de ⇒ 5
67896 :
8 67896;8 67896 :
8
∧ ≡
≡ < conjunción de objetivos 5
67896 : ;8 67896 :
8
∧ ≡
⇐ < regla de Leibnitz 5
: ; :
∧ ≡
≡ < axioma de ⇒ 5
: ;

El comando =?>A@ B

• Axioma del comando =?>A@ BCED F


GH=?>A@ BDIG equivale a F ⇒I (su ejecución no tiene
ningún efecto en el estado actual)

El comando de asignación
Se escribe JKCML N donde O representa una secuencia finita de variables y N representa una
secuencia de expresiones (una por cada variable en O ) OKPMQ N evalúa las expresiones en N y

1
Un programa se llama determinístico cuando al iniciar con los mismos datos, todas las ejecuciones del programa dan
siempre los mismos resultados (p.e. siempre aborta, o siempre se queda en ciclo infinito, o siempre se detiene con los
mismos resultados. Existen programas que iniciando con los mismos datos producen resultados diferentes bajo diferentes
ejecuciones. Estos programas se llaman no-determinísticos.

Diseño de Algoritmos Cap 2 31


Jaime A Bohórquez V
 
cada variable en toma el valor de la correspondiente expresión en . La asignación 

se lee “ se vuelve ”.
 
• Axioma de asignación  
  
equivale a  ⇒  

En realidad este axioma presupone que siempre tiene valor, sin embargo muchas
expresiones no son totales. Por ejemplo,  está definida solo si  ≠  y la referencia al
arreglo  :   está definida sólo si  está dentro de los limites del arreglo. Para toda
expresión  definimos el predicado "! # que se satisface exactamente en aquellos
estados en que # está definido. Ejemplo: "! √ $&%(')+* ≡ ) ≠ , ∧ %(') ≥ ,

Podemos dar ahora un axioma de definición más general para la asignación:


• - . / %012#3-4/ ≡ "!# ∧ . ⇒ 465 %017#8
Hecho esto, con frecuencia omitiremos "! # de las precondiciones para simplificar las
discusiones. Aplicando el axioma de asignación a un caso particular, . ≡ 45 %012#8 ,
obtenemos:
-465 %012#8/ %017#3-4/
Afirmamos que 465 %012#8 es la precondición más débil2, tal que al ejecutar %017# termina
con 4 verdadero. En otras palabras, le encontramos significado al axioma de asignación:
- . / %012#3-4/ ≡ . ⇒ 465 %017#8
Ejemplo: Sea 9 : %:1;$ Σ< =?>A@CB < DE=GFGH BJI que estipula que K es la suma de los D primeros
elementos del arreglo LNMPORQQSUTWV?X Q
Investigamos para que expresión Y tenemos que Z[\ ]_^`7abdce^f`hgjikZ[\(l Esto es verdad si:
[6m ]_^`2abnc^`hgji?o
≡ p definición de [ y sustituyendo q
cb;r Σs t?uwvyx6z|{h}j~kt ?€ xJ
≡ ‚ ruptura por xƒn{J„
… ƒ;† Σ‡ t?uwvyx6z|{ˆt ?€ xJ‰}wG€ {
≡ ‚ suponiendo Šd„
… ƒˆ‹} ?€ {
Luego la elección … ƒˆ‹}wG€ { responde a nuestra pregunta.

Otro ejemplo: Solucionar para … en ŒŠ  Ž"’‘ Σ“ Že”2•3–—|˜™Ž š?› –Jœ(ž”hŸeŽn”U W¡ Ÿf¢¤£¥  
Para hallarlo tenemos que resolver para ¢ en ¥  ⇒ ¥  ‘¦”UŸŽn”U W¡ Ÿf¢Jœ

2
Un predicado § se dice "más débil que" otro ¨ , si ¨ ⇒© es un teorema. La definición dual aplica al concepto “mas
fuerte que”.

Diseño de Algoritmos Cap 2 32


Jaime A Bohórquez V
 




≡ definición de , sustitución textual 

 
 !#"# $&% ('
Σ
 )
≡  ruptura por 
  *+!#"# ,$% ('.-/$0'
Σ
≡  suponiendo 
 12-3$4'

EJERCICIOS
0. Determine el predicado más débil que satisfaga:
67
8-. 29;:<6
(i) 5 5

67
1  29;:<6
(ii) 5 ⋅ 5

67
1  =?>
(iii) 5 ⋅ ⋅ ⋅@2ABDCE@2F;G<H
(iv) CIH7@
J K1@A.LMCE@ N OPRQ S T/UQ2V;W<X

(v) YZX7Q
[ \1Q ⋅Q ⋅Q=O?U ⋅Q2T]^YEQ _ O&PRQ S T/UQ2V;W<X

(vi) YZX7Q
[ \1QT.`MYEQ=\1QT.`X

(vii) YZX7Q
[ \)a+YEQ=\1aX

(viii) YZX7Q
[ \1Q bdcfe UgYEQ=\1Q bdcfe UhX

(ix) YZX7QjiRk
[ \8QT.`iRkjO`MYEQTjk2V;W<X

(x) YZX7QjiRk
[ \8kT.`iRQjO`MYEQ2V;W<X

(xi) YZX7QjiRk
[ \1k ⋅QjiRQ ⋅k#YEQTjk2V;W<X
(xii) YZXmln[ \ l ≡ o/YRlpX
(xii) YZXmln[ \ l ⇒ o3YRl ∨ o/X
1. Muestre que la ejecución de Q
[ \1QT.` termina

El comando qjrsftvu

• Axioma del comando qjrsftvu : wx3ymqjrsftvu*wzy ≡ x ⇒ {|qj}~v

Diseño de Algoritmos Cap 2 33


Jaime A Bohórquez V
Comandos compuestos

Secuenciación: Si  y   son programas en LCG,   ;   (la concatenación o


secuenciación de   y   ) ejecuta primero   y enseguida   (suponiendo terminación
normal, claro está, de   )
• Axioma de secuenciación:   
    ≡             donde  es
algún predicado adecuado.

Programando con secuencias de asignaciones


Para encontrar la precondición mas débil tal que la ejecución de la secuenciación de
asignaciones  ; ! termine con " verdadero, es decir, solucionar la incógnita en
#%$'&)(*+, - .*+0/1# 2 &
es necesario observar que
# 243 .*+/657&).*+0/8# 2 & ∧ # 2 3 .*+0/6593 (*+0,657&)(*+,8# 243 .*+0/657&
y por tanto # 243 .*+0/6593 (*+0,657&:(*+,;-<.*+0/=# 2 &

Ejemplo: Hallar la precondición mas débil tal que la ejecución >?*+( ; (*+:. ; .*+> logre
que (@+BA ∧ .@+DC sea verdad.
E
(@+A ∧ .6+FCHGI3 .*+:>J593 (*+.K593L>?*+0(K5
≡ M sust. textualN
E
(@+A ∧ >+DCHG3 (*+.K593L>?*+0(K5
≡ M sust. textualN
E
.@+A ∧ >+DCHG3L>?*+(K5
≡ M sust. textualN
E
.@+A ∧ (6+FCHG

Esta secuencia de asignaciones intercambia ( e .

EJERCICIOS
0. Determine el predicado más débil O que satisface:
(i) # O &)(*+(QPSR9-<(*+0(QPSR7#T(6UDVW&
(ii) # O &)(*+0( ⋅(X-<(*+0(QPSR7#T(6UDVW&
(iii) Y Z [)\]^0\Q_a`Xb<`]^0\ac `Xb<\]^\ac `BYT\@^0d ∧ e6f0g h
(iv) i j h)klfeXm<elfkBiTk@fn ∧ e@f0g h

Diseño de Algoritmos Cap 2 34


Jaime A Bohórquez V
(iv) 
     
1. Calcule expresiones  tales que
(i) !#"%$ ⋅&')(+* $-,
"/.10 ( ,
" (23& !4"5$ ⋅&5'(+*
(ii) 36 (87:9*; ,
"%.#0<,
"/< =?>
@ ACBDA ⋅EGF/H-I
(iii) B E ⋅HKJL ⋅MNF%OGIEP
F/ERQSL5T M-P
F/U B E ⋅HKJL ⋅MNF%OVI
2. Pruebe
|[ var ERW3HNP Y> X?Z T
B EGF [ ∧ HKF/\I
EP
F/ERQH]T3HP
F/E JRH]T3EP
F/HRQE
B EGF/\ ∧ HKF [KI
]|

Comandos y expresiones condicionales


El comando alternativo. Corresponde a la noción de alternación de casos, se usa el
nombre ^`_ como abreviación. Su sintaxis es la siguiente:
if a1bYc d e]fYg
[] h1fji d efjiDf
f
f
[] h1flknmpoqi:r d esknmpoqi:r
fi
h1fYg a h1flknmpoqi:r son expresiones booleanas llamadas guardas. Las expresiones efYg
a efYg
denotan a su vez, programas del lenguaje de comandos guardados. La ejecución de este
comando procede como sigue:
− La ejecución aborta si al evaluarlas, alguna de las guardas no está definida.
− La ejecución aborta también, si ninguna de las guardas es verdadera.
− Si más de una guarda es verdadera, se escoge sólo una de ellas (arbitrariamente) y se
ejecuta su comando correspondiente, con esta ejecución finaliza la ejecución del
comando alternativo.
• Axioma de alternación tDuwvyx`z#t{v equivale a:
1. u ⇒ h|h y
}
f k ∀ ~€gƒ‚#~]„NmV:tDu†…‡hyf ~nv1e]f ~€t{v:r
donde h|h ≡ (∃~€:gƒ‚#~„GmVh1f ~nr

Diseño de Algoritmos Cap 2 35


Jaime A Bohórquez V
Ejercicios
0. Probar :
(i) 
if     []    fi !#"%$& .
(ii) '()*
& if +-,%. /1032 4 [] 56,7.89,:; ,8 fi ! +6,<& .
(iii) |[ var 8,:2=>'@?
'()*
&
8,:; , ⋅,8A ⋅B?
if C+D,E. : ;FG9, [] ,C+DE. ,B:;F,G9 fi
!H+JILKM,C+JIN&
]|.
(iv) |[ var O
8>PQ:RPS>STU?
'()*
&
if 9V W7XZY [ W \ ]^V9W
[] W7_ X V3Y`[ YQ\]V3Y
fi
a
WbXcYd
]|
a9e anm
1. Probar : d if f g [ih g jh
[] f k [lh k jh fi d es equivalente a
9a e anm
d if f g [ih g [] f k [lh k fi joh d .
a9e anm
2. Probar : d if f g [ih g [] f k [lh k fi implica d
a9e anm
d if f g i
[ h g [] f k pqVrf g l
[ h k fi d .
e
3. Determinar el predicado mas débil tal que
|[ var s\otu>v@j
a9e
d
s\]Fswx#j
if %
s y{z [ sB\]Fs|x
[] ~s }z€[ s\] swN
[] 7 s ]^x‚[ ƒ1„3t …
fi
a
s †xd
]|.

Diseño de Algoritmos Cap 2 36


Jaime A Bohórquez V
Equivalencia de programas y precondición más débil
(Axiomatización alternativa de corrección)
Si es un predicado y  un programa,  
es también un predicado que se lee: “la
precondición mas débil de  con respecto a ” y es cierto exactamente en aquellos estado
para los cuales, si se ejecuta  termina normalmente en un estado que satisface .
Axiomas de 
•   ≡  (milagro excluido)
•  "!$#  ≡  %&!$' #  (∧-distributividad)
•   ∨ #  ⇐  % ∨  #  (∨-semidistributividad)
la equivalencia se da para programas determinísticos
• Si  ⇒ # entonces  % ⇒  #( (monotonía sobre ⇒)

Definición de corrección en términos de 


Los axiomas de corrección dados al principio de este capítulo resultan ser teoremas que se
deducen de los anteriores axiomas, si aceptamos también como axioma la siguiente
definición de corrección total
• Definición: )*%+,-).# + ≡  ⇒  # 
Aprovechamos esta axiomatización para dar una definición formal de equivalencia de dos
programas:
Definición: Siendo  y / programas, 012/ si y sólo si 3450 6 7 ≡ 3845 / 6(7 para
todo predicado 6
Los siguientes axiomas definen los comandos simples y el comando de alternación en
términos del transformador de predicados 34 .
• 3459:<; 4>=?6 7 ≡ 6 (axioma de 9:<; 4 )
• 345@ACBEDFG=?6 7 ≡ H@I9J (axioma de @ACBEDF )
• 345LK-MN1POQ=L6 7 ≡ REBESUT O ∧ 6,V K-MN1WOUX (axioma de asignación)
• 3450GY[ZC0\]=?6 7 ≡ 3450GY^=_3450\]=?6 7[7 (axioma de secuenciación)
• 345?`ba"=L6 7 ≡ ccedQf?gihGjlk$mQhonqprj.c,s hutwvxfyzL{ |[| (axioma de alternación)
Estos axiomas dan lugar a una teoría de corrección de programas en la que se puede
demostrar teoremas generales y particulares sobre corrección de algorítmos, y más
importante aún nos permitirá elaborar una metodología de derivación o desarrollo de
programas correctos por construcción.
Ejemplo: El siguiente es un teorema:
} cc ⇒ ~€‚Pƒ„C…E†‡

Diseño de Algoritmos Cap 2 37


Jaime A Bohórquez V
Prueba:



≡  definición de equivalencia, cuantificación universal implicita 


  

 ≡  


≡  axioma de 
  

 ≡ 

≡   ≡ !  ≡ 
 
! 

≡  axioma de 
#""
! ∧ ∀$&%('*)+$-,/./% "10 $ ⇒ 3240 $ 5


≡  ley de De Morgan 
""
! ∨ !  ∀$&%('6)+$-,/./% "10
$ ⇒ 3240 $ 5
⇐   ∨ 7 ⇐  
""
!

EJERCICIOS

1. 32 8 9 2 :  9 2 ; 2 8 9<32 : 9 2 ;
 (la secuenciación es asociativa)
= >9 2  249 =   2 =
2. $ $ ( $  es la unidad de la secuenciación)

 9 2  2-9 
 ?@
 

3. ( es el anulador de la secuenciación)
= A9 =  = 
4. Muestre que $ $ es equivalente a $ .
2
5. Si es un programa determinístico que termina normalmente siempre, entonces
32?B 32/B
!  ≡ !  para todo predicado  .
2 " EF2
6. Probar que C 7*D C D ⇐ C 7*D if fi C D

El comando de repetición o iteración


Se escribe:
do " G E 2 G
" 8 E 2 8
[]
.
.
.
" H&IKJ H&IKJ
[] L M
od
Como antes N1OQP a N1OSR#TUWVYX son expresiones booleanas llamadas guardas. Las
expresiones M4OQP a M4OQP denotan a su vez, programas del lenguaje de comandos guardados. La
ejecución de este comando procede como sigue:

Diseño de Algoritmos Cap 2 38


Jaime A Bohórquez V
− La ejecución aborta si al evaluarlas, alguna de las guardas no está definida
− Si todas las guardas (están definidas) y evalúan a  , el comando se comporta como

.
− Si más de una guarda es verdadera, se escoge sólo una de ellas (arbitrariamente) y se
ejecuta su comando correspondiente. Al terminar este comando su ejecución (normal)
volvemos a la situación inicial repitiendose de nuevo el proceso que se acaba de
describir.
Por simplicidad, consideramos primero repeticiones de la forma:
do   od

De la descripción operacional se obtiene


 
do   od
≡  semántica operacional3 
 
if   
[]   do   od fi

Anotando la selección obtenemos



  
if   ∧  

  
[]  ∧    do   od
fi


  
Como do  od debería valer. Escogemos como predicado intermedio en la
secuencia:   do   od es decir,

"!  
if    

"!   
[]    do   od
fi


de donde se obtiene:
# "! 

%$  '&
# "!   


(
%$ 
  # # #
(iii) do   od vuelve a dar lugar a %
$ ,
(
%$ y
(
(
%$ .
# #
Si podemos garantizar que la repetición termina
%$ y (

%$ bastan.
Formulamos estas condiciones para una repetición con dos guardas:

3
La semántica operacional es la forma clásica de describir el significado de un programa (el efecto de su ejecución)
mediante la composición de los efectos de los comandos que conforman dicho programa.

Diseño de Algoritmos Cap 2 39


Jaime A Bohórquez V

 
 ¬



  
 

implican
 do
  []
  od 

siempre y cuando esta repetición termine.



Un predicado  que satisface se llama un invariante de do
   []   !  od. La
terminación de una repetición se prueba por medio de una función entera sobre el espacio
de estados que es acotada inferiormente y que decrece en cada paso de la repetición. Tal
función se llama una función cota o límite.
El algoritmo de Euclides
"#
var $&%('*)(+,.-0/
12
)$436587'439:7;$4<>=?7;'4<>=A@
BDCFE(G BJI
+H
1K E
)$4365 L H 9M@
N "

Solución:
BDCFE(G BJI
+H = do $<O' $*)P3Q$&R'
[] '4<O$ S'*)P3T'&R$
od

Diseño de Algoritmos Cap 2 40


Jaime A Bohórquez V
donde     ↑


 
 para !#"
Propiedades (leyes) del máximo común divisor
&$ %(' ) *,+ '-.'
/10(2 3 4,5 67.6 34,5 2
8:9(; > < =? @ AB,C D>EFGIHJDLK M N,O D
Por (2) tenemos también
D PRQ>S Q TU,V WXQ TU,V YWIZJQL[
Probaremos (3):
\(].^ _`,a b
⇒ c aritmética y definición de de,f gih jk>l
m!n kpo m!n&qrIs kLt
⇒ u definición de vw,x l
y>z|{}I~JL€ ‚,ƒ 
⇒ „ y(….} ‚,ƒ  † ‡‰ˆŠ‹IŒJLŽ ,‘  y aritmética ’
“>”R‡–•|‡˜—‹p•™‡˜—
⇒ š “(ˆ.‹ ,‘  ’
“>”R‡ •›‡˜”œ“
⇒ š aritmética ’
“(ˆ.‡

Hemos probado:
‹  •ž“(ˆ‹ ,‘ •›‡Ÿˆ Š‹IŒJLŽ ,‘    “(ˆ‡
Lo cual implica (3.).

Mostraremos que la solución es correcta, es decir:


¡£¢™¤(¥§¦©¨ª¬«®­¯¥,° ¡J±!¤
Sea ²‰³µ´!¶#·‰¸º¹!¶»·Ÿ¸|´ ¼½,¾ ¿>ÀÂÁ ÃÄ,Å ÆÈÇ Observe que:
É
≡ Ê definición de ÉÌË
ÍÎÏÑÐ|Ò>Î Æ Ð|Í!Ó#ԟÐ|Ò!Ó#Ô
≡ Ê regla de Leibnitz Ë
Í ÕÖ,× ÒÎ Ï ÕÖ,× Æ Ð›Í>ÓØÔ!ЛÒ>ÓØÔ
≡ Ê definición de Ù Ë
Ù
Diseño de Algoritmos Cap 2 41
Jaime A Bohórquez V
es decir: 
Ahora bien,
 

≡  definición de 
       
≡  aritmética y proposición (3.) 
!" #
$&%' !" )(    
≡  sustitución textual 
*,+ -/.102-!3"465
*7
- 8 4 ≡ 9: ;/<1=2;!>"?6@BA por tanto por axioma de asignación
C 9DE;F?)GH;/<1=I;!>"? C 9G
es decir:

C 9D? F ;)GH?/<1=2?!>"; C 9G


Similarmente se puede obtener:

JKMLON'P QR#STR Q P)U VWV Aserción válida al final del ciclo


Finalmente:

≡ X aritmética Y
JKMLON'P ≠ R)U
≡ X definición de ≠ Y
JK
P = R
⇒ X regla de Leibnitz y proposición (1.) de Z[\ Y
P]I^ Z[\ _
Hemos mostrado la corrección parcial del ciclo `baO[dcfeg\W`h es decir:
iBjlk `baO[dcfeg\W`Bh i"mk siempre y cuando nBolp"qbrOsdtfugvWqwdndxgyzrOq/p
¿Como mostrar la terminación del ciclo solución para qbrOsdtfugvWqw ?
do { |} ~{1€I{!"}
[] }|{~}‚1€2}!"{
od
Considere la función (del estado de ejecución de ƒb„O…d†f‡gˆWƒ‰ ) ŠŒ‹I Ž 
‘“’  ≠ )”
(1) Claramente:

⇒ • aritmética –

Diseño de Algoritmos Cap 2 42


Jaime A Bohórquez V


en la medida que haya otra iteración por realizarse i.e. ≠ 


se tiene que  
(2) En cada iteración, decrece:
!"$#%&'()+*,!
y
!",#%'()+*!

Para mostrar la primera afirmación de (2) basta mostrar que:


-.+*,!/10 (#%&'32
65
≡ 4 definición de
-78*,!/10 (#%&'32
5
≡ 4 sustitución textual y aritmética
*,
 65
≡ 4 y definición de
*98
5
≡ 4 aritmética
:
;5
⇐ 4 definición de

BADC
(1) y (2) garantizan que <>=@? <1E no puede ejecutar indefinidamente. En general, para
mostrar que un ciclo:

Diseño de Algoritmos Cap 2 43


Jaime A Bohórquez V
 do    

[] 


[]     
od
cumple  es suficiente encontrar un predicado (invariante) y función límite !
tal que:

(0)  "#

(1) %$'&)(*( ⇒ 
(2) %$+(-, ./01, .2 para 354768:9;9;9<8>=
(3) ?%@BACAEDGF1HJI
(4) KL%M+N-O P:MRQTSVU1W0X1O P2KYQTZ[U1W para PTS\]:O;O;O ]_^ donde N*N'Sa` b c deBfhg2fjilkm0n g/o
No olvidar que:
p'qsr ∀c kte ≤ g ≤ ulv>w;x;yz{0z |/} es otro compromiso de demostración subyacente.

2.2 Técnicas Elementales de Derivación Formal de Algoritmos


Derivación de asignaciones
Ejemplo: Considere la función ~ definida por:
~0€ƒ‚„€
~0†…‡‚7…
~ˆŠ‰ ‹ ŒŽ’‘-“ Œ para Œ•”—–
‘˜Š™ ‹ Œ›šœ–:‘-“ Œ•š•‘˜žŒ›šœ–: para Œ•”JŸ
y el predicado:
 j¡¢j£V¤ ¥ ¦-§ ¨•©ª « ¦¬ž¨›©œ­:® (¯ constante entera)
Queremos encontrar ° y ± tales que:
²³µ´·¶•¸R¹º´¼»¾½;¿À ¶ŽÁ0¶›Â_½›Â;ÃÄ<ŝ¶ Æ;Ç<È ÉËÊ_ƛÊ_̕ÍÎÏ
Æ ÉBׄØ
(donde оÑ;ÒÓ Ô ≡ Ô Õ‡Ö ), este problema aparece en la derivación de ciclos del estilo:

Diseño de Algoritmos Cap 2 44


Jaime A Bohórquez V
 

do
if 

     


“Preservar reduciendo a la mitad
y actualizando  y  adecuadamente”
 
[]  





fi
od
investigando


=  definición de 
   "!  $#%&!('*)  
=  suponiendo 
,+$ y definición de 
  $#% -
.0/  12)(!   #3$#% -
.0/ 12)(!4$#% -
.0/ 15!('*)6)
=
  aritmética
#%&!  )  $#% -
.0/ 12)(!  $#% -7.0/ 18!('*)
=
: 9 ,+sustitución
;   textual y definición de
-
.0/ 1<+=&! ?>
Derivación de comandos alternativos (Análisis de casos)

HJI*K*K LNM O P @
Ejemplo: Siendo entero “al menos cero” A @CBED<F
y arreglo entero con subindices enG
y , variables enteras, considere los predicados:
Q R S;TVUXWZY []\ ^ _8`bacedgf d4hi_kj;l c3a`mXjnl f"op`<q
r s _8`5ah"d4t
u _;vVwXxZy z _*`bac,d{h{_|j;l c}a`<q
se desea solucionar el siguiente problema de programación:
~ r  m r s m u5€
 _ “Incrementar h ‚ ƒ
~r  € en actualizando ”

este problema aparece al derivar un ciclo del estilo:

do „6…‡†ˆ ‰ Š ‹ ŒbŠ  ŒŽ5


‘i’ “incrementar „ en “ actualizando ” ”
‰ Š ‹ 
Diseño de Algoritmos Cap 2 45
Jaime A Bohórquez V
od

Observando la estructura sintáctica de  


observamos que no aparece en el miembro

derecho de la igualdad (y no aparece en lado izquierdo). Sabemos además que debe 

incrementarse en , queremos averiguar como actualizar 
consecuentemente. Trabajando
con el miembro derecho de 
bajo la sustitución:  

y suponiendo como hipótesis
    tenemos:
      !
"$#&% '() *#&%,+(.-
=  ruptura por / , suponiendo  0
      !!1#&% '() *#2% 3+4.-
  567891#2% '4 *#&% 9+4.-
=  suponiendo  0
:
  ;!!<#2% '4= >#&% 9+4.-
=  análisis de casos sobre #&% 30
 si #&% ,?

 :

  6789$#&% @(.- si #&% 9+4


=  suponiendo A0
 si #&% , 

B
7C si #&% D+(

Obtenemos la siguiente solución para E


FG    ;H
if #&% 3I"JK!L

[] #2% 9+4"JK MNO L3
PMNB
7C
fi
FG Q R
Derivación de ciclos (repeticiones)

Dado un problema SUT RLVXWXY[Z SG\ R


. Excplicaremos como derivar una solución para XV WXY[Z ,
suponiendo que sabemos como proponer (o contamos con) invariantes y funciones ][^ WX_
adecuados

Diseño de Algoritmos Cap 2 46


Jaime A Bohórquez V
Dos métodos:
a) Guardas primero:
Paso 0: Elija invariante y guarda que sastisfagan  
. Esta garantiza que al
finalizar la ejecución del ciclo a diseñarse obtenemos el objetivo: (Logro del objetivo).

Paso 1: Establezca inicialmente el invariante . Es decir, derive un programa que  


satisfaga   
. Esto garantiza que el invariante vale al inicio de la repetición.

Paso 2: (criterio de terminación) Escoja una función cota que satisfaga .    
En otras palabras encuentre una función (así sea implicitamente) cuyo decremento
garantice la falsificación de la guarda del ciclo. Esto nos garantiza que el cuerpo del ciclo
no ejecutará indefinidamente.

!
Paso 3: Derive (el cuerpo del ciclo) de tal manera que satisfaga "#$! (es

%&')(*',+.-0/213$%4+657/21
decir, que preserve el invariante después de cada iteración) y a la vez,
(avance hacia terminación).

&
b) Terminación primero:
Paso 0: Encuentre una forma de establecer el predicado invariante inicialmente.

.3 < =
Paso 1: Encuentre una función 8:+ 9 + ;
adecuada al invariante elegido ( ). Proponga
(>< =
&
%&?'@(>< =A',+.- 8 136< =%4+.5 8 1 8& :9 + ;
subprogramas que decrementen . Encuentre guarda tal que :

%&')(>< =B136< =%&1 decrezca la


preserve
y
invariante.

C DFEGHGJIK>L EBMON7PRQTS
Paso 2: Continue realizando el Paso 1 hasta que:

GYE Z[]\_^ X ≥ `_a


EJERCICIOS
U W Y
V X
U ^dGcbE Zef` G
0. |[ var

` ≤U ≤X
\[G XdgUha
\ do U ≠ X → U Gcb Ujilk od
^ U b Xa
]|

Diseño de Algoritmos Cap 2 47


Jaime A Bohórquez V
1. |[ var  
  ≥ 


 !#" $ ∧ % ≤ &('()+*&,%.-
' do % ≠ & → %/0*12%354/030 od
6
071#8 9 :
]|

2. |[ var ;<= >? @ACBD= ≥ E:


;>FHG
D? @I >J ∃K7>K ≥ EL>M;7FON P Q ∧ R(SOTVU(W+X √Y  Z [\R.]
U do R!^_Y → RX`aRbR od
c
R ≥ Y ∧ d ∃e7Xe ≥ TfXR7`Og P Qh]
]|
c
3. |[ var ij RjY Xk lWU Y ≥ T]
ijRX`TjT
c
k lm XR ≤ Y ∧ i ≥ TVU(WnXibodpY[R.Q ⋅ dpY\brqVQs]
U do i ≠ T → iX`2i[q
[] R ≠ Y → ijRX`tYjRb5q
odc
i7`uT ∧ R7`aYv]
]|
c
4. |[ var ij Rjw(Xk lWU W xzyV{|]
ijRX`TjT
c
W+X} ⋅ d~i ↑R ↑wQr[d~ibRb|wQs]
U do i!^7R → iX`aib5q
[] R(^_w → RX`2Rb5q
[] w€^!i → wX`twMb5q
od c
i7`2R7`tw ]
]|

Diseño de Algoritmos Cap 2 48


Jaime A Bohórquez V
5. El siguiente programa puede usarse para calcular (no determinísticamente) un par de
números naturales e  tales que ⋅ . Demuestre
|[ var  ,   

 ≥ 
       
 ! ⋅ "  ∧ # $  ∨ $ &%'
 do  ≠ ( →
if  )+*, - ( →    . "    
[]  )+*,  ( →   ! "    
fi
& ⋅  
]|

6. Para números naturales / y 0 , / )+12, 0 denota el máximo común divisor de / y 0 . Por


definición ( )+12, /3 ( y / )+12, (  ( . Demuestre
|[ var  456&57 89:;<=>6 ≥ 7@?BADC
E 5 48F.657
= E ≥ 4-?GA ∧ E H+I2J 4F.6 H+I2J 7 C
E 548F.657
< do 4 ≠ A → E 548F!4 5 EKH+LJ 4 od
= E F.6 H+I2J 7 C
]|

Diseño de Algoritmos Cap 2 49


Jaime A Bohórquez V
2.3 Subprogramas: Comandos Modulares
Es frecuente en programación la necesidad de diseñar comandos que conforman unidades
constitutivas de un programa más complejo, y por tanto, no se reducen a simples
fragmentos del programa global, sino que la intención de su diseño es la de poder
invocarlos repetidas veces y respondiendo a diferentes valores de parámetros. Conviene
entonces, dar un nombre a este fragmento de programa y seleccionar unos parámetros de
entrada y unos resultados.
Existen dos estilos de definir estos comandos modulares que responden a los conceptos de
procedimiento y función (calculada algorítmicamente). El principal uso de estos comandos
es el de realizar abstracciones. Con el término abstracción, nos referimos al acto de
singularizar o separar algunas propiedades de un objeto para uso o estudio posterior,
omitiendo la consideración de otras propiedades que no nos conciernen en el momento. La
principal propiedad que se singulariza, al escribir una función o procedimiento, es qué
hace; la principal propiedad que se omite es cómo lo hace.

Funciones definidas en términos de comandos.


Procedemos a explicar el concepto de función. Para especificar mediante precondición y
poscondición una función es preciso conocer que variables (o parámetros) representan
datos y que variables resultados. Es útil elegir un nombre para la función. Así pues la
especificación constará de tres partes, que escribiremos usualmente en lineas sucesivas: el
encabezado de la función, su precondición y su poscondición.
El encabezado indica el nombre de la función y también el nombre y tipo de los parámetros
(variables locales) en que recibe los datos, y las variables locales en las que se calculan los
resultados. La precondición constituira usualmente una aserción que involucre los
parámetros. La poscondición involucrará además las variables elegidas para los resultados,
su validez deberá ser establecida antes de efectuar el comando de devolución o retorno de
resultados que como veremos, aparece siempre como último comando (del cuerpo) de una
función.
Por tanto, la sintaxis para presentar el encabezado de una función es como sigue:
funct nombre  parámetros ret resultados
donde parámetros y resultados se reemplazan por declaraciones separadas por ";"
Tanto los parámetros como los resultados se comportan como variables locales o
privadas al fragmento de programa que define el cuerpo de la función (programa que la
define); los parámetros obtienen como valores iniciales, los valores de los argumentos, que
son los que se pasan con ese fin, en el momento de invocar (o llamar) la función. No se
suponen valores iniciales para los resultados. Los identificadores que se usen para denotar
los resultados, si hay varios, han de ser todos distintos entre si.

Diseño de Algoritmos Cap 2 50


Jaime A Bohórquez V
Por ejemplo, la especificación de una función que calcula cociente y residuo de una
división entera entre dos números naturales, el segundo de ellos no nulo, se vería así:
funct  
 
 ret 


  "!$#&%')(*#,+

 .-/ ⋅102/%3#541678+
Los resultados de una función especificada de este modo, se deben asignar a variables que
aparezcan en comandos de asignación desde donde se haya producido la llamada a la
función. Se dispondrá de una asignación múltiple para el caso en que la función devuelva
varios resultados simultáneamente.
Una vez calculados los resultados, todos ellos apareceran al final del cuerpo de la función
en una instrucción ret que representa la devolución de resultados al punto en que se
produjo la llamada. Sólo puede haber una instrucción ret en cada función, ha de estar
situada como última comando a ejecutar. Así, completando el ejemplo anterior
obtendremos algo como:
|[ funct  
 5
9 dev :


  "!$#&%')(*#,+
:1 -;#: =<

 .-> ⋅?02/%@!A#,+
do !B CDE->0GFHJI od;

 .-/ ⋅0KL%M#54E658+
ret :
]|
Observe que la poscondición se escribe justo antes de la devolución de resultados.

Invocación de comandos modulares


En las expresiones que aparecen a la derecha de un comando de asignación pueden aparecer
invocaciones a funciones matemáticas. El cálculo de corrección de programas que hemos
venido describiendo presupone el conocimiento de propiedades algebraicas de estas
funciones, para poder realizar razonamientos basados en aserciones. Estas propiedades
provienen en general de la teoría de números o del álgebra booleana o en particular, de las
teorías asociadas a los tipos de las funciones invocadas.
Sin embargo, es posible invocar funciones especificadas en términos de precondiciones y
poscondiciones que se evaluan de acuerdo a los resultados arrojados por la ejecución de su
cuerpo (programa que la define); dicha ejecución es iniciada con los argumentos
proporcionados en la invocación, como valores iniciales de sus parámetros. Este caso se
tratará mediante una extensión del postulado de la asignación de la siguiente manera.
Cuando se realice una invocación a una función especificada con precondición y
Diseño de Algoritmos Cap 2 51
Jaime A Bohórquez V
poscondición (y por tanto definida en términos de comandos), con el fin de de facilitar los
razonamientos sobre su corrección, se escribirá en un comando de asignación de la forma:


o en caso de devolución de varios resultados simultáneos
 
  
y análogamente para más de dos resultados.
En primer lugar, toda aserción en que no aparezcan libres las variables asignadas puede
suponerse cierta después de las asignaciones arriba mencionadas, si valía justo antes de
ejecutarlas. En otras palabras, la invocación de una función (comando modular) no produce
efectos colaterales, sólo resultan afectadas las variables en el lado izquierdo de la
asignación. Concretamente, se debe establecer que justo antes de esta asignación, las
expresiones que se pasen como argumentos cumplan la precondición de la función; en
seguida de la ejecución de este comando, las variables a las que se han asignado los
resultados cumplirán la poscondición.


Supongamos por ahora, que ningún parámetro tiene el mismo nombre que un resultado.
Entonces si es una función especificada como sigue:
      ret   !
"
funct
" ##$&
Pre
Pos '%
%
Una llamada a ( sobre los datos ) * +-,,+) . que asigne los resultados a las variables / * +0,-,+/ !
responde al siguiente postulado:
" $21 3 * +-,,+3 . # 45) * +-,,+6) . 7%
" /';* 1 +3 ,* +,+,/ ,! +<3 #4 (8) * +,,+9) . :
. +6= * +,,+9= ! #4>) * +,,+9) . +/ * +,,+/ ! 7%
Continuando con el ejemplo anteriormente presentado, como la función division retorna dos
resultados es preciso invocarla de la siguiente manera:
? +@A#4>BCDCEBCE=98) * +6) F : donde ) * GH) F son expresiones aritméticas
Aplicando el postulado anterior, este comando satisface la siguiente especificación:
" 8 I J2KL5MHNOK0:P1QI+MR#4>) * +9) F 7%
?
" 8+I@A4T#4SM B⋅U;CDVCEB=W
CE=98) * +6) F :
LXKZY[=]\ZMA:P1QI+M+6U+6=#4>) * +9) F + ? +@^7_%
Con lo que se obtiene
" ) * J2KL`) F NOKZ%
? +@A#4SBCDCEBCE=98) * +6) F :
Diseño de Algoritmos Cap 2 52
Jaime A Bohórquez V
     
⋅

 
No es necesario que los argumentos sean variables: pueden ser expresiones. Por ejemplo si
los datos fuesen  ⋅ e  ,

(*),+.⋅ -0/2 1 "034!#
1 65*%7  $&⋅ 
) ' 98
 /
⋅ 7:98 ⋅(  + !;
< += 7:98>'
que se puede argumentar como ya se mostró.
Prescindimos ahora, de la suposición realizada un poco más arriba, de que ningún
parámetro tiene el mismo nombre que un resultado. En caso de que se empleen como
parámetros una o más de las variables que retornan los resultados, para relacionar y
distinguir entre sus valores iniciales y los que éstas adoptan después de la llamada, es
preciso hacer uso de variables de especificación (estáticas) que registren dichos valores
iniciales en la precondición.
Parámetros externos o contextuales

Es posible también, mencionar y afectar variables contextuales o externas a una función


(diferentes de sus parámetros de entrada, resultados y variables locales al cuerpo de ésta).
Su uso es conveniente cuando la ejecución de una función (en especial recurrente) lleva a
cabo multiples asignaciones que afectan localmente estructuras de datos complejas. En ésta
y en otras situaciones las variables "contextuales" (es decir, bien entendidas), simplifican y
evitan el uso de excesivos parámetros en los encabezados de función que compliquen y
enturbien el texto de sus invocaciones. Estas variables que proporcionan contexto a la
invocación de una función y que existen y persisten antes y después de su ejecución son
llamadas globales (a la función) en la literatura sobre lenguajes de programación. La
diferencia aquí, es su uso disciplinado mediante su documentación en la especificación de
las funciones que las mencionan y afectan.
Procedemos a explicar los efectos adicionales que ocasiona la invocación de una función
especificada en términos de precondiciones y poscondiciones cuando se mencionan
variables externas o contextuales en su cuerpo. Una correcta especificación de una
invocación a una tal función debe mencionar las variables contextuales que afecta. Es
-0/A@ 7:BC8 , ? )9D-0/E@ 7GF ) 3 )9H 8 , etc. Para
preciso recordar, que los argumentos relativos a la correcta invocación de una función se
realizan en el contexto de asignaciones de la forma ?
estas asignaciones se debe establecer que, además de lo ya estipulado anteriormente, justo
antes de su ejecución, los valores iniciales de las variables contextuales afectadas por la
función satisfagan su precondición; en seguida de la ejecución de este comando, (los
valores finales de) las variables contextuales afectadas por la ejecución del cuerpo de la
función deberán cumplir con la poscondición.
Los efectos de la invocación de una función que afecte variables contextuales (globales)
son llamados efectos colaterales (inglés: side effects) en la literatura sobre lenguajes de
Diseño de Algoritmos Cap 2 53
Jaime A Bohórquez V
programación, con obvias connotaciones negativas debidas a la impredecibilidad de los
mismos; aquí, preferimos llamarlos efectos contextuales (sin connotaciones negativas!)
pues a diferencia de los anteriores, éstos estan debidamente documentados en la
especificación de la función.
Con esta extensión del concepto de función calculada con base en comandos no es
indispensable el cálculo de resultados. Los ya mencionados efectos contextuales de una
invocación pueden constituir la razón de ser de un comando modular (y no los resultados
producidos). Desde este punto de vista, es razonable hablar de funciones basadas en
comandos que no producen resultados. Es en este caso, que se prefiere llamar
procedimientos a este tipo de comandos modulares. En consecuencia, modificaremos la
sintaxis del encabezado de funciones que en realidad respondan al concepto de
procedimiento de la siguiente manera:
proc nombre  parámetros
No habiendo resultados que calcular y guardar, (además de la inutilidad de la mención de la
instrucción ret en el cuerpo del procedimiento,) el requisito de realizar la invocación en el
seno de un comando de asignación deja de tener sentido:
Si  es el nombre de un procedimiento que responde a la siguiente especificación:
|[con  
   

     

var 
   

  "! 

proc $#&% ' (*) ) (+% , -
.
. Pre / 021
Pos /4351
]|
(donde las constantes y variables declaradas en el primero y segundo renglón corresponden
a los parámetros contextuales antes mencionados); una llamada a  sobre los datos
' () ) (
,
responde a la siguiente sintaxis y postulado:
.
076 % ' (*) ) (+% , / 89
' (*) ) (
, : 1
. $#
' (*) ) (
, -
3;6 % ' () ) (<% , /=8>
' () ) (
, : 1
Ejemplo: El procedimiento
  asigna el valor cero a las primeras  celdas de un
arregloentero de longitud ? .  , ? y  son parámetros contextuales de
  .
. .
|[ con ?5/@ BA ? ≥ CD1 3N/ # ∀O /C ≤ QPRE/ ) S8TC - 1
var E/@ GFH6IC )J) ? - LK BA ]|
proc
G  # E/@  -
.
  # ?  = U -
02/*C ≤  ≤ ?M1 La invocación cumple:

Diseño de Algoritmos Cap 2 54


Jaime A Bohórquez V

≤  ≤ 
    
     
  
∀ ≤ "!## %$'& " 
#  )  
(
2.4 Corrección de Algorítmos Recurrentes
Entre las posiblilidades que ofrecen los lenguajes de programación de repetir cálculos
mediante un texto breve, además de los ciclos o comandos iterativos está la recurrencia, es
decir, la posibilidad de que un subprograma (en nuestro caso una función) contenga entre
sus comandos, una invocación a sí misma.
Como primera observación, destaquemos el hecho de que, en todo programa recurrente
debe haber al menos un comando alternativo. De hecho, el texto debe incluir invocaciones
del mismo programa, por ser recurrente, pero no en todos los casos, pues de lo contrario la
recurrencia no detendría su ejecución; por tanto, han de aparecer en un comando alternativo
en el que no todas sus guardas o ramas lleven a una recurrencia. Distinguiremos entonces
en ese comando alternativo dos tipos de casos: los casos directos, que no ocasionan
llamadas recurrentes, y los casos recurrentes. Los programas recurrentes más sencillos
obedecen al siguiente patrón:
*  ,
funct + - .  ret  - /
Pre 01
if 24365879;:=< >
[] ¬2?3@5879BA'CD>FEDGHCJIK< >MLNL
O fi
Post 7KPRQ
ret 5
SNT

Donde U , : , I y A son expresiones o funciones conocidas (bien entendidas)

Esquema de corrección de una función recurrente.


Para encontrar condiciones suficientes para la corrección del patrón de función recurrente GVE
planteamos una prueba inductiva de G aplicada a un valor > ; asociando a cada valor > que
pueda aparecer como parámetro de la función un número natural W < > ; de esta forma
podemos suponer como hipótesis de inducción, que funciona correctamente para todos
aquellos parámetros cuyo natural asociado es inferior a W < > . El caso base de la inducción es
el caso directo, en el que no se supone la corrección de G en ningún valor.
Análogamente al caso de los comandos de repetición, la función W < > recibe el nombre de
función límite o función cota. Esta función W , a la vez que valida el razonamiento por
inducción (todo conjunto bien fundado admite inducción), garantiza la terminación de la
Diseño de Algoritmos Cap 2 55
Jaime A Bohórquez V
secuencia de llamadas recurrentes, ya que cada una ha de tener un valor natural  
estrictamente inferior al de la anterior, lo que no puede ocurrir indefinidamente.
En síntesis, para la función cota se pide:

 

b)  ¬   

Teniendo en cuenta el postulado de corrección del comando alternativo, observamos que


para el caso directo, es preciso justificar que  efectivamente resuelve el problema para los
datos que satisfacen la condición  , es decir, por el postulado de la asignación,
(0)      !"#  (caso directo o trivial)
Para el caso recurrente, aplicamos el postulado que se dió para verificar la corrección de
una invocación a una función definida en términos de comandos. Deberiamos entonces
garantizar
(1)  ¬$    %  (corrección llamada recurrente)
para asegurarnos de que la invocación o llamada se realiza legalmente, y por otra usando la
hipótesis de inducción y el postulado de la asignación:
 3
(2)  ¬&'  )(*!% +(-,)./      0%12.-)(,)./  ] (caso recurrente)

Como ejemplo verificamos la corrección de la siguiente función recurrente:


4 76 
 funct 5 ./8*9587 ret : *9583
;<
>=?*8 ≥ A@

if 8BC D : C
76 6 JI 6
[] 8 ≠ ED :  F7 ⋅5 ./8 9G H 8 :LK H

;<
fi
IB  6 
K ! : M. N AO  ./82( ⋅ F7 P Q3R

ret S ;
T3U

donde VW/X2Y+Z Q es el Z -ésimo dígito binario de la representación de X en base 2 comenzando


por la derecha y enumerando desde 0.
Formalmente: VW/X2Y*Z Q[ W/X V7Z\ ] ^ Q SL_7V ] . Además, es bien sabido que la relación entre
VW/X2Y+Z Q y X se puede escribir también como: X [ Wa`BbdcNeAfgbhc!VW/X2Y*b Q ⋅] P Q

Para el caso trivial, claramente,


i T
_7j0k SBc [ e

= l sustituyendo m

Diseño de Algoritmos Cap 2 55


Jaime A Bohórquez V

  ⋅   
⇐  ∀
 
  ! "
#
La recurrencia se apoya sobre una relación bien fundada pues, eligiendo $
% como función
límite tenemos claramente que
 ≥ ⇒$ ≥ y
 ≥ ∧
 ≠ ⇒
 '&)( *+, .
La llamada recurrente es correcta puesto que:

≥ ∧ ≠

⇒  aritmética "
 '&)( * ≥

' '&)( *+ :


Para verificar el caso recurrente, intentamos expresar el resultado de $.- '0/  en
terminos de $.-
 1  23 ⋅   
 〈 definición de  〉
 1  4 &)( *   576' *+ ⋅   
 〈 ruptura por 8 y aritmética 〉
0  
 &)( *+ '&)( * 9:; < =7>'? @+< ⋅ 'A B 9:!; ⋅ A'B <CD =7>'? @
E 〈 distributividad y cambio de variable FHGJIKML 〉
L'N ⋅ OQPFSR
N T FMR
OOU V'F)W X+Y V'F)W X Z Y [7\'V X )⋅ L'N Z YPU [7\'V X
G 〈 definición de V 〉
L'N ⋅ OQP0FSR
N TFR]VOU V'F)W X!^F_Y ⋅ L'N Z Y`PaU [7\'V X
G 〈 Hipotesis de recurrencia b.cdI'VOU V'F)W X+YeGOP0FR
N T FR3VOU V'F)W X!^3F_Y ⋅ L'N Z Y 〉
L'N ⋅bfcdI'VOU V'F)W X+YPU [7\'V X
Por tanto,
g \'h]ij[#R)GkL'N ⋅.b cdI'VOU V'F)W X+YPU 7[ \'V Xml

U ≥ N ∧ U ≠ N ∧ g \'h]ijU2^3[#R)GJU V')F W X!^3b.cdI'VOU V'F)W X+Y'l
Corrección de recurrencias no lineales

En realidad, las ideas anteriormente expuestas aplican a toda clase de funciones recurrentes
sin que sea necesario enunciar explícitamente un postulado de corrección para ellas. Todo
lo que se debe tener en cuenta para el desarrollo de una prueba de corrección de una
función o procedimiento recurrente es, además de la aplicación de los postulados de
corrección para los comandos secuenciales involucrados (en particular para el comando de
Diseño de Algoritmos Cap 2 56
Jaime A Bohórquez V
selección), la aplicación de argumentos inductivos fundamentados en una relación bien
fundada que permita usar la especificación de sus invocaciones recurrentes como hipótesis
inductivas que apelan a los postulados de corrección que se establecieron para las llamadas
o invocaciones a comandos modulares (funciones o procedimientos).

Presentamos a continuación la verificación de una solución recurrente a un problema


elemental que ilustra en la práctica, las observaciones expresadas en el párrafo anterior, a la
vez que exhibe el manejo y la conveniencia del uso de parámetros contextuales (variables
globales documentadas!). Se trata de hallar los elementos máximo y mínimo de un conjunto
de números. Especificamos el problema de la siguiente manera:
 con 
 
   
"!# ≥ $&%
var '()+*,'(-.

!/0;(2<1 =?∀>@3;(*54AB   ≤ 7684869   ≠  4,:%
C#DFE ;(<=GIH ↑ A E"JLK A?M9N EPO,Q A R ∧ ;(ABGIH ↓ A E JLK A?M9N .E O,Q SA R(T
]|

el programa ;(<=?>@;(AB
La solución
E J
;(<=+U+;(AB GV;(;WH UNR , donde ;(; es un comando de función
para
que se apoya en N
es simplemente la asignación:
Oy como parámetros contextuales y que responde a la siguienterecurrente
X Y con N E AB
Z [ OE <
\\<] YJQQ NR^_ AB
Z [ C N ≥ ` T
especificación:

Ca0E H ∀A3U5b E"J ≤ A7M8b8M9N EO,Q A ≠ O,Q b,R:T


E
funct ;(;WHc<?U
d AB:ZSR ret e Ucf AB
Z
E
Ca g E"J ≤ <MLd ≤ NhT
C#D g E e GIH ↑ A E < K A?MLd EOQ A R ∧ fiGjH ↓ A E < K A?MLd EOQ ASRkT
]|
;(;
E E
El cuerpo de la función es como sigue:
|[ funct ;(;WHc<+U
d AB
ZSR ret e Ulf AB
Z
var enm Ulf m U e+` Ulf ` U:op[,AB
Z [
if dpGq<+r mjste Ucf G
E OQ <?U O,Q <
[] d ≠ <+r mIs
o E G Hc<+r2duR v
Axw ` [
Cly g E"JLK <Mzo{M|d K NhT
enC8m y Ulgf m U y e+` Ucf ` E G};(y ;W E Hc<?U:ouGIR~UH ;(;WA HE o< U
Kd2R€A?[ MLo E OQ A@R ∧ f m GIH ↓ A E < K 7A M|o .E O,Q ASR ∧
∧ donde enm GIH ↑ A E o K A7MLd E.O,Q A@R ∧ f ` IG H ↓ A E o K A7M|d E.O,Q ASR T
e+` ↑
Diseño de Algoritmos Cap 2 57
Jaime A Bohórquez V

↑ 
↓ 
fi
ret 
]|

Verificamos la corrección de este código. En primer lugar, fijamos   como función
límite para mostrar que la recurrencia de  se apoya una relación bien fundada, y por
tanto, termina.

Note que
 
⇒ ≥
 
≡  definición de y 
 ≤  !
  ≤ " ⇒  ≥ 


≡  aritmética 
$#&%'
Y por tanto, la primera condición para la función cota  se cumple. El resultado de la
siguiente demostración nos será útil:
 
∧  ≠  ()

 
⇒  definición de y aritmética 
 ( ≤ 
⇒  monotonía de ≤ 
 ( ≤  ( ∧  (*( ≤ +
⇒  monotonía de ,*-. y aritmética 
 0/1 (32 ,*-. 4!

Procedemos a mostrar que la función cota  cumple con su segunda condición, teniendo en
cuenta, que la única función de la variable 5 es la de guardar el valor /1 (32 ,*-. :
 
∧  ≠  ()

⇒  resultado anterior 
 0/1 (32 *, -. 4!
⇒  aritmética 
 60/1 (32 ,*-. !7 ∧   6!/1 (32 *, -.
⇒  definición de 8
 6 :9   /1 (32 ,;-. =< ∧  6 > 9 ? /1 (32 ,*- . =<
Mostramos ahora la corrección del caso no recurrente del comando de selección del cuerpo
de  :

Diseño de Algoritmos Cap 2 58


Jaime A Bohórquez V
 
    

≡ sustituyendo 

  
    " #   
↑    ! ∧ ↓ $  %!

⇐  regla de un punto 
&')(


')(
Para continuar con la prueba de corrección del caso recurrente ( ≠ ) podemos hacer
uso de la corrección de las llamadas recurrentes (hipótesis de inducción):
*,+  .- / /465
1023
*87  
 25 7  9
 0 0 ∧
(8,:(8;<=;> &?@?A ?@?A 
0B! 0 <!
*  ,
(8,:(.  ,
&;<=;C +  5
∧ ∧
*D+  + E 5

y entonces, basta demostrar los siguientes dos hechos:
*87  ')(F5
∧ ≠
' ;BJ
0 B! GH I
*,+  .- / /465
1023

y
*D+  + E 5

,
( ;<,:( =;
↑ ↓
*  5

El primero resulta trivial si nos apoyamos en un resultado probado anteriormente.


Mostramos el segundo:
 
( ;<,:( =;C
↑ ↓
≡  sustituyendo 
( ;  KL K  :( =;    
↑ ↑ $3  ! ∧ ↓ ↓   %!
+ 
≡  suponiendo y por ruptura de rango 
( ;  KL K     
↑ ↑ $30  ! ↑ ↑  0    ! ∧
:( =;        
↓ ↓  0 %! ↓ ↓  0   %!

⇐  Regla de Leibnitz 
+ E

EJERCICIOS

Diseño de Algoritmos Cap 2 59


Jaime A Bohórquez V

1. Dados naturales y diferentes, sabemos que cualquier natural que divida a ambos
divide también a su suma y a su diferencia. Utilizar este hecho para especificar y escribir
un programa recurrente verificado que calcule el máximo común divisor de dos
naturales dados garantizando su corrección. Proponer varias soluciones.


2. Especifique y escriba un programa recurrente que, dados dos naturales y , calcule al
parte entera por defecto del logaritmo de en base . Garantice su corrección.

  

 
3. Especifique y escriba un programa recurrente que evalúe el número combinatorio:
m
⋅ . Calcúlelo evitando hacer uso de la función factorial, pues da
n
lugar a valores exageradamente altos. Búsque al menos dos soluciones distintas ambas
linealmente recurrentes.


4. Diseñe un programa recurrente que, dados dos naturales y , calcule de cuantas formas


diferentes se pueden seleccionar naturales no nulos, posiblemente repetidos que sumen


. Ayuda: Plantear una recurrencia múltiple, reservando una llamada recurrente para
contar las descomposiciones que incluyen algún , y otra para las que no contienen
ninguno.
5. El recorrido en inorden de un árbol binario puede dafirse como una secuencia que
comienza con los elementos del del recorrido en inorden del hijo izquierdo, continúa con
la raíz del árbol, y sigue con el recorrido en inorden del hijo derecho. Especificar
ecuacionalmente esta operación, y diseñar un programa recurrente que calcule el
recorrido de un árbol binario.

Diseño de Algoritmos Cap 2 60


Jaime A Bohórquez V

También podría gustarte