LENGUAJES LOGICOS IMPLEMENTACION CALCULO DE PREDICADOS PROLOG

Download Report

Transcript LENGUAJES LOGICOS IMPLEMENTACION CALCULO DE PREDICADOS PROLOG

LENGUAJES LOGICOS
IMPLEMENTACION
CALCULO DE PREDICADOS
PROLOG
1
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
2
La Máquina de Warren
TR: cabeza del trail
E: ámbito activo
B: punto de elección activo
B0:
TR
PDL
Trail
H:Final del Heap
HB:Final del Heap de la última
bifurcación no determinista E
S: ayuda a la unificación
B
B0
P: contador de programa
CP: continuación
Ambito
Punto de elección
Pila
H
HB
S
Heap
CP
P
Area
de código
3
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
4
Representación de los Functors
11 <STR,5>
• Representar el functor: 10
9
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
8
7
6
5
4
3
2
1
0
<STR,1>
<REF,2>
p/3
<STR,8>
<REF,3>
f/1
<STR,5>
<REF,3>
<REF,2>
h/2
<STR,1>
set_variable Xi
Heap[H]=<REF,H>
Xi=Heap[H]
H=H+1
set_value Xi
Heap[H]=Xi
H=H+1
5
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
6
Código de creación de Functores
• 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
11
10
9
8
7
6
5
4
3
2
1
0
<STR,5>
<STR,1>
<REF,2>
p/3
<STR,8>
<REF,3>
f/1
<STR,5>
<REF,3>
<REF,2>
h/2
<STR,1>
• Asignación de los registros
X1=p(X2,X3,X4)
X2=Z
X3=h(X2,X5)
X4=f(X5)
X5=W
7
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
8
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;
9
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;
}
}
}
}
10
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
11
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
12
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)
13
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
14
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”
15
Ámbito
• Lo crea la instrucción allocate y lo
destruye deallocate
• Contiene las variables necesarias para
ejecutar una regla.
E
Yn
...
Y2
Y1
n (número de variables permanentes)
CP (apuntador a la continuación)
CE (ámbito de continuación)
• 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];
16
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
17
Implementación de las Bifurcaciones no
Deterministas
• La implementación del no determinismo se
base en las instrucciones:
– try_me_else siguiente 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_else siguiente 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.
18
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
19
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.
B
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
n (número de argumentos)
20