我正在使用序言,我有这个代码:
:- 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) 但我无法在没有错误的情况下实现它
计算解决方案数量的一种直接方法是生成它们,然后查看有多少。
比如你贴的这个程序,我们可以用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)。
这个答案表明一定E
是1!如果我们使用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
以及类似的谓词,内置的和手动编写的)分开是一种很好的做法。
如果您遵守这一原则,您可以孤立地研究约束的终止和传播。
此外,这允许您在不重新编译程序的情况下尝试不同的搜索策略!