Para resolver um problema com o Prolog, como em qualquer linguagem de programação, seja ela declarativa ou imperativa, é necessário pensar na representação da solução e da entrada.
Como essa é uma questão de programação, teria sido popular no StackOverflow.com, onde os programadores resolvem problemas de programação. Aqui eu tentaria ser mais científico.
Um t t e n d( X) → Um t t e n d( Y) ∧ Um t t e n d( Z)Um t t e nd( A D ) ∧ A t t e n d( B M) → A t t e nd( D D )
Daisy Dodderidge disse que viria se Albus Dumbledore e Burdock Muldoon viessem
são mais difíceis de tratar.
Com o Prolog, a primeira abordagem simples é evitar uma reversão completa do relacionamento e, em vez disso, ser direcionada à meta.
Assuma uma ordem na lista de convidados e use uma regra
⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪A ( X) ∧ A ( Y)A ( W)A ( W)XY→ A ( Z) ,→ A ( X) ,→ A ( Y) ,< Z,< Z⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⊢A ( W) → A ( Z)
A ( X)Um t t e n d( X)
Esta regra é fácil de implementar.
Uma abordagem bastante ingênua
Para facilitar a leitura, follows
seja a relação dada como entrada e brings
seja o seu inverso.
Então a entrada é dada por
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]).
E brings
pode ser definido da seguinte maneira:
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]).
brings/3(X,L,S)
X comparecer.
Se definirmos
partymaker(X):-Guests=[ad,bm,cp,dd,ec,fa],member(X,Guests),brings(X,Guests).
Temos as seguintes soluções exclusivas:
[ad,ec]
Esta não é a lista completa, pois sob a ordem alfabética da cláusula
follows(bm,[cp,dd]).
não está funcionando.
Uma solução bastante envolvida para o quebra-cabeça original
Para resolver o problema completamente, você deve realmente deixar o sistema tentar provar a presença de convidados posteriores sem introduzir loops infinitos na árvore de pesquisa. Existem várias maneiras de atingir esse objetivo. Cada um tem suas vantagens e desvantagens.
Uma maneira é redefinir da brings/2
seguinte maneira:
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).
O último argumento em brings/4
é necessário para evitar um loop infinito try_bring
.
Isso fornece as seguintes respostas: Albus, Carlotta, Elfrida e Falco. No entanto, essa solução não é a mais eficiente, uma vez que o retorno é introduzido, onde às vezes pode ser evitado.
Uma solução geral
r ( X, S) : V→ V′
S⊆ VV′= V∪ { X}
VvocêV
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).
Agora, se, por exemplo, o conjunto de dados # 2 for fornecido como
follows(fa,[dd,ec]).
follows(cp,[ad,bm]).
guests([ad,bm,cp,dd,ec,fa]).
Nós obtemos a resposta L = [[ad, bm, dd, ec]]. O que significa que todos os convidados, exceto Carlotte e Falco, devem ser convidados.
As respostas que essa solução me deu correspondem às soluções fornecidas no artigo da Wicked Witch, com exceção do conjunto de dados # 6, onde mais soluções foram produzidas. Esta parece ser a solução correta.
Finalmente, devo mencionar a biblioteca de Prolog CLP (FD) que é particularmente adequada para esse tipo de problemas.
attend(BM) :- attend(AD).
é exatamente o mesmo queattend(X) :- attend(Y).