如何在Prolog中将命题公式转换为析取范式(DNF)?

时间:2013-12-28 10:32:33

标签: prolog

我是Prolog的新手,我需要将真值表转换为析取正常形式。 我已经能够按照给出的真值表生成:

?- table(p or(q and not r) or not s or r).
[p,q,r,s] | (p or (q and not r) or not s or r) 

----------------------------------------------|

[0,0,0,0] | 1 |

[0,0,0,1] | 0 |

[0,0,1,0] | 1 |

[0,0,1,1] | 1 |

[0,1,0,0] | 1 |

[0,1,0,1] | 1 |

[0,1,1,0] | 1 |

[0,1,1,1] | 1 |

[1,0,0,0] | 1 |

[1,0,0,1] | 1 |

[1,0,1,0] | 1 |

[1,0,1,1] | 1 |

[1,1,0,0] | 1 |

[1,1,0,1] | 1 |

[1,1,1,0] | 1 |

[1,1,1,1] | 1 |

-----------------------------------------------

如果有人能帮助我从这张桌子上做出分离的正常形式,我会贬低它。

1 个答案:

答案 0 :(得分:0)

让我们实现一个通用的真值表评估器,转换为CDNF中的Prolog可评估公式,然后,通过definition,我们将分离每个小项:

:- 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而不是not / 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, ..., ...;..., ...;...;...)