4

在学习 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?

4

3 回答 3

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).

例子:

?- cnf(X, Y, Z).
X = true,
Y = true,
Z = true .

编辑:正如@repeat 所解释的,还要认真看看 CLP(B): Constraint Solveving over Booleans。

使用 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).

请参阅@repeat 的答案以获取有关此的更多信息。

于 2011-02-26T23:17:27.770 回答
2

在 Prolog 中查找“精益定理证明器”(例如leanTAPleanCoP)以获得简单、简短的定理证明器。这些设计旨在最大限度地利用 Prolog 功能。尽管像这样的证明者使用一阶逻辑,但 CNF 是其中的一个子集。Prolog 也有专门的 SAT 求解器,例如这个

于 2011-02-26T21:44:08.070 回答
2

使用

:- use_module ( library(clpb) )。

要检查某个布尔表达式是否可满足,请使用: sat/1

% OP: “(!x||y||!z) && (x||!y||z) && (x||y||z) && (!x||!y||z)”
?-((~X + Y + ~Z)*(X + ~Y + Z)*(X + Y + Z)*(~X + ~Y + Z))。
坐(X=\=X*Y#Z)。

还没有具体的解决方案......但是一个比我们开始的术语简单得多的残留物!

要获得具体的真值,请使用labeling/1

?- sat (X=\=X*Y#Z),标记([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。
于 2015-11-12T18:11:48.647 回答