¿Se pueden resolver los problemas de "asistencia a la fiesta" en Prolog? Por ejemplo:
Burdock Muldoon y Carlotta Pinkstone dijeron que vendrían si venía Albus Dumbledore. Albus Dumbledore y Daisy Dodderidge dijeron que vendrían si viniera Carlotta Pinkstone. Albus Dumbledore, Burdock Muldoon y Carlotta Pinkstone dijeron que vendrían si venía Elfrida Clagg. Carlotta Pinkstone y Daisy Dodderidge dijeron que vendrían si venía Falco Aesalon. Burdock Muldoon, Elfrida Clagg y Falco Aesalon dijeron que vendrían si Carlotta Pinkstone y Daisy Dodderidge vinieran. Daisy Dodderidge dijo que vendría si Albus Dumbledore y Burdock Muldoon vinieran. ¿A quién se debe convencer para que asista a la fiesta para asegurarse de que asistan todos sus invitados?
He tratado de expresar esto en GNU Prolog:
attend(BM) :- attend(AD).
attend(CP) :- attend(AD).
attend(AD) :- attend(CP).
attend(DD) :- attend(CP).
attend(AD) :- attend(EC).
attend(BM) :- attend(EC).
attend(CP) :- attend(EC).
attend(CP) :- attend(FA).
attend(DD) :- attend(FA).
attend(BM) :- attend(CP),attend(DD).
attend(EC) :- attend(CP),attend(DD).
attend(FA) :- attend(CP),attend(DD).
attend(DD) :- attend(AD),attend(BM).
attend(FA). /* try different seed invitees in order to see if all would attend*/
/* input:
write('invited:'),nl,
attend(X),write(X),nl,
fail.*/
Estoy experimentando un desbordamiento de pila (sin juego de palabras) y no tengo conocimiento de la evaluación del prólogo, es por eso que pregunto.
En términos generales, este problema se puede incluir en la fórmula de satisfacción del CNF booleano (con 6 variables booleanas). Por lo tanto, ¿la perspectiva del prólogo tiene algún mérito?
fuente
attend(BM) :- attend(AD).
es exactamente lo mismo queattend(X) :- attend(Y).
Respuestas:
Para resolver un problema con Prolog, como con cualquier lenguaje de programación, ya sea declarativo o imperativo, debe pensar en la representación de la solución y la entrada.
Como se trata de una pregunta de programación, habría sido popular en StackOverflow.com, donde los programadores resuelven problemas de programación. Aquí intentaría ser más científico.
Para resolver el problema en el OP uno tiene que revertir la relación definida por las dependencias establecidas en la entrada. Las cláusulas de la forma son fáciles de revertir. Las cláusulas A t t e n d ( A D ) ∧ A t t e n d (Attend(X)→Attend(Y)∧Attend(Z) comoA t t e n d( A D ) ∧ A t t e n d( B M) → A t t e n d( D D )
son más difíciles de tratar
Con Prolog, el primer enfoque simple es evitar una inversión completa de la relación y, en su lugar, ser dirigido a un objetivo.
Asuma un pedido en la lista de invitados y use una regla
(Usamos lugar de A t t e n d ( X ) para mantenerlo corto)A ( X) A t t e n d( X)
Esta regla es fácil de implementar.
Un enfoque bastante ingenuo
Para
follows
facilitar la lectura, sea la relación dada como entrada, ybrings
sea su reverso.Entonces la entrada está dada por
Y
brings
se puede definir de la siguiente manera:brings/3(X,L,S)
Si definimos
Obtenemos las siguientes soluciones únicas:
Esta no es la lista completa, ya que bajo el orden alfabético de la cláusula
no está trabajando.
Una solución bastante complicada para el rompecabezas original.
Para resolver el problema por completo, debe dejar que el sistema intente probar la asistencia para invitados posteriores sin introducir bucles infinitos en el árbol de búsqueda. Hay múltiples formas de lograr este objetivo. Cada uno tiene sus ventajas y desventajas.
Una forma es redefinir de la
brings/2
siguiente manera:El último argumento
brings/4
es necesario para evitar un bucle infinitotry_bring
.Esto da las siguientes respuestas: Albus, Carlotta, Elfrida y Falco. Sin embargo, esta solución no es la más eficiente ya que se introduce el retroceso donde a veces se puede evitar.
Una solución general
Ahora si, por ejemplo, el conjunto de datos # 2 se da como
Obtenemos la respuesta L = [[ad, bm, dd, ec]]. Lo que significa que todos los invitados excepto Carlotte y Falco deben ser invitados.
Las respuestas que me dio esta solución coincidieron con las soluciones dadas en el artículo de Wicked Witch con la excepción del conjunto de datos # 6, donde se produjeron más soluciones. Esta parece ser la solución correcta.
Finalmente, debo mencionar la biblioteca CLP (FD) de Prolog que es particularmente adecuada para este tipo de problemas.
fuente
Como lo detectó svick, el primer problema con el código en el OP es que los nombres que comienzan con letras mayúsculas son variables en Prolog. Por
admit(CP) :- admit(AD)
lo tanto, es equivalente aattend(X) :- attend(Y)
, lo que resulta en que Prolog ingrese inmediatamente a un ciclo infinito tratando de demostrar que seattend
cumple para algún término al encontrar algún término para el cual seattend
mantiene.Sin embargo, si quisiste decir que cada conjunto de iniciales es un término distinto concreto, entonces todavía te encontrarás con un desbordamiento de pila porque tienes ciclos, por ejemplo
Por lo tanto
attend(cp)
, para determinar si lasattend(ad)
retenciones, Prolog tratará de determinar si retenciones, lo que hará mediante la verificación de lasattend(cp)
retenciones, y así sucesivamente hasta que se desborde la pila.No creo que Vanilla Prolog haga ningún intento de determinar si existe tal ciclo, y examinar otras formas de hacer que uno
attend(cp)
seaattend(ad)
verdadero o no en lugar de quedarse atrapado en un bucle infinito.Puede haber o no versiones de Prolog que admitan dicha función. Estoy más familiarizado con Mercury, y creo que la "tabla mínima de modelos" de Mercury es exactamente lo que necesita para este caso. En realidad, nunca lo he usado, pero entiendo que más o menos permite que un término que implique se considere verdadero si hay alguna otra forma de probarlo, o falso de lo contrario, sin quedar atrapado en un bucle infinito. Consulte la sección correspondiente de los documentos de Mercury y, si le interesa, un documento que describa la implementación.
Mercury es un lenguaje de programación lógico de pureza forzada, con una sintaxis similar a Prolog pero con sistemas de tipo y modo fuertes, y se compila en lugar de interpretarse.
Acabo de volver a leer la introducción al documento (que no he leído en mucho tiempo), y menciona que la tabulación se ha implementado en varias versiones de Prologs, por lo que es posible que pueda avanzar más buscando en Google para la presentación. en Prolog.
fuente
Encontré el siguiente documento sobre la resolución de SAT usando prolog:
Una implementación del solucionador se puede encontrar aquí .
Consulte esta respuesta de stackoverflow para obtener detalles sobre el código y cómo usarlo.
fuente
Dejando a un lado el tema en minúsculas / mayúsculas, hay un ciclo en las cláusulas:
Entonces, cuando llame a un intérprete de arriba hacia abajo, se repetirá. Es posible que tenga más suerte con la Programación de conjunto de respuestas (ASP), que funciona de abajo hacia arriba. Aquí hay una codificación a través de la biblioteca ( mínimo / asp ):
Aquí hay un ejemplo de ejecución:
fuente