INDUCCION ESTRUCTURAL

P => Q
Probar que esto vale, no prueba que valga P ni que valga Q
(paratodo x) P(x)
Puedo olvidarme del cuantificador siempre que no suponga nada en particular sobre x
¿Cuándo es correcto y cuando incorrecto mover o intercambiar cuantificadores?
EXPLICAR
¿qué es el principio de inducción?
¿para que sirve?
¿Cómo se usa?
¿Qué son HI y TI?
¿por qué funciona?
Para asegurarnos de cubrir todas las instancias nos aprovechamos del mismo mecanismo
que permite generar esas instancias
El esquema de la demostración:
Uno o más casos base y/o uno o más pasos inductivos. Cada PI con su hipótesis inductiva
y su tesis inductiva.
¿Cuántos CB podríamos necesitar? ¿Cuántos PI? Depende únicamente de los generadores
¿Qué pinta tiene el universo de todos los términos?
¿Qué pinta tiene el esquema de inducción estructural?
No se relacionan con la propiedad a demostrar, sí con los generadores del TAD.
Generadores del TAD – Esquema de demostración – Universo de instancias posibles.
(paratodo s: secu P(s)) => (paratodo s: secu, paratodo a:alfa) P(a·S)
Acá la HI está afirmando lo que que queremos probar.
Cada paso inductivo ya es de por sí una implicación HI => TI
Plantear la propiedad como predicado unario. El predicado unario es lo que vamos a
demostrar que vale. Para plantearlo, tenemos que quitar el cuantificador que liga a la
variable sobre la que vamos a hacer inducción.
Ejemplo:
(paratodo s: secu) (long(duplicar(s)) = 2*long(s))
P(s) = [long(duplicar(s)) = 2*long(s)]
Luego (paratodo s:secu) P(s) es equivalente a lo que queremos demostrar.
El esquema de inducción consiste en los casos base y los pasos inductivos que vamos a
tener que probar. Este esquema es propio del tipo ya que se deriva de su conjunto de
generadores; los casos base se plantean sobre los generadores básicos y los pasos
inductivos sobre los recursivos. Para cualquier propiedad que se quiera probar sobre un
TAD dado, el esquema de inducción es siempre el mismo:
(paratodo s: secu P(s)) => (paratodo a:alfa) P(a·S)

bajo el paradigma funcional. .P(s) es la HI y P(a·S) es la TI La idea es ir viendo qué axiomas podemos ir aplicando para ir reduciendo la expresión que tenemos.if !p then q else r = if p then r else q .a. Cuando necesito poder determinar datos “históricos” incluir la operación como otra operación podría no respetar la congruencia. Una forma de resolverlo es agregando como observador básico una función que “lleve la cuenta de la historia” TADs EN VARIOS NIVELES Cuando definimos TADs que usan otros TADs internamente. P=>Q es lo mismo que !P oo Q. lo explicamos usando TADs. es trivialmente verdadero.d: ab(alfa)) (P(i) yy P(d) => (paratodo a:alfa) P(bin(i. En el paso inductivo asumimos que la HI es verdadera. Hay que tener cuidado de que todos los pasos de la deducción hayan sido sii ya que formalmente la deducción logica es la que resulta de leer las expresiones desde abajo hacia arriba. para el paso intuctivo la hipótesis inductiva será: (paratodo i. la implicación es trivialmente verdadera. Para hacer que el TAD sea lo más simple y consiso posible expresando todo lo que debe expresar.if p then q else q fi = q -función (if p then q else r fi) = if p then función(q) else funcion(r) fi . INTRODUCCION AL DISEÑO En la etapa de especificación nos ocupamos del “¿qué?”. ya que si es falsa.if p then (if p then q else r) else t = if p then q else t. Si P es false. ESPECIFICANDO: Los observadores deben permitirnos distinguir todas las instancias. En el caso de los árboles por ejempo. Lo mismo si la incluyo como observador (más sutil). Es decir. Los generadores deben permitirnos construir todas las instancias observacionalmente distintas. deberíamos poder definir todas las operaciones a partir de los observadores.d)) Propiedades válidas sobre el if: . reciben dos instancias de tipo ab(alfa) por lo tanto. Se hace principalmente para agrupar información y simplificar TADs mediante el uso de otros y sus propiedades. Una operación f es congruente (respecto de la igualdad observacional) sii para cada par de i =obsi’ también vale f(i) =obsf(i’). como el paso inductivo es una implicación con P(s) como antecedente. Los axiomas nos brindan equivalencias por lo cual son “reversibles”.

Definición de la forma en que se representan las instancias del tipo que estamos diseñando. eligiendo justificadamente una o más estructuras. dependencias con otros modulos…) Representación: Sección no accesible a los usuarios del módulo. Servicios usados: Donde se detallan todos los supuestos sobre los servicios que exportan los otros módulos. (Parámetros formales. Un módulo de abstracción de divide en tres secciones: Interfaz: sección accesible para los usuarios del módulo donde se detallan los servicios exportados con la información relevante para el usuario. donde se detalla y justifica la elección de la estructura de representación y los algoritmos con su complejidad. Los servicios exportados de la interfaz de un módulo deben satisfacer los requisitos impuestos por las secciones de servicios usados de todos los módulos que lo utilizan. como efectos colaterales y complejidad. las operaciones de los TADs se explican a través de la axiomatización. Abs está definido para cada instancia que hace verdadero el Rep y le asigna la instancia correspondiente del TAD que estamos diseñando.En la etapa del diseño nos ocupamos del “¿cómo?”. Revisar no estar diciendo lo mismo varias veces.Coherencia en la información redundante: Hay que chequear que distintos campos que proveen la misma información no se contradigan entre sí. Relaciones entre la representación y la abstracción que representa. Tener en cuenta para un buen rep: . . Para un buen ABS: . El comportamiento de las operaciones en la interfaz se explica mediante pre y pos condiciones (estas se escriben usando las operaciones de los tads).Decisiones de diseño: chequear las restricciones a la estructura de representación que no provengan de un chequeo de coherencia o de restricciones especificadas en el TAD. lo explicamos con módulos de abstracción usando el paradigma imperativo. Punteros & : tipo_dato -> puntero(tipo_dato) * : puntero(tipo_dato) -> tipo_dato NULL: puntero(tipo_dato) REP y ABS El rep indica si una instancia del tipo con el que represento para representar es o no válida. Son admisibles aquellas instancias de la estructura tales que Rep(e) es verdadero.Restricciones del TAD: hay que chequear que se vean reflejadas en la estructura de representación. El Abs asigna la instancia correspondiente del tipo a representar a cada instancia del tipo con el que represento.Recordar que tiene como restricción al Rep . . En la especificación.

para no olvidarnos de mantenerlos . Si alguien modifica la colección que estamos iterando justo en medio de la recorrida ¡No está definido! La estructura de representación depende de cada caso. bidireccionales. etc. Necesitamos alguna manera de crearlo.De nuestra estructura. La idea es siempre la misma..De estructuras conocidas. entonces cualquier contenedor se puede iterar del mismo modo. con borrado (del elemento actual). Un iterador no debe confundirse con un mero puntero a un elemento. ELECCION DE ESTRUCTURAS: Tener muy en cuenta los invariantes: . Conceptualmente. puede servirnos para mejorar la complejidad. } También existen iteradores: reversos. Queremos poder tener múltiples iteradores de un mismo contenedor. Los iteradores suelen tener estado. Nos permite recorrer los elementos en algun orden. de acceder al próximo. Si todos los contenedores exportan generadores de una manera estandar. Una abstracción de “por cada elem e de la colección A…” que es independiente de la estructura de representación interna de la colección A. podríamos verlo como un puntero a un elemento en el contexto de una colección. Con eso alcanza para expresar de manera muy genérica: Por cada elemento e de la colección C{ hacerAlgoCon(e). de acceder al elemento actual.Recordar que queremos identificar unívocamente la instancia del tipo representado y usar una forma de asegurarlo INTRODUCCION A ITERADORES Tenemos contenedores/colecciones de “cosas”/tipos El iterador se utiliza para recorrer los elementos de un contenedor. de averiguar si hay más. Tener punteros/iteradores/referencias cruzadas. pueden ser pensados como una abstracción de los punteros. para poder aprovecharlas. ¡No romper el encapsulamiento! . OJO! No podemos tener punteros a cosas de la estructura de representación de otro módulo que no deberíamos conocer. Recordar “por donde vamos” podría ser más complicado que un simple puntero. e incluso independiente de la interfaz que pudiera exportar cada tipo de colección A.

y no requieren de alta sofisticación matematica para ser usados. y junto al concepto de encapsulamiento(ocultamiento de la información). Las fórmulas cerradas son las que son susceptibles de ser verdaderas o falsas. Los TADs son flexibles. Una fórmula bien formada es cerrada si todas sus variables están cuantificadas. Sintaxis(¿cómo se escribe?): Para especificar un TAD es necesario definir: 1. Los tipos abstractos de datos son modelos matemáticos que se construyen con el fin de exponer los aspectos relevantes del problema bajo análisis (es un tipo de lenguaje formal para especificar software). situaciones e interacciones que se pueden encontrar en él hacen imposible un análisis exhaustivo del mismo que permita una comprensión cabal sobre su funcionamiento. Los axiomas: que determinan el comportamiento de las operaciones.Es conveniente tener en claro para qué sirve cada parte de nuestra estructura y estar convencidos de que la estructura funciona antes de pensar los detalles más finos. . sus posibles interpretaciones. Los términos son en nuestro caso las variables. Los TADs buscan precisamente eso. Son fórmulas bien formadas según ciertas reglas (gramática). Un TAD es el “conjunto de modelos de una especificación”. Un sistema deductivo es un conjunto de axiomas y reglas de inferencias. Utilizar la abstracción como herramienta para la comprensión es fundamental. conforman una herramienta muy util para resaltar las cualidades relevantes de lo que queremos analizar. la signatura: solo dice qué operaciones y con qué aridad deben tener los modelos 2. es aquello que la especificación describe. Es decir. los símbolos de constantes y los símbolos de función aplicados a términos. Es lo que se entiende al leer una especificación. En este contexto nace la idea de utilizar un lenguaje formal para especificar el comportamiento del software. que pueda interpretarse sin lugar a dudas. Dada una especificación de un TAD podemos utilizar reglas de inferencia para razonar sobre la misma. Dado un objeto de estudio. generales. ORDENAMIENTO Cuando se tiene información extra sobre la entrada es posible conseguir algo de complejidad menor a O(n log n) APUNTE ESPECIFICACIÓN Para resolver un problema es necesario tener una descripción precisa del mismo. Un modelo determina qué elementos del mundo real estarán reflejados en la especificación y que operaciones se permitirá realizar sobre ellos. la cantidad de detalles.

(a partir de P(x) es posible concluir que para todo x P(x)… ) . Buscamos que un TAD modele cierto aspecto de la vida real (por eso tal vez todos los videoclubes el planeta podían ser un modelo de tad.Al decir de primer orden queremos decir que incluye los axiomas de la lógica de primer orden. Al realizar la especificación de un problema en realidad estamos trabajando sobre una abstracción del mismo. En las teorías inconsistentes. (verdadero y falso perteneces al metalenguaje y no forman parte de los TADs) Especificar: Se trata de capturar lo más fielmente posible y con precisión matemática.y las reglas de lógica ecuacional (reemplazo de iguales por iguales). En nuestro caso los axiomas son los que damos explícitamente (más los de la lógica de priemr orden que están implicitos) y las reglas de inferencia son: -Modus Ponens: (p=>q.p) |. lo que queremos es que una clase asociada a una especificación de un TAD satisfaga que las implementaciones de las operaciones computen funciones con las que puedo armar un modelo de la especificación. para concentrarnos en aquellos aspectos que son fundamentales. . Es decir. lo más probable es que lo que reflejemos en nuestro modelo sean los aspectos importantes de aquel ente que queremos capturar. -Generalización: P(x) |. …¿lo que? Metalenguaje Hay una diferencia entre true constante del lenguaje y verdadero como el resultado que se obtiene de evaluar una fórmula cerrada. Ejemplo long(a·b·<>) > 0 Semántica(Qué significa): Un ente matemático es modelo de nuestra teoría si hace corresponder a cáda género del tad un conjunto y a cada operación una función (total). es decir si p implica q y vale p entonces vale q. Los axiomas y aquellas cosas que se infieren a partir de ellos y las reglas de inferencia son teoremas. abstrayéndonos de que estos son finitos y mirando a cada videoclub como un ente matemático) Cuando implementamos. todo es cierto y por ende no tienen modelos (con lo cual no modelan en particular aquello que pretendíamos modelar). Una teoría es consistente cuando en ella no es cierto que verdadero es igual a falso. Los teoremas son formulas bien formadas del sistema deductivo que tienen una demostración.q.(paratodo x: P(x) si x no aparece en ninguna premisa. un problema para el que luego encontraremos una solución. En esta etapa lo que debe preocuparnos es el problema a resolver y no sus soluciones. La abstracción se trata de dejar de lado los detalles que no son importantes a los fines que perseguimos. Cualquier modelo de un TAD representa a todas las instancias del TAD y las instancias son infinitas.

Si comparamos dos instancias observacionalmente iguales no debería pasar que al aplicar un observador a ambas . A veces una caracterización más debil nos permite decidir al implementar. Tampoco se debe sobreespecificar. mediante los axiomas. En particular. tener en claro cuando vamos a considerar que dos instancias son iguales. una relación de equivalencia en la que si se aplica cualquier operación a dos instancias de la misma clase. Ventaja: la relación de igualdad que queda definida en el modelo es una congruencia (esto es. los resultados obtenidos también formen parte de la misma clase (correspondiente al TAD al que pertenzca el resultado). legibles e intuitivos. con la idea de agrupar en cada clase a las instancias que posean un comportamiento similar con respecto al estudio que queremos realizar.A la hora de escribir los axiomas para nuestras operaciones debemos tener en cuenta que siempre son funciones totales (esán definidos para todo valor de su dominio). como por ejemplo con el dameUno). Deventaja: en el caso general. cualquier implementación que utilice otro criterio no satisface nuestra especificación. entonces deberíamos indicar. deseamos que el TAD se convierta en una congruencia. Al hacer esto. Podemos obtener inconsistencias y privar a nuestra teoría de modelos. cosas que están en la misma clase de equivalencia van a la misma clase de equivalencia sin importar qué función se les aplique). cual es el resultado de la función para esos valores (o qué características tiene. La idea de dejar algunos aspectos particulares sin una definición precisa es un recurso muy útil para manejar algunas incertidumbres a la hora de especificar. excepto que haya ecuaciones que permitan deducir que son iguales. El universo se particiona de acuerdo a ellos. Es importante a la hora de elegir los observadores. Desventaja: los modelos no son muy bonitos salvo que uno agregue axiomas ad hoc (para este propósito). es decir. Sin embargo debemos ser cuidados de dotar al resto de los valores del dominio de su correspondiente imagen. en el sentido de que estamos dejando constancia que no vamos a decir qué valores toma la función cuando sus parámetros no cumplen con la restricción. que burdamente descripta trata de partir el universo de acuerdo a las ecuaciones que aparecen en el TAD. Cuando hay varias formas de saber el resultado para unos valores dados de sus parámetros. Si no lo hacemos. Algunas funciones se etiquetan como observadores básicos. Debido a este problema se inventó a semántica observacional. Igualdad observacional. se obtiene que todos los términos se interpretan en el modelo como distintos. Si determinado valor de los parámetros de una operación es válido de acuerdo a las restricciones. Para los TADs una semántica posible es la semántica inicial. la igualdad del modelo no es una congruencia (la igualdad de términos no se interpreta con una congruencia) Observadores básicos Son un conjunto de funciones pertenecientes al TAd que permiten particionar el universo de sus instancias en clases de equivalencia. a veces. En este sentido al utilizar restricciones estamos subespecificando. Ventaja: los modelos son más bonitos. El problema se presenta cuando dependiendo de nuestra eleccion obtenemos valores distintos (¡recordemos que son funciones).

dificulta la axiomatización de las funciones y lleva a la posible aparición de errores e inconsistencias en la especificación. sino que se está generando una nueva instancia basada en la anterior. Al aplicar un generador recursivo a una instancia de un TAD no se está modificando la instancia que recibe como parámetro ya que en nuestro lenguaje abstracto no existe la noción de “cambio de estado”. Generadores básicos o no recursivos: los que reciben como parámetro ninguna instancia del tipo que están generando. porque en ese caso el TAD no se comportaría como una congruencia (sus funciones no lo harían). No puede existir una instancia de un TAD que no se pueda generar a partir de una sucesión de aplicaciones de sus generadores. Recursión: . No deberían existir observadores que solo identifiquen aspectos de la instancia que ya han sido identificados por los otros observadores.obtengamos resultados distintos. Restricciones Son una parte fundamental de un TAD. Este punto es fundamental a la hora de realizar demostraciones de propiedades sobre tipos abstractos de datos. suponiendo que la propiedad es válida para las instancias del TAD que reciben como parámetros (que a su vez están generadas a partir de los generadores base o recursivos). Aportan expresividad a nuestro lenguaje ya que nos permiten limitar el universo al cual aplican ciertas operaciones de nuestros TADs Géneros Es el nombre colectivo con el que se va a hacer referencia a instancias del TAD que estamos definiendo. La primer parte demuestra la propiedad para todas las instancias generadas por generadores base. y la segunda demuestra la propiedad para todas las instancias generadas por generadores recursivos. aportan claridad y coherencia a una especificación. Otras operaciones No debería ocurrir que una función que aparezca en esta sección devuelva valores distintos cuando se aplique sobre dos instancias observacionalmente iguales del TAD. ya que nos ofrece un esquema de demostración dividido en dos partes. con ellas explicitamos los casos para los cuales ciertas operaciones no tienen sentido. y que tienen la particularidad de que a partir de una aplicación finita de ellos se pueden construir o generar absolutamente todas las instancias del TAD. Definir generadores de más. Generadores Son un conjunto de funciones que retornan un resultado del género principal del TAD especificado. Generadores recursivos: los que reciben como parámetro al menos una instancia del tipo que están generando.

DISEÑO JERARQUICO DE TIPOS ABSTRACTOS DE DATOS Al diseñar comenzamos a resolver el problema. . TAD Secu(alfa) (alfa es el parámetro formal). Parámetros formales: Podría entenderse como una variable del tipo. nos basta con saber qué tiene que devolver la función para ese caso particular. Al realizar estas axiomatizaciones lo preferible es que ellas se efectuen en función de los observadores básicos del tipo usado y no sobre los generadores (nuestra operación podría violar la igualdad observacional del tipo usado). el caso base. Cada iteración de este proceso definirá un nivel de nuestro diseño. Para resolver el caso base.proveer una representación para sus valores. Allí la definición se resuelve directamente sin usar el concepto que se esta definiendo. La idea es que al ir simplificando se llega a un punto donde no se puede simplificar más. La manera más habitual de garantizar esto es que en cada caso recursivo se logre disminuir la complejidad de los parámetros invlucrados.definir las funciones del tipo en función de las de su representación .Una definición es recursiva si hace referencia a sí misma. Debemos garantizar que eventualmente se llegará al caso base para todos los valores sobre los cuales se encuentra definida la operación. … Un tipo se define por sus funciones antes que por sus valores. cada uno de estos niveles tendrá asociado uno o más modulos de abstracción que básicamente indicará como se resuelven las operaciones de un módulo utilizando otras de módulos del nivel inmediato inferior. Centraremos nuestro interes en el tipo (TAD) como en los aspectos que se necesitan para optimizarlo (espacio. Con el propósito de implementar un tipo deberemos: . a veces tenemos una operación auxiliar que recibe elementos de tipos definidos en otros TADs. . tiempo de ejecución). nunca la forma de construirlos o representarlos físicamente. Nuestra metodología del diseño parte de un modelo abstracto (nuestra especificación) no implementable directamente en un lenguaje imperativo de programación y aplicará iterativamente sobre dicho modelo sucesivos pasos de refinamiento (desabstracciones) hasta llegar a estructuras que sí son implementables. Define una cosa en función de las interpretaciones más simples de la misma. Los modulos de abstracción son implementables en un lenguaje de programación. La forma en que los valores se representan es menos importante que las funciones que se proveen para manipularlos. Los generadores de los tipos describen la forma abstracta de construir elementos. Por su parte. No axiomatizar sobre casos restringidos ni sobre generadores de otros tipos.demostrar que las funciones implementadas satisfacen las relaciones especificadas en los axiomas. “alfa” TAD Conj(alfa). Sobre lo segundo.

Todo módulo que se diseñe y cuyas instancias se desee copiar. deberá proveer una función a tal efecto. real. Por ejemplo si en la especificación tenemos al cardinal de un conjunto como: Cardinal(c) = long(VolcarElementosEnSecuencia(c)) Deberíamos plantear si tiene sentido considerar en el diseño al tipo secuencia. habrá que diseñar eventualmente el tipo secuencia. El mapeo de los parámetros de las funciones del tipo en las operaciones del módulo no siempre es uno a uno. y no conocen (ni usan) a los módulos de otros niveles). En el paradigma funcional los datos solo tienen sentido en cuanto sean argumentos o resultados de funciones. Por ejemplo. Para utilizar un tipo. no necesariamente debemos diseñar todos los tipos que usamos en la especificación. nat. en principio no sería necesario y la función cardinal podría implementarse de otra manera sin pasar por la secuencia. puede ser que la interfaz haya agregado requerimientos en el contexto de uso…etc Pasaje de parámetros: Se deberá tener en cuenta que los parámetros de tipos primitivos (bool . Al diseñar un módulo. aunque puede haber mejorado su performance. . es una buena práctica comenzar por los tipos mas importantes pues estos serán los principales generadores de requerimientos de eficiencia para los tipos menos importantes (modalidad top-down). y la funcionalidad provista por las mismas no cambió. no se accede directamente a la estructura que lo representa sino que se accede a través de la interfaz que se le define.Los módulos de un cierto nivel son usuarios de los servicios que les brindan los de nivel inmediato inferior. int. dicha copia debe ser explícita. El módulo exporta al menos las mismas funciones que se exportaban antes. Es usual que se trabaje con una instancia de un objeto que se va modificando y cuyos valores anteriores no interesen. puntero) y solo estos siempre se pasan por valor y los de tipos no primitivos siempre se pasan por referencia. no tiene sentido construir cada vez un objeto nuevo para devolverlo como resultado de una función. Paradigma imperativo. char. Si realmente nos interesa ofrecer una función que vuelque el conjunto en una secuencia. Cualquier cambio de implementación del nivel n será transparente al nivel superior n+1 siempre que el nivel n mantenga su interfaz. los datos son tratados como entidades independientes de las funciones que los utilizan. sin embargo. Pero si no se exporta y no aparece visible en ningún otro lado de la especificación. Sin embargo. Por lo tanto. Método: El orden en el cual se diseñan los tipos es arbitrario. en el paradigma imperativo. por cuestiones de optimización y su uso. Si fuera necesario construir una copia de un parámetro de tipo no primitivo.

Elección de la estructura. Además es muy importante considerar criterios de optimización tales como: espacio de disco. La idea es que la principal justificación para el resultado obtenido en cada iteración de diseño es el contexto de uso que se le impuso al diseñador. Hay que tener en cuenta cuales son las operaciones que nos interesan optimizar y en qué contexto de uso serán utilizadas. si no se aclara precisamente el contexto de uso. espacio de memoria. Las variables en un programa referencian valores. En la interfaz se describe básicamente la funcionalidad del módulo y en qué contexto puede ser usada. una forma de representación utilizando otros módulos y se resuelven las operaciones del módulo en función de su representación. etc. homogeneidad de los algoritmos. . Será imposible el acceso a la implementación interne de estos. Es el conocimiento sobre la estructura que necesitan las distintas operaciones para funcionar correctamente y que garantizan finalizar. También es importante. claridad y sencillez de la implementación. Al acceder a los objetos solo a través de su interfaz. un diseño puede contener tipos para los que no tenemos una propuesta de diseño. En este punto. En la representación se elige. Esto afecta a los usuarios que tengan referencias a dichos elementos. Esto es útil para aumentar el nivel de abstracción y diseñar código que sea más fácilmente modificables. surgidas de la redundancia de información que pueda haber. por lo que será el usuario el encargado de liberarlas al momento de implementar su módulo. la definición de la interfaz y la definición de la representación.No es importante la manera en que se axiomatizaron las funciones si no lo que esos axiomas significan. bajo algún criterio. Si se los elimina. seguirán vigentes pero ya no estarán en la estructura. mantenible y extensible. Cada módulo de abstracción está compuesto por dos secciones. tiempo de ejecución. Para escribir las precondiciones y las poscondiciones usaremos un lenguaje de descripción de estados aprovechando la especificación del tipo a diseñar. reusabilidad. las referencias a ellos dejarán de ser válidas. y esto redundará en la modularidad de nuestro diseño y en el ocultamiento de información. Cualquier cambio de implementación en un tipo que no altere la funcionalidad no nos obligará a rediseñar los tipos superiores. En caso contrario. en las operaciones que quitan elementos de la estructura indicar si estos elementos seguirán existiendo o serán eliminados. Relación entre la representación y la abstracción Invariante de representación Es un predicado que nos indica si una instancia del tipo de representación es valida para representar una instancia del tipo representado. Este nos permite hacer invisibles algunos aspectos que serán encapsulados. Son otros problemas a resolver de un nivel de abstracción menor al original. Quedan expresados en el las restricciones de coherencia de la estructura. solo a su funcionalidad. No se puede saber si un diseño es adecuado. no nos atamos a su implementación.

sus precondiciones y poscondiciones. del mundo de los TADs) de la representación del tipo. junto con sus algoritmos. En el caso de las funciones auxiliares. in n:nat). Si no lo fuera. . y asumimos que el lenguaje de implementación se encarga de la conversión de tipos.Su dominio es la imagen funcional del tipo que estamos implementando. Por ejemplo. estamos describiendo sin ambigüedad el objeto representado. significaría que hay elementos del tipo que queremos representar que no podrán ser efectivamente representados. de la interfaz o auxiliares. para interpretar que el parámetro que recibe es del tipo de representación y por ende se puede acceder a su estructura.20] de nat no podemos representar conjuntos de más de 20 elementos. con un arreglo [1.. La estructura sería válida si el contexto de uso nos garantiza que efectivamente no manejaremos tales conjuntos. Puede que en algun caso todas las instancias del tipo de representación sean válidas (Rep = TRUE) Función de abstracción: Tiene por dominio al conjunto de instancias que son la imagen abstracta del tipo de representación y que verifican el invariante de representación. Rep toma la imagen “abstracta” (funcional. tenemos un conjunto representado con una secuencia. Esto es necesario para que podamos “tratar” los elementos del dominio en lógica de primero orden. al menos con respecto al universo que nos ha restringido nuestro contexto de uso. Deben aparecer algoritmos de cada una de las operaciones. Por ejemplo. Por ejemplo. La primera. Al escribir los algoritmos. La interfaz tendrá Agregar(in/out c: conj(nat). es bueno incluir. Algoritmos En este paso se implementan las operaciones del tipo a diseñar en términos de operaciones de los tipos soporte. Un tipo que lo ve desde afuera debe invocar a la interfaz. No necesariamente debe ser inyectiva (ver ejemplo anterior) ¿Todo debe devolver algo del universo que representamos pero quizas haya cosas del universo que no puedan ser hechas con esta estructura? Tenemos dos maneras de escribir la función de abstracción. La función de abstracción debe ser sobreyectiva. al hablar del valor que tienen los observadores básicos aplicados al objeto. en función de los observadores básicos. Dado que estos identifican de manera unívoca al objeto del cual hablan. y devuelve una imagen abstracta de la instancia del tipo representado (aquella instancia que estamos pretendiendo representar). Abs(s)). en un conjunto implementado sobre una secuencia: Abs(<>) = (conj vacío) Abs(n·S) = Ag(n. Su imagen no es el genero bool si no los valores lógicos verdadero o falso. agregamos una i al nombre de la función. Otra forma de describir la función de abstracción es en función de los generadores del tipo de representación.

Especificidad de los algoritmos: Dado que el mecanismo de iteración es el diferente para cada estructura.Copiado innecesario: Dado que la única forma de iterar una estructura es a traves de operaciones que la destruyen. Esto hace notar un problema puesto que no es posible utilizar el contenedor sin copiarlo. habrá que diseñar su iterador. . De esta manera. por lo que no hacemos asunciones acerca de cómo está implementada. Servicios usados: Aquí es donde indicamos que responsabilidades le dejamos a los tipos soporte que usamos. el código está oculto a los demás módulos. Son las pautas de requerimientos que se extraen del diseño de este tipo para el diseño de los tipos de la representación. es necesario implementar algoritmos básicos para cada una. fin). Cuando una operación pertenece a otro módulo. No tenerlos trae dos tipos de problemas: . Dado que se pretende que la implementación de un iterador no realice una copia del contenedor que va a iterar. . Iteradores Un iterador. no nos metemos dentro de la estructura de representación de la secuencia. Luego pasarán a ser las interfaces y los contextos de uso y requerimientos de eficiencia para los módulos soporte de los tipos usados. la unica forma para iterar los elementos es destruirlos (dameUno. en su forma más simple. puesto que es de esperarse que en algún momento sea necesario recorrer los elementos que esta contiene. un cambio en la implementación de secuencia no tendría impacto en el diseño de nuestro conjunto. es necesario realizar una copia previa a iterarla.Al hacer la función. por lo que sería necesario hacer una copia para no destruir el original. es una estructura de datos que permite recorrer de forma eficiente otra estructura. es de esperarse que conozca su estructura interna. Es por esto que para cada contenedor. APUNTE ITERADORES: La necesidad de los iteradores surge con la implementación de un algoritmo que utilice alguna estructura contenedora. en la secuencia o el conjunto. Lo único que se necesita para usarlo es conocer las operaciones exportadas. Por ejemplo.

. en el conjunto X no puede haber dos o más elementos que tengan la misma imagen. es decir. En matemáticas. suprayectiva. y a cada elemento del conjunto de llegada le corresponde un elemento del conjunto de salida. cada elemento del conjunto Y tiene a lo sumo una antiimagen en X. si todos los elementos del conjunto de salida tienen una imagen distinta en el conjunto de llegada. exhaustiva o subyectiva). una función es biyectiva si es al mismo tiempo inyectiva y sobreyectiva. o. cuando cada elemento de "Y" es la imagen de como mínimo un elemento de "X".GLOSARIO En el análisis matemático. la aridad de un operador matemático o de una función es el número de argumentos necesarios para que dicho operador o función se pueda calcular. una función es sobreyectiva (epiyectiva. Es decir. En matemáticas. una función es inyectiva si a elementos distintos del conjunto (dominio) les corresponden elementos distintos en el conjunto (imagen) de . suryectiva. es decir. si está aplicada sobre todo el codominio. En matemática. lo que es lo mismo.