You are on page 1of 45

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS CURSO DE SISTEMAS BASADOS EN EL CONOCIMIENTO 1 PROFESOR: PERVYS RENGIFO RENGIFO AUTOR:

FELIPE FORERO INGENIERIA DE SISTEMAS VIII SEMESTRE 2007-I

1) Elabore un programa en prolog que permita resolver el problema de las Torres de Hanoi. Solucin: Las torres de Hanoi se ha convertido en uno de los problemas clsicos dentro de las ciencias de la computacin- El problema es fcil de comprender, y admite una solucin recursiva simple. La historia puede ser embellecida de varias formas. Hay tres varillas, una de las cuales tiene un nmero de discos insertados, formando una pirmide. La cuestin fundamental es los discos estn insertados en orden de tamao, con el ms grande en el fondo. La figura siguiente ilustra la condicin inicial del problema Varilla de la izquierda Varilla central Varilla de la derecha

Figura 1: Ilustracin de la condicin inicial del problema de la torre de Hanoi (Tomada de http://www.pbclibrary.org/raton/towers.htm) La tarea es transferir los discos desde la varilla de la izquierda hasta la varilla de la derecha, apoyndose, si se necesita, en la varilla central. Lo que hace no trivial este problema es que se deben cumplir tres restricciones: 1) Los discos pueden ser movidos uno a la vez. Si no estuviera esta restriccin el problema se resolvera moviendo el bloque de la varilla actual a la varilla de la derecha. 2) Un disco slo puede ser movido a otra varilla. Otra vez, esto previene una solucin trivial dejar los disco en el piso, y luego insertarlos en las varilla de la derecha. Esta restriccin obliga a utilizar la varilla del centro para almacenar temporalmente los discos. 3) Un disco ms grande nunca puede ser coloca encima de uno ms pequeo.

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS Si esta restriccin no existiera, el problema podra, otra vez ser fcilmente resuelto. Simplemente se pasaran todos discos en la varilla central y luego trasladaran a la varilla de la derecha. El problema computacional bsico de las torres de Hanoi consiste en escribir un programa que incluya las operaciones necesarias para realizar la transferencia de un conjunto de N discos desde la varilla de la izquierda hasta la varilla de la derecha. La manera de pensar un problema recursivo es siempre concentrarse en dos preguntas: a) Cul es el caso base El caso ms simple de las torres de Hanoi podra ser para una pirmide de solo un disco. El caso ms simple es a menudo directo el es fcil de olvidar pero es fundamental para el xito de cualquier recursin. Aqu, la cuestin es esencialmente esta: Como transferir una pila de un disco desde el la varilla de la izquierda, utilizando la varilla de la mitad( si es necesario), a la verilla de la derecha?. La respuesta es directa: Slo mueva el disco de la pila de la izquierda a la pila de la derecha. Tambin podra tomarse como caso base, el caso de que no haya discos. En este caso la respuesta es muy simple: Si no hay discos, entonces, no haga nada. En este momento no se sabe precisamente como formalizar esta respuesta. Debido a que el caso base es el ms simple, su definicin podra no aclarar qu factores se deben tomar en cuenta para la solucin general del problema, es decir que argumentos tendra la funcin o el predicado principal que aproxime la solucin. Sin embargo, el planteamiento si hace una distincin entre dos operaciones y el tipo de entidades a las que se aplican: Transferencia de pilas(de discos) y movimiento de un disco individual. Recuerde que la tarea general es transferir una pirmide de n discos, desde una varilla a otra, apoyndose en una tercera varilla como almacenamiento temporal, pero una de las restricciones establece que su solucin debe involucrar el movimiento de discos individuales de una varilla a otra. b) Cual es el caso recursivo Pensar acerca de este problema recursivamente es pensar cmo puede usar la transferencia de una pila de discos para ayudar en su propia definicin, es decir pensar cmo el problema de la transferencia de N discos puede ser reducido a un caso ms simple de transferencia. Una aproximacin inicial para este problema se logra haciendo la siguiente reflexin: Se deben pasar todos los discos desde la varilla de la izquierda hasta la varilla de la derecha pero no puede colocarse un disco ms grande sobre uno ms pequeo, moviendo solo un disco a la vez. Si pudiera pasar el disco ms grande desde la varilla de la izquierda a la varilla de la derecha, tendra un comienzo excelente para transferir la pila de discos hasta la varilla de la derecha, ya que para que esta transferencia sea exitosa los discos se deben transferir aqu desde el mayor hasta el menor (recuerde que as estn ordenados en la pila de la izquierda). Sin embargo, para hacer esto se requieren dos condiciones:

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS Que el disco ms grande quede solo en la varilla de la izquierda(sin ningn disco encima de l) y que la varilla de la derecha no tenga, en este momento, ningn disco. De estas condiciones resulta como consecuencia que los N-1 discos que se encuentran inicialmente encima del disco ms grande deben ser transferidos a la varilla central(utilizando, si se requiere, a la varilla de la derecha como varilla de almacenamiento temporal). La siguiente grfica ilustra estas condiciones:

Figura 2: Se deben pasar n-1 discos desde la varilla izquierda hasta la varilla central

Figura 3: Luego se puede pasar el disco ms grande desde la varilla izquierda hasta la varilla de la derecha.

Figura4: Estado final luego de las acciones anteriores.

Esto sugiere la primera fase de la recursin: Con el fin de transferir N discos desde la varilla de la izquierda a la varilla de la derecha, se debe transferir N1 discos desde la varilla de la izquierda a la varilla central. El problema de transferir una pila de N discos se ha reducido al problema de transferir una pila de N-1 discos. Observe que durante la transferencia de los N-1 discos de la varilla de la izquierda hasta la varilla del centro, la varilla de la derecha actuar como varilla de almacenamiento temporal. Sin embargo, a pesar de que en el proceso de este paso, la varilla de la derecha almacenar temporalmente discos, al final de este paso, la varilla de la derecha no contendr ningn disco, ya que todos estarn en la varilla del centro(N-1 disco) y en la varilla de la izquierda (el disco ms grande)(ver figura 3). El paso siguiente de la recursin es el paso pivotal: mover el disco ms grande desde la varilla de la izquierda hasta la varilla de la derecha(ver Figuras 3 y 4). La tercera fase de la recursin requiere que se transfiera los N-1 discos desde la varilla central hasta la varilla de la derecha, durante lo cual, la varilla de la izquierda actuar como varilla de almacenamiento temporal. Esta solucin requiere que se distinga entre cada varilla particular y el papel que juega en cualquier fase de la operacin. Cuando se inicia con N discos, la varilla de la izquierda es la fuente y la varilla de la derecha es el destino y la varilla central es la de almacenamiento temporal. Cuando esto se reduce al problema de transferir N-1 discos, la varilla de la mitad es la fuente, la de la derecha es el destino y la de la izquierda es la de almacenamiento temporal. Implementacin en Prolog Para la implementacin se requiere un predicado que permita transferir una pila de N discos desde una fuente X, apoyndose como almacenamiento temporal en Y, a un destino Z, que se podra declarar como: transfiera(N,X,Y,Z).

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS Caso Base: El caso base del algoritmo recursivo, como se mencion ms arriba podra ser el caso en que la pila de la izquierda tenga solamente un disco, para lo cual se requiere solamente, mover el disco desde el origen hasta el destino. En prolog, esto podra escribirse como: transfiera(1,Izquierda,Centro,Derecha):- mueva_disco(Izquierda,Derecha). Tambin podra considerarse como caso base el caso ms trivial, en el cual no hay disco, en este caso simplemente, no hay que hacer nada. En prolog se escribira as: transfiera(0,Izquierda,Centro,Derecha). Usted puede elegir uno de estos dos casos bases. Para este ejemplo se elegir el caso de 0 discos como el caso base, y se exigir que N>=0.

Caso Recursivo Aqu simplemente se debe expresar en la sintaxis de prolog el algoritmo discutido anteriormente: Para transferir N discos desde la varilla Izquierda hasta la varilla Derecha haga lo siguiente: Transfiera N-1 discos desde la varilla de la izquierda hasta la varilla central, utilizando la varilla de la derecha como varilla de almacenamiento temporal. Luego, mueva el disco ms grande (que qued solo en la varilla de la izquierda), desde la varilla Izquierda hasta la varilla Derecha. A continuacin, transfiera los N-1 discos desde la varilla Centro, hasta la varilla Derecha, utilizando la varilla izquierda como varilla de almacenamiento temporal. En prolog, esto se expresara de la siguiente forma transfiera(N,Izquierda,Centro,Derecha):como apoyo %Para transferir N discos de Izquierda a Derecha, utilizando Centro

N>0,M is N-1, % se asegura que N>0 y almacena N-1 en M transfiera(M,Izquierda,Derecha,Centro), %transfiera N-1 discos de Izquierda a Centro, utilizando Derecha como
apoyo

mueva_disco(Izquierda, Derecha), %mueva el disco mayor de Izquierda a Derecha transfiera(M,Centro,Izquierda,Derecha). %transfiera N-1 discos de Centro a Derecha, utilizando a Derecha como
apoyo

Ahora se define el predicado mueva_disco(Izquierda, Derecha). Este predicado solo debe indicar de donde a donde se realizar el movimiento del disco mueva_disco(Izquierda,Derecha):- write('Mueva el disco de arriba desde '), write(Izquierda), write(' hasta '), write(Derecha),nl. Finalmente el programa quedara de la siguiente manera: transfiera(0,Izquierda,Centro,Derecha). transfiera(N,Izquierda,Centro,Derecha):- N>0,M is N-1,

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS transfiera(M,Izquierda,Derecha,Centro), mueva_disco(Izquierda, Derecha), transfiera(M,Centro,Izquierda,Derecha). mueva_disco(Izquierda,Derecha):- write('Mueva el disco de arriba desde '), write(Izquierda), write(' hasta '), write(Derecha),nl. mueva_disco(Izquierda,Derecha):- write('Mueva el disco de arriba desde '), write(Izquierda), write(' hasta '), write(Derecha),nl. Al compilar este programa y correrlo con 3 discos en la varilla izquierda, mediante transfiera(3,izquierda,centro,derecho), se obtiene:

2) Un sistema de produccin consiste en un conjunto de pares situacinaccin, indicando que si esta situacin surge, tome esta accin. Un ejemplo de un sistema de produccin es el programa numerales romanos dado abajo:

% Numerales Romanos para 1 <= X <= 39 romano(X) :X > 39, write('Numero debe estar entre 1 y 39'), nl. romano(X) :X < 0, write(' Numero debe estar entre 1 y 39'), nl. romano(X) :X >= 10, X =< 39, write('X'), Y is X - 10, romano(Y). romano(X) :X == 9, write('IX'). romano(X) :X >= 5, X =< 8, write('V'),

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS


Y is X - 5, romano(Y). romano(X) :X == 4, write('IV'). romano(X) :X >= 1, X =< 3, write('I'), Y is X - 1, romano(Y). romano(0) :- nl.

Estudie como trabaja este algoritmo, y extindalo para manejar todos los nmeros desde 1 a 399. Muestre que su programa funciona para 49, 51, 99, 101,299, y 399. Escriba un ciclo que despliegue los nmeros romanos de todos los nmeros entre 1 y 399 inclusive. SOLUCION: Se puede notar que la manera de procesar el nmero es de los mayores valores hacia los menores, ya que es la manera de escribir un nmero romano, encontramos primero los smbolos de mayor peso, o que representan mayor valor. Para expender el cdigo para que maneje los nmero del 1 al 399, empezamos de manera similar, procesando primero los nmeros de mayor valor, descomponindolo hasta llegar a un mnimo valor. Antes de comenzar se valida que el nmero este en el rango que el algoritmo puede manejar:

romano(X) :X > 399, write('Numero debe estar entre 1 y 399'), nl. romano(X) :X < 0, write(' Numero debe estar entre 1 y 399'), nl. Empezamos entonces con los nmeros que sean mayores o iguales que 100 y menores a 400, si esto sucede, se imprime una C como parte del resultado, y le restamos al numero de entrada estos 100 que ya se representaron, y volvemos a llamar la funcin, de manera recursiva, de tal manera que vuelva a hacer esta evaluacin, y as poner tantas C como sea necesario o seguir con uno de los predicados siguientes: romano(X) :X >= 100, X =< 399, write('C'), Y is X - 100, romano(Y).

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS Una vez el numero sea menor que 100, se evala de nuevo, y si esta entre 90 y 99, agregamos a la salida XC, que es la manera de representar al 90, al hacer esto, tenemos que restarle al numero 90, ya que ya fueron representados, y se vuelve a llamar la funcin con este nuevo numero como argumento romano(X) :X >= 90, X < 100, write('XC'), Y is X-90, romano(Y). Si el nmero esta entre 50 y 89, se le agrega a la salida una L, que representa el numero 50 en romano, y estos 50 son restados del numero a representar, y se vuelve a llamar la funcin romano con este nuevo valor romano(X) :X >= 50, X < 90, write('L'), Y is X - 50, romano(Y). En el caso en que el nmero al que se le aplica la funcin romano es mayor o igual a 40 y menor que 50, se agrega a la salida XL, que representa 40 en romano. Como se ha venido haciendo, se le resta al numero procesado 40, que ya fueron representados, y con este valor se llama de nuevo la funcin romano, para seguir procesando el valor restante. Hasta este punto es la modificacin que se le tuvo que hace al algoritmo para que procesara nmeros del 1 a 399. romano(X) :X >= 40, X < 50, Y is X-40, write('XL'), romano(Y). En otro caso, si el numero a procesar es mayor o igual a 10 y menor que 40, se agrega a la salida una X que representa un 10, estos se le restan a el numero y se vuelve a llamar la funcin con este nuevo valor romano(X) :X >= 10, X =< 39, write('X'), Y is X - 10, romano(Y). Cuando el nmero es igual a 9, se agrega a la salida IX, que representa al nmero 9 en romano, y no se vuelve a llamar la funcin. Cuando el nmero esta entre 5 y 8, se agrega a la salida V, se le resta 5 al nmero y se vuelve a llamar la funcin con este nuevo valor.

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS romano(X) :X == 9, write('IX'). romano(X) :X >= 5, X =< 8, write('V'), Y is X - 5, romano(Y). En otra entrada a la funcin, si el nmero es igual a 4, se agrega a la salida IV, y no se vuelve a llamar la funcin, ya que el nmero estara totalmente representado en romano. Cuando el numero es menor que 4 y mayor o igual a 1, se agrega a la salida I, se resta 1, y se vuelve a llamar la funcin con el nuevo valor. El algoritmo quedara de la siguiente manera:

% Numerales Romanos para 1 <= X <= 39 romano(X) :X > 399, write('Numero debe estar entre 1 y 399'), nl. romano(X) :X < 0, write(' Numero debe estar entre 1 y 399'), nl.

romano(X) :X >= 100, X =< 399, write('C'), Y is X - 100, romano(Y). romano(X) :X >= 90, X < 100, write('XC'), Y is X-90, romano(Y). romano(X) :X >= 50, X < 90, write('L'), Y is X - 50, romano(Y). romano(X) :X >= 40, X < 50, Y is X-40, write('XL'), romano(Y). romano(X) :X >= 10, X =< 39,

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS write('X'), Y is X - 10, romano(Y). romano(X) :X == 9, write('IX'). romano(X) :X >= 5, X =< 8, write('V'), Y is X - 5, romano(Y). romano(X) :X == 4, write('IV'). romano(X) :X >= 1, X =< 3, write('I'), Y is X - 1, romano(Y). romano(0) :- nl. Finalmente, para imprimir todos los nmeros del 1 al 399 en romano, usamos la funcin forall, acompaada de la funcin integer_bound: romanos:- forall(integer_bound(1,A,399), romano(A)), nl. De esta manera, al llamar la funcin romanos, se imprimirn todos los nmeros. El programa final sera el siguiente: % Numerales Romanos para 1 <= X <= 39 romano(X) :X > 399, write('Numero debe estar entre 1 y 399'), nl. romano(X) :X < 0, write(' Numero debe estar entre 1 y 399'), nl.

romano(X) :X >= 100, X =< 399, write('C'), Y is X - 100, romano(Y). romano(X) :X >= 90, X < 100, write('XC'), Y is X-90, romano(Y). romano(X) :-

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS X >= 50, X < 90, write('L'), Y is X - 50, romano(Y). romano(X) :X >= 40, X < 50, Y is X-40, write('XL'), romano(Y). romano(X) :X >= 10, X =< 39, write('X'), Y is X - 10, romano(Y). romano(X) :X == 9, write('IX'). romano(X) :X >= 5, X =< 8, write('V'), Y is X - 5, romano(Y). romano(X) :X == 4, write('IV'). romano(X) :X >= 1, X =< 3, write('I'), Y is X - 1, romano(Y). romano(0) :- nl. romanos:- forall(integer_bound(1,A,399), romano(A)), nl. Al correr el predicado romanos, se obtiene el siguiente resultado:

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS Si quisiera saber cmo se escribe un nmero cualquiera en el intervalo [1,399], puede utilizar el predicado romano, de la siguiente forma:

3) Definir los siguientes predicados

a. Definir en prolog la siguiente funcin: F(x)=2, si x>10 F(x)= raz(x), si 0 F(x)=-x, si x <0 SOLUCION Se definen los predicados de la misma manera que estn enunciados, usando la funcin de prolog ,sqrt(X), que sirve para hallar la raz cuadrada de X. funcion(X,2):-X>10, !. funcion(X,Y):-X>=0, X=<10, Y is sqrt(X), !. funcion(X,Y):-X<0, Y is -X, !. Al correr el programa, se obtiene:

10

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS b. suma(Liminferior, LimSup, Suma), donde suma es igual a la suma de los enteros desde lmite inferior hasta lmite superior. Por ejemplo: Suma(2, 10, Suma), debera retornar suma= 2+3+4+5+6+7+8+9+10= 54 SOLUCION Se definen los predicados de manera recursiva: Caso base: Cuando el valor del lmite inferior, Liminferior, es igual al limite superior, LimSup. En este caso la Suma es igual a Liminferior. Esto se podra indicar de la siguiente manera: suma(Liminferior, Liminferior, Liminferior):- !. Caso recursivo: Cuando Liminferior < LimSup, en este caso, la Suma es igual a Liminferior ms la suma desde Liminferior+1 hasta LimSup.

Esto se escribe de la siguiente manera: suma(Liminferior, LimSup, Suma):- Liminferior<LimSup, NuevoLim is Liminferior+1, suma(NuevoLim,LimSup,NuevaSuma), Suma is Liminferior + NuevaSuma. En este predicado, NuevoLim es Liminferior+1, y es el nuevo lmite de la suma. NuevaSuma es la suma desde NuevoLim hasta LimSup, y Suma es la suma total, igual a Liminferior ms NuevaSuma. Es decir, que para este caso, se vuelve a llamar al predicado suma, esta vez con el limite inferior incrementado en 1, y el resultado se le suma al limite inferior. Finalmente, el programa quedara suma(Liminferior, Liminferior, Liminferior):- !. suma(Liminferior, LimSup, Suma):- Liminferior<LimSup, NuevoLim is Liminferior+1, suma(NuevoLim,LimSup,NuevaSuma), Suma is Liminferior + NuevaSuma. A continuacin una corrida de este programa:

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS

c. Construya el predicado: Productoria(Liminferior, LimSup, Prod), donde Prod sea el producto de los enteros entre liminferior y LimSup. Por ejemplo Productoria(2,5,Prod), debe retornar, Prod= 2*3*4*5=120 SOLUCION La manera de implementar el predicado que realice este producto, es similar a la manera en que se desarrollo el punto 4 de este taller, la nica diferencia es que en lugar de hacer la suma, se hace el producto: productoria(X,Y,X):- X==Y,!. productoria(X,Y,Prod):- X<Y, A is X+1, productoria(A,Y,S), Prod is X*S d. Construya el predicado: raicesecuacion(A,B,C,X1.X2) donde X1 y X2 son las races de la ecuacin cuadrtica: AX^2+BX+C= 0. SOLUCION Para solucionar este problema se consideran dos casos: 1) Cuando el discriminante, , en este caso las soluciones son reales.

Aqu se incluye el caso en que 2) Cuando el discriminante, soluciones son conjugadas complejas. | |

, en el cual X1=X2 , en este caso las

| |

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS Adicionalmente, con el fin de garantizar que la ecuacin sea cuadrtica, se verificar que el primer coeficiente sea diferente de cero. El programa quedara de la siguiente forma: raicesecuacion(A,_,_,_,_):-A=:=0, write('Para que la ecuacin sea cuadrtica,el primer coeficiente debe ser diferente de cero'),abort,!. raicesecuacion(A,B,C,X1,X2):-B*B-4*A*C>=0, X1 is (-B+sqrt(B*B-4*A*C))/(2*A), X2 is (-B-sqrt(B*B-4*A*C))/(2*A),!. raicesecuacion(A,B,C,X1,X2):-B*B-4*A*C<0, Aux is abs(B*B-4*A*C), Xr is -B/(2*A), Xi is sqrt(Aux )/(2*A), X1=Xr+Xi*i, X2=Xr-Xi*i. A continuacin se presentan varias corridas de este programa:

e. Construya el predicado: potencia(X,N, Pot), donde Pot= X^N, pero sin utilizar la funcin ^ definida en prolog. SOLUCION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

La potenciacin tiene una definicin recursiva: Caso Base: X0=1, lo cual se indicara en prolog de la siguiente manera:
potencia(X,0, 1).

Caso recursivo:
potencia(X,N,P):-Y is N-1, potencia(X,Y,Q), P is X*Q,!.

Aunque esto captura el contenido lgico de la potenciacin, no es totalmente correcta como un programa, debido a la forma como prolog busca la solucin a una consulta. En primera instancia este programa retornar el resultado correcto para un X>0, pero cuando se pregunte por soluciones adicionales, se har una recursin infinita, ya que en ninguna parte del programa se ha establecido que existe una

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS nica solucin para X0,por lo tanto prolog intentar encontrar otras soluciones para potencia(X,0, P), ahora utilizando la definicin recursiva. En este caso se generar una recursin infinita, ya que no hay un caso base para detenerla y se produdir un desbordamiento de pila.

Al escribir ; o presionar la barra espaciadora, se pregunta a prolog por soluciones alternativas, obtenindose:

Para resolver este inconveniente, se debe indicar a prolog que X0=1 y no hay ms soluciones; esto se puede hacer utilizando el corte,!, de la siguiente forma:
potencia(X,0, 1):-!.

El corte evita que prolog, una vez halle una solucin, siga buscando otras soluciones. Para evitar que se produzcan errores por el procesamiento de exponentes negativos:
%caso recursivo N>0 potencia(X,N,P):-N>0, Y is N-1, potencia(X,Y,Q), P is X*Q,!.

El caso de exponentes negativos se puede incluir teniendo en cuenta que para N<0:

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS

| |

Con lo cual esta parte quedara como:


%caso recursivo N<0 potencia(X,N,P):-N<0, AN is abs(N), potencia(X,AN,Q), P is 1/Q,!.

El programa, finalmente sera:


%%%Potencias(X,N,P) calcula el valor de X^N, y lo almacena en P %caso base X^0=1 potencia(X,0,1):-!. %caso recursivo N>0 potencia(X,N,P):-N>0, Y is N-1, potencia(X,Y,Q), P is X*Q,!. %caso recursivo N<0 potencia(X,N,P):-N<0, AN is abs(N), potencia(X,AN,Q), P is 1/Q,!.

A continuacin se presentan algunas ejecuciones de este programa:

f. Construya el predicado: Fibonacci(N,M), donde M es N-simo trmino de la serie de fibonacci SOLUCION La serie fibonacci tambin la definimos en trminos recursivos, ya que el n-esimo trmino de la serie es igual a la suma de los dos trminos anteriores. Los casos base de la serie son el primer y segundo termino

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS de la serie, que son el 0 y el 1. Los otros los podemos hallar de la suma de los dos anteriores trminos de la serie:
fibonacci(0,0):-!. fibonacci(1,1):-!. fibonacci(N,M):-N>0, A is N-2, B is N-1, fibonacci(A,X), fibonacci(B,Y), M is X+Y.

g. Construya el predicado:Tabla_de_multiplicar(X, LimSup) imprima la tabla de multiplicar de X, desde 1 hasta LimSup. Ejemplos: Tabla_multiplicar(2, 5), debe imprimir: 2*1=2 2*2=4 2*3=6 2*4=8 2*5=10

SOLUCION Para este predicado podemos usar la funcin de Prolog llamada integer_bound, la cual, si se llama con los parmetros (1,M,L), en M asignar un numero entero desde 1 hasta L, incrementndose de 1 en 1, cada vez que se llame la funcin. Para obligar a que prolog vuelva a entrar en el predicado, usamos la instruccin fail, que hace que prolog vuelva a buscar una solucin, y as incrementar a M en la siguiente entrada. Cada vez que entre se va a imprimir la multiplicacin con M del numero del que se quiere la tabla de multiplicar, que en este caso es X. esto suceder hasta que M llegue a L.

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS tabla_de_multiplicar(X,L):- integer_bound(1,M,L), R is X*M, write(X * M = R), nl, fail. Al ejecutar este predicado para generar la tabla de multiplicacin del 9, desde 1 hasta 10, se obtiene lo siguiente:

Utilizando un esquema recursivo tambin es posible obtener el mismo resultado. Se define un predicado que escribe las multiplicaciones: escribir_mult(X,N,R):-write(X*N=R), nl. Se define un predicado que imprime las tabla de multiplicar para X, desde LimInf hasta LimSup: Caso Base: Si LimInf =LimSup, entonces escriba X*N=R, donde R es la variable en donde se almacena el resultado numrico de X*N. multiplicar(X,LimSup,LimSup):-Resultado is X*LimSup, escribir_mult(X,LimSup,Resultado),!. Caso Recursivo: Si LimInf<LimSup, escriba X*LimInf=Resultado, incremente LimInf y almacnelo en NuevoLimInf y haga la tabla desde NuevoLimInf hasta LimSup. multiplicar(X,LimInf,LimSup):-LimInf<LimSup , Resultado is X*LimInf, escribir_mult(X,LimInf,Resultado), NuevoLimInf is LimInf+1, multiplicar(X,NuevoLimInf,LimSup). Con base en este predicado se define el predicado tabla_de_multiplicar(X,LimSup) as: tabla_de_multiplicar(X,LimSup):- multiplicar(X,1,LimSup). El programa completo sera: escribir_mult(X,LimSup,Resultado):-write(X*LimSup=Resultado), nl. multiplicar(X,LimSup,LimSup):-Resultado is X*LimSup, escribir_mult(X,LimSup,Resultado),!.

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS multiplicar(X,LimInf,LimSup):-LimInf<LimSup , Resultado is X*LimInf, escribir_mult(X,LimInf,Resultado), NuevoLimInf is LimInf+1, multiplicar(X,NuevoLimInf,LimSup). tabla_de_multiplicar(X,LimSup):- multiplicar(X,1,LimSup). En la siguiente figura se muestra un ejemplo de la ejecucin de este predicado

h. Elabore un programa que simule una instruccin while, imprimiendo en pantalla una palabra, un nmero determinado de veces. SOLUCIN: Se puede plantear una solucin recursiva, basados en un predicado imprima_palabra(Veces, palabra), se la siguiente forma: Caso Base: Si Veces es igual a cero, no haga nada. Esto se escribira como: imprima_palabra(0, Palabra). Caso Recursivo: Si Veces es diferente a 0, entonces escriba Palabra , decremente Veces en 1 y vuelva a llamar el predicado imprima_palabra. Esto se indica en prolog de la siguiente forma imprima_palabra(Veces, Palabra):write(Palabra),nl, % esto corresponde al predicado que desea repetir Veces1 is Veces-1, imprima_palabra(Veces1,Palabra). Al ejecutar este predicado con Veces=5, y Palabra = Pervys, se obtiene

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS

4) Construya predicados convenientes para calcular las siguientes series:


( ) ( )

a) b)

c) d) e) f)

( ) ( ) ( ) ( )

) ( )
(

SOLUCION Para desarrollar estos ejemplos se requiere desarrollar los siguientes predicados bsicos: %%%Potencias(X,N,P) calcula el valor de X^N, y lo almacena en P %caso base X^0=1 potencia(X,0,1):-!. %caso recursivo N>0 potencia(X,N,P):-N>0, Y is N-1, potencia(X,Y,Q), P is X*Q,!. %caso recursivo N<0 potencia(X,N,P):-N<0, AN is abs(N), potencia(X,AN,Q), P is 1/Q,!.

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS %%factorial(N,Factorial) calcula el valor de N!, y lo almacena en NFactorial %caso base 0!=1 factorial(0,1):-!. %caso recursivo factorial(N,NFactorial):-N>0,X is N-1, factorial(X,Y), NFactorial is N*Y,!. %%%Factorial version iterativa factorial_iter(N,F) :- fact_iter(N,1,F). %El valor en Aux, cuando I sea 0 es el factorial fact_iter(0,F,F):-!. fact_iter(I,Aux,F) :- I1 is I-1, Aux1 is I*Aux, fact_iter(I1,Aux1,F). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% a) ( )

%%versin 1 suma1(X,LimInf,LimInf, Suma1):-potencia(X,LimInf,Suma1),!. suma1(X,LimInf,N,Suma1):-N>0,K is LimInf+1, potencia(X,LimInf,R), suma1(X,K,N,T), Suma1 is R+T. f1(X,N,F1):- suma1(X,0,N, F1). Considrese el caso en el cual X=3 y N=7 ( )

Al correr este programa se obtiene:

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS %%versin 2 suma11(X,0,1):-!. suma11(X,N,S):-N>0,K is N-1, potencia(X,N,R), suma11(X,K,T), S is R+T,!. f11(X,N,F1):- suma11(X,N, F1). Al correr esta nueva versin se obtiene:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% a) ( )

f2(X,0,X):-!. f2(X,N,S):-N>0,Q is N-1, P is 2*N+1, potencia(X,P,Z), f2(X,Q,T), S is Z/P+T. Al correr esta predicado con X=3 y N=4, se obtiene:
( ) ( ) ( ) ( ) ( )

( )

( )

( )

( )

( )

( )

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% a) ( ) ( )
( )

suma3(X,0,X):-!. suma3(X,N,S):-N>0,Q is N-1, P is 2*N+1, potencia(X,P,Z), potencia(-1,N,R), factorial(P,F),suma3(X,Q,T), S is R*Z/F+T. Ahora, con base en el predicado anterior se define la funcin seno, tomando N= 8 trminos de la serie( N mayores producirn mayor exactitud) seno(X,Seno):-suma3(X,8,Seno). El programa completo quedara as: suma3(X,0,X):-!. suma3(X,N,S):-N>0,Q is N-1, P is 2*N+1, potencia(X,P,Z), potencia(-1,N,R), factorial(P,F),suma3(X,Q,T), S is R*Z/F+T. seno(X,Seno):-suma3(X,8,Seno). Al correr este programa con X=0.5 se obtiene: Sen(0.5)= 0.47942554

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

b)

( )

suma5(X,0,1):-!. suma5(X,N,S):-P is N-1, potencia(X,N,R), factorial(N,F), suma5(X,P,T), S is R/F+T. %Ahora se define la funcin exponencial con N=11 exp (X,Exp):-suma5(X,11,Exp). Al correr este programa con X=0.5, se obtiene: Exp(0.5)= 1.64872127

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% c) ( ) ( )
( )

suma6(X,1,S):-S is -1+X,!. suma6(X,N,S):-P is N-1, Q is -1+X, potencia(-1,P,R), potencia(Q,N,T), suma6(X,P,M), S is R*T/N+M.

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS %Con base en el predicado anterior se define el Logaritmo, tomando 30 trminos de la serie ln(X,Ln):-suma6(X,30,Ln). Al correr este programa con X=0.5 se obtiene: ln(0.5)= -0.69314718

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% d) ( ) ( )
( )

%%version 1 suma7(X,0,1):-!. suma7(X,N,S):-Q is N-1, P is 2*N, potencia(X,P,Z), potencia(-1,N,R), factorial(P,F), suma7(X,Q,T), S is R*Z/F+T,!. coseno(X,Cos):-suma7(X,8,Cos). %%version 2 suma71(X,N,N,S):- P is 2*N,potencia(1,N,R),potencia(X,P,Z),factorial(P,F),S is R*Z/F,!. suma71(X,N,N1,S):-Q is N+1, P is 2*N, potencia(X,P,Z), potencia(-1,N,R), factorial(P,F), suma71(X,Q,N1,T), S is R*Z/F+T,!. coseno1(X,Cos):-suma71(X,0,7,Cos). Al correr estos programas con X=0.5, se obtiene:cos(0.5)= 0.87758256

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS

5) Elabore un programa que permita responder consultas acerca de las capitales de los departamentos de Colombia, siguiendo los siguientes lineamiento: Que cargue al iniciar la base de conocimiento incompleta sobre departamentos y capitales del archivo capital.pl, lo cual se puede hacer almacenando en este archivo, hechos de la forma capital(departamento, capital). Cuando el usuario digite un departamento que no se encuentre en la base de conocimiento actual, el programa debe solicitar al usuario que ingrese la capital de ese departamento con el fin de aprenderla y poder responder adecuadamente en la siguiente ocasin. Al finalizar el programa debe guardar en el archivo capital.pl, toda la base de conocimiento. SOLUCIN %Se define a capital como un predicado dinmico de dos argumentos. Esto permite agregar instancias de este predicado, en tiempo de corrida % durante el tiempo de corrida. :-dynamic(capital/2).

% encuentraCapital es el predicado principal. El acepta el nombre de un departamento % y llama a buscaCapital para que haga la bsqueda pregunta_cont:-write('desea continuar? '),read(T),continue(T). continue('s'):-encuentraCapital,!. continue('S'):-encuentraCapital,!. continue('n'):-continue('N'). continue('N'):-write('Ahora se proceder a salvar la base de conocimiento'),nl, tell('capital.pl'), listing(capital), told, write('Ya se ha guardado'),nl,write(' ADIOS!!!!!!'). continue(_):-pregunta_cont,!. inicio:-reconsult('capital.pl'), encuentraCapital.

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS encuentraCapital :- write('ingrese el departamento: '),nl, read(Departamento), buscaCapital(Departamento), pregunta_cont. % buscaCapital usa la busqueda de encadenamiento hacia atrs para encontrar una matching % capital(Departamento, Capital). Si l tiene xito, entonces imprime la ciudad y se detiene buscaCapital(Departamento) :- capital(Departamento, Capital), write('La capital del departamento: '),write(Departamento), write(' es: '), write(Capital), nl. % El control pasar aqu solamente si el primer intento de bsqueda falla % En ese caso se pregunta al usuario para que proporcione la informacin. % Observe el uso de assertz, que adiciona la nueva informacin al final de la base de conocimiento buscaCapital(Departamento) :-write('Yo no conozco ese departamento.'),nl, write('Usted me podra decir cul es su capital?'),nl, write('Yo lo recordar la prxima vez.'), read(Capital), assertz(capital(Departamento, Capital)), write('Gracias!'), nl.

inicio:-captchreconsult('capital.pl'), encuentraCapital. inicio:-catch(Error,reconsult('capital.pl')),Error=:=31>fcreate(cap,'capital.pl',0,0,0),fclose(cap),reconsult('capital.pl'), encuentraCapital;encuentraCapital. %reconsult('capital.pl'), encuentraCapital. 1. Construya un programa que implemente los siguientes mtodos para hallar races de ecuaciones no lineales: Mtodo de Biseccin Mtodo de Regla falsa

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS Mtodo de la Secante.

CONTROL CON EL CORTE Por una variedad de razones, una definicin puede ser lgicamente correcta pero ser ineficiente como un programa. Una forma en la que un programa es ineficiente es por permitir a Prolog que busque ms soluciones cuando no hay ms soluciones. Esto hace que Porlog gaste un poco de tiempo hasta darse cuenta que ya no hay ms solucines y en el pero de los casos lo enviar a un ciclo infinito. Prolog tiene una caracterstica especial que restringe la bsqueda para soluciones alternativas, el corte. En la sintaxis de Edimburgo ella se escribe como una signo de exclamacin. A pesar de su nombre el corte es un buen instumento de corte para controlar a un programa restringiendo el backtracking. La idea bsica es que cuando prolog pasa por una ocurrencia de !, al intentar resolver alguna consulta, el corte previene el re-paso de ese punto cuando hace el backtracking.Una vez prolog alcanza el ! En algn punto dentro de una clusula, else vuelve comprometido para la solucin de cualquier meta que lo obtenga en la bsqueda de ese punto , y puede backtarck solamente a la derecha del corte. Suponga que diversas clusulas en la definicin de algn predicado p, y que una de ellas contiene una ocurrencia de !,imagine que en el curso de resolver alguna consulta , Prolog necesita encontrar una solucin ap(x) y obtener la clusula con el corte. Una analoga sera, si pensamos a prolog como un vehculo que viaja una ruta hacia adelante y haca atrs a traves de un progrmam, buscano soluciones, ese corte es un tipo especial de traluz de trfico. Inicialmente, las luces estan en verde. Cuando Prolog pasa a travs de la luz , bsqueda de una solucin, ellas automticamente cambian a rojo,. Prolog puede seguir hacia delante y hacia atrs la parte de la carretera que est despus de las luces, en la bsqueda de soluciones , pero no puede pasar hacia atrs de las luces para intentar re-resolver las metas que las preceden. Tv(t) Tv(f) Pair(X,Y):-tv(X),tv(Y). Sintcticamente, el corte puede ser adicionado como una condicin atmica en cualquier parte en el cuerpo de una regla. Por ejemplo podemos colocarlo as. Pair(X,Y):-tv(X),!!,tv(Y). Hay tres lugares en donde podra ser colocado en esta regla, la cual marcara como sigue: Pair(X,Y):- (iii), tv(X), (ii) tv(Y) (i). Ninguna de las tres posiciones corresponde a un usos realsticos del corte, pero ilustran su efecto sobre el backtracking. Si nosotros colocamos el cote al final de la clusula n la posicin (i), Prolog es reducido a las soluciones que l obtiene para tv(X) y tv(Y) que obtiene all; el no puede baktrack de ninguna forma. Si nosotros lo clocamos en la posicin ii) esto libera para backtrack sobre la solucines de tv(Y), pero no sobre tv(X). Ponindolo en la posicin iii, significa que prolog cruza el corte tan pronto como intenta resolver pair, y es reducido a esa clusula. El puede backtrack por todas las metas a la derecha, justo como el programa original sin corte. Pero si hubieran clausulas adicionales a la definicin de pair, un! En la posicin (iii) podra resultar redundante

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS


Y=t X=t ii tv(Y) Y=f pait(t,f) i pair(t,t)

pair(X,Y)

iii

tv(X) pair(f,t)

Y=t X=f tv(Y)

Y=f

pair(f,f)

Posicin (i) permite a este programa solo una solucin, (i) le permite dos, y (iii) permite todas las cuatro. Factorial: La funcin factorial es uno de los ejemplos ms simples de recursin numrica. Para construir la funcin vamos a analizar el procedimiento de clculo para un ejemplo en particular: 5!=5*4*3*2*1=5*4! Generalizando: n!=n(n-1)! En palabras: el factorial de un nmero es ese nmero multiplicado por el factorial de su predecesor. Adicionando a esto el caso base de que 1!=1, se tiene una definicin recursiva del factorial. En notacin matemtica: 1!. N!=N(N-1)! Para calcular el factorial de un nmero n, primero encontramos el nmero X que es uno menos que n, luego halle el factorial Y de X, luego multiplique Y por N. En prolog Fac.(1,1). Fac.(N,M):-X is N-1, fact(X,Y), M is N*Y. Aunque esto es esencialmente correcto, aqu surge el mismo problema que ocurre durante el retroceso para el caso de la potenciacin. Si se requieren soluciones adicionales, fact generar una regresin infinita.

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS


Ruta de la solucin fact(3,M) Ruta invertida durante el retroceso

M=6

X is 3-1 X=2

fact(2,Y) Y=2

M is 3*2

6 is 3*2 2 is 3-1 A is 2-1 A=1 fact(1,B) B=1 Y is 2*1

1 is 2-1

6 is 3*2

fact(1,1)

C is 1-1 C=0

fact(0,D)

! E=0-1 E=-1 fact(-1,F)

Nosotros podemos prevenir esto conla estrategia adoptada para exp: insertando un N>1 como la primera condicin en el antecedente de la clusula general, nosotros hacemos explcita la condicin que fact aplica solamente para nmero mayores que 1. Hay sin embargo, una manera completamente diferente de asegurar este efecto. Ms que construir en la definicin la condicin que fact solo aplica a nmeros positivos, nosotros tenemos como meta hacerlo a partir del hecho de que fact es una funcin. En este sentido aunque sabemos que el factorial es una relacin funcional que para la cualquier N solo puede existir uno y solo un M tal que fact(N,M), no hay nada en el programa que lo explicite. Nosotros sabemos por ejemplo que la nica solucin para fact(1,M) es M=1. Pero si Prolog est buscando soluciones para esta meta, nada en le programa hasta ahora le dice que esta es la nica instancia de esa relacin. El corte nos habilita para asegurar este efecto-decirle a Prolog que no intente buscar soluciones alternativas para fact(1,M). Ya que es sintcticamente solo una condicin atmica, si nosotros deseamos adicionar un corte a una sentencia incondicional, la haremos condicional: fact(1,1):-!. En general, es mejor pensar el corte como no teniendo ningn efecto sobre la lectura declarativa de un sentencia, es decir para leer esto como: El fatorial e 1 es 1, incondicionalmente( es decir si nada) Esto es esencialmente lo mismo que antes. Debido a que el corte esta relacionado con el

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS control, es decir con la restriccin del backtracking, el corte no se muestra realmente en el contenido lgico de un programa. Donde el hace una diferencia significativa es en la lectura procedimental. Para probar que el factorial de 1 es 1, no haga nada(esto es lo mismo que sin )-pero falle totalmente en cualquier intento por re-resolver esta meta. Sin embargo, en este caso la presencia del corte es ligeramente especial, en que nosotros podemos pensarlo como una afectacin al contenido descriptivo de la definicin. , viz El factorial de 1 es, nicamente 1. Esto es, pensarlo como decirle a prolo que fact es una funcin que para el caso del nmero 1 , el nico M para el cual fact(1,M) es 1(y el nico N para el cual fac(N,1) es 1) Debido a que esto es la base para una recursin, la unicidad tiene aqu el efecto de asegurar la unicidad para todos los nmeros. Para ver la forma que tiene el corte para prevenir que fact entre en una regresin infinita en el retroceso, ayuda seguie la manera como el factorial es calculado en un caso particular, por ejemplo hallar el factorial de 3 es 6. Nosotros ilustramos el camino para la solucin como siguies. Cada vez el fact se llama recursivamente , mostramos el valor obtenido en los clculos como instanciaciones sucesivas de la regla general hasta que se verifique la condicin base. El siguiente predicado chequea si un elemento pertenece a una lista

pertenece(X,[X|_]). pertenece(X,[_|Ys]):-pertenece(X,Ys).

Tamao de una lista


longitud([],0).

longitud([H|T],N) :- size(T,N1), N is N1+1.


The length of the empty list is 0. The length of the list whose head is H and whose tail is the list T is: 1 + (the length of T).

La longitud de la lista vacia es cero: La longitud de la lista cuya cabeza es H y cuya cola es T es 1+(la longitud de T)
Suma de los elementos de una lista sumlist([],0).

sumlist([H|T],N) :- sumlist(T,N1), N is N1+H. La suma de los elementos de la lista vaca es 0. La suma de los elementos de la lista cuya cabeza es H y cuya cola es T, es H+ ( la suma de los elementos de T).
Menbresa member(X,[X|_]).

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS


member(X,[_|T]) :- member(X,T). x es un miembro si la lista cuyo elemento de la cabeza es X( y cuya cola es cualquiera. X es miembro de la lista cuya cabeza es cualquiera y cuya cola es T, si X es un miembro de T Predicado append append([a,b,c],[one,two,three],Result).

Suponga uque se desea escribir un predicado de un argumento, e imprima todos los nmero entre l y 0. Imprima_hasta(0) :- write(0). Imprima_hasta(N) :- N>0, write(N), nl, N1 is N-1, imprima_hasta(N1) Si N=0, imprima 0 Si N>0, escriba N, haga N-1 y luego imprima N-1, hasta que N=0. Ahora suponga que deseamos tomar estos nmeros y procesarlos en una cierta otra parte del programa; para hacer esto tendramos que almacenarlos en alguna parte - la opcin natural es utilizar una lista. As desearamos un predicado de la forma collect_to(N, L) donde estaba el nmero N de la entrada, y L era la lista que contena la respuesta. collect_to(0,L) :- L=[].

This will be slightly different to the other list predicates, since now we want to build a list as we iterate, rather than take one apart. However, the process will still use the standard "[H|T]" notation that we have been using. We should work it out int he usual recursive manner:
Esto ser levemente diferente a los otros predicados de lista, ya que ahora nosotros deseamos construir una lista conforme se itera, y no tomar cada uno por separado. Sin embargo, el proceso usar la notacion estndar [ H|T ] . Caso Base: Si el numero que se ingresa es igual a 0, entonces la respuesta es sera [ 0 ], as se puede escribir collect_to(0,L) :- L=[]. Caso Recursivo: Si se est tratando con un numero, por decir N, entonces asumimos que sabemos como recolectar todos los nmero hasta N-1(gracias a la recursin) de tal forma que solo necesitamos conocer como asicionarun bit de informacin extra acerca del elemento actual; el codigo seria collect_to(N,L) :- N>0, N1 is N-1, collect_to(N1,T), L=[N|T].

Aunque esto esta bien la manera mas normal de escribir esto es: new_collect_to(0,[]). new_collect_to(N,[N|T]) :- N>0, N1 is N-1, new_collect_to(N1,T). JUNTANDO LISTAS

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS


Nosotros podemos escribir un predicado que junte dos listas; el predicado append(L1,L2,L3) significa Si juntamos L1 y L2 se obtine L3

Si se consideran las posibilidades para L1 1) L1 es vaca, caso en el cual L3 es L2 2) L1 es de la forma [H1 | T1]. 1. L1 is the empty list, in which case L3 is just L2 2. L1 is of the form [H1 | T1]., se obtendra una lista cuya cabeza es H1 y cuya cola es el resultado de juntar T1 y L2 As un intento inicial sera
append(L1,L2,L3) :- L1=[], L3=L2. append(L1,L2,L3) :- L1=[H1|T1], append(T1,L2,T3), L3=[H1|T3].

Ya que se sabe que prolog har unificacin cuando el empareje(matches) parmetro contra argumentos, una solucin mas simple( pero equivalente) sera append([], L2, L2). append([H1|T1], L2, [H1|L3]) :- append(T1,L2,L3). Haga las siguientes consultas append([1,2],[6,7],X) append(X, [5,6], [3,5,6]). append([3,4], Y, [3,4,5,6]). append(X,Y,[1,2]).

El operador "corte". El operador corte, representado por el smbolo "!" nos da un cierto control sobre el mecanismo de deduccin del PROLOG. Su funcin es la de controlar el proceso de reevaluacin, limit ndolo a los hechos que nos interesen. Supongamos la siguiente regla:
regla :- hecho1, hecho2, !, hecho3, hecho4, hecho5.

PROLOG efectuar reevaluaciones entre los hechos 1, 2 sin ningn problema, hasta que se satisface el hecho2. En ese momento se alcanza el hecho3, pudiendo haber a continuacin reevaluaciones de los hechos 3, 4 y 5. Sin embargo, si el hecho3 fracasa, no se intentara de ninguna forma reevaluar el hecho2. Una interpretacin prctica del significado del corte en una regla puede er que "si has llegado hasta aqu es que has encontrado la nica solucin a este problema y no hay razn para seguir buscando alternativas".

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS Aunque se suele emplear como una herramienta para la optimizacin de programas, en muchos casos marca la diferencia entre un programa que funciona y otro que no lo hace.

% From the book % PROLOG PROGRAMMING IN DEPTH % by Michael A. Covington, Donald Nute, and Andre Vellino % (Prentice Hall, 1997). % Copyright 1997 Prentice-Hall, Inc. % For educational use only % File CAR.PL % Simple automotive expert system :- reconsult('getyesno.pl'). % Use ensure_loaded if available. % % Main control procedures % start :write('This program diagnoses why a car won''t start.'),nl, write('Answer all questions with Y for yes or N for no.'),nl, clear_stored_answers, try_all_possibilities. try_all_possibilities :defect_may_be(D), explain(D), fail. try_all_possibilities. % Backtrack through all possibilities...

% ...then succeed with no further action.

% % Diagnostic knowledge base % (conditions under which to give each diagnosis) % defect_may_be(drained_battery) :user_says(starter_was_ok,yes), user_says(starter_is_ok,no). defect_may_be(wrong_gear) :user_says(starter_was_ok,no). defect_may_be(starting_system) :user_says(starter_was_ok,no).

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS defect_may_be(fuel_system) :user_says(starter_was_ok,yes), user_says(fuel_is_ok,no). defect_may_be(ignition_system) :user_says(starter_was_ok,yes), user_says(fuel_is_ok,yes).

% % Case knowledge base % (information supplied by the user during the consultation) % :- dynamic(stored_answer/2). % (Clauses get added as user answers questions.)

% % Procedure to get rid of the stored answers % without abolishing the dynamic declaration % clear_stored_answers :- retract(stored_answer(_,_)),fail. clear_stored_answers.

% % Procedure to retrieve the user's answer to each question when needed, % or ask the question if it has not already been asked % user_says(Q,A) :- stored_answer(Q,A). user_says(Q,A) :- \+ stored_answer(Q,_), nl,nl, ask_question(Q), get_yes_or_no(Response), asserta(stored_answer(Q,Response)), Response = A.

% % Texts of the questions % ask_question(starter_was_ok) :write('When you first started trying to start the car,'),nl,

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS write('did the starter crank the engine normally? '),nl. ask_question(starter_is_ok) :write('Does the starter crank the engine normally now? '),nl. ask_question(fuel_is_ok) :write('Look in the carburetor. Can you see or smell gasoline?'),nl.

% % Explanations for the various diagnoses % explain(wrong_gear) :nl, write('Check that the gearshift is set to Park or Neutral.'),nl, write('Try jiggling the gearshift lever.'),nl. explain(starting_system) :nl, write('Check for a defective battery, voltage'),nl, write('regulator, or alternator; if any of these is'),nl, write('the problem, charging the battery or jump-'),nl, write('starting may get the car going temporarily.'),nl, write('Or the starter itself may be defective.'),nl. explain(drained_battery) :nl, write('Your attempts to start the car have run down the battery.'),nl, write('Recharging or jump-starting will be necessary.'),nl, write('But there is probably nothing wrong with the battery itself.'),nl. explain(fuel_system) :nl, write('Check whether there is fuel in the tank.'),nl, write('If so, check for a clogged fuel line or filter'),nl, write('or a defective fuel pump.'),nl. explain(ignition_system) :nl, write('Check the spark plugs, cables, distributor,'),nl, write('coil, and other parts of the ignition system.'),nl, write('If any of these are visibly defective or long'),nl, write('overdue for replacement, replace them; if this'),nl, write('does not solve the problem, consult a mechanic.'),nl.

% suma de vectores sumavectores( [],[],[] ).

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS

sumavectores( [C1|R1],[C2|R2],[C3|R3] ):-C3 is C1+C2, sumavectores( R1,R2,R3 ). ?-sumavectores( [1,2,3], [4,5,6], X ). X=[5,7,9] %suma de matrices bidimensionales sumamatrices( [],[],[] ). sumamatrices( [C1|R1],[C2|R2],[C3|R3] ):sumavectores(C1,C2,C3),sumamatrices(R1,R2,R3). ?-sumamatrices([[1,2],[3,4]],[[5,6],[7,8]],X). X=[[6,8],[10,12]]. %suma generalizada suma([],[],[]). suma(X,Y,Z):- var(Z),number(X),number(Y),Z is X+Y. suma( [C1|R1],[C2|R2],[C3|R3] ):suma(C1,C2,C3),suma(R1,R2,R3). ?-suma( [1,2,3], [4,5,6], X ). X=[5,7,9] ?-suma([[1,2],[3,4]],[[5,6],[7,8]],X). X=[[6,8],[10,12]]. ?-suma([[[1,2],[1,1]],[[2,2],[3,4]]],[[[5,6],[0,0]],[[8,8],[7,8]]],X). X=[[[6,8],[1,1]],[[10,10],[10,12]]].

Definicin de operadores - Contenido de la base de conocimiento :- op(800,xfx,estudian). :- op(400,xfx,y). juan y ana estudian logica. - Consultas: ?- Quienes estudian logica. Quienes = juan y ana ?- juan y Otro estudian Algo. Otro = ana Algo = logica
2.6 Tree data and relations
Consider the following tree diagram.

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS

Fig. 2.6 The file 2_6.pl has a representation for this tree and predicate definitions to do some processing of the tree. Note the use of Prolog operators in some of the definitions.
/* The tree database */ :- op(500,xfx,'is_parent'). a a a b b is_parent is_parent is_parent is_parent is_parent b. c. d. e. f. c c c d e is_parent is_parent is_parent is_parent is_parent g. h. i. j. k. f f h i i is_parent is_parent is_parent is_parent is_parent l. m. n. o. p. j j j m is_parent is_parent is_parent is_parent q. r. s. t.

/* X and Y are siblings */ :- op(500,xfx,'is_sibling_of'). X is_sibling_of Y :- Z is_parent X, Z is_parent Y, X \== Y. /* X and Y are on the same level in the tree. */ :-op(500,xfx,'is_same_level_as'). X is_same_level_as X is_same_level_as X . Y :- W is_parent X, Z is_parent Y, W is_same_level_as Z.

/* Depth of node in the tree. */ :- op(500,xfx,'has_depth'). a has_depth 0 :- !. Node has_depth D :- Mother is_parent Node, Mother has_depth D1, D is D1 + 1. /* Locate node by finding a path from root down to the node. */ locate(Node) :- path(Node), write(Node), nl. path(a). /* Can start at a. */

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS


path(Node) :- Mother is_parent Node, path(Mother), write(Mother), write(' --> '). /* /* Choose parent, /* find path and then */ */

Calculate the height of a node, length of longest a leaf under the node. */

path to

height(N,H) :- setof(Z,ht(N,Z),Set), */ max(Set,0,H). ht(Node,0) :- leaf(Node), !. ht(Node,H) :- Node is_parent Child, ht(Child,H1), H is H1 +1.

/* See section 2.8 for 'setof'.

leaf(Node) :- not(is_parent(Node,Child)). max([],M,M). max([X|R],M,A) :- (X > M -> max(R,X,A) ; max(R,M,A)).

The 'is_sibling_of' relationship tests whether two nodes have a common parent in the tree. For example,
?- h is_sibling_of S=g ; S=i ; no S.

Note the use of the literal X \==Y, which succeeds just in case X and Y are not cobound (bound to the same value). The 'is_same_level_as' relationship tests whether two nodes are on the same level in the tree. The 'depth' predicate computes the depth of a node in the tree (how many edges from the root). For example,
?- t has_depth D. D=4

Here is an alternate definition of 'depth' using Prolog implication:


N has_depth D :- N == 'a' -> D=0 ; Mother is_parent N, Mother has_depth D1, D is D1 + 1.

The 'locate' predicate computes and prints a path from the root to a node. For example,
?- locate(n). a --> c --> h --> n

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS The 'leaf' predicate defines a leaf to be a node which is not a parent. Note the free variable inside the negation. This is correct, since if the node has any child then the node is not a leaf. The 'height' predicate computes the height of a node -- defined as the length of the longest path to a leaf under the node. This definition uses lists and the second-order Prolog predicate 'setof'. We will continue discussion of 'height' and 'setof' in section 2.8. Load the program into the Prolog environment and test the program by issuing various goals. Exercise 2.6.1 Write a Prolog definition for 'ancestor(X,Y)' with the intended meaning that "X is an ancestor of Y in the tree". Pay attention: recursion from the top of the tree or from the bottom of the tree? Exercise 2.6.2 Formulate definitions for a human family tree using relations 'male', 'female', 'parent', 'father', 'mother', 'sibling', 'grandparent', 'grandmother', 'grandfather', 'cousin', 'aunt', and 'uncle'. Let 'male', 'female', 'parent' be the fundamental relations and define the others in terms of these.

Prolog Code for this section. Prolog Tutorial Contents

The program is mainly interesting with regard to how it tries to verify certain properties that it uses to draw conclusions, and how it asks questions and records the answers for further reference. If a question q is asked and the answer is 'yes', then that answer is recorded by asserting 'yes(q)' and succeeding, otherwise the answer is recorded by asserting 'no(q)' and failing. Even 'yes' answers need to be recorded since a subsequent 'no' answer to a different question while trying to verify the same hypothesis may cause the entire hypothesis to fail, but that same 'yes' answer could lead to a successful verification of a different hypothesis later. This is how the program avoids asking the same question twice. The general method of verifying a condition q is then to check whether 'yes(q)' has been stored in memory, and succeed, or 'no(q)' has been stored, and fail, otherwise ask(q).

Factorial (N) Si N = 0 entonces Factorial = 1 Si N > 0 entonces Factorial = N * Factorial (N-1)

Suponga que desea crear un programa que halle todas las soluciones para un objetivo dado. Si se pretende crear un predicado que recursivamente muestre las soluciones, entonces puede ocurrir un desbordamiento de pila. Una opcin es utilizar los siguientes predicados: Findall(T,C,L)
father(michael,cathy). father(charles_gordon,michael). father(jim,melody).

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS


We can ask Prolog to display the names of all the fathers by issuing a query such as: ?- father(X,_), write(X), nl, fail. That is: Find an X for which father(X,_) succeeds, print it, and backtrack to find another one. But what if, instead of displaying the names, we want to process them further as a list? We are in a dilemma. In order to get all the names, the program must backtrack. But in order to construct the list, it must use recursion, passing the partially constructed list as an argument from one iteration to the next which a backtracking program cannot do. One possibility would be to use assert and retract to implement roughly the following algorithm: 1. Backtrack through all solutions of father(X,_), storing each value of X in a separate fact in the knowledge base; 2. After all solutions have been tried, execute a recursive loop that retracts all the stored clauses and gathers the information into a list. Fortunately, we dont have to go through all this. The builtin predicate findall will gather the solutions to a query into a list without needing to perform asserts and retracts.5 Heres an example: ?- findall(X,father(X,_),L). L = [michael,charles_gordon,jim] More generally, a query of the form ?- findall(Variable,Goal,List). will instantiate List to the list of all instantiations of Variable that correspond to solutions of Goal. You can then process this list any way you want to. The first argument of findall need not be a variable; it can be any term with variables in it. The third argument will then be a list of instantiations of the first argument, each one corresponding to a solution of the goal. For example: ?- findall(Parent+Child,father(Parent,Child),L). L = [michael+cathy,charles_gordon+michael,jim+melody] Here the plus sign (+) is, of course, simply a functor written between its arguments. Exercise 5.14.1 Given the knowledge base 5If your Prolog lacks findall, define it: findall(V,Goal,L) :- bagof(V,Goal^Goal,L).

5.15. USING bagof AND setof A BAG is a mathematical object like a set except that the same element can occur in it more than once. Obviously, findall creates a bag, not a set, because the same solution can appear in it more than once. Likewise, bagof creates a bag in the form of a list containing all the solutions to a query; setof does the same thing except that the list is sorted into alphabetical order and duplicates are removed. The sorting operation takes extra time, but it can be worthwhile if it saves duplication of subsequent work. The big difference between bagof and setof on the one hand, and findall on the other, concerns the way they handle uninstantiated variables in Goal that do not occur in X. As you might expect, findall treats them as uninstantiated on every pass. Thus, ?- findall(X,parent(X,Y),L). means Find everyone who is the parent of anybody Y need not have the same value for each parent. But ?- bagof(X,parent(X,Y),L).

findall/3

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS

Retorna una lista no ordenada de trminos en las soluciones de una meta u objetivo dado.
findall( Termino, Objetivo, Lista ) ?Termino <trmino> +Objetivo <Objetivo> ?Lista <variable> o <lista> Comentarios Este predicado retorna una lista no ordenada de soluciones que normalmente se pueden obtener slo por falla y backtracking a travs de una consulta. Este predicado es exitoso si Lista puede ser unificada a una lista de todas las instancias de Trmino tales que el Objetivo sea cierto. El Trmino puede ser cualquier termino de Prolog, y el Objetivo puede ser cualquier objetivo Prolog, con o sin llamadas al predicado cuantificador existencial, ^ / 2, que es ignorado en el presente predicado Examples Consider the database relation: foo( 1, c ). foo( 2, a ). foo( 1, b ). foo( 2, a ). La siguiente llamada devuelve una lista de todas las soluciones de "X" en el Objetivo "foo(Y,X)", sin hacer particin en los diferentes valores de "Y": ?- findall( X, foo(Y,X), Z ). <enter> X=_, Y=_, Z = [c,a,b,a] Notes A diferencia de los predicados bagof/3 y setof/3, findall/3 no realiza ninguna particin de resultados. Por lo tanto, no tiene el concepto de "cuantificacin existential ", y como tal trata cualquier llamada a ^/2 slo como si el objetivo apropiado se llamara directamente.

bagof/3
Retorna una lista no ordenada de trminos en las soluciones de un objetivo dado bagof( Termino, Objetivo, Lista ) ?Term <term> +Goal <goal> ?List <variable> or <list> Comments Este predicado retorna una lista no ordenada de soluciones que normalmente se pueden obtener slo por falla y backtracking a travs de una consulta. Este predicado es exitoso Lista puede ser unificada a una lista de todos las instancias de Trmino tales que el Objetivo sea cierto. El Trmino puede ser cualquier termino de Prolog, y el Objetivo puede ser cualquier objetivo Prolog, con o sin llamadas al predicado cuantificador existencial, ^ / 2, que es usado para alterar la particin e las soluciones

Examples Consider the database relation: padre( felipe, jose ). foo( Felipe, maria ). foo( 1, b ). foo( 2, a ).

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS La siguiente llamada retorna los conjuntos de soluciones de "X" en el objetivo "foo(Y,X)", particionado de acuerdo a los diferentes valroes de "Y": ?- bagof( X, foo(Y,X), Z ). <enter> X=_, Y=1, Z = [c,b] ; <space> X=_, Y=2, Z = [a,a] ; <space> no If it is desired to get all solutions irrespective of the bindings of "Y", then " existential quantification" can be used: Si se desea obtener todas las soluciones independientemente de los valores de "Y", entonces se puede usar "la cuantificacin existencial": ?- bagof( X, Y^foo(Y,X), Z ). <enter> X=_, Y=_, Z = [c,a,b,a] Notes El predicado bagof/3 est muy relacionado con setof/3. La nica diferencia en el comportamiento es que el ltimo ordena los conjuntos retornados, removiendo las solcuiones duplicadas en el proceso. La caracterstica de "existential quantification" de bagof/3 y setof/3 a menudo causan confusin. En general, las solcuiones para ambos predicados se particionan simplmente de acuerdo con los valores de las variables que aparecen en el Objetivo pero no en el Trmino Considere el comando: ?- bagof( (X,Y), foo(X,Y,A,B), Z ). Esto podra retornar una serie de listas de (X,Y) para el predicado hipottico, foo/4, con cada lista correspondiente a una combinacin diferente de (A,B). Supngase que lo que se desea es obtener una particin de acuerdo a los valores de B, pero no de A, todo lo que se requiere es mencionar a A en el Objetivo como el operando izquierdo de una llamada a ^/2: ?- bagof( (X,Y), A^foo(X,Y,A,B), Z ). Esta vez, las series de listas de las soluciones (X,Y) sern divididas de acuerdo cin los diferentes valores de B: efectivamente, A ser ignorado durante la particin. El tomo "^" se define como un operador infijo y asociativo por la izquierda, de tal forma que se puede mencionar una serie de variables, extendiendo(profundizando) simplmente la secuencia de llamadas de a ^/2: ?- bagof( (X,Y), A^B^foo(X,Y,A,B), Z ). Note que aparte de la interpretacin especial en los predicados bagof/3 y setof/3, ^/2 no tiene ningn significado diferente al de la meta que constituye su segundo argumento; Es por esto que el comando: ?- A ^ foo(A,B). Es en todo los aspectos idntico al comando ?- call( foo(A,B) ). One remaining solution set predicate, findall/3, returns all solutions to a goal, without partitioning or sorting: in this case, use of existential quantification is meaningless.

setof/3
Retorna conjuntos ordenados de trminos en las soluciones de un objetivo dado

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS setof( Termino, Objetivo, Lista ) ?Termino <terminos> +Objetivo<objetivo> ?Lista<variable> o <lista> Este predicado retorna conjuntos ordenados de soluciones que normalmente se pueden obtener slo por falla y backtracking a travs de una consulta. Este predicado es exitoso Lista puede ser unificada a una lista de todos las instancias de Trmino tales que el Objetivo sea cierto. El Trmino puede ser cualquier termino de Prolog, y el Objetivo puede ser cualquier objetivo Prolog, con o sin llamadas al predicado cuantificador existencial, ^ / 2, que es usado para alterar la particin e las soluciones Examples Consider the database relation: foo( 1, c ). foo( 2, a ). foo( 1, b ). foo( 2, a ). La siguiente llamada retorna conjuntos de soluciones de "X" en el Objetivo "foo(Y,X)", particionado de acuerdo a los diferentes valores de "Y": ?- setof( X, foo(Y,X), Z ). <enter> X=_, Y=1, Z = [b,c] ; <space> X=_, Y=2, Z = [a] ; <space> no If it is desired to get all solutions irrespective of the bindings of "Y", then "existential quantification" can be used: ?- setof( X, Y^foo(Y,X), Z ). <enter> X=_, Y=_, Z = [a,b,c]

integer_bound/3
genera o prueba enteros entre una cota superior y una cota inferior integer_bound( Cota_Inferior, Numero, Cota_Superior ) +Cota_Inferior <entero> ?Numero <entero> o <variable> +Cota_Superior <integer> Comments When called with three integers, this predicate succeeds if the given Number is greater than or equal to the given Lower bound, and less than or equal to the given Upper bound. If both the Lower and Upper bounds are specified, but Number is an unbound variable, successive integers in the range [Lower..Upper] are bound to Number on backtracking. Cuando se llama con tres enteros, este predicado tiene xito si el Nmero es mayor o igual a Cota_Inferior, y menor o igual que la Cota_Superior. Si se especifican tanto Cota_Inferior como Cota_Superior, pero Nmero es una variable no acotada, entonces, enteros sucesivos en el rango [Cota_Inferior Cota_Superior], se unifican con el Nmero.

FUNDACIN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERA DE SISTEMAS Examples La siguiente llamada verifica simplemente que "2" es un entero en el rango [1..3]: ?- integer_bound( 1, 2, 3 ). <enter> yes La siguiente llamada muestra que este predicado puede generar soluciones sucesivas en el backtracking: ?- integer_bound( 1, X, 3 ). <enter> X = 1 ; <space> X = 2 ; <space> X=3 Notes Aunque conveniente en su modo de "prueba", integer_bound/3 es en realidad como un generador de nmeros. Debido a que Prolog no proporciona la asignacin destructiva, es difcil escribir programas que se comporten como ciclos "for", incrementando un contador y detenindolo cuando se alcanza el lmite. Una combinacin de integer_bound / 3 y backtracking permite una solucin simple a esta necesidad particular. La siguiente es una forma de escribir "para los valores de X de 0 a 9, escribir X" ?- integer_bound( 0, X, 9 ), write( X ), fail ; nl. <enter> 0123456789 X=_