0

我正在使用序言,我有这个代码:

:- 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) 但我无法在没有错误的情况下实现它

4

1 回答 1

2

蛮力方法

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

比如你贴的这个程序,我们可以用findall/3下面的方法来获取答案:

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

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

选择:sat_count/2

使用 CLP(B),我们拥有sat_count/2您已经发现的。

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

使用的技巧sat_count/2避免,并以仅 发布约束labeling/1的方式编写您的核心关系。

例如:

有趣(A、B、C、D、E):-
   坐(A + B + C + D),
   饱和(E)。

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

?- 有趣(A、B、C、D、E)。
E = 1 ,
坐(A=\= ... # ... # B#B*C#B*C*D#B*D#C#C*D#D)。

这个答案表明一定E1!如果我们使用labeling/1,这会有点难以看到。

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

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

所以,我们可以使用:

?- 有趣(A、B、C、D、E),
   sat_count(+ [1,A,B,C,D,E],计数)。
E = 1,
计数 = 15 ,
坐(A=\= ... # ... # B#B*C#B*C*D#B*D#C#C*D#D)。

概括

在这种特定情况下,解决方案的数量是如此之少,以至于两种方法之间几乎没有区别。

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

将核心关系与解决方案的实际搜索labeling/1以及类似的谓词,内置的和手动编写的)分开是一种很好的做法。

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

此外,这允许您在不重新编译程序的情况下尝试不同的搜索策略!

于 2016-11-21T23:55:17.273 回答