Kısıt memnuniyeti problemleri Prolog ile çözülebilir mi?


18

"parti katılım" sorunların tipi Prolog'da çözülebilir? Örneğin:

Dulavratotu Muldoon ve Carlotta Pinkstone, Albus Dumbledore gelirse geleceklerini söylediler. Albus Dumbledore ve Daisy Dodderidge, Carlotta Pinkstone gelirse geleceklerini söylediler. Albus Dumbledore, Burdock Muldoon ve Carlotta Pinkstone Elfrida Clagg gelirse geleceklerini söylediler. Carlotta Pinkstone ve Daisy Dodderidge, Falco Aesalon gelirse geleceklerini söylediler. Dulavratotu Muldoon, Elfrida Clagg ve Falco Aesalon, her ikisi de Carlotta Pinkstone ve Daisy Dodderidge'nin gelmesi durumunda geleceklerini söylediler. Daisy Dodderidge, Albus Dumbledore ve Burdock Muldoon gelse geleceğini söyledi. Tüm davetlilerinin katılmasını sağlamak için partiye katılmaya kimi ikna etmek gerekir?

Bunu GNU Prolog'da ifade etmeye çalıştım:

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.*/

Yığın taşması yaşıyorum (pun yok) ve prolog değerlendirmesi hakkında hiçbir bilgim yok, bu yüzden soruyorum.

Genel olarak, bu sorun Boolean CNF memnuniyet formülüne (6 boolean değişkenle) dönüştürülebilir. Bu nedenle, prolog perspektifinin bir değeri var mı?


2
O yüzden senin sorunun büyük tanımlayıcılar değişkenler olduğunu düşünüyorum attend(BM) :- attend(AD).tam olarak aynıdırattend(X) :- attend(Y).
svick

Küçük harflerle denenmiş ( ideone.com/w622Z ) yine aynı sonuç.
Tegiri Nenashi

Açıkçası çok uzun süredir herhangi bir Merkür / Prolog yapmadım, tabii ki svick'in noktası doğru ve ilk programınız kabaca "bir kişi kabul edilirse bir kişi kabul edilir" ifadesine karşılık geliyor. Değişkenleri somut terimlerle değiştirdikten sonra cevabımda açıklanan sorunla karşılaşıyorsunuz.
Ben

Prolog bir Turing-complete dilidir, çünkü basit cevap "Evet" dir.
David Richerby

Yanıtlar:


13

Prolog ile ilgili bir sorunu çözmek için, herhangi bir programlama dilinde olduğu gibi, ister açıklayıcı ister zorunlu olsun, çözümün ve girdinin temsilini düşünmelisiniz.

Bu bir programlama sorusu olduğundan, programcıların programlama sorunlarını çözdüğü StackOverflow.com'da popüler olurdu. Burada daha bilimsel olmaya çalışacağım.

OP'deki problemi çözmek için, girdide belirtilen bağımlılıklar tarafından tanımlanan ilişki tersine çevrilmelidir. formunun cümleleri kolayca tersine çevrilebilir. Maddeleri bir T T , e n d ( A D ) bir T T , e n dAttend(X)Attend(Y)Attend(Z) gibibirttend(birD)birttend(BM)birttend(DD)

Daisy Dodderidge Albus Dumbledore ve Burdock Muldoon gelse geleceğini söyledi

tedavisi daha zordur.

Prolog ile ilk basit yaklaşım, ilişkinin tamamen tersine çevrilmesini önlemek ve bunun yerine hedefe yönelik olmaktır.

Konuk listesinde bir sipariş olduğunu varsayalım ve bir kural kullanın

{bir(X)bir(Y)bir(Z),bir(W)bir(X),bir(W)bir(Y),X<Z,Y<Z}bir(W)bir(Z)

( Kısa tutmak için A t t e n d ( X ) yerine kullanıyoruz )bir(X)birttend(X)

Bu kuralın uygulanması kolaydır.

Oldukça naif bir yaklaşım

Okunabilirlik followsiçin bir girdi olarak verilen ilişki ve bringsbunun tersi olsun.

Sonra giriş tarafından verilir

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]).

Ve bringsaşağıdaki gibi tanımlanabilir:

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

Eğer tanımlarsak

 partymaker(X):-Guests=[ad,bm,cp,dd,ec,fa],member(X,Guests),brings(X,Guests).

Aşağıdaki benzersiz çözümleri elde ediyoruz:

 [ad,ec]

Bu tam liste değildir, çünkü cümlenin alfabetik sıralaması altında

 follows(bm,[cp,dd]).

çalışmıyor.

Orijinal bulmacanın oldukça karmaşık bir çözümü

Sorunu tamamen çözmek için, sistemin arama ağacına sonsuz döngüler getirmeden daha sonraki konuklar için katılımı kanıtlamaya çalışmasına izin vermelisiniz. Bu hedefe ulaşmak için birçok yol vardır. Her birinin avantajı ve dejavantajı var.

Bunun bir yolu brings/2aşağıdaki gibi yeniden tanımlamaktır :

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).

İçindeki son argüman, brings/4sonsuz bir döngüden kaçınmak için gereklidir try_bring.

Bu şu cevapları verir: Albus, Carlotta, Elfrida ve Falco. Ancak bu çözüm en etkili çözüm değildir, çünkü bazen önlenebilir, bazen önlenebilir.

Genel bir çözüm

Orijinal soruya Üçüncü Uluslararası NoCOUG SQL ve NoSQL Mücadelesi bağlantısının eklenmesinden sonra, peşinde olduğumuz şeyin, geçiş ilişkisinin tanımlandığı konuk grubunun alt kümelerinde genel bir erişilebilirlik denetleyicisi olduğu ortaya çıktı. kuralın uygulanması için kurallar verilir r(X,S):VV' korumalı bir komuttur:

Eğer SV sonra V'=V{X}.

Minimum alt kümelerle ilgileniyoruz V öyle ki bütün set U misafirlerden V sonlu kural uygulamaları dizisinden sonra.

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).

Şimdi örneğin 2 numaralı veri kümesi şu şekilde verilirse

follows(fa,[dd,ec]).
follows(cp,[ad,bm]).
guests([ad,bm,cp,dd,ec,fa]).

L = [[ad, bm, dd, ec]] cevabını alıyoruz. Bu, Carlotte ve Falco dışındaki tüm misafirlerin davet edilmesi gerektiği anlamına gelir.

Bu çözümün verdiği cevaplar, daha fazla çözümün üretildiği veri seti # 6 dışında, Wicked Witch makalesinde verilen çözümleri eşleştirdi. Bu doğru çözüm gibi görünüyor.

Son olarak, Prolog'un bu tür problemler için özellikle uygun olan CLP (FD) kütüphanesinden bahsetmeliyim.


Doğru cevap F'yi de içerir (yani A, C, E, F). Kurallarda yazım hatası ya da programda daha ciddi bir sorun var.
Tegiri Nenashi


İdeone.com/21AmX makalesinde bağlantılı siteden Veri Seti # 2 Çalışmıyor gibi görünüyor ...
Tegiri Nenashi

Çözümünüz birden fazla alternatifi ele alıyor mu (veri kümesi # 8) ideone.com/rBjXi
Tegiri Nenashi

@TegiriNenashi Bağlantılı sitede 6 "varsayma" varsayımı vardır. Çözümüm № 2 ve № 5'i karşılamıyor. № 5'in düzeltilmesi kolay görünüyor: iki "% Takipçi değil" kuralını genelleştirin. Bu düzeltilmişse, 8 numaralı veri kümesi için ilk cevabı almalıdır. Varsayım umption 2 karşılanıncaya kadar örnek veri kümelerinin ikisi de doğru şekilde çözülemez.
Dmitri Chubarov

10

Svick tarafından tespit edildiği gibi, OP kod ile ilk sorun büyük harflerle başlayan isimlerin Prolog değişkenler olmasıdır. Yani buna admit(CP) :- admit(AD)eşdeğerdir attend(X) :- attend(Y), bu da Prolog'un derhal sonsuz bir döngüye girmesiyle sonuçlanır attend;attend .

Bununla birlikte, her bir ilk harf grubunun somut farklı bir terim olmasını istediyseniz, döngüleriniz olduğu için yine de yığın taşmasıyla karşılaşırsınız, ör.

attend(cp) :- attend(ad).
attend(ad) :- attend(cp).

Yani anlayacak attend(cp)Prolog olmadığını belirlemek için çalışacağız tutan attend(ad)o olmadığını kontrol ederek yapacak olan tutar attend(cp)ve böylece yığın taşması kadar tutar.

Vanilya Prolog'un böyle bir döngü olup olmadığını belirlemek için herhangi bir girişimde bulunduğuna ve sonsuz bir döngüde sıkışıp kalmak yerine birini yapmanın veya doğru yapmanın başka yollarını incelemeye inanmıyorum .attend(cp)attend(ad)

Prolog'un böyle bir özelliği destekleyen sürümleri olabilir veya olmayabilir. Merkür hakkında daha fazla bilgi sahibiyim ve bence Merkür'ün "minimal model tablosu" tam da bu dava için ihtiyacınız olan şey. Aslında hiç kullanmadım, ama benim anlayışım az ya da çok sonsuz bir döngüye yakalanmadan başka türlü kanıtlamanın doğru olduğunu düşünen bir terimin az ya da çok bir terime izin vermesidir. Mercury belgelerinin ilgili bölümüne bakın ve uygulamayı açıklayan bir makaleyle ilgileniyorsanız .

Merkür, Prolog ile benzer sözdizimine ancak güçlü tip ve mod sistemlerine sahip, zorlayıcı bir mantıksal programlama dilidir ve yorumlanmak yerine derlenmiştir.

Ben sadece (bir süredir okumadım) kağıdın girişini yeniden gözden kaçırdım ve Prolog'ların çeşitli sürümlerinde uygulandığını belirtmekten bahsediyor, bu yüzden tablolama için googling yaparak daha da ileri gidebilirsiniz Prolog'da.



0

Küçük / büyük harf sorununu bir kenara bırakırsak, maddelerde bir döngü vardır:

attend(cp) :- attend(ad).
attend(ad) :- attend(cp).

Yukarıdan aşağıya bir tercüman çağırdığınızda, döngü gerçekleşir. Aşağıdan yukarıya doğru çalışan Yanıt Seti Programlama (ASP) ile daha fazla şansınız olabilir . İşte kütüphane üzerinden kodlama ( minimal / asp ):

:- use_module(library(minimal/asp)).

choose([admit(bm)]) <= posted(admit(ad)).
choose([admit(cp)]) <= posted(admit(ad)).
choose([admit(ad)]) <= posted(admit(cp)).
choose([admit(dd)]) <= posted(admit(cp)).
choose([admit(ad)]) <= posted(admit(ec)).
choose([admit(bm)]) <= posted(admit(ec)).
choose([admit(cp)]) <= posted(admit(ec)).
choose([admit(cp)]) <= posted(admit(fa)).
choose([admit(dd)]) <= posted(admit(fa)).
choose([admit(bm)]) <= posted(admit(cp)),posted(admit(dd)).
choose([admit(ec)]) <= posted(admit(cp)),posted(admit(dd)).
choose([admit(fa)]) <= posted(admit(cp)),posted(admit(dd)).
choose([admit(dd)]) <= posted(admit(ad)),posted(admit(bm)).

choose([admit(fa)]) <= posted(init).

İşte bir örnek çalışma:

Jekejeke Prolog 3, Runtime Library 1.3.8 (23 May 2019)

?- post(init), listing(admit/1).
admit(fa).
admit(cp).
admit(ad).
admit(bm).
admit(dd).
admit(ec).
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.