如何在Prolog中将命题公式转换为析取范式(DNF)?
我是Prolog新手,我需要将结果从真值表转换为析取范式。 我已经能够生成如下所示的真值表:如何在Prolog中将命题公式转换为析取范式(DNF)?,prolog,Prolog,我是Prolog新手,我需要将结果从真值表转换为析取范式。 我已经能够生成如下所示的真值表: ?- table(p or(q and not r) or not s or r). [p,q,r,s]|(p或(q和非r)或非s或r)-------------------------------------------------------------[0,0,0,0]|1 |[0,0,0,1]|[0,0,1,0]|[0,0,1,1]|[0,1,0,0]|1 |[0,1,0,1]|[0,1,1,
?- table(p or(q and not r) or not s or r).
[p,q,r,s]|(p或(q和非r)或非s或r)-------------------------------------------------------------[0,0,0,0]|1 |[0,0,0,1]|[0,0,1,0]|[0,0,1,1]|[0,1,0,0]|1 |[0,1,0,1]|[0,1,1,0]|[0,1,1,1]|[1,0,0,0,0]|[1,0,0,1]|[1,0,0,1]|[1,0,1,0]|[1,0,1,1]|1 |[1,1,0,0]| 1 |[1,1,0,1]|[1,1,1,0]|[1,1,1,1]|-------------------------------------
如果有人能帮我把这个表转换成析取范式,我会很感激的。让我们实现一个通用真值表求值器,在中转换成Prolog可求值公式,然后,通过,我们将每个minterm分离:
:- op(900, fy, neg).
:- op(1000, xfy, and).
:- op(1100, xfy, or).
formula(p or (q and neg r) or neg s or r).
cnf(F, CNF) :-
setof(V, literal(F, V), Ls),
setof(La, T^(assign(Ls, La), translate(F, La, T), T), CNF).
literal((X or Y), L) :- literal(X,L) ; literal(Y,L).
literal((X and Y), L) :- literal(X,L) ; literal(Y,L).
literal(neg X, L) :- literal(X,L).
literal(L, L) :- atom(L).
assign(Ls, La) :- maplist(assign_literal, Ls, La).
assign_literal(L, L=true).
assign_literal(L, L=false).
translate((X or Y), Ls, (A;B)) :- translate(X, Ls, A), translate(Y, Ls, B).
translate((X and Y), Ls, (A,B)) :- translate(X, Ls, A), translate(Y, Ls, B).
translate(neg X, Ls, \+ A) :- translate(X, Ls, A).
translate(L, Ls, V) :- memberchk(L=V, Ls).
收益率:
?- formula(F),cnf(F,CNF),maplist(writeln,CNF).
[p=false,q=false,r=false,s=false]
[p=false,q=false,r=true,s=false]
[p=false,q=false,r=true,s=true]
[p=false,q=true,r=false,s=false]
[p=false,q=true,r=false,s=true]
[p=false,q=true,r=true,s=false]
[p=false,q=true,r=true,s=true]
[p=true,q=false,r=false,s=false]
[p=true,q=false,r=false,s=true]
[p=true,q=false,r=true,s=false]
[p=true,q=false,r=true,s=true]
[p=true,q=true,r=false,s=false]
[p=true,q=true,r=false,s=true]
[p=true,q=true,r=true,s=false]
[p=true,q=true,r=true,s=true]
F = or(p, or(and(q, neg(r)), or(neg(s), r))),
CNF = [[p=false, q=false, r=false, s=false], [p=false, q=false, r=true, s=false], [p=false, q=false, r=true, s=true], [p=false, q=true, r=false, s=false], [p=false, q=true, r=false, ... = ...], [p=false, q=true, ... = ...|...], [p=false, ... = ...|...], [... = ...|...], [...|...]|...].
抱歉,输出有点冗长。可根据进一步规格轻松定制
我使用了neg/1而不是/1(这已经是一个有效的Prolog操作符),只是为了明确区别
编辑
这里是一个简化,结果是一个语法概括。只更改了literal/2和translate/3,并添加了translate/2:
literal(F, L) :- F =.. [_,X,Y], (literal(X,L) ; literal(Y,L)).
literal(F, L) :- F =.. [_,X], literal(X,L).
literal(L, L) :- atom(L).
translate(and, (,)).
translate(or, (;)).
translate(neg, (\+)).
translate(F, Ls, T) :-
F =.. [S,X,Y],
translate(S,O),
T =.. [O,A,B],
translate(X, Ls, A), translate(Y, Ls, B).
translate(F, Ls, T) :-
F =.. [S,X],
translate(S,O),
T =.. [O,A],
translate(X, Ls, A).
translate(F, Ls, T) :- memberchk(F=T, Ls).
更多编辑
上面的代码可以更加高效,只需将翻译移出循环即可
cnf(F, CNF) :-
setof(V, literal(F, V), Ls),
translate(F, La, T),
setof(La, (assign(Ls, La), T), CNF).
最后一个translate/3子句中需要做一个小修改:使用member/2而不是memberchk
...
translate(F, Ls, T) :- member(F=T, Ls).
时间:与旧版本
4 ?- formula(F),time(cnf(F,CNF)).
% 1,788 inferences, 0.002 CPU in 0.002 seconds (98% CPU, 834727 Lips)
对于新的:
5 ?- formula(F),time(cnf(F,CNF)).
% 282 inferences, 0.001 CPU in 0.001 seconds (99% CPU, 315768 Lips)
大约好6倍
带memberchk的旧版本:
6 ?- formula(F),time(cnf(F,CNF)).
% 1,083 inferences, 0.002 CPU in 0.002 seconds (98% CPU, 561426 Lips)
好吧,还是差不多好4倍
编辑需要更多步骤才能获得真正的Prolog公式
cdnf(F, CNDF, Prolog) :-
cdnf(F, CNDF), % well, was cnf/2, I renamed to be more precise
maplist(cj, CNDF, CJs),
reverse(CJs, [H|T]),
foldl(dj, T, H, Prolog).
dj(A, B, (A;B)).
cj(A, J) :-
maplist(tf, A, B),
reverse(B, [H|T]),
foldl(cj, T, H, J).
cj(A, B, (A,B)).
tf(S=true,S).
tf(S=false,\+S).
现在,结果更有用了
?- formula(_,F), cdnf(F,_,P).
F = or(p, or(and(q, neg(r)), or(neg(s), r))),
P = (\+p, \+q, \+r, \+s;\+p, \+q, r, \+s;\+p, \+q, r, s;\+p, q, \+r, \+s;\+p, q, \+r, s;\+p, q, r, \+ ...;\+p, q, ..., ...;p, ..., ...;..., ...;...;...)
这并不容易,因为第一列中的所有值都等于0。为什么所有行都显示[0,0,0,0]?表/1应在符号列表下显示1/0。
?- formula(_,F), cdnf(F,_,P).
F = or(p, or(and(q, neg(r)), or(neg(s), r))),
P = (\+p, \+q, \+r, \+s;\+p, \+q, r, \+s;\+p, \+q, r, s;\+p, q, \+r, \+s;\+p, q, \+r, s;\+p, q, r, \+ ...;\+p, q, ..., ...;p, ..., ...;..., ...;...;...)