Algoritmos y Estructuras de Datos II

74
Algoritmos y Estructuras de Datos I Departamento de Computaci´on, FCEyN, UBA 2 cuatrimestre de 2008 1 Contenido Especificaci´ on I clase 1, p. 3 I clase 2, p. 28 I clase 3, p. 48 I clase 4, p. 78 Programaci´ on funcional I clase 1: p. 94 I clase 2: p. 114 I clase 3: p. 131 I clase 4: p. 154 I clase 5: p. 181 Programaci´ on imperativa I clase 1: p. 205 I clase 2: p. 225 I clase 3: p. 247 I clase 4: p. 260 I clase 5: p. 272 2 Especificaci´on Clase 1 Introducci´ on a la especificaci´ on de problemas 3 Cursada I clases te´ oricas I Paula Zabala y Santiago Figueira I clases pr´ acticas I Carlos L´ opez Pombo, Pablo Turjanski y Mart´ ın Urtasun I sitio web de la materia: www.dc.uba.ar/people/materias/algo1 I egimen de aprobaci´ on I parciales I 3 parciales I 3 recuperatorios (al final de la cursada) I trabajos pr´ acticos I 3 entregas I 3 recuperatorios (cada uno a continuaci´on) I grupos de 4 alumnos I examen final (si lo dan en diciembre 2008 o febrero/marzo 2009, cuenta la nota de la cursada) 4

Transcript of Algoritmos y Estructuras de Datos II

Page 1: Algoritmos y Estructuras de Datos II

Algoritmos y Estructuras de Datos I

Departamento de Computacion, FCEyN, UBA

2◦ cuatrimestre de 2008

1

ContenidoEspecificacion

I clase 1, p. 3I clase 2, p. 28I clase 3, p. 48I clase 4, p. 78

Programacion funcionalI clase 1: p. 94I clase 2: p. 114I clase 3: p. 131I clase 4: p. 154I clase 5: p. 181

Programacion imperativaI clase 1: p. 205I clase 2: p. 225I clase 3: p. 247I clase 4: p. 260I clase 5: p. 272

2

EspecificacionClase 1

Introduccion a la especificacion de problemas

3

Cursada

I clases teoricasI Paula Zabala y Santiago Figueira

I clases practicasI Carlos Lopez Pombo, Pablo Turjanski y Martın Urtasun

I sitio web de la materia: www.dc.uba.ar/people/materias/algo1I regimen de aprobacion

I parcialesI 3 parcialesI 3 recuperatorios (al final de la cursada)

I trabajos practicosI 3 entregasI 3 recuperatorios (cada uno a continuacion)I grupos de 4 alumnos

I examen final (si lo dan en diciembre 2008 o febrero/marzo2009, cuenta la nota de la cursada)

4

Page 2: Algoritmos y Estructuras de Datos II

Objetivos y contenidosI Objetivos:

I especificar problemasI describirlos de forma no ambigua

I escribir programas sencillosI tratamiento de secuencias

I razonar acerca de estos programasI demostrar matematicamente que un programa es correctoI vision abstracta del proceso de computacionI manejo simbolico y herramientas para demostrar

I Contenidos:I especificacion

I describir problemas en un lenguaje formal (preciso, claro,abstracto)

I programacion funcional (Haskell)I parecido al lenguaje matematicoI escribir de manera simple algoritmos y estructuras de datos

I programacion imperativa (C++)I paradigma mas difundidoI mas eficienteI se necesita para seguir la carrera

5

Especificacion, algoritmo, programa

1. especificacion = descripcion del problemaI ¿que problema tenemos?I en lenguaje formalI describe propiedades de la solucionI Dijkstra, Hoare (anos 70)

2. algoritmo = descripcion de la solucion (escrito para humanos)I ¿como resolvemos el problema?

3. programa = descripcion de la solucion (escrito para lacomputadora)

I tambien, ¿como resolvemos el problema?I usando un lenguaje de programacion

6

Problemas y solucionSi voy a escribir un programa, es porque hay un problema aresolver

I a veces, la descripcion es vaga o ambigua

I no siempre es claro que haya solucion

I no siempre involucra uno o mas programas de computacion

Ejemplos de problemas:I cerre el auto con las llaves adentro

I seguramente tiene solucion, sin programas

I quiero calcular la edad de una personaI tal vez podamos crear un programa

I necesitamos que la empresa reduzca sus gastos en un 10 %I puede o no tener solucion, que puede o no requerir programas

nuevos o existentes

I soy muy petisoI quizas no tenga solucion

7

Problema vs. solucionParece una diferencia trivial

I en los ejemplos, es claraI pero es facil confundirlos

Ejemplo:

I confundir el problema con la solucion:A: “tengo un problema: necesito un alambre”B: “no tengo”

I en realidad, ese no era el problema:A: “tengo un problema: cerre el auto con las llaves adentro”B: “toma la copia de la llave que me pediste que te guardaracuando compraste el auto”

I confundir el problema con la solucion trae nuevos problemasI es muy comun en computacion

I los programas de computadora casi nunca son la solucioncompleta

I a veces forman parte de la solucionI ¡y a veces ni siquiera se necesitan! 8

Page 3: Algoritmos y Estructuras de Datos II

Etapas en el desarrollo de programas

1. especificacion: definicion precisa del problema

↓2. diseno: elegir una solucion y dividir el problema en partes

↓3. programacion: escribir algoritmos e implementarlos en algun

lenguaje

↓4. validacion: ver si el programa cumple con lo especificado

↓5. mantenimiento: corregir errores y adaptarlo a nuevos

requerimientos

E D P V M · · ·

9

1. EspecificacionI el planteo inicial del problema es vago y ambiguoI especificacion = descripcion clara y precisaI optimo: lenguaje formal, por ejemplo, el lenguaje de la logica matematica

Por ejemplo, el problema de calcular de edad de una persona parece bienplanteado, pero:

I ¿como recibo los datos? manualmente, archivo en disco, sensorI ¿cuales son los datos? fecha de nacimiento, tamano de la persona,

deterioro celularI ¿como devuelvo el resultado? pantalla, papel, voz alta, emailI ¿que forma van a tener? dıas, anos enteros, fraccion de anos

Una buena especificacion responde algunas:I Necesito una funcion que, dadas dos fechas en formato dd/mm/aaaa, me

devuelva la cantidad de dıas que hay entre ellas.

todavıa faltan los requerimientos no funcionalesI forma de entrada de parametros y de salida de resultados, tipo de

computadora, tiempo con el que se cuenta para programarlo, etc.I no son parte de la especificacion funcional y quedan para otras materias

10

2. Diseno

Etapa en la que se responde

I ¿varios programas o uno muy complejo?I ¿como dividirlo en partes, que porcion del problema resuelve

cada una?I ¿distintas partes en distintas maquinas?I estudio de las partes que lo componen

I (mini) especificacion de cada parteI un programador recibe una sola (o una por vez)

I ¿programas ya hechos con los que interactuar?

I lo van a ver en Algoritmos y Estructuras de Datos II y enIngenierıa del Software I

11

3. Programacion - Algoritmos

Pensar en la solucion al problema. Escribir un algoritmo:

I pasos precisos para llegar al resultado buscado de manera efectivaI primero tienen que estar definidos los pasos primitivos

Ejemplo de algoritmo para la especificacion

Necesito una funcion que, dadas dos fechas a y b en formatodd/mm/aaaa, me devuelva la cantidad de dıas que hay entre ellas.

1. restar el ano de b al ano de a2. multiplicar el resultado por 3653. sumarle la cantidad de dıas desde el 1◦ de enero del ano de b hasta el dıa b4. restarle la cantidad de dıas desde el 1◦ de enero del ano de a hasta el dıa a5. sumarle la cantidad de 29 de febrero que hubo en el perıodo6. devolver ese resultado, acompanado de la palabra “dıas”

¿Son todos primitivos? (3, 4, 5)

I si no, hay que dar algoritmos para realizarlos

12

Page 4: Algoritmos y Estructuras de Datos II

Pasos primitivos

I problema: sumar dos numeros naturalesI algoritmos:

I voy sumando uno al primero y restando uno al segundo, hastaque llegue a cero

I sumo las unidades del primero a las del segundo, despues lasdecenas y ası (“llevandome uno” cuando hace falta)

I escribo el primero en una calculadora, aprieto +, escribo elsegundo, aprieto =

I los tres son validosI depende de que operaciones primitivas tenga

I sumar / restar unoI sumar dıgitos (y concatenar resultados)I apretar una tecla de una calculadora

13

3. Programacion - Programas

I traducir el algoritmo (escrito o idea) para que unacomputadora lo entienda

I lenguaje de programacionI vamos a empezar usando uno: HaskellI despues, C++

I hay muchos otrosI pueden ser mas adecuados para ciertas tareasI depende del algoritmo, de la interfaz, tiempo de ejecucion, tipo

de maquina, interoperabilidad, entrenamiento de losprogramadores, licencias, etc.

14

Representacion de los datos

I ya vimos que era importante en el ejemplo de calcular la edadde una persona (dıas, meses, anos, fracciones de ano)

I otro ejemplo:I contar la cantidad de alumnos de cada sexoI yo puedo darme cuenta a simple vista (a veces)I la computadora probablemente no. ¿Que dato conviene tener?

I fotoI foto del documentoI ADNI valor de la propiedad sexo para cada alumno

I estructuras de datosI necesarias para especificarI puede ser que haya que cambiarlas al programarI las van a estudiar a fondo en Algoritmos y Estructuras de

Datos II

15

4. ValidacionAsegurarse de que un programa cumple con la especificacion

I testingI probar el programa con muchos datos y ver si hace lo que tiene

que hacerI en general, para estar seguro de que anda bien, uno tendrıa

que probarlo para infinitos datos de entradaI si hay un error, con algo de suerte uno puede encontrarloI no es infalible (puede pasar el testing pero haber errores)I en Ingenierıa del Software I van a ver tecnicas para hacer

testingI verificacion formal

I demostrar matematicamente que un programa cumple con unaespecificacion

I es mas difıcil que hacer testingI una demostracion cubre infinitos valores de entrada a la vez

(abstraccion)I es infalible (si esta demostrado, el programa no tiene errores)I en esta materia van a estudiar como demostrar que programas

simples son correctos para una especificacion16

Page 5: Algoritmos y Estructuras de Datos II

5. Mantenimiento

I tiempo despues, encontramos erroresI el programa no cumplıa la especificacionI la especificacion no describıa correctamente el problema

I o cambian los requerimientos

I puede hacerlo el mismo equipo u otroI justifica las etapas anteriores

I si se hicieron bien la especificacion, diseno, programacion yvalidacion, las modificaciones van a ser mas sencillas y menosfrecuentes

17

Especificacion

I objetivos:I antes de programar: entender el problemaI despues de programar: determinar si el programa es correcto

I testingI verificacion formalI derivacion (construyo el programa a partir de la especificacion)

I estrategia:I evitar pensar (todavıa) una solucion para el problemaI limitarse a describir cual es el problema a resolver

I que propiedades tiene que cumplir una solucion para resolverel problema

I buscamos el que y no el como

18

Instancias de un problema

I ejemplo de problema: arreglar una cafeteraI para solucionarlo, necesitamos mas datos

I ¿que clase de cafetera es?I ¿que defecto tiene?I ¿cuanto presupuesto tenemos?

I se llaman parametros del problemaI cada combinacion de valores de los parametros es una

instancia del problemaI una instancia: “arreglar una cafetera de filtro cuya jarra pierde

agua, gastando a lo sumo $30”

I los valores de los parametros se llaman argumentos

19

Problemas funcionales

I no podemos especificar formalmente cualquier problemaI el hambre en el mundoI la salud de Sandro

I simplificacion (para esta materia)I problemas que puedan solucionarse con una funcion

I parametros de entradaI un resultado para cada combinacion de valores de entrada

20

Page 6: Algoritmos y Estructuras de Datos II

Tipos de datos

Cada parametro tiene un tipo de datos

I conjunto de valores para los que hay ciertas operacionesdefinidas

Por ejemplo:I parametros de tipo fecha

I valores: ternas de numeros enterosI operaciones: comparacion, obtener el ano,...

I parametros de tipo dineroI valores: numeros reales con dos decimalesI operaciones: suma, resta,...

21

Encabezado de un problemaIndica la forma que debe tener una solucion.

problema nombre(parametros) = nombreRes : tipoRes

I nombre: nombre que le damos al problemaI sera resuelto por una funcion con ese mismo nombre

I nombreRes: nombre que le damos al resultadoI tipoRes: tipo de datos del resultadoI parametros: lista que da el tipo y el nombre de cada uno

EjemploI problema resta(minuendo, sustraendo : Int) = res : IntI la funcion se llama restaI da un resultado que vamos a llamar res

I y es de tipo Int (los enteros)I depende de dos parametros: minuendo y sustraendo

I tambien son de tipo Int22

ContratosI la funcion que solucione el problema va a ser llamada o invocada por

un usuarioI puede ser el programador de otra funcion

I especificacion = contrato entre el programador de una funcion queresuelva el problema y el usuario de esa funcion

Por ejemplo:I problema: calcular la raız cuadrada de un realI solucion (funcion)

I va a tener un parametro realI va a calcular un resultado real

I para hacer el calculo, debe recibir un numero no negativoI compromiso para el usuario: no puede proveer numeros negativosI derecho para el programador de la funcion: puede suponer que el

argumento recibido no es negativoI el resultado va a ser la raız del numero

I compromiso del programador: debe calcular la raız, siempre y cuandohaya recibido un numero no negativo

I derecho del usuario: puede suponer que el resultado va a ser correcto23

Partes de una especificacion

Tiene 3 partes

1. encabezado (ya lo vimos)

2. precondicionI condicion sobre los argumentosI el programador da por ciertaI lo que requiere la funcion para hacer su tareaI por ejemplo: “el valor de entrada es un real no negativo”

3. poscondicionI condicion sobre el resultadoI debe ser cumplida por el programador, siempre y cuando el

usuario haya cumplido la precondicionI lo que la funcion asegura que se va a cumplir despues de

llamarla (si se cumplıa la precondicion)I por ejemplo: “la salida es la raız del valor de entrada”

24

Page 7: Algoritmos y Estructuras de Datos II

El contrato dice:El programador va a hacer un programa P tal que si elusuario suministra datos que hacen verdadera laprecondicion, entonces P va a terminar en una cantidadfinita de pasos y va a devolver un valor que haceverdadera la poscondicion.

I si el usuario no cumple la precondicion y P se cuelga o nocumple la poscondicion...

I ¿el usuario tiene derecho a quejarse? No.I ¿se viola el contrato? No. El contrato preve este caso y dice

que P solo debe funcionar en caso de que el usuario cumplacon la precondicion

I si el usuario cumple la precondicion y P se cuelga o no cumplela poscondicion...

I ¿el usuario tiene derecho a quejarse? Sı.I ¿se viola el contrato? Sı. Es el unico caso en que se viola el

contrato. El programador no hizo lo que se habıacomprometido a hacer.

25

Lenguaje naturales y lenguajes formalesI lenguajes naturales

I idiomas (castellano)I mucho poder expresivo (emociones, deseos, suposiciones y demas)I con un costo (conocimiento del contexto, experiencias compartidas

ambiguedad e imprecision)I queremos evitarlo al especificar

I lenguajes formalesI limitan lo que se puede expresarI todas las suposiciones quedan explıcitasI relacion directa entre lo escrito (sintaxis) y su significado (semantica)I pueden tratarse formalmente

I sımbolos manipulables directamenteI seguridad de que las manipulaciones son validas tambien para el significado

I ejemplo: aritmeticaI lenguaje formal para los numeros y sus operacionesI resolvemos problemas simbolicamente sin pensar en los significados

numericos y llegamos a resultados correctosI en Teorıa de Lenguajes y Logica y Computabilidad van a estudiarlos en

profundidad26

Especificacion formal

I ya aprendimos a escribir encabezadosI tenemos que dar tambien

I la precondicion (lo que la funcion requiere)I la poscondicion (lo que asegura)

I usamos un lenguaje formal para describir la precondicion y laposcondicion

I ejemplo de problema: calcular la raız cuadrada de un numeroI lo llamamos rcuadI Float representa el conjunto R

problema rcuad(x : Float) = result : Float {requiere x ≥ 0;asegura result ∗ result == x ;

}

27

EspecificacionClase 2

Logica proposicional - tipos basicos

28

Page 8: Algoritmos y Estructuras de Datos II

Logica proposicional - sintaxis

I sımbolos

true , false , ⊥ , ¬ , ∧ , ∨ , → , ↔ , ( , )

I variables proposicionales (infinitas)

p , q , r , . . .

I formulas1. true, false y ⊥ son formulas2. cualquier variable proposicional es una formula3. si A es una formula, ¬A es una formula4. si A1,A2, . . . ,An son formulas, (A1 ∧ A2 ∧ · · · ∧ An) es una

formula5. si A1,A2, . . . ,An son formulas, (A1 ∨ A2 ∨ · · · ∨ An) es una

formula6. si A y B son formulas, (A→ B) es una formula7. si A y B son formulas, (A↔ B) es una formula

29

Ejemplos

¿Cuales son formulas?

I p ∨ q no

I (p ∨ q) sı

I p ∨ q → r no

I (p ∨ q)→ r no

I ((p ∨ q)→ r) sı

I (p → q → r) no

30

Semantica clasica

I 2 valores de verdad posibles

1. verdadero (1)2. falso (0)

I interpretacion:

I true siempre vale 1I false siempre vale 0I ¬ se interpreta como “no”, se llama negacionI ∧ se interpreta como “y”, se llama conjuncionI ∨ se interpreta como “o”(no exclusivo), se llama disyuncionI → se interpreta como “si... entonces”, se llama implicacionI ↔ se interpreta como “si y solo si”, se llama doble implicacion

o equivalencia

31

Semantica clasica

Conociendo el valor de las variables proposicionales de unaformula, conocemos el valor de verdad de la formula

p ¬p

1 0

0 1

p q (p ∧ q)

1 1 1

1 0 0

0 1 0

0 0 0

p q (p ∨ q)

1 1 1

1 0 1

0 1 1

0 0 0

p q (p → q)

1 1 1

1 0 0

0 1 1

0 0 1

p q (p ↔ q)

1 1 1

1 0 0

0 1 0

0 0 1

32

Page 9: Algoritmos y Estructuras de Datos II

Ejemplo: tabla de verdad para ((p ∧ q)→ r)

p q r (p ∧ q) ((p ∧ q)→ r)

1 1 1 1 1

1 1 0 1 0

1 0 1 0 1

1 0 0 0 1

0 1 1 0 1

0 1 0 0 1

0 0 1 0 1

0 0 0 0 1

33

Semantica trivaluada

I 3 valores de verdad posibles

1. verdadero (1)2. falso (0)3. indefinido (−)

I es la que vamos a usar en esta materiaI ¿por que?

I queremos especificar problemas que puedan resolverse con unalgoritmo

I puede ser que un algoritmo realice una operacion invalida

I dividir por ceroI raız cuadrada de un numero negativo

I necesitamos contemplar esta posibilidad en la especificacion

I interpretacion:

I true siempre vale 1I false siempre vale 0I ⊥ siempre vale −I se extienden las definiciones de ¬,∧,∨,→,↔

34

Semantica trivaluada (secuencial)Se llama secuencial porque

I los terminos se evaluan de izquierda a derecha

I la evaluacion termina cuando se puede deducir el valor deverdad, aunque el resto este indefinido

Extendemos la semantica de ¬, ∧, ∨

p ¬p

1 0

0 1

− −

p q (p ∧ q)

1 1 1

1 0 0

0 1 0

0 0 0

1 − −0 − 0

− 1 −− 0 −− − −

p q (p ∨ q)

1 1 1

1 0 1

0 1 1

0 0 0

1 − 1

0 − −− 1 −− 0 −− − −

35

Semantica trivaluada (secuencial)

Extendemos la semantica de →, ↔

p q (p → q)

1 1 1

1 0 0

0 1 1

0 0 1

1 − −0 − 1

− 1 −− 0 −− − −

p q (p ↔ q)

1 1 1

1 0 0

0 1 0

0 0 1

1 − −0 − −− 1 −− 0 −− − −

36

Page 10: Algoritmos y Estructuras de Datos II

Dos conectivos bastan

I ¬ y ∨I (A ∧ B) es ¬(¬A ∨ ¬B)I (A→ B) es (¬A ∨ B)I true es (A ∨ ¬A)I false es ¬true

I ¬ y ∧I (A ∨ B) es ¬(¬A ∧ ¬B)I (A→ B) es ¬(A ∧ ¬B)I false es (A ∧ ¬A)I true es ¬false

I ¬ y →I (A ∨ B) es (¬A→ B)I (A ∧ B) es ¬(A→ ¬B)I true es (A→ A)I false es ¬true

37

Tautologıas, contradicciones y contingenciasI una formula es una tautologıa si siempre toma el valor 1 para

valores definidos de sus variables proposicionalesPor ejemplo, ((p ∧ q)→ p) es tautologıa:

p q (p ∧ q) ((p ∧ q)→ p)

1 1 1 1

1 0 0 1

0 1 0 1

0 0 0 1

I una formula es una contradiccion si siempre toma el valor 0para valores definidos de sus variables proposicionalesPor ejemplo, (p ∧ ¬p) es contradiccion:

p ¬p (p ∧ ¬p)

1 0 0

0 1 0

I una formula es una contingencia cuando no es ni tautologıa nicontradiccion

38

Relacion de fuerza

Decimos que A es mas fuerte que B cuando (A→ B) es tautologıa.

Tambien decimos que A fuerza a B o que B es mas debil que A.

Por ejemplo,

I ¿(p ∧ q) es mas fuerte que p? sı

I ¿(p ∨ q) es mas fuerte que p? no

I ¿p es mas fuerte que (q → p)? sı

I ¿p es mas fuerte que q? no

I ¿p es mas fuerte que p? sı

I ¿hay una formula mas fuerte que todas? sı, por ej. false

I ¿hay una formula mas debil que todas? sı, por ej. true

39

Lenguaje de especificacion

I hasta ahora vimos logica proposicionalI es muy limitada

I nuestro objetivo es especificar (describir problemas)I vamos a usar un lenguaje mas poderoso

I permite hablar de elementos y sus propiedadesI es un lenguaje tipado

I los elementos pertenecen a distintos dominios o conjuntos(enteros, reales, etc.)

40

Page 11: Algoritmos y Estructuras de Datos II

Tipos de datos

I conjunto de valores con operaciones

I vamos a empezar viendo tipos basicosI para hablar de un elemento de un tipo T en nuestro lenguaje,

escribimos un termino o expresionI variable de tipo TI constante de tipo TI funcion (operacion) aplicada a otros terminos (del tipo T o de

otro tipo)

I todos los tipos tienen un elemento distinguido: ⊥ o Indef

41

Tipo Bool (valor de verdad)

I valores: 1, 0 , −I constantes: true, false, ⊥ (o Indef)I conectivos logicos: ¬, ∧, ∨, →, ↔ con la semantica

trivaluada que vimos antes

I ¬A se puede escribir no(A)I (A ∧ B) se puede escribir (A && B)I (A ∨ B) se puede escribir (A || B)I (A→ B) se puede escribir (A --> B)I (A↔ B) se puede escribir (A <--> B)

I comparacion: A == B

I todos los tipos tienen esta operacion (A y B deben ser delmismo tipo T )

I es de tipo boolI es verdadero si el valor de A igual al valor de B (salvo que

alguno este indefinido - ver hoja 47)I A 6= B o A ! = B es equivalente a ¬(A == B)

I semantica secuencial42

Tipo Int (numeros enteros)I sus elementos son los de ZI constantes: 0 ; 1 ; −1 ; 2 ; −2 ; . . .I operaciones aritmeticas

I a + b (suma)I a− b (resta)I a ∗ b (multiplicacion)I a div b (division entera)I a mod b (resto de dividir a a por b)I ab o pot(a,b) (potencia)I abs(a) (valor absoluto)

I comparaciones (de tipo bool)I a < b (menor)I a ≤ b o a <= b (menor o igual)I a > b (mayor)I a ≥ b o a >= b (mayor o igual)

I β o beta. Si A es de tipo Bool, se definide como:

β(A) = beta(A) =

1 si A es verdadero

0 si A es falso

− si A es indefinido 43

Tipo Float (numeros reales)

I sus elementos son los de R

I constantes: 0 ; 1 ; −7 ; 81 ; 7,4552 ; π . . .

I operaciones aritmeticasI las mismas que Int, salvo div y modI a/b (division)I logb(a) (logaritmo)I trigonometricas

I comparaciones (de tipo bool)I las mismas que para Int

I conversion a enteroI bac o int(a)

I todos los terminos de tipo Int pueden usarse como terminosde tipo Float

44

Page 12: Algoritmos y Estructuras de Datos II

Tipo Char (caracteres)

I sus elementos son los las letras, dıgitos y sımbolos

I constantes:‘a‘, ‘b‘, ‘c ‘, . . . , ‘z ‘, . . . , ‘A‘, ‘B‘, ‘C ‘, . . . , ‘Z ‘, . . . , ‘0‘, ‘1‘, ‘2‘, . . . , ‘9‘(en algun orden)

I funcion ord

I numera todos los caracteresI no importa mucho cual es el valor de cada uno, pero

I ord(‘a‘) + 1 == ord(‘b‘)I ord(‘A‘) + 1 == ord(‘B‘)I ord(‘1‘) + 1 == ord(‘2‘)

I funcion charI es la inversa de ord

I las comparaciones entre caracteres son comparaciones entresus ordenes

I a < b es equivalente a ord(a) < ord(b)I lo mismo para ≤, >, ≥

45

Terminos

I simplesI variables del tipo oI constantes del tipo

I complejosI combinaciones de funciones aplicadas a funciones, constantes y

variables

Ejemplos de terminos de tipo Int

I 0 + 1

I ((3 + 4) ∗ 7)2 − 1

I 2 ∗ β(1 + 1 == 2)

I 1 + ord(‘A‘)I con x variable de tipo Int; y de tipo Float; z de tipo Bool

I 2 ∗ x + 1I β(y 2 > π) + xI (x mod 3) ∗ β(z)

46

Semantica de los terminos

I vimos que los terminos representan elementos de los tiposI los terminos tienen valor indefinido cuando no se puede hacer

alguna operacionI 1 div 0I (−1)1/2

I las operaciones son estrictas (salvo los conectivos de bool)I si uno de sus argumentos es indefinido, el resultado tambien

esta indefinidoI ejemplos

I 0 ∗ (−1)1/2 es indefinido (∗ es estricto)I 01/0 es indefinido (pot es estricto)I ((1 + 1 == 2) ∨ (0 > 1/0)) es verdadero (∨ no es estricto)

I las comparaciones con ⊥ son indefinidasI en particular, si x esta indefinido, x == x es indefinido (no es

verdadero)

47

EspecificacionClase 3

Lenguaje de especificacion

48

Page 13: Algoritmos y Estructuras de Datos II

Funciones auxiliares

I Facilitan la lectura y la escritura de especificaciones

I Asignan un nombre a una expresion

aux f (parametros) : tipo = e;

I f es el nombre de la funcion

I Puede usarse en el resto de la especificacion en lugar de laexpresion e

I Los parametros son opcionales

I Se reemplazan en e cada vez que se usa f

I tipo es el tipo del resultado de la funcion (el tipo de e)

Ejemplo

aux suc(x : Int) : Int = x + 1;

Puedo usarla, por ejemplo, en la poscondicion de un problema49

Definir vs. especificar

I Definimos funciones auxiliaresI Expresion del lenguaje a la que la funcion es equivalenteI Esto permite usar la funcion dentro de las especificaciones

I Especificamos problemasI Condiciones (el contrato) que deberıa cumplir alguna funcion

para ser solucion del problemaI No quiere decir que exista esa funcion o que sepamos como

escribirlaI Podrıa no haber ningun algoritmo que sirviera como solucionI Si damos la solucion va a ser en otro lenguaje (por ejemplo,

de programacion)

I En la especificacion de un problema o de un tipo no podemosusar otra funcion que hayamos especificado

50

Tipos enumerados

I Primer mecanismo para definir tipos propios

I Cantidad finita de elementos. Cada uno, representado por unaconstante

tipo Nombre = constantes;

I Nombre (del tipo): tiene que ser nuevo

I constantes: nombres nuevos separados por comas

I Convencion: todos con mayusculas

I ord(a) da la posicion del elemento en la definicion(empezando de 0)

I Opuesta: nombre u ord−1

51

Ejemplo de tipo enumerado

tipo Dıa = Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo;

I ValenI ord(Lunes) == 0I Dıa(2) == MiercolesI Jueves < Viernes

I Podemos definir

aux esFinde(d : Dıa) : Bool = (d == Sabado || d == Domingo);

I Otra forma

aux esFinde2(d : Dıa) : Bool = d > Viernes;

52

Page 14: Algoritmos y Estructuras de Datos II

Secuencias

I Tambien se llaman listasI Familia de tipos

I Para cada tipo de datos hay un tipo secuenciaI Tiene como elementos las secuencias de elementos de ese tipo

I Secuencia: varios elementos del mismo tipo, posiblementerepetidos, ubicados en un cierto orden

I Muy importantes en el lenguaje de especificacion

I [T ]: Tipo de las secuencias cuyos elementos son de tipo T

53

Notacion

I Una forma de escribir un elemento de tipo secuencia de tipoT es escribir varios terminos de tipo T separados por comas,entre corchetes

secuencia de Int: [1, 1 + 1, 3, 2 ∗ 2, 3, 5]

I La secuencia vacıa (de elementos de cualquier tipo) serepresenta []

I Se puede formar secuencias de elementos de cualquier tipoI Como las secuencias de enteros son tipos, existen por ejemplo

las secuencias de secuencias de enteros

secuencia de secuencias de enteros:

[[12, 13], [−3, 9, 0], [5], [], [], [3]]

54

Secuencias por comprensionElementos de otras secuencias que cumplan ciertas condiciones

[expresion | selectores, condiciones]

I expresion: cualquier expresion valida del lenguajeI selectores: variable ← secuencia (se puede usar ∈)

I La variable va tomando el valor de cada elemento de lasecuencia

I Las variables que aparecen en selectores se llaman ligadas, elresto de las que aparecen en una expresion se llaman libres

I condiciones: expresiones de tipo BoolI Resultado: Secuencia con el valor de la expresion calculado

para todos los elementos seleccionados por los selectores quecumplen las condiciones

Ejemplo:

[(x , y)|x ← [1, 2], y ← [1, 2, 3], x < y ] == [(1, 2), (1, 3), (2, 3)]

55

Intervalos

[expresion1..expresion2]

I Las expresiones tienen que ser del mismo tipo, discreto ytotalmente ordenado (por ejemplo, Int, Char, enumerados)

I Resultado: todos los valores del tipo entre el de la expresion1

y el de la expresion2 (ambos inclusive)

I Si no vale expresion1 ≤ expresion2, la secuencia es vacıa

I Con un parentesis en lugar de un corchete, se excluye uno delos extremos o ambos

Ejemplos:

I [5..9] == [5, 6, 7, 8, 9]

I [5..9) == [5, 6, 7, 8]

I (5..9] == [6, 7, 8, 9]

I (5..9) == [6, 7, 8]

56

Page 15: Algoritmos y Estructuras de Datos II

Ejemplos de secuencias por comprension

Divisores comunes (asumir a y b positivos)

aux divCom(a, b : Int) : [Int] =

[x |x ← [1..a + b], divide(x , a), divide(x , b)];

aux divide(a, b : Int) : Bool = b mod a == 0;

Ejemplo:

divCom(8, 12) == [1, 2, 4]

57

Ejemplos de secuencias por comprension

Cuadrados de los elementos impares

aux cuadImp(a : [Int]) : [Int] = [x ∗ x |x ← a,¬divide(2, x)];

Ejemplo:

cuadImp([1..9)) == [1, 9, 25, 49]

58

Ejemplos de secuencias por comprension

Suma de los elementos distintos

aux sumDist(a, b : [Int]) : [Int] = [x + y |x ← a, y ← b, x 6= y ];

Ejemplo:

sumDist([1, 2, 3], [2, 3, 4, 5]) == [3, 4, 5, 6, 5, 6, 7, 5, 7, 8]

59

Operaciones con secuencias

I Longitud: long(a : [T ]) : IntI Longitud de la secuencia aI Notacion: long(a) se puede escribir |a|

I Indexacion: indice(a : [T ], i : Int) : TI requiere 0 ≤ i < |a|;I Elemento en la i-esima posicion de aI La primera posicion es la 0I Notacion: indice(a, i) se puede escribir a[i ] y tambien ai

I Cabeza: cab(a : [T ]) : TI requiere |a| > 0;I Primer elemento de la secuencia

60

Page 16: Algoritmos y Estructuras de Datos II

Mas operaciones

I Cola: cola(a : [T ]) : [T ]I requiere |a| > 0;I La secuencia sin su primer elemento

I Pertenencia: en(t : T , a : [T ]) : BoolI Indica si el elemento aparece (al menos una vez) en la

secuenciaI Notacion: en(t, a) se puede escribir t en a y tambien t ∈ aI t /∈ a es ¬(t ∈ a)

I Agregar cabeza: cons(t : T , a : [T ]) : [T ]I Una secuencia como a, agregandole t como primer elementoI Notacion: cons(t, a) se puede escribir t : a

61

Mas operaciones

I Concatenacion: conc(a, b : [T ]) : [T ]I Secuencia con los elementos de a, seguidos de los de bI Notacion: conc(a, b) se puede escribir a + +b

I Subsecuencia: sub(a : [T ], d , h : Int) : [T ]I Sublista de a en las posiciones entre d y h (ambas inclusive)I Cuando no es 0 ≤ d ≤ h < |a|, da la secuencia vacıa

I Asignacion a una posicion:cambiar(a : [T ], i : Int, val : T ) : [T ]

I requiere 0 ≤ i < |a|;I Igual a la secuencia a, pero el valor en la posicion i es val

62

Subsecuencias con intervalos

I Notacion para obtener una subsecuencia de una secuenciadada, en un intervalo de posiciones

I Admite intervalos abiertosI a[d ..h] == sub(a, d , h)I a[d ..h) == sub(a, d , h − 1)I a(d ..h] == sub(a, d + 1, h)I a(d ..h) == sub(a, d + 1, h − 1)I a[d ..] == sub(a, d , |a| − 1)I a(d ..] == sub(a, d + 1, |a| − 1)

63

Operaciones de combinacion

I Todos verdaderos: todos(sec : [Bool]) : BoolEs verdadero solamente si todos los elementos de la secuenciason True (o la secuencia es vacıa)

I Alguno verdadero: alguno(sec : [Bool]) : BoolEs verdadero solamente si algun elemento de la secuencia esTrue (y ninguno es Indef)

64

Page 17: Algoritmos y Estructuras de Datos II

Operaciones de combinacion

I Sumatoria: sum(sec : [T ]) : TI T debe ser un tipo numerico (Float, Int)I Calcula la suma de todos los elementos de la secuenciaI Si sec es vacıa, el resultado es 0I Notacion: sum(sec) se puede escribir

∑sec

I Ejemplo:aux potNegDosHasta(n : Int) : Float =

∑[2−m|m← [1..n]];

I Productoria: prod(sec : [T ]) : TI T debe ser un tipo numerico (Float, Int)I Calcula el producto de todos los elementos de la secuenciaI Si sec es vacıa, el resultado es 1I Notacion: prod(sec) se puede escribir

∏sec

65

Para todo

(∀ selectores, condiciones) expresion

I Termino de tipo BoolI Afirma que todos los elementos de una lista por comprension

cumplen una propiedadI Notacion: en lugar de ∀ se puede escribir paratodoI Equivale a todos([expresion | selectores, condiciones])

I Ejemplo: “todos los elementos en posiciones pares sonmayores que 5”:

auxpar(n : Int) : Bool = n mod 2 == 0;

aux posParM5(a : [Float]) : Bool =(∀i ← [0..|a|), par(i)) a[i ] > 5;

Esta expresion es equivalente a

todos([a[i ] > 5|i ← [0..|a|), par(i)]);66

Existe

(∃ selectores, condiciones)expresion

I Hay algun elemento que cumple la propiedad

I Equivale a alguno([expresion | selectores, condiciones])

I Notacion: en lugar de ∃ se puede escribir existe o existen

I Ejemplo: “Hay algun elemento de la lista que es par y mayorque 5”:

aux hayParM5(a : [Int]) : Bool = (∃x ← a, par(x)) x > 5;

Es equivalente a

alguno([x > 5|x ← a, par(x)]);

67

CantidadesI Es habitual querer contar cuantos elementos de una secuencia

cumplen una condicionI Para eso, medimos la longitud de una secuencia definida por

comprension

Ejemplos:

I “¿cuantas veces aparece el elemento x en la secuencia a?”

aux cuenta(x : T , a : [T ]) : Int = long([y |y ← a, y == x ]);

Podemos usarla para saber si dos secuencias tienen los mismoselementos (en otro orden)

aux mismos(a, b : [T ]) : Bool =(|a| == |b| ∧ (∀c ← a) cuenta(c , a) == cuenta(c, b));

I “¿cuantos primos positivos hay que sean menores a n?”

aux primosMenores(n : Int) : Int = long([y | y ← [0..n), primo(y)]);aux primo(n : Int) : Bool =

(n ≥ 2 ∧ ¬(∃m← [2..n)) n mod m == 0);68

Page 18: Algoritmos y Estructuras de Datos II

Acumulacion

acum(expresion | inicializacion, selectores, condicion)

I Notacion parecida a las secuencias por comprensionI Construye un valor a partir de una o mas secuenciasI inicializacion tiene la forma acumulador : tipoAcum = init

I acumulador es un nombre de variable (nuevo)I init es una expresion de tipo tipoAcum

I selectores y condicion: Como en las secuencias porcomprension

I expresion: Tambien, pero puede (y suele) aparecer elacumulador

I acumulador no puede aparecer en la condicion

I Significado:I El valor inicial de acumulador es el valor de initI Por cada valor de los selectores, se calcula la expresionI Ese es el nuevo valor que toma el acumuladorI El resultado de acum es el resultado final del acumulador (de

tipo tipoAcum) 69

Ejemplos de acumulacionI aux sum(l : [Float]) : Float = acum(s+i | s : Float = 0, i ← l);

I Productoria

aux prod(l : [Float]) : Float =acum(p ∗ i | p : Float = 1, i ← l);

I Fibonacciaux fiboSuc(n : Int) : [Int] =

acum(f ++[f [i−1]+f [i−2]] | f : [Int] = [1, 1], i ← [2..n]);

I si n ≥ 1, devuelve los primeros n + 1 numeros de FibonacciI si n == 0, devuelve [1, 1]

I por ejemplo, fiboSuc(5) == [1, 1, 2, 3, 5, 8]

I n-esimo numero de Fibonacci (n ≥ 1)

aux fibo(n : Int) : Int = (fiboSuc(n − 1))[n − 1];

I por ejemplo, fibo(6) == 8

70

Mas ejemplos de acumulacion

I Concatenacion de elementos de una secuencia de secuencias(aplanar)

aux concat(a : [[T ]]) : [T ] =acum(l + +c | l : [T ] = [], c ← a);

I por ejemplo, concat([[1, 2], [3], [4, 5, 6]]) == [1, 2, 3, 4, 5, 6]

I Secuencias por comprension

El termino [expresion | selectores, codicion] es equivalente a

acum(res + +[expresion] | res : [T ] = [], selectores, codicion);

71

Especificacion de problemas

I Problema: funcion a definir

I Especificacion: contrato que debe cumplir la funcion para serconsiderada solucion del problema

I Hay que distinguirI el que (especificacion, el contrato a cumplir)I el como (implementacion de la funcion)

I Sin referencias a posibles metodos para resolver el problemaI Distintas soluciones a un mismo problema

I Distintos lenguajes de programacionI Para el mismo lenguaje de programacion, distintas formas de

programar una funcion que cumpla con la especificacionI Cada algoritmo posible es una solucion distinta para el

problema

I Conclusion: hay un conjunto (tal vez vacıo) de algoritmos quecumplen cada especificacion

72

Page 19: Algoritmos y Estructuras de Datos II

Ejemplos de especificacionI Calcular el cociente de dos enteros

problema division(a, b : Int) = result : Int {requiere b 6= 0;asegura result == a div b;

}

I Calcular el cociente y el resto, para divisor positivoI Necesitamos devolver dos valoresI Usamos una tuplaI El tipo (Int, Int) son los pares ordenados de enterosI prm y sgd devuelven sus componentes

problema cocienteResto(a, b : Int) = result : (Int,Int) {requiere b > 0;asegura a == q ∗ b + r ∧ 0 ≤ r < b;aux q = prm(result), r = sgd(result);

}73

Parametros modificablesI Alternativa 2

I Unico resultado: el cocienteI Resto: parametro modificable

problema cocienteResto2(a, b, r : Int) = q : Int {requiere b > 0;modifica r ;asegura a == q ∗ b + r ∧ 0 ≤ r < b;

}

I Alternativa 3I Otro parametro para el cocienteI La funcion no tiene resultado

problema cocienteResto3(a, b, q, r : Int){requiere b > 0;modifica q, r ;asegura a == q ∗ b + r ∧ 0 ≤ r < b;

}74

Mas ejemplos de especificacion

I Sumar los inversos multiplicativos de varios reales

Como no sabemos la cantidad, usamos secuencias

problema sumarInvertidos(a : [Float]) = result : Float {requiere 0 /∈ a;asegura result =

∑[1/x | x ← a];

}

I Precondicion: que el argumento no contenga ningun 0I Si no, la poscondicion podrıa indefinirseI Formas equivalentes:

I requiere (∀x ← a) x 6= 0;I requiere ¬(∃x ← a) x == 0;I requiere ¬(∃i ← [0..|a|)) a[i ] == 0;

75

Mas ejemplos de especificacionI Encontrar una raız de un polinomio de grado 2 a coeficientes

reales

problema unaRaızPoli2(a, b, c : Float) = r : Float {asegura a ∗ r ∗ r + b ∗ r + c == 0;

}I No tiene precondicion (la precondicion es True)I Pero si a == 1, b == 0 y c == 1, no existe ningun r tal que

r ∗ r + 1 == 0I Especificacion que no puede ser cumplida por ninguna funcionI La precondicion es demasiado debilI La nueva precondicion podrıa ser:

requiere b ∗ b ≥ 4 ∗ a ∗ c ;I La poscondicion describe que hacer y no como hacerlo

No dice como calcular la raız, ni que raız devolverI Sobrespecificacion: poscondicion que pone mas restricciones de

las necesarias (fija la forma de calcular la solucion)Ejemplo: asegura r == (−b + (b2 − 4 ∗ a ∗ c)1/2)/(2 ∗ a)

I esto serıa sobreespecificar aun con a 6= 0 en la precondicion76

Page 20: Algoritmos y Estructuras de Datos II

Otro ejemplo

Encontrar el ındice (la posicion) del menor elemento en unasecuencia de numeros reales distintos no negativos

problema ındiceMenorDistintos(a : [Float]) = res : Int {requiere NoNegativos: (∀x ← a) x ≥ 0;requiere Distintos: (∀i ← [0..|a|), j ← [0..|a|), i 6= j) ai 6= aj ;asegura 0 ≤ res < |a|;asegura (∀x ← a) a[res] ≤ x ;

}I Nombramos las precondiciones, para aclarar su significado

I Los nombres tambien pueden usarse como predicados encualquier lugar de la especificacion

I El nombre no alcanza, hay que escribir la precondicion en ellenguaje

I Otra forma de escribir la segunda precondicion:requiere Distintos2: (∀i ← [0..|a|)) a[i ] /∈ a[0..i);

77

EspecificacionClase 4

Tipos compuestos

78

Tipos compuestos

I cada valor de un tipo basico representa un elemento atomico,indivisible

I IntI FloatI BoolI Char

I un valor de un tipo compuesto contiene informacion quepuede ser dividida en componentes de otros tipos

I ya vimos dos ejemplos de tipos compuestos:I secuencias: un valor de tipo secuencia de enteros tiene varios

componentes, cada uno es un enteroI tuplas: un valor de tipo par ordenado de enteros tiene dos

componentes

I para definir un tipo compuesto, tenemos que darleI un nombreI uno o mas observadores

79

Observadores

I funciones que se aplican a valores del tipo compuesto ydevuelven el valor de sus componentes

I pueden tener mas parametros

I definen el tipo compuestoI si dos terminos del tipo dan el mismo resultado para todos los

observadores, se los considera igualesI esta es la definicion implıcita de la igualdad == para tipos

compuestos (el == esta en todos los tipos)

I pueden tener precondicionesI si vale la precondicion, no pueden devolver un valor indefinido

I no tienen poscondiciones propias

I si hay condiciones generales que deben cumplir los elementosdel tipo, se las presenta como invariantes de tipo

80

Page 21: Algoritmos y Estructuras de Datos II

Tipo PuntoI un punto en el planoI componentes: coordenadas (x e y)I un observador para obtener cada una

tipo Punto {observador X (p : Punto) : Float;observador Y (p : Punto) : Float

}I especificacion una funcion que recibe dos numeros reales y

construye un punto con esas coordenadas:

problema nuevoPunto(a, b : Float) = res : Punto {asegura X (res) == a;asegura Y (res) == b;

}

Cuando el resultado es de un tipo compuesto, usamos losobservadores para describir el resultado

I funcion auxiliar para calcular la distancia entre dos puntosaux dist(p, q : Punto) : Float =

((X (p)− X (q))2 + (Y (p)− Y (q))2

)1/2

81

Tipo CırculoI sus componentes son de tipos distintos

tipo Cırculo {observador Centro(c : Cırculo) : Punto;observador Radio(c : Cırculo) : Float;invariante Radio(c) > 0;

}I especificar el problema de construir un cırculo a partir de

I su centro y su radio

problema nuevoCırculo(c : Punto, r : Float) = res : Cırculo {requiere r > 0;asegura (Centro(res) == c ∧ Radio(res) == r);

}I su centro y un punto sobre la circunferencia:

problema nuevoCırculoPuntos(c , x : Punto) = res : Cırculo {requiere dist(c , x) > 0;asegura (Centro(res) == c ∧ Radio(res) == dist(c , x));

}82

Invariantes de tipo

I son la garantıa de que los elementos esten bien construidos

I deben cumplirse para cualquier elemento del tipo

I los problemas que reciban valores del tipo compuesto comoargumentos pueden suponer que se cumplen los invariantes

tipo T {observador . . . ;

...invariante R(x);

}

problema probA(. . . , x : T, . . . ) = . . . {requiere . . . ∧ R(x)︸︷︷︸

no hace falta

∧ . . . ;

asegura . . . ;

}

83

Tipos genericosI en los ejemplos vistos, cada componente es de un tipo

determinado de antemanoI tambien hay tipos compuestos que representan una estructura

I su contenido van a ser valores no siempre del mismo tipoI comportamiento uniforme

I se llaman tipos genericos o tipos parametricosI definen una familia de tipos

I cada elemento de la familia es una instancia del tipo genericoI los problemas que usen un tipo generico definen una familia de

problemasI permiten definir funciones auxiliares o especificar problemas

I genericos: su descripcion depende unicamente de la estructuradel tipo generico

I especıficos de un tipo: su descripcion solo tiene sentido paraun cierto tipo

I el nombre del tipo tiene parametrosI variables que representan a los tipos de los componentesI los parametros de tipo se escriben entre los sımbolos 〈 y 〉

despues del nombre del tipo

84

Page 22: Algoritmos y Estructuras de Datos II

Tipo Matriz〈T 〉I tipo generico de las matrices cuyos elementos pertenecen a un

tipo cualquiera T

tipo Matriz〈T 〉{observador filas(m : Matriz〈T 〉) : Int;observador columnas(m : Matriz〈T 〉) : Int;observador val(m : Matriz〈T 〉, f , c : Int) : T {

requiere 0 ≤ f < filas(m);requiere 0 ≤ c < columnas(m);

}

precondicion del observador

invariante filas(m) > 0;invariante columnas(m) > 0;

}I ejemplo: una instancia del tipo generico Matriz〈T 〉 es

Matriz〈Char〉I el tipo de matrices cuyos elementos son caracteres

I un tipo generico define una familia (infinita) de tiposI algunos miembros de la familia Matriz〈T 〉 son

Matriz〈Int〉 , Matriz〈Punto〉 , Matriz〈Matriz〈Float〉〉85

Operaciones genericas con matrices

I expresion que cuenta la cantidad de elementos de una matriz

aux elementos(m : Matriz〈T 〉) : Int = filas(m) ∗ columnas(m);

I especificacion del problema de cambiar el valor de unaposicion de una matriz

problema cambiar(m : Matriz〈T 〉, f , c : Int, v : T ) {requiere 0 ≤ f < filas(m);requiere 0 ≤ c < columnas(m);modifica m;asegura filas(m) == filas(pre(m));asegura columnas(m) == columnas(pre(m));asegura val(m, f , c) == v ;asegura (∀i ← [0..filas(m)))

(∀j ← [0..columnas(m)),¬(i == f ∧ j == c))val(m, i , j) == val(pre(m), i , j);

}

86

Operaciones sobre matrices para tipos instanciados

I expresion que suma los elementos de una matriz de enteros

aux suma(m : Matriz〈Int〉) : Int =∑[val(m, i , j) | i ← [0..filas(m)), j ← [0..columnas(m))];

I especificacion del problema de construir la matriz identidad den × n:

problema matId(n : Int) = ident : Matriz〈Int〉 {requiere n > 0;asegura filas(ident) == columnas(ident) == n;asegura (∀i ← [0..n)) val(ident, i , i) == 1;asegura (∀i ← [0..n))(∀j ← [0..n), i 6= j) val(ident, i , j) == 0;

}

I ¿importa el orden?I sı; si estuviera al reves, se podrıa indefinir val(ident, i , i)I en este caso, se indefinirıa la poscondicion, valiendo la

precondicion

87

El tipo Secuencia〈T 〉

I ya lo usamos con su nombre alternativo: [T ]

I presentamos tambien sus observadores: longitud e indexacion

tipo Secuencia〈T 〉{observador long(s : Secuencia〈T 〉) : Int;observador ındice(s : Secuencia〈T 〉, i : Int) : T{

requiere 0 ≤ i < long(s);−→ precondicion de observador}

}I notaciones alternativas

I |s| para la longitudI si o s[i ] para la indexacion

88

Page 23: Algoritmos y Estructuras de Datos II

Operaciones genericas con secuencias

I podemos definirI aux ssc(a, b : [T ]) : Bool =

(∀i ← [0..|b| − |a|)) a == b[i ..(i + |a|));I aux cab(a : [T ]) : T = a[0];I aux cola(a : [T ]) : [T ] = a[1..|a|);I aux en(t : T , a : [T ]) : Bool = [x | x ← a, x == t] 6= [ ];I aux sub(a : [T ], d , h : Int) : [T ] =

[a[i ] | i ← [d ..h], (0 ≥ ∧h < |a|)];I aux todos(sec : [Bool]) : Bool = false /∈ sec ;I aux alguno(sec : [Bool]) : Bool = true ∈ sec ;

I para algunas no usamos directamente los observadores

I aprovechamos la notacion de listas por comprension

I el selector es parte de la notacion de listas por comprension(estructura especial de nuestro lenguaje de especificacion)

89

Operaciones sobre secuencias para tipos instanciadosI para representar textos (cadenas de caracteres) usamos el tipo

Secuencia〈Char〉 (o [Char])I queremos ver si alguna palabra de una lista aparece en un libro

problema hayAlguna(palabras : [[Char]], libro : [Char]) = res : Bool{requiere NoVacıas : (∀p ← palabras) |p| > 0;requiere SinEspacios : ¬(∃p ← palabras) ‘ ‘ ∈ p;asegura res == (∃p ← palabras) ssc(p, libro);

}I lista de palabras: tipo [[Char]] o Secuencia〈Secuencia〈Char〉〉

I secuencias que en cada posicion tienen una secuencia decaracteres

I precondicionesI cada palabra debe tener al menos una letraI no contienen ningun espacio (dejarıan de ser palabras)

I en vez de SinEspacios: que las palabras no contengan ningunsımbolo que no sea una letra

requiere SinSımbolos: (∀p ← palabras) soloLetras(p);aux letras: [Char ] = [‘A‘..‘Z ‘] + +[‘a‘..‘z ‘];

aux soloLetras(s : [Char]) : Bool = (∀l ← s) l ∈ letras; 90

Tuplas

I ya las mencionamos

I secuencias de tamano fijo

I cada elemento puede pertenecer a un tipo distinto

I ejemplos: pares, ternas

tipo Par〈A,B〉{observador prm(p : Par〈A,B〉) : A;observador sgd(p : Par〈A,B〉) : B;

}

tipo Terna〈A,B,C 〉{observador prm3(t : Terna〈A,B,C 〉) : A;observador sgd3(t : Terna〈A,B,C 〉) : B;observador trc3(t : Terna〈A,B,C 〉) : C ;

}I notacion

I Par〈A,B〉 tambien se puede escribir (A,B)I Terna〈A,B,C 〉 tambien se puede escribir (A,B,C )

91

ifThenElse〈T 〉Funcion que elige entre dos elementos del mismo tipo, segun unacondicion (guarda)

I si la guarda es verdadera, elige el primeroI si no, elige el segundo

Por ejemplo

I expresion que devuelve el maximo entre dos elementos:

aux max(a, b : Int) : Int = ifThenElse〈Int〉(a > b, a, b)

cuando los argumentos se deducen del contexto, se puedeescribir directamente

aux max(a, b : Int) : Int = ifThenElse(a > b, a, b) o bienaux max(a, b : Int) : Int = if a > b then a else b

I expresion que dado x devuelve 1/x si x 6= 0 y 0 sino

aux unoSobre(x : Float) : Float = if x 6= 0 then 1/x else 0︸ ︷︷ ︸no se indefine cuando x = 0

92

Page 24: Algoritmos y Estructuras de Datos II

Mas aplicaciones de IfThenElse

I agregar un elemento como primer elemento de una lista

aux cons(x : T , a : [T ]) : [T ] =

[if i == −1 then x else a[i ] | i ← [−1..|a|)];

I concatenar dos listas

aux conc(a, b : [T ]) : [T ] =

[if i < |a| then a[i ] else b[i − |a|] | i ← [0..|a|+ |b|)];

I cambiar el valor de una posicion

aux cambiar(a : [T ], i : Int, v : T ) : [T ] =[if i 6= j then a[i ] else v | j ← [0..|a|)];

93

Programacion funcionalClase 1

Funciones Simples - recursion - tipos de datos

94

Algoritmos y programas

I aprendieron a especificar problemasI el objetivo es ahora escribir un algoritmo que cumpla esa

especificacionI secuencia de pasos que pueden llevarse a cabo mecanicamente

I puede haber varios algoritmos que cumplan una mismaespecificacion

I una vez que se tiene el algoritmo, se escribe el programaI expresion formal de un algoritmoI lenguajes de programacion

I sintaxis definidaI semantica definidaI que hace una computadora cuando recibe ese programaI que especificaciones cumpleI ejemplos: Haskell, C, C++, C#, Java, Smalltalk, Prolog, etc.

95

Paradigmas

I paradigmas de programacionI formas de pensar un algoritmo que cumpla una especificacionI cada uno tiene asociado un conjunto de lenguajesI nos llevan a encarar la programacion segun ese paradigma

I Haskell: paradigma de programacion funcionalI programa = coleccion de funciones

I aparatos que transforman datos de entrada en un resultado

I los lenguajes funcionales nos dan herramientas para explicarlea la computadora como calcular esas funciones

96

Page 25: Algoritmos y Estructuras de Datos II

Expresiones

I tira de sımbolos que representan (denotan) un valorI ejemplos:

I 2I 1+1I (3*7+1)/11I todas representan el mismo valor

I los valores se agrupan en tiposI como en el lenguaje de especificacion: Int, Float, Bool, CharI hay tambien tipos compuestos (por ejemplo, pares ordenados)

97

Transparencia referencial

I propiedad muy importante de la programacion funcional

Una expresion representa siempre el mismo valoren cualquier lugar de un programa

I otros paradigmas: el significado de una expresion depende delcontexto

I muy util al modificar programasI modificar una parte no afecta otras

I tambien para verificar (demostrar que se cumple laespecificacion)

I podemos usar propiedades ya probadas para sub expresionesI valor no depende de la historiaI valen en cualquier contexto

98

Formacion de expresiones

I expresiones atomicas (las mas simples)I tambien se llaman formas normalesI son la forma mas intuitiva de representar un valorI ejemplos

I 2I FalseI (3, True)

I es comun llamarlas “valores”I aunque no son un valor, representan un valor, como las demas

expresiones

I expresiones compuestasI se construyen combinando expresiones atomicas con

operacionesI ejemplos:

I 1+1I 1==2I (4-1, True || False)

99

Expresiones mal formadas

I algunas cadenas de sımbolos no forman expresionesI por problemas sintacticos

I +*1-I (TrueI (’a’,)

I o por error de tiposI 2 + FalseI 2 || ’a’I 4 * ’b’

I para saber si una expresion esta bien formada, aplicamosI reglas sintacticasI reglas de asignacion de tipos (o de inferencia de tipos)

100

Page 26: Algoritmos y Estructuras de Datos II

Aplicacion de funciones

En programacion funcional (como en matematica) las funcionesson elementos (valores)

I una funcion es un valorI la operacion basica que podemos realizar con ese valor es la

aplicacionI aplicar la funcion a un elemento para obtener un resultado

I sintacticamente, la aplicacion se escribe como unayuxtaposicion (la funcion seguida de su parametro)

I f es una funcion y e un elemento de su conjunto de partidaI f e denota el elemento que se relaciona con e por medio de la

funcion f

I por ejemplo, doble 2 representa al numero 4

101

Ecuaciones

I Dada una expresion, ¿como sabemos que valor denota?I Usando las ecuaciones que la definen

I por ejemplo: doble x = x + x

I se reemplaza cada sub expresion por otras segun lasecuaciones

I pero este proceso puede no terminarI aun con ecuaciones bien pensadas

doble (1 + 1)I reemplazo 1 + 1 por doble 1

doble (doble 1)I reemplazo doble 1 por 1 + 1I volvı a empezar...

102

Ecuaciones orientadasI solucion: usar ecuaciones orientadas

I lado izquierdo: expresion a definirI lado derecho: definicion

I calculo de valores = reemplazar subexpresiones que sean ladoizquierdo de una ecuacion por su lado derecho

Ejemplo: doble x = x + xdoble (1 + 1) (1 + 1) + (1 + 1) 2 + (1 + 1) 2 + 2 4

Tambien podrıa ser:doble (1 + 1) doble 2 2 + 2 4

Mas adelante veremos como funciona Haskell en particular.

I reduccion = reemplazar una subexpresion por su definicion,sin tocar el resto

I la expresion resultante puede no ser mas cortaI pero seguramente esta “mas definida”

I mas cerca de ser una forma normal

103

Programa funcional

I conjunto de ecuaciones que definen una o mas funcionesI ¿para que se usa un programa funcional?

I para reducir expresionesI puede no ser tan claro que esto resuelva un problemaI las ecuaciones orientadas, junto con el mecanismo de reduccion

describen algoritmos: pasos para resolver un problema

Ejemplos:

I doble x = x+x

I fst (x,y) = x

I dist (x,y) = sqrt (x^2+y^2)

I signo 0 = 0

signo x | x > 0 = 1

signo x | x < 0 = -1

I promedio1 (x,y) = (x+y)/2

I promedio2 x y = (x+y)/2

I fact 0 = 1

fact n | n > 0 = n * fact (n-1)

I fib 1 = 1

fib 2 = 1

fib n | n > 2 = fib (n-1) + fib (n-2)

104

Page 27: Algoritmos y Estructuras de Datos II

Definiciones recursivas

I en el cuerpo de la definicion de fact y fib (lado derecho)aparece el nombre de la funcion

I propiedades de la definicionI tiene que tener uno o mas casos bases

I en el caso de fact el caso base es

fact 0 = 1

I en el caso de fib los casos bases son

fib 1 = 1 y fib 2 = 1

I las llamadas recursivas del lado derecho tienen que acercarsemas al caso base

I en el caso de fact la llamada recursiva es

fact (n-1)

I en el caso de fib las llamadas recursivas son

fib (n-1) y fib (n-2)

105

Asegurarse de llegar a un caso base

Supongamos esta especificacion:problema par(n : Int) = result : Bool{

requiere n ≥ 0;asegura result == (n mod 2 == 0);

}I ¿este programa cumple con la especificacion?

par 0 = Truepar n = par (n-2)

I no, porque se indefine para los impares positivos

I se arregla de alguna de estas formas:

par 0 = Truepar 1 = Falsepar n = par (n-2)

par 0 = Truepar n = not (par (n-1))

106

Correctitud

I para demostrar que una definicion es correcta, hace falta una especificaciony un programa:

problema fact(n : Int) = result : Int{requiere n ≥ 0;asegura result ==

∏[1..n];

}

fact 0 = 1fact n | n > 0 = n * fact (n-1)

I la especificacion (o cualquier otro comentario) se puede escribir en elmismo programa funcional precediendo cada linea con -- (doble menos)

I no se considera parte del programaI por ejemplo:

-- problema fact (n: Int) = result: Int {-- requiere n >= 0;-- asegura result == prod [1..n];-- }fact 0 = 1fact n | n > 0 = n * fact (n-1)

107

Demostracion de correctitudSi la definicion es recursiva, lo mas natural es demostrar porinduccion

I caso base (n == 0)I la especificacion dice que hay que probar que la funcion fact

con entrada 0 devuelve∏

[1..0] ==∏

[ ] = 1I pero eso es justamente lo que devuelve fact en el caso base

I hipotesis inductiva (HI): fact(n) ==∏

[1..n]I la especificacion dice que hay que probar que la funcion fact

con entrada n + 1 devuelve∏

[1..n + 1]I calculemos fact(n + 1)I gracias a la precondicion, n + 1 > 0. Entonces uso la segunda

ecuacion instanciando en n + 1

fact(n + 1) == (n + 1) ∗ fact(n)

I por HI:

fact(n + 1) == (n + 1) ∗∏

[1..n]

==∏

[1..(n + 1)]

I entonces, demostre que fact con entrada n + 1 devuelve∏[1..(n + 1)]

108

Page 28: Algoritmos y Estructuras de Datos II

Tipos de datosI es un concepto que vimos en el lenguaje de especificacionI conjunto de valores a los que les pueden aplicar las mismas

operacionesI en Haskell, todo valor pertenece a algun tipo

I las funciones son valores, y tambien tienen tipoI ejemplo: el tipo “funciones de enteros en enteros”

I todo valor pertenece a un tipo. Toda expresion (bien formada)denota un valor. Entonces, toda expresion tiene un tipo (el delvalor que representa)

Haskell es un lenguaje fuertemente tipadoI no se pueden pasar elementos de un tipo a una operacion que

espera argumentos de otro

Tambien tiene tipado estaticoI no hace falta hacer funcionar un programa para saber de

que tipo son sus expresionesI el interprete puede controlar si un programa tiene errores de

tipos109

Notacion para tiposI e :: T

I la expresion e es de tipo TI el valor denotado por e pertenece al conjunto de valores

llamado TI ejemplos:

I 2 :: IntI False :: BoolI ’b’:: CharI doble :: Int -> Int

I sirve para escribir reglas y razonar sobre HaskellI tambien se usa dentro de Haskell

I indica de que tipo queremos que sean los nombres quedefinimos

I el interprete chequea que el tipo coincida con el de lasexpresiones que lo definen

I podemos obviar las declaraciones de tipos pero nos perdemosla oportunidad del doble chequeo

I existen casos en los que sı es obligatorio, para dirimirambiguedades

110

PolimorfismoI el tipado de Haskell es fuerteI pero hay funciones que pueden aplicarse a distintos tipos de

datos (sin redefinirlas)I se llama polimorfismo

I se usa cuando el comportamiento de la funcion no depende delvalor de sus parametros

I lo vimos en el lenguaje de especificacion con las funcionesgenericas

I ejemplo: la funcion identidad: id x = xI ¿de que tipo es id?

I id 3: Por las reglas, id :: Int -> IntI id True: Por las reglas, id :: Bool -> BoolI id doble: Por las reglas, id :: (Int -> Int) -> (Int ->

Int)I la idea es id :: a -> a

I sin importar que tipo sea aI en Haskell se escribe usando variables de tipo.I “id es una funcion que dado un elemento de algun tipo a

devuelve otro elemento de ese mismo tipo”I indica que id es de de un tipo parametrico (depende de un

parametro)I id es una funcion polimorfica

111

Declaraciones de tipo

I doble :: Int -> Int

doble x = x+x

I fst :: (a,b) -> a

fst (x,y) = x

I dist :: (Float, Float) -> Float

dist (x,y) = sqrt (x^2+y^2)

I signo Int -> Int

signo 0 = 0

signo x | x > 0 = 1

signo x | x < 0 = -1

I promedio1 :: (Float, Float) -> Float

promedio1 (x,y) = (x+y)/2

I promedio2 :: Float -> Float -> Float

promedio2 x y = (x+y)/2

I fact :: Int -> Int

fact 0 = 1

fact n | n > 0 = n * fact (n-1)

I fact :: Int -> Int

fib 1 = 1

fib 2 = 1

fib n | n > 2 = fib (n-1) + fib (n-2)

112

Page 29: Algoritmos y Estructuras de Datos II

Currificacion

I diferencia entre promedio1 y promedio2I promedio1 :: (Float, Float) -> Float

promedio1 (x,y) = (x+y)/2I promedio2 :: Float -> Float -> Float

promedio2 x y = (x+y)/2

I solo cambia el tipo de datos de la funcionI promedio1 recibe un solo parametro (un par)I promedio2 recibe dos Float separados por un espacioI para declararla, separamos los tipos de los parametros con una

flechaI tiene motivos teoricos y practicos (que no veremos ahora)

I la notacion se llama currificacion en honor al matematicoHaskell B. Curry

I para nosotros, alcanza con ver que evita el uso de variossignos de puntuacion (comas y parentesis)

I promedio1 (promedio1 (2, 3), promedio1 (1, 2))I promedio2 (promedio2 2 3) (promedio2 1 2)

113

Programacion funcionalClase 2

Tipos algebraicos

114

Tipos algebraicos y abstractos

I ya vimos los tipos basicosI IntI FloatI CharI Bool

I otros tipos de datos:I tipos algebraicoI tipos abstracto

I tipo algebraicoI conocemos la forma que tiene cada elementoI tenemos un mecanismo para inspeccionar como

esta construido cada dato

I tipo abstractoI solo conocemos sus operacionesI no sabemos como estan formados los elementosI la unica manera de obtener informacion sobre ellos es mediante

las operaciones

115

Tipos algebraicos

I para crear un tipo algebraico decimos que forma va a tenercada elemento

I se hace definiendo constantes que se llaman constructoresI empiezan con mayuscula (como los tipos)I pueden tener argumentos, pero no hay que confundirlos con

funcionesI no tienen reglas de inferencia asociadaI forman expresiones atomicas (valores)

I ejemplo muy sencillo de tipo algebraico: BoolI tiene dos constructores (sin argumentos)

True :: BoolFalse :: Bool

116

Page 30: Algoritmos y Estructuras de Datos II

Definicion de tipos algebraicosI clausulas de definicion de tipos algebraicos

I empiezan con la palabra dataI definen el tipo y sus constructoresI cada constructor da una alternativa distinta para construir un

elemento del tipoI los constructores se separan entre sı por barras verticales

I data Sensacion = Frıo | CalorI tiene dos constructores sin parametrosI el tipo tiene unicamente dos elementos, como el tipo Bool

I data Figura = Cırc Float | Rect Float FloatI dos constructores con parametrosI algunas figuras son cırculos y otras rectangulos

I los cırculos se diferencian por un numero (su radio)I los rectangulos, por dos (su base y su altura)

I ejemplos:I c1 = Cırc 1I c2 = Cırc (4.5 - 3.5)I cırculo x = Cırc (x+1)I r1 = Rect 2.5 3I cuadrado x = Rect x x

117

Pattern matching

I correspondencia o coincidencia de patrones

I mecanismo para ver como esta construido un elemento de untipo algebraico

I si definimos una funcion que recibe como parametro unaFigura, podemos averiguar si es un cırculo o un rectangulo (ycon que parametros fue construida)

I patterns: expresiones del lenguaje formadas solamente porconstructores y variables que no se repiten

I Rect x y es un patronI 3 + x no es un patronI Rect x x tampoco porque tiene una variable repetida

I matching: operacion asociada a un patronI dada una expresion cualquiera dice si su valor coincide por su

forma con el patronI si la correspondencia existe, entonces liga las variables del

patron a las subexpresiones correspondientes

118

Ejemploarea :: Figura -> Float

area (Cırc radio) = pi * radio * radioarea (Rect base altura) = base * altura

cırculo :: Float -> Figuracırculo x = Cırc (x+1)

I lado izquierdo: funcion que estamos definiendo aplicada a unpatron

I evaluemos la expresion area (cırculo 2)I el interprete debe elegir cual de las ecuaciones de area utilizarI primero debe evaluar cırculo 2 para saber a que constructor

correspondeI la reduccion da Cırc (2+1)I ya se puede verificar cada ecuacion de area para buscar el

matchingI se logra con la primera ecuacion

I radio queda ligada a (2+1)

I luego de varias reducciones (aritmeticas) mas, se llega al valorde la expresion: 28.2743

119

Sinonimos de tiposI se usa la clausula type para darle un nombre nuevo a un tipo

existenteI no se crea un nuevo tipo, sino un sinonimo de tipoI los dos nombres son equivalentes

I ejemplo: nombrar una instancia particular de un tipoparametrico: type String = [Char]

I ejemplo: renombrar un tipo existente con un nombre massignificativo:type Nombre = Stringtype Sueldo = Inttype Empleado = (Nombre, Sueldo)type Direccion = String

type Persona = (Nombre, Direccion)

I Persona es un par de String, pero (String, String), esmas difıcil de entender

I tambien hay sinonimos de tipos parametricos:type IntY a = (Int, a)

120

Page 31: Algoritmos y Estructuras de Datos II

Tipos recursivos

El tipo definido es argumento de alguno de los constructores

Ejemplo:

I data N = Z | S NI tiene dos constructores:

1. Z es un constructor sin argumentos2. S es un constructor con argumentos (de tipo N)

I elementos del tipo N:

Z , S Z , S (S Z) , S (S (S Z)) , . . .↓ ↓ ↓ ↓0 1 2 3

Este tipo puede representar a los numeros naturales.

121

Ejemplos

Usando pattern matching, podemos definir funciones recursivassobre cualquier termino mediante recursion estructural.

I suma :: N -> N -> N

suma n Z = n

suma n (S m) = S (suma n m)

I producto :: N -> N -> N

producto n Z = Z

producto n (S m) = suma n (producto n m)

I menorOIgual :: N -> N -> Bool

menorOIgual Z m = TruemenorOIgual (S n) Z = False

menorOIgual (S n) (S m) = menorOIgual n m

122

Otro ejemplo

I data P = T | F | A P P | N PI tiene cuatro constructores:

1. T y F son constructores sin argumentos2. A es un constructor con dos argumentos (de tipo P)3. N es un constructor con un argumento (de tipo P)

I elementos del tipo P:

T , F , A T F , N (A T F) , . . .↓ ↓ ↓ ↓

true false (true ∧ false) ¬(true ∧ false)

Este tipo puede representar a las formulas proposicionales.

123

Ejemplos

I contarAes :: P -> Int

contarAes T = 0contarAes F = 0contarAes (N x) = contarAes x

contarAes (A x y) = 1 + (contarAes x) + (contarAes y)

I valor :: P -> Bool

valor T = Truevalor F = Falsevalor (N x) = not (valor x)

valor (A x y) = (valor x) && (valor y)

124

Page 32: Algoritmos y Estructuras de Datos II

ListasI se usan mucho (el igual que en el lenguaje de especificacion)I son un tipo algebraico recursivo parametrico

I en especificacion las vimos definidas con observadoresI en Haskell, se definen con constructores

I primero, vamos a definirlas como un tipo algebraico comun

data List a = Nil | Cons a (List a)

I interpretamosI Nil como la lista vacıaI Cons x l como la lista que resulta de agregar x como

primer elemento de lI por ejemplo,

I List Int es el tipo de las listas de enteros. Son de este tipo:I NilI Cons 2 NilI Cons 3 (Cons 2 Nil)

I List (List Int) es el tipo de las listas de listas de enteros.Son de este tipo:

I NilI Cons Nil NilI Cons (Cons 2 Nil) (Cons Nil Nil) 125

Ejemplos

I calcular la longitud de una lista

longitud :: List a -> Intlongitud Nil = 0

longitud (Cons x xs) = 1 + (longitud xs)

I sumar los elementos de una lista de enteros

sumar :: List Int -> Intsumar Nil = 0

sumar (Cons x xs) = x + (sumar xs)

I concatenar dos listas

concat :: List a -> List a -> List aconcat Nil ys = ys

concat (Cons x xs) ys = Cons x (concat xs ys)

126

Notacion de listas en HaskellI List a se escribe [a]I Nil se escribe []I (Cons x xs) se escribe (x:xs)I los constructores son : y []

I Cons 2 (Cons 3 (Cons 2 (Cons 0 Nil)))I (2 : (3 : (2 : (0 : []))))I 2 : 3 : 2 : 0 : []

I notacion mas comoda: [2,3,2,0]

Ejemplos (todas estan en el preludio)I length :: [a] -> Int

length [] = 0

length (x:xs) = 1 + (length xs)I sum :: [Int] -> Int

sum [] = 0

sum (x:xs) = x + (sum xs)

I (++) :: [a] -> [a] -> [a][] ++ ys = ys

(x:xs) ++ ys = x:(xs ++ ys)

++ concatena dos listas.Es un operador que se usacon notacion infija[1, 2] + +[3, 4, 5] 127

Arboles

I estructuras formadas por nodos

I almacenan valores de manera jerarquica (cada nodo guarda unvalor)

I vamos a trabajar con arboles binariosI de cada nodo salen cero o dos ramasI hoja: es un nodo que no tiene ramas

Ejemplos:

2 2

4 5

2

4 5

0 1

2

4

7 9

5

0 1

128

Page 33: Algoritmos y Estructuras de Datos II

Definicion del tipo ArbolDefinicion del tipo

data Arbol a = Hoja a | Nodo a (Arbol a) (Arbol a)

2

2

4 5

2

4 5

0 1

−→ Hoja 2

−→ Nodo 2 (Hoja 4) (Hoja 5)

−→ Nodo 2 (Hoja 4) (Nodo 5 (Hoja 0) (Hoja 1))

hojas :: Arbol a -> Inthojas (Hoja x) = 1hojas (Nodo x i d) = (hojas i) + (hojas d)

altura :: Arbol a -> Intaltura (Hoja x) = 1

altura (Nodo x i d) = 1 + ((altura i) ’max’ (altura d))129

Recorridos en arbolesI las funciones que vimos van recorriendo un arbol y operando

con cada nodoI podrıan hacerlo en cualquier orden con el mismo resultadoI a veces es importante el orden al recorrer un arbol para

aplicarle alguna operacion

inOrder, preOrder :: Arbol a -> [a]

inOrder (Hoja x) = [x]inOrder (Nodo x i d) = (inOrder i) ++ [x] ++ (inOrder d)

preOrder (Hoja x) = [x]

preOrder (Nodo x i d) = x : ((preOrder i) ++ (preOrder d))

Por ejemplo, para el arbol A

2

4 5

0 1

inOrder A es [4,2,0,5,1]

preOrder A es [2,4,5,0,1]

130

Programacion funcionalClase 3

Tipos abstractos

131

Tipos abstractos

I Vimos como crear y como usar tipos de datos algebraicosI Tambien se puede recibir un tipo como abstracto

I No se puede acceder a su representacion

I No hace falta mas de un programadorI Creo un tipo (algebraico) y oculto su representacionI En otras partes del programa me esta prohibido accederla

I En el diseno de lenguajes de programacion es un punto claveI Facilitar que el programador haga lo que quiere, pero alentarlo

a hacerlo bienI Y, mas importante, impedirle hacerlo mal: usar la

representacion interna del tipo en otros programas

I Dos motivosI Criterios basicos para tipos algebraicosI Mantenimiento

132

Page 34: Algoritmos y Estructuras de Datos II

Criterios para tipos algebraicos

1. Toda expresion del tipo representa un valor validoI ConstructorI Valores cualesquiera para sus parametros

2. Igualdad por construccionI Dos valores son iguales solamente si se construyen igual

I Mismo constructorI Mismos argumentos

Condiciones idealesI A veces se construyen tipos algebraicos sin respetarlas

I Cırc (-1.2)I Rect 2.3 4.5 6= Rect 4.5 2.3

133

Ejemplo de tipo algebraico: Complejo

I Toda combinacion de dos Float es un complejo

I Dos complejos son iguales sii sus partes reales y sus partesimaginarias coinciden

data Complejo = C Float Float

parteReal, ParteImag :: Complejo -> Float

ParteReal (C r i) = rParteImag (C r i) = i

hacerPolar :: Float -> Float -> ComplejohacerPolar rho theta =

C (rho * cos theta) (rho * sin theta)

134

Racionales

data Racional = R Int Int

numerador, denominador :: Racional -> Int

numerador (R n d) = n

denominador (R n d) = d

¿Esta bien definido? ¡No!

I No todo par de enteros es un racional: R 1 0

I Hay racionales iguales con distinto numerador y denominador:R 4 2 y R 2 1

135

Racionales como tipo algebraico

Se puede usar, pero con mucho cuidadoI Al construir

I Nunca segunda componente 0

I Al definir funcionesI Mismo resultado para toda representacion del mismo racionalI Funcion numerador (devuelve la primera componente)

I Resultados distintos para R (-1) (-2) y R 2 4I Son el mismo numero, no estamos representando las fracciones

Tipos abstractos

I Ayuda del lenguaje

I La representacion interna se usa en pocas funciones

I Mensaje de error si se intenta violar ese acuerdo

136

Page 35: Algoritmos y Estructuras de Datos II

Mantenimiento

I Acceso por pattern matching limitado a pocas funcionesI Si cambia la representacion interna, solamente hay que

cambiar esas funcionesI En lo posible, muy cerca una de otra en el codigo (mismo

archivo)

I Si no pedimos al lenguaje esta proteccionI Riesgo de usar la implementacion en otros programasI Cuando la cambiemos, dejan de funcionarI Hay que modificar uno por uno

137

Uso de tipos abstractos

I Se recibe un tipo de datos abstractoI nombre del tipoI nombres de sus operaciones basicasI tipos de las operacionesI especificacion de su funcionamiento

I puede ser mas o menos formalI en Haskell no es chequeada por el lenguaje

I ¿Como se utiliza el tipo?I a traves de sus operaciones y unicamente asıI no se puede usar pattern matching

138

Racionales como tipo abstractoI Recibimos operaciones, que no sabemos como estan

implementadas

crearR :: Int -> Int -> RacionalnumerR :: Racional -> IntdenomR :: Racional -> Int

I Y especificacion

tipo Racional {observador numerR(r : Racional): Int;observador denomR(r: Racional): Int;invariante denomR(r) > 0;invariante mcd(numerR(r), denom(R)) == 1;

}problema crearR(n, d: Int) = rac: Racional {

requiere d 6= 0;asegura numerR(rac) * d == denomR(rac) * n;

} 139

Racionales como tipo abstracto

I Numerador y denominador: forma normalizada (maximasimplificacion) con signo en el numerador

I No sabemos cuando se produce la simplificacion paranormalizar

I al construir el numero en crearRI al evaluarlo, en numerR y denomR

140

Page 36: Algoritmos y Estructuras de Datos II

Definicion de nuevas operaciones

I Tal vez incluya operaciones basicasI Suma, multiplicacion, division

I Tambien podemos definirlas nosotros:

sumaR, multR, divR :: Racional -> Racional -> Racional

r1 ‘sumaR‘ r2 = crearR(denomR r2 * numerR r1 + denomR r1 * numerR r2)(denomR r1 * denomR r2)

r1 ‘multR‘ r2 = crearR(numerR r1 * numerR r2)(denomR r1 * denomR r2)

r1 ‘divR‘ r2 = crearR(denomR r2 * numerR r1)

(denomR r1 * numerR r2)

141

Otro ejemplo: Conjuntos

I Teorıa de conjuntosI Herramienta muy poderosa para el razonamiento matematico

I Pero el tipo de datos preferido para representar colecciones noes conjuntos, sino listas

I MotivoI Los conjuntos no pueden representarse con un tipo algebraico

que cumpla los criterios

I SolucionI Crear un tipo abstracto para los conjuntosI Las operaciones disponibles para el usuario van a limitar su uso

142

Operaciones de conjuntos

Vamos a definir conjuntos de enteros

I El conjunto vacıovacıo :: IntSet

I ¿El conjunto dado es vacıo?esVacıo :: IntSet -> Bool

I ¿Un elemento pertenece al conjunto?pertenece :: Int -> IntSet -> Bool

I Agregar un elemento al conjunto, si no estaba. Si estaba,dejarlo igual

agregar :: Int -> IntSet -> IntSet

I Elegir el menor numero y quitarlo del conjuntoelegir :: IntSet -> (Int, IntSet)

143

Transparencia referencial

I Las descripciones usan la metafora de la modificacionI Las operaciones no modifican los conjuntos, construyen

conjuntos nuevosI Pero es facil explicar las funciones en estos terminos

I elegir no quita nadaI El original, sigue igualI Devuelve un elemento y otro conjunto, con todos los

elementos del primero menos eseI No queda claro que pasa si el conjunto es vacıoI Se puede suponer que da error

I Estas descripciones no sustituyen a una especificacion

144

Page 37: Algoritmos y Estructuras de Datos II

Nuevas operacionesI Definamos una operacion nueva: union

union :: IntSet -> IntSet -> IntSet

union p q | esVacıo p = qunion p q | otherwise = unionAux (elegir p) q

unionAux (x, p’) q = agregar x (union p’q)

I Pudimos hacerlo sin conocer la representacion de losconjuntos

I Usamos las operaciones provistasI Si cambia la representacion

I Habra que rescribir las ecuaciones para las operaciones del tipoabstracto (vacıo, esVacıo, pertenece, agregar,elegir)

I union y cualquier otra definida en otros programas quedanintactas

I La recursion no es privativa del pattern matchingI union esta definida en forma recursiva (a traves de unionAux)I Pero no usa recursion estructural ¡ni siquiera conocemos la

estructura! 145

Creacion de tipos abstractos

I Escribir un tipo abstracto que puedan usar otrosprogramadores

I En Haskell se hace con modulosI Archivos de texto que contienen parte de un programa

I Dos caracterısticas importantes en cualquier lenguajeI Encapsulamiento

I Agrupar estructura de datos con funciones basicasI Un programa no es una lista de definiciones y tipos, son

”capsulas”I Cada una con un (tal vez mas) tipo de datos y sus funciones

especıficas

I OcultamientoI Cuando se escribe un modulo se indica que nombres exporta

Cuales van a poder usarse desde afuera y cuales noI Aplicacion

Ocultar funciones auxiliares (como unionAux)Tambien para crear tipos de datos abstractos: Ocultar larepresentacion interna

146

Ejemplo de moduloI El primer ejemplo no es un tipo abstractoI Vamos a agrupar la funcionalidad de los complejosI Se representan bien mediante tipo algebraicoI Exportemos el tipo completo

module Complejos (Complejo(..), parteReal, parteIm) where

data Complejo = C Float Float

parteReal, parteIm:: Complejo -> Float

parteReal(C r i) = r

parteIm (C r i) = i

I module introduce el modulo: nombre, que exportaI Tipo(..) exporta el nombre del tipo y sus constructores

I Permite hacer pattern matching fuera del moduloI Despues del where van las definicionesI Si no hay lista de exportacion se exportan todos los nombres

definidosI module Complejos where...

147

Ejemplo de tipo abstracto

module Racionales (Racional, crearR, numerR, denomR)where

data Racional = R Int Int

crearR :: Int -> Int -> RacionalcrearR n d = reduce (n*signum d) (abs d)

reduce :: Int -> Int -> Racionalreduce x 0 = error "Racional con denom. 0"reduce x y = R (x ‘quot‘ d) (y ‘quot‘ d)

where d = gcd x y

numerR, denomR :: Racional -> Int

numerR (R n d) = n

denomR (R n d) = d

148

Page 38: Algoritmos y Estructuras de Datos II

Aclaraciones

I signum (signo), abs (valor absoluto), quot (division entera) ygcd (gratest common divisor (MCD)) estan en el preludio

I En la lista de exportacion no dice (..) despues de RacionalI Se exporta solamente el nombre del tipoI NO sus constructoresI Convierte el tipo en abstracto para los que lo usen

I Tampoco exportamos reduce (auxiliar)

149

Uso del tipo

I Volvemos al rol de usuarioI Hay que indicar (en otro modulo) que queremos incorporar

este tipo de datosI Se usa la clausula import

I Todos los nombres exportados por un moduloI O solamente algunos de ellos (aclarando entre parentesis

cuales)

module Main whereimport Complejosimport Racionales (Racional, crearR)miPar :: (Complejo, Racional)miPar = (C 1 0, crearR 4 2)

I Las siguientes expresiones dan errorI numerR (snd miPar)I reduce 4 2I R 4 2 + R 2 1

150

Otra forma de crear tipos

I Vimos como crear sinonimos de tiposI Nombre adicional para un tipo existenteI Son intercambiables

I A veces, queremos un tipo nuevo con la representacion de unoexistente

I Que NO puedan intercambiarseI Por ejemplo, para un tipo abstracto

I Clausula newtype

151

newtype

Ejemplo: conjuntos

I Los representamos internamente con listas

I Encerramos la representacion en un tipo abstracto

newtype IntSet = Set [Int]

Diferencias con data

I Llama la atencion sobre renombreI A otro implementador encargado de modificarlaI A alguien que tenga que revisar el codigoI Al mismo programador dentro de un tiempo

I Admite un solo constructor con un parametroI No crea nuevos elementosI Renombra elementos existentes (no intercambiable)

I Mejor rendimiento

152

Page 39: Algoritmos y Estructuras de Datos II

Implementacion de conjuntos

module ConjuntoInt (IntSet, vacıo, esVacıo, pertenece,agregar, elegir) where

import List (insert)

newtype IntSet = Set [Int]

vacıo :: IntSetvacıo = Set []

esVacıo :: IntSet -> BoolesVacıo (Set xs) = null xs

pertenece :: Int -> IntSet -> Boolpertenece x (Set xs) = x ‘elem‘ xs

agregar :: Int -> IntSet -> IntSetagregar x (Set xs) | elem x xs = Set xsagregar x (Set xs) | otherwise = Set (insert x xs)

elegir :: IntSet -> (Int, IntSet)

elegir (Set (x:xs)) = (x, Set xs)

153

Programacion funcionalClase 4

Terminacion

154

Causas de indefinicionLa evaluacion de una funcion puede no terminar (bien) porque:

1. se genera una cadena infinita de reducciones:

func1 :: Int -> Int -> Intfunc1 0 acum = acum

func1 i acum = func1 (i-1) (2*acum)

Si evaluamos func1 6 5 nos devuelve 320, pero la evaluacionde func1 (-6) 5 no termina.

2. ninguna lınea de la definicion de la funcion indica que hacer:

func2 :: [a] -> (a,a)func2 [x1,x2] = (x1,x2)

func2 (x:xs) = (x, snd (func2 xs))

Por ejemplo, func2 "algo1" = (’a’,’1’), pero laevaluacion de func2 "a" no termina.

3. invocamos a una funcion que no termina (bien)

No importa que Hugs nos devuelva el control en estos casos.Diremos que no termina o que la funcion se indefine.

155

Terminacion

Un programa (funcional) cumple con una especificacion cuandopara valores de entrada que satisfacen la precondicion:

1. el programa devuelve un valor definido (terminacion)

2. el valor devuelto satisface la poscondicion (correctitud)

I en esta clase vamos a aprender un metodo formal parademostrar que ciertos programas terminan

I en Algoritmos y Estructuras de Datos II van a estudiarmetodos para probar que los programas funcionales soncorrectos (induccion estructural)

Dada una funcion f y una precondicion Pf , diremos que f terminasi para cualesquiera valores de entrada x definidos que haganverdaderos a Pf , la evaluacion de f x termina.Aquı, x representa a todas las variables de entrada.

156

Page 40: Algoritmos y Estructuras de Datos II

Demostracion de terminacion

Si miramos

func1 :: Int -> Int -> Intfunc1 0 acum = acum

func1 i acum = func1 (i-1) (2*acum)

puede parecer evidente que func1 termina si tomamosPfunc1 : i ≥ 0.

Veamos otro ejemplo:

func3 :: Int -> Boolfunc3 n | n == 1 = True

| n ‘mod‘ 2 == 0 = func3 (n ’div’ 2)

| otherwise = func3 (3*n + 1)

¿Es evidente que func3 termina cuando consideramosPfunc3 : x > 0?

157

Ecuaciones canonicasI en Haskell hay muchas maneras de definir funciones (guardas,

pattern matching, where, etc.)I queremos usar una serie de definiciones que nos permitan

analizar la funcion de manera homogeneaI para esto: ecuaciones canonicas

f x/(B1,C1,G1) = E1

f x/(B2,C2,G2) = E2

...

f x/(Bn,Cn,Gn) = En

I Gi es la guarda explıcita (en Haskell)I Bi es la guarda implıcita (termino de tipo Bool del lenguaje de

especificacion). ¿Por que entra por la i-esima ecuacion?I Ci es el contexto de evaluacion (termino de tipo Bool; escrito

en lenguaje de especificacion) que representa informacionadicional proveniente de pattern matching o clausula where.

I Ei es la expresion del lado derecho (en Haskell).158

Ejemplo

problema suma(l : [Int]) = res : Int{asegura : res ==

∑l ;

}

suma :: [Int] -> Intsuma [] = 0

suma (x:xs) = x + suma xs

Las ecuaciones canonicas son:

suma l / (|l | == 0, true , True) = 0suma l / (|l | > 0 , x == cab(l) ∧ xs == cola(l), True) = x + suma xs

o, alternativamente,

suma l / (|l | == 0, true , True) = 0suma l / (|l | > 0 , x == l [0] ∧ xs == l [1..|l |], True) = x + suma xs

159

Hipotesis de la demostracion

Asumimos que:

1. esta demostrado que cada funcion g que aparece en algunaguarda o where termina si se utiliza cierta precondicion(conocida) Pg

2. esta demostrado que cada funcion g 6= f que aparece en algunlado derecho termina si se utiliza cierta precondicion(conocida) Pg

Quedan fuera de este esquema de demostracion las funcionesmutuamente recursivas.

160

Page 41: Algoritmos y Estructuras de Datos II

Reglas de terminacion

Daremos 5 reglas sobre ecuaciones canonicas de una cierta funcionf: R1, R2, R3, R4 y R5.

I si se pueden probar las 5 reglas, entonces f termina

I las reglas solo predican sobre las ecuaciones canonicas; nosolvidamos de las ecuaciones originales

I si no podemos probar alguna de las 5 reglas no quiere decirque la funcion no termine; las 5 reglas son condicionessuficientes pero no necesarias

161

R1 - las funciones se evaluan dentro de su precondicionproblema prLL(l : [[Int]]) = res : [R]{asegura res ==[if |y | > 0 then prom(y) else 0 | y ← l ]}

problema prom(l : [Int]) = res : R{requiere |l | > 0;asegura res == prom(l); }aux prom(l : [Int]) : Float =

∑l/|l |

prLL :: [[Int]] -> [Float]prLL [] = []prLL ([]:xs) = 0 : (prLL xs)prLL (x:xs) = (prom x) : (prLL xs)

prLL l / (|l | == 0 , true , True) = []

prLL l / (|l | > 0 ∧ l [0] == [ ], xs == l [1..|l |) , True) = 0 : (prLL xs)

prLL l / (|l | > 0 , l [0] == x ∧ xs == l [1..|l |), True) = (prom x):(prLL xs)

R1 sea i entre 1 y n, y sea g y (g puede ser f) una expresion queaparece en Gi o en Ei . Si

I x hace verdadero Pf ,I valen ¬B1, . . . ,¬Bi−1,I si g y aparece en Ei vale ademas Bi ,

entonces y debe hacer verdadero Pg .

En el ejemplo, prom siempre se invoca con argumentos que satisfacen Pprom.162

R2 - hay suficientes ecuaciones

problema diferenciaAbsoluta(a, b : Int) = d : Int{asegura : d == |a− b|;

}diferenciaAbsoluta :: Int -> Int -> IntdiferenciaAbsoluta a b | a > b = a - b

| a < b = b - a

Aquı hay un problema porque falta analizar el caso a == b.Deberıa ser, por ejemplo:

diferenciaAbsoluta :: Int -> Int -> IntdiferenciaAbsoluta a b | a > b = a - b

| a < b = b - a| a == b = 0

R2 si x estan definidas y hacen verdadero Pf , entonces existe un ientre 1 y n tal que x hacen verdadero Bi .

163

R3, R4 y R5 - no hay reducciones infintas

problema factorial(n : Int) = fact : Int{asegura : fact ==

∏[1..n];

}factorial :: Int -> Int -> Intfactorial n | n == 0 = 1

| otherwise = n * factorial (n-1)

Si evaluamos factorial 5 obtenemos 120. Pero al evaluarfactorial (-1) se genera una cadena infinita de reducciones

Idea:

I garantizar que en cada llamado recursivo nos “acercamos”masal caso base

I dar una forma numerica de medir que tan cerca del caso baseestamos

I esa forma numerica es la funcion variante, que sera untermino de tipo Int de nuestro lenguaje de especificacion

164

Page 42: Algoritmos y Estructuras de Datos II

R3, R4 y R5 - no hay reducciones infintas

f x/(B1,C1,G1) = E1

f x/(B2,C2,G2) = E2

...

f x/(Bn,Cn,Gn) = En

Proponemos una funcion variante Fv (x) tal que:

R3 si x estan definidas y hacen verdadero Pf , entonces Fv (x) nose indefine.

R4 sea i entre 1 y n, con Ei un caso recursivo, y x tales que secumple (Pf ∧ ¬B1 ∧ . . . ∧ ¬Bi−1 ∧ Bi ). Entonces, para cadaaparicion de f y en Ei , vale que Fv (x) > Fv (y).

R5 existe una constante entera k, que denominaremos cota deFv , con la siguiente propiedad: toda vez que x hace verdaderoPf y Fv (x) ≤ k , debe existir i entre 1 y n tal que

I Ei es un caso base yI vale (¬B1 ∧ . . . ∧ ¬Bi−1 ∧ Bi ).

165

Resumiendo

Condiciones basicas (y faciles de demostrar)

R1 todas las funciones se evaluan dentro de su precondicion

R2 hay suficientes ecuaciones (no faltan casos)

Debemos proponer una funcion variante Fv (x) y una cota tal que(esto es mas difıcil de demostrar):

R3 Fv (x) no se indefine (si vale Pf )

R4 Fv (x) es decreciente

R5 si Fv (x) pasa la cota entonces f entra a un caso base (y porlo tanto termina)

166

ultimo - ejemplo completo

problema ultimo(l : [T ]) = u : T{requiere : |l | > 0;asegura : u == l [|l | − 1];

}

ultimo :: [a] -> aultimo [x] = x

ultimo (x:xs) = ultimo xs

Las ecuaciones canonicas son:

ultimo l / (|l | == 1, x == l [0] , True) = xultimo l / (|l | > 0 , x == l [0] ∧ xs == l [1..|l |), True) = ultimo xs

167

ultimo - R1ultimo l / (|l | == 1, x == l [0] , True) = xultimo l / (|l | > 0 , x == l [0] ∧ xs == l [1..|l |), True) = ultimo xs

R1 sea i entre 1 y n, y sea g y (g puede ser f) una expresion queaparece en Gi o en Ei . Si

I x hace verdadero Pf ,I valen ¬B1, . . . ,¬Bi−1,I si g y aparece en Ei vale ademas Bi ,

entonces y debe hacer verdadero Pg .

La unica funcion utilizada es ultimo, en E2. Tenemos que ver que si:

a) l satisface Pultimo, es decir |l | > 0,

b) vale ¬B1, esto es, ¬|l | == 1, y

c) vale ademas B2, es decir |l | > 0,

entonces xs satisface Pultimo, o sea: |xs| > 0.

I de a) y b) sabemos que |l | ≥ 2

I de C2 sabemos xs == l [1..|l |); entonces |xs| == |l | − 1

I concluimos |xs| > 0 168

Page 43: Algoritmos y Estructuras de Datos II

ultimo - R2

ultimo l / (|l | == 1, x == l [0] , True) = xultimo l / (|l | > 0 , x == l [0] ∧ xs == l [1..|l |), True) = ultimo xs

R2 si x estan definidas y hacen verdadero Pf , entonces existe un ientre 1 y n tal que x hacen verdadero Bi .

Es claro que B2 cumple la regla.

169

ultimo - R3

ultimo l / (|l | == 1, x == l [0] , True) = xultimo l / (|l | > 0 , x == l [0] ∧ xs == l [1..|l |), True) = ultimo xs

Proponemos Fv (l) = |l | y cota k = 1.

R3 si x estan definidas y hacen verdadero Pf , entonces Fv (x) noesta indefinido.

La operacion de longitud es una funcion total sobre listas. Es decir,no se indefine para ningun valor definido.

170

ultimo - R4

ultimo l / (|l | == 1, x == l [0] , True) = xultimo l / (|l | > 0 , x == l [0] ∧ xs == l [1..|l |), True) = ultimo xs

R4 sea i entre 1 y n, con Ei un caso recursivo, y x tales que secumple (¬B1 ∧ . . . ∧ ¬Bi−1 ∧ Bi ). Entonces, para cadaaparicion de f y en Ei , vale que Fv (x) > Fv (y).

I solo tenemos un caso recursivo, que corresponde a i = 2I supongamos que l cumple (Pultimo ∧ ¬B1 ∧ B2). Debemos

comprobar que vale

Fv (l) > Fv (xs)

I por (el contexto de) B2, sabemos que xs == l [1..|l |), con locual |xs| == |l | − 1. Entonces

Fv (l) == |l | > |l | − 1 == |xs| == Fv (xs).171

ultimo - R5

ultimo l / (|l | == 1, x == l [0] , True) = xultimo l / (|l | > 0 , x == l [0] ∧ xs == l [1..|l |), True) = ultimo xs

R5 toda vez que x hace verdadero Pf y Fv (x) ≤ k, debe existir ientre 1 y n tal que Ei es un caso base, y vale(¬B1 ∧ . . . ∧ ¬Bi−1 ∧ Bi ).

Debemos garantizar la entrada a un caso base cuando Fv esta pordebajo de la cota.

I supongamos l tal que valen Pultimo y Fv (l) ≤ k

I entonces |l | > 0 y |l | ≤ 1

I como |l | es un entero, debe ser necesariamente |l | == 1

I esto coincide con B1, que es la guarda correspondiente al casobase (i = 1).

172

Page 44: Algoritmos y Estructuras de Datos II

Entonces ultimo termina

Como pudimos probar las reglas R1, R2, R3, R4 y R5. concluimosque ultimo termina.

Observar que:

I se debe proponer una funcion variante Fv y una cota k paraprobar R3, R4 y R5

I esa funcion variante y cota deben ser las mismas para probarR3, R4 y R5

I hubiera servido una cota menor, por ejemplo, k = 0 ok = −1. ¿Por que?

173

mezclarOrdenado - ejemplo completo

problema mezclarOrdenado(l1, l2 : [Int]) = r : [Int]{requiere : ordenado(l1) ∧ ordenado(l2);asegura : ordenado(r) ∧mismos(r , l1 + +l2);

} aux ordenado(l : [T ]) : Bool = (∀i ← [0..|l | − 1)) l [i ] ≤ l [i + 1]

mezOrd :: [Int] -> [Int] -> [Int]mezOrd [] l2 = l2mezOrd l1 [] = l1mezOrd (x:xs) (y:ys) | x<=y = x : (mezOrd xs (y:ys))

mezOrd (x:xs) (y:ys) | otherwise = y : (mezOrd (x:xs) ys)

mezOrd l1 l2 / (|l1| == 0, true, True) = l2mezOrd l1 l2 / (|l2| == 0, true, True) = l1mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0 ∧ x ≤ y ,

x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),x<=y) = x : (mezOrd xs (y:ys))

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),

True) = y : (mezOrd (x:xs) ys) 174

mezclarOrdenado - R1

mezOrd l1 l2 / (|l1| == 0, true, True) = l2

mezOrd l1 l2 / (|l2| == 0, true, True) = l1

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0 ∧ x ≤ y ,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),x<=y) = x : (mezOrd xs (y:ys))

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),True) = y : (mezOrd (x:xs) ys)

R1 sea i entre 1 y n, y sea g y (g puede ser f) una expresion queaparece en Gi o en Ei . Si

I x hace verdadero Pf ,I valen ¬B1, . . . ,¬Bi−1,I si g y aparece en Ei vale ademas Bi ,

entonces y debe hacer verdadero Pg .

Observar que mezord siempre se llama con parametros que verifican la

precondicion (las dos listas que recibe estan ordenadas).

175

mezclarOrdenado - R2

mezOrd l1 l2 / (|l1| == 0, true, True) = l2

mezOrd l1 l2 / (|l2| == 0, true, True) = l1

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0 ∧ x ≤ y ,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),x<=y) = x : (mezOrd xs (y:ys))

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),True) = y : (mezOrd (x:xs) ys)

R2 si x estan definidas y hacen verdadero Pf , entonces existe un i entre1 y n tal que x hacen verdadero Bi .

Observar que siempre ocurre que

|l1| = 0 ∨ |l2| = 0 ∨ (|l1| > 0 ∧ |l2| > 0)

176

Page 45: Algoritmos y Estructuras de Datos II

mezclarOrdenado - Funcion variante y cotamezOrd l1 l2 / (|l1| == 0, true, True) = l2

mezOrd l1 l2 / (|l2| == 0, true, True) = l1

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0 ∧ x ≤ y ,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),x<=y) = x : (mezOrd xs (y:ys))

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),True) = y : (mezOrd (x:xs) ys)

Posibilidades:

I Fv(l1, l2) == |l1|I en E3 decreceI pero no sirve porque en E4 no decrece

I Fv(l1, l2) == |l2|I en E4 decreceI pero no sirve porque en E3 no decrece

I Fv(l1, l2) == |l1|+ |l2| es un buen candidato

I proponemos cota k = 0177

mezclarOrdenado - R3

mezOrd l1 l2 / (|l1| == 0, true, True) = l2

mezOrd l1 l2 / (|l2| == 0, true, True) = l1

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0 ∧ x ≤ y ,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),x<=y) = x : (mezOrd xs (y:ys))

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),True) = y : (mezOrd (x:xs) ys)

R3 si x estan definidas y hacen verdadero Pf , entonces Fv (x) noesta indefinido.

Fv(l1, l2) == |l1|+ |l2|

La operacion de longitud y la suma son funciones totales.

178

mezclarOrdenado - R4mezOrd l1 l2 / (|l1| == 0, true, True) = l2

mezOrd l1 l2 / (|l2| == 0, true, True) = l1

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0 ∧ x ≤ y ,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),x<=y) = x : (mezOrd xs (y:ys))

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),True) = y : (mezOrd (x:xs) ys)

R4 sea i entre 1 y n, con Ei un caso recursivo, y x tales que secumple (Pf ∧ ¬B1 ∧ . . . ∧ ¬Bi−1 ∧ Bi ). Entonces, para cadaaparicion de f y en Ei , vale que Fv (x) > Fv (y).

I hay dos casos recursivos, i = 3 e i = 4I para E3, tenemos

Fv(xs, l2) == |xs|+ |l2| < |l1|+ |l2| = Fv(l1, l2)

I para E4, tenemos

Fv(l1, ys) == |l1|+ |ys| < |l1|+ |l2| = Fv(l1, l2)179

mezclarOrdenado - R5mezOrd l1 l2 / (|l1| == 0, true, True) = l2

mezOrd l1 l2 / (|l2| == 0, true, True) = l1

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0 ∧ x ≤ y ,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),x<=y) = x : (mezOrd xs (y:ys))

mezOrd l1 l2 / (|l1| > 0 ∧ |l2| > 0,x == l1[0] ∧ xs == cola(l1) ∧ y == l2[0] ∧ ys == cola(l2),True) = y : (mezOrd (x:xs) ys)

R5 toda vez que x hace verdadero Pf y Fv (x) ≤ k, debe existir ientre 1 y n tal que Ei es un caso base, y vale(¬B1 ∧ . . . ∧ ¬Bi−1 ∧ Bi ).

Debemos garantizar la entrada a un caso base cuandoFv (l1, l2) ≤ 0.

I supongamos Fv(l1, l2) = |l1|+ |l2| ≤ 0I entonces |l1| == 0 y |l2| == 0I en particular, vale B1 (tambien vale B2)

180

Page 46: Algoritmos y Estructuras de Datos II

Programacion funcionalClase 5

Correctitud - ordenes de evaluacion - alto orden

181

Correctitud

I ya vimos como demostrar terminacion

I para demostrar que una definicion es correcta, hace falta

I una especificacionproblema fact(n : Int) = result : Int{

requiere n ≥ 0;asegura result ==

∏[1..n];

}I y un programa

fact 0 = 1fact n | n > 0 = n * fact (n-1)

I definicion recursiva: es natural demostrar por induccion

182

Demostracion de correctitudQuiero probar que para todo x , la funcion fact con entrada xdevuelve

∏[1..x ].

I caso base (n == 0)I la especificacion dice que hay que probar que la funcion fact

con entrada 0 devuelve∏

[1..0] ==∏

[ ] = 1I pero eso es justamente lo que devuelve fact en el caso base

I hipotesis inductiva (HI): fact n ==∏

[1..n]I la especificacion dice que hay que probar que la funcion fact

con entrada n + 1 devuelve∏

[1..n + 1]I calculemos fact n + 1I gracias a la precondicion, n + 1 > 0. Entonces uso la segunda

ecuacion instanciando en n + 1

fact(n + 1) == (n + 1) ∗ fact(n)

I usando HI:

fact(n + 1) == (n + 1) ∗∏

[1..n]

==∏

[1..(n + 1)]

I entonces, demostre que fact con entrada n + 1 devuelve∏[1..(n + 1)] 183

Principio de induccion para NI sea P(x) una propiedad de x ∈ NI supongamos que queremos probar que vale P(x) para todo

x ∈ NI el axioma de induccion dice:

I siI P(0) es verdadero yI para todo n, P(n)→ P(n + 1) es verdadero

I entonces P(x) es verdadero para todo x ∈ NI el axioma de induccion completa dice:

I siI P(0) es verdadero yI para todo n, (∀m ≤ n P(m))→ P(n + 1) es verdadero

I entonces P(x) es verdadero para todo x ∈ NI en el ejemplo anterior, P(x) dice

“la funcion fact con entrada x devuelve∏

[1..x ]”

184

Page 47: Algoritmos y Estructuras de Datos II

Otro ejemplo de demostracion de correctitudI vimos como demostrar la correctitud de fact(n) haciendo induccion en el

parametro de entrada (es decir, en n)I tambien se puede hacer induccion en el valor que toma una funcionI por ejemplo,

problema suma(l : [Int]) = result : Int{asegura result ==

∑l ;

}

suma [] = 0suma (x:xs) = x + suma xs

I quiero probar P(l) :“la salida de suma con entrada l es∑

l”I se puede hacer induccion en |l | (que toma valores en N)

I caso base: pruebo P(l) para l tal que |l | == 0.Es decir, tengo que probar P(l) para l == [ ].suma con entrada [ ] devuelve 0 = |l |.

I HI: vale P(l) para toda l tal que |l | ≤ n (n ∈ N)Quiero ver que vale P(l) para toda l tal que |l | == n + 1.Sea y tal que |y | == n + 1. Quiero ver que vale P(y).Como |y | == n + 1, sabemos que y == x : xs para alguna lista xs y entero x .La salida de suma con entrada y es x + salida de suma con entrada xs.Uso la HI (notar que |xs| ≤ n): la salida de suma con entrada y es x +

∑xs.

Por propiedad de∑

, x +∑

xs ==∑

(x : xs) ==∑

y .Entonces la salida de suma con entrada y es

∑y .

Es decir, vale P(y). 185

Principio de induccion para tipos algebraicosI se llama induccion estructural. La van a estudiar en Algoritmos y

Estructuras de Datos II

I sea P(x) una propiedad de un elemento x de un tipo algebraico T

I supongamos que queremos probar que vale P(x) para todo x de tipo T

I sea c una funcion matematica T → N

I el axioma de induccion dice:I si

I P(y) es verdadero para toda y tal que c(y) = 0 yI para todo y , si ∀y (c(y) = n→ P(y)) entonces ∀y (c(y) = n + 1→ P(y))

I entonces P(y) es verdadero para todo y de tipo T

I el axioma de induccion completa dice:I si

I P(y) es verdadero para toda y tal que c(y) = 0 yI para todo y , si ∀y (c(y) ≤ n→ P(y)) entonces ∀y (c(y) = n + 1→ P(y))

I entonces P(y) es verdadero para todo y de tipo T

I en el ejemplo anterior T es el tipo [Int] yI P(y) dice “la funcion suma con entrada y devuelve

∑y”

I c(y) = |y |. 186

Reduccion

Modelo de computo:

I como se calcula el valor de una expresionI puede afectar la semantica

I distintos modelos pueden dar distintos resultados

Reduccion:

I mecanismo de evaluacion en HaskellI reemplazar una subexpresion por otra

I reemplazada:I instancia del lado izquierdo de una ecuacion orientadaI se llama redex (reducible expression) o radical

I reemplazante:I lado derecho, instanciado de manera acordeI el resto de la expresion queda igual

I instanciacionI asignacion de expresiones a variables de un pattern

187

Ejemplo

I expresionsuma (restar 2 (amigos Juan)) 4

I ecuacionrestar x y = x - y

I reduccion

1. busco un redex y asignacionsuma (restar 2 (amigos Juan)︸ ︷︷ ︸

redex

) 4

I asignacion:x ← 2

y ← (amigos Juan)

2. reemplazo el redex con esa asignacion

suma (restar 2 (amigos Juan)) 4 suma (2 - (amigos Juan)) 4

188

Page 48: Algoritmos y Estructuras de Datos II

Formas normales

I valor de una expresionI sigo reduciendo hasta que no haya mas redexes

I obtengo una forma normalI solamente constantes y constructores

I son formas normalesI 2I (3, True, C 5.1 (-6.2))

I no son formas normalesI 1 + 1I (9 ‘quot‘ 3, 3>=2, sumarC (C 1.05 (-12.4)) (C 4.05

(6.2)))

189

Mecanismo de reduccion

1. si la expresion esta en forma normal, terminamos

2. si no, buscar un redex

3. reemplazarlo

4. volver a empezar

I todos los mecanismos de reduccion comparten este algoritmoI las estrategias dependen del paso 2

I en que orden elijo los redexesI se las llama ordenes de reduccion

I pueden influir en que se llegue o no a una forma normal

190

Normalizacion

I ¿toda expresion tiene forma normal?I no. Las siguientes expresiones no tienen forma normal

I f x = f (f x) ¿cuanto vale f 3?I infinito = infinito + 1 ¿cuanto vale infinito?I inverso x | x /= 0 = 1 / x ¿cuanto vale inverso 0?

I si se consigue, ¿toda estrategia encuentra la misma?I sıI se llama confluencia

191

Bottom

I las expresiones que no tienen forma normal se llamanindefinidas

I se puede decir que su valor es ⊥I podrıamos definirlo en Haskell

bottom :: abottom = bottom

I cualquier intento de evaluar bottom se indefineg :: Int -> Intg x = if x == bottom then 1 else 0g 2 ⊥

192

Page 49: Algoritmos y Estructuras de Datos II

IndefinicionI le pasamos un valor definido a una funcion

I parciales: a veces devuelven ⊥I totales: nunca

I le pasamos ⊥ a una funcionI ¿devuelve ⊥?

I no siempreI depende de sus ecuaciones y del orden de reduccion

I estrictas: f⊥ ⊥I no estrictas: f⊥ valor

Totales vs. parciales

I totalsuc :: Integer -> Integer

suc x = x + 1

I parcialesrecip :: Float -> Float

recip x | x /= 0 = 1/x

I las dos son estrictasI si les paso ⊥ devuelven ⊥

Estrictas vs. no estrictas

I ecuacionesconst :: a -> b -> a

const x y = x

I ¿cuanto vale?I const 2 infinito

Depende del diseno del lenguaje. Elsecreto esta en el orden de evaluacion

193

Orden de evaluacion

I forma de elegir el proximo redexI recordar confluencia

I si por dos ordenes llegamos a valores definidos, es el mismovalor

I pero puede ser que un orden llegue a ⊥ y otro no

infinito :: Integer -> Integer

infinito = infinito + 1

const :: a -> b -> a

const x y = x

const 2 infinito

2 const 2 (infinito+1)

2 const 2 ((infinito+1)+1)

2 . . .

194

Ordenes de evaluacion

I aplicativoI primero redexes internosI primero los argumentos, despues la aplicacion

I normalI el redex mas externo

I para el que pueda hacer pattern matching

I primero la aplicacion, despues los argumentosI si se necesitan

I siempre encuentra la forma normalI si la hay

I los dos empiezan a izquierdaI en caso de mas de un redex del mismo nivel

195

Ejemplos de evaluacion aplicativa

f x = 0

f (1/0) se indefine

————————————————————————————

infinito :: Integer -> Integer

infinito = infinito + 1

const :: a -> b -> a

const x y = x

const 2 infinito const 2 (infinito+1) const 2 ((infinito+1)+1) const 2 (((infinito+1)+1)+1) . . .

————————————————————————————

head :: [a] -> a

head (x:xs) = x

tail :: [a] -> a

tail (x:xs) = xs

inc :: [a] -> a

inc [] = []

inc (x:xs) = (x+1):inc xs

head (tail (inc [1,2,3,4])) head (tail (2:inc [2,3,4])) head (tail (2:3:inc [3,4])) head (tail (2:3:4:inc [4])) head (tail (2:3:4:5:inc [])) head (tail (2:3:4:5:[])) head (3:4:5:[]) 3

196

Page 50: Algoritmos y Estructuras de Datos II

Ejemplos de evaluacion normal

f x = 0

f (1/0) 0

————————————————————————————

infinito :: Integer -> Integer

infinito = infinito + 1

const :: a -> b -> a

const x y = x

const 2 infinito 2

————————————————————————————

head :: [a] -> a

head (x:xs) = x

tail :: [a] -> a

tail (x:xs) = xs

inc :: [a] -> a

inc [] = []

inc (x:xs) = (x+1):inc xs

head (tail (inc [1,2,3,4])) head (tail (2:inc [2,3,4])) head (inc [2,3,4]) head (3:inc [3,4]) 3

197

Propiedades de los ordenes

I orden aplicativoI const es estrictaI todas son estrictas

I orden normalI const es no estrictaI hay funciones estrictas y no estrictasI depende de si necesitan evaluar todos sus argumentos

198

Ordenes y performance

fib 1 = 1fib 2 = 1fib n | n > 2 = fib (n-1) + fib (n-2)

¿Cuantas reducciones necesito?

I fib 20 → 200.000I const 3 (fib 20) → ?

I aplicativo: 200.001I normal: 1

I quin x = x + x + x + x + xquin (fib 20) → ?

I aplicativo: 200.005I normal: (fib 20) + (fib 20) + (fib 20) + (fib 20) + (fib 20) →

1.000.000

199

Evaluacion lazy

I perezosa, haragana, fiaca

I algoritmo usado en HaskellI orden normal, pero...

I aprovecha la transparencia referencialI si una expresion vuelve a aparecer, se acuerda el valor anteriorI quin (fib 20) → 200.005

200

Page 51: Algoritmos y Estructuras de Datos II

Estructuras infinitas

I es una ventaja de la evaluacion lazyI ejemplos

I naturales, pares, impares :: [Integer]naturales = secuencia 0 1impares = secuencia 1 2pares = secuencia 0 2

secuencia :: Integer -> Integer -> [Integer]secuencia n p = n:secuencia (n+p) p

I evaluacion de estructuras infinitasI head naturales head (secuencia 0 1)

head (0:secuencia 1 1) 0I take 10 impares · · · [1,3,5,7,9,11,13,15,17,19]

201

Alto ordenI filtrar los elementos mayores a 2 de una lista:

filtroMayoresADos :: [Int] -> [Int]

filtroMayoresADos [] = []

filtroMayoresADos (x:xs) | x>2 = x:filtroMayoresADos xs

| otherwise = filtroMayoresADos xs

I filtrar los elementos pares de una lista:filtroPares :: [Int] -> [Int]

filtroPares [] = []

filtroPares (x:xs) | (x ‘mod‘ 2==0) = x:filtroPares xs

| otherwise = filtroPares xs

I mas general:filter: (Int -> Bool) -> [Int] -> [Int]

filter f [] = []

filter f (x:xs) | f x = x:filter f xs

| otherwise = filter f xs

I filtroMayoresADos xs = filter mayorADos xs

where mayorADos x = x>2I filtroPares xs = filter par xs

where par x = (x ‘mod‘ 2 == 0)

I las funciones de alto orden son aquellas que reciben odevuelven funciones 202

Alto ordenI sumar los elementos de una lista

suma [] = 0

suma (n:ns) = n + suma ns

I verificar que sean todos verdaderosall [] = True

all (b:bs) = b && all bs

I aplanar una lista de listasconcat [] = []

concat (xs:xss) = xs ++ concat xss

I mas general:foldr f a [] = a

foldr f a (x:xs) = x ‘f‘ (foldr f a xs)

I suma = foldr (+) 0I all = foldr (&&) TrueI concat = foldr (++) []

I ¿cual es el tipo de foldr?I de los ejemplos se deduce (a -> a -> a) -> a -> [a] -> a

I pero puede ser un poco mas general:(a -> b -> b) -> b -> [a] -> b

203

Currificacion

I suma’ :: (Int , Int) -> Intsuma’ (x,y) = x + y

I recibe un par ordenado

I suma :: Int -> Int -> Intsuma x y = x + y

I el tipo de suma se interpreta comosuma :: Int -> (Int -> Int)

I es una funcion que recibe un entero y devuelve una funcion deenteros en enteros

I ¿que es suma 1?I una funcion de tipo Int -> IntI (suma 1) y = suma 1 y = 1+y

I ¿que es suma 23?I tambien es una funcion de tipo Int -> IntI (suma 23) y = suma 23 y = 23+y

I en general suma x y = (suma x) y = x+y

204

Page 52: Algoritmos y Estructuras de Datos II

Programacion imperativaClase 1

Introduccion a la programacion imperativa

205

Programacion imperativa (diferencias con funcional)I los programas no necesariamente son funciones

I ahora pueden devolver mas de un valorI hay nuevas formas de pasar argumentos

I nuevo concepto de variablesI posiciones de memoriaI cambian explıcitamente de valor a lo largo de la ejecucion de

un programaI perdida de la transparencia referencial

I nueva operacion: la asignacionI cambiar el valor de una variable

I las funciones no pertenecen a un tipo de datosI distinto mecanismo de repeticion

I en lugar de la recursion usamos la iteracionI nuevo tipo de datos: el arreglo

I secuencia de valores de un tipo (como las listas)I longitud prefijadaI acceso directo a una posicion (en las listas, hay que acceder

primero a las anteriores)

206

Lenguaje C++

I vamos a usarlo para la programacion imperativa (tambiensoporta parte del paradigma de objetos)

I vamos a usar un subconjunto (como hicimos con Haskell)I no objetos, no memoria dinamica, etc.I sı vamos a usar la notacion de clases, para definir tipos de

datos

I el tipado es mas debil que el de HaskellI tipos basicos:

I charI floatI int

(con minuscula)

207

Programa en C++

I coleccion de tipos y funciones

I definicion de funcion

tipoResultado nombreFuncion (parametros)bloqueInstrucciones

I ejemplo

int suma2 (int x, int y) {int res = x + y;return res;

}

I su evaluacion consiste en ejecutar una por una lasinstrucciones del bloque

I el orden entre las instrucciones es importanteI siempre de arriba hacia abajo

208

Page 53: Algoritmos y Estructuras de Datos II

Variables en imperativo

I nombre asociado a un espacio de memoria

I puede cambiar de valor varias veces en la ejecucionI en C++ se declaran dando su tipo y su nombre

I int x; −→ x es una variable de tipo intI char c; −→ c es una variable de tipo char

I programacion imperativaI conjunto de variablesI instrucciones que van cambiando sus valoresI los valores finales, deberıan resolver el problema

209

La asignacionI operacion fundamental para modificar el valor de una variableI sintaxis

variable = expresion;

I operacion asimetricaI lado izquierdo: debe ir una variable u otra expresion que

represente una posicion de memoriaI lado derecho: puede ser una expresion del mismo tipo que la

variableI constanteI variableI funcion aplicada a argumentos

I efecto de la asignacion1. se evalua el valor de la expresion de la derecha2. ese valor se copia en el espacio de memoria de la variable3. el resto de la memoria no cambia

I ejemplos: x = 0; y = x; x = x+x;

x = suma2(z+1,3); x = x*x + 2*y + z;I no son asignaciones:

3 = x; doble (x) = y; 8*x = 8;210

La instruccion return

I termina la ejecucion de una funcion

I retorna el control a su invocador

I devuelve la expresion como resultado

int suma2 (int x, int y) {int res = x + y;return res;

}

int suma2 (int x, int y) {return x + y;

}

211

Transformacion de estados

I llamamos estado de un programa a los valores de todas susvariables en un punto de su ejecucion

I antes de ejecutar la primera instruccionI entre dos instruccionesI despues de ejecutar la ultima instruccion

I podemos ver una ejecucion de un programa como unasucesion de estados

I la asignacion es la instruccion que transforma estadosI el resto de las instrucciones son de control

I modifican el flujo de ejecucionI orden de ejecucion de las instrucciones

212

Page 54: Algoritmos y Estructuras de Datos II

Afirmaciones en imperativoI al demostrar una propiedad, agregamos afirmaciones sobre el

estado entre instruccionesI se amplıa el lenguaje de especificacion con la sentencia vale

vale nombre: P;

I el nombre (nombre) es opcionalI P es un predicado

I expresion de tipo Bool del lenguaje de especificacionI se coloca entre dos instruccionesI significa que P vale en ese punto del programa en cualquier

ejecucionI el compilador no entiende las sentencias del lenguaje de

especificacionI para que no de error, las ponemos en comentarios

I como en Haskell, pero con otra sintaxisI hay dos maneras:

I // comenta una sola lıneaI /*...*/ comenta varias lıneas

213

Clausulas vale y estado

I ejemplo de codigocon afirmaciones

x = 0;//vale x == 0;

x = x + 3;//vale x == 3;

x = 2 * x;//vale x == 6;

I para referirnos al valor que tenıa en un estadoanterior

I usamos estado para dar un nombre al estado

I nos referimos al estado anterior con

variable@nombreEstado

I semantica de la asignacion:

//estado av = e;

//vale v == e@a

I despues de ejecutar la asignacion, la variable vtiene el valor que tenıa antes la expresion e

I en cada ejecucion el estado puede ser distinto

214

Clausula preI el operador pre se refiere al estado previo a la ejecucion de

una funcion

pre(expresion)

I representa el valor de la expresion en el estado inicialI cuando los parametros de una funcion reciben el valor de los

argumentos con los que se la invoco

problema suc(x : Int) = res : Int {asegura res == x + 1; }

int suc(int x) {int y = x;

//estado a//vale y == x ;

y = y + 1;//vale y == y@a + 1;

return y;}

int suc(int x) {//local x//vale x == pre(x)

x = x + 1;//vale x == pre(x) + 1;

return x;}

215

Clausula localI en las afirmaciones, se presupone que los parametros mantienen su valor inicialI en cualquier estado n

vale parametro@n == pre(parametro)

I evita tener que repetir esta afirmacion en cada estado, exceptoI parametros que aparecen en clausulas modifica de la especificacionI si queremos usar un parametro como variable temporaria, usamos la

clausula local

problema suma1(x , y : Int) {modifica x ;asegura x == pre(x) + y ; }

void suma1(int &x, int y) {//estado a//vale x == pre(x);//vale y == pre(y); (no hace falta)

x = x + y;//vale x == pre(x) + y ;//vale y == pre(y); (no hace falta)

}

problema suma2(x , y : Int) = res : Int {asegura res == x + y ; }

int suma2(int x, int y) {//local x//vale x == pre(x);//vale y == pre(y); (no hace falta)

x = x + y;//vale x == pre(x) + y ;//vale y == pre(y); (no hace falta)

return x;}

216

Page 55: Algoritmos y Estructuras de Datos II

Clausula implicaI clausula

implica P;

I se pone despues de una o mas afirmaciones vale o implicaI indica que P se deduce de las afirmaciones anteriores

problema suc(x : Int) = res : Int {asegura res == x + 1; }

¡todas las clausulas implica deben serjustificadas!

I en el ejemplo,I //implica x == pre(x) + 2− 1: sale

de reemplazar x@a por pre(x) + 2,de acuerdo a lo que dice el estado a

I //implica x == pre(x) + 1:operaciones aritmeticas

I //implica res == pre(x) + 1: sale dereemplazar x@b por pre(x) + 1, deacuerdo a lo que dice el estado b

int suc(int x) {//local x

x = x + 2;//estado a//vale x == pre(x) + 2;

x = x - 1;//estado b//vale x == x@a− 1;//implica x == pre(x) + 2− 1;//implica x == pre(x) + 1;

return x;//vale res == x@b;//implica res == pre(x) + 1;

} 217

Pasaje de argumentos

I los argumentos tienen que pasar del invocador al invocado

I hay que establecer una relacion entre argumentos y parametrosI las convenciones mas habituales son dos

I por valorI antes de hacer la llamada se obtiene el valor del argumentoI se lo coloca en la posicion de memoria del parametro correspondienteI durante la ejecucion de la funcion, se usan esas copias de los

argumentosI por eso tambien se llama por copiaI los valores originales quedan protegidos contra escritura

I por referenciaI en la memoria asociada a un parametro se almacena la direccion de

memoria del argumento correspondienteI el parametro se convierte en una referencia indirecta al argumentoI todas las asignaciones al parametro afectan directamente el valor de la

variable pasada como argumentoI el argumento no puede ser una expresion cualquiera (por ejemplo, un

literal) debe indicar un espacio de memoria (en general, es una variable)

218

Referencias en C++

I referencia a una variable

I constructor de tipos &

I actua como un alias (se usa sin sintaxis especial, como el tipooriginal)

int &b = a;b = 3;

//vale a == b == 3;a = 4;

//vale a == b == 4;

I complica la comprension del programa y su semantica

I por eso pedimos que una posicion de memoria no tenga dosnombres

219

Pasaje de argumentos en C++I siempre por valorI para pasar por referencia, se usan referenciasI tambien se pasan por valor (copia), pero lo que se copia no es

el valor del argumento, se copia su direccionI la modificacion del parametro implica modificacion del

argumentoI indicamos que parametros son de tipo referencia con el

operador & (pueden usarse como parametros de salida o deentrada/salida)

void A(int &i) {i = i-1;

}

void B(int i) {i = i-1;

}

void C() {int j = 6;

//vale j == 6;A(j);

//vale j == 5;B(j);

//vale j == 5;}

I no se puede pasar a A una expresion que no sea una variable(u otra descripcion de una posicion de memoria) 220

Page 56: Algoritmos y Estructuras de Datos II

Pasaje por referencia para las variables en modifica

I en el lenguaje de especificacion sabemos indicar que los argumentosse modificanproblema swap(x , y : Int) {

modifica x , y ;

asegura x == pre(y) ∧ y == pre(x); }I los lenguajes imperativos permiten implementar esto directamente

void swap(int& x, int& y) {int z; //estado 1; vale x == pre(x) ∧ y == pre(y);z = x; //estado 2; vale z == x@1 ∧ x == x@1 ∧ y == y@1;x = y; //estado 3; vale z == z@2 ∧ x == y@2 ∧ y == y@2;y = z; //estado 4; vale z == z@3 ∧ x == x@3 ∧ y == z@3;

//implica x == pre(y) ∧ y == pre(x);}

I justificacion del implica: x == x@3 == y@2 == y@1 == pre(y);y == z@3 == z@2 == z@1 == pre(x)

I el estado 4 cumple la poscondicion (entonces, la funcion es correctarespecto de su especificacion)

221

¿Que hace esta funcion?void prueba(int &x, int &y) {

//estado 1; vale x == pre(x) ∧ y == pre(y);x = x + y;

//estado 2; vale y == y@1 ∧ x == x@1 + y@1;//implica x == pre(x) + pre(y); (pues y@1 == pre(y) y x@1 == pre(x))

y = x - y;//estado 3; vale x == pre(x) + pre(y) ∧ y == x@2− y@2;//implica y == pre(x) + pre(y)− pre(y); (pues y@2 == y@1 == pre(y))

//implica y == pre(x); (operaciones aritmeticas)

x = x - y;//estado 4; vale y == pre(x) ∧ x == x@3− y@3;//implica x == pre(x) + pre(y)− pre(x); (justificacion trivial)

//implica y == pre(x) ∧ x == pre(y); (operaciones aritmeticas)

}por lo tanto, esta funcion tambien es correcta respecto de la especificaciondel problema swap

I salvo que sea llamada con prueba(x,x)222

Invocacion de funciones - pasaje por valor

problema doble(x : Int) = res : Int {asegura res == 2 ∗ x ; }

problema cuad(x : Int) = res : Int {asegura res = 4 ∗ x ; }

int cuad(int x) {int c = doble(x);

//estado 1;//vale c == 2 ∗ x ; (usando la poscondicion de doble)

c = doble(c);//vale c == 2 ∗ c@1; (usando la poscondicion de doble)//implica c == 2 ∗ 2 ∗ x == 4 ∗ x ; (justificacion trivial)

return c;//vale res == 4 ∗ x ;

}

223

Invocacion de funciones - pasaje por referenciaproblema swap(x , y : Int) {

modifica x , y ;asegura x == pre(y) ∧ y == pre(x); }

problema swap3(a, b, c : Int) {modifica a, b, c ;asegura a == pre(b) ∧ b == pre(c) ∧ c == pre(a); }

void swap3(int& a, int& b, int& c) {//vale a == pre(a) ∧ b == pre(b) ∧ c == pre(c);

swap(a,b);//estado 1;//vale a == pre(b) ∧ b == pre(a); (usando la poscondicion de swap)//vale c == pre(c);

swap(b,c) ;//estado 2;//vale b == c@1 ∧ c == b@1; (usando la poscondicion de swap)//vale a == a@1;//implica a == pre(b) ∧ b == pre(c) ∧ c == pre(a); (justificar...)

}224

Page 57: Algoritmos y Estructuras de Datos II

Programacion imperativaClase 2

Teorema del Invariante

225

AsignacionSemantica de la asignacion:

I sea e una expresion cuya evaluacion no modifica el estado

//estado av = e;

//vale v == e@a ∧ z1 = z1@a ∧ · · · ∧ zk = zk@a

I donde z1, . . . , zk son todas las variables del programa encuestion distintas a v que aparezcan en una clausula modificao local

I las otras variables se supone que no cambian ası que no hacefalta decir nada)

I si la expresion e es la invocacion a una funcion que recibeparametros por referencia, puede haber mas cambios, pero almenos

//vale v == e@a

esta en la poscondicion de la asignacion226

CondicionalesI supongamos este codigo:

if (B) uno else dos;

I B tiene que ser una expresion booleana (verdadera o falsa) sinefectos secundarios (no tiene que modificar el estado)

I se llama guardaI uno y dos son instrucciones

I en particular, pueden ser bloques (entre llaves)

I si sabemos que

//vale P ∧ Buno;

//vale Q

//vale P ∧ ¬Bdos;

//vale Q

I entonces podemos afirmar

//vale Pif (B) uno else dos;

//vale Q

I decimos que P es la precondicion del condicional y Q es suposcondicion 227

Condicionales

Equivalentemente:

I si sabemos que

//vale P ∧ Buno;

//vale Q1

//vale P ∧ ¬Bdos;

//vale Q2

I entonces podemos afirmar

//vale Pif (B) uno else dos;

//vale Q1 ∨ Q2

228

Page 58: Algoritmos y Estructuras de Datos II

Ejemplo de demostracion de condicional

problema max(x , y : Int) = result : Int{asegura Q : (x > y ∧ result == x) ∨ (x ≤ y ∧ result == y)

}

int max(int x, int y) {int m = 0;

//vale Pif : m == 0;if (x > y)

m = x;else

m = y;//vale Qif : (x > y ∧m == x) ∨ (x ≤ y ∧m == y);

return m;//vale Q;

}

229

Ejemplo de demostracion de condicional

I demuestro cada rama fuera del condicionalI rama true:

//vale m == 0 ∧ x > y ;m = x;

//vale x > y ∧m == x ;//implica (x > y ∧m == x) ∨ (x ≤ y ∧m == y);(justificacion: p → (p ∨ q) es tautologıa)

I rama false://vale m == 0 ∧ x ≤ y ;

m = y;//vale x ≤ y ∧m == y ;//implica (x > y ∧m == x) ∨ (x ≤ y ∧m == y);(justificacion: p → (p ∨ q) es tautologıa)

I pudimos llegar a Qif por las dos ramas,I entonces demostre que el condicional es correcto para la

precondicion Pif y poscondicion Qif

230

Ciclos

I while (B) cuerpo;I B: expresion booleana, sin efectos colaterales

I tambien se la llama guarda

I cuerpo es una instruccionI en particular, puede ser un bloque (entre llaves)I se repite mientras B valga

I cero o mas vecesI si es una cantidad finita, el programa terminaI si es > 0, alguna de las ejecuciones tiene que hacer B falsaI y el estado final de esa ejecucion sera el estado final del ciclo

231

Ejemplo de ciclo

problema sumat(x : Int) = r : Int{requiere P : x ≥ 0asegura r ==

∑[0..x ]

}

I en funcionalsumat :: Int -> Intsumat 0 = 0

sumat n = n + (sumat (n-1))

I en imperativoint sumat (int x) {

int s = 0, i = 0;while (i < x) {

// estado 1i = i + 1;s = s + i;

// estado 2}return s;

}

estados para x == 4i@1 s@1 i@2 s@2

0 0 1 1

1 1 2 3

2 3 3 6

3 6 4 10

Observar que en cada paso:I 0 ≤ i ≤ x

I cuando i == x , sale del ciclo

I s ==∑

[0..i ]

Estas dos valen en estado 1 y estado2 (pero no en el medio) 232

Page 59: Algoritmos y Estructuras de Datos II

Otro ejemplo de ciclo

problema fact(x : Int) = r : Int{requiere P : x ≥ 0asegura r ==

∏[1..x ]

}

I en funcionalfact :: Int -> Intfact 0 = 1

fact n = n * (fact (n-1))

I en imperativoint fact (int x) {

int f = 1, i = 0;while (i < x) {

// estado 1i = i + 1;f = f * i;

// estado 2}return f;

}

estados para x == 4i@1 f @1 i@2 f @2

0 1 1 1

1 1 2 2

2 2 3 6

3 6 4 24

Observar que en cada paso:I 0 ≤ i ≤ x

I cuando i == x , sale del ciclo

I f ==∏

[1..i ]

Estas dos valen en estado 1 y estado2 (pero no en el medio) 233

Semantica de ciclosI la semantica requiere cuatro expresiones del lenguaje de

especificacionI una precondicion PC

I una poscondicion QC

I un invariante II una guarda B

I invarianteI condicion cuya veracidad es preservada por el cuerpo del cicloI vale antes de entrar al ciclo (justo antes de evaluar la guarda por

primera vez)I vale en cada iteracion

I justo despues de entrar al cuerpo delciclo

I y justo despues de ejecutar la ultimainstruccion del cuerpo del ciclo

I pero pude no valer en el medio delcuerpo

//vale PC ;while (B) {

//vale I ∧ B;cuerpo//vale I ;

}//vale QC ;

I no hay forma algorıtmica de encontrarloI conviene darlo al escribir el ciclo, porque encierra la idea del

programador o disenador 234

Terminacion y correctitud

//vale PC ;while (B) {

//vale I ∧ B;cuerpo//vale I ;}

//vale QC ;

Herramientas:

I PC = precondicion del ciclo

I QC = poscondicion del ciclo

I I invariante

I B guarda

Especificacion del ciclo = (PC ,QC )

I un ciclo termina (con respecto a la especificacion del ciclo) sino importa para que valores de entrada que satisfagan PC , elciclo, despues de una cantidad finita de pasos termina (esdecir, se verifica ¬B)

I para demostrar esto, necesitamos herramientas adicionales:I funcion varianteI cota

I un ciclo es correcto (con respecto a la especificacion del ciclo)si termina y al salir satisface QC

I para demostrar esto, vamos a usar fuertemente el invariante

235

Terminacion

I ¿como podemos garantizar queel ciclo termina?

I similares a conceptos que vimospara programacion funcional

//vale PC ;while (B) {

//vale I ∧ B;cuerpo//vale I ;}

//vale QC ;I para hablar de la cantidad de veces que se ejecuta un ciclo

necesitamos:I expresion variante (v)

I es una expresion del lenguajede especificacion, de tipo Int

I usa variables del programa

I debe decrecer en cada paso

//estado a;//vale B ∧ I ;cuerpo//vale v < v@a;

I cota (c)I valor (fijo, por ejemplo 0 o −8) que, si es alcanzado o pasado

por la expresion variante, garantiza que la ejecucion sale delciclo

I mas formalmente: (I ∧ v ≤ c)→ ¬B236

Page 60: Algoritmos y Estructuras de Datos II

Teorema de terminacion

TeoremaSi v es una expresion variante (con las propiedades de la p. 236) eI es un invariante (con las propiedades de la p. 234) de un ciclo yc es una cota tal que (I ∧ v ≤ c)→ ¬B, entonces el ciclo termina.

Demostracion.I por el absurdo: supongamos que el ciclo no termina

I sea vj el valor que toma v despues de ejecutar el cuerpo delciclo por j-esima vez (j ≥ 0)

I como v es estrictamente decreciente, v1 > v2 > v3 > . . .

I como v es de tipo Int, vj ∈ N para todo j

I debe existir un k tal que vk ≤ c

I como vale (I ∧ v ≤ c)→ ¬B, tenemos que para este k vale¬B y por lo tanto sale del ciclo (despues de iterar k veces)

I llegamos a un absurdo porque habıamos supuesto que el ciclono terminaba. Entonces el ciclo termina.

¿Que pasarıa si v fuese de tipo Float? ¿Funciona igual la demo? 237

Observaciones sobre terminacionint dec1(int x) {

while (x > 0)

x = x - 1;

return x;

}

int dec2(int x) {while (x != 0)

x = x - 1;return x;

}Supongamos que x no es negativo

I la implicacion (I ∧ v ≤ c)→ ¬B:I el invariante deberıa ser I : x ≥ 0 en los dos casosI ambos devuelven 0I iteran la misma cantidad de veces (x veces)

I ¿hace falta I en (I ∧ v ≤ c)→ ¬B?I en los dos casos, v = x y c = 0 deberıan ser buenas

x ≤ 0→ x 6> 0, luego no se usa I para dec1pero x ≤ 0 6→ x == 0, luego hay que usar I para dec2usando I en dec2 tenemos: (x ≥ 0 ∧ x ≤ 0)→ x == 0

I si c es una buena cota, cualquier cota k < c tambien:I −2 es buena cota para dec1: x ≤ −2→ x ≤ 0→ x 6> 0I −2 es buena cota para dec2: (x ≥ 0 ∧ x ≤ −2)→ cualquier cosa

I ¡no hay trampa en este ejemplo!I si v es una buena funcion variante con cota k, v ′ = v − k es una

buena funcion variante con cota 0I entonces sin perdida de generalidad, podemos suponer siempre una cota 0238

Teorema de Correctitud

TeoremaSi un ciclo que termina satisface PC → I y (I ∧ ¬B)→ QC

entonces el ciclo es correcto con respecto a su especificacion.

Demostracion.Queremos ver que el ciclo es correcto para su especificacion, esdecir, queremos ver que para variables que satisfagan PC , cuandoel ciclo termina se satisface QC

I supongamos que las variables en el estado 1 satisfacenPC

I como PC → I , entonces en el estado 1 se satisface I

I ejecutamos el ciclo (0 o mas veces)

I por definicion de invariante (ver p. 234), en cadaiteracion, el invariante se restablece

I por hipotesis, el ciclo termina y en el estado 2 vale ¬B

I ademas, en el estado 2 vale I

I como (I ∧ ¬B)→ QC entonces en el estado 2 vale QC

//estado 1//vale PC ;

while (B) {//vale I ∧ B;cuerpo//vale I ;}

//estado 2//vale QC ;

239

Todo junto: Teorema del Invariante

TeoremaSea while (B) { cuerpo } un ciclo con guarda B,precondicion PC y poscondicion QC . Sea I un predicado booleano,v una funcion variante y c una cota. Si valen

1. PC → I

2. (I ∧ ¬B)→ QC

3. el invariante se preserva en la ejecucion delcuerpo, i.e. si I ∧ B vale en el estado Aentonces I vale en el estado B

4. v es decreciente, i.e. v@A > v@B

5. (I ∧ v ≤ c)→ ¬B

//estado Acuerpo//estado B

entonces para cualquier valor de las variables del programa quehaga verdadera PC , el ciclo termina y hace verdadera QC , i.e. elciclo cumple con su especificacion (PC ,QC ).

Demostracion.Combinar el Teorema de Terminacion (p. 237) y el Teorema deCorrectitud (p. 239). 240

Page 61: Algoritmos y Estructuras de Datos II

Ejemplo de demostracion de correctitudDemostracion de PC → I

problema sumat(x : Int) = r : Int{requiere P : x ≥ 0asegura r ==

∑[0..x ]

}

int sumat (int x) {int s = 0, i = 0;

//vale PC : s == 0 ∧ i == 0while (i < x) {

//invariante I : 0 ≤ i ≤ x ∧ s ==∑

[0..i ]//variante v : x − i

i = i + 1;s = s + i;

}//vale QC : i == x ∧ s ==

∑[0..x ]

return s;//vale r ==

∑[0..x ]

}

1. PC → I :

Supongamos que vale PC y veamosque vale cada parte de I

I 0 ≤ i : si i == 0 esto es trivialI i ≤ x : si i == 0 y x == 0

esto es trivialI s ==

∑[0..i ]: como s == 0 y

i == 0 hay que probar que0 ==

∑[0..0], pero esto es

trivial

241

Ejemplo de demostracion de correctitudDemostracion de (I ∧ ¬B)→ QC

problema sumat(x : Int) = r : Int{requiere P : x ≥ 0asegura r ==

∑[0..x ]

}

int sumat (int x) {int s = 0, i = 0;

//vale PC : s == 0 ∧ i == 0while (i < x) {

//invariante I : 0 ≤ i ≤ x ∧ s ==∑

[0..i ]//variante v : x − i

i = i + 1;s = s + i;

}//vale QC : i == x ∧ s ==

∑[0..x ]

return s;//vale r ==

∑[0..x ]

}

2. (I ∧ ¬B)→ QC :

Supongamos que vale I ∧ ¬B yveamos que vale cada parte de QC porseparado:

I i == x : de I sabemos quei ≤ x y de ¬B sabemos i ≥ x

I s ==∑

[0..x ]: ya vimos quei == x . De I sabemoss ==

∑[0..i ].

242

Ejemplo de demostracion de correctitudDemostracion de que el cuerpo preserva el invariante

problema sumat(x : Int) = r : Int{requiere P : x ≥ 0asegura r ==

∑[0..x ]

}

int sumat (int x) {int s = 0, i = 0;

//vale PC : s == 0 ∧ i == 0while (i < x) {

//invariante I : 0 ≤ i ≤ x ∧ s ==∑

[0..i ]//variante v : x − i

i = i + 1;s = s + i;

}//vale QC : i == x ∧ s ==

∑[0..x ]

return s;//vale r ==

∑[0..x ]

}

3. el cuerpo preserva el invariante:

Hacemos la transformacion de estadosdel cuerpo:

//estado 1

//vale B ∧ I

//implica 0 ≤ i < x ∧ s ==∑

[0..i ]

(justificacion trivial)

i = i + 1;

//estado 2

//vale i == 1 + i@1 ∧ s == s@1

s = s + i;

//estado 3

//vale i == i@2 ∧ s == s@2 + i@2243

Ejemplo de demostracion de correctitudDemostracion de que el cuerpo preserva el invariante (cont.)

Transformacion de estados del cuerpo

//estado 1//vale B ∧ I//implica 0 ≤ i < x ∧ s ==

∑[0..i ]

i = i + 1;//estado 2//vale i == 1 + i@1 ∧ s == s@1

s = s + i;//estado 3//vale i == i@2 ∧ s == s@2 + i@2

Queremos ver que vale I @3:

I i@3 ≥ 0: sabemosi@3 == i@2 == 1 + i@1 y por elestado 1 sabemos i@1 ≥ 0. Luego1 + i@1 ≥ 0

I i@3 ≤ x@3: ya vimos quei@3 == 1 + i@1. Como x no cambiaporque es una variable de entrada queno aparece ni en modifica ni en local,x@3 == x@1. Del estado 1 sabemosi@1 < x@1. Sumando 1 en amboslados, 1 + i@1 < 1 + x@1. De lo quedijimos antes, i@3 < 1 + x@3 y estoes equivalente a i@3 ≤ x@3.

I s@3 ==∑

[0..i@3]: ya vimos quei@3 == 1 + i@1. Sabemos ques@3 == s@2 + i@2 == 1 + s@1 + [email protected] s@1 ==

∑[0..i@1], entonces

s@3 ==∑

[0..i@1] + 1 + i@1 ==∑[0..1 + i@1] ==

∑[0..i@3]. 244

Page 62: Algoritmos y Estructuras de Datos II

Ejemplo de demostracion de correctitudDemostracion de que v es decreciente

problema sumat(x : Int) = r : Int{requiere P : x ≥ 0asegura r ==

∑[0..x ]

}

int sumat (int x) {int s = 0, i = 0;

//vale PC : s == 0 ∧ i == 0while (i < x) {

//invariante I : 0 ≤ i ≤ x ∧ s ==∑

[0..i ]//variante v : x − i

i = i + 1;s = s + i;

}//vale QC : i == x ∧ s ==

∑[0..x ]

return s;//vale r ==

∑[0..x ]

}

4. v es decreciente:

Recordemos la transformacion deestados

//estado 1

//vale B ∧ I

//implica 0 ≤ i < x ∧ s ==∑

[0..i ]

i = i + 1;

//estado 2

//vale i == 1 + i@1 ∧ s == s@1

s = s + i;

//estado 3

//vale i == i@2 ∧ s == s@2 + i@2

I v@3 == x@3− i@3 == pre(x)− i@3I v@1 == x@1− i@1 == pre(x)− i@1I ya vimos que i@3 = 1 + i@1I luego v@3 == pre(x)− (1 + i@1) <

pre(x)− i@1 == v@1245

Ejemplo de demostracion de correctitudDemostracion de (I ∧ v ≤ c)→ ¬B

problema sumat(x : Int) = r : Int{requiere P : x ≥ 0asegura r ==

∑[0..x ]

}

int sumat (int x) {int s = 0, i = 0;

//vale PC : s == 0 ∧ i == 0while (i < x) {

//invariante I : 0 ≤ i ≤ x ∧ s ==∑

[0..i ]//variante v : x − i

i = i + 1;s = s + i;

}//vale QC : i == x ∧ s ==

∑[0..x ]

return s;//vale r ==

∑[0..x ]

}

5. (I ∧ v ≤ c)→ ¬B:

Supongamos que vale I ∧ v ≤ c

I v ≤ c es equivalente ax − i ≤ 0, que es equivalentea x ≤ i y esto es ¬B

246

Programacion imperativaClase 3

Algoritmos de busqueda

247

Arreglos

I secuencias de una cantidad fija de variables del mismo tipoI se declaran con un nombre, un tamano y un tipo

I int a[10];I arreglo de 10 elementos enterosI nos referimos a los elementos a traves del nombre del arreglo y

un ındice entre corchetesI a[0], a[1],..., a[9]

I solamente hay valores en las posiciones validasI de 0 a la dimension menos unoI una referencia a una posicion fuera del rango da error (en

ejecucion)I el tamano se mantiene constante

248

Page 63: Algoritmos y Estructuras de Datos II

Arreglos y listas

I ambos representan secuencias de elementos de un tipo

I los arreglos tienen longitud fija; las listas, noI los elementos de un arreglo pueden accederse en forma

independienteI los de la lista se acceden secuencialmente, empezando por la

cabezaI para acceder al i-esimo elemento de una lista, hay que obtener

i veces la cola y luego la cabezaI para acceder al i-esimo elemento de un arreglo, simplemente se

usa el ındice

249

Arreglos en C++

I los arreglos en C++ son referenciasI pueden modificarse cuando son pasados como argumentos

I no hay forma de averiguar su tamano una vez que fueron creadosI el programa tiene que encargarse de almacenarlo de alguna formaI en la declaracion de un parametro no se indica su tamano

problema ceroPorUno(a : [Int], tam : Int){requiere tam == |a|;modifica a;

asegura a == [if i == 0 then 1 else i | i ← pre(a)[0..tam)]; }

void ceroPorUno(int a[], int tam) {int j = 0;while (j < tam) {

// invariante 0 ≤ j ≤ tam ∧ a[j ..tam) == pre(a)[j ..tam)∧// a[0..j) == [if i == 0 then 1 else i | i ← pre(a)[0..j)];// variante tam − j ;if (a[j] == 0) a[j] = 1;j++;

}}

250

Busqueda lineal sobre arreglosI Especificacion

problema buscar (a : [Int], x : Int, n : Int) = res : Bool{requiere n == |a| ∧ n > 0;asegura res == (x ∈ a);

}I Implementacion

bool buscar (int a[], int x, int n) {int i = 0;while (i < n && a[i] != x) {

i = i + 1;}return i < n;

}

El algoritmo de busqueda lineal

I es el mas ingenuoI revisa los elementos del arreglo en ordenI en el peor caso realiza n operaciones

251

Especificacion del ciclo

bool buscar(int a[], int x, int n) {int i = 0;

// vale Pc : i == 0

while (i < n && a[i] != x) {

// invariante I : 0 ≤ i ≤ n ∧ x /∈ a[0..i)// variante v : n − i

i = i + 1;}

// vale Qc : i < n↔ x ∈ a[0..n)

return i < n;}

252

Page 64: Algoritmos y Estructuras de Datos II

Correctitud del ciclo

// vale Pc// implica I

while (i < n && a[i] != x) {

// estado E// vale I ∧ i < n ∧ a[i ] 6= x

i = i+1;

// estado F// vale I// vale v < v@E

}

// vale I ∧ ¬(i < n ∧ a[i ] 6= x)// implica Qc

1. El cuerpo del ciclo preservael invariante

2. La funcion variante decrece

3. Si la funcion variante pasa lacota, el ciclo termina:v ≤ 0⇒ ¬(i < n ∧ a[i ] 6= x)

4. La precondicion del cicloimplica el invariante

5. La poscondicion vale al final

El Teorema del Invariante nos garantiza que si valen 1, 2, 3, 4 y 5,el ciclo termina y es correcto con respecto a su especificacion.

253

1. El cuerpo del ciclo preserva el invarianteRecordar que

I el invariante es I : 0 ≤ i ≤ n ∧ x /∈ a[0..i)

I la guarda B es i < n ∧ a[i ] 6= x

// estado E (invariante + guarda del ciclo)// vale 0 ≤ i ≤ n ∧ x /∈ a[0..i) ∧ i < n ∧ a[i ] 6= x// implica 0 ≤ i < n (juntando 0 ≤ i ≤ n y i < n)// implica x /∈ a[0..i ] (juntando x /∈ a[0..i) y a[i ] 6= x)// implica x /∈ a[0..i + 1) (propiedad de listas)

i = i + 1;

// estado F// vale i = i@E + 1// implica 1 ≤ i@E + 1 < n + 1 (esta en E y sumando 1 en cada termino)// implica 0 ≤ i ≤ n (usando que i == i@E + 1 y propiedad de Z)// implica x /∈ a[0..i@E + 1) (esta en E ; a no puede cambiar)// implica x /∈ a[0..i) (usando que i == i@E + 1)// implica I (se reestablece el invariante)

254

2. La funcion variante decrece

// estado E (invariante + guarda del ciclo)// vale I ∧ B

i = i + 1;

// estado F// vale i == i@E + 1

¿Cuanto vale v = n − i en el estado F ?

v@F == (n − i)@F

== n − i@F

== n − (i@E + 1)

== n − i@E − 1

< n − i@E

== v@E

255

5. La poscondicion vale al final

Quiero probar que:

1︷ ︸︸ ︷0 ≤ i ≤ n ∧

2︷ ︸︸ ︷x /∈ a[0..i) ∧

5︷ ︸︸ ︷(i ≥ n ∨ x == a[i ])

⇓Qc : i < n︸ ︷︷ ︸

3

↔ x ∈ a[0..n)︸ ︷︷ ︸4

Demostracion:

I supongamos i ≥ n (i.e. 3 es falso). Por 1, i == n. Por 2,tenemos x /∈ a[0..n). Luego 4 tambien es falso.

I supongamos i < n (i.e. 3 es verdadero). Por 5, x == a[i ]. De1 concluimos que 4 es verdadero.

256

Page 65: Algoritmos y Estructuras de Datos II

3 y 4 son triviales

3. Si la funcion variante pasa la cota, el ciclo termina:

n − i ≤ 0 ⇒ n ≤ i ⇒ ¬B

4. La precondicion del ciclo implica el invariante

i == 0 ⇒ 0 ≤ i ≤ n ∧ x /∈ a[0..i)

Entonces el ciclo es correcto con respecto a su especificacion.Observar que

// estado H// vale Qc : i < n↔ x ∈ a[0..n)

return i < n;

// vale res == (i < n)@H ∧ i = i@H// implica res == x ∈ a[0..n) (esta es la poscondicion del problema)

257

Complejidad de un algoritmo

I maxima cantidad de operaciones que puede realizar elalgoritmo

I hay que buscar los datos de entrada que lo hacen trabajar mas

I se define como funcion del tamano de la entradaI T (n), donde n es la cantidad de datos recibidos

I notacion O grandeI decimos que T (n) es O(f (n)) cuando

I T (n) es a lo sumo una constante por f (n)I excepto para valores pequenos de n

I T (n) es O(f (n)) sii (∃c , n0)(∀n ≥ n0) T (n) ≤ c · f (n)I se suele leer T (n) es del orden de f (n)

258

Complejidad de la busqueda lineal

I ¿cuando se da la maxima cantidad de pasos?I cuando el elemento no esta en la estructura

I ¿cuantos pasos son?I tantos como elementos tenga la estructura

I la complejidad del algoritmo es del orden del tamano de laestructura

I en un arreglo o lista, hay que hacer tantas comparaciones (ysumas) como elementos tenga el arreglo o lista

I si llamamos n a la longitud de la estructuraI el algoritmo tiene complejidad O(n)I en cada paso tengo cuatro operaciones (dos comparaciones,

una conjuncion y el incremento del ındice), entonces c = 4I pero esto no es importanteI lo importante es como crece la complejidad cuando crece la

estructura

259

Programacion imperativaClase 4

Algoritmos de busqueda

260

Page 66: Algoritmos y Estructuras de Datos II

Mejorando la busqueda

Supongamos que tenemos un diccionario y queremos buscar unapalabra x .

¿Como podemos mejorar la busqueda?

I abrimos el diccionario a la mitad

I si x esta en esa pagina, terminamos

I si x es menor (segun el orden de diccionario) que las palabrasde la pagina actual, x no puede estar en la parte derecha

I si x es mayor (segun el orden de diccionario) que las palabrasde la pagina actual, x no puede estar en la parte izquierda

I seguimos buscando solo en la parte izquierda o derecha (segunsea el caso)

261

Busqueda binaria - especificacion del problemaSupongamos que en lugar de un diccionario tenemos un arregloordenado y en lugar de buscar palabras buscamos numeros enteros.

Podemos hacer una busqueda mas eficiente

I revisamos solo algunas posiciones del arreglo: en cada pasodescartamos la mitad del espacio de busqueda

I menos comparaciones

Este tipo de algoritmo se llama busqueda binaria.

Tenemos un nuevo problema en donde

I mantenemos la poscondicionI reforzamos la precondicion

problema buscarBin (a : [Int], x : Int, n : Int) = res : Bool{requiere |a| == n > 0;requiere (∀j ∈ [0..n − 1)) a[j ] ≤ a[j + 1];asegura res == (x ∈ a);

}262

El programa

bool buscarBin(int a[], int x, int n) {int i = 0, d = n - 1;bool res; int m;if (x < a[i] || x > a[d]) res = false;else {

while (d > i + 1) {m = (i + d) / 2;if (x == a[m]) i = d = m;else if (x < a[m]) d = m;else i = m;

}res = (a[i] == x || a[d] == x);

}return res;

}

Ejemplo n = 12, x = 14, a = 2 5 5 6 8 12 14 19 22 27 27 290 1 2 3 4 5 6 7 8 9 10 11

Ni

Nd

NmNi

Nd

Nm

Ni

Nd

NmN

i=m=dN

i=m=d

Ejemplo n = 12, x = 13, a = 2 5 5 6 8 12 14 19 22 27 27 290 1 2 3 4 5 6 7 8 9 10 11

Ni

Nd

NmNi

Nd

Nm

Ni

Nd

Nm

NiNd

263

Especificacion del ciclo

bool buscarBin(int a[], int x, int n) {int i = 0, d = n - 1; bool res; int m;if (x < a[i] || x > a[d]) res = false;else {

// vale Pc : i == 0 ∧ d == n − 1 ∧ a[i ] ≤ x ≤ a[d ]

while (d > i + 1) {

// invariante I : 0 ≤ i ≤ d < n ∧ a[i ] ≤ x ≤ a[d ]// variante v : d − i − 1

m = (i + d) / 2;if (x == a[m]) i = d = m;else if (x < a[m]) d = m;else i = m;

}

// vale Qc : 0 ≤ i < n ∧ 0 ≤ d < n ∧ x ∈ a↔ (a[i ] == x ∨ a[d ] == x)

res = (a[i] == x || a[d] == x);}return res;

}

por la inicializacion

por el if

i y d son ındicesvalidos del arreglo

i siempre estaa la izquierda de d(o son iguales, peronunca se cruzan)

i y d delimitan elespacio de busqueda(se hereda de Pc)

es, basicamente, lalongitud del espaciode busqueda (resto1 para garantizar quev ≤ 0⇒ d ≤ i + 1)

264

Page 67: Algoritmos y Estructuras de Datos II

Correctitud del ciclo

// vale Pc// implica I

while (d > i + 1) {

// estado E// vale I ∧ d > i + 1

m = (i + d) / 2;if (x == a[m]) i = d = m;else if (x < a[m]) d = m;else i = m;

// vale I// vale v < v@E

}

// vale 0 ≤ i < n ∧ 0 ≤ d < n ∧x ∈ a↔ (a[i ] == x ∨ a[d ] == x)// implica Qc

1. El cuerpo del ciclopreserva el invariante

2. La funcion variantedecrece

3. Si la funcion variante pasala cota, el ciclo termina:v ≤ 0⇒ d ≤ i + 1

4. La precondicion del cicloimplica el invariante

5. La poscondicion vale alfinal

El Teorema del Invariante nos garantiza que si valen 1, 2, 3, 4 y 5,el ciclo termina y es correcto con respecto a su especificacion.

265

1. El cuerpo del ciclo preserva el invariante// estado E (invariante + guarda del ciclo)// vale 0 ≤ i ∧ i + 1 < d < n ∧ a[i ] ≤ x ≤ a[d ]

m = (i + d) / 2;// estado F// vale m = (i + d)@E div 2 ∧ i = i@E ∧ d = d@E// implica 0 ≤ i < m < d < n

if (x == a[m]) i = d = m;else if (x < a[m]) d = m;else i = m;

// vale m == m@F// vale (x == a[m@F ] ∧ i == d == m@F ) ∨

(x < a[m@F ] ∧ d == m@F ∧ i == i@F ) ∨(x > a[m@F ] ∧ i == m@F ∧ d == d@F )

Falta ver que esto ultimo implica el invariante

I 0 ≤ i ≤ d < n: sale del estado FI a[i ] ≤ x ≤ a[d ]:

I caso x == a[m]: es trivial pues a[i ] == a[m] == a[d ] == xI caso x < a[m]: tenemos a[i ] ≤ x < a[m] == a[d ]I caso x > a[m]: tenemos a[i ] == a[m] < x ≤ a[d ]

266

2. La funcion variante decrece// estado E (invariante + guarda del ciclo)// vale 0 ≤ i ∧ i + 1 < d < n ∧ a[i ] ≤ x ≤ a[d ]// implica d − i − 1 > 0

m = (i + d) / 2;// estado F// vale m == (i + d) div 2 ∧ i == i@E ∧ d == d@E// implica 0 ≤ i < m < d < n

if (x == a[m]) i = d = m;else if (x < a[m]) d = m;else i = m;

// vale m == m@F// vale (x == a[m@F ] ∧ i == d == m@F ) ∨

(x < a[m@F ] ∧ d == m@F ∧ i == i@F ) ∨(x > a[m@F ] ∧ i == m@F ∧ d == d@F )

¿Cuanto vale v = d − i − 1?

I caso x == a[m]: es trivial pues v = −1I caso x < a[m]: d decrece pero i queda igualI caso x > a[m]: i crece pero d queda igual

267

3 y 4 son triviales

3. Si la funcion variante pasa la cota, el ciclo termina:

d − i − 1 ≤ 0 ⇒ d ≤ i + 1

4. La precondicion del ciclo implica el invariante

Pc : i == 0 ∧ d == n − 1 ∧ a[i ] ≤ x ≤ a[d ]

⇓I : 0 ≤ i ≤ d < n ∧ a[i ] ≤ x ≤ a[d ]

268

Page 68: Algoritmos y Estructuras de Datos II

5. La poscondicion vale al finalQuiero probar que:

1︷ ︸︸ ︷0 ≤ i ≤ d < n ∧

2︷ ︸︸ ︷a[i ] ≤ x ≤ a[d ] ∧

3︷ ︸︸ ︷d ≤ i + 1

⇓0 ≤ i < n ∧ 0 ≤ d < n︸ ︷︷ ︸

4

∧ x ∈ a︸ ︷︷ ︸5

↔ (a[i ] == x ∨ a[d ] == x)︸ ︷︷ ︸6

Demostracion:

I Por 1, resulta 4 verdadero.I Supongamos 6 verdadero. De 1 concluimos que 5 es

verdadero.I Supongamos a[i ] 6= x ∧ a[d ] 6= x (i.e. 6 es falso): a[j ] == x

para algun jI i < j < d : contradice 3, d ≤ i + 1I j < i : gracias al orden, x == a[j ] < a[i ]; contradice 2, x ≥ a[i ]I j > d : gracias al orden, x == a[j ] > a[d ]; contradice 2,

x ≤ a[d ]

Entonces el ciclo es correcto con respecto a su especificacion.269

Complejidad

¿Cuantas comparaciones hacemos como maximo?

I en cada iteracion mequedo con la mitad delespacio de busqueda (talvez uno mas; no influyeen el orden)

I paramos cuando elsegmento de busquedatiene longitud 1 o 2

numero deiteracion

longitud delespacio de busqueda

1 n2 n/23 (n/2)/2 = n/22

4 (n/22)/2 = n/23

......

t n/2t−1

En total hacemos t iteraciones

1 = n/2t−1 ⇒ 2t−1 = n ⇒ t = 1 + log2 n.

Luego, la complejidad de la busqueda binaria es O(log2 n). Muchomejor que la busqueda lineal, que es O(n).

270

Conclusiones

I vimos dos algoritmos de busqueda

I en general, mas informacion → algoritmos mas eficientes

problema buscar (a : [Int], x : Int, n : Int) = res : Boolrequiere |a| == n > 0;asegura res == (x ∈ a);

problema buscarBin (a : [Int], x : Int, n : Int) = res : Boolrequiere |a| == n > 0;requiere (∀j ∈ [0..n − 1)) a[j ] ≤ a[j + 1];asegura res == (x ∈ a);

I la busqueda binaria es esencialmente mejor que la busquedalineal - O(log2 n) vs. O(n)

271

Programacion imperativaClase 5

Algoritmos de ordenamiento

272

Page 69: Algoritmos y Estructuras de Datos II

Ordenamiento de un arreglo

I tenemos un arreglo de un tipo T con una relacion de orden(≤)

I queremos modificar el arregloI para que sus elementos queden en orden crecienteI vamos a hacerlo permutando elementos

I nuestra poscondicion se va a parecer a la precondicion de labusqueda binaria

273

La especificacion

problema sort<T> (a : [T], n : Int){requiere 1 ≤ n == |a|;modifica a;asegura mismos(a, pre(a)) ∧ (∀j ← [0..n − 1)) aj ≤ aj+1;

}

aux cuenta(x : T, a : [T]) : Int = |[y | y ← a, y == x ]|;

aux mismos(a, b : [T]) : Bool = |a| == |b| ∧(∀x ← a) cuenta(x , a) == cuenta(x , b);

T tiene que ser un tipo con una relacion de orden ≤ definida

274

El algoritmo Upsort

I ordenamos de derecha a izquierda

I el segmento desordenado va desde el principio hasta laposicion que vamos a llamar actual

I comenzamos con actual = n − 1I mientras actual > 0

I encontrar el mayor elemento del segmento todavıa no ordenadoI intercambiarlo con el de la posicion actualI decrementar actual

Ejemplo 9 5 2 7 1 20 1 2 3 4 5

Nactual

Nm

Ejemplo 2 5 2 7 1 90 1 2 3 4 5

NactualNm

Ejemplo 2 5 2 1 7 90 1 2 3 4 5

Nactual

Nm

Ejemplo 2 1 2 5 7 90 1 2 3 4 5

NactualNm

Ejemplo 2 1 2 5 7 90 1 2 3 4 5

NactualNm

Ejemplo 1 2 2 5 7 90 1 2 3 4 5

Nactual

275

El programa

void upsort (int a[], int n) {int m, actual = n-1;while (actual > 0) {

m = maxPos(a,0,actual);swap(a[m],a[actual]);actual--;

}}

problema maxPos(a : [Int], desde, hasta : Int) = pos : Int{requiere 0 ≤ desde ≤ hasta ≤ |a| − 1;asegura desde ≤ pos ≤ hasta ∧ (∀x ← a[desde..hasta]) x ≤ apos ;

}

problema swap(x , y : Int){modifica x , y ;asegura x == pre(y) ∧ y == pre(x);

}276

Page 70: Algoritmos y Estructuras de Datos II

Correctitud de Upsort

void upsort (int a[], int n) {

// vale P : 1 ≤ n == |a| (es la precondicion del problema)

int m, actual = n-1;

// vale PC : a == pre(a) ∧ actual == n − 1 (es la precondicion del ciclo)

while (actual > 0) {m = maxPos(a,0,actual);swap(a[m],a[actual]);actual--;

}

// vale QC : mismos(a, pre(a)) ∧ (∀j ← [0..n − 1)) aj ≤ aj+1

(es la poscondicion del ciclo)// vale Q : mismos(a, pre(a)) ∧ (∀j ← [0..n − 1)) aj ≤ aj+1

(es la poscondicion del problema)

}

Como QC ⇒ Q, lo que queda es probar que el ciclo es correcto para su

especificacion.277

Especificacion del ciclo

void upsort (int a[], int n) {int m, actual = n-1;

// vale PC : a == pre(a) ∧ actual == n − 1

while (actual > 0) {

// invariante I : 0 ≤ actual ≤ n − 1 ∧mismos(a, pre(a))∧ (∀k ← (actual ..n − 1)) ak ≤ ak+1

∧ actual < n − 1→ (∀x ← a[0..actual ]) x ≤ aactual+1

// variante v : actual

m = maxPos(a,0,actual);swap(a[m],a[actual]);actual--;

}

// vale QC : mismos(a, pre(a)) ∧ (∀j ← [0..n − 1)) aj ≤ aj+1

}

en cada paso actualse decrementa.

Comienza en n − 1y termina en 0

en cada paso el arreglo

es permutacion

del original

en cada paso

el segmento desde

actual + 1 hasta n − 1

esta ordenado

en cada paso actual + 1

tiene el maximo valordel segmento desde 0

hasta actual + 1

278

Correctitud del ciclo

// vale PC

// implica I

while (actual > 0) {

// estado E// vale I ∧ actual > 0

m = maxPos(a,0,actual);swap(a[m],a[actual]);actual--;

// vale I// vale v < v@E

}

// vale I ∧ ¬(actual > 0)// implica QC

1. El cuerpo del ciclo preservael invariante

2. La funcion variante decrece

3. Si la funcion variante pasa lacota, el ciclo termina:v ≤ 0⇒ ¬(actual > 0)

4. La precondicion del cicloimplica el invariante

5. La poscondicion vale al final

El Teorema del Invariante nos garantiza que si valen 1, 2, 3, 4 y 5,el ciclo termina y es correcto con respecto a su especificacion.

279

1. El cuerpo del ciclo preserva el invariante// estado E (invariante + guarda del ciclo)// vale 0 < actual ≤ n − 1 ∧mismos(a, pre(a))

∧(∀k ← (actual ..n − 1)) ak ≤ ak+1

∧(actual < n − 1→ (∀x ← a[0..actual ]) x ≤ aactual+1)

m = maxPos(a,0,actual);

// estado E1 Recordar especificacion de MaxPos:PMP : 0 ≤ desde ≤ hasta ≤ |a| − 1, se cumple porque 0 < atual ≤ n − 1QMP : desde ≤ pos ≤ hasta ∧ (∀x ← a[desde..hasta]) x ≤ apos

// vale 0 ≤ m ≤ actual ∧ (∀x ← a[0..actual ]) x ≤ am

// vale a == a@E ∧ actual == actual@E// implica 0 < actual ≤ n − 1 ∧mismos(a, pre(a))// implica (∀k ← (actual ..n − 1)) ak ≤ ak+1

// implica (actual < n − 1→ (∀x ← a[0..actual ]) x ≤ aactual+1)(Justificacion de los implica: actual y a no cambiaron–lo dice el segundo vale de este estado

)280

Page 71: Algoritmos y Estructuras de Datos II

1. El cuerpo del ciclo preserva el invariante (cont.)// estado E1

// vale 0 ≤ m ≤ actual ∧ (∀x ← a[0..actual ]) x ≤ am

// implica 0 < actual ≤ n − 1 ∧mismos(a, pre(a))// implica (∀k ← (actual ..n − 1)) ak ≤ ak+1

// implica actual < n − 1→ (∀x ← a[0..actual ]) x ≤ aactual+1

swap(a[m],a[actual]);

// estado E2

// vale am == (a@E1)actual ∧ aactual == (a@E1)m (por poscon. de swap)// vale (∀i ← [0..n), i 6= m, i 6= actual) ai == (a@E1)i (idem)// vale actual == actual@E1 ∧m == m@E1

// implica 0 < actual ≤ n − 1 (actual no se modifico)// implica mismos(a, pre(a)) (el swap no agrega ni quita elementos)// implica (∀k ← (actual ..n − 1)) ak ≤ ak+1

(a(actual ..n − 1] no se modifico porque m ≤ actual)// implica (∀k ← (actual − 1..n − 1)) ak ≤ ak+1 del tercer vale de E2: m == m@E1 y actual == actual@E1;

del primer vale de y ultimo implica de E1: (a@E1)m ≤ (a@E1)actual+1;del primer y segundo vale de E2: aactual ≤ aactual+1)

// implica (∀x ← a[0..actual ]) x ≤ aactual (del primer vale de E1 y E2) 281

1. El cuerpo del ciclo preserva el invariante (cont.)// estado E2

// implica 0 < actual ≤ n − 1// implica mismos(a, pre(a))// implica (∀k ← (actual − 1..n − 1)) ak ≤ ak+1

// implica (∀x ← a[0..actual ]) x ≤ aactual

actual--;

// estado E3

// vale actual == actual@E2 − 1 ∧ a == a@E2

// implica 0 ≤ actual@E2 − 1 < n − 1 (de primer vale de E3)// implica 0 ≤ actual ≤ n − 1 (reemplazando actual@E2 − 1 por actual)// implica mismos(a, pre(a)) (de segundo implica de E2 y a == a@E2)// implica (∀k ← (actual@E2 − 1..n − 1)) ak ≤ ak+1 (por E2)// implica (∀k ← (actual ..n − 1)) ak ≤ ak+1

(reemplazo actual@E2 − 1 por actual)// implica (∀x ← a[0..actual + 1]) x ≤ aactual+1 (por E2 + reemplazo)// implica (∀x ← a[0..actual ]) x ≤ aactual+1

(por ser un selector mas acotado)// implica actual < n − 1→ (∀x ← a[0..actual ]) x ≤ aactual+1

(pues q implica p → q)282

2 y 3 son triviales

2. La funcion variante decrece:

// estado E (invariante + guarda del ciclo)// vale I ∧ B

m = maxPos(a,0,actual);swap(a[m],a[actual]);actual--;

// estado F// vale actual == actual@E − 1// implica v@F == v@E − 1 < v@E

3. Si la funcion variante pasa la cota, el ciclo termina:

actual ≤ 0 es ¬B

283

4. La precondicion del ciclo implica el invarianteRecordar que

I P : 1 ≤ n == |a|I PC : a == pre(a) ∧ actual == n − 1I I : 0 ≤ actual ≤ n − 1 ∧mismos(a, pre(a))

∧(∀k ← (actual ..n − 1)) ak ≤ ak+1

∧actual < n−1→ (∀x ← a[0..actual ]) x ≤ aactual+1

Demostracion de que PC ⇒ I :

I 1 ≤ n ∧ actual == n − 1 ⇒ 0 ≤ actual ≤ n − 1

I a == pre(a) ⇒ mismos(a, pre(a))

I actual == n − 1 ⇒ (∀k ← (actual ..n − 1)) ak ≤ ak+1

porque el selector actua sobre una lista vacıa

I actual == n − 1 ⇒actual < n − 1→ (∀x ← a[0..actual ]) x ≤ aactual+1

porque el antecedente es falso

284

Page 72: Algoritmos y Estructuras de Datos II

5. La poscondicion vale al finalQuiero probar que: (¬B ∧ I )⇒ QC

Recordemos

¬B ∧ I : 0 ≤ actual ≤ n − 1 ∧mismos(a, pre(a)) ∧ (∀k ← (actual ..n − 1)) ak ≤ ak+1 ∧actual < n − 1→ (∀x ← a[0..actual + 1]) x ≤ aactual+1 ∧actual ≤ 0

QC : mismos(a, pre(a)) ∧ (∀j ← [0..n − 1)) aj ≤ aj+1

Veamos que vale cada parte de QC :

I mismos(a, pre(a)): trivial porque esta en II (∀j ← [0..n − 1)) aj ≤ aj+1:

I primero observar que actual == 0I si n == 1, no hay nada que probar porque [0..n − 1) == []I si n > 1

I sabemos (∀k ← (0..n − 1)) ak ≤ ak+1

I sabemos que (∀x ← a[0..1]) x ≤ a1, entonces a0 ≤ a1

I concluimos (∀j ← [0..n − 1)) aj ≤ aj+1

285

Implementacion de maxPos

problema maxPos (a : [Int], desde, hasta : Int) = pos : Int{requiere PMP : 0 ≤ desde ≤ hasta ≤ |a| − 1;asegura QMP : desde ≤ pos ≤ hasta ∧

(∀x ← a[desde..hasta]) x ≤ apos ;}

int maxPos(const int a[], int desde, int hasta) {int mp = desde, i = desde;while (i < hasta) {

i++;if (a[i] > a[mp]) mp = i;

}return mp;

}

286

Correctitud de maxPosproblema maxPos (a : [Int], desde, hasta : Int) = pos : Int{

requiere PMP : 0 ≤ desde ≤ hasta ≤ |a| − 1;asegura QMP : desde ≤ pos ≤ hasta ∧

(∀x ← a[desde..hasta]) x ≤ apos ;}

int maxPos(const int a[], int desde, int hasta) {

//vale PMP : 0 ≤ desde ≤ hasta ≤ |a| − 1 (precondicion del problema)

int mp = desde, i = desde;

//vale PC : mp == i == desde (precondicion del ciclo)

while (i < hasta) {i++;if (a[i] > a[mp]) mp = i;

}

//vale QC : desde ≤ mp ≤ hasta ∧ (∀x ← a[desde..hasta]) x ≤ amp

(poscondicion del ciclo)return mp;

//vale QMP : desde ≤ pos ≤ hasta ∧ (∀x ← a[desde..hasta]) x ≤ apos

(poscondicion del problema)} 287

Especificacion del ciclo

// vale PC : mp == i == desde

while (i < hasta) {

// invariante I : desde ≤ mp ≤ i ≤ hasta ∧ (∀x ← a[desde..i ]) x ≤ amp

// variante v : hasta− i

i++;if (a[i] > a[mp]) mp = i;

}

// vale QC : desde ≤ mp ≤ hasta ∧ (∀x ← a[desde..hasta]) x ≤ amp

288

Page 73: Algoritmos y Estructuras de Datos II

Correctitud del ciclo

// vale PC

// implica I

while (i < hasta) {

// estado E// vale I ∧ i < hasta

i++;if (a[i] > a[mp]) mp = i;

// vale I// vale v < v@E

}

// vale I ∧ i ≥ hasta// implica QC

1. El cuerpo del ciclopreserva el invariante

2. La funcion variantedecrece

3. Si la funcion variante pasala cota, el ciclo termina:v ≤ 0⇒ i ≥ hasta

4. La precondicion del cicloimplica el invariante

5. La poscondicion vale alfinal

El Teorema del Invariante nos garantiza que si valen 1, 2, 3, 4 y 5,el ciclo termina y es correcto con respecto a su especificacion.

289

1. El cuerpo del ciclo preserva el invarianteRecordar que desde, hasta y a no cambian porque son variables deentrada que no aparecen en local ni modifica// estado E (invariante + guarda del ciclo)// vale desde ≤ mp ≤ i < hasta ∧ (∀x ← a[desde..i ]) x ≤ amp

i++;// estado E1

// vale i == i@E + 1 ∧mp = mp@E// implica Pif : desde ≤ mp ≤ i ≤ hasta ∧ (∀x ← a[desde..i)) x ≤ amp(

de E , reemplazando i@E por i − 1y cambiando el lımite del selector adecuadamente

)if (a[i] > a[mp]) mp = i;

// vale Qif : desde ≤ mp ≤ i ≤ hasta ∧ (∀x ← a[desde..i ]) x ≤ amp observar que en este punto, tratamos al if como una solagran instruccion que convierte Pif en Qif . La justificacionde este paso es la transformacion de estados de la hoja siguiente

// implica I(

observar que I es igual que Qif , pero en generalalcanzarıa con que Qif implique I

)290

Especificacion y correctitud del If

Pif : desde ≤ mp ≤ i ≤ hasta ∧ (∀x ← a[desde..i)) x ≤ amp

Qif : desde ≤ mp ≤ i ≤ hasta ∧ (∀x ← a[desde..i ]) x ≤ amp

// estado Eif

// vale desde ≤ mp ≤ i ≤ hasta ∧ (∀x ← a[desde..i)) x ≤ amp

if (a[i] > a[mp]) mp = i;

// vale (ai > amp@Eif∧mp == i@Eif ∧ i == i@Eif )

∨(ai ≤ amp@Eif∧mp == mp@Eif ∧ i == i@Eif )

// implica desde ≤ mp ≤ i ≤ hastaoperaciones logicas; observar que desde, hasta y ano pueden modificarse porque son variables de entrada queno aparecen ni en modifica ni en local ;observar que i == i@Eif

// implica amp@Eif

≤ amp ∧ ai ≤ amp (Justificar...)// implica (∀x ← a[desde..i ]) x ≤ amp

// implica Qif

291

2. La funcion variante decrece// estado E (invariante + guarda del ciclo)// vale desde ≤ i < hasta

i++;

// estado E1

// vale i == i@E + 1// implica desde ≤ i ≤ hasta

if (a[i] > a[mp]) mp = i;

// estado F// vale i == i@E1

// implica i == i@E + 1

¿Cuanto vale v = hasta− i en el estado F ?

v@F == (hasta− i)@F

== hasta− i@F

== hasta− (i@E + 1)

== hasta− i@E − 1

< hasta− i@E

== v@E 292

Page 74: Algoritmos y Estructuras de Datos II

3, 4 y 5 son triviales

3. Si la funcion variante pasa la cota, el ciclo termina:

hasta− i ≤ 0 ⇒ hasta ≤ i

4. La precondicion del ciclo implica el invariante:Recordar que la precondicion de maxPos dice

PMP : 0 ≤ desde ≤ hasta ≤ |a| − 1

y que desde y hasta no cambian de valor. Entonces

PC : i == desde ∧mp == desde

⇓I : desde ≤ mp ≤ i ≤ hasta ∧ (∀x ← a[desde..i ]) x ≤ amp

5. La poscondicion vale al final: es facil ver que I ∧ i ≥ hastaimplica QC

Entonces el ciclo es correcto con respecto a su especificacion.293

Complejidad de maxPos

¿Cuantas comparaciones hacemos como maximo?

I el ciclo itera hasta− desde vecesI cada iteracion hace

I una comparacion (en la guarda)I una asignacion (el incremento)I otra comparacion (guarda del condicional)I otra asignacion (si se cumple esa guarda)

I antes del ciclo se hacen dos asignaciones

I todo estos detalles no importan para calcular el orden

I O(longitud del segmento) = O(hasta− desde + 1)

I peor caso: desde == 0 y hasta == |a| − 1

I la complejidad es O(|a|) para el peor caso

294

Complejidad de UpsortI el ciclo de Upsort itera n veces

I empieza con actual == n − 1I termina con actual == 0I en cada iteracion decrementa actual en uno

I una iteracion haceI una busqueda de maxPosI un swapI un decremento

I de estos pasos, el unico que no es O(1), constante, es elprimero

I ¿cuantos pasos hace maxPos en cada iteracion?I siempre O(hasta− desde + 1) = O(actual + 1)I en la primera hace n (busca el maximo del segmento a ordenar)I en la segunda hace n − 1 (busca el segundo mayor)I en la tercera hace n − 2I y ası (podrıamos verlo por induccion) hasta 2

I el total de pasos esO(n + (n − 1) + . . .+ 2) = O(n ∗ (n + 1)/2− 1) = O(n2)

I los mejores algoritmos de ordenamiento son O(n log n)295