Claúsulas de Horn. Resolución SLD 1 / 114 Refinando la resolución La resolución general es un mecanismo muy potente de demostración... pero tiene un alto grado de indeterminismo: en la selección de las cláusulas con las que hacer resolución y en la selección de los literales a utilizar en la resolución Desde el punto de vista computacional es muy ineficiente. Desde el punto de vista práctico puede sacrificarse algo de expresividad y obtener un mecanismo más eficiente que sustente un lenguaje de programación más “realista”: restringimos la forma de las cláusulas de modo que a lo sumo tengan un literal positivo. En notación de Kowalski esto quiere decir que a lo sumo tienen un átomo en el lado izquierdo de ← estudiaremos un método de resolución especı́fico para este tipo de cláusulas. 2 / 114 Cláusulas de Horn Una cláusula de Horn es una secuencia de literales que contiene a lo sumo un literal positivo. Al escribirla en notación de Kowalski tendrá una de estas cuatro formas: 1 2 Hecho: p ← Regla: p ← q1 , . . . , qn |{z} | {z } cabeza 3 4 cuerpo Objetivo: ← q1 , . . . , qn Éxito: ← Los hechos y las reglas se denominan cláusulas definidas: los hechos representan “hechos acerca de los objetos” (de nuestro universo de discurso), relaciones elementales entre estos objetos las reglas expresan relaciones condicionales entre los objetos, dependencias. 3 / 114 Cláusulas de Horn (cont.) Las reglas engloban todos los casos en el siguiente sentido: un hecho es una regla con cuerpo vacı́o un objetivo es una regla con cabeza vacı́a y el éxito es una regla con cabeza y cuerpo vacı́os Nótese que en las cláusulas de Horn trabajamos con secuencias de literales en vez de conjuntos (como venı́amos haciendo con las cláusulas generales). Esto implica dos cosas: los literales pueden aparecer repetidos en el cuerpo hay un orden en los literales del cuerpo (podemos hablar del primer literal, segundo literal, etc). 4 / 114 Predicados y programas lógicos Un predicado p queda definido por el conjunto de claúsulas (hechos y reglas) cuyas cabezas tienen ese sı́mbolo de predicado. Ası́ pues la definición de un predicado en general tendrá el aspecto: p(t1 , . . . , tn ) p(s1 , . . . , sn ) ... p(u1 , . . . , un ) p(u1 , . . . , un ) ... ← ← ← q1 (. . .), . . . , qm (. . .) ← r1 (. . .), . . . , rk (. . .) (puede haber solo hechos, solo reglas o ambos tipos). Un programa lógico es un conjunto de definiciones de predicados (es decir, un conjunto de claúsulas definidas: hechos y reglas). 5 / 114 Un ejemplo Representación de un grafo mediante hechos: a b c d arco(a, b) ← arco(a, c) ← arco(b, d) ← arco(c, d) ← arco(c, e) ← arco(d, e) ← e 6 / 114 Ejemplo (cont.) La relación de conexión entre nodos (caminos) puede expresarse mediante reglas: camino(X , Y ) ← X = Y camino(X , Y ) ← arco(X , Z ), camino(Z , Y ) (la primera regla, también se podrı́a haber escrito como un hecho: camino(X , X ) ← ) La lectura de estas dos resglas es: hay un camino de un nodo a otro, si son el mismo hay un camino de un nodo X a otro Y si existe un nodo Z tal que hay arco entre X y Z , y hay camino entre Z e Y 7 / 114 Ejemplo (cont.) Ahora, se podrı́a plantear un objetivo, i.e., entendiendo los hechos y las reglas que hemos escrito como premisas podrı́amos plantear una conclusión y tratar de mostrar la validez de la argumentación. Por ejemplo, podemos plantear los objetivos (o preguntas): ← arco(b, d) ← camino(a, d) ← camino(a, X ) ← camino(e, Y ) ← camino(X , Y ) ← camino(X , b), camino(X , d) los dos primeros son objetivos cerrados porque no contienen variables, mientras que los restantes son objetivos abiertos. ... ¿qué deberı́amos obtener (por resolución) en cada caso? 8 / 114 Variables lógicas en las cláusulas Todas las variables lógicas en de una claúsula están cuantificadas universalmente de forma implı́cita. Por ejemplo, en la claúsula: camino(X , Y ) ← arco(X , Z ), camino(Z , Y ) implı́citamente tenemos: ∀X .∀Y .∀Z .(camino(X , Y ) ← arco(X , Z ), camino(Z , Y )) Ahora bien, esta sentencia es lógicamente equivalente a: ∀X .∀Y .(camino(X , Y ) ← ∃Z .(arco(X , Z ), camino(Z , Y ))) Es decir, las variables que sólo aparecen a la derecha de la claúsula están localmente afectadas de una cuantificación existencial. Se dice que son variables existenciales o extra o locales. Interpretarlas existencialemente facilita la lectura de la cláusula: Para todo X y todo Y , hay un camino entre X e Y si existe Z tal que hay arco de X a Z y hay camino entre Z e Y 9 / 114 Otro ejemplo Podemos definir la suma de naturales (representados como c y s) mediante un hecho y una regla: suma(c, X , X ) ← suma(s(X ), Y , s(Z )) ← suma(X , Y , Z ) y plantear distintos objetivos: ← suma(s(c), s(s(c)), s(s(s(c)))) ← suma(X , s(c), s(s(c))) ← suma(s(c), Y , Z ) ← suma(X , Y , Z ) ← suma(X , X , Z ), suma(Z , Z , H) 10 / 114 SLD-Resolución Selection-rule driven Linear resolution for Definite clauses Es un caso particular de la resolución general, donde: Los resolventes son siempre objetivos (cláusulas sin cabeza). Los programas son conjuntos de claúsulas (de Horn) definidas, i.e., hechos y reglas. Hay una función de selección que selecciona un átomo del resolvente a quien aplicar resolución. 11 / 114 SLD-resolución (cont.) Formalmente: Sea un programa lógico P, un par de objetivos G y G 0 , y una función de selección fs . Una derivación de G a G 0 con SLD-resolución (P ∪ {G } `SLD G 0 ) es una secuencia de objetivos G0 , G1 , . . . , Gk tal que: G0 = G Gk = G 0 para todo i ∈ {0, ..., k − 1}, Gi+1 de obtiene a partir de Gi “resolviendo” (en el sentido de la resolución general) el literal L = fs (Gi ) con una variante de una regla de P. Si G 0 ≡←, entonces tenemos una SLD-refutación de G a partir de P. 12 / 114 Ejemplo Supongamos el programa (c representa cero y s sucesor): suma(c, Y , Y ) ← suma(s(X ), Y , s(Z )) ← suma(X , Y , Z ) y el objetivo ← suma(s(c), s(c), s(s(c))) (asumimos que fs selecciona el primer objetivo por la izquierda). ← suma(s(c), s(c), s(s(c))) suma(s(X1 ), Y1 , s(Z1 )) ← suma(X1 , Y1 , Z1 ) θ1 = [X1 /c, Y1 /s(c), Z1 /s(c)] ← suma(c, s(c), s(c)) suma(c, Y2 , Y2 ) ← θ2 = [Y2 /s(c)] ← 13 / 114 Respuestas correctas Dado un programa P y un objetivo G ≡← q1 , . . . , qn , diremos que una sustitución θ es una respuesta correcta para P ∪ {G } si θ únicamente actúa sobre las variables de G y P |= ∀X1 . . . . .∀Xm (q1 ∧ . . . ∧ qn )θ, siendo {X1 , . . . , Xn } el conjunto de variables de G (notación: P |= [(q1 ∧ . . . ∧ qn )θ]∀ ) Por ejemplo, consideremos la siguiente refutación: G ≡← suma(c, s(A), B) suma(c, Y1 , Y1 ) ← θ1 = [Y1 /s(A), B/s(A)] ← La sustitución obtenida, θ1 , restringida a las variables del objetivo original G es θ1 |var (G ) = [B/s(A)] (la variable Y1 no aparece en en G ). θ = [B/s(A)] es una respuesta correcta para G ... por qué? 14 / 114 Respuestas correctas (cont.) θ = [B/s(A)] es una respuesta correcta para P ∪ {G }: por un lado, aplicando θ tenemos suma(c, s(A), s(A)) y ahora, si consideramos cualquier otra sustitución σ tendremos que P |= suma(c, s(A), s(A))σ o lo que es lo mismo (ver pag. 27): P |= ∀A.suma(c, s(A), s(A)) P |= [suma(c, s(A), s(A))]∀ Intuitivamente, si reemplazamos A por cualquier valor lo que obtenemos pertenecerá al modelo de la primera claúsula de P y por tanto al modelo de P (recordemos que en la página 53 estudiamos un modelo de Herbrand para este programa en el que sumaH = {(s m (c), s n (c), s k (c)) | m + n = k} 15 / 114 Corección y completitud de la SLD-resolución Teorema Sea P un programa, fs una función de selección y G un objetivo. Tenemos: Corrección: Si P ∪ {G } `SLD ← en n pasos y θ = θ1 . . . θn es la composición de la secuencia de unificadores usados en la SLD-refutación, entonces: θ0 = θ |var (G ) es una respuesta correcta para P ∪ {G } Completitud: Sea θ una respuesta correcta para P ∪ {G }, entonces existe una SLD-refutación de G a partir de P con una secuencia de unificadores θ1 , . . . , θn tal que θ = (θ1 . . . θn ) |var (G ) . Nótese que la función de selección concreta que se utilice no es relevante para los resultados de corrección y completitud. 16 / 114 Ejemplo Consideremos el programa de los caminos en un grafo: arco(a, b) ← arco(a, c) ← arco(b, d) ← arco(c, d) ← arco(c, e) ← arco(d, e) ← camino(X , X ) ← camino(X , Y ) ← arco(X , Z ), camino(Z , Y ) Y consideremos el objetivo ← camino(X , e) 17 / 114 Ejemplo (cont.) Una posible refutación (tomando como función de selección la que toma el primer literal por la izquierda): ← camino(X , e) camino(X1 , Y1 ) ← arco(X1 , Z1 ), camino(Z1 , Y1 ) θ1 = [X1 /X , Y1 /e] ← arco(X , Z1 ), camino(Z1 , e) arco(a, c) ← θ2 = [X /a, Z1 /c] ← camino(c, e) 18 / 114 Ejemplo (cont.) ← camino(c, e) camino(X3 , Y3 ) ← arco(X3 , Z3 ), camino(Z3 , Y3 ) θ3 = [X3 /c, Y3 /e] arco(c, e) ← arco(c, Z3 ), camino(Z3 , e) θ4 = [Z3 /e] ← camino(X4 , X4 ) ← camino(e, e) θ5 = [X4 /e] ← 19 / 114 Ejemplo (cont.) La composición de sustituciones obtenidas es: θ = θ1 . . . θ5 = [X /a, X1 /a, Y1 /e, Z1 /c, X3 /c, Y3 /e, Z3 /e, X4 /e] Si consideramos la restricción a las variables del objetivo original, es decir, a X tenemos: θ0 = θ |{X } = [X /a] Por el teorema de corrección θ0 = [X /a] es una respuesta correcta para el objetivo original. Por el teorema de completitud, este mecanismo debe ser capaz de encontrar además otras respuestas. Intuitivamente es fácil ver que serán [X /b], [X /c], [X /d], [X /e]... cómo se construirı́an las SLD-refutaciones para encontrar estas respuestas? 20 / 114 Hacia Prolog La resolución SLD está mucho más próxima a una implementación realista de la programación lógica porque ha acotado notablemente el indeterminismo con respecto a la resolucion general. Las claúsulas de Horn son lo suficientemente expresivas para utilizarlas como lenguaje de programación. Quedan dos cuestiones por resolver: ¿Qué función de selección utilizamos? (esto, según hemos visto no afecta a la corrección y la completitud). ¿Qué criterio seguimos para seleccionar una de las reglas aplicables para resolver un objetivo? (esto, está relacionado con la completitud). En el último ejemplo, utilizando uno u otro criterio se obtienen distintas respuestas. 21 / 114