2014-01-12 87 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.