在学习Prolog时,我尝试编写解决CNF问题的程序(性能不是问题),所以我最终得到了以下代码来解决(!x||y||!z)&&(x||!y||z)&&(x||y||z)&&(!x||!y||z)
:
vx(t).
vx(f).
vy(t).
vy(f).
vz(t).
vz(f).
x(X) :- X=t; \+ X=f.
y(Y) :- Y=t; \+ Y=f.
z(Z) :- Z=t; \+ Z=f.
nx(X) :- X=f; \+ X=t.
ny(Y) :- Y=f; \+ Y=t.
nz(Z) :- Z=f; \+ Z=t.
cnf :-
(nx(X); y(Y); nz(Z)),
(x(X); ny(Y); z(Z)),
(x(X); y(Y); z(Z)),
(nx(X); ny(Y); z(Z)),
write(X), write(Y), write(Z).
使用这种声明性语言有没有更简单,更直接的方法来解决CNF?
答案 0 :(得分:5)
考虑直接使用内置谓词true/0
和false/0
,并使用顶层显示结果(独立地,而不是几个后续的write/1
调用,请考虑使用{{1} }):
format/2
示例:
boolean(true).
boolean(false).
cnf(X, Y, Z) :-
maplist(boolean, [X,Y,Z]),
(\+ X; Y ; \+ Z),
( X ; \+ Y ; Z),
( X ; Y ; Z),
( \+ X ; \+ Y ; Z).
编辑:正如@repeat解释的那样,还要认真看看CLP(B):约束解决布尔值。
使用CLP(B),您可以将上面的整个程序编写为:
?- cnf(X, Y, Z).
X = true,
Y = true,
Z = true .
请参阅@repeat的答案,了解更多相关信息。
答案 1 :(得分:2)
在Prolog中查找“精益定理证明”(例如leanTAP或leanCoP)以获得简单,简短的定理证明。这些旨在使用Prolog功能以获得最佳可能的优势。虽然这样的证明者使用一阶逻辑,但CNF是其中的一个子集。 Prolog也有专门的SAT求解器,例如this one。
答案 2 :(得分:2)
使用clpb!
:- use_module(library(clpb)).
要检查某个布尔表达式是否可满足,请使用 sat/1
:
% OP: "(!x||y||!z) && (x||!y||z) && (x||y||z) && (!x||!y||z)" ?- sat((~X + Y + ~Z)*(X + ~Y + Z)*(X + Y + Z)*(~X + ~Y + Z)). sat(X=\=X*Y#Z).
还没有具体的解决方案......但是比我们开始使用的术语更简单的残留物!
要获得具体的真值,请使用labeling/1
:
?- sat(X=\=X*Y#Z), labeling([X,Y,Z]). X = 0, Y = 0, Z = 1 ; X = 0, Y = 1, Z = 1 ; X = 1, Y = 0, Z = 0 ; X = 1, Y = 1, Z = 1.