计算CSP中的解决方案

时间:2016-11-21 14:57:13

标签: prolog clp clpb

我正在使用prolog,我有这段代码:

:- use_module(library(clpb)).

fun(A, B, C, D, E) :-
  sat(A + B + C + D),
  sat(E),
  labeling([A, B, C, D, E]).

如果我想要计算所有解决方案,我该怎么办?我已经读过clpb中使用的sat_count(+ Expr,-Count),但是我无法在没有错误的情况下实现它

1 个答案:

答案 0 :(得分:2)

蛮力方法

计算解决方案数量的直接方法是生成它们,并查看有多少解决方案。

例如,对于您发布的程序,我们可以使用findall/3如下获取答案:

?- findall(., fun(A, B, C, D, E), Ls),
   length(Ls, L).
Ls = ['.', '.', '.', '.', '.', '.', '.', '.', '.'|...],
L = 15.

当然,这种情况相当严重,并且在更复杂的情况下很快变得不可行。不过,在这个例子中,这个策略就足够了。

替代方案:sat_count/2

使用CLP(B),我们已经发现了sat_count/2

sat_count/2的主要优势在于我们可以计算解决方案的数量而无需枚举。当有很多解决方案时,这当然非常方便。

使用sat_count/2的诀窍是避免 labeling/1,并以只有发布约束的方式编写核心关系

例如:

fun(A, B, C, D, E) :-
   sat(A + B + C + D),
   sat(E).

这有几个优点。首先,我们现在可以查询:

?- fun(A, B, C, D, E).
E = 1,
sat(A=\= ... # ... # B#B*C#B*C*D#B*D#C#C*D#D).

此答案显示E 必须为1 !如果我们使用labeling/1,那么这将更难以看到。

此外,在发布相关约束之后,我们可以使用sat_count/2,通过提供必须评估为真值的CLP(B)表达式作为第一个参数。

在我们的例子中,我们不希望对解决方案施加进一步的约束,因此我们将重言式指定为包含我们感兴趣的变量的第一个参数。一个合适的习惯用法是+[1|Vs]

所以,我们可以使用:

?- fun(A, B, C, D, E),
   sat_count(+[1,A,B,C,D,E], Count).
E = 1,
Count = 15,
sat(A=\= ... # ... # B#B*C#B*C*D#B*D#C#C*D#D).

摘要

在这种特定情况下,解决方案的数量非常少,两种方法之间几乎没有差异。

但是,在编写约束逻辑程序时,我想强调一个重要的一般原则:

  

优良作法是将核心关系与实际的搜索分开用于解决方案(labeling/1和类似的谓词,内置和手动编写)

如果您遵守这一原则,您可以单独研究约束的终止和传播。

此外,这允许您尝试不同的搜索策略,而无需重新编译您的程序!