200 likes | 430 Views
LENGUAJES LOGICOS. IMPLEMENTACION CALCULO DE PREDICADOS PROLOG. Intérpretes/Compiladores de Lenguajes Lógicos (PROLOG). Las diferencias de implementación de un lenguaje lógico son provocadas por El manejo del desconocido necesario para la implementación de la unificación.
E N D
LENGUAJES LOGICOS IMPLEMENTACION CALCULO DE PREDICADOS PROLOG
Intérpretes/Compiladores de Lenguajes Lógicos (PROLOG) • Las diferencias de implementación de un lenguaje lógico son provocadas por • El manejo del desconocido necesario para la implementación de la unificación. • El no determinismo y su implementación mediante vuelta atrás (backtracking). • Actualmente las implemetaciones de compiladores de PROLOG se basan en la máquina de Warren o variantes. • Ejemplo de no determinismo member(X,[X|L]). member(X,[_|L]):-member(X,L). member(Y,[1,2,3,4,5])? Y=1,2,3,4,5
La Máquina de Warren TR: cabeza del trail E: ámbito activo B: punto de elección activo B0: H:Final del Heap HB:Final del Heap de la última bifurcación no determinista S: ayuda a la unificación P: contador de programa CP: continuación PDL TR Trail Ambito Pila E Punto de elección B B0 H Heap HB S Area de código CP P
Máquina de Warren (II) • La máquina tiene un conjunto de registros Xn (variables globales para uso temporal • Yn son las variables que se guardan en el ámbito • An son los argumentos que se guardan al final de la pila. • Heap • <ref,dirección> Es una referencia a donde se encuentra el valor • <str,dirección> es un apuntador a un nodo • functor/n: es la cabecera de un functor con n argumentos. Ej. p(a,b) : p/2 • átomo/0: es un átomo o functor con cero argumentos. • predicado/n: especifica un predicado con n argumentos
Representación de los Functors 11 10 9 8 7 6 5 4 3 2 1 0 <STR,5> • Representar el functor: p(Z,h(Z,W),f(W)). • Instrucciones de creación put_structure f/n,Xi Heap[H]=<STR,H+1> Heap[H+1]=f/n Xi=Heap[H] H=H+2 set_variable Xi Heap[H]=<REF,H> Xi=Heap[H] H=H+1 set_value Xi Heap[H]=Xi H=H+1 <STR,1> <REF,2> p/3 <STR,8> <REF,3> f/1 <STR,5> <REF,3> <REF,2> h/2 <STR,1>
Celdas en el Heap • Celda variable • <REF, k> k es la dirección donde se guarda el “valor” • Celda estructura • <STR, k> k es la dirección donde se guarda el functor (nodo) • Celda functor • nombre/n nombre del functor y número de elementos • Los elementos le siguen inmediatamente • Celda átomo • nombre/0 nombre del atomo y número de elementos 0 • Desconocido • <REF, k> k es la dirección de el mismo
Código de creación de Functores 11 10 9 8 7 6 5 4 3 2 1 0 <STR,5> • Crear el functor: p(Z,h(Z,W),f(W)). • Código put_structure h/2,X3 set_variable X2 set_variable X5 put_structure f/1,X4 set_value X5 put_structure p/3,X1 set_value X2 set_value X3 set_value X4 • Asignación de los registros X1=p(X2,X3,X4) X2=Z X3=h(X2,X5) X4=f(X5) X5=W <STR,1> <REF,2> p/3 <STR,8> <REF,3> f/1 <STR,5> <REF,3> <REF,2> h/2 <STR,1>
Instrucciones de Unificación (I) get_structure f/n,Xi addr=deref(Xi) switch (STORE[addr]) { case <REF,_>: HEAP[H]=<STR,H+1> HEAP[H+1]=f/n; bind(addr,H) H=H+2; mode=WRITE; break; case <STR,a>: if (HEAP[a]=f/n) { S=a+1; mode=READ; } else fail=True; break; default: fail=true } unify_variable Xi unify_value Xi
Instrucciones de Unificación (II) unify_variable Xi switch (mode) { case READ: Xi=HEAP[S]; break; case WRITE: HEAP[H]=<REF,H>; Xi=HEAP[H] H=H+1; break; } S=S+1; unify_value Xi switch (mode) { case READ: unify(Xi,S); break; case WRITE: HEAP[H]=Xi; H=H+1; } S=S+1;
Unificación void unify(a1,a2) { push(a1,PDL);push(a2,PDL); fail=false; while (!empty(PDL) && !fail) { d1=deref(pop(PDL)); d2=deref(pop(PDL)); if (d1!=d2) { <t1,v1>=STORE[d1];<t2,v2>=STORE[d2]; if (t1==REF || t2==REF) bind(d1,d2) else { f1/n1=STORE[v1];f2/n2=STORE[v2]; if (f1==f2 && n1==n2) { for (i=1;i<=n1;++i) { push(v1+i,PDL); push(v2+i,PDL); } } else fail=true; } } } }
Código de Unificación Functores • Unificar el functor: p(Z,h(Z,W),f(W)). • Código get_structure p/3,X1 unify_variable X2 unify_variable X3 unify_variable X4 get_structure h/2,X3 unify_value X2 unify_variable X5 get_structure f/1,X4 unify_value X5 • Asignación de los registros X1=p(X2,X3,X4) Valor a unificar con p(…) X2=Z X3=h(X2,X5) X4=f(X5) X5=W
Instrucciones de Llamada a un Predicado • put_variable Xn,Ai Heap[H]=<Ref,H> Xn=Heap[H] Ai=Heap[H] H=H+1 • put_value Xn,Ai Ai=Xn • get_value Xn,Ai unify(Xn,Ai) • put_structure f/n,Ai Heap[H]=f/n Ai=<STR,H> H=H+1 • Call p/n CP=P+instruction_size(P) P=@(p/n) (dirección del código del predicado p con n argumentos) • Proceed P=CP
Llamada a un Predicado • Fuente: p(Z,h(Z,W),f(W))? • Código put_variable X4,A1 put_structure h/2,A2 set_value X4 set_variable X5 put_structure f/1,A3 set_value X5 call p/3 • Argumentos A1=Z A2=h(Z,W) A3=f(W)
Código de un Predicado • Hecho: p(f(X),h(Y,f(a)),Y). • Código: get_structure f/1,A1 unify_variable X4 get_structure h/2,A2 unify_variable X5 unify_variable X6 get_value X5,A3 get_structure f/1,X6 unify_variable X7 get_structure a/0,X7 proceed • Argumentos A1=f(X) A2=h(Y,f(a)) A3=Y
Código de una Regla • P0(…):-p1(…),…,pn(…). • Estructura del código allocate N leer argumentos de p0 poner los argumentos de p1 call p1 … poner los argumentos de pn call pn deallocate • Al llamar a otros predicados se pierden los valores de Xi y para solucionarlo se guardan los valores en los registros permanentes Yi • allocate N reserva N registros Yi • deallocate los “libera”
Ámbito • Lo crea la instrucción allocate y lo destruye deallocate • Contiene las variables necesarias para ejecutar una regla. • Allocate if (E>B) newE=E+STACK[E+2 ] +3 else newE=B+STACK[B] +7 STACK[newE]=E; STACK[newE+1]=CP; STACK[newE+2]=N; E=newE; P=P+instruction_size(P); • deallocate P=STACK[E+1]; E=STACK[E]; Yn ... Y2 Y1 n (número de variables permanentes) CP (apuntador a la continuación) E CE (ámbito de continuación)
Código de una Regla • P(X,Y):-q(X,Z),r(Z,Y). P/2: allocate 2 get_variable X3, A1 get_variable Y1, A2 put_value X3, A1 put_variable Y2, A2 call q/2 put_value Y2, A1 put_value Y1, A2 call r/2 deallocate
Implementación de las Bifurcaciones no Deterministas • La implementación del no determinismo se base en las instrucciones: • try_me_elsesiguiente regla • Crea un bloque de activación de un punto de elección. • En caso que se produzca un fallo transfiere la ejecución a la regla siguiente. • retry_me_elsesiguiente regla • Se ejecuta después de una vuelta atrás. • Deshace las instanciaciones y cambios de estado producidos después de ejecutar try_me_else o retry_me_else • En caso que se produzca un fallo transfiere la ejecución a la regla siguiente • trust_me • Se ejecuta después de una vuelta atrás. • Deshace las instanciaciones y cambios de estado producidos después de ejecutar try_me_else o retry_me_else • Elimina el bloque de activación de un punto de elección.
Ejemplo de Bifurcación no Determinista • Fuente p(X,a). p(b,X). p(X,Y):-p(X,a),p(b,Y). • Código try_me_else L1 get_variable X3,A1 get_structure a/0,A2 proceed L1: retry_me_else L2 get_structure b/0,A1 get_variable X3,A2 proceed L2: trust_me allocate 1 get_variable X3,A1 put_value Y1,A1 put_structure a/0,A2 call p/2 deallocate
Punto de Elección • Lo crea la instrucción try_me_else y lo destruye trust_me • Contiene los registros de la máquina para poder recuperar el estado en caso de vuelta atrás. H (apuntador al heap) TR (apuntador al camino) BP (siguiente regla) B (anterior punto de elección) CP (apuntador a la continuación) CE (ámbito de continuación) An … A2 A1 B n (número de argumentos)