Pour résoudre un problème avec Prolog, comme avec tout langage de programmation, qu'il soit déclaratif ou impératif, vous devez penser à la représentation de la solution et de l'entrée.
Comme il s'agit d'une question de programmation, elle aurait été populaire sur StackOverflow.com où les programmeurs résolvent les problèmes de programmation. Ici, j'essaierais d'être plus scientifique.
Pour résoudre le problème dans l'OP, il faut inverser la relation définie par les dépendances indiquées dans l'entrée. Les clauses de la forme sont faciles à inverser. Les clauses 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( O) ∧ A t t e n d( Z) commeA t t e n d( A D ) ∧ A t t e n d( B M) → A t t e n d( D D )
Daisy Dodderidge a dit qu'elle viendrait si Albus Dumbledore et Burdock Muldoon venaient tous les deux
sont plus difficiles à traiter.
Avec Prolog, la première approche simple consiste à éviter un renversement complet de la relation et à être plutôt orienté vers un objectif.
Supposons une commande sur la liste des invités et utilisez une règle
⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪A ( X) ∧ A ( Y)A ( W)A ( W)XOui→ A ( Z) ,→ A ( X) ,→ A ( Y) ,< Z,< Z⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⊢A ( W) → A ( Z)
(Nous utilisons au lieu de A t t e n d ( X ) pour faire court)UNE( X)A t t e n d( X)
Cette règle est facile à mettre en œuvre.
Une approche plutôt naïve
Pour la lisibilité, follows
soit la relation donnée en entrée, et brings
son inverse.
Ensuite, l'entrée est donnée par
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]).
Et brings
peut être défini comme suit:
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
Si nous définissons
partymaker(X):-Guests=[ad,bm,cp,dd,ec,fa],member(X,Guests),brings(X,Guests).
Nous obtenons les solutions uniques suivantes:
[ad,ec]
Ce n'est pas la liste complète, car dans l'ordre alphabétique, la clause
follows(bm,[cp,dd]).
ne fonctionne pas.
Une solution plutôt impliquée au puzzle original
Pour résoudre complètement le problème, vous devez laisser le système essayer de prouver la présence des invités ultérieurs sans introduire de boucles infinies dans l'arborescence de recherche. Il existe plusieurs façons d'atteindre cet objectif. Chacun a ses avantages et désavantages.
Une façon consiste à redéfinir brings/2
comme suit:
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).
Le dernier argument dans brings/4
est nécessaire pour éviter une boucle infinie try_bring
.
Cela donne les réponses suivantes: Albus, Carlotta, Elfrida et Falco. Cependant, cette solution n'est pas la plus efficace car le retour en arrière est introduit là où il est parfois possible de l'éviter.
Une solution générale
r ( X, S) : V→ V′
S⊆ VV′= V∪ { X}
VUV
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).
Maintenant, si par exemple l'ensemble de données # 2 est donné comme
follows(fa,[dd,ec]).
follows(cp,[ad,bm]).
guests([ad,bm,cp,dd,ec,fa]).
Nous obtenons la réponse L = [[ad, bm, dd, ec]]. Ce qui signifie que tous les invités sauf Carlotte et Falco doivent être invités.
Les réponses que cette solution m'a données correspondaient aux solutions données dans l'article Wicked Witch à l'exception du jeu de données # 6, où plus de solutions ont été produites. Cela semble être la bonne solution.
Enfin, je dois mentionner la bibliothèque CLP (FD) de Prolog qui est particulièrement adaptée à ce type de problèmes.
attend(BM) :- attend(AD).
c'est exactement la même chose queattend(X) :- attend(Y).