2015-07-03 71 views
4

這就是問題簡而言之: 16個孩子要坐在4 x 4陣列椅子上。這些孩子是8個女孩(編號1..8)和8個男孩(編號9..16)。 1,3,5,8認爲男孩是墮胎 9,10,11,14認爲女孩是毛 這些對是敵人: [[1,2],[4,6],[4,7], [4,9],[9,11],[12,14],[14,16]]排除序言中的tuples_in列表

找到兩個孩子不是敵人謂詞被定義爲:

not_enemy(A, B) :- 
    NotA #\= A #\/ NotB #\= B, 
    tuples_in([[NotA, NotB]], 
       [[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]). 

上面代碼被發現here

但是當我查詢? - not_enemy(1,2)輸出是真實的。

我不得不改用此長碼:

not_enemy(A, B) :- 
      A #=1 #==> B #\= 2, 
      A #=4 #==> B #\= 6, 
      A #=4 #==> B #\= 7, 
      A #=4 #==> B #\= 9, 
      A #=9 #==> B #\= 11, 
      A #=12 #==> B #\= 14, 
      A #=14 #==> B #\= 16. 

任何人都可以請幫助糾正第一段代碼?提前致謝。

+1

這個例子是錯誤的,並且混合使用'tuples_in/2'的通知肯定不是用CLP(FD)表達給定約束的好方法。你的代碼是正確的方法(+1!)。另一種方法是應用方法@repeat描述:您可以構建關係的補充並使用tuples_in/2來將這些對約束爲* compatible *元素。另一種方法是否定個別的'tuples_in/2'約束。要小心,儘管不會意外否定涉及多對的tuples_in/2約束,因爲這不會在邏輯上等同於其他方式。 – mat

回答

5

我會改進你的代碼,只是爲了讓通用

not_enemy(A, B) :- 
    maplist(not_enemy(A,B), [[1,2], [4,6], [4,7], [4,9], [9,11], [12,14], [14,16]]). 
not_enemy(A,B,[X,Y]) :- 
    X #= A #==> Y #\= B. 

我無法找到使用tuples_in來解決這個問題的適當方式。

3

以上使用tuples_in/2是錯誤的。

tuples_in定義爲「兼容表」的思維方式: 然後,它應該是顯而易見的,隨着(#\=)/2組合不可能表達「不兼容表」工作。

爲什麼?因爲---帶有不兼容表---我們不希望排除任何單個不兼容的元組,但是所有 其中在同一時間。

當使用有限域時,我們可以通過以笛卡爾積作爲消除不兼容對的基礎,顯式構造一個兼容性表。

+0

如何?兼容性表格? – false

+0

謝謝,我可以從概念上理解你的想法,我會在序言中嘗試。 –

3

我找到了另一種答案,而不是使用此

not_enemy(A, B) :- 
    NotA #\= A #\/ NotB #\= B, 
    tuples_in([[NotA, NotB]], 
       [[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]). 

就否定tuples_in用#\

not_enemy(A, B) :- 
    #\ tuples_in([[A,B]], 
       [[1,2], [4,6], [4,7], [4, 9],[9,11], [12, 14], [14,16]]). 
+1

它有用嗎?很高興知道!我認爲\#是用於可約束的,而tuples_in不屬於這個類別。所以我沒有嘗試... – CapelliC

+3

我檢查了文檔,如果經過進一步調查,你的答案證明是正確的,我將提交一份關於clpfd文檔的錯誤報告 – CapelliC

+0

是的,它確實有效。 \#否定後面的任何內容(在clpfd中)。 –

1

擴展在我上面已經給出了評論,我想告訴你的SWI-Prolog頂層的一個重要特徵,有助於檢測出一個明顯的錯誤表達問題。

首先考慮的not_enemy/2的明顯錯誤的答案:

?- not_enemy(1, 2). 
true. 

但是,還有更多的它,你看到後,您可以使用:

?- set_prolog_flag(toplevel_residue_vars, true). 
true. 

然後,頂層顯示待定由於涉及的變量未出現在查詢中,通常不會顯示剩餘目標:

?- not_enemy(1, 2). 
% with pending residual goals 
_G454 in 0..1, 
_G454#\/_G460#<==>1, 
etc. 

由此可見,該公式存在一些問題:存在未決的剩餘約束,CLP(FD)通常不會也不能保證待處理約束的一致性。您必須使用其中一個枚舉謂詞來查看是否有任何具體的解決方案。

在這種情況下,即使使用枚舉謂詞,也會得到錯誤的結果,因爲問題被錯誤地表達出來。然而,單單待定的剩餘約束已經給你一個清晰的表示,你不能把答案當作具體的解決方案。

標誌toplevel_residue_vars通過隱式地將查詢包裝在名爲call_residue_vars/2的重要謂詞中工作。這在SICStus和SWI中可用來顯示所有剩餘約束。使用它來確保您不會在您的配方中某處意外地創建不可滿足的約束。

由於這樣的原因,我強烈建議你避免副作用,這樣你可以更多地聲明你的代碼的原因,並使用頂層顯示答案和具體的解決方案。