Czy problemy typu „obecność na imprezie” można rozwiązać w Prologu? Na przykład:
Łopian Muldoon i Carlotta Pinkstone powiedzieli, że przybędą, jeśli przyjdzie Albus Dumbledore. Albus Dumbledore i Daisy Dodderidge powiedzieli, że przybędą, jeśli przyjdzie Carlotta Pinkstone. Albus Dumbledore, Burdock Muldoon i Carlotta Pinkstone powiedzieli, że przyjdą, jeśli przyjdzie Elfrida Clagg. Carlotta Pinkstone i Daisy Dodderidge zapowiedziały, że przybędą, jeśli przyjdzie Falco Aesalon. Łopian Muldoon, Elfrida Clagg i Falco Aesalon wszyscy powiedzieli, że przyjdą, jeśli pojawią się Carlotta Pinkstone i Daisy Dodderidge. Daisy Dodderidge powiedziała, że przyjdzie, jeśli przyjdą Albus Dumbledore i Burdock Muldoon. Kogo należy przekonać do udziału w przyjęciu, aby zapewnić udział wszystkich zaproszonych przez nią osób?
Próbowałem to wyrazić w 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.*/
Mam problem z przepełnieniem stosu (bez gry słów) i nie mam wiedzy na temat oceny prologu, dlatego pytam.
Ogólnie rzecz biorąc, problem ten można przerzucić na formułę logicznego zadowolenia CNF (z 6 zmiennymi logicznymi). Czy zatem perspektywa prologu ma jakąś wartość?
źródło
attend(BM) :- attend(AD).
jest dokładnie taki sam jakattend(X) :- attend(Y).
Odpowiedzi:
Aby rozwiązać problem z Prologiem, jak w każdym języku programowania, zarówno deklaratywnym, jak i imperatywnym, musisz pomyśleć o reprezentacji rozwiązania i danych wejściowych.
Ponieważ jest to pytanie programistyczne, byłoby popularne na StackOverflow.com, gdzie programiści rozwiązują problemy z programowaniem. Tutaj chciałbym być bardziej naukowy.
Aby rozwiązać problem w PO, należy odwrócić relację określoną przez zależności określone na wejściu. Klauzule postaci można łatwo odwrócić. Klauzule A t t e n d ( A D ) ∧ A t t e n d (Attend(X)→Attend(Y)∧Attend(Z) jakA t t e nd( A D ) ∧ A t t e n d( B M) → A t t e n d( D D )
są trudniejsze do leczenia.
W przypadku Prologu pierwsze proste podejście polega na unikaniu pełnego odwrócenia relacji i kierowaniu się celem.
Załóż zamówienie na liście gości i zastosuj regułę
(Używamy zamiast A t t e n d ( X ), aby było krótkie)A ( X) A t t e n d( X)
Ta zasada jest łatwa do wdrożenia.
Raczej naiwne podejście
Dla czytelności niech
follows
będzie relacją podaną jako dane wejściowe ibrings
odwrotnie.Następnie dane wejściowe są podawane przez
I
brings
można zdefiniować w następujący sposób:brings/3(X,L,S)
Jeśli zdefiniujemy
Otrzymujemy następujące unikalne rozwiązania:
To nie jest pełna lista, ponieważ w kolejności alfabetycznej klauzula
nie działa.
Raczej zaangażowane rozwiązanie oryginalnej układanki
Aby całkowicie rozwiązać problem, musisz faktycznie pozwolić systemowi udowodnić obecność późniejszych gości bez wprowadzania nieskończonych pętli do drzewa wyszukiwania. Istnieje wiele sposobów osiągnięcia tego celu. Każdy ma swoje zalety i wady.
Jednym ze sposobów jest przedefiniowanie
brings/2
w następujący sposób:Ostatni argument
brings/4
jest niezbędny, aby uniknąć nieskończonej pętlitry_bring
.To daje następujące odpowiedzi: Albus, Carlotta, Elfrida i Falco. Jednak to rozwiązanie nie jest najskuteczniejsze, ponieważ wycofywanie jest wprowadzane tam, gdzie czasem można go uniknąć.
Ogólne rozwiązanie
Po dodaniu linku do Trzeciego Międzynarodowego Wyzwania NoCOUG SQL i NoSQL w pierwotnym pytaniu stało się jasne, że szukamy ogólnego sprawdzania osiągalności na zbiorze podzbiorów zbioru gości, gdzie relacja przejścia jest zdefiniowana przez zasady podane tak, że zastosowanie regułyr ( X, S) : V→ V.′
Teraz, jeśli na przykład zestaw danych nr 2 jest podany jako
Otrzymujemy odpowiedź L = [[ad, bm, dd, ec]]. Co oznacza, że wszyscy goście oprócz Carlotte i Falco muszą zostać zaproszeni.
Odpowiedzi, które dało mi to rozwiązanie, pasowały do rozwiązań podanych w artykule Wicked Witch, z wyjątkiem zestawu danych nr 6, w którym wyprodukowano więcej rozwiązań. To wydaje się właściwe rozwiązanie.
Na koniec muszę wspomnieć o bibliotece CLP (FD) firmy Prolog, która jest szczególnie odpowiednia do tego rodzaju problemów.
źródło
Jak zauważył svick, pierwszym problemem z kodem w OP jest to, że nazwy zaczynające się od wielkich liter są zmiennymi w Prologu.
admit(CP) :- admit(AD)
Jest to więc równoważne z tymattend(X) :- attend(Y)
, co powoduje, że Prolog natychmiast wchodzi w nieskończoną pętlę, próbując wykazać, żeattend
utrzymuje się przez pewien okres, znajdując jakiś termin, dla którego sięattend
trzyma.Jeśli jednak chciałeś, aby każdy zestaw inicjałów był konkretnym odrębnym terminem, nadal będziesz mieć problem z przepełnieniem stosu, ponieważ masz cykle, np.
Aby sprawdzić, czy
attend(cp)
wstrzymania Prolog spróbuje ustalić, czyattend(ad)
wstrzymuje, co zrobi, sprawdzając, czyattend(cp)
wstrzymania itd., Aż do przepełnienia stosu.Nie wierzę, że waniliowy Prolog próbuje podjąć próbę ustalenia, czy istnieje taki cykl, i zbadać inne sposoby, aby jeden
attend(cp)
lubattend(ad)
prawdziwe, a nie utknąć w nieskończonej pętli.Mogą istnieć lub nie wersje Prologa obsługujące taką funkcję. Jestem bardziej zaznajomiony z Mercury i myślę, że „minimalne modelowanie” Mercury jest dokładnie tym, czego potrzebujesz w tym przypadku. Tak naprawdę nigdy go nie użyłem, ale rozumiem, że mniej więcej pozwala na to, aby termin, który implikuje, był uważany za prawdziwy, jeśli istnieje jakiś inny sposób udowodnienia tego, lub fałszywy, bez uwięzienia w nieskończonej pętli. Zobacz odpowiednią sekcję dokumentacji Mercury, a jeśli interesuje Cię artykuł opisujący wdrożenie.
Mercury jest logicznym językiem programowania o wymuszonej czystości, z podobną składnią jak Prolog, ale silnymi systemami typu i trybu, i jest raczej kompilowany niż interpretowany.
Właśnie przerzuciłem wstęp do artykułu (którego nie czytałem od dłuższego czasu) i wspomina, że tabling został zaimplementowany w kilku wersjach Prologów, więc może być tak, że możesz przejść dalej, przeglądając go na tabling w Prolog.
źródło
Znalazłem następujący artykuł na temat rozwiązywania problemów SAT za pomocą prologu:
Implementację solvera można znaleźć tutaj .
Zobacz tę odpowiedź dotyczącą przepełnienia stosu, aby uzyskać szczegółowe informacje na temat kodu i sposobu jego użycia.
źródło
Pomijając kwestię małych / wielkich liter, w klauzulach występuje cykl:
Kiedy zadzwonisz do interpretera odgórnego, zapętla się. Możesz mieć więcej szczęścia dzięki programowi Answer Set Programming (ASP), który działa oddolnie. Oto kodowanie za pomocą biblioteki ( minimalna / asp ):
Oto przykładowy przebieg:
źródło