Prolog로 제약 만족 문제를 해결할 수 있습니까?


18

인가 "파티 참석" 문제의 유형은 프롤로그에서 해결 가능? 예를 들면 다음과 같습니다.

우엉 뮬둔과 카를로 타 핑크 스톤은 모두 알버스 덤블도어가 오면 올 것이라고 말했다. Albus Dumbledore와 Daisy Dodderidge는 Carlotta Pinkstone이 오면 올 것이라고 말했다. 엘프 리다 클래 그 (Alfrida Clagg)가 오면 알버스 덤블도어 (Albus Dumbledore), 우엉 뮬둔 (Burdock Muldoon), 카를로 타 핑크 스톤 (Carlotta Pinkstone)은 모두 올 것이라고 말했다. Carlotta Pinkstone과 Daisy Dodderidge는 Falco Aesalon가 오면 올 것이라고 말했다. Burdock Muldoon, Elfrida Clagg 및 Falco Aesalon는 모두 Carlotta Pinkstone과 Daisy Dodderidge가 모두 오면 올 것이라고 말했습니다. Daisy Dodderidge는 Albus Dumbledore와 Burdock Muldoon이 모두 오면 그녀가 올 것이라고 말했다. 모든 초대받은 사람이 참석하도록 파티에 참석하도록 설득해야하는 사람은 누구입니까?

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

스택 오버플로 (펑크 없음)가 발생하고 프롤로그 평가에 대한 지식이 없으므로 이것이 내가 묻는 이유입니다.

일반적으로이 문제는 부울 CNF 만족 공식 (6 개의 부울 변수 포함)으로 변환 될 수 있습니다. 따라서 프롤로그 관점에 장점이 있습니까?


2
귀하의 문제는 대문자 식별자가 변수라는 것 attend(BM) :- attend(AD).입니다.attend(X) :- attend(Y).
svick

작은 글자 ( ideone.com/w622Z ) 로 시도 했지만 여전히 동일한 결과입니다.
Tegiri Nenashi

물론 머큐리 / 프롤로그를 너무 오랫동안 수행하지 않았으며, 물론 svick의 요점은 맞으며, 첫 번째 프로그램은 "어떤 사람이 입국하면 어떤 사람은 입원했다"는 말과 거의 일치합니다. 변수를 구체적인 용어로 바꾸면 내 대답에 설명 된 문제가 발생합니다.
Ben

Prolog는 Turing-complete 언어이므로 간단한 대답은 "예"입니다.
David Richerby

답변:


13

프로그래밍 언어와 마찬가지로 Prolog로 문제를 해결하려면 선언적이거나 명령적인 솔루션과 입력의 표현에 대해 생각해야합니다.

이것은 프로그래밍 질문이므로 프로그래머가 프로그래밍 문제를 해결하는 StackOverflow.com에서 인기가있었습니다. 나는 더 과학적이 되려고 노력할 것이다.

OP의 문제를 해결하려면 입력에 명시된 종속성에 의해 정의 된 관계를 역전시켜야합니다. 폼의 절 t t E N D ( X ) t t n 개의 D ( Y ) t t E N D ( Z ) 역방향 쉽다. 조항 A t t e n d ( A D ) A t t e n d (Attend(X)Attend(Y)Attend(Z)At이자형()이자형(미디엄)이자형()

Daisy Dodderidge는 Albus Dumbledore와 Burdock Muldoon이 모두 오면 그녀가 올 것이라고 말했다

치료하기가 더 어렵습니다.

Prolog를 사용하는 첫 번째 간단한 방법은 관계의 완전한 반전을 피하고 대신 목표를 지시하는 것입니다.

손님 목록에 주문을 가정하고 규칙을 사용하십시오.

{(엑스)(와이)(),()(엑스),()(와이),엑스<,와이<}()()

(우리가 사용 ( X ) 대신 t를 t의 E N D ( X는 ) 짧아야하는)(엑스)이자형(엑스)

이 규칙은 쉽게 구현할 수 있습니다.

다소 순진한 접근

가독성 follows을 위해 입력으로 주어진 관계가 brings되며 그 반대가됩니다.

그런 다음 입력이

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

그리고 brings다음과 같이 정의 할 수 있습니다 :

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)엑스

우리가 정의하면

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

우리는 다음과 같은 독특한 솔루션을 얻습니다.

 [ad,ec]

사전 순 목록은 아닙니다.

 follows(bm,[cp,dd]).

작동하지 않는다.

원래 퍼즐에 대한 다소 관련된 솔루션

문제를 완전히 해결하려면 실제로 검색 트리에 무한 루프를 도입하지 않고 나중에 게스트가 참석하도록 증명해야합니다. 이 목표를 달성하는 방법에는 여러 가지가 있습니다. 각각의 장단점이 있습니다.

한 가지 방법은 brings/2다음과 같이 재정의 하는 것입니다.

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

brings/4에서 무한 루프를 피하려면 마지막 인수 가 필요합니다 try_bring.

Albus, Carlotta, Elfrida 및 Falco와 같은 답변이 제공됩니다. 그러나 역 추적을 피할 수있는 위치에 역 추적이 도입되므로이 솔루션이 가장 효율적인 솔루션은 아닙니다.

일반적인 해결책

아르 자형(엑스,에스):VV'

에스VV'=V{엑스}

VV

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

예를 들어 데이터 세트 # 2가 다음과 같이 주어지면

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

우리는 L = [[ad, bm, dd, ec]]라는 답을 얻습니다. 이는 Carlotte와 Falco를 제외한 모든 손님을 초대해야 함을 의미합니다.

이 솔루션이 제공 한 답변은 더 많은 솔루션이 생성 된 데이터 세트 # 6을 제외하고 Wicked Witch 기사에 제공된 솔루션과 일치합니다. 이것은 올바른 해결책 인 것 같습니다.

마지막으로 이런 종류의 문제에 특히 적합한 Prolog의 CLP (FD) 라이브러리를 언급해야합니다.


정답에는 F (예 : A, C, E, F)도 포함됩니다. 규칙에 오타가 있거나 프로그램에 더 심각한 문제가 있습니다.
Tegiri Nenashi


기사에 링크 된 사이트에서 데이터 집합 # 2 ideone.com/21AmX 그것은 제대로 작동 나던 ...
Tegiri Nenashi

솔루션 핸들 여러 대안 (세트 # 8)합니까 ideone.com/rBjXi
Tegiri Nenashi에게

@TegiriNenashi 링크 된 사이트에 6 개의 "가정을 가정하지 않음"가정이 있습니다. 내 솔루션이 № 2와 № 5를 만족하지 않습니다. № 5는 해결하기 쉬운 것 같습니다 : 두 개의 "추종자 아님"규칙을 일반화하십시오. 그것이 수정되면 데이터 세트 # 8에 대한 첫 번째 대답을 얻어야합니다. 가정 № 2가 충족 될 때까지 예제 데이터 세트 중 어느 것도 올바르게 해결 될 수 없습니다.
Dmitri Chubarov 2016 년

10

svick에서 알 수 있듯이 OP 코드의 첫 번째 문제는 대문자로 시작하는 이름이 Prolog의 변수라는 것입니다. 따라서 Prolog가 즉시 무한 루프에 들어가서 보유하고있는 일부 항을 찾아서 일부 항에 대한 보유 를 증명하려고 시도하는 admit(CP) :- admit(AD)것과 같습니다 .attend(X) :- attend(Y)attendattend

그러나 각 이니셜 세트가 구체적으로 구별되는 용어를 의미했다면 사이클이 있기 때문에 여전히 스택 오버플로가 발생합니다.

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

따라서 attend(cp)Prolog는 보류 여부 를 확인하기 위해 attend(ad)보류 여부를 확인 attend(cp)하여 스택 오버플로가 발생할 때까지 보류 여부를 확인합니다 .

나는 바닐라 프롤로그가 그러한주기가 있는지 여부를 결정하려고 시도 하고 무한 루프에 빠지기보다는 하나 또는 진실 을 만드는 다른 방법을 조사한다고 생각하지 않습니다 .attend(cp)attend(ad)

이러한 기능을 지원하는 Prolog 버전이있을 수도 있고 없을 수도 있습니다. 저는 Mercury에 대해 더 잘 알고 있으며 Mercury의 "최소 모델 테이블 링"이 바로이 경우에 필요한 것 같습니다. 나는 실제로 그것을 사용하지는 않았지만, 내 이해는 그것을 증명하는 다른 방법이 있다면 그 자체가 참으로 간주되거나 무한 루프에 빠지지 않고 거짓으로 간주되는 용어를 허용한다는 것입니다. Mercury 문서 의 관련 섹션 을 참조하고 구현에 대해 설명 하는 문서 가 필요하면

Mercury는 Prolog와 유사한 구문을 사용하지만 강력한 유형 및 모드 시스템으로 강제 순도 논리 프로그래밍 언어이며 해석되지 않고 컴파일됩니다.

방금 읽지 않은 종이에 대한 소개를 다시 살펴 보았으며 여러 버전의 프롤로그에서 구현 된 표 작성에 대해 언급 했으므로 표 작성을 위해 인터넷 검색을 통해 더 많은 것을 얻을 수 있습니다. 프롤로그에서.



0

소문자 / 대문자 문제를 제외하고 절에주기가 있습니다.

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

따라서 하향식 통역사를 호출하면 반복됩니다. 상향식으로 작동하는 ASP ( 응답 세트 프로그래밍 )를 사용하면 더 많은 행운을 얻을 수 있습니다 . 다음은 라이브러리 ( 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).

다음은 예제 실행입니다.

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).
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.