Ist „Partybesuch“ Art von Problemen auflösbar in Prolog? Beispielsweise:
Klette Muldoon und Carlotta Pinkstone sagten beide, sie würden kommen, wenn Albus Dumbledore käme. Albus Dumbledore und Daisy Dodderidge sagten beide, sie würden kommen, wenn Carlotta Pinkstone käme. Albus Dumbledore, Burdock Muldoon und Carlotta Pinkstone sagten alle, sie würden kommen, wenn Elfrida Clagg käme. Carlotta Pinkstone und Daisy Dodderidge sagten beide, sie würden kommen, wenn Falco Aesalon käme. Klette Muldoon, Elfrida Clagg und Falco Aesalon sagten alle, sie würden kommen, wenn Carlotta Pinkstone und Daisy Dodderidge beide kämen. Daisy Dodderidge sagte, sie würde kommen, wenn sowohl Albus Dumbledore als auch Burdock Muldoon kämen. Wen muss man dazu überreden, an der Party teilzunehmen, um sicherzustellen, dass alle ihre Eingeladenen teilnehmen?
Ich habe versucht, dies in GNU Prolog auszudrücken:
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.*/
Ich habe einen Stapelüberlauf (kein Wortspiel) und keine Kenntnisse über die Prologauswertung. Deshalb frage ich.
Im Allgemeinen kann dieses Problem in eine boolesche CNF-Zufriedenheitsformel (mit 6 booleschen Variablen) umgewandelt werden. Hat die Prologperspektive also irgendeinen Vorteil?
quelle
attend(BM) :- attend(AD).
ist es genau dasselbe wieattend(X) :- attend(Y).
Antworten:
Um ein Problem mit Prolog zu lösen, müssen Sie wie bei jeder Programmiersprache, sei es deklarativ oder imperativ, über die Darstellung der Lösung und die Eingabe nachdenken.
Da es sich um eine Programmierfrage handelt, wäre sie auf StackOverflow.com beliebt gewesen, wo Programmierer Programmierprobleme lösen. Hier würde ich versuchen, wissenschaftlicher zu sein.
Um das Problem im OP zu lösen, muss die Beziehung umgekehrt werden, die durch die in der Eingabe angegebenen Abhängigkeiten definiert ist. Sätze der Form sind leicht umzukehren. Die Klauseln A t t e n d ( A D ) ∧ A t t e n d (A t t e n d( X) → A t t e n d( Y) ∧ A t t e n d( Z) mögenA t t e n d( A D ) ∧ A t t e n d( B M) → A t t e n d( D D )
sind schwieriger zu behandeln.
Bei Prolog besteht der erste einfache Ansatz darin, eine vollständige Umkehrung der Beziehung zu vermeiden und stattdessen zielgerichtet zu sein.
Nehmen Sie eine Reihenfolge in der Gästeliste an und verwenden Sie eine Regel
(Wir verwenden anstelle von A t t e n d ( X ) , um es kurz zu halten.)A ( X) A t t e n d( X)
Diese Regel ist einfach zu implementieren.
Ein eher naiver Ansatz
Zur besseren Lesbarkeit sei
follows
die Beziehung als Eingabe angegeben undbrings
umgekehrt.Dann ist die Eingabe durch gegeben
Und
brings
kann wie folgt definiert werden:brings/3(X,L,S)
Wenn wir definieren
Wir erhalten die folgenden einzigartigen Lösungen:
Dies ist nicht die vollständige Liste, da unter der alphabetischen Reihenfolge die Klausel
funktioniert nicht.
Eine ziemlich komplizierte Lösung für das ursprüngliche Rätsel
Um das Problem vollständig zu lösen, muss das System versuchen, die Anwesenheit späterer Gäste nachzuweisen, ohne Endlosschleifen in den Suchbaum einzufügen. Es gibt mehrere Möglichkeiten, um dieses Ziel zu erreichen. Jeder hat seine Vor- und Nachteile.
Eine Möglichkeit ist die
brings/2
folgende Neudefinition :Das letzte Argument in
brings/4
ist notwendig, um eine Endlosschleife in zu vermeidentry_bring
.Dies gibt die folgenden Antworten: Albus, Carlotta, Elfrida und Falco. Diese Lösung ist jedoch nicht die effizienteste, da das Zurückverfolgen dort eingeführt wird, wo es manchmal vermieden werden kann.
Eine allgemeine Lösung
Nun, wenn zum Beispiel Datensatz # 2 als gegeben ist
Wir erhalten die Antwort L = [[ad, bm, dd, ec]]. Das bedeutet, dass alle Gäste außer Carlotte und Falco eingeladen werden müssen.
Die Antworten, die diese Lösung mir gab, stimmten mit den im Wicked Witch-Artikel angegebenen Lösungen überein, mit Ausnahme des Datensatzes Nr. 6, in dem mehr Lösungen hergestellt wurden. Dies scheint die richtige Lösung zu sein.
Abschließend muss ich die CLP (FD) -Bibliothek von Prolog erwähnen, die für diese Art von Problemen besonders geeignet ist.
quelle
Wie von svick entdeckt, ist das erste Problem mit dem Code im OP, dass Namen, die mit Großbuchstaben beginnen, Variablen in Prolog sind. Also
admit(CP) :- admit(AD)
ist äquivalent zuattend(X) :- attend(Y)
, was dazu führt, dass Prolog sofort in eine Endlosschleife eintritt, um zu demonstrieren, dassattend
für einen Begriff gilt, indem ein Begriff gefunden wird, für denattend
gilt.Wenn Sie jedoch jeden Satz von Initialen als einen konkreten unterschiedlichen Begriff verstanden haben, stoßen Sie immer noch auf einen Stapelüberlauf, weil Sie Zyklen haben, z
Um herauszufinden, ob
attend(cp)
Holds vorhanden sind, versucht Prolog herauszufinden, ob Holds vorhanden sind.attend(ad)
Überprüfen Sie, obattend(cp)
Holds vorhanden sind, und so weiter, bis der Stack überläuft.Ich glaube nicht, dass Vanille Prolog einen Versuch unternimmt, festzustellen, ob es einen solchen Zyklus gibt, und andere Wege untersucht, um einen von
attend(cp)
oderattend(ad)
wahr zu machen , anstatt in einer Endlosschleife zu stecken.Möglicherweise gibt es Versionen von Prolog, die eine solche Funktion unterstützen. Mercury ist mir vertrauter und ich denke, Mercurys "Minimal Model Tabling" ist genau das, was Sie für diesen Fall benötigen. Ich habe es eigentlich nie benutzt, aber meines Wissens lässt es mehr oder weniger zu, dass ein Begriff, der sich als wahr erweist, wenn es eine andere Möglichkeit gibt, es zu beweisen, oder falsch, ohne in eine Endlosschleife geraten zu müssen. Lesen Sie den entsprechenden Abschnitt in den Mercury-Dokumenten und bei Interesse ein Dokument, in dem die Implementierung beschrieben wird.
Mercury ist eine reinste logische Programmiersprache mit einer ähnlichen Syntax wie Prolog, aber starken Typ- und Modus-Systemen. Sie wird kompiliert und nicht interpretiert.
Ich habe gerade die Einleitung zu dem Artikel überflogen (die ich seit einiger Zeit nicht mehr gelesen habe), und es wird erwähnt, dass das Tabling in mehreren Versionen von Prologs implementiert wurde. Es kann also sein, dass Sie durch Googeln zum Tabling weiter kommen in Prolog.
quelle
Ich habe das folgende Papier über SAT-Lösungen mit Prolog gefunden:
Eine Implementierung des Lösers finden Sie hier .
In dieser Stackoverflow-Antwort finden Sie Details zum Code und dessen Verwendung.
quelle
Abgesehen von Klein- und Großbuchstaben gibt es einen Zyklus in den Abschnitten:
Wenn Sie also einen Top-Down-Interpreter aufrufen, wird eine Schleife ausgeführt. Möglicherweise haben Sie mehr Glück mit der Antwortsatzprogrammierung ( Answer Set Programming, ASP), die von unten nach oben funktioniert. Hier ist eine Codierung per Bibliothek ( minimal / asp ):
Hier ist ein Beispiellauf:
quelle