Generalización de funciones Eliminación de la recursión Eliminación de la recursión Algoritmos y Estructuras de Datos 2 Leandro Radusky Universidad de Buenos Aires Primer Cuatrimestre 2010 Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Generalización de funciones Inmersión de Rango: Se agregan resultados. Inmersión de Dominio: Se agregan argumentos a la función. Inmersión de Género: Se amplı́a el dominio de algún parámetro de la función. Se busca: No repetir cálculos. No recorrer una estructura más de una vez (o menor cantidad de veces). Eliminar la recursión. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Generalización de funciones Inmersión de Rango: Se agregan resultados. Inmersión de Dominio: Se agregan argumentos a la función. Inmersión de Género: Se amplı́a el dominio de algún parámetro de la función. Se busca: No repetir cálculos. No recorrer una estructura más de una vez (o menor cantidad de veces). Eliminar la recursión. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Generalización de funciones Inmersión de Rango: Se agregan resultados. Inmersión de Dominio: Se agregan argumentos a la función. Inmersión de Género: Se amplı́a el dominio de algún parámetro de la función. Se busca: No repetir cálculos. No recorrer una estructura más de una vez (o menor cantidad de veces). Eliminar la recursión. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Generalización de funciones Inmersión de Rango: Se agregan resultados. Inmersión de Dominio: Se agregan argumentos a la función. Inmersión de Género: Se amplı́a el dominio de algún parámetro de la función. Se busca: No repetir cálculos. No recorrer una estructura más de una vez (o menor cantidad de veces). Eliminar la recursión. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Ejercicio Se nos pide reescribir la siguiente función, de manera que pueda calcularse recorriendo la secuencia s slo una vez: PS : Secu(Nat) → Nat PS(s) ≡ |prod(s) − suma(s)| En donde: prod : Secu(Nat) → Nat prod(s) ≡ if vacia?(s) then 1 else prim(s) × prod(fin(s)) fi suma : Secu(Nat) → Nat suma(s) ≡ if vacia?(s) then 0 else prim(s) + suma(fin(s)) fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Ejercicio (cont.) Consideremos la siguiente función, que generaliza la suma y el producto. gen : Secu(Nat) → tupla(Nat, Nat) gen(s) ≡ hsuma(s), prod(s)i Veamos que gen se puede calcular recorriendo s una sola vez: gen(s) ≡ if vacia?(s) then h0, 1i else aux(prims(s), gen(fin(s))) fi En donde aux es la función no recursiva: aux : Nat X tupla(Nat, Nat) → tupla(Nat, Nat) aux(e, t) ≡ he + Π1 (t), e × Π2 (t)i Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Ejercicio (cont.) Hemos hecho una generalización de rango. Para PS tenemos las siguientes definiciones: PS(s) ≡ |prod(s) − suma(s)| PS(s) ≡ |Π1 (gen(s)) − Π2 (gen(s))| Estas dos funciones recorren la secuencia dos veces! Para recorrerla solo una vez hacemos: PS(s) = aux 0 (gen(s)) En donde: aux 0 : tupla(Nat, Nat) → Nat aux 0 (t) ≡ |Π1 (t) − Π2 (t)| Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Eliminación de la recursión Vimos como generalizar funciones. Hicimos una generalización de rango para no repetir cálculos. Vamos a ver un ejemplo de generalización de dominio para eliminar la recursión. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Eliminación de la recursión Vimos como generalizar funciones. Hicimos una generalización de rango para no repetir cálculos. Vamos a ver un ejemplo de generalización de dominio para eliminar la recursión. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Eliminación de la recursión Vimos como generalizar funciones. Hicimos una generalización de rango para no repetir cálculos. Vamos a ver un ejemplo de generalización de dominio para eliminar la recursión. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Tipos de recursión Lineal a la cola: tienen una sola llamada recursiva y es la última operación que se aplica. Lineal no a la cola: tienen una sola llamada recursiva pero no es la última operación que se aplica. No lineal a la cola(anidada): la llamada recursiva es la última operación que se aplica pero hay más de una llamada. No lineal no a la cola: Hay más de una llamada recursiva y esta no es la última operación que se aplica. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Tipos de recursión Lineal a la cola: tienen una sola llamada recursiva y es la última operación que se aplica. Lineal no a la cola: tienen una sola llamada recursiva pero no es la última operación que se aplica. No lineal a la cola(anidada): la llamada recursiva es la última operación que se aplica pero hay más de una llamada. No lineal no a la cola: Hay más de una llamada recursiva y esta no es la última operación que se aplica. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Tipos de recursión Lineal a la cola: tienen una sola llamada recursiva y es la última operación que se aplica. Lineal no a la cola: tienen una sola llamada recursiva pero no es la última operación que se aplica. No lineal a la cola(anidada): la llamada recursiva es la última operación que se aplica pero hay más de una llamada. No lineal no a la cola: Hay más de una llamada recursiva y esta no es la última operación que se aplica. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Tipos de recursión Lineal a la cola: tienen una sola llamada recursiva y es la última operación que se aplica. Lineal no a la cola: tienen una sola llamada recursiva pero no es la última operación que se aplica. No lineal a la cola(anidada): la llamada recursiva es la última operación que se aplica pero hay más de una llamada. No lineal no a la cola: Hay más de una llamada recursiva y esta no es la última operación que se aplica. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales a la cola Estas funciones son aquellas que tienen una única llamada recursiva y esta es la última operación que se aplica. Para estas funciones la eliminación de la recursión es trivial. Por lo tanto, para eliminar la recursión alcanza con reescribir la función recursiva dada como una función recursiva lineal a la cola. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales a la cola Estas funciones son aquellas que tienen una única llamada recursiva y esta es la última operación que se aplica. Para estas funciones la eliminación de la recursión es trivial. Por lo tanto, para eliminar la recursión alcanza con reescribir la función recursiva dada como una función recursiva lineal a la cola. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales a la cola Estas funciones son aquellas que tienen una única llamada recursiva y esta es la última operación que se aplica. Para estas funciones la eliminación de la recursión es trivial. Por lo tanto, para eliminar la recursión alcanza con reescribir la función recursiva dada como una función recursiva lineal a la cola. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales a la cola Cómo podrı́amos eliminar la recursión en este caso? Si tenemos el siguiente ejemplo mcd(a, b) ≡ if (b = 0) then a else mcd(b, a mod b) fi La forma iterativa de escribirlo serı́a itMcd(a,b): while (b != 0) < a, b > = < b, a mod b > return a Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales a la cola Cómo podrı́amos eliminar la recursión en este caso? Si tenemos el siguiente ejemplo mcd(a, b) ≡ if (b = 0) then a else mcd(b, a mod b) fi La forma iterativa de escribirlo serı́a itMcd(a,b): while (b != 0) < a, b > = < b, a mod b > return a Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales a la cola Cómo podrı́amos eliminar la recursión en este caso? Si tenemos el siguiente ejemplo mcd(a, b) ≡ if (b = 0) then a else mcd(b, a mod b) fi La forma iterativa de escribirlo serı́a itMcd(a,b): while (b != 0) < a, b > = < b, a mod b > return a Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Estas funciones son aquellas que tienen una única llamada recursiva y esta no es la última operación que se aplica. Ej: Prod(s) ≡ if vacia(s) then 1 else prim(s) x Prod(fin(s)) fi La última operación que se aplica no es Prod. Proponemos una generalización que utilice un acumulador. genProd(n, s) ≡ n x Prod(s) Generaliza Prod pues genProd(1, s) ≡ 1 x Prod(s) ≡ Prod(s) . Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Estas funciones son aquellas que tienen una única llamada recursiva y esta no es la última operación que se aplica. Ej: Prod(s) ≡ if vacia(s) then 1 else prim(s) x Prod(fin(s)) fi La última operación que se aplica no es Prod. Proponemos una generalización que utilice un acumulador. genProd(n, s) ≡ n x Prod(s) Generaliza Prod pues genProd(1, s) ≡ 1 x Prod(s) ≡ Prod(s) . Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Estas funciones son aquellas que tienen una única llamada recursiva y esta no es la última operación que se aplica. Ej: Prod(s) ≡ if vacia(s) then 1 else prim(s) x Prod(fin(s)) fi La última operación que se aplica no es Prod. Proponemos una generalización que utilice un acumulador. genProd(n, s) ≡ n x Prod(s) Generaliza Prod pues genProd(1, s) ≡ 1 x Prod(s) ≡ Prod(s) . Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Estas funciones son aquellas que tienen una única llamada recursiva y esta no es la última operación que se aplica. Ej: Prod(s) ≡ if vacia(s) then 1 else prim(s) x Prod(fin(s)) fi La última operación que se aplica no es Prod. Proponemos una generalización que utilice un acumulador. genProd(n, s) ≡ n x Prod(s) Generaliza Prod pues genProd(1, s) ≡ 1 x Prod(s) ≡ Prod(s) . Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Ahora queremos convertir esa generalización en una función lineal a la cola. Utilizaremos la técnica de plegado y desplegado: genProd(s, n) ≡ n x Prod(s) ≡ n x (if vacia(s) then 1 else prim(s) x Prod(fin(s)) fi) ≡ if vacia(s) then n x 1 else n x prim(s) x Prod(fin(s)) fi ≡ if vacia(s) then n else (n x prim(s)) x Prod(fin(s)) fi ≡ if vacia(s) then n else genProd(fin(s), n x prim(s)) fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Ahora queremos convertir esa generalización en una función lineal a la cola. Utilizaremos la técnica de plegado y desplegado: genProd(s, n) ≡ n x Prod(s) ≡ n x (if vacia(s) then 1 else prim(s) x Prod(fin(s)) fi) ≡ if vacia(s) then n x 1 else n x prim(s) x Prod(fin(s)) fi ≡ if vacia(s) then n else (n x prim(s)) x Prod(fin(s)) fi ≡ if vacia(s) then n else genProd(fin(s), n x prim(s)) fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Ahora queremos convertir esa generalización en una función lineal a la cola. Utilizaremos la técnica de plegado y desplegado: genProd(s, n) ≡ n x Prod(s) ≡ n x (if vacia(s) then 1 else prim(s) x Prod(fin(s)) fi) ≡ if vacia(s) then n x 1 else n x prim(s) x Prod(fin(s)) fi ≡ if vacia(s) then n else (n x prim(s)) x Prod(fin(s)) fi ≡ if vacia(s) then n else genProd(fin(s), n x prim(s)) fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Ahora queremos convertir esa generalización en una función lineal a la cola. Utilizaremos la técnica de plegado y desplegado: genProd(s, n) ≡ n x Prod(s) ≡ n x (if vacia(s) then 1 else prim(s) x Prod(fin(s)) fi) ≡ if vacia(s) then n x 1 else n x prim(s) x Prod(fin(s)) fi ≡ if vacia(s) then n else (n x prim(s)) x Prod(fin(s)) fi ≡ if vacia(s) then n else genProd(fin(s), n x prim(s)) fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Ahora queremos convertir esa generalización en una función lineal a la cola. Utilizaremos la técnica de plegado y desplegado: genProd(s, n) ≡ n x Prod(s) ≡ n x (if vacia(s) then 1 else prim(s) x Prod(fin(s)) fi) ≡ if vacia(s) then n x 1 else n x prim(s) x Prod(fin(s)) fi ≡ if vacia(s) then n else (n x prim(s)) x Prod(fin(s)) fi ≡ if vacia(s) then n else genProd(fin(s), n x prim(s)) fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Ahora queremos convertir esa generalización en una función lineal a la cola. Utilizaremos la técnica de plegado y desplegado: genProd(s, n) ≡ n x Prod(s) ≡ n x (if vacia(s) then 1 else prim(s) x Prod(fin(s)) fi) ≡ if vacia(s) then n x 1 else n x prim(s) x Prod(fin(s)) fi ≡ if vacia(s) then n else (n x prim(s)) x Prod(fin(s)) fi ≡ if vacia(s) then n else genProd(fin(s), n x prim(s)) fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Ahora queremos convertir esa generalización en una función lineal a la cola. Utilizaremos la técnica de plegado y desplegado: genProd(s, n) ≡ n x Prod(s) ≡ n x (if vacia(s) then 1 else prim(s) x Prod(fin(s)) fi) ≡ if vacia(s) then n x 1 else n x prim(s) x Prod(fin(s)) fi ≡ if vacia(s) then n else (n x prim(s)) x Prod(fin(s)) fi ≡ if vacia(s) then n else genProd(fin(s), n x prim(s)) fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Llegamos a una expresión de genProd lineal a la cola. Ahora sabemos cómo escribir de manera iterativa tanto genProd y luego Prod. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas lineales no a la cola Llegamos a una expresión de genProd lineal a la cola. Ahora sabemos cómo escribir de manera iterativa tanto genProd y luego Prod. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola Son aquellas en donde la llamada recursiva es la última operación que se aplica, pero no es la única. Ejemplo, consideremos la función de Ackerman: Ack(m, n) ≡ if m = 0 then n + 1 else if n = 0 then Ack(m − 1, 1) else Ack(m − 1, Ack(m, n − 1)) fi fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola Son aquellas en donde la llamada recursiva es la última operación que se aplica, pero no es la única. Ejemplo, consideremos la función de Ackerman: Ack(m, n) ≡ if m = 0 then n + 1 else if n = 0 then Ack(m − 1, 1) else Ack(m − 1, Ack(m, n − 1)) fi fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola Cuando queremos calcular el valor de la función para dos m y n genéricos la expansión consta de muchas llamadas recursivas. Idea: Agrupar todas esas llamadas en un contenedor. Hacemos una generalización de género, convirtiendo el primer parámetro en una pila: genAck : pila(nat) x nat → nat genAck(vacı́a, n) ≡ n genAck(apilar (p, m), n) ≡ genAck(p, Ack(m, n)) Que es una generalización de Ack pues: Ack(m, n) ≡ genAck(apilar (m, vacı́a), n) Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola Cuando queremos calcular el valor de la función para dos m y n genéricos la expansión consta de muchas llamadas recursivas. Idea: Agrupar todas esas llamadas en un contenedor. Hacemos una generalización de género, convirtiendo el primer parámetro en una pila: genAck : pila(nat) x nat → nat genAck(vacı́a, n) ≡ n genAck(apilar (p, m), n) ≡ genAck(p, Ack(m, n)) Que es una generalización de Ack pues: Ack(m, n) ≡ genAck(apilar (m, vacı́a), n) Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola Cuando queremos calcular el valor de la función para dos m y n genéricos la expansión consta de muchas llamadas recursivas. Idea: Agrupar todas esas llamadas en un contenedor. Hacemos una generalización de género, convirtiendo el primer parámetro en una pila: genAck : pila(nat) x nat → nat genAck(vacı́a, n) ≡ n genAck(apilar (p, m), n) ≡ genAck(p, Ack(m, n)) Que es una generalización de Ack pues: Ack(m, n) ≡ genAck(apilar (m, vacı́a), n) Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola Cuando queremos calcular el valor de la función para dos m y n genéricos la expansión consta de muchas llamadas recursivas. Idea: Agrupar todas esas llamadas en un contenedor. Hacemos una generalización de género, convirtiendo el primer parámetro en una pila: genAck : pila(nat) x nat → nat genAck(vacı́a, n) ≡ n genAck(apilar (p, m), n) ≡ genAck(p, Ack(m, n)) Que es una generalización de Ack pues: Ack(m, n) ≡ genAck(apilar (m, vacı́a), n) Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola Ahora nos gustarı́a escribir genAck como una función recursiva que no dependa de Ack. Plegamos y desplegamos: genAck(vacı́a, n) ≡ n genAck(apilar (m, p), n) ≡ genAck(p, Ack(m, n)) genAck(apilar (m, p), n) ≡ if m = 0 then genAck(p, n + 1) else if n = 0 then genAck(p, Ack(m − 1, 1)) else genAck(p, Ack(m − 1, Ack(m, n − 1))) fi fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola Ahora nos gustarı́a escribir genAck como una función recursiva que no dependa de Ack. Plegamos y desplegamos: genAck(vacı́a, n) ≡ n genAck(apilar (m, p), n) ≡ genAck(p, Ack(m, n)) genAck(apilar (m, p), n) ≡ if m = 0 then genAck(p, n + 1) else if n = 0 then genAck(p, Ack(m − 1, 1)) else genAck(p, Ack(m − 1, Ack(m, n − 1))) fi fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola Ahora nos gustarı́a escribir genAck como una función recursiva que no dependa de Ack. Plegamos y desplegamos: genAck(vacı́a, n) ≡ n genAck(apilar (m, p), n) ≡ genAck(p, Ack(m, n)) genAck(apilar (m, p), n) ≡ if m = 0 then genAck(p, n + 1) else if n = 0 then genAck(p, Ack(m − 1, 1)) else genAck(p, Ack(m − 1, Ack(m, n − 1))) fi fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola Ahora nos gustarı́a escribir genAck como una función recursiva que no dependa de Ack. Plegamos y desplegamos: genAck(vacı́a, n) ≡ n genAck(apilar (m, p), n) ≡ genAck(p, Ack(m, n)) genAck(apilar (m, p), n) ≡ if m = 0 then genAck(p, n + 1) else if n = 0 then genAck(p, Ack(m − 1, 1)) else genAck(p, Ack(m − 1, Ack(m, n − 1))) fi fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola Ahora nos gustarı́a escribir genAck como una función recursiva que no dependa de Ack. Plegamos y desplegamos: genAck(vacı́a, n) ≡ n genAck(apilar (m, p), n) ≡ genAck(p, Ack(m, n)) genAck(apilar (m, p), n) ≡ if m = 0 then genAck(p, n + 1) else if n = 0 then genAck(p, Ack(m − 1, 1)) else genAck(p, Ack(m − 1, Ack(m, n − 1))) fi fi Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola genAck(apilar (m, p), n) ≡ if m = 0 then genAck(p, n + 1) else if n = 0 then genAck(Apilar (m − 1, p), 1)) else genAck(apilar (m, apilar (m − 1, p)), n − 1) fi fi Y ahora tenemos una función lineal a la cola. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales a la cola genAck(apilar (m, p), n) ≡ if m = 0 then genAck(p, n + 1) else if n = 0 then genAck(Apilar (m − 1, p), 1)) else genAck(apilar (m, apilar (m − 1, p)), n − 1) fi fi Y ahora tenemos una función lineal a la cola. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales no a la cola En este caso tenemos más de una llamada recursiva y esta no es la última operación que se aplica. Un ejemplo serı́a Fib(n) ≡ if n < 2 then n else Fib(n − 1) + Fib(n − 2) fi. Resolverlo como ejercicio. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales no a la cola En este caso tenemos más de una llamada recursiva y esta no es la última operación que se aplica. Un ejemplo serı́a Fib(n) ≡ if n < 2 then n else Fib(n − 1) + Fib(n − 2) fi. Resolverlo como ejercicio. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Funciones recursivas no lineales no a la cola En este caso tenemos más de una llamada recursiva y esta no es la última operación que se aplica. Un ejemplo serı́a Fib(n) ≡ if n < 2 then n else Fib(n − 1) + Fib(n − 2) fi. Resolverlo como ejercicio. Leandro Radusky Eliminación de la recursión Generalización de funciones Eliminación de la recursión Preguntas? Leandro Radusky Eliminación de la recursión