使用Prolog解决CNF问题

ban*_*anx 4 prolog conjunctive-normal-form clpb

在学习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).
Run Code Online (Sandbox Code Playgroud)

有没有更简单,更直接的方法来解决使用这种声明性语言的CNF?

mat*_*mat 5

考虑使用内置的谓词true/0false/0直接,并使用顶级显示效果(独立的,而不是随后的几次write/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).
Run Code Online (Sandbox Code Playgroud)

例:

?- cnf(X, Y, Z).
X = true,
Y = true,
Z = true .
Run Code Online (Sandbox Code Playgroud)

编辑:正如@repeat解释的那样,也要认真看看CLP(B):约束解决布尔值.

使用CLP(B),您可以将上面的整个程序编写为:

:- use_module(library(clpb)).

cnf(X, Y, Z) :-
        sat(~X + Y + ~Z),
        sat(X + ~Y + Z),
        sat(X + Y + Z),
        sat(~X + ~Y + Z).
Run Code Online (Sandbox Code Playgroud)

有关此问题的更多信息,请参阅@repeat的答案.

  • 添加规则"false: - fail".如果你的系统还不支持false/0.GNU Prolog(1.4),YAP和SWI的最新开发版本都有它. (2认同)