布尔公式的强力Prolog SAT解算器
我试图编写一个算法,天真地寻找布尔公式(NNF,但不是CNF)的模型 我的代码可以检查现有的模型,但当要求查找模型时,它将失败(或无法完成),这似乎是因为它为布尔公式的强力Prolog SAT解算器,prolog,sat,clpb,Prolog,Sat,Clpb,我试图编写一个算法,天真地寻找布尔公式(NNF,但不是CNF)的模型 我的代码可以检查现有的模型,但当要求查找模型时,它将失败(或无法完成),这似乎是因为它为成员(X,Y)生成了无限多的解决方案,其思路是[X |.],\ux,X |.],\uu,X,X |]… 到目前为止,我得到的是: :- op(100, fy, ~). :- op(200, xfx, /\). :- op(200, xfx, \/). :- op(300, xfx, =>). :- op(300,
成员(X,Y)
生成了无限多的解决方案,其思路是[X |.],\ux,X |.],\uu,X,X |]…
到目前为止,我得到的是:
:- op(100, fy, ~).
:- op(200, xfx, /\).
:- op(200, xfx, \/).
:- op(300, xfx, =>).
:- op(300, xfx, <=>).
formula(X) :- atom(X).
formula(~X) :- formula(X).
formula(X /\ Y) :- formula(X), formula(Y).
formula(X \/ Y) :- formula(X), formula(Y).
formula(X => Y) :- formula(X), formula(Y).
formula(X <=> Y) :- formula(X), formula(Y).
model(1, _).
model(X, F) :- atom(X), member([X, 1], F).
model(~X, F) :- atom(X), member([X, 0], F). % NNF
model(A /\ B, F) :- model(A, F), model(B, F).
model(A \/ B, F) :- (model(A, F); model(B, F)).
model(A => B, F) :- model(~A \/ B, F).
model(A <=> B, F) :- model((A => B) /\ (B => A), F).
sat(A) :- model(A, F), \+ (member([X, 1], F), member([X, 0], F)).
%%% examples:
% formula(~(~ (a /\ b) \/ (c => d))).
% model(a, [[a,1]]).
:-op(100,fy,~)。
:-op(200,xfx,/\)。
:-op(200,xfx,\/)。
:-op(300,xfx,=>)。
:-op(300,xfx,)。
式(X):-原子(X)。
公式(~X):-公式(X)。
公式(X/\Y):-公式(X),公式(Y)。
公式(X\/Y):-公式(X),公式(Y)。
公式(X=>Y):-公式(X),公式(Y)。
公式(xy):-公式(X),公式(Y)。
模型(1,1)。
模型(X,F):-原子(X),成员([X,1],F)。
模型(~X,F):-原子(X),成员([X,0],F)。%NNF
模型(A/\B,F):-模型(A,F),模型(B,F)。
模型(A\/B,F):-(模型(A,F);模型(B,F))。
模型(A=>B,F):-model(~A\/B,F)。
模型(ab,F):-model((A=>B)/\(B=>A),F)。
sat(A):-模型(A,F),\+(成员([X,1],F),成员([X,0],F))。
%%%示例:
%公式((~(a/\b)\/(c=>d)))。
%模型(a,[[a,1]])。
对于F
,是否有更好的数据结构,或者以其他方式切断部分实例化的列表
编辑:添加了定义和示例。我通过编写一个
generate\u model
谓词解决了这个问题,该谓词创建了一个预定义列表,每个变量只有一个元素:
generate_model([], []).
generate_model([X|T], [[X,_]|T2]) :- generate_model(T, T2).
sat(A) :-
var_list(A, Vars),
generate_model(Vars, F),
model(A, F).
使用强>
:- use_module(library(clpb)).
一些变量(A
和B
)已经绑定到一个布尔值(在上面的查询中),但搜索尚未完成(由剩余目标指示)
要触发所有解决方案的智能暴力枚举,请如下所示:
?sat(~(A*B)+(C*D)),([A,B,C,D])。
A=B,B=1,C=D,D=0
; A=B,B=D,D=1,C=0
; A=B,B=C,C=1,D=0。
我是否了解你,你对单一型号感到满意。你 不需要贴标签或计数。这里有一个替代方案,与您的类似,但只返回一致的模型 因为它可以找到计数器模型,所以您需要提供公式的否定式来找到模型。谓词迷宫/3是作为肯定谓词证明/2的否定实现开发的:
% Find a counter model.
% maze(+Norm,+List,-List)
maze(or(A,_),L,_) :- member(A,L), !, fail.
maze(or(A,B),L,R) :- !, inv(A,C), maze(B,[C|L],R).
maze(and(A,_),L,R) :- maze(A,L,R), !.
maze(and(_,B),L,R) :- !, maze(B,L,R).
maze(A,L,_) :- member(A,L), !, fail.
maze(A,L,M) :- oneof(L,B,R), connective(B), !,
inv(A,C), inv(B,D), maze(D,[C|R],M).
maze(A,L,[B|L]) :- inv(A,B).
它可以找到以下所有谬误的对应模型:
Affirming a Disjunct: (p v q) & p => ~q.
Affirming the Consequent: (p => q) & q => p.
Commutation of Conditionals: (p => q) => (q => p).
Denying a Conjunct: ~(p & q) & ~p => q.
Denying the Antecedent: (p => q) & ~p => ~q.
Improper Transposition: (p => q) => (~p => ~q).
下面是一个运行示例:
Jekejeke Prolog 2, Runtime Library 1.2.5
(c) 1985-2017, XLOG Technologies GmbH, Switzerland
?- negcase(_,N,F), norm(F,G), maze(G,[],L),
write(N), write(': '), sort(L,R), write(R), nl, fail; true.
Affirming a Disjunct: [pos(p),pos(q)]
Affirming the Consequent: [neg(p),pos(q)]
Commutation of Conditionals: [neg(p),pos(q)]
Denying a Conjunct: [neg(p),neg(q)]
Denying the Antecedent: [neg(p),pos(q)]
Improper Transposition: [neg(p),pos(q)]
有趣的是,这比中电(B)快得多。以下是在CLP(B)和迷宫中运行相同问题的一些计时:
?- time((between(1,1000,_), negcaseclp(_,N,F,L),
sat(~F), once(labeling(L)), fail; true)).
% Up 296 ms, GC 3 ms, Thread Cpu 250 ms (Current 01/27/18 00:34:20)
Yes
?- time((between(1,1000,_), negcase(_,_,F),
norm(F,G), maze(G,[],_), fail; true)).
% Up 82 ms, GC 0 ms, Thread Cpu 78 ms (Current 01/27/18 00:30:21)
Yes
DanielLyons说:“我觉得生成模型很像,我是不是遗漏了什么?”。我同意。是的<代码>术语变量/2加上一些合适的
地图列表/3
。。。直接使用逻辑变量会更惯用(而且很可能更快)。另外,它还可以防止使用F
像[[x,0],[x,1],…]
(这很糟糕!)哦,太好了!虽然在这种特殊情况下,公式本身并不包含真正的Prolog变量,但每个“变量”都由一个原子项(通常是字符串)表示。然后,我的var\u list
谓词列出唯一原子的方式与term\u variables
列出变量的方式相同。是的,我想逻辑变量在这种情况下会更好——但我们正在做的大部分工作是符号操作,而不是求值。我需要它来自动检查Equisatisfability,以验证某些Tseytin实现的正确性。如果您的语义与Prolog的足够相似,您可以允许它为您执行提升操作。:)请使您的代码自包含,以便其他人可以实际尝试。抱歉,我在代码的其余部分进行了编辑。关于表示法的一条注释:您知道每个这样的列表正好有2个元素。在这种情况下,最好使用诸如x=0
,x=1
这样的术语来更简洁地表示绑定:[x,0]
是(x,.(0,[])
,为每个这样的结构浪费一个额外的函子/2
和一个原子[/code>。相反,x=0
是=(x,0)
,即只有一个函子和它的两个参数。不过,正如其他人所说的,您可以使用实际的逻辑变量来轻松地将绑定委托给Prolog。您可以存储符号/变量对应关系,而不是变量/值对应关系!
Jekejeke Prolog 2, Runtime Library 1.2.5
(c) 1985-2017, XLOG Technologies GmbH, Switzerland
?- negcase(_,N,F), norm(F,G), maze(G,[],L),
write(N), write(': '), sort(L,R), write(R), nl, fail; true.
Affirming a Disjunct: [pos(p),pos(q)]
Affirming the Consequent: [neg(p),pos(q)]
Commutation of Conditionals: [neg(p),pos(q)]
Denying a Conjunct: [neg(p),neg(q)]
Denying the Antecedent: [neg(p),pos(q)]
Improper Transposition: [neg(p),pos(q)]
?- time((between(1,1000,_), negcaseclp(_,N,F,L),
sat(~F), once(labeling(L)), fail; true)).
% Up 296 ms, GC 3 ms, Thread Cpu 250 ms (Current 01/27/18 00:34:20)
Yes
?- time((between(1,1000,_), negcase(_,_,F),
norm(F,G), maze(G,[],_), fail; true)).
% Up 82 ms, GC 0 ms, Thread Cpu 78 ms (Current 01/27/18 00:30:21)
Yes