Práctica N o 4 - Programación Lógica Para resolver esta práctica, recomendamos usar el SWI-Prolog, de distribución gratuita, que puede bajarse de http://www.swi-prolog.org. No utilizar cut (!) ni predicados de alto orden (como setof). La única excepción es el not, que está permitido. Ejercicio 1 A partir de los predicados binarios padre y esposo y de los predicados unarios hombre y mujer, definir en Prolog los predicados binarios: hijo, abuelo, progenitor, hermano, descendiente, tio. i. Considerar el árbol genealógico de la siguiente figura. Dibuje el árbol de búsqueda de Prolog para la consulta abuelo(who, ron). john mary bob sue bill jane nancy jeff ron padre madre i Defina una nueva relación primo. Cómo se puede definir una consulta para conocer todos los primos de ron? Considerar el agregado del siguiente hecho y regla: ancestro(x, X). ancestro(x, Y) :- ancestro(z, Y), progenitor(x, Z). y el árbol genealógico del item anterior. a) Explicar la respuesta a la consulta ancestro(bill, X). b) Describir las circunstancias en las que puede ocurrir un loop infinito en Prolog. c) Sugerir un solución al problema hallado en los puntos anteriores reescribiendo el programa de ancestro. Página 1 de 7
Ejercicio 2 Usando la definición de número natural a partir de cero y sucesor, definir un predicado unario nn, tal que nn(-x) sii X es un número natural. Definir las siguientes relaciones entre números naturales: i. moi(-x, +Y) sii X es menor o igual que Y. producto(+x, +Y, -Z) sii Z es el producto de X con Y. i fact(+x, -F) sii F es el factorial de X. iv. mod(+x, +Y, -Z) sii Z es el resto de la división entrera entre X e Y. Dar una definición recursiva y una no recursiva. v. Definir un predicado unario que determine si un número entero dado es primo. Tener en cuenta que el argumento siempre está instanciado. Ejercicio 3 Sea el siguiente programa lógico: vecino(x, Y, [X [Y Ls]]). vecino(x, Y, [W Ls]) :- vecino(x, Y, Ls). i. Mostrar el árbol de derivación en Prolog para resolver vecino(5, Y, [5,6,5,3]), devolviendo todos los valores de Y que hacen que la meta se deduzca lógicamente del programa. Si se invierte el orden de las reglas, los resultados son los mismos? Y el orden de los resultados? Ejercicio 4 Definir los siguientes predicados: i. last(-l, -U), donde U es el último elemento de la lista L. Definirlo en forma recursiva, y usando el predicado append definido de la siguiente manera: append([], X, X). append( [H T], Y, [H Z]) :- append(t, Y, Z). reverse(+l, -L1), donde L1 contiene los mismos elementos que L, pero en orden inverso. Ejemplo: reverse([a,b,c], [c,b,a]). Realizar una definición usando append, y otra sin usarlo. Mostrar el árbol de prueba para el ejemplo dado. i maxlista(+l, -M) y minlista(+l, -M), donde M es el máximo/mínimo de la lista L. iv. palindromo(+l, -L1), donde L1 es un palíndromo construido a partir de L. Ejemplo: palindromo([a,b,c], [a,b,c,c,b,a]). Página 2 de 7
v. doble(-l, -L1), donde cada elemento de L aparece dos veces en L1. Ejemplo: doble([a,b,c], [a,a,b,b,c,c]). vi. prefijo(-p, +L), donde P es prefijo de la lista L. v sufijo(-s, +L), donde S es sufijo de la lista L. vi sublista(-s, +L), donde S es sublista de L. ix. iesimo(-i, +L, -X), donde X es el I-ésimo elemento de la lista L. Ejemplo: iesimo(2, [10, 20, 30, 40], 20). Ejercicio 5 Definir los siguientes predicados: i. mezcla(l1, L2, L3), donde L3 es el resultado de mezclar uno a uno los elementos de las listas L1 y L2. Si una lista tiene longitud menor, entonces el resto de la lista más larga es pasado sin cambiar. Verificar la reversibilidad, es decir si es posible obtener L3 a partir de L1 y L2, y viceversa. Ejemplo: mezcla([a,b,c], [d,e], [a,d,b,e,c]). i split(n, L, L1, L2), donde L1 tiene los N primeros elementos de L, y L2 el resto. Si L tiene menos de N elementos el predicado debe fallar. Cuán reversible es este predicado? Es decir, qué elementos pueden estar indefinidos al momento de la invocación? borrar(+listaconxs, +X, -ListaSinXs), que elimina todas las ocurrencias de X de la lista ListaConXs. iv. sacarduplicados(+l1, -L2), que saca todos los elementos duplicados de la lista L1. Ejercicio 6 Considerando los predicados append, prefijo y sufijo ya definidos, realizar el árbol de búsqueda para las siguientes consultas: i. sufijo([a], L), prefijo(l, [a,b,c]). sufijo([b], L), prefijo(l, [a,b,c]). Ejercicio 7 Definir el predicado aplanar(+xs, -Ys), que es verdadero sii Ys contiene los elementos contenidos en algún nivel de Xs, en el mismo orden de aparición. Los elementos de Xs son enteros, átomos o nuevamente listas, de modo que Xs puede tener una profundidad arbitraria. Por el contrario, Ys es una lista de un solo nivel de profundidad. Ejemplos:?- aplanar([a, [3, b, []], [2]], [a, 3, b, 2]).?- aplanar([[1, [2, 3], [a]], [[[]]]], [1, 2, 3, a]). Página 3 de 7
Ejercicio 8 Definir los siguientes predicados: i. ordenada(+l), que será cierta si los elementos de L están ordenados en forma ascendente. i quicksort(+l, -L1), donde L1 es el resultado de ordenar L por el método de quicksort, que consiste en dividir a L en 2 sublistas con los menores y mayores al primer elemento, ordenar cada una de ellas y luego proceder a concatenarlas. inssort(+l, -L1), donde L1 es el resultado de ordenar L por el método de inserción, que consiste en insertar cada elemento en el lugar adecuado del resto de la lista ya ordenada. Ejercicio 9 Definir un predicado rotar(+l, +N, -R), tal que R sea la lista L rotada N posiciones (la rotación se debe hacer hacia la derecha si N>0 y hacia la izquierda si N<0). Ejemplos: rotar([1, a, 2, b, 3], 3, X) debe dar como respuesta X = [2, b, 3, 1, a] rotar([1, a, 2, b, 3], -3, X) debe dar como respuesta X = [b, 3, 1, a, 2] Ejercicio 10 Definir un predicado que reciba una lista de números naturales y devuelva otra lista de números naturales, en la que cada número n de la primera lista aparezca repetido n veces en forma consecutiva, respetando su orden de aparición. Considerar que la lista original siempre está instanciada. Ejemplo: para la lista [2, 3, 1, 0, 2] la salida es [2, 2, 3, 3, 3, 1, 2, 2]. Ejercicio 11 Escribir en Prolog un predicado que devuelva la mediana de una lista (la mediana es el elemento que se halla en la posición del medio de dicha lista, tras ser ordenada). Utilizar los predicados definidos anteriormente. Considerar que la lista siempre está instanciada. Ejercicio 12 Escribir en Prolog los siguientes predicados: pertenece(-x, -L), que es verdadero sii el elemento X se encuentra en la lista L. interseccion(+x, +Y, -Z), tal que Z es la intersección sin repeticiones de las listas X e Y, respetando en Z el orden en que aparecen los elementos en X. Ejercicio 13 Un árbol binario se representará en Prolog con: nil, si es vacío. bin(sai, v, sad), donde v es el valor del nodo, sai es el subárbol izquierdo y sad es el subárbol derecho. Página 4 de 7
i. Definir predicados en Prolog para las operaciones comunes de árboles: vacio, raiz, altura y cantidadnodos. Asumir siempre que el árbol está instanciado. Se define la profundidad de un nodo como la distancia desde la raíz hasta el mismo (la raíz tiene profundidad 0). Definir un predicado hpp que permita, dado un árbol binario instanciado, obtener la lista de todos los valores de las hojas que tengan profundidad par. Puede ocurrir que dos o más hojas distintas tengan el mismo valor, pero en la respuesta de hpp los valores no deben repetirse. Ejemplo: hpp( bin(bin(nil, 2, nil), 2, bin(bin(nil, 4, nil), 1, nil) ), L). L = [4]; No. Ejercicio 14 Definir los siguientes predicados, utilizando la misma representación de árbol binario definida en el ejercicio 13: i. abb(+t) que será verdadero si T es un árbol binario de búsqueda. abbinsertar(+x, +T1, -T2) donde T2 resulta de insertar X en orden en el árbol T1. Ejercicio 15 Un árbol n-ario de naturales se representará en Prolog con: hoja(v), donde V es un natural según la representaciǿn de Prolog. nodo(v, Hijos), donde V es un natural según la representaciǿn de Prolog, e Hijos es una lista no vacía de árboles n-arios de naturales. Definir el predicado mayores(+arbol, +Max) que dado un árbol n-ario de naturales (que podría contener variables en los nodos) devuelve verdadero si: Los naturales que contiene el árbol son menores o iguales a Max (en caso de ser variables, deberán instanciarse con valores en dicho rango). El valor de cada nodo del árbol es mayor que la suma de los valores de sus hijos. Página 5 de 7
Ejemplo: mayores( nodo(x, [hoja(0), nodo(1,[hoja(0), hoja(0)]), nodo(4,[hoja(1), hoja(0), nodo(1, [hoja(0)])])]),9 ) debe responder: X=8; X=9; No Ejercicio 16 Definir el predicado combinador(+l,+d,+h,-xs), que debe dar verdadero cuando XS es una lista de naturales de longitud L, y cada uno de sus elementos XS i cumple que D XS i H. No se deben devolver soluciones repetidas. Por ejemplo: combinador(2,3,5,x). X = [3,3] ; X = [3,4] ; X = [3,5] ; X = [4,3] ; X = [4,4] ; X = [4,5] ; X = [5,3] ; X = [5,4] ; X = [5,5] ; Ejercicio 17 Un cuadrado semi-latino es una matriz cuadrada de naturales (incluido el cero) donde todas las filas de la matriz suman lo mismo. Por ejemplo: 1 3 0 2 2 0 todas las filas suman 4 1 1 2 Representamos la matriz como una lista de filas, donde cada fila es una lista de naturales. El ejemplo anterior se representaría de la siguiente manera: [[1,3,0],[2,2,0],[1,1,2]]. Se pide definir el predicado cuadradosemilatino(n,xs). El parámetro N debe estar instanciado, y XS no puede estar instanciado. El predicado debe ir devolviendo matrices (utilizando la representación antes mencionada), que sean cuadrados semi-latinos de dimensión N*N. Dichas matrices deben devolverse de manera ordenada: primero aquéllas cuyas filas suman 0, luego 1, luego 2, etc.. Página 6 de 7
Ejemplo: cuadradosemilatino(2,x). devuelve: X = [[0, 0], [0, 0]] ; X = [[0, 1], [0, 1]] ; X = [[0, 1], [1, 0]] ; X = [[1, 0], [0, 1]] ; X = [[1, 0], [1, 0]] ; X = [[0, 2], [0, 2]] ; etc. Para la implementación de cuadradosemilatino se cuenta con el siguiente predicado: desde(d, D). desde(d, X) :- DD is D+1, desde(dd, X). Ejercicio 18 Sea la estructura Agenda, y los siguientes predicados disponibles: personas(+agenda, -Personas), que tiene éxito cuando Personas contiene toda la lista de personas de la Agenda. edad(+agenda, +Persona, -Edad), que tiene éxito cuando la Persona tiene edad Edad según la Agenda. Definir el predicado personasenpromedio(+agenda, +Edad, -Conjunto) que tenga éxito cuando Conjunto sea una lista de Personas de la Agenda, cuyo promedio de edad sea menor a Edad. Ejercicio 19 (opcional) Torres de Hanoi. Se tienen tres estacas A, B y C, yndiscos de distintos tamaños, perforados en el centro. Los discos pueden apilarse en las estacas formando torres, y están ubicados inicialmente en la estaca A en orden decreciente de tamaño. El problema consiste en mover los discos de A a C de tal manera que terminen ordenados como lo estaban originalmente. La tarea debe efectuarse bajo las siguientes restricciones: En cada paso sólo un disco puede moverse de una estaca a otra. Nunca puede ubicarse un disco sobre otro más pequeño. Usando Prolog, modelar y resolver el problema de las torres de Hanoi para tres estacas y N discos. Página 7 de 7