Sie sind auf Seite 1von 55

Especificacin e Implementacin

de
Tipos Abstractos de Datos
Jess N. Ravelo
Universidad Simn Bolvar
Dpto. de Computacin y Tecnologa de la Informacin
Resumen
Estas notas presentan un esquema de especificacin de tipos abstractos de datos, abreviado TADs, acompaado de tcnicas de implementacin de estos TADs que garantizan la
consistencia entre especificaciones e implementaciones dadas.
El estilo de especificacin de TADs utilizado es el llamado basado en modelos, y la teora
en la que se fundamenta la correctitud de las implementaciones con respecto a sus respectivas
especificaciones es la de refinamiento de datos.

0.

Introduccin

La construccin de un nuevo tipo de datos requiere que las caractersticas deseadas de ste
sean inicialmente especificadas de manera clara, para luego proceder a implementarlo. A tales
nuevos tipos de datos los llamaremos tipos abstractos de datos, trmino que abreviaremos como
TADs. Este nombre se debe a que el comportamiento deseado de estos tipos debe ser especificado
de manera abstracta, independientemente de las mltiples posibles implementaciones concretas
que puedan luego construirse.
Los estilos de especificacin de TADs ms conocidos y utilizados son el estilo algebraico y
el estilo basado en modelos. Especificaciones en el estilo algebraico pueden ser conseguidas en,
por ejemplo, [Mit92]. En estas notas utilizaremos el estilo basado en modelos. Un ejemplo de
presentacin de especificaciones de TADs usando el estilo basado en modelos puede encontrarse
en [Lis01]. Sin embargo, en [Lis01] se utilizan modelos de especificacin descritos principalmente
en lenguaje natural, mientras en estas notas presentaremos tales modelos no slo en lenguaje
natural (siempre imprescindible para nuestra comprensin como seres humanos) sino tambin
por medio de estructuras matemticas como, por ejemplo, conjuntos y relaciones, entre otras
estructuras.
En estas notas, cada nuevo TAD ser presentado primero en lenguaje natural, a efectos de
lograr una primera aproximacin al nuevo tipo de la forma ms clara y sencilla posible. Una vez
hecho esto, procederemos a la especificacin formal del nuevo TAD usando un modelo abstracto
de representacin, basado en estructuras matemticas como las antes sealadas, esto es, conjuntos, relaciones, etctera. De esta manera, con una especificacin formal, se logra que a la primera
aproximacin al tipo presentada en lenguaje natural se le pulan los detalles opacos con una
0

buena y precisa formalizacin. Esto es, se eliminan posibles dudas de interpretacin del comportamiento del nuevo tipo, las cuales usualmente surgen debido al caracter inherentemente informal
del lenguaje natural, que da pie a ambigedades e inexactitudes en la descripcin.
Una vez especificado formalmente un TAD, se desea, por supuesto, implementarlo. Para esto,
lo primero que debe hacerse es escoger una estructura de datos que lo soporte, a la cual llamaremos el modelo concreto de representacin escogido. El TAD es entonces re-especificado en
trminos del nuevo modelo concreto, esto es, en trminos de la estructura de datos escogida. Esta
re-especificacin es la que entonces debe ser implementada, programando todas las subrutinas
(procedimientos, funciones, o mtodos) correspondientes a las operaciones del TAD.
Sin embargo, antes de proceder a la implementacin final de la re-especificacin del TAD,
se debe garantizar la consistencia entre la re-especificacin del TAD con modelo concreto y
la especificacin original del TAD con modelo abstracto. Esto se logra utilizando tcnicas de
refinamiento de datos.
La presentacin inicial de todos los aspectos involucrados en el estilo de especificacin de TADs
basado en modelos, y de todos los pormenores de la tcnica de refinamiento de datos, ser hecha
utilizando permanentemente como ejemplo a un TAD Diccionario. Una vez completada toda la
presentacin del estilo de especificacin y de las tcnicas de implementacin, se mostrarn otros
ejemplos interesantes de TADs, algunos de ellos clsicos, en el sentido de ser TADs de mucho
uso en las ciencias e ingeniera de la computacin, como Cola, Pila, Conjunto, Multiconjunto y
Grafo. Tambin sern presentados otros TADs que no son clsicos, sino simplemente ejemplos
interesantes.

1.

Un TAD Diccionario

En el Diccionario RAE (de la Real Academia Espaola), el trmino diccionario aparece con
las siguientes acepciones: (i) Libro en el que se recogen y explican de forma ordenada voces de
una o ms lenguas, de una ciencia o de una materia determinada., y (ii) Catlogo numeroso de
noticias importantes de un mismo gnero, ordenado alfabticamente. [Por ejemplo:] Diccionario
bibliogrfico, biogrfico, geogrfico.
La clase de TAD Diccionario de nuestro inters es cercana a la acepcin (ii), en el hecho de
que nos interesa que nuestros diccionarios correspondan a catlogos, salvo que no necesariamente
almacenarn noticias. . . de un mismo gnero, sino objetos cualesquiera siempre que, eso s, sean
de un mismo gnero. Estos objetos listados o catalogados en un Diccionario debern estar
acompaados de una clave que permita identificarlos unvocamente, de manera similar a como
los nmeros de cdula de identidad identifican a personas venezolanas y extranjeras residentes en
Venezuela.
As, nuestro TAD Diccionario permitir almacenar pares clave/valor, de forma tal que las
claves sean nicas e identifiquen unvocamente a su correspondiente valor, esto es, el objeto o
cosa asociado con cada clave.
Podramos conectar a la acepcin (i) del trmino diccionario en el Diccionario RAE con
nuestro TAD Diccionario, teniendo como claves a las distintas palabras que pueden aparecer en
un diccionario, y teniendo como valores a una posible acepcin de cada palabra. En esto ltimo
son diferentes un diccionario (segn DRAE) y un Diccionario (segn nuestro TAD), pues en el
primero una palabra puede tener muchas acepciones mientras que en el segundo cada palabra slo
puede tener una acepcin (salvo que en un Diccionario almacenramos una lista de acepciones
como el nico objeto asociado a cada palabra como clave).
1

Para terminar nuestra presentacin informal del TAD Diccionario, veamos un par de ejemplos
especficos.
En un Diccionario podramos almacenar una pequea agenda de cumpleaos con las fechas
de cumpleaos de nuestras amistades. Las claves seran los nombres de nuestras amistades y los
objetos asociados las fechas. Por ejemplo:
Claves
Luisa S.
Carlos A.
Elena C.
Ana R.
Juan A.

Valores
25 Sept
3 Jul
12 Dic
17 Ene
12 Dic

Note que no hay ningn problema en que haya fechas repetidas. Esto es, en un diccionario varias
claves pueden tener asociado el mismo valor. Sin embargo, las claves deben ser nicas, por lo que
si contamos con dos personas amigas con el mismo nombre e inicial de apellido, debemos agregar
ms informacin en el nombre (clave) para diferenciarlas.
Tambin podramos usar el TAD Diccionario para almacenar notas de estudiantes usando
como claves a sus nmeros de carnet:
Claves
2153751
2255182
2254977
2153710
2053201
2154111

Valores
3
3
5
3
4
3

De nuevo, note la unicidad de claves y posible repeticin de valores.


Por ltimo, note que nuestro TAD Diccionario es genrico, en el sentido de que acepta diversos tipos de claves (en los dos ltimos ejemplos son nombres o nmeros de carnet), siempre
y cuando en un mismo Diccionario todas las claves sean del mismo tipo, y tambin diversos
tipos de valores (en los dos ltimos ejemplos son fechas o notas), de nuevo siempre y cuando en un mismo Diccionario todos los valores sean del mismo tipo. Debido a esto, definiremos
nuestro TAD Diccionario de manera paramtrica, esto es, en trminos de dos parmetros T0
y T1 correspondientes respectivamente al tipo de las claves y al tipo de los valores: un TAD
Diccionario (T0 , T1 ) .

2.

Especificacin de un TAD

En la seccin anterior vimos una descripcin informal en lenguaje natural de nuestro TAD
Diccionario, para as lograr una primera aproximacin sencilla al nuevo TAD. Ahora lo especificaremos formalmente.

2.0.

Modelo Abstracto de Representacin

Lo primero que necesitamos es modelar la descripcin dada en lenguaje natural en trminos de


un modelo abstracto formal de representacin. Tales modelos abstractos formales corresponden
a estructuras matemticas.
La descripcin informal de nuestro TAD Diccionario (T0 , T1 ) da a entender que nuestros
diccionarios corresponden formalmente a funciones de claves en valores, siendo las claves de tipo
T0 y los valores de tipo T1 , por lo cual necesitamos funciones de T0 en T1 . Efectivamente,
utilizaremos en nuestro modelo abstracto de representacin a una funcin de T0 en T1 para
representar a cada diccionario.
Esta funcin ser una funcin parcial T0
p T1 , pues, por supuesto, cada diccionario conoce
slo a algunas claves y no a todo el posible dominio T0 de claves. Esto es, por ejemplo, en mi
agenda de cumpleaos el diccionario slo conoce a los nombres de mis amistades como claves y
no a cualquier nombre, y en la lista de notas el diccionario slo conoce a los carnets de quienes
estn cursando la asignatura correspondiente y no a cualquier nmero de carnet. Por lo tanto, la
funcin correspondiente al diccionario ser en el caso general una funcin parcial T0
p T1 en
lugar de una funcin total T0 T1 .
Esta funcin ser entonces incluida en nuestra especificacin formal del nuevo TAD como un
atributo del modelo abstracto de representacin, atributo al cual llamaremos, por analoga con
las tablas de ejemplo presentadas en la seccin anterior, tabla. La sintaxis que utilizaremos es la
siguiente:
Modelo de Representacin
var tabla : T0
p T1

El conjunto de claves conocidas por un diccionario es extrable del atributo tabla, pues es el
dominio de esta funcin. Sin embargo, en el resto de la especificacin del TAD necesitaremos con
bastante frecuencia referirnos a este conjunto. Por lo tanto, para poder hacer referencia fcilmente
a este conjunto, lo incluiremos como otro atributo del modelo. (Adems, as nuestro ejemplo se
hace un poco ms interesante. . . )
Tendramos ahora entonces:
Modelo de Representacin
var conoc : set T0
tabla : T0
p T1

Por ltimo, especificaremos nuestro TAD Diccionario acotando la capacidad de las tablas a
ser almacenadas. As, agregaremos un atributo ms al modelo abstracto de representacin que
indique la capacidad mxima de cada diccionario. Tal capacidad no podr ser cambiada una
vez que un diccionario sea creado, por lo cual declararemos a este atributo en el modelo de
representacin como atributo constante en lugar de como atributo variable.
Nuestra versin final del modelo abstracto de representacin de nuestro TAD es entonces:
Modelo de Representacin
const MAX : int
var conoc : set T0
tabla : T0
p T1

As como en este modelo abstracto de representacin de nuestro ejemplo utilizamos un conjunto y una funcin, en todos nuestros modelos abstractos de representacin utilizaremos estructuras
3

matemticas tomadas de la teora de conjuntos. Estas estructuras sern siempre una de las siguientes: conjuntos, multiconjuntos, secuencias, relaciones y funciones.
Para estandarizar la notacin utilizada sobre estas estructuras, nos apoyaremos en la presentacin de [Mor94, captulo 9], donde se le dedica una seccin a cada una de las cinco estructuras
arriba mencionadas. En algunos pocos casos, nos desviaremos ligeramente de la notacin utilizada
en [Mor94] y haremos la aclaratoria correspondiente.
Continuamos ahora con el resto de la especificacin. . .

2.1.

Invariante de Representacin

Una vez que han sido declarados todos los atributos del modelo de representacin, debemos
analizar qu caractersticas adicionales deben ser satisfechas por estos atributos (adicionales al
hecho de pertenecer a los tipos indicados en la declaracin del modelo).
Por ejemplo, teniendo un atributo entero, puede que nos interese que tal atributo sea un
nmero impar, o que sea no-negativo, o que sea mltiplo de 10, etctera. Debemos analizar qu
caractersticas son necesarias para que el atributo tenga sentido.
En el caso de nuestro atributo entero MAX en nuestro modelo de representacin, si ste representa la capacidad mxima de un diccionario, no tiene sentido que sea negativo. Y quiz conviene
descartar tambin la posibilidad de que sea cero. Exigiremos entonces que sea estrictamente
positivo. La sintaxis que utilizaremos es la siguiente:
Invariante de Representacin
MAX > 0

En el caso de un atributo de tipo conjunto, nos podra interesar exigir que no sea vaco, o
que su cardinalidad sea un nmero par, o cualquier otra caracterstica. En nuestro ejemplo, nos
interesa limitar la cardinalidad de conoc, la cual denotamos como # conoc , siguiendo la notacin
de [Mor94, captulo 9]. Si MAX corresponde a la capacidad mxima de un diccionario, la cantidad
de claves conocidas, esto es, # conoc , no puede superar tal capacidad. Esto enriquece nuestro
invariante de representacin de la siguiente forma:
Invariante de Representacin
MAX > 0 # conoc 6 MAX

Por ltimo, en el caso de un atributo de tipo funcin, nos podra interesar que sta no fuese
vaca, o que los elementos de su dominio o de su rango cumplan con algunas otras restricciones.
En nuestro ejemplo, el atributo funcin tabla debe ser consistente con el conjunto conoc de claves
conocidas, en el sentido de que toda clave que est en el dominio de la funcin debe ser conocida
y toda clave conocida debe estar en el dominio de la funcin: el dominio de tabla tiene que ser
exactamente igual a conoc. Esto da forma a la versin final de nuestro invariante de representacin:
Invariante de Representacin
MAX > 0 # conoc 6 MAX conoc = dom tabla

En resumen, el invariante de representacin impone restricciones adicionales que deben ser


satisfechas por los atributos del modelo de representacin, ya sean stas restricciones individuales
sobre algn atributo particular (como nuestra primera restriccin sobre MAX ) o exigencias de
4

que dos o ms atributos sean consistentes entre ellos (como nuestras otras dos restricciones, que
demandan consistencia entre conoc y MAX , y entre conoc y tabla, respectivamente).
En caso de que no haga falta exigir caractersticas adicionales al modelo de representacin, el
invariante de representacin puede ser omitido, lo cual corresponde formalmente (y es equivalente)
a utilizar:
Invariante de Representacin
true

2.2.

Operaciones

Como ltima componente, la especificacin de un nuevo TAD debe indicar qu operaciones


son aplicables a los objetos del nuevo tipo. Note que esto es una de las principales caractersticas
de todo tipo de datos. Por ejemplo, en el caso del tipo entero, las operaciones que cualquier tpico
lenguaje de programacin ofrece sobre este tipo incluyen suma, resta, multiplicacin, cociente y
resto de divisin entera, etctera. Para el tipo booleano, las operaciones tpicas incluyen conjuncin, disyuncin, negacin y quiz algunas otras. Los TADs, como tipos de datos que son, no son
una excepcin a esta regla y, por lo tanto, es componente primordial de su especificacin enumerar
y describir el comportamiento esperado de todas sus operaciones. En el caso de los TADs, sus
operaciones sern ofrecidas en forma de subrutinas, esto es, procedimientos y funciones.
Para nuestro TAD Diccionario, podramos contar con las siguientes operaciones bsicas:
(i) agregar un par clave/valor a un diccionario; (ii) eliminar un par clave/valor de un diccionario; (iii) dada una clave, determinar el valor asociado a tal clave en un diccionario; y (iv) dada
una clave, determinar si sta es conocida o no por un diccionario. Y, adems de todas estas operaciones, necesitamos una operacin de inicializacin o creacin de un nuevo diccionario. (Note
que todas las operaciones anteriores son aplicables a un diccionario preexistente, por lo cual hace
falta al menos una primera operacin de creacin o inicializacin.)
Cada una de estas operaciones, en vista de que sern ofrecidas como procedimientos o funciones, debe ser especificada de la manera conocida: a travs de un par pre/post-condicin.
Crear Empecemos con la operacin de creacin o inicializacin. Daremos a esta operacin como
nico parmetro de entrada a la capacidad mxima deseada para el diccionario a ser creado, y la
operacin devolver como parmetro de salida un diccionario con la capacidad mxima indicada.
Esto determina la interfaz del procedimiento correspondiente:
proc crear ( in m : int ; out d : Diccionario )
{ Pre : . . . }
{ Post : . . . }
.
Ahora nos falta describir el comportamiento de la operacin completando el par pre/post-condicin. La nica restriccin que hace falta exigir al nico parmetro de entrada es que sea un
valor adecuado como capacidad mxima y, ya que en el invariante de representacin lo que se
especific como valores aceptables para el atributo MAX fueron nmeros positivos, pues se exigir
que m sea positivo en la precondicin. En cuanto al diccionario de salida, ste deber tener como
capacidad mxima a m y en cuanto a sus pares clave/valor iniciales, lo natural es que no cuente
con ninguno al principio; esto ser por tanto lo indicado en la postcondicin. Veamos entonces la

especificacin completa de nuestra primera operacin:


proc crear ( in m : int ; out d : Diccionario )
{ Pre : m > 0 }
{ Post : d.MAX = m d.conoc = d.tabla = }

Es conveniente destacar que la notacin utilizada para referirnos a cada atributo de cada diccionario, segn los atributos declarados en el modelo de representacin para todo diccionario, es un
. infijo. Por ello, el atributo conoc del diccionario d es denotado por d.conoc ; y este atributo
conoc es un atributo de todo diccionario por haber sido declarado como atributo del modelo de
representacin utilizado para todos los diccionarios.
Nota:
En este punto es importante mencionar que utilizamos la usual convencin de considerar a los parmetros de entrada como constantes. De all que en la postcondicin
arriba indicada para la operacin crear , el valor (final) de m se refiera al mismo valor
(inicial) de entrada de m.
Continuaremos utilizando esta convencin sobre parmetros de entrada a lo largo
de todas estas notas.
(Fin de nota.)
Por ltimo, hay un punto muy interesante e importante a discutir en relacin con la postcondicin especificada para la operacin crear y el invariante de representacin presentado en
la subseccin anterior. Recuerde que el invariante de representacin es una exigencia que se le
impone al modelo de representacin, y es por tanto una exigencia impuesta a todo diccionario.
De acuerdo con esto, los atributos del diccionario d siempre deben cumplir con el invariante de
representacin. Esto es, d siempre debe cumplir con lo siguiente:
d.MAX > 0 # d.conoc 6 d.MAX d.conoc = dom d.tabla

Por lo tanto, esta ltima condicin es parte implcita de la postcondicin de la operacin crear .
Como consecuencia de esta conjuncin implcita de la postcondicin especificada explcitamente con el invariante de representacin aplicado a d, la postcondicin dada contiene redundancia:
la frmula central implica a la frmula derecha en presencia del invariante y, viceversa, la derecha implica a la central. Tenemos entonces que, en presencia del invariante aplicado a d, la
postcondicin dada arriba es equivalente a
{ Post : d.MAX = m d.conoc = }

debido a que dom f = implica f = para cualquier funcin f , y tambin es equivalente a


{ Post : d.MAX = m d.tabla = }

debido a que dom = .


Estas dos ltimas postcondiciones pueden ser consideradas mejores que la primera en vista
de que son ms breves, pero la primera tiene la ventaja de ser ms clara y explcita. En estas
notas preferiremos la claridad por encima de la longitud de una especificacin, por lo cual nos
quedamos con la primera postcondicin explcita dada originalmente.
Sin embargo, ms adelante veremos la utilidad de contar con varias postcondiciones equivalentes, haciendo uso de la ms explcita para especificar mientras se hace uso de la ms breves
para otras labores.
6

Agregar Segn se indic en la introduccin de esta subseccin, esta operacin es para agregar
a un diccionario dado un par clave/valor. El parmetro de tipo diccionario deber ser de entrada/salida, ya que debe ser modificado, mientras los otros dos parmetros, del par clave/valor a
agregar, sern slo de entrada:
proc agregar ( in-out d : Diccionario ; in c : T0 ; in v : T1 )
{ Pre : . . . }
{ Post : . . . }
.
De acuerdo con la descripcin en lenguaje natural de esta operacin, agregar el par (c, v) al
diccionario d , el comportamiento de sta puede parecer obvio. Pero un momento de reflexin
plantea la siguiente duda: debe la clave c ser totalmente nueva, o puede sta ya existir en el
diccionario, en cuyo caso se reemplaza su valor asociado anterior por el nuevo valor v?
ste es el valor agregado que resulta de combinar una descripcin inicial en lenguaje natural
con una posterior especificacin formal detallada con pre/post-condicin. Luego de que la primera descripcin informal nos permite obtener una inicial comprensin bsica de la operacin, la
segunda especificacin formal pule los detalles opacos que puedan haber quedado de la primera
descripcin informal debido a la ambigedad y tendencia a la incompletitud propias del uso de
lenguaje natural.
Optaremos por la primera interpretacin en la pregunta planteada arriba, exigiendo que la
clave c sea totalmente nueva, y dejaremos la formalizacin de la segunda interpretacin como
ejercicio (ver ejercicio 2.4-b). La especificacin completa de nuestra operacin es entonces:
proc agregar ( in-out d : Diccionario ; in c : T0 ; in v : T1 )
{ Pre : c 6 d.conoc # d.conoc < d.MAX }
{ Post : d.conoc = d0 .conoc { c } d.tabla = d0 .tabla { (c, v) } }

Cuando tengamos un parmetro de entrada/salida, como es el caso de d en esta operacin, en


la postcondicin podremos referirnos a su valor inicial indexando con 0 a su nombre. Por tanto,
en la postcondicin recin planteada, d0 se refiere al valor del diccionario d en el estado inicial,
mientras d se refiere al valor de d en el estado final.
La precondicin exige que la clave c sea nueva en el diccionario y que an quede capacidad en
el diccionario para almacenar un nuevo par. La postcondicin seala que el diccionario resultante
conoce la nueva clave c adems de continuar conociendo todas las claves anteriores, y que la nueva
clave c est asociada al valor v mientras las claves conocidas previamente siguen asociadas a los
mismos valores que al principio de la operacin.
Vale ahora el mismo comentario sobre el invariante de representacin que hicimos antes en
relacin con la especificacin de la operacin crear , pero ahora con un par de variaciones. En la
especificacin de crear , dijimos que el invariante de representacin sobre el diccionario d estaba
presente implcitamente en la postcondicin. Ahora bien, en el caso de la operacin agregar , el
invariante de representacin sobre el parmetro d est presente tanto en la precondicin como
en la postcondicin. La diferencia estriba en el hecho de que en la operacin crear el diccionario
d era un parmetro slo de salida, mientras ahora en la operacin agregar es un parmetro de
entrada/salida. Por ltimo, el hecho de que se exija el invariante de representacin a d en la
precondicin tambin garantiza que en la postcondicin d0 cumpla con el invariante de representacin.
De acuerdo con esto, la precondicin especificada para agregar es equivalente a
{ Pre :

c 6 dom d.tabla # d.tabla < d.MAX }


7

mientras la postcondicin especificada para agregar puede ser abreviada sin prdida de informacin, esto es, siendo equivalente, como
{ Post : d.tabla = d0 .tabla { (c, v) } }

Tal como con la operacin crear , nos quedaremos con el par pre/post-condicin inicialmente
planteado, por considerarlo la especificacin ms clara y completa.
Por otra parte, recuerde que el atributo MAX del modelo de representacin fue declarado
como atributo constante. Esto quiere decir que, una vez creado un diccionario e inicializado su
atributo MAX , este valor ya no puede cambiar. Por lo tanto, la postcondicin de agregar (y de
toda operacin que tenga un parmetro de entrada/salida d de tipo diccionario) tambin incluye
implcitamente a la condicin
d.MAX = d0 .MAX

Eliminar Esta operacin es para eliminar de un diccionario dado a un par clave/valor. Sin
embargo, debido a la naturaleza de los diccionarios, bastar indicar la clave que se desea eliminar,
pues el valor ser implcitamente el asociado a tal clave en el diccionario. Al igual que en la
operacin agregar , el parmetro de tipo diccionario deber ser de entrada/salida, y el segundo
parmetro, la clave a eliminar, ser slo de entrada:
proc eliminar ( in-out d : Diccionario ; in c : T0 )
{ Pre : . . . }
{ Post : . . . }
.
De nuevo, nos planteamos una duda de interpretacin: debe la clave c ser conocida por el
diccionario, o puede ser sta tanto conocida como desconocida por el diccionario?
Lo consistente con la interpretacin escogida en el caso de la operacin agregar , esto es, para
agregar una clave, sta debe ser nueva, ser de nuevo la primera interpretacin de la interrogante
planteada: para eliminar una clave, sta debe ser conocida. La formalizacin de la segunda interpretacin queda de nuevo como ejercicio (ver ejercicio 2.4-b). Nuestra especificacin de eliminar
es entonces:
proc eliminar ( in-out d : Diccionario ; in c : T0 )
{ Pre : c d.conoc }
{ Post : d.conoc = d0 .conoc { c } d.tabla = d0 .tabla { (c, d0 .tabla c) } } .
La precondicin exige que la clave c sea conocida por el diccionario, mientras la postcondicin
seala que el diccionario resultante deja de conocer la clave c pero contina conociendo el resto
de las claves que conoca previamente, y el par que asociaba a la clave c con su valor, obtenido
por la aplicacin de la funcin inicial d0 .tabla a la clave c, esto es, d0 .tabla c , es eliminado de la
tabla de pares registrados, mantenindose todo el resto presente.
Nuevamente, la presencia implcita del invariante de representacin sobre d tanto en la precondicin como en la postcondicin (d es parmetro de entrada/salida) hace que la precondicin
especificada sea equivalente a
{ Pre :

c dom d.tabla }

y que la postcondicin dada pueda ser abreviada equivalentemente como


{ Post : d.tabla = d0 .tabla { (c, d0 .tabla c) } }
8

Como hemos comentado anteriormente, las condiciones abreviadas sern convenientes de utilizar
ms adelante, pero a efectos de la especificacin preferimos las ms completas y claras.
Por otra parte, gracias a propiedades de operadores presentes en la teora de conjuntos, esta
ltima postcondicin tambin puede ser reescrita como
{ Post : d.tabla = d0 .tabla ({ c } T1 ) }

o como
{ Post : d.tabla = { c } C
d0 .tabla }

siendo C
, segn la notacin de [Mor94, captulo 9], el operador de co-restriccin de dominio,
esto es, restriccin de dominio de una funcin (o relacin) al complemento de un conjunto dado
(ver [Mor94, pgina 88]).
Buscar y determinar existencia Las ltimas dos operaciones, segn la lista dada en la
introduccin a esta subseccin, corresponden a, dada una clave, buscar su valor asociado en un
diccionario dado y determinar si sta es conocida o no por un diccionario dado. Las llamaremos
buscar y existe.
Para mantener consistencia con la interpretacin dada a la clave de entrada en agregar y
eliminar , en la operacin buscar exigiremos en la precondicin que la clave de entrada sea conocida
por el diccionario. En la operacin existe, por la naturaleza misma de la operacin, la clave podr
ser cualquiera.
En estas dos operaciones, el parmetro d de tipo diccionario ser de entrada, ya que no hace
falta modificarlo. Por lo tanto, el invariante de representacin sobre d ser supuesto implcitamente
slo en la precondicin. Sin embargo, recuerde que acostumbramos exigir que un parmetro de
entrada permanezca constante en una subrutina y, por lo tanto, d tendr el mismo valor inicial
al final de la operacin, por lo que las referencias a d en la postcondicin se refieren al mismo
valor inicial de d.
La especificacin completa de las operaciones se encuentra en la figura 2.3.(a).

2.3.

Armando el aparato completo. . .

Ya hemos construido por completo una especificacin para nuestro TAD Diccionario. Los
componentes de la especificacin corresponden a lo descrito en cada una de las subsecciones
anteriores: modelo (abstracto) de representacin, invariante de representacin, y operaciones.
La especificacin completa del TAD se encuentra ensamblada en la figura 2.3.(a). All Ud.
ver que a la especificacin se le di el nombre A. Ms adelante se explicar la razn de este
nombre (cuando debamos construir una re-especificacin del mismo TAD, re-especificacin a la
que llamaremos B).

2.4.

Ejercicios

2.4-a. . . . demostrar equivalencia entre las postcondiciones y precondiciones de las que se dijo
tal cosa (y en esos puntos poner referencia a este ejercicio). . .
2.4-b. . . . re-especificacin de las operaciones relajando las precondiciones. . .
9

Especificacin A de TAD Diccionario (T0 , T1 )


Modelo de Representacin
const MAX : int
var conoc : set T0
tabla : T0
p T1
Invariante de Representacin
MAX > 0 # conoc 6 MAX conoc = dom tabla
Operaciones
proc crear ( in m : int ; out d : Diccionario )
{ Pre : m > 0 }
{ Post : d.MAX = m d.conoc = d.tabla = }
proc agregar ( in-out d : Diccionario ; in c : T0 ; in v : T1 )
{ Pre : c 6 d.conoc # d.conoc < d.MAX }
{ Post : d.conoc = d0 .conoc { c } d.tabla = d0 .tabla { (c, v) } }
proc eliminar ( in-out d : Diccionario ; in c : T0 )
{ Pre : c d.conoc }
{ Post : d.conoc = d0 .conoc { c } d.tabla = d0 .tabla { (c, d0 .tabla c) } }
proc buscar ( in d : Diccionario ; in c : T0 ; out v : T1 )
{ Pre : c d.conoc }
{ Post : v = d.tabla c }
proc existe ( in d : Diccionario ; in c : T0 ; out e : boolean )
{ Pre : true }
{ Post : e (c d.conoc) }
Fin TAD

Figura 2.3.(a): Especificacin con modelo abstracto de un TAD Diccionario

10

2.4-c. . . . re-especificar el TAD Diccionario sin considerar capacidad mxima. . .


2.4-d. . . . buscar especificaciones de TADs basadas en modelos en el texto de Liskov [Lis01], y
compararlas con las nuestras. . .
2.4-e. . . . especificar un TAD MultiDiccionario, en el que cada clave pueda tener asociados mltiples valores. . .

3.

Otros ejemplos de especificacin de TADs (clsicos)

En esta seccin veremos algunos otros ejemplos de especificacin de TADs. Todos los TADs
que consideramos en esta seccin son clsicos, en el sentido reseado en la introduccin de
estas notas de ser TADs muy usados en las ciencias e ingeniera de la computacin. En la futura
seccin 8 presentaremos otros TADs que no son clsicos, mas son ejemplos interesantes.

3.0.

Un TAD Cola

Entre los TADs clsicos se encuentran, adems de nuestro ya conocido TAD Diccionario, los
TADs Cola y Pila. Estos dos TADs se parecen un poco el uno al otro, mas no son exactamente
iguales. En esta seccin presentaremos un TAD Cola y dejaremos como ejercicio lo relacionado
con Pila.
Una cola es, tal como en la vida real dentro de un banco o en alguna institucin pblica
de servicio, una estructura a la que se anexan nuevos elementos por un extremo, el final, y
de la que se extraen elementos por el otro extremo, el principio. En ingls, esta estructura es
conocida como una secuencia FIFO, por first-in-first-out, ya que es una secuencia en la que el
primer elemento que entra ser el primero en salir.
Un TAD Cola usualmente cuenta con las siguientes operaciones: (i) agregar un elemento a la
cola; (ii) extraer un elemento de la cola; (iii) ver el primer elemento de la cola; y (iv) determinar
si una cola tiene o no elementos. Y, al igual que en el caso del TAD Diccionario, se requiere una
operacin de inicializacin o creacin de un nueva cola, usualmente vaca.
En la especificacin que presentaremos del TAD Cola, utilizaremos en el modelo abstracto a
una secuencia para representar a la cola (ver secuencias como estructuras matemtcas en [Mor94,
seccin 9.3]). Adems, al igual que en el caso de Diccionario, limitaremos cada cola a una cierta
capacidad mxima, que tambin ser un atributo del modelo abstracto de representacin.
La figura 3.0.(b) muestra una especificacin completa de un TAD Cola. Al igual que en el
caso de Diccionario, nuestro TAD Cola es genrico, esto es, parametrizado por el tipo T de los
elementos a ser almacenados en la cola.
Como maneras interesantes de re-frasear algunas de las pre/post-condiciones de nuestra especificacin del TAD Cola, de acuerdo con las definiciones de los operadores sobre secuencias
presentados en [Mor94, seccin 9.3], la precondicin de desencolar y primero es equivalente a
# c.contenido > 0

mientras la postcondicin de desencolar es equivalente a


( e :: c0 .contenido = hei ++ c.contenido )
y la postcondicin de primero es equivalente a
( s :: c.contenido = hxi ++ s )

.
11

Especificacin A de TAD Cola (T )


Modelo de Representacin
const MAX : int
var contenido : seq T
Invariante de Representacin
MAX > 0 # contenido 6 MAX
Operaciones
proc crear ( in m : int ; out c : Cola )
{ Pre : m > 0 }
{ Post : c.MAX = m c.contenido = hi }
proc encolar ( in-out c : Cola ; in x : T )
{ Pre : # c.contenido < c.MAX }
{ Post : c.contenido = c0 .contenido ++ hxi }
proc desencolar ( in-out c : Cola )
{ Pre : c.contenido 6= hi }
{ Post : c.contenido = tl c0 .contenido }
proc primero ( in c : Cola ; out x : T )
{ Pre : c.contenido 6= hi }
{ Post : x = hd c.contenido }
proc vacia ( in c : Cola ; out v : boolean )
{ Pre : true }
{ Post : v (c.contenido = hi) }
Fin TAD

Figura 3.0.(b): Especificacin con modelo abstracto de un TAD Cola

12

3.1.

Un TAD Conjunto

Otro par de TADs clsicos son Conjunto y Multiconjunto. Al igual que en la seccin anterior, presentaremos slo un TAD Conjunto y dejaremos como ejercicio el trabajar con un TAD
Multiconjunto.
Definiremos un TAD Conjunto en el que las primeras operaciones trabajan los elementos
uno a uno, que seran las siguientes: (i) agregar un elemento a un conjunto, permitiendo que la
operacin sea siempre aplicable, indepedientemente de si el elemento estaba previamente en el
conjunto o no; (ii) eliminar un elemento de un conjunto, de nuevo permitiendo que la operacin
sea siempre aplicable, est o no el elemento previamente en el conjunto; (iii) extraer un elemento
cualquiera de un conjunto no-vaco; (iv) determinar si un elemento est o no en un conjunto;
y (v) determinar si un conjunto est vaco o no. Adems de estas primeras operaciones, que
trabajan sobre un solo conjunto y manejan elementos uno por uno, tendremos un segundo grupo
de operaciones correspondientes a tpicas operaciones binarias de la teora de conjuntos: (vi) unir
dos conjuntos devolviendo el resultado en un tercero; (vii) dem para intersectar; y (viii) dem
para calcular diferencia de conjuntos. Por ltimo, como de costumbre, tendremos una operacin
de inicializacin de un conjunto en vaco.
En la especificacin de nuestro TAD Conjunto, utilizaremos en el modelo abstracto a un
conjunto, lo cual requiere una breve aclaratoria de sutilezas que ser dada en el siguiente prrafo.
Y, como en nuestras especificaciones anteriores, el modelo abstracto de representacin tambin
indicar una cierta capacidad mxima de almacenamiento.
Ahora bien, en cuanto a la dualidad entre TAD Conjunto vs. conjunto como un atributo
del modelo de representacin, debemos aclarar la diferencia (y similitudes). Un conjunto como
modelo abstracto de representacin se refiere a la estructura matemtica conjunto de la teora
de conjuntos (tal como en todos nuestros otros modelos abstractos de representacin), mientras
un conjunto como TAD es un tipo de datos que aspiramos a implementar en un computador
utilizando algn lenguaje de programacin. He all la diferencia entre conjunto como TAD
y como modelo abstracto. En consecuencia, los conjuntos como modelo abstracto pueden ser
utilizados con todas las posibles operaciones que provee la teora de conjuntos para ello, mientras
los conjuntos de nuestro TAD slo pueden ser utilizados con las operaciones que se definan para el
TAD. El operador de producto cartesiano sobre conjuntos, el operador de conjunto potencia, y el
operador de complementacin seran ejemplos de operadores disponibles en la teora de conjuntos
y, por lo tanto, operadores disponibles para ser utilizados sobre nuestro modelo abstracto de
representacin, pero que no estaran a disposicin de los usuarios de nuestro TAD, simplemente
porque quien dise el TAD decidi no incluir tales operaciones. Igualmente, si en nuestro TAD
hubisemos decidido quedarnos slo con el primer grupo de operaciones (i)-(v), sin el segundo
grupo (vi)-(viii), entonces los operadores de unin, interseccin y diferencia no habran estado
disponibles para los usuarios de nuestro TAD mientras s habran sido operadores disponibles para
nuestro modelo abstracto de representacin (de hecho, note ms adelante que estos operadores
son utilizados sobre el modelo abstracto para especificar las operaciones (i) y (ii) del primer grupo
de operaciones de nuestro TAD).
Aclarada la sutil dualidad entre conjunto como TAD y conjunto como modelo abstracto
de representacin, mostramos en la figura 3.1.(c) una especificacin completa de nuestro TAD
Conjunto. Al igual que todos los TADs presentados hasta ahora, nuestro TAD Conjunto es
genrico, parametrizado por el tipo T de los elementos a ser almacenados en un conjunto.
Note que las precondiciones de unir , intersectar y restar son ms fuertes de lo estrictamente

13

Especificacin A de TAD Conjunto (T )


Modelo de Representacin
const MAX : int
var contenido : set T
Invariante de Representacin
MAX > 0 # contenido 6 MAX
Operaciones
proc crear ( in m : int ; out c : Conjunto )
{ Pre : m > 0 }
{ Post : c.MAX = m c.contenido = }
proc agregar ( in-out c : Conjunto ; in x : T )
{ Pre : x 6 c.contenido # c.contenido < c.MAX }
{ Post : c.contenido = c0 .contenido { x } }
proc eliminar ( in-out c : Conjunto ; in x : T )
{ Pre : true }
{ Post : c.contenido = c0 .contenido { x } }
proc extraer ( in c : Conjunto ; out x : T )
{ Pre : c.contenido 6= }
{ Post : x c.contenido }
proc pertenece ( in c : Conjunto ; in x : T ; out p : boolean )
{ Pre : true }
{ Post : p (x c.contenido) }
proc vacio ( in c : Conjunto ; out v : boolean )
{ Pre : true }
{ Post : v (c.contenido = ) }
proc unir ( in c0 , c1 : Conjunto ; in m : int ; out c : Conjunto )
{ Pre : # c0 .contenido + # c1 .contenido 6 m }
{ Post : c.MAX = m c.contenido = c0 .contenido c1 .contenido }
proc intersectar ( in c0 , c1 : Conjunto ; in m : int ; out c : Conjunto )
{ Pre : # c0 .contenido 6 m # c1 .contenido 6 m }
{ Post : c.MAX = m c.contenido = c0 .contenido c1 .contenido }
proc restar ( in c0 , c1 : Conjunto ; in m : int ; out c : Conjunto )
{ Pre : # c0 .contenido 6 m }
{ Post : c.MAX = m c.contenido = c0 .contenido c1 .contenido }
Fin TAD

Figura 3.1.(c): Especificacin con modelo abstracto de un TAD Conjunto

14

necesario. Las precondiciones ms dbiles requeridas en cada caso seran


# (c0 .contenido c1 .contenido) 6 m
para unir ,
# (c0 .contenido c1 .contenido) 6 m
para intersectar , y
# (c0 .contenido c1 .contenido) 6 m
para restar . Sin embargo, estas precondiciones seran ms difciles de garantizar por los clientes
de nuestro TAD, previa llamada a las operaciones. La dificultad radicara en que poder garantizar tales precondiciones requerira conocer previamente el resultado que se desea obtener con la
llamada, esto es, el resultado de la unin, el resultado de la interseccin o el resultado de la diferencia. Las precondiciones que escogimos para nuestra especificacin requieren slo verificaciones
simples en trminos de los tamaos de los operandos de entrada (a diferencia de las ms dbiles
que requeriran verificaciones en trminos de los tamaos de los resultados de salida!).

3.2.

Ejercicios

3.2-a. . . . especificar un TAD Pila. . .


3.2-b. . . . especificar un TAD ColaConPrioridades. . .
3.2-c. . . . especificar un TAD MultiConjunto. . .

4.

Implementacin de un TAD

Las dos ltimas secciones nos mostraron cmo especificar un nuevo TAD. Para esto se utiliz
en cada caso un modelo abstracto de representacin. Ntese que lo ms importante en un TAD
son sus operaciones con sus respectivas descripciones de comportamiento, mientras que el modelo
abstracto en s no tiene mayor relevancia. El nico papel que jug el modelo abstracto de representacin en todos los ejemplos fue el permitir describir el comportamiento de las operaciones
(notar que sin el modelo no habra habido manera de especificar los pares pre/post-condicin de
las operaciones).
Ahora, para implementar un TAD necesitamos ante todo escoger una estructura de datos con
la cual poder almacenar la informacin correspondiente al TAD. Para construir tal estructura
de datos, necesitaremos los posibles constructores de estructuras provistos por algn lenguaje
de programacin. En estas notas utilizaremos nicamente arreglos y registros, limitndonos a
arreglos en los primeros ejemplos. (Algunos ejemplos muy interesantes de implementacin de
TADs incluyen el uso de estructuras recursivas de datos construidas con apuntadores/referencias,
como listas enlazadas y rboles de diversos tipos; consideraremos a tales ejemplos fuera del alcance
de estas notas.)
La estructura de datos que se decida utilizar para almacenar la informacin del TAD corresponder en consecuencia a un nuevo modelo de representacin para el TAD, al cual llamaremos
modelo concreto de representacin. Con tal nuevo modelo, las operaciones del TAD deben ser reespecificadas, y tal re-especificacin debe ser consistente con la especificacin original del TAD. La
consistencia de la re-especificacin del TAD con modelo concreto en relacin con la especificacin
original del TAD con modelo abstracto ser garantizada a travs de una relacin de acoplamiento
entre los dos modelos (tambin llamada invariante de acoplamiento o relacin de abstraccin).
15

4.0.

Modelo Concreto de Representacin

Este nuevo modelo, como ya fue indicado, corresponde a la estructura de datos sobre la
que se decida basar la construccin de la implementacin del TAD. En el caso de nuestro TAD
Diccionario, si queremos limitarnos a utilizar arreglos, podemos almacenar los pares del diccionario mediante dos arreglos: un arreglo de claves y un arreglo de valores, de forma tal que los pares
se asocien componente a componente; esto es, la clave de la posicin 0 se aparea con el valor de
la posicin 0, la clave de la posicin 1 se aparea con el valor de la posicin 1, y as sucesivamente.
Empezamos entonces la construccin de nuestro modelo concreto de representacin de la
siguiente forma:
Modelo de Representacin
var claves : array [ . . . ) of T0
valores : array [ . . . ) of T1

Note que el tamao conveniente para estos arreglos debe ser la capacidad mxima indicada por la
especificacin original. Por ello, tomamos el atributo MAX del modelo abstracto y lo re-usamos
en el modelo concreto, de nuevo como atributo constante en lugar de como atributo variable:
Modelo de Representacin
const MAX : int
var claves : array [ 0..MAX ) of T0
valores : array [ 0..MAX ) of T1

Por ltimo, el tamao conveniente para los arreglos puede ser MAX . Sin embargo, no siempre
un diccionario almacenar la mxima cantidad posible de pares. Un diccionario almacenar a lo
sumo tal cantidad mxima, pero usualmente tendr menos. Necesitamos entonces un atributo
ms que indique cul es la cantidad actual real de pares almacenados en el diccionario:
Modelo de Representacin
const MAX : int
var claves : array [ 0..MAX ) of T0
valores : array [ 0..MAX ) of T1
tam : int

Este ltimo atributo tam lo manejaremos en combinacin con los arreglos de forma tal que los
pares del diccionario estn almacenados en las primeras tam posiciones de los arreglos. Esto es,
en ambos arreglos el segmento con informacin relevante ser [ 0..tam ) , mientras lo que haya en
el segmento [ tam..MAX ) de ambos arreglos ser ignorado.

4.1.

Invariante de Representacin

Todo modelo de representacin va acompaado de un invariante de representacin (aunque sea


el invariante trivial true). Por lo tanto, as como nuestro modelo abstracto de representacin
tena su invariante, nuestro nuevo modelo concreto de representacin tambin contar con su
correspondiente invariante.
Al igual que antes, debemos analizar qu restricciones adicionales deben ser satisfechas por
los atributos de nuestro nuevo modelo. Veamos: MAX , de nuevo, deber ser positivo; tam deber
estar en el rango [ 0..MAX ] , ambos extremos incluidos como las cantidades mnima y mxima
posibles de pares a ser almacenadas en el diccionario; y, por ltimo, no puede haber claves
16

repetidas en el segmento relevante, esto es, el segmento [ 0..tam ) , del arreglo claves. Nuestro
invariante de representacin es entonces:
Invariante de Representacin
MAX > 0 0 6 tam 6 MAX
( i, j : 0 6 i, j < tam : i 6= j claves[i] 6= claves[j] )

4.2.

Relacin de Acoplamiento

He aqu un nuevo componente que ha de estar presente en la re-especificacin del TAD, la cual
estamos construyendo con miras a implementar el TAD. La especificacin original del TAD con
modelo abstracto es la especificacin propiamente dicha, o contrato inicial de comportamiento,
del TAD. La re-especificacin del TAD con modelo concreto es una especie de puente intermedio entre el contrato inicial y la implementacin final. En consecuencia, la re-especificacin con
modelo concreto debe ser consistente con la especificacin original con modelo abstracto. Para
poder analizar tal consistencia, se requiere indicar cmo el nuevo modelo representa al modelo
anterior. Esto se logra por medio de una relacin de acoplamiento (tambin llamada invariante
de acoplamiento o relacin de abstraccin).
En la subseccin anterior, al presentar el modelo concreto tambin dimos una breve descripcin
en lenguaje natural de cmo este nuevo modelo representara a un diccionario. Tal descripcin
informal es lo que debemos usar para formalizar detalladamente cmo el nuevo modelo concreto
representa a los componentes del modelo abstracto anterior.
Veamos, las claves conocidas por el diccionario estarn almacenadas en el arreglo claves y,
como sealamos en la subseccin anterior, el segmento relevante de este arreglo ser [ 0..tam ) .
Por lo tanto, el conjunto conoc se construye formalmente a partir de nuestro modelo concreto de
acuerdo con la siguiente frmula:
conoc = { i : 0 6 i < tam : claves[i] }

Igualmente, los pares del diccionario se encuentran en el mismo segmento de ambos arreglos,
apareando los arreglos componente a componente:
tabla = { i : 0 6 i < tam : (claves[i], valores[i]) }

Por tanto, nuestra relacin de acoplamiento completa es la siguiente:


Relacin de Acoplamiento
conoc = { i : 0 6 i < tam : claves[i] }

tabla = { i : 0 6 i < tam : (claves[i], valores[i]) }

En cuanto al atributo MAX , note que ste est presente tanto en el modelo abstracto como
en el modelo concreto. Supondremos siempre que cuando un atributo del modelo abstracto sea
repetido en el modelo concreto, ste se representar a s mismo; esto es, el atributo abstracto
MAX es igual al atributo concreto MAX .
Debemos ac acotar que la notacin que hemos utilizado recin para conjuntos definidos
por comprensin difiere ligeramente de la notacin de [Mor94]. En nuestra notacin de tres
partes hemos utilizado : para ambos separadores, mientras el texto en cuestin separa con
| y , adems de hacer siempre explcito al tipo o conjunto del que toma valores la variable generadora: all el conjunto asociado a conoc antes especificado habra sido denotado como
17

{ i : N | 0 6 i < tam claves[i] } . Nuestra desviacin se debe a razones de consistencia con nuestra notacin para cuantificaciones, que tambin usa doble separacin con : y deja implcito el
tipo de la variable generadora, desvindose exactamente en la misma forma de la notacin para
cuantificaciones de [Mor94]. Ms detalles sobre la notacin para conjuntos definidos por comprensin en nuestro texto de referencia, que adems permite la omisin de la segunda o tercera parte
mientras nosotros evitaremos hacer tal cosa, pueden ser consultados en [Mor94, seccin 9.1.3].

4.3.

Operaciones

Por ltimo, las operaciones del TAD deben ser re-especificadas en trminos del nuevo modelo
concreto, de manera tal que se mantenga correspondencia con la intencin expuesta en los pares
pre/post-condicin originales. Una vez hecho esto, slo faltara implementar los cuerpos de las
subrutinas correspondientes a las operaciones del tipo, lo cual es un ejercicio algortmico que no
es de nuestro inters central en estas notas.
No es imprescindible que esta re-especificacin concreta de las operaciones sea hecha explcitamente. Esto se debe a que la relacin de acoplamiento induce implcitamente una cierta
re-especificacin para cada operacin que automticamente mantiene la correspondencia adecuada con la especificacin original. Ms adelante, cuando estudiemos las tcnicas de refinamiento de
datos que utilizaremos para analizar la consistencia entre especificacin e implementacin, en la
seccin 6, veremos cul es tal re-especificacin concreta implcita y por qu es autmaticamente
adecuada.
Sin embargo, a pesar de la existencia de tal re-especificacin implcita automticamente correcta para las operaciones, tambin es posible que hagamos nuestra propia re-especificacin
explcita. En este caso, para cada operacin que re-especifiquemos explcitamente, debemos luego
mostrar que hemos mantenido la intencin de su especificacin original. La posible conveniencia
de optar por una re-especificacin explcita estriba en el que sta pueda entonces sugerir implementaciones particulares para una operacin, en cuanto a la construccin del cuerpo de la
subrutina correspondiente.
En estas notas, optaremos siempre por re-especificar explcitamente todas las operaciones,
principalmente porque consideramos que esto ayuda a una mejor comprensin de las operaciones
en el marco del modelo concreto. En algunos casos comentaremos si una re-especificacin explcita
sugiere o no cierta implementacin particular; as mismo, en algunos casos comentaremos si una
re-especificacin explcita corresponde exactamente a la re-especificacin implcita inducida por
la relacin de acoplamiento.
Crear En cuanto a la primera operacin de creacin o inicializacin, tenemos la misma interfaz
que antes para la misma:
proc crear ( in m : int ; out d : Diccionario )
{ Pre : . . . }
{ Post : . . . }
.
De hecho, para todas las operaciones, la interfaz de parmetros entrada/salida siempre debe
mantenerse igual.
En cuanto a la precondicin, lo consistente es mantener la misma anterior: m debe ser positivo.
En relacin con la postcondicin, las restricciones sobre MAX siempre se mantendrn iguales ya
que este atributo se mantuvo igual en el cambio de modelo. Ahora, en cuanto a que el diccionario
18

resultante deba ser vaco, en el nuevo modelo concreto esto corresponde a exigir que el atributo
tam sea cero. Veamos entonces la re-especificacin completa de la primera operacin:
proc crear ( in m : int ; out d : Diccionario )
{ Pre : m > 0 }
{ Post : d.MAX = m d.tam = 0 }

Vale la pena recordar que, al igual que anteriormente, el invariante de representacin (concreto)
sobre el diccionario de salida d se encuentra implcitamente anexo a la postcondicin.
Agregar

Mantenemos la misma interfaz anterior:


proc agregar ( in-out d : Diccionario ; in c : T0 ; in v : T1 )
{ Pre : . . . }
{ Post : . . . }
.

En lo que a la precondicin atae, exigir que la clave c sea nueva se traduce en que sta no debe
estar en el segmento [ 0..tam ) del arreglo claves, y exigir que quede capacidad en el diccionario
se re-expresa en trminos del atributo tam. En cuanto a la postcondicin, agregar el nuevo
par al diccionario se expresa en trminos de los contenidos de los dos arreglos del modelo de
representacin (concreto). Veamos la re-especificacin:
proc agregar ( in-out d : Diccionario ; in c : T0 ; in v : T1 )
{ Pre : ( i : 0 6 i < d.tam : d.claves[i] = c ) d.tam < d.MAX }
{ Post : d.tam = d0 .tam + 1
d.claves = d0 .claves (d0 .tam : c)
d.valores = d0 .valores (d0 .tam : v) }
.
Note que en la postcondicin estamos utilizando la notacin a(i : x) de construccin de un
nuevo arreglo por reemplazo en a de la posicin i con el valor x (ver definicin en [Kal90, seccin 10.1] o [Mez00, seccin 6.2]). Esto es, a(i : x) denota a un arreglo que coincide con a en
todas las posiciones, excepto en i, posicin en la que el nuevo arreglo contiene x. Formalmente,
a(i : x)[j] = a[j] para toda posicin j diferente de i, y a(i : x)[i] = x . La postcondicin arriba
indicada para agregar expresa entonces que ambos arreglos d.claves y d.valores se mantienen
intactos, salvo por la posicin correspondiente a d0 .tam (esto es, el valor inicial de d.tam ), en
la que se almacena el nuevo par (c, v) .
Note que la postcondicin dada es, en trminos estrictamente lgicos, ligeramente ms fuerte
de lo necesario. Dado que el segmento [ tam..MAX ) es irrelevante en ambos arreglos, su contenido no tiene por qu permanecer igual; si esta porcin de los arreglos cambiase, igualmente
cumpliramos con lo deseado. Sera vlido entonces slo exigir la postcondicin, ligeramente ms
dbil, siguiente:
{ Post : d.tam = d0 .tam + 1
( i : 0 6 i < d0 .tam : d.claves[i] = d0 .claves[i]
d.valores[i] = d0 .valores[i] )
d.claves[d0 .tam] = c d.valores[d0 .tam] = v }
,
lo cual equivale a la postcondicin anterior en el segmento relevante de los arreglos mientras
se permite que el segmento irrelevante de los arreglos sea alterado arbitrariamente. En particular, esta nueva postcondicin permitira que tal alteracin arbitraria del segmento irrelevante
correspondiese a mantener los valores (irrelevantes) anteriores.
19

Como de costumbre, preferimos la postcondicin que dimos inicialmente. En este caso, pues es
ms concisa y clara, y porque sabemos que la restriccin innecesaria impuesta sobre los segmentos
irrelevantes no involucrar costos innecesarios de ejecucin al momento de implementar el cuerpo
de la subrutina/operacin.
Note tambin que la relacin de acoplamiento entre nuestro modelo concreto y el modelo
abstracto de la especificacin original del TAD no impone ningn requerimiento de orden sobre
los pares clave/valor en los arreglos. Por lo tanto, si estos pares fuesen reorganizados apropiadamente en los arreglos, el diccionario representado seguira siendo el mismo. Por ejemplo, nuestra
postcondicin podra requerir la siguiente reorganizacin, correspondiente a insertar el nuevo par
(c, v) en la posicin 0 desplazando el resto de los elementos hacia la derecha, y el resultado an
sera el deseado:
{ Post : d.tam = d0 .tam + 1
d.claves[0] = c d.valores[0] = v
( i : 1 6 i < d.tam : d.claves[i] = d0 .claves[ i 1 ]
d.valores[i] = d0 .valores[ i 1 ] ) } .
Sin embargo, a pesar de que esta postcondicin (concreta) es consistente con la postcondicin
(abstracta) original que se desea satisfacer, nuestros conocimientos de programacin nos sealan
que satisfacer esta postcondicin ser ms costoso que satisfacer la postcondicin (concreta)
originalmente especificada (satisfacer esta nueva postcondicin sera de complejidad lineal sobre
el tamao del diccionario, mientras que satisfacer la primera sera de complejidad constante).
En esta operacin hemos visto un buen ejemplo de cmo una re-especificacin explcita puede
sugerir implementaciones particulares. Cada una de las postcondiciones antes propuestas sugiere
una cierta implementacin: colocar el nuevo par al final del segmento relevante de los arreglos, o
colocar el nuevo par al inicio de tal segmento haciendo un corrimiento del resto de los pares.
Eliminar En este caso, la precondicin puede reexpresarse en los nuevos trminos sin mayor
problema, de manera similar a como se hizo con la operacin anterior agregar :
proc eliminar ( in-out d : Diccionario ; in c : T0 )
{ Pre : ( i : 0 6 i < d.tam : d.claves[i] = c ) }
{ Post : . . . }
.
La postcondicin es un poco ms compleja. Al eliminar el par de ambos arreglos, no podemos
dejar un hueco en medio del segmento relevante. Una posibilidad sera mover una posicin
hacia a la izquierda a todos los pares relevantes que estn a la derecha del par eliminado. Sin
embargo, esto sera innecesariamente costoso, ya que no es necesario mantener a los elementos
en el orden en el que estaban inicialmente en los arreglos. La manera menos costosa de tapar el
hueco dejado por el par eliminado es trayendo al ltimo par hacia el espacio dejado por el par
eliminado. Re-especificamos eliminar entonces de esa forma:
proc eliminar ( in-out d : Diccionario ; in c : T0 )
{ Pre : ( i : 0 6 i < d.tam : d.claves[i] = c ) }
{ Post : d.tam = d0 .tam 1
( i : 0 6 i < d0 .tam : d0 .claves[i] = c
d.claves = d0 .claves (i : d0 .claves[ d0 .tam 1 ])
d.valores = d0 .valores (i : d0 .valores[ d0 .tam 1 ]) ) } .
Note que existen otras posibles reorganizaciones vlidas para los arreglos, tal como sealamos
anteriormente para la operacin agregar . Sin embargo, la manera escogida parece ser la ms
sencilla de obtener el resultado deseado.
20

De nuevo, note que el haber utilizado para esta operacin la alternativa de re-especificacin
explcita permiti proponer, en la postcondicin, una manera particular de implementar la eliminacin de un par.
Buscar y determinar existencia Ya hemos jugado lo suficiente con el nuevo modelo (concreto) como para que la especificacin de las ltimas dos operaciones no represente un problema.
La especificacin de stas se encuentra en la figura 4.4.(d).

4.4.

Armando el aparato completo. . . ahora como refinamiento

La re-especificacin de nuestro TAD Diccionario con el modelo concreto ya est completa.


Los componentes de esta re-especificacin son casi los mismos de la especificacin inicial anterior:
modelo (ahora concreto) de representacin, invariante de representacin, y operaciones. Mas
ahora hay un nuevo componente: la relacin de acoplamiento. Esta relacin enlaza el nuevo
modelo (concreto) con el anterior modelo (abstracto), por lo cual esta re-especificacin ha de
establecerse desde un principio como dependiente de la anterior. He all la necesidad de haber
dado un nombre, A, a la especificacin anterior: para poder referirnos a ella posteriormente.
Nuestra nueva especificacin ser llamada B, y desde el encabezado de la especificacin ser
declarada como una re-especificacin. Diremos que la especificacin B es un refinamiento de A.
Formalmente, las tcnicas que nos permitirn mostrar que nuestra re-especificacin B con
miras a implementar el TAD es consistente con la especificacin original A son tcnicas de
refinamiento de datos. De all que digamos que B es un refinamiento de A o, ms especficamente , B es un datos-refinamiento de A (del trmino en ingls data-refinement), ya que lo que
se ha modificado para acercarnos a una implementacin es el espacio de datos, esto es, el modelo
de representacin.
La re-especificacin completa del TAD Diccionario ha sido ensamblada en la figura 4.4.(d).

4.5.

Finalizando la implementacin

Una vez re-especificado el TAD con modelo concreto, lo nico que resta hacer para completar
la implementacin es construir un cuerpo para cada subrutina/operacin del TAD, de forma tal
que el cuerpo sea correcto con respecto a la especificacin pre/post-condicin dada para cada
operacin. En estas notas no nos ocuparemos de la construccin de tales cuerpos de subrutinas
y dejamos esta labor como ejercicio.

4.6.

Ejercicios

4.6-a. . . . ejercicios sobre reespecificacin de las operaciones relajando las precondiciones. . .


4.6-b. . . . ejercicios sobre cambio de modelo concreto. . .
4.6-c. . . . ejercicio sobre TAD MultiDiccionario. . .

21

Especificacin B de TAD Diccionario (T0 , T1 ) , refinamiento de A


Modelo de Representacin
const MAX : int
var claves : array [ 0..MAX ) of T0
valores : array [ 0..MAX ) of T1
tam : int
Invariante de Representacin
MAX > 0 0 6 tam 6 MAX
( i, j : 0 6 i, j < tam : i 6= j claves[i] 6= claves[j] )
Relacin de Acoplamiento
conoc = { i : 0 6 i < tam : claves[i] }

tabla = { i : 0 6 i < tam : (claves[i], valores[i]) }


Operaciones
proc crear ( in m : int ; out d : Diccionario )
{ Pre : m > 0 }
{ Post : d.MAX = m d.tam = 0 }
proc agregar ( in-out d : Diccionario ; in c : T0 ; in v : T1 )
{ Pre : ( i : 0 6 i < d.tam : d.claves[i] = c ) d.tam < d.MAX }
{ Post : d.tam = d0 .tam + 1
d.claves = d0 .claves (d0 .tam : c)
d.valores = d0 .valores (d0 .tam : v) }
proc eliminar ( in-out d : Diccionario ; in c : T0 )
{ Pre : ( i : 0 6 i < d.tam : d.claves[i] = c ) }
{ Post : d.tam = d0 .tam 1
( i : 0 6 i < d0 .tam : d0 .claves[i] = c
d.claves = d0 .claves (i : d0 .claves[ d0 .tam 1 ])
d.valores = d0 .valores (i : d0 .valores[ d0 .tam 1 ]) ) }
proc buscar ( in d : Diccionario ; in c : T0 ; out v : T1 )
{ Pre : ( i : 0 6 i < d.tam : d.claves[i] = c ) }
{ Post : ( i : 0 6 i < d.tam : d.claves[i] = c d.valores[i] = v ) }
proc existe ( in d : Diccionario ; in c : T0 ; out e : boolean )
{ Pre : true }
{ Post : e ( i : 0 6 i < d.tam : d.claves[i] = c ) }
Fin TAD

Figura 4.4.(d): Re-especificacin con modelo concreto del TAD Diccionario

22

5.

Otros ejemplos de implementacin de TADs (clsicos)

En esta seccin veremos otros ejemplos de implementacin de TADs, correspondientes a los


ejemplos de especificacin de la seccin 3. As como los TADs entonces presentados fueron clsicos,
las soluciones de implementacin para ellos que ac presentaremos son clsicas en s mismas.

5.0.

Una implementacin del TAD Cola

Como el TAD Cola especificado en la seccin 3.0 corresponde a colas con capacidad acotada, es
razonable utilizar un arreglo en el modelo concreto de representacin para almacenar los elementos
de una cola. Por supuesto, tambin es razonable utilizar como tamao del arreglo a la capacidad
mxima prescrita por la especificacin (a pesar de que en el ejercicio 5.2-a mencionaremos otra
posibilidad de implementacin en la que el tamao del arreglo es otro). Nuestro modelo concreto
empieza entonces as:
Modelo de Representacin
const MAX : int
var elems : array [ 0..MAX ) of T

Para manejar el contenido del arreglo, es natural pensar que, partiendo de una cola vaca,
los elementos se empezaran a encolar en ella en las posiciones 0, 1, 2, y as sucesivamente, del
arreglo. Esto sugiere agregar un ndice entero al modelo concreto de representacin que permita
controlar qu segmento del arreglo contiene a la cola en cada momento, con lo que este ndice
siempre sealara la posicin en la cual se debe encolar al siguiente elemento. Llamemos fin a tal
ndice, puesto que ste seala el final de la cola, y tomemos entonces que el segmento [ 0..fin )
del arreglo correspondera a la cola. Ntese que la operacin de encolar con este modelo sera
entonces implementable con complejidad constante.
Hasta ahora, nuestro ndice fin juega un papel similar al que jug el ndice tam en nuestra
implementacin del TAD Diccionario. Ahora bien, suponiendo que nos limitamos a utilizar un
solo ndice, como hicimos al implementar Diccionario, analicemos qu ocurrir con la operacin
de desencolar. El elemento que debera ser eliminado de la cola en esta operacin sera el ubicado
en la posicin 0 y entonces, si insistimos en que el segmento del arreglo que representa la cola
sea [ 0..fin ) , esto involucrara desplazar al resto de los elementos una posicin hacia la izquierda,
lo cual implicara que la operacin tuviese que ser implementada con complejidad lineal sobre el
tamao de la cola. Esto en s mismo no parece ser un gran problema, y de hecho la operacin
de eliminacin sugerida por la re-especificacin de implementacin en el caso de Diccionario
resulta ser de complejidad lineal, pero en el caso de nuestro TAD Cola podemos obtener mejor
complejidad. Para ello, en lugar de insistir en la posicin 0 como inicio de la cola, basta introducir
un segundo ndice entero inic que indique el inicio de la cola, avanzando a ste una posicin hacia
la derecha cada vez que se desencole un elemento, en lugar de desplazar a los elementos dentro del
arreglo. Esto permite que la operacin de desencolar sea implementable con la misma complejidad
constante con la que es implementable la operacin de encolar.
Tenemos entonces por ahora que el segmento del arreglo que representara a la cola sera
[ inic..fin ) . El ndice inic seala por dnde desencolar elementos, mientras fin seala por dnde
encolar nuevos elementos. Ahora bien, cuando al encolar un elemento el ndice fin llegue al extremo
derecho del arreglo, no tiene sentido declarar a la cola como llena si se tiene que inic ha avanzado
desde su posicin inicial de 0 debido a desencolamientos previos. Si disemos la cola por llena
en un caso as, estaramos desaprovechando parte del arreglo que no est en uso, especficamente
23

el segmento [ 0..inic ) del arreglo, y adems estaramos irrespetando la especificacin original,


la cual exige que una cola sea considerada llena slo cuando cuenta con MAX elementos. Esta
situacin la podemos manejar utilizando al arreglo de manera circular, considerando que la
ltima casilla del arreglo tiene como vecina a su derecha a la casilla inicial del arreglo. As, luego
de la posicin MAX 1 , estara ubicada la posicin 0, lo que nos permite reusar el segmento
[ 0..inic ) para continuar agregando elementos a la cola que en este momento se encontrara
en el segmento [ inic..MAX ) . Llevando fin circularmente en este caso a 0 y continuando as
otros encolamientos, terminaramos con que la cola correspondera en tal momento al segmento
[ inic..MAX ) seguido del segmento [ 0..fin ) del arreglo.
Nuestro modelo concreto tendra entonces ahora la siguiente forma:
Modelo de Representacin
const MAX : int
var elems : array [ 0..MAX ) of T
inic, fin : int

donde los ndices enteros delimitaran la cola. Segn lo discutido en el prrafo anterior, esta
delimitacin ser en ocasiones continua convencional y en ocasiones circular. Analicemos ahora
cmo discriminar la utilizacin de un estilo u otro de delimitacin.
Cuando se tenga que inic < fin , tendremos una cola almacenada de manera continua convencional en el segmento [ inic..fin ) del arreglo. Por el contrario, cuando se tenga que inic > fin ,
tendremos una cola almacenada de manera circular en el segmento [ inic..MAX ) seguido del
segmento [ 0..fin ) del arreglo. Ahora bien, el caso inic = fin es problemtico, pues puede ser
interpretado de dos maneras: se tiene una cola vaca en [ inic..fin ) , o se tiene una cola llena
con MAX elementos en [ inic..MAX ) seguido de [ 0..fin ) . Para poder distinguir estas dos situaciones, utilizaremos un atributo booleano que nos indique si la cola est vaca o no, para as
poder discenir qu tenemos cuando los dos ndices enteros sean iguales (simtricamente, tambin
podramos haber utilizado un booleano que indicase si la cola est llena o no; el ejercicio 5.2-a
explora esta otra posibilidad). Esto completa nuestro modelo de la siguiente forma:
Modelo de Representacin
const MAX : int
var elems : array [ 0..MAX ) of T
inic, fin : int
nada : boolean

La figura 5.0.(e) muestra la re-especificacin completa de nuestro TAD Cola con modelo
concreto de representacin para implementacin correspondiente a arreglo circular.
En cuanto al invariante de representacin, note que a los ndices enteros no se les permite
alcanzar el valor MAX (a diferencia de, por ejemplo, el ndice entero tam de la implementacin de
Diccionario), ya que el manejo circular involucra considerar a 0 como el sucesor de MAX 1 .
Adems, la tercera y ltima restriccin elimina la posibilidad de inconsistencia entre el booleano
y los ndices enteros: no puede ocurrir que la cola est vaca y los ndices sean diferentes.
La relacin de acoplamiento discrimina si la cola est almacenada de manera continua o
circular, construyendo la secuencia correspondiente de manera apropiada. Las condiciones de
discriminacin han sido simplificadas en la figura 5.0.(e). Ms detalladamente, estas condiciones
corresponderan a las siguientes frmulas: el almacenamiento continuo ocurre cuando se tiene
inic < fin (inic = fin nada)

,
24

Especificacin B de TAD Cola (T ) , refinamiento de A


Modelo de Representacin
const MAX : int
var elems : array [ 0..MAX ) of T
inic, fin : int
nada : boolean
Invariante de Representacin
MAX > 0 0 6 inic, fin < MAX (nada inic = fin)
Relacin de Acoplamiento
(inic < fin nada contenido = h i : inic fin : elems[i] i)

(inic > fin nada


contenido = h i : inic MAX : elems[i] i ++ h i : 0 fin : elems[i] i)
Operaciones
proc crear ( in m : int ; out c : Cola )
{ Pre : m > 0 }
{ Post : c.MAX = m c.inic = 0 c.fin = 0 c.nada }
proc encolar ( in-out c : Cola ; in x : T )
{ Pre : c.inic 6= c.fin c.nada }
{ Post : c.inic = c0 .inic c.fin = (c0 .fin + 1) mod c.MAX
c.elems = c0 .elems (c0 .fin : x) c.nada }
proc desencolar ( in-out c : Cola )
{ Pre : c.nada }
{ Post : c.inic = (c0 .inic + 1) mod c.MAX c.fin = c0 .fin
c.elems = c0 .elems (c.nada (c.inic = c.fin)) }
proc primero ( in c : Cola ; out x : T )
{ Pre : c.nada }
{ Post : x = c.elems[c.inic] }
proc vacia ( in c : Cola ; out v : boolean )
{ Pre : true }
{ Post : v c.nada }
Fin TAD

Figura 5.0.(e): Re-especificacin con modelo concreto del TAD Cola

25

mientras el almacenamiento circular ocurre cuando se tiene


inic > fin (inic = fin nada)

Sin embargo, el invariante de representacin nos permite obtener frmulas ms concisas. Para el
almacenamiento continuo, simplificamos como se indica a continuacin:
inic < fin (inic = fin nada)

h por invariante de representacin, nada inic = fin ; lgica proposicional i


inic < fin nada .
Para el almacenamiento circular, manipulamos de la siguiente forma:
inic > fin (inic = fin nada)

h distributividad de disyuncin sobre conjuncin, relaciones aritmticas i


inic > fin (inic > fin nada)


por invariante de representacin y contrarrecproco, inic 6= fin nada ;

por relaciones aritmticas, inic > fin inic 6= fin ; lgica proposicional
inic > fin nada .
Continuando con la relacin de acoplamiento, una vez discriminado en qu segmento o segmentos est almacenada la cola, se determina la secuencia correspondiente al atributo abstracto
contenido. Explicamos brevemente a continuacin nuestra notacin para definir secuencias por
comprensin, que es de la forma h x : a b : E i , con x una variable generadora, a y b enteros,
y E una expresin del tipo deseado para los elementos de la secuencia. A diferencia de la notacin
para definir conjuntos por comprensin, el rango o componente medio que determina los valores a
utilizar para la variable x no es una expresin booleana sino una secuencia, ya que para conjuntos
el orden de tales valores no era relevante pero ahora para secuencias s lo es. El rango a b
denota a la secuencia formada por los enteros del segmento [ a..b ) en orden ascendente, de la
cual toma valores x de manera ordenada. Para cada uno de tales valores se utiliza la expresin
E para determinar los elementos de la secuencia en construccin.
De nuevo nos hemos desviado de la notacin de [Mor94], donde al igual que antes se utiliza a
| y como separadores, pero adems se mantiene el carcter booleano del rango cambiando
en su lugar al tipo de la variable generadora por una secuencia en lugar de un conjunto. Nuestra
h x : a b : E i sera en el texto en cuestin h x : a b | true E i . Mantener el rango booleano da a [Mor94] mayor poder expresivo, pero nuestro limitado uso de secuencias definidas por
comprensin permite que nos mantengamos con nuestra ms sencilla versin. Ms informacin
sobre tal notacin ms poderosa para definir secuencias por comprensin en [Mor94, seccin 9.3.3].
Volviendo a nuestra re-especificacin del TAD, y pasando ahora a las pre/post-condiciones de
las operaciones, note que bajo nuestro modelo concreto una cola c est llena exactamente cuando
c.inic = c.fin c.nada

mientras que est vaca exactamente cuando se cumple


c.nada
(frmula ms sencilla gracias al invariante de representacin). La negacin de estas dos condiciones
es usada, respectivamente, en la precondicin de encolar para asegurar la existencia de espacio
26

para el nuevo elemento, y en las precondiciones de desencolar y primero para asegurar la existencia
de elementos.
El manejo circular para los ndices se logra mediante aritmtica modular con la operacin de
resto de divisin entera. As, por ejemplo, avanzar el ndice fin de una cola c se indica mediante
c.fin = (c0 .fin + 1) mod c.MAX

lo cual corresponde a c.fin = c0 .fin + 1 si se tiene que c0 .fin < c.MAX 1 , y a c.fin = 0 si se
tiene que c0 .fin = c.MAX 1 . Anlogamente se especifica el avance del otro ndice inic.
Por ltimo, vale la pena comentar la importancia de no olvidar especificar en las postcondiciones el comportamiento del atributo booleano nada cuando alguna cola es creada o cambiada
(esto es, cuando una cola es parmetro de salida o de entrada/salida). En los casos de crear y
encolar es sencillo, pues el valor final es fijo. En el caso de desencolar depende del valor final
de los ndices enteros; note que es importante usar una equivalencia para determinar el valor del
atributo booleano en todos los casos (la igualdad de los ndices no puede confundirse en este caso
con la posibilidad de cola llena pues se acaba de desencolar un elemento).
Tal como se adelant al inicio de esta seccin 5, esta implementacin de Cola con un arreglo
circular es una solucin clsica de implementacin de este TAD. Otra presentacin de esta
solucin puede conseguirse en [CLRS09, seccin 10.1], aunque all se usa la variante sin el booleano
discutida en el ejercicio 5.2-a.

5.1.

Una implementacin del TAD Conjunto

Escogemos para nuestro TAD Conjunto especificado en la seccin 3.1 un modelo concreto de
representacin anlogo al utilizado para el TAD Diccionario: un arreglo cuyo tamao corresponda
a la capacidad mxima y un ndice que seale el segmento inicial del arreglo que realmente
almacena a los elementos. Las figuras 5.1.(f ) y 5.1.(g) muestran la re-especificacin completa
con modelo concreto. El invariante de representacin y la relacin de acoplamiento son anlogos
a los utilizados en el caso de Diccionario.
Note que la postcondicin de agregar es ms compleja que la utilizada en el caso de Diccionario
(a pesar de tener un arreglo menos en el modelo). Esto se debe al carcter menos restrictivo de
la precondicin correspondiente, pues en el caso de Diccionario slo se poda agregar claves no
existentes previamente, mientras que ahora se permite que el elemento a agregar pueda estar o no
previamente en la coleccin. Discriminar entre estas dos posibilidades genera el anlisis de casos
que puede verse en la postcondicin, segn el cual el modelo debe ser actualizado o no.
En el caso de la postcondicin correspondiente en la especificacin original con modelo abstracto, el anlisis por casos no hizo falta pues todas las posibilidades son manejadas adecuadamente por el operador de unin de conjuntos. Esto podra haberse explotado tambin en esta
re-especificacin con modelo concreto, usando como postcondicin a
{ i : 0 6 i < c.tam : c.elems[i] } = { i : 0 6 i < c0 .tam : c0 .elems[i] } { x }

Note que esta nueva propuesta de postcondicin es una especie de traduccin directa de la postcondicin original, re-expresando lo referido al atributo abstracto contenido con los atributos
concretos elems y tam segn lo indicado por la relacin de acoplamiento. Esto es un ejemplo de
las re-especificaciones concretas implcitas inducidas por relaciones de acoplamiento de las que se
habl en la seccin 4.3 y que sern elaboradas con ms detalle en la futura seccin 6.
Analicemos brevemente, en el caso de agregar , posibles ventajas y desventajas de la reespecificacin implcita inducida por la relacin de acoplamiento presentada en el prrafo anterior
27

Especificacin B de TAD Conjunto (T ) , refinamiento de A


Modelo de Representacin
const MAX : int
var elems : array [ 0..MAX ) of T
tam : int
Invariante de Representacin
MAX > 0 0 6 tam 6 MAX
( i, j : 0 6 i, j < tam : i 6= j elems[i] 6= elems[j] )
Relacin de Acoplamiento
contenido = { i : 0 6 i < tam : elems[i] }
Operaciones
proc crear ( in m : int ; out c : Conjunto )
{ Pre : m > 0 }
{ Post : c.MAX = m c.tam = 0 }
proc agregar ( in-out c : Conjunto ; in x : T )
{ Pre : ( i : 0 6 i < c.tam : c.elems[i] = x ) c.tam < c.MAX }
{ Post : (( i : 0 6 i < c0 .tam : c0 .elems[i] = x )
c.tam = c0 .tam c.elems = c0 .elems)

( ( i : 0 6 i < c0 .tam : c0 .elems[i] = x )


c.tam = c0 .tam + 1 c.elems = c0 .elems (c0 .tam : x)) }
proc eliminar ( in-out c : Conjunto ; in x : T )
{ Pre : true }
{ Post : ( ( i : 0 6 i < c0 .tam : c0 .elems[i] = x )
c.tam = c0 .tam c.elems = c0 .elems)

(( i : 0 6 i < c0 .tam : c0 .elems[i] = x )


c.tam = c0 .tam 1
( i : 0 6 i < c0 .tam : c0 .elems[i] = x
c.elems = c0 .elems (i : c0 .elems[ c0 .tam 1 ]) )) }
proc extraer ( in c : Conjunto ; out x : T )
{ Pre : c.tam > 0 }
{ Post : ( i : 0 6 i < c.tam : c.elems[i] = x ) }
proc pertenece ( in c : Conjunto ; in x : T ; out p : boolean )
{ Pre : true }
{ Post : p ( i : 0 6 i < c.tam : c.elems[i] = x ) }
..
.

Figura 5.1.(f ): Re-especificacin con modelo concreto del TAD Conjunto (inicio)

28

..
.
proc vacio ( in c : Conjunto ; out v : boolean )
{ Pre : true }
{ Post : v (c.tam = 0) }
proc unir ( in c0 , c1 : Conjunto ; in m : int ; out c : Conjunto )
{ Pre : c0 .tam + c1 .tam 6 m }
{ Post : c.MAX = m
{ i : 0 6 i < c.tam : c.elems[i] } =
{ i : 0 6 i < c0 .tam : c0 .elems[i] }
{ i : 0 6 i < c1 .tam : c1 .elems[i] } }
proc intersectar ( in c0 , c1 : Conjunto ; in m : int ; out c : Conjunto )
{ Pre : c0 .tam 6 m c1 .tam 6 m }
{ Post : c.MAX = m
{ i : 0 6 i < c.tam : c.elems[i] } =
{ i : 0 6 i < c0 .tam : c0 .elems[i] }
{ i : 0 6 i < c1 .tam : c1 .elems[i] } }
proc restar ( in c0 , c1 : Conjunto ; in m : int ; out c : Conjunto )
{ Pre : c0 .tam 6 m }
{ Post : c.MAX = m
{ i : 0 6 i < c.tam : c.elems[i] } =
{ i : 0 6 i < c0 .tam : c0 .elems[i] }
{ i : 0 6 i < c1 .tam : c1 .elems[i] } }
Fin TAD

Figura 5.1.(g): Re-especificacin con modelo concreto del TAD Conjunto (fin)

29

contra la re-especificacin explcita utilizada en la figura 5.1.(f ). La postcondicin implcita es


concisa, adems de deducible automticamente, ambas cosas puntos a su favor. Por otra parte,
no sugiere casi nada para la implementacin del cuerpo de la operacin; slo dice algo como
haga lo que quiera siempre y cuando el conjunto final representado sea el adecuado. Esto tiene
la ventaja de mantener abiertas todas las posibilidades existentes de implementacin del cuerpo,
pero tiene la desventaja de no sugerir a ninguna de tales posibilidades como deseable. Por el
contrario, la postcondicin explcita presentada en la figura 5.1.(f ) sugiere cmo implementar el
cuerpo: haga anlisis por casos y luego actualice adecuadamente al modelo. Esto tiene la ventaja
de guiar la implementacin, pero la desventaja de descartar otras posibles implementaciones (por
ejemplo, ubicar al nuevo elemento en otra posicin diferente a la ltima). Podemos ver que no hay
respuesta clara a qu es mejor al decidir entre re-especificaciones implcitas y re-especificaciones
explcitas que restringen posibles implementaciones.
A la postcondicin de eliminar le aplica analgamente todo el anlisis hecho con agregar .
En cuanto a unir , intersectar y restar , note que las postcondiciones de la re-especificacin
explcita propuesta corresponden exactamente a la re-especificacin implcita inducida por la
relacin de acoplamiento. En estos tres casos, cualquier otro intento de re-especificacin de la
postcondicin sera considerablemente ms complejo; se le sugiere que intente y se convenza de
esto personalmente.

5.2.

Ejercicios

5.2-a. . . . cambiar modelo de implementacin del TAD Cola; explorar varias posibilidades: cambio de interpretacin de booleano, cambio de booleano por entero, cambio de booleano
por casilla extra. . .
5.2-b. . . . una implementacin del TAD ColaConPrioridades. . .
5.2-c. . . . una implementacin del TAD Pila. . .
5.2-d. . . . cambiar modelo de implementacin del TAD Conjunto, por ejemplo exigiendo que el
arreglo est ordenado y analizando implementaciones de unin e interseccin. . .
5.2-e. . . . dos implementaciones del TAD MultiConjunto. . .

6.

Consistencia Implementacin vs. Especificacin

Tal como hemos sealado ya repetidamente, en estas notas consideramos a una especificacin
de TAD con modelo abstracto como el contrato original que se le exige a un TAD o, en otras
palabras, como la especificacin propiamente dicha del TAD, mientras consideramos a cualquier
subsiguiente re-especificacin del TAD con modelo concreto como un diseo intermedio entre
el contrato original y una implementacin final ya con todas las operaciones completamente
construidas. Ahora bien, el sentido comn indica que tal diseo intermedio debe ser consistente
con el contrato original, para que tenga sentido continuar construyendo una implementacin por
esa va.
Para mostrar tal consistencia entre una especificacin con modelo abstracto de un TAD, o
contrato original del TAD, y una re-especificacin con modelo concreto del mismo, o diseo intermedio hacia una implementacin completa, existen tcnicas llamadas de refinamiento de datos.

30

El nombre proviene del hecho de que una especificacin se ha de refinar, o transformar hacia una
implementacin, mediante un cambio en el modelo de datos utilizado: exactamente nuestro caso.
Entre las dos especificaciones a ser mostradas como consistentes tenemos como componentes
comunes a (i) el modelo de representacin, (ii) el invariante de representacin, y (iii) las operaciones, mientras que el nico componente no-comn ser precisamente el que servir de puente,
que es la relacin de acoplamiento. El componente (i) es justamente lo que cambia: no tenemos
nada que decir all. Los componentes (ii) y (iii) deben guardar una cierta relacin de consistencia;
de esto nos ocuparemos en las siguientes subsecciones.

6.0.

Invariante de Representacin

Llamemos InvA al invariante de representacin de la especificacin original con modelo abstracto, llamemos InvC al invariante de representacin de la re-especificacin con modelo concreto,
y por ltimo llamemos Ac a la relacin de acoplamiento entre ambos modelos.
Lo que necesitamos es asegurar que la implementacin con modelo concreto garantice que los
requerimientos iniciales con modelo abstracto sean satisfechos. Por lo tanto, lo que necesitamos
garantizar es que el invariante concreto InvC implique que tambin se cumple el invariante
abstracto InvA. Como estos invariantes estn definidos en espacios diferentes, se requiere asumir
como hiptesis al acoplamiento Ac para poder establecer la implicacin deseada. Lo que ha de
demostrarse es entonces
[ Ac InvC InvA ]

lo cual expresa de manera ms sencilla la implicacin arriba sugerida en lenguaje natural, que
formalizada literalmente sera [ Ac (InvC InvA) ] .
Nota:
Utilizamos los corchetes [ . . . ] como cuantificacin universal implcta, de la
misma manera que es utilizada en [Kal90], tal como fue propuesto inicialmente
por Dijkstra y compaa en [DS90].
(Fin de nota.)
Para demostrar este requerimiento en el caso de nuestras especificacin e implementacin
propuestas en las secciones anteriores para el TAD Diccionario, suponemos primero todas las
hiptesis correspondientes a Ac e InvC :
(Hip0)
(Hip1)
(Hip2)
(Hip3)
(Hip4)

conoc = { i : 0 6 i < tam : claves[i] }


tabla = { i : 0 6 i < tam : (claves[i], valores[i]) }
MAX > 0
0 6 tam 6 MAX
( i, j : 0 6 i, j < tam : i 6= j claves[i] 6= claves[j] )

y debemos demostrar como consecuente a las afirmaciones de InvA:


(Cons0)
(Cons1)
(Cons2)

MAX > 0
# conoc 6 MAX
conoc = dom tabla

Procedamos entonces con las demostraciones correspondientes. . .


31

Primero, (Cons0) es consecuencia trivial de la hiptesis (Hip2).


Luego, en relacin con (Cons1), razonamos de la siguiente forma:
# conoc
=
h hiptesis (Hip0) i
# { i : 0 6 i < tam : claves[i] }
* hiptesis (Hip4) garantiza que todos los elementos generados +
para el conjunto son diferentes y, por lo tanto, la cantidad de
=
ellos es exactamente igual a la cantidad de valores del rango
tam
6
h hiptesis (Hip3) i
MAX
.
Note que la hiptesis (Hip4) no es imprescindible ya que, de no haber contado con sta, el segundo
paso se habra podido dar con una desigualdad 6 en lugar de una igualdad =. Esto se debe a
que, de haber podido existir claves repetidas en el segmento [ 0..tam ) del arreglo claves, habra
a lo sumo tam claves en el conjunto conoc, posiblemente menos.
Por ltimo, para demostrar (Cons2) partimos del lado derecho (que es el ms complejo) y
llegamos al lado izquierdo de la siguiente forma:
dom tabla
=
h hiptesis (Hip1) i
dom { i : 0 6 i < tam : (claves[i], valores[i]) }
=
h dom extrae las primeras componentes i
{ i : 0 6 i < tam : claves[i] }
=
h hiptesis (Hip0) i
conoc .
Listo: hemos demostrado el requerimiento de consistencia [ Ac InvC InvA ] correspondiente a los invariantes de representacin para nuestras especificaciones del TAD Diccionario.

6.1.

Operaciones

Para cada una de las operaciones se deber mostrar que su re-especificacin con modelo
concreto es consistente con la especificacin original con modelo abstracto. Tomemos entonces
una operacin cualquiera y supongamos que su especificacin original estaba dada por el par
pre/post-condicin PreA y PostA ( . . . A por abstractas) mientras la re-especificacin est dada
por PreC y PostC ( . . . C por concretas).
Primera versin (excesivamente fuerte) de la consistencia Lo ideal es que ambas especificaciones de la operacin digan exactamente lo mismo, por lo que el objetivo pareciera ser
demostrar
[ . . . PreA PreC ]

32

y
[ . . . PostA PostC ]

Sin embargo, no tiene sentido intentar demostrar estas equivalencias por s solas, ya que las
frmulas involucradas se refieren a modelos diferentes. Esto es, PreA y PostA estn formuladas
sobre el modelo abstracto y, por lo tanto, no tiene sentido intentar demostrar que son equivalentes
a PreC y PostC , que estn formuladas sobre el modelo concreto. Debemos entonces echar mano
de nuestro puente: la relacin de acoplamiento entre ambos modelos.
Si el nuevo TAD en definicin y construccin es T , los modelos abstracto y concreto son
utilizados sobre los parmetros de tipo T de la operacin. Las precondiciones slo hacen referencia
a parmetros que son dados como entrada a la operacin, por lo que la conexin debe construirse
haciendo uso de la relacin de acoplamiento aplicada sobre todo parmetro que sea dato de
entrada. Con tal puente como hiptesis tiene entonces sentido intentar demostrar la consistencia
deseada entre las dos precondiciones:
[ ( x : x es parmetro in o in-out de tipo T : x.Ac ) (PreA PreC ) ]

entendiendo que x.Ac denota las condiciones exigidas por la relacin de acoplamiento Ac particularizadas para los atributos del objeto x. Por otra parte, las postcondiciones pueden referirse
a: (i) los parmetros de salida, (ii) tanto el estado final como el estado inicial de los parmetros
de entrada/salida, y (iii) los parmetros de entrada (a los cuales, recuerde, por convencin consideramos constantes). La hiptesis puente debe entonces en este caso considerar a todos estos
parmetros:
[ ( x : x es parmetro in, out o in-out de tipo T : x.Ac )
( x : x es parmetro in-out de tipo T : x0 .Ac ) (PostA PostC ) ]

donde, de nuevo, x.Ac se refiere a la relacin de acoplamiento formulada sobre los atributos del
objeto x e, igualmente, x0 .Ac se refiere al acoplamiento formulado sobre los atributos de x0 , esto
es, el valor inicial del parmetro (de entrada/salida) x.
Hay un ltimo detalle a considerar relacionado con los invariantes de representacin, el cual, al
ser discutido, puede adems dilucidar una potencial duda que las personas lectoras podran tener
en este momento. Recuerde que los invariantes de representacin sobre los parmetros de tipo
T de las operaciones son considerados parte implcita de la precondicin o de la postcondicin
(dependiendo de si el parmetro es de entrada, de salida, o de entrada/salida). Sin embargo, en
las demostraciones de refinamiento de datos basta slo considerar los componentes explcitos en
los pares pre/post-condicin, lo cual significa que arriba nos referamos con PreA, PostA, PreC y
PostC a las pre/post-condiciones explcitas de las operaciones. Ms an, los componentes implcitos de los pares pre/post-condicin, esto es, los relacionados con invariantes de representacin,
no slo no hace falta incluirlos en los consecuentes a demostrar en las reglas de refinamiento de
datos, sino que pueden ser supuestos como hiptesis en tales demostraciones. Esto es:
[ ( x : x es parmetro in o in-out de tipo T : x.Ac x.InvA x.InvC )
(PreA PreC ) ]
y
[ ( x : x es parmetro in, out o in-out de tipo T : x.Ac x.InvA x.InvC )
( x : x es parmetro in-out de tipo T : x0 .Ac x0 .InvA x0 .InvC )
(PostA PostC ) ] ,
33

donde, al igual que antes con x.Ac y x0 .Ac , las expresiones x.InvA , x.InvC , x0 .InvA e x0 .InvC
se refieren a los invariantes de representacin particularizados a los objetos x y x0 . Note adems
que, gracias a haber demostrado previamente que en presencia de la relacin de acoplamiento
el invariante concreto InvC implica al invariante abstracto InvA, en las hiptesis antes referidas
es formalmente equivalente el listar solamente al invariante concreto InvC . Por mayor claridad,
mantenemos las reglas con la enumeracin completa de ambos invariantes, con lo que adems se
facilita el tener mayor conciencia sobre todas las hiptesis disponibles para las demostraciones.
El hecho de poder suponer los invariantes de representacin como hiptesis tiene que ver con
una propiedad llamada induccin sobre tipos de datos (ver, por ejemplo, [Lis01, seccin 5.7.1]).
Esto es: si
- toda operacin que produce inicialmente como parmetros de salida a objetos de tipo T
garantiza que tales objetos cumplan con el invariante de representacin (caso base), y
- toda operacin que recibe como entrada objetos de tipo T y produce como salida otros objetos de tipo T , al suponer que los de entrada cumplen con el invariante de representacin,
garantiza que los nuevos objetos de salida tambin lo cumplan (caso inductivo),
entonces todo objeto de tipo T producido por tal conjunto de operaciones cumplir siempre
el invariante de representacin. Por ello, tales invariantes pueden ser supuestos como ciertos
al demostrar la equivalencia entre las precondiciones abstracta/concreta y las postcondiciones
abstracta/concreta.
Cpsula breve sobre la presencia/ausencia de invariantes de representacin
Los invariantes de representacin deben ser considerados presentes implcitamente en las
pre/post-condiciones al momento de implementar las operaciones. Esto es, al construir los
cuerpos de los procedimientos/funciones correspondientes a las operaciones, las pre/postcondiciones con los invariantes de representacin son el contrato a cumplir.
Los invariantes de representacin deben ser considerados ausentes de las pre/post-condiciones al momento de demostrar las condiciones de consistencia correspondientes a refinamiento de datos (ya que los invariantes de representacin pueden ser supuestos como
ciertos gracias a induccin de tipos de datos).
Segunda versin (ms dbil) de la consistencia La versin ya presentada de la consistencia entre los pares pre/post-condicin abstractos vs. concretos es excesivamente fuerte. Esto se
debe a que no hace falta que los consecuentes a demostrar sean equivalencias: PreA PreC y
PostA PostC . Para que el refinamiento de datos sea correcto no hace falta que estas equivalencias sean vlidas, y de hecho en muchos casos estas equivalencias no sern ciertas (luego
veremos que en nuestro ejemplo del TAD Diccionario algunas de ellas no son ciertas). Basta con
que se cumpla slo una de las dos implicaciones presente en tales equivalencias. Sin embargo,
entender cul es la implicacin requerida en cada caso requiere un anlisis cuidadoso.
Recordemos un par de reglas sobre tripletas de Hoare que son de conocimiento comn:
si la tripleta { P } I { Q } es vlida
y tambin se tiene [ P 0 P ] ,
entonces la tripleta { P 0 } I { Q } tambin es vlida
34

y
si la tripleta { P } I { Q } es vlida
y tambin se tiene [ Q Q0 ] ,
entonces la tripleta { P } I { Q0 } tambin es vlida

stas pueden ser combinadas en una nica regla, como se especifica a continuacin:
si la tripleta { P } I { Q } es vlida
y se tienen las implicaciones [ P 0 P ] y [ Q Q0 ] ,
entonces la tripleta { P 0 } I { Q0 } tambin es vlida

Demos la siguiente lectura empresarial a esta ltima regla combinada: teniendo las implicaciones en cuestin, al cumplir con el contrato P/Q tambin se est entonces cumpliendo con
el contrato P 0 /Q0 . Y ahora volteemos los contratos y demos la siguiente re-lectura a la regla:
teniendo las implicaciones en cuestin, si el contrato original que se desea cumplir es P 0 /Q0
entonces basta con cumplir el contrato P/Q .
Extrapolando esta ltima lectura a nuestro problema de refinamiento de datos, esto es, garantizar la consistencia entre la especificacin abstracta y la especificacin concreta de una operacin,
el contrato que debemos cumplir es PreA/PostA y aspiramos que baste cumplir con una implementacin del contrato PreC /PostC . De acuerdo con la regla arriba planteada lo que necesitamos
entonces es cumplir con las implicaciones
[ . . . PreA PreC ]
y
[ . . . PostC PostA ]

Mas, como hay incompatibilidad en los espacios de datos utilizados entre las pre/post-condiciones
abstractas y las concretas, necesitamos como hiptesis todos los puentes ya antes planteados a
travs de la relacin de acoplamiento.
Nuestra nueva versin de las reglas sera entonces:
[ ( x : x es parmetro in o in-out de tipo T : x.Ac x.InvA x.InvC )
(PreA PreC ) ]
y
[ ( x : x es parmetro in, out o in-out de tipo T : x.Ac x.InvA x.InvC )
( x : x es parmetro in-out de tipo T : x0 .Ac x0 .InvA x0 .InvC )
(PostC PostA) ] .
Estas nuevas reglas son ms dbiles y, por lo tanto, ms fciles de satisfacer.
Por ltimo, hay una hiptesis adicional que an podemos agregar a la regla de las postcondiciones. Mientras se demuestra la correspondencia entre postcondiciones, puede utilizarse tambin
el hecho de que los parmetros de entrada (que son, recuerde, constantes) cumplan inicialmente
con la precondicin y que esto tambin ocurra para el valor inicial de los parmetros de entrada/salida. Por lo tanto, denotando Pre 0 al resultado de tomar la precondicin Pre y sustituir
en ella a todo parmetro de entrada/salida x por x0 , nuestra ltima versin de la regla (la ms
completa) para postcondiciones es:
[ ( x : x es parmetro in, out o in-out de tipo T : x.Ac x.InvA x.InvC )
( x : x es parmetro in-out de tipo T : x0 .Ac x0 .InvA x0 .InvC )
PreA0
(PostC PostA) ] .
35

Resumen Para cada una de las operaciones de un TAD T cuya especificacin original en
trminos del modelo abstracto est dada por el par pre/post-condicin PreA/PostA y cuya re-especificacin en trminos del modelo concreto est dada por el par pre/post-condicin
PreC /PostC , la consistencia entre ambas especificaciones debe ser garantizada demostrando
[ ( x : x es parmetro in o in-out de tipo T : x.Ac x.InvA x.InvC )
(PreA PreC ) ]
y
[ ( x : x es parmetro in, out o in-out de tipo T : x.Ac x.InvA x.InvC )
( x : x es parmetro in-out de tipo T : x0 .Ac x0 .InvA x0 .InvC )
PreA0
(PostC PostA) ] ,
siendo Ac la relacin de acoplamiento, InvA el invariante de representacin correspondiente al
modelo abstracto, e InvC el invariante de representacin correspondiente al modelo concreto.
Crear En el caso de esta operacin en nuestro TAD Diccionario de ejemplo, la precondicin
abstracta y la concreta son idnticas. Por lo tanto, ambas son equivalentes, an sin suponer
ninguna de las hiptesis de las que podemos disponer.
El caso de las postcondiciones no es tan directo. Teniendo que d es el nico parmetro de
tipo Diccionario de la operacin, y siendo ste de salida (out), podemos tomar como hiptesis
a d.Ac , d.InvA y d.InvC . Tal como veremos en la demostracin, slo la hiptesis d.Ac y una
parte de d.InvC terminan resultando necesarias para la demostracin, por lo cual listamos a
continuacin slo a tales componentes que necesitaremos:
(Hip0)
(Hip1)
(Hip2)

d.conoc = { i : 0 6 i < d.tam : d.claves[i] }


d.tabla = { i : 0 6 i < d.tam : (d.claves[i], d.valores[i]) }
0 6 d.tam 6 d.MAX
.

Suponiendo entonces las hiptesis sealadas, razonamos de la siguiente forma slo sobre las
porciones de las postcondiciones que no son idnticas sintcticamente:

d.conoc = d.tabla =
h hiptesis (Hip0) e (Hip1) i
{ i : 0 6 i < d.tam : d.claves[i] } =
{ i : 0 6 i < d.tam : (d.claves[i], d.valores[i]) } =


vacuidad de conjuntos definidos por comprensin:
ocurre si y slo si el rango de generacin es vaco
( i :: 0 6 i < d.tam )
h aritmtica i
d.tam 6 0
h por hiptesis (Hip2) se tiene d.tam > 0 i
d.tam = 0 .

Ntese que en este caso hemos logrado demostrar la versin fuerte de la consistencia (segn
refinamiento de datos), ya que las postcondiciones resultaron equivalentes.
36

Note tambin que esta demostracin la habramos podido hacer de manera ms simple. Recuerde que discutimos anteriormente (seccin 2.2) que, gracias a la presencia implcita de invariantes de representacin en las pre/post-condiciones, podamos disponer de varias versiones
equivalentes de tales pre/post-condiciones. En el caso de la postcondicin abstracta de crear , una
de tales versiones equivalentes a la original (de nuevo ignorando la porcin de la postcondicin
referente a d.MAX ) era d.conoc = . Utilizando esta versin, la demostracin anterior habra
sido un poco ms sencilla.
He aqu la razn por la que se seal anteriormente que era positivo el contar con versiones
ms breves y versiones ms extensas y detalladas, pero equivalentes, de alguna especificacin (ver,
por ejemplo, la discusin final en la especificacin de la operacin crear en la seccin 2.2). Las ms
detalladas antes insistimos en utilizarlas en las especificaciones, gracias a que stas, siendo ms
explcitas, son ms claras y, por lo tanto, ayudan ms a la comprensin de la especificacin. Por
otra parte, las ms concisas son ms tiles en las demostraciones de consistencia por refinamiento
de datos, ya que pueden convertirse en consecuentes a demostrar ms sencillos. (Sin embargo, si
tal pre/post-condicin no es el consecuente a demostrar sino una hiptesis, de nuevo sera mejor
utilizar la versin ms detallada y explcita.)
Agregar Para razonar sobre las precondiciones, podemos tomar como hiptesis toda la informacin del nico parmetro d de tipo Diccionario de la operacin, ya que ste es de entrada/salida (in-out); tal informacin es d.Ac , d.InvA y d.InvC . De nuevo, detallamos a continuacin slo las porciones de estas hiptesis que terminaremos utilizando:
(Hip0)
(Hip1)

d.conoc = { i : 0 6 i < d.tam : d.claves[i] }


( i, j : 0 6 i, j 6 d.tam : i 6= j d.claves[i] 6= d.claves[j] )

Razonamos ahora sobre las porciones claves de las precondiciones de la siguiente forma:
c d.conoc

h hiptesis (Hip0) i
c { i : 0 6 i < d.tam : d.claves[i] }

h pertenencia a conjuntos definidos por comprensin i


( i : 0 6 i < d.tam : d.claves[i] = c ) ,
y
# d.conoc < d.MAX

h hiptesis (Hip0) i
# { i : 0 6 i < d.tam : d.claves[i] } < d.MAX
* gracias a hiptesis (Hip1) todos los elementos generados para +
el conjunto son diferentes y, por lo tanto, la cantidad de ellos

es exactamente la cantidad de valores del rango: d.tam


d.tam < d.MAX
.
Discutamos un par de detalles sobre esta demostracin. Primero, el razonamiento sobre la parte
izquierda de las precondiciones optamos por realizarlo sin las negaciones involucradas. Esto es
vlido pues la misma negacin se encontraba a ambos lados y, por propiedades de lgica proposicional, sabemos que es equivalente el razonar cancelando las negaciones a ambos lados, y fue
37

conveniente pues prescindir de las negaciones simplific (aunque slo ligeramente) las frmulas
involucradas en la demostracin. Segundo, en el razonamiento sobre la parte derecha de las precondiciones note lo importante de haber utilizado la hiptesis (Hip1); de no haber contado con
ella, slo habramos podido asegurar la desigualdad
# { i : 0 6 i < d.tam : d.claves[i] } 6 d.tam
debido a la posibilidad de elementos repetidos, en cuyo caso de la ltima equivalencia slo habramos podido asegurar la implicacin mas no la implicacin . Esto nos habra estropeado
la consistencia segn refinamiento de datos deseada, ya que la regla exige que se cumpla la
implicacin desde la precondicin abstracta hacia la concreta.
Para razonar sobre las postcondiciones, sobre nuestro nico parmetro d de tipo Diccionario,
en vista de que ste es de entrada/salida (in-out), podemos tomar como hiptsis a d.Ac , d.InvA
y d.InvC , y tambin a d0 .Ac , d0 .InvA y d0 .InvC . A continuacin las hiptesis que realmente
se utilizarn:
(Hip0)
(Hip1)
(Hip2)

d.tabla = { i : 0 6 i < d.tam : (d.claves[i], d.valores[i]) }


d0 .tabla = { i : 0 6 i < d0 .tam : (d0 .claves[i], d0 .valores[i]) }
0 6 d0 .tam 6 d0 .MAX
.

Por otra parte, para demostrar que la precondicin concreta implica a la abstracta utilizaremos
la tcnica de suponer el antecedente de la implicacin a demostrar y mostraremos que as se
puede concluir el consecuente de sta. Agregamos entonces las hiptesis correspondientes a la
postcondicin concreta:
(Hip3)
(Hip4)
(Hip5)

d.tam = d0 .tam + 1
d.claves = d0 .claves (d0 .tam : c)
d.valores = d0 .valores (d0 .tam : v)

Finalmente, esta vez s utilizaremos una de nuestras postcondiciones abreviadas. Como postcondicin concreta utilizaremos la versin reducida que slo se refiere al atributo tabla y no al atributo
conoc (ver comentarios luego de la especificacin de agregar en la seccin 2.2). El consecuente a
demostrar es entonces
(Cons)

d.tabla = d0 .tabla { (c, v) }

Probamos (Cons) partiendo de su lado izquierdo hasta llegar a su lado derecho, razonando como

38

sigue:

=
=

d.tabla
h hiptesis (Hip0) i
{ i : 0 6 i < d.tam : (d.claves[i], d.valores[i]) }
h hiptesis (Hip3) i
{ i : 0 6 i < d0 .tam + 1 : (d.claves[i], d.valores[i]) }


separacin de trmino, gracias a que d0 .tam > 0 por hiptesis (Hip2)
(de lo contrario el rango sera vaco y no habra trmino a separar)
{ i : 0 6 i < d0 .tam : (d.claves[i], d.valores[i]) } { (d.claves[d0 .tam], d.valores[d0 .tam]) }
* gracias a hiptesis (Hip4), tenemos que
+
d.claves[i] = d0 .claves[i] para todo i tal que 0 6 i < d0 .tam ,
y tambin tenemos que d.claves[d0 .tam] = c
{ i : 0 6 i < d0 .tam : (d0 .claves[i], d.valores[i]) } { (c, d.valores[d0 .tam]) }
* de manera similar, gracias a hiptesis (Hip5), tenemos que
+
d.valores[i] = d0 .valores[i] para todo i tal que 0 6 i < d0 .tam ,
y tambin tenemos que d.valores[d0 .tam] = v
{ i : 0 6 i < d0 .tam : (d0 .valores[i], d0 .valores[i]) } { (c, v) }
h hiptesis (Hip1) i
d0 .tabla { (c, v) } .

Listo.
Dejamos como ejercicio (ver ejercicio 6.4-a) el responder a la siguiente pregunta: qu habra
pasado si hubisemos tratado de demostrar que la postcondicin abstracta tambin implica a la
concreta?
Eliminar, buscar y determinar existencia Dejaremos como ejercicio demostrar la consistencia bajo refinamiento de datos del resto de las operaciones de nuestro TAD Diccionario. Sin
embargo, haremos una ltima demostracin correspondiente a la consistencia de las postcondiciones de eliminar , que es la demostracin ms compleja de lo que resta. Sobre el nico parmetro d
de tipo Diccionario de la operacin, podemos tomar como hiptsis a d.Ac , d.InvA y d.InvC ,
de las cuales nicamente terminaremos utilizando a sus componentes
(Hip0)
(Hip1)

d.tabla = { i : 0 6 i < d.tam : (d.claves[i], d.valores[i]) }


0 6 d.tam 6 d.MAX
,

y tambin podemos tomar como hiptesis, por ser d parmetro de entrada/salida (in-out), a
d0 .Ac , d0 .InvA y d0 .InvC , de las cuales utilizaremos a
(Hip2)
(Hip3)

d0 .tabla = { i : 0 6 i < d0 .tam : (d0 .claves[i], d0 .valores[i]) }


( i, j : 0 6 i, j < d0 .tam : i 6= j d0 .claves[i] 6= d0 .claves[j] )

Por ltimo, para concluir bajo estas hiptesis que la postcondicin concreta implica a la postcondicin abstracta, agregaremos a la primera a nuestras hiptesis para luego proceder a demostrar

39

la segunda. Suponemos entonces tambin a


(Hip4)
(Hip5)

d.tam = d0 .tam 1
( i : 0 6 i < d0 .tam : d0 .claves[i] = c
d.claves = d0 .claves (i : d0 .claves[ d0 .tam 1 ])
d.valores = d0 .valores (i : d0 .valores[ d0 .tam 1 ])

y nuestro consecuente a demostrar ser


(Cons)

d.tabla = d0 .tabla { (c, d0 .tabla c) }

Ahora bien, antes de proceder con (Cons), extraigamos la informacin de (Hip5) tomando un
testigo para el existencial (ver metateorema de testigo para existenciales como hiptesis en, por
ejemplo, [GS94, seccin . . . ?]) de manera tal de poder disponer de tal informacin directamente
y usemos entonces las hiptesis
(Hip6)
(Hip7)
(Hip8)
(Hip9)

0 6 < d0 .tam
d0 .claves[ ] = c
d.claves = d0 .claves ( : d0 .claves[ d0 .tam 1 ])
d.valores = d0 .valores ( : d0 .valores[ d0 .tam 1 ])

Iniciemos ahora la demostracin de (Cons) intentando hacer lo mismo que hicimos en el caso de
las postcondiciones de agregar , esto es, partiendo del lado izquierdo y buscando re-expresar toda
la informacin de d en trminos de d0 hasta llegar al lado derecho:
d.tabla
=
h hiptesis (Hip0) i
{ i : 0 6 i < d.tam : (d.claves[i], d.valores[i]) }
* necesitamos re-expresar los atributos de d en trminos de atributos de d : +
0
slo podemos hacerlo fcilmente para el atributo tam utilizando (Hip4),
=
mientras para el resto de los atributos requeriremos un anlisis por casos
{ i : 0 6 i < d0 .tam 1 : (d.claves[i], d.valores[i]) } .
(i)
Para continuar la transformacin de expresiones sobre d en expresiones sobre d0 , podemos (debemos) aplicar las hiptesis (Hip8) e (Hip9) sobre los atributos arreglos claves y valores. Pero luego
de hacer esto no podremos simplificar las expresiones resultantes salvo que logremos distinguir
cundo la indexacin de los arreglos de d por medio de i coincide o no con el ndice de modificacin utilizado en (Hip8) e (Hip9). Tal necesidad de distincin de ndices puede ser resuelta
separando el trmino del resto de los elementos, pero esto tiene un problema: no necesariamente
se encuentra en el rango 0 6 i < d0 .tam 1 utilizado en (i).
La hiptesis (Hip6) determina los posibles valores de y muestra que no necesariamente se
encuentra en el rango de (i). Sin embargo, (Hip6) tambin nos muestra que la pertenencia de
a tal rango slo depende de su igualdad o no con el valor d0 .tam 1 . Continuemos entonces
nuestro razonamiento separando estos dos casos, empezando por el caso en que podremos extraer
del rango en cuestin debido a su pertenencia a ste.

40

Caso 6= d0 .tam 1 :
(i)



separacin de trmino, pues (Hip6) y la hiptesis sobre de este caso
=
garantizan la pertenencia de al rango de generacin del conjunto
{ i : 0 6 i < d0 .tam 1 i 6= : (d.claves[i], d.valores[i]) }
{ (d.claves[ ], d.valores[ ]) }


hiptesis (Hip8) e (Hip9) nos permiten ahora re-expresar a
=
d.claves y d.valores en trminos de d0 .claves y d0 .valores
{ i : 0 6 i < d0 .tam 1 i 6= : (d0 .claves[i], d0 .valores[i]) }
{ (d0 .claves[ d0 .tam 1 ], d0 .valores[ d0 .tam 1 ]) }
* separacin de trmino (en sentido contrario: agregacin de trmino), pues +
las hiptesis (Hip1) e (Hip4) ms la hiptesis sobre de este caso garantizan
=
que i := d0 .tam 1 pertenece al rango resultante del cual se separa/agrega
{ i : 0 6 i < d0 .tam i 6= : (d0 .claves[i], d0 .valores[i]) } ,
y en este punto pareciera que no podemos hacer ninguna otra simplificacin o manipulacin
razonable, por lo que nos detenemos ac y analizamos el otro caso con la esperanza de llegar a
la misma expresin (para as cerrar el anlisis separado de casos).
Caso = d0 .tam 1 :
(i)
=
h re-expresin del rango, gracias a la hiptesis sobre de este caso i
{ i : 0 6 i < d0 .tam i 6= : (d.claves[i], d.valores[i]) }


hiptesis (Hip8) e (Hip9) nos permiten de nuevo re-expresar
=
a d.claves y d.valores en trminos de d0 .claves y d0 .valores
{ i : 0 6 i < d0 .tam i 6= : (d0 .claves[i], d0 .valores[i]) } ,
con lo cual hemos exitosamente alcanzado nuestro objetivo de llegar a una conclusin comn en
los dos casos analizados.
Nuestra conclusin comn, producto de la manipulacin inicial que condujo a (i) y de los dos
ltimos razonamientos, es entonces
d.tabla = { i : 0 6 i < d0 .tam i 6= : (d0 .claves[i], d0 .valores[i]) }

(ii)

y, tal como se mencion antes, pareciera no haber otra simplificacin o manipulacin razonable
que hacer a este expresin, por lo que nos detenemos en este punto de la manipulacin del lado
izquierdo de (Cons) y nos dedicamos ahora a su lado derecho con el objetivo de llegar al mismo
resultado (y as completar la demostracin).

41

Para manipular el lado derecho de (Cons), empezamos slo con una parte de ste:
d0 .tabla
=
h hiptesis (Hip2) i
{ i : 0 6 i < d0 .tam : (d0 .claves[i], d0 .valores[i]) }


separacin de trmino, gracias a que (Hip6) garantiza
=
que se encuentra en el rango de generacin del conjunto
{ i : 0 6 i < d0 .tam i 6= : (d0 .claves[i], d0 .valores[i]) }
{ (d0 .claves[ ], d0 .valores[ ]) }


por hiptesis (Hip7) tenemos, primero, que d0 .claves[ ] = c y, luego,
=
combinada con (Hip2), tambin tenemos que d0 .valores[ ] = d0 .tabla c
{ i : 0 6 i < d0 .tam i 6= : (d0 .claves[i], d0 .valores[i]) } { (c, d0 .tabla c) }

Con esta conclusin parcial, manipulamos ahora el lado derecho completo de (Cons) y lo mostramos igual al lado izquierdo de (Cons) como sigue:
d0 .tabla { (c, d0 .tabla c) }
* por el clculo anterior y las siguientes propiedades de conjuntos: para +
X, Y y Z cualesquiera tenemos (X Y ) Z = (X Z) (Y Z)
=
y, por lo tanto, tambin tenemos (X Y ) Y = X Y
{ i : 0 6 i < d0 .tam i 6= : (d0 .claves[i], d0 .valores[i]) } { (c, d0 .tabla c) }


por hiptesis (Hip6) e (Hip7) combinadas con (Hip3), en el primer
=
conjunto no puede haber un par con c como primera componente
{ i : 0 6 i < d0 .tam i 6= : (d0 .claves[i], d0 .valores[i]) }
=
h por (ii) i
d.tabla .
Listo!

6.2.

Otros ejemplos de consistencia

Bajo las reglas vistas en esta seccin, es posible mostrar que nuestras re-especificaciones para
implementacin de los TADs Cola y Conjunto presentadas en la seccin 5 son consistentes con
las especificaciones originales presentadas en la seccin 3. Buena parte de la demostracin de
consistencia para estos dos ejemplos es mostrada en el apndice A.

6.3.

Re-especificacin implcita de operaciones

hh OJO, seccin slo en borrador. . . ii


Explicar de nuevo a qu se refiere esto. . .
Simple sustitucin gracias a igualdad hh OJO, seccin slo en borrador. . . ii Explicar
que relaciones de acoplamiento que definen a los atributos abstractos mediante igualdades, esto
es, funcionales, se usan para re-especificar simplemente por sustitucin. . .

42

Dar un ejemplo. . . Para operacin de agregar , precondicin. . .


c 6 { i : 0 6 i < d.tam : d.claves[i] } # { i : 0 6 i < d.tam : d.claves[i] } < d.MAX
y postcondicin (versin breve). . .
{ i : 0 6 i < d.tam : (d.claves[i], d.valores[i]) } =
{ i : 0 6 i < d0 .tam : (d0 .claves[i], d0 .valores[i]) } { (c, v) }
Notar que con frecuencia en las demostraciones esto corresponde al primer paso; esto ocurri
con la precondicin de agregar . . . Tambin, por ejemplo, con la postcondicin de crear en la
demostracin correspondiente. . .
d.MAX = m
{ i : 0 6 i < d.tam : d.claves[i] } =
{ i : 0 6 i < d.tam : (d.claves[i], d.valores[i]) } =
Notar que otras relaciones de acoplamiento podran complicar la cosa. . . Por ejemplo, en Cola
s se tienen igualdades que definen lo abstracto, pero hay que involucrar permanentemente al
anlisis de casos. . . En otros casos la relacin de acoplamiento podra ser no-funcional, lo cual
elimina la posibilidad de esta sencilla sustitucin; en nuestros ejemplos, esto nunca ocurrir, y en
la prctica es muy poco comn. . .
Justificacin general de re-especificacin implcita por sustitucin hh OJO, seccin
slo en borrador. . . ii En esta seccin se demuestra por qu la sustitucin recin explicada
siempre funciona bien. . . La lectura de esta seccin no es imprescindible; vale la pena principalmente para quienes gustan de razonamientos y manipulaciones lgicas, o de quienes quieran
entender por qu la sustitucin arriba propuesta cumple con las reglas de consistencia. . .
Explicar mtodo. . . A partir de las reglas se despejar a la pre/post-condicin concreta
deseada, primero separndola del resto y luego eliminando los atributos abstractos de las variables
libres de la frmula correspondiente. . . Esto se har simplificando, con un solo parmetro de
entrada para la precondicin y con un solo parmetro de salida para la postcondicin. . . Adems,
se elimina la precondicin de las hiptesis de la regla de postcondiciones. . .

43

Para precondicin. . .

[ x.Ac x.InvA x.InvC (PreA PreC ) ]


h regla probada de invariantes i
[ x.Ac x.InvC (PreA PreC ) ]
h lgica proposicional, para despejar PreC ) i
[ x.Ac x.InvC PreA PreC ]
h lgica proposicional, para agrupar atributos abstractos i
[ x.InvC (x.Ac PreA) PreC ]
h cuantificacin universal explcita i
( x.a , x.c , w :: x.InvC (x.Ac PreA) PreC )
h regla de cuantificaciones i
( x.c , w :: ( x.a :: x.InvC (x.Ac PreA) ) PreC )
h reglas de cuantificaciones i
( x.c , w :: x.InvC ( x.a : x.Ac : PreA ) PreC )
h re-introduccin de cuantificacin universal implcita i
[ x.InvC ( x.a : x.Ac : PreA ) PreC ] .

y para postcondicin. . .

[ x.Ac x.InvA x.InvC PreA0 (PostC PostA) ]


h por lgica proposicional, para simplificar las hiptesis eliminando la precondicin i
[ x.Ac x.InvA x.InvC (PostC PostA) ]
h regla probada de invariantes i
[ x.Ac x.InvC (PostC PostA) ]
h lgica proposicional, para despejar PostC i
[ PostC (x.Ac x.InvC PostA) ]
h lgica proposicional, para agrupar atributos abstractos i
[ PostC (x.InvC (x.Ac PostA)) ]
h cuantificacin universal explcita i
( x.a , x.c , w :: PostC (x.InvC (x.Ac PostA)) )
h regla de cuantificaciones i
( x.c , w :: PostC ( x.a :: x.InvC (x.Ac PostA) ) )
h reglas de cuantificaciones i
( x.c , w :: PostC (x.InvC ( x.a : x.Ac : PostA )) )
h re-introduccin de cuantificacin universal implcita i
[ PostC (x.InvC ( x.a : x.Ac : PostA )) ] .

Los despejes sugieren tomar para PreC a. . .


x.InvC ( x.a : x.Ac : PreA )
y para PostC a. . .
x.InvC ( x.a : x.Ac : PostA )
44

Y, como en las pre/post-condiciones se supone implcitamente al invariante de representacin, al


reemplazar a InvC por true y simplificar, tenemos que los despejes terminan sugiriendo tomar
como par pre/post-condicin PreC /PostC a. . .
( x.a : x.Ac : PreA )
y. . .
( x.a : x.Ac : PostA )
Esto justifica las sustituciones antes utilizadas. . . Si el acoplamiento define lo abstracto con
igualdades, por ejemplo, en nuestro anlisis simplificado habra alguna funcin f tal que. . .
a = fc
Aplicado a nuestro parmetro x de arriba, es. . .
x.a = f x.c
y aplicando entonces regla de un punto a las cuantificaciones, terminamos con la siguiente sugerencia para PreC /PostC , calculada por simple sustitucin sobre PreA/PostA, que automticamente
cumple con las reglas de consistencia por construccin. . .
PreA [ x.a := f x.c ]
y. . .
PostA [ x.a := f x.c ]

6.4.

Ejercicios

6.4-a. . . . buscar contraejemplo para la implicacin de la postcondicin abstracta hacia la concreta de agregar . . .
6.4-b. . . . completar el resto de las demostraciones de consistencia. . .
6.4-c. . . . ?

Un buen ejemplo (clsico) final: un TAD Grafo

7.
...

8.

Ms ejemplos de TADs (un par no-clsicos)

8.1.

Un TAD RegistroEstudiantil

. . . tomarlo del examen viejo en que lo us. . .

45

Un TAD ConexionYTarifas

8.2.

. . . tomar el ejemplo de la empresa Llvatelo de uno de los exmenes viejos. . .

8.3.

Ejercicios

8.3-a. . . . cambiar modelo abstracto de representacin del TAD RegistroEstudiantil . . .


8.3-b. . . . cambiar modelo concreto de representacin del TAD RegistroEstudiantil . . .
8.3-c. . . . inventar otro TAD similar a RegistroEstudiantil y pedir especificacin de ste. . .
8.3-d. . . . inventar cambios similares para el ejemplo de Llvatelo. . .

Referencias
[CLRS09] T.H. Cormen, C.E. Leiserson, R.L. Rivest, and C. Stein. Introduction to Algorithms.
MIT Press, 3rd edition, 2009.
[DS90]

E.W. Dijkstra and C.S. Scholten. Predicate Calculus and Program Semantics. Texts
and Monographs in Computer Science. Springer-Verlag, 1990.

[GS94]

D. Gries and F.B. Schneider. A Logical Approach to Discrete Math. Texts and Monographs in Computer Science. Springer-Verlag, 1994.

[Kal90]

A. Kaldewaij. Programming: The Derivation of Algorithms. International Series in


Computer Science. Prentice Hall, 1990.

[Lis01]

B. Liskov with J. Guttag. Program Development in Java Abstraction, Specification,


and Object-Oriented Design. Addison-Wesley, 2001.

[Mez00]

O. Meza. Introduccin a la programacin. Departamento de Computacin y Tecnologa


de la Informacin, Universidad Simn Bolvar, disponible va www.ldc.usb.ve/meza/,
2000.

[Mit92]

R. Mitchell. Abstract Data Types and Modula-2 A worked example of design using
data abstraction. Prentice Hall, 1992.

[Mor94]

C.C. Morgan. Programming from Specifications. International Series in Computer


Science. Prentice Hall, 2nd edition, 1994.

A.

Otros ejemplos de consistencia

hh OJO, seccin slo en borrador. . . ii


En esta seccin mostramos parte de la consistencia de los otros ejemplos que se han venido
desarrollando. . .

46

A.0.

Consistencia de la implementacin del TAD Cola

hh OJO, seccin slo en borrador. . . ii


Regla de invariantes. . . Suponer hiptesis. . .
(Hip0)
(Hip1)
(Hip2)
(Hip3)
(Hip4)

inic < fin nada contenido = h i : inic fin : elems[i] i


inic > fin nada
contenido = h i : inic MAX : elems[i] i ++ h i : 0 fin : elems[i] i
MAX > 0
0 6 inic, fin < MAX
nada inic = fin ,

y demostrar consecuentes. . .
(Cons0)
(Cons1)

MAX > 0
# contenido 6 MAX

Propiedad de secuencias que ser usada repetidamente. . .


#hx : a b : E i = b a

si a 6 b

La parte interesante es (Cons1). . . Acoplamiento pide anlisis por casos. . . Primer caso, suponemos
inic < fin nada . . .

<
6

# contenido
h suposicin de primer caso e (Hip0) i
# h i : inic fin : elems[i] i


propiedad de secuencias antes enunciada,
condicin requerida inic 6 fin demostrada luego
fin inic
h por (Hip3) tenemos fin < MAX i
MAX inic
h por (Hip3) tenemos inic 6 0 i
MAX

lo cual demuestra # contenido < MAX , lo cual implica # contenido 6 MAX en este primer
caso. . . La condicin que se ofreci demostrar falta. . .
inic 6 fin

h relaciones aritmticas i
inic < fin inic = fin

h hiptesis (Hip4) i
inic < fin nada

h hiptesis de primer caso i


true
47

Segundo caso, suponemos inic > fin nada . . .

=
=

6
=

# contenido
h suposicin de segundo caso e (Hip1) i
# ( h i : inic MAX : elems[i] i ++ h i : 0 fin : elems[i] i )
h propiedad de secuencias i
# h i : inic MAX : elems[i] i + # h i : 0 fin : elems[i] i


propiedad de secuencias antes enunciada, condiciones
requeridas inic 6 MAX y 0 6 fin se tienen por (Hip3)
MAX inic + fin
h por hiptesis de segundo caso tenemos fin 6 inic i
MAX inic + inic
h aritmtica i
MAX

lo cual demuestra # contenido 6 MAX tambin en el segundo caso. . .


Vemos slo operacin encolar . . .
Precondicin de encolar . . . Suponemos hiptesis c.Ac, c.InvA y c.InvC . . . Listamos slo las
que se usarn. . .
(Hip0)

(Hip1)

c.inic > c.fin c.nada


c.contenido = h i : c.inic c.MAX : c.elems[i] i ++
h i : 0 c.fin : c.elems[i] i
0 6 c.inic, c.fin < c.MAX
,

Se debe demostrar. . .
# c.contenido < c.MAX c.inic 6= c.fin c.nada
Para habilitar el uso de los casos de la relacin de acoplamiento, es mejor intentar demostrar el
contrarrecproco. . .
c.inic = c.fin c.nada # c.contenido > c.MAX
Suponemos entonces nueva hiptesis. . .
(Hip2)
(Hip3)

c.inic = c.fin
c.nada

y demostramos consecuente. . .
(Cons)

# c.contenido > c.MAX

Notar que este consecuente es, gracias a hiptesis del invariante abstracto, no listada antes explcitamente, equivalente a igualdad. . . De hecho, se demostrar igualdad, pero como sta implica a

48

lo indicado en (Cons) no usamos la hiptesis nombrada, por innecesaria. . . Demostramos. . .

=
=

# c.contenido
h por (Hip0), (Hip2) e (Hip3) i
# ( h i : c.inic c.MAX : c.elems[i] i ++ h i : 0 c.fin : c.elems[i] i )
h propiedad de secuencias i
# h i : c.inic c.MAX : c.elems[i] i + # h i : 0 c.fin : c.elems[i] i


propiedad de secuencias antes enunciada, condiciones
requeridas c.inic 6 c.MAX y 0 6 c.fin se tienen por (Hip1)
c.MAX c.inic + c.fin
h por (Hip2) y aritmtica i
c.MAX

Qued demostrado (Cons). . .


Postcondicin de encolar . . . Suponemos de nuevo hiptesis c.Ac, c.InvA y c.InvC , pero tambin c0 .Ac, c0 .InvA y c0 .InvC , y adems PreA0 . . . Notar que por lo demostrado para precondiciones tambin podemos entonces contar con hiptesis PreC 0 . . . Listamos slo lo que se terminar
utilizando. . . De la informacin de c tenemos. . .
(Hip0)

c.inic < c.fin c.nada


c.contenido = h i : c.inic c.fin : c.elems[i] i

(Hip1)

c.inic > c.fin c.nada


c.contenido = h i : c.inic c.MAX : c.elems[i] i ++
h i : 0 c.fin : c.elems[i] i
0 6 c.inic, c.fin < c.MAX

(Hip2)

De c0 utilizaremos lo mismo, ms la parte final del invariante de representacin concreto. . .


(Hip3)

c0 .inic < c0 .fin c0 .nada


c0 .contenido = h i : c0 .inic c0 .fin : c0 .elems[i] i

(Hip4)

c0 .inic > c0 .fin c0 .nada


c0 .contenido = h i : c0 .inic c0 .MAX : c0 .elems[i] i +
+
h i : 0 c0 .fin : c0 .elems[i] i
0 6 c0 .inic, c0 .fin < c0 .MAX
c0 .nada c0 .inic = c0 .fin

(Hip5)
(Hip6)

Ntese que c0 .MAX es siempre trivialmente igual a c.MAX por tratarse de un atributo constante. . . De la hiptesis PreA0 , como referido antes, gracias a la informacin sobre c0 y la consistencia
ya demostrada entre postcondiciones, obtenemos tambin a PreC 0 , que listamos entonces ahora
como hiptesis. . .
(Hip7)

c0 .inic 6= c0 .fin c0 .nada

Por ltimo, suponemos PostC para luego demostrar PostA. . . Esto nos da nuestras ltimas hip-

49

tesis. . .
(Hip8)
(Hip9)
(Hip10)
(Hip11)

c.inic = c0 .inic
c.fin = (c0 .fin + 1) mod c.MAX
c.elems = c0 .elems (c0 .fin : x)
c.nada

Debemos entonces demostrar el consecuente. . .


(Cons)

c.contenido = c0 .contenido ++ hxi

Trabajar con este consecuente exige distinguir los casos correspondientes a (Hip0) vs. (Hip1) para
estudiar a c.contenido , y en cada uno de estos casos distinguir las posibilidades correspondientes
a (Hip3) vs. (Hip4) de c0 .contenido . . . Cuando se est haciendo tal anlisis de casos, la aritmtica
modular de (Hip9) se estudiar tambin por casos. . . La hiptesis (Hip5) da una cota superior
para c0 .fin que permite separar los casos correspondientes a (Hip9) como sigue (recordar que
c.MAX y c0 .MAX coinciden). . .
(Hip12)
(Hip13)

c0 .fin < c.MAX 1 c.fin = c0 .fin + 1


c0 .fin = c.MAX 1 c.fin = 0

Empezamos finalmente a demostrar (Cons). . . Para manipular a c.contenido , debemos distinguir los casos dados por (Hip0) e (Hip1). . . Gracias a (Hip11), tenemos que c.nada es falso, por
lo que los dos casos se basan slo en la relacin entre c.inic y c.fin . . .
Vamos con caso (A): c.inic < c.fin . . . En este caso (al igual que en los siguientes casos que
vendrn), debemos analizar las posibilidades para c0 .contenido segn (Hip3) e (Hip4), y analizar las posibilidades para c.fin segn (Hip12) e (Hip13). . . Empezamos mostrando que en este
caso (A) no puede ocurrir el caso correspondiente a (Hip13). . .
c.inic < c.fin c0 .fin = c.MAX 1

h por (Hip13) i
c.inic < c.fin c.fin = 0

h Leibniz i
c.inic < 0

h por (Hip2) i
false
Por lo tanto. . .
c.inic < c.fin

h por reduccin al absurdo del clculo anterior i


c0 .fin 6= c.MAX 1

h por (Hip5) y ser MAX atributo constante i


c0 .fin < c.MAX 1

50

(i)

Vemos entonces que c.fin slo puede estar definido en este caso (A) segn lo estipulado en
(Hip12). . . En cuanto a los posibles casos segn (Hip3) y (Hip4), tenemos. . .

c.inic < c.fin


h por (Hip8), y por (Hip12) con (i) i
c0 .inic < c0 .fin + 1
h relaciones aritmticas i
c0 .inic 6 c0 .fin
h por (Hip7) i
c0 .inic 6 c0 .fin (c0 .inic 6= c0 .fin c0 .nada)
h distributividad de conjuncin sobre disyuncin i
(c0 .inic 6 c0 .fin c0 .inic 6= c0 .fin) (c0 .inic 6 c0 .fin c0 .nada)
h relaciones aritmticas, lgica proposicional i
c0 .inic < c0 .fin c0 .nada

(ii)

(iii)

Esto ltimo, (iii), determina el caso para c0 . . . Las tres consecuencias (i), (ii) y (iii) de la condicin
del caso (A) han sido marcadas para posterior uso. . . Finalizamos la demostracin de (Cons) en
este caso (A). . .

=
=
=
=
=

c.contenido
h por (Hip0) con hiptesis de caso (A) i
h i : c.inic c.fin : c.elems[i] i
h por (Hip8), y por (Hip12) con (i) i
h i : c0 .inic c0 .fin + 1 : c.elems[i] i
h separacin de trmino, gracias a que (ii) garantiza que el rango no es vaco i
h i : c0 .inic c0 .fin : c.elems[i] i ++ h c.elems[c0 .fin] i
h por (Hip10) podemos re-expresar a c.elems en trminos de c0 .elems i
h i : c0 .inic c0 .fin : c0 .elems[i] i ++ hxi
h por (Hip3) con (iii) i
c0 .contenido ++ h x i

Vamos ahora con caso (B): c.inic > c.fin . . . De nuevo debemos analizar las posibilidades para
c0 .contenido segn (Hip3) e (Hip4), y tambin las posibilidades para c.fin segn (Hip12) e
(Hip13). . . Atacamos primero lo ltimo, ya que esto determina lo primero. . .
Vamos entonces con sub-caso (B.0): c0 .fin < c.MAX 1 . . . Discernimos ahora en qu caso

51

estamos para c0 .contenido . . .

c.inic > c.fin


h por (Hip8), y por (Hip12) con hiptesis de caso (B.0) i
c0 .inic > c0 .fin + 1
h relaciones aritmticas i
c0 .inic > c0 .fin
h relaciones aritmticas i
c0 .inic > c0 .fin c0 .inic 6= c0 .fin
h por contrarrecproco de (Hip6) i
c0 .inic > c0 .fin c0 .nada

(iv)

(v)

Esto determina el caso para c0 . . . Por lo tanto. . .

=
=
=

c.contenido
h por (Hip1) con hiptesis de caso (B) i
h i : c.inic c.MAX : c.elems[i] i ++ h i : 0 c.fin : c.elems[i] i
h por (Hip8), y por (Hip12) con hiptesis de caso (B.0) i
h i : c0 .inic c.MAX : c.elems[i] i ++ h i : 0 c0 .fin + 1 : c.elems[i] i
h separacin de trmino, rango no-vaco gracias a 0 6 c0 .fin de (Hip5) i
h i : c0 .inic c.MAX : c.elems[i] i ++ h i : 0 c0 .fin : c.elems[i] i ++ h c.elems[c0 .fin] i


por (Hip10) podemos re-expresar a c.elems en trminos de c0 .elems ,
gracias a (iv) se tiene que c0 .fin no ocurre en el primer rango
h i : c0 .inic c.MAX : c0 .elems[i] i ++ h i : 0 c0 .fin : c0 .elems[i] i ++ hxi
h por (Hip4) con (v), recordar que MAX es atributo constante i
c0 .contenido ++ h x i

Finalizamos con sub-caso (B.1): c0 .fin = c.MAX 1 . . . De nuevo, lo primero ser discernir
qu caso define a c0 .contenido . . .
c0 .fin = c.MAX 1


por (Hip5) se tiene que c0 .inic 6 c0 .MAX 1 ,

recordar que MAX es atributo constante, Leibniz


c0 .inic 6 c0 .fin

h por el mismo clculo entre (ii) y (iii) del caso (A) i


c0 .inic < c0 .fin c0 .nada

52

(vi)
(vii)

Esto determina el caso para c0 y por tanto. . .

=
=
=
=
=
=

c.contenido
h por (Hip1) e hiptesis de caso (B) i
h i : c.inic c.MAX : c.elems[i] i ++ h i : 0 c.fin : c.elems[i] i
h por (Hip8), y por (Hip13) con hipetsis de caso (B.1) i
h i : c0 .inic c.MAX : c.elems[i] i ++ h i : 0 0 : c.elems[i] i
h por hiptesis de caso (B.1) y concatenacin con secuencia vaca i
h i : c0 .inic c0 .fin + 1 : c.elems[i] i
h separacin de trmino, gracias a que (vi) garantiza que el rango no es vaco i
h i : c0 .inic c0 .fin : c.elems[i] i ++ h c.elems[c0 .fin] i
h por (Hip10) podemos re-expresar a c.elems en trminos de c0 .elems i
h i : c0 .inic c0 .fin : c0 .elems[i] i ++ hxi
h por (Hip3) con (vii) i
c0 .contenido ++ h x i

Resto de la consistencia queda como ejercicio. . .

A.1.

Consistencia de la implementacin del TAD Conjunto

hh OJO, seccin slo en borrador. . . ii


En lugar de demostrar toda la consistencia segn todas las reglas vistas, demostramos un
par de lemas que luego ayudaran a demostrar todo lo dems. . . Esto ilustra las bondades de
seleccionar un par de buenos lemas que puedan ser re-utilizados con frecuencia. . .
Para un objeto x cualquiera de tipo Conjunto tomamos las hiptesis x.Ac , x.InvA e x.InvC y
demostramos los siguientes lemas, que relacionan expresiones sobre atributos del modelo abstracto
con expresiones sobre atributos del modelo concreto. . .
(Lema0)
(Lema1)

# x.contenido = x.tam
y x.contenido ( i : 0 6 i < x.tam : x.elems[i] = y )

Para las demostraciones, de todas las hiptesis listamos ahora slo lo que terminaremos usando
explcitamente. . .
(Hip0)
(Hip1)

x.contenido = { i : 0 6 i < x.tam : x.elems[i] }


( i, j : 0 6 i, j < x.tam : i 6= j x.elems[i] =
6 x.elems[j] )

Procedemos ahora a demostrar los lemas. . . Empezamos con (Lema0). . .


# x.contenido
=
h hiptesis (Hip0) i
# { i : 0 6 i < x.tam : x.elems[i] }
* hiptesis (Hip1) garantiza que todos los elementos generados +
para el conjunto son diferentes y, por lo tanto, la cantidad de
=
ellos es exactamente igual a la cantidad de valores del rango
x.tam
53

Continuamos con (Lema1). . .


y x.contenido

h hiptesis (Hip0) i
y { i : 0 6 i < x.tam : x.elems[i] }

h pertenencia a conjuntos definidos por comprensin i


( i : 0 6 i < x.tam : x.elems[i] = y ) ,
Listos los lemas. . .
Dar algunos ejemplos de cmo los lemas ayudan. . . Para precondicin de agregar , ambos lemas
con x, y := c, x ; para postcondiciones de extraer y pertenece, (Lema1) con x, y := c, x ; para
precondiciones de unir , intersectar y restar , (Lema0) con x := c0 y x := c1 . . . Incluso, para
postcondiciones de crear y vacio, y tambin para precondicin de extraer , (Lema0) con x := c
ms la equivalencia de teora de conjuntos entre A = y #A = 0 para cualquier conjunto A. . .
Resto de la consistencia queda como ejercicio. . .

J.N. Ravelo / Diciembre 2011 (corregido y aumentado de versiones anteriores de febrero 2009 y febrero 2010)

54

Das könnte Ihnen auch gefallen