Burdock Muldoon and Carlotta Pinkstone both said they would come if Albus Dumbledore came. Albus Dumbledore and Daisy Dodderidge both said they would come if Carlotta Pinkstone came. Albus Dumbledore, Burdock Muldoon, and Carlotta Pinkstone all said they would come if Elfrida Clagg came. Carlotta Pinkstone and Daisy Dodderidge both said they would come if Falco Aesalon came. Burdock Muldoon, Elfrida Clagg, and Falco Aesalon all said they would come if Carlotta Pinkstone and Daisy Dodderidge both came. Daisy Dodderidge said she would come if Albus Dumbledore and Burdock Muldoon both came. Whom is needs to be persuaded to attend the party in order to ensure that all her invitees attend?
I have tried to express this in 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.*/
I’m experiencing stack overflow (no pun), and have no knowledge of prolog evaluation, this is why I’m asking. Generally speaking, this problem can be cast into Boolean CNF satisfaction formula (with 6 boolean variables). Therefore, does the prolog perspective have any merit?
Asked By : Tegiri Nenashi
Answered By : Dmitri Chubarov
Daisy Dodderidge said she would come if Albus Dumbledore and Burdock Muldoon both came
are more difficult to treat. With Prolog the first simple approach is to avoid a full reversal of the relationship and be goal directed instead. Assume an ordering on the list of guests and use a rule $qquad left{begin{align} A(X)wedge A(Y) &to A(Z), A(W)&to A(X), A(W)&to A(Y), X&<Z, Y&<Zend{align}right}quad vdash quad A(W) to A(Z)$ (We use $A(X)$ instead of $Attend(X)$ to keep it short) This rule is easy to implement. A rather naive approach For readability let follows be the relation given as an input, and brings be its reverse. Then the input is given by
follows(bm,[ad]). follows(cp,[ad]). follows(ad,[cp]). follows(dd,[cp]). follows(ad,[ec]). follows(bm,[ec]). follows(cp,[ec]). follows(cp,[fa]). follows(dd,[fa]). follows(bm,[cp,dd]). follows(ec,[cp,dd]). follows(fa,[cp,dd]). follows(dd,[ad,bm]).
And brings can be defined as follows:
brings(X,S):-brings(X,S,[]). brings(_X,[],_S). brings(X,[X|L],S):-brings(X,L,[X|S]). brings(X,[Y|L],S):-follows(Y,[X]),brings(X,L,[Y|S]). brings(X,[Y|L],S):-follows(Y,[A,B]), member(A,S),member(B,S),brings(X,L,[Y|S]).
Here the third argument in brings/3(X,L,S) is the list of guests that were already proven to attend if $X$ attends. If we define
partymaker(X):-Guests=[ad,bm,cp,dd,ec,fa],member(X,Guests),brings(X,Guests).
We get the following unique solutions:
[ad,ec]
This is not the complete list, since under the alphabetical ordering the clause
follows(bm,[cp,dd]).
is not working. A rather involved solution to the original puzzle To solve the problem completely you have to actually let the system try to prove attendance for later guests without introducing infinite loops to the search tree. There are multiple ways to accomplish this goal. Each has its advantages and disadvantages. One way is to redefine brings/2 as follows:
brings(X,S):-brings(X,S,[],[]). % brings(X,RemainsToBring,AlreadyTaken,AlreadyTried). % % Problem solved brings(_X,[],_S,_N). % Self brings(X,[X|L],S,N):-brings(X,L,[X|S],N). % Follower brings(X,[Y|L],S,N):-follows(Y,[X]),brings(X,L,[Y|S],N). % Y is not a follower, but X can bring 2 brings(X,[Y|L],S,N):- +member(Y,N),+follows(Y,[X]), follows(Y,[A,B]), try_bring(X,A,L,S,[Y|N]), try_bring(X,B,L,S,[Y|N]),brings(X,L,[Y|S],N). % Y is not a follower, but X can bring 1 brings(X,[Y|L],S,N):- +member(Y,N),+follows(Y,[X]),+follows(Y,[_A,_B]), follows(Y,[C]), try_bring(X,C,L,S,[Y|N]),brings(X,L,[Y|S],N). try_bring(_X,A,_L,S,_N):-member(A,S). try_bring(X,A,L,S,N):- +member(A,S),sort([A|L],Y),brings(X,Y,S,N).
The last argument in brings/4 is necessary to avoid an infinite loop in try_bring. This gives the following answers: Albus, Carlotta, Elfrida and Falco. However this solution is not the most efficient one since backtracking is introduced where it sometimes can be avoided. A general solution After the link to the Third International NoCOUG SQL & NoSQL Challenge was added to the original question, it became clear that what we are after is a general reachability checker on the set of subsets of the set of guests, where the transition relation is defined by rules given such that an application of the rule $r(X,S): V to V’$ is a guarded command:
if $S subseteq V$ then $V’ = V cup {X}$.
We are interested in the minimal subsets $V$ such that the whole set $U$ of guests is reachable from $V$ after a finite sequence of rule applications.
add_element(X,V,U):- ( var(V) -> % set difference that works in both modes member(X,U),subtract(U,[X],V); +member(X,V),sort([X|V],U) ). support(V,U):- guests(G), % rule application member(X,G), add_element(X,V,U), follows(X,S), subset(S,V). set_support(U,V):- support(V1,U), % sort of a minimal set ( support(_V2,V1) -> set_support(V1,V) ; V = V1). is_duplicate(X,[Y|L]):- ( subset(Y,X) ; is_duplicate(X,L) ). % purging solutions that are not truly minimal minimal_support(U,L):-minimal_support(U,[],L). minimal_support([],L,L). minimal_support([X|L],L1,L2):-( append(L,L1,U),is_duplicate(X,U) -> minimal_support(L,L1,L2); minimal_support(L,[X|L1],L2) ). solution(L):- guests(G),setof(X,set_support(G,X),S), minimal_support(S,L).
Now if for instance dataset #2 is given as
follows(fa,[dd,ec]). follows(cp,[ad,bm]). guests([ad,bm,cp,dd,ec,fa]).
We get the answer L = [[ad, bm, dd, ec]]. Which means that all guests but Carlotte and Falco must be invited. The answers this solution gave me matched the solutions given in the Wicked Witch article with the exception of dataset #6, where more solutions were produced. This seems to be the correct solution. Finally, I must mention the CLP(FD) library of Prolog that is particularly suitable for this sort of problems.
Best Answer from StackOverflow
Question Source : http://cs.stackexchange.com/questions/2031