2016-06-28 73 views
5

創建算術和disequality限制我的品牌新的Prolog的,我很感興趣,將下面的文字題成(SWI)序言:如何Prolog的

有4個孩子:安倍晉三,丹,瑪麗和蘇。他們的年齡沒有特別的順序是3,5,6和8歲。安倍比丹年長。蘇比瑪麗還年輕。蘇的年齡是丹的年齡加上3年。瑪麗比安倍還年長。

到目前爲止,我已經拿出

child(X) :- 
    member(X, [3,5,6,8]). 

solution(Abe, Dan, Mary, Sue) :- 
    child(Abe), 
    child(Dan), 
    child(Mary), 
    child(Sue), 
    Abe > Dan, 
    Sue < Mary, 
    Sue == Dan+3, 
    Mary > Abe, 
    Abe \== Dan, 
    Abe \== Mary, 
    Abe \== Sue, 
    Dan \== Mary, 
    Dan \== Sue, 
    Mary \== Sue. 

但運行查詢

?- solution(Abe, Dan, Mary, Sue) 

我只是得到false。作爲一個側面的問題,Prolog會執行蠻力搜索解決方案,還是有一些機器可以解決這個問題(比O(n!)更好)?

我想要的結果是Abe = 5, Dan = 3, Mary = 9, Sue = 6

+3

你必須寫**蘇=:=丹+ 3 ** **代替蘇==丹+ 3 ** – joel76

+3

'蘇==丹+ 3'將不執行算術操作。你需要'Sue =:= Dan + 3'。 – lurker

+0

哎呀!謝謝 – Brent

回答

7

對整數的算術約束(如此益智中的約束)最好用您的Prolog系統的CLP(FD) 約束表示。

例如,在SICStus序言,YAP或SWI:

 
:- use_module(library(clpfd)). 

ages(As) :- 
     As = [Abe,Dan,Mary,Sue], % There are 4 children: Abe, Dan, Mary, Sue 
     As ins 3\/5\/6\/8,   % Their ages are 3, 5, 6 and 8 
     all_different(As), 
     Abe #> Dan,     % Abe is older than Dan 
     Sue #< Mary,    % Sue is younger than Mary 
     Sue #= Dan + 3,    % Sue's age is Dan's age plus 3 years 
     Mary #> Abe.    % Mary is older than Abe 

樣品查詢及其結果:

 
?- ages([Abe,Dan,Mary,Sue]). 
Abe = 5, 
Dan = 3, 
Mary = 8, 
Sue = 6. 

我們從這個答案的謎題有着獨特的解決方案看。

請注意,沒有搜索任何是必要獲得這個答案!約束求解器通過一個強大的隱式機制推斷出獨特的解決方案,稱爲約束傳播,這是CLP系統在蠻力搜索上的關鍵優勢。在此示例中,約束傳播成功用於刪除搜索樹的所有剩餘分支。

+1

要走的路。 S(X)!你的答案有一些小問題:(1)需要定義SICStus clpfd'(ins)/ 2'。 (2)最好將域3/5/6/8寫爲可與SWI和SICStus一起使用的{3} \/{5} \/{6} \/{8}'。 (3)當使用'library(clpz)'和​​SICStus時,這兩個問題都消失了---可以在http://github.com/triska/clpz找到。如何給SWI引入一個名爲'clpz'的模塊呢? – repeat

+2

查找clpfd後發現http://www.swi-prolog.org/man/clpqr.html我有一些小問題,也許你可以回答。 1)CLP(Q,R)是CLP(FD)的一個超集 - CLP(Q,R)能否有效地解決這個問題,還是嚴格使用整數有用的約束? 2)我發現CLP(FD)是與整數一起工作的,但FD實際上代表什麼呢? – Brent

+2

雖然使用CLP(Q,R)來解決這個問題(更準確的說,類似但更大的問題)會帶來性能損失嗎? – Brent

1

由於值在child電話後接地,可以使用is操作:

child(X) :- 
    member(X, [3,5,6,8]). 
solution(Abe, Dan, Mary, Sue) :- 
    child(Abe), 
    child(Dan), 
    child(Mary), 
    child(Sue), 
    Abe > Dan, 
    Sue < Mary, 
    Sue is Dan+3, 
    Mary > Abe, 
    Abe =\= Dan, 
    Abe =\= Mary, 
    Abe =\= Sue, 
    Dan =\= Mary, 
    Dan =\= Sue, 
    Mary =\= Sue. 

您還可以通過交錯生成和測試提高性能,而不是首先生成,然後測試:

child(X) :- 
    member(X, [3,5,6,8]). 
solution(Abe, Dan, Mary, Sue) :- 
    child(Abe), 
    child(Dan), 
    Abe > Dan, 
    Abe =\= Dan, 
    child(Mary), 
    Mary > Abe, 
    Abe =\= Mary, 
    Dan =\= Mary, 
    Sue is Dan+3, 
    Sue < Mary, 
    child(Sue), 
    Abe =\= Sue, 
    Dan =\= Sue, 
    Mary =\= Sue. 

那麼你也可以消除一些不等於謂詞=\= ),因爲這些暗示的小於<)或大於>)謂詞;或由is斷言:

child(X) :- 
    member(X, [3,5,6,8]). 
solution(Abe, Dan, Mary, Sue) :- 
    child(Abe), 
    child(Dan), 
    Abe > Dan, 
    child(Mary), 
    Mary > Abe, 
    Dan =\= Mary, 
    Sue is Dan+3, 
    Sue < Mary, 
    child(Sue), 
    Abe =\= Sue. 

然而使用約束邏輯編程(CLP)工具可能是解決這個問題的最好辦法。

+1

爲什麼不在'孩子(蘇)'之前放置'蘇丹+ 3'?然後,也許,再往上移動;我知道......它永遠不會結束:) – repeat

4

answer by @WillemVanOnsem —產生與低級別的算術—測試老派

相比之下, @mat's code勝在通用/通用/魯棒性,declarativity,簡潔,效率和更多!怎麼來的?運氣?天才?神聖的干預?可能有點每個,但主要原因是這樣的:@mat使用優越的工具。 @mat使用

好消息! 一般是可用的。使用它&獲得的好處:

  • 注意密切@墊的Prolog的代碼和原來的規格如何!

  • 代碼保留。這具有重要的後果:

    • 可以使用高級調試方法(它利用純Prolog代碼的有用的代數屬性)!

    • 低級別調試可能, 但探索高層次的方法先!

+2

我真的很喜歡使用置換函數,因爲它非常類似於我的問題的內部模型。你會簡單解釋一下maplist調用中發生了什麼? #是maplist/3的第一個參數嗎?它是什麼? – Brent

+1

@Brent。稍後我會編輯我的答案,但讓我從這裏開始:'maplist/3'是一個廣泛可用的[tag:meta-predicate],這是一個將另一個謂詞作爲參數的謂詞。 '(#<)/ 2'完全錯過了2個參數。作爲第一個參數的'' repeat

+1

這很有道理。感謝您的澄清。 – Brent