2014-01-12 43 views
6

鑑於代碼下面的示例:PROLOG CLPFD如何通過約束來表達這一點?

example(Ls) :- 
    Ls = [X,Y], 
    Ls ins 1..2, 
    Cost #= max((X #= 1)*3 + (Y #= 1)*5, 
       (X #= 2)*3 + (Y #= 2)*5), 
    labeling([minimize(Cost)], Ls). 

的想法是找到分配給Ls的變量最小化成本(在這個簡單的例子,這將是要麼X = 1和Y = 2,或X = 2和Y = 1)。

我想使用約束條件#=/2是可驗證的事實,這意味着將它們的真值反映爲由整數0和1表示的布爾值(取自手冊http://www.swi-prolog.org/man/clpfd.html)。

但是,它不起作用。我收到以下錯誤:

ERROR: Domain error: `clpfd_expression' expected, found `_G3154#=1' 

什麼是等效的正確版本?

回答

5

物化涉及單獨約束#<==>/2#==>/2等),可以使用它們例如像:

example(Ls) :- 
    Ls = [X,Y], 
    Ls ins 1..2, 
    X #= 1 #<==> B1, 
    Y #= 1 #<==> B2, 
    X #= 2 #<==> B3, 
    Y #= 2 #<==> B4, 
    Cost #= max(B1*3 + B2*5, B3*3 + B4*5), 
    labeling([min(Cost)], Ls). 

示例查詢和它的結果:

?- example(Ls). 
Ls = [1, 2] ; 
Ls = [2, 1] ; 
Ls = [1, 1] ; 
Ls = [2, 2] ; 
false. 
+0

有什麼辦法來同不使用中間變量B1..B4?在真正的計劃中,將會有超過200個。 – user2460978

+1

我已經使用了多達10,000個這樣的中間變量(例如,在解決100x100棋盤上的100皇后問題時動畫搜索過程),沒有任何問題。所以,我建議你先試試它是否有效,並且只有在你確實需要它們時才尋找更有效的配方。當然,在一個更大的例子中,您不需要手動引入這些中間變量,而是通過一個輔助謂詞來設置它們,例如通過您指定或計算的某些輸入數據將它們與變量和值列表相關聯。 – mat

+0

在你的例子中使用該方法,我得到它的工作。然而,每個元素有超過10個變量,每個元素有7個可能值,完成需要一分鐘。 – user2460978

3

作爲替代使用實體,您還可以使用額外的算術約束來在表達式中「捕獲」相等性:

example([X,Y]) :- 
    X in 1..2, 
    Y in 1..2, 
    Cost #= max(3*(1-min(1,abs(X-1))) + 5*(1-min(1,abs(Y-1))), 
       3*(1-min(1,abs(X-2))) + 5*(1-min(1,abs(Y-2)))), 
    labeling([min(Cost)], [X,Y]). 

請注意,Cost #= max(...)內部的表達式可以稍微簡化一下。

使用示例:

?- example(Ls). 
    Ls = [1,2] 
; Ls = [2,1] 
; Ls = [1,1] 
; Ls = [2,2] 
; false.