我正在使用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),但是我无法在没有错误的情况下实现它
答案 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
和类似的谓词,内置和手动编写)
如果您遵守这一原则,您可以单独研究约束的终止和传播。
此外,这允许您尝试不同的搜索策略,而无需重新编译您的程序!