Prolog SAT解算器

Prolog SAT解算器,prolog,boolean-logic,clpb,Prolog,Boolean Logic,Clpb,我正在尝试构建一个简单的Prolog SAT解算器。我的想法是,用户应该使用Prolog列表输入要在CNF(共轭范式)中求解的布尔公式,例如(A或B)和(B或C)应该表示为sat([[A,B],[B,C]]),Prolog程序可以找到A,B,C的值 我下面的代码不起作用,我不明白为什么。在trace调用的这一行:(7)sat([[true,true]])?我期待着start\u solve\u子句([[u G609,[u G612]]) 免责声明:对于几天前我甚至不知道的有关Prolog或SAT

我正在尝试构建一个简单的Prolog SAT解算器。我的想法是,用户应该使用Prolog列表输入要在CNF(共轭范式)中求解的布尔公式,例如(A或B)和(B或C)应该表示为sat([[A,B],[B,C]]),Prolog程序可以找到A,B,C的值

我下面的代码不起作用,我不明白为什么。在trace调用的这一行:(7)sat([[true,true]])?我期待着start\u solve\u子句([[u G609,[u G612]])

免责声明:对于几天前我甚至不知道的有关Prolog或SAT问题的蹩脚代码,我深表歉意

p.S.:关于解决SAT的建议是受欢迎的

跟踪

sat([[X, Y, Z], [X, Y]]).
Call: (6) sat([[_G609, _G612, _G615], [_G609, _G612]]) ? creep
Call: (7) start_solve_clause([_G609, _G612, _G615]) ? creep
Call: (8) solve_clause([_G615], _G726) ? creep
Call: (9) or(_G725, _G615, true) ? creep
Exit: (9) or(true, true, true) ? creep
Exit: (8) solve_clause([true], true) ? creep
Call: (8) or(_G609, _G612, true) ? creep
Exit: (8) or(true, true, true) ? creep
Exit: (7) start_solve_clause([true, true, true]) ? creep
Call: (7) sat([[true, true]]) ?  
% Knowledge base
or(true, true, true).
or(false, false, false).
or(true, false, true).
or(false, true, true).

or(not(true), true, true).
or(not(false), false, true).
or(not(true), false, false).
or(not(false), true, true).

or(true, not(true), true).
or(false, not(false), true).
or(true, not(false), true).
or(false, not(true), false).

% SAT solver
sat([]).
sat([Clause | Tail]) :- start_solve_clause(Clause), sat(Tail).

% Clause solver
start_solve_clause([Var1, Var2 | Tail]) :- solve_clause(Tail, Result), or(Var1, Var2, Result).

solve_clause([X | []], Result) :- or(Result, X, true).
solve_clause([X | Tail], Result) :- solve_clause(Tail, Result2), or(Result, X, Result2).
序言源代码

sat([[X, Y, Z], [X, Y]]).
Call: (6) sat([[_G609, _G612, _G615], [_G609, _G612]]) ? creep
Call: (7) start_solve_clause([_G609, _G612, _G615]) ? creep
Call: (8) solve_clause([_G615], _G726) ? creep
Call: (9) or(_G725, _G615, true) ? creep
Exit: (9) or(true, true, true) ? creep
Exit: (8) solve_clause([true], true) ? creep
Call: (8) or(_G609, _G612, true) ? creep
Exit: (8) or(true, true, true) ? creep
Exit: (7) start_solve_clause([true, true, true]) ? creep
Call: (7) sat([[true, true]]) ?  
% Knowledge base
or(true, true, true).
or(false, false, false).
or(true, false, true).
or(false, true, true).

or(not(true), true, true).
or(not(false), false, true).
or(not(true), false, false).
or(not(false), true, true).

or(true, not(true), true).
or(false, not(false), true).
or(true, not(false), true).
or(false, not(true), false).

% SAT solver
sat([]).
sat([Clause | Tail]) :- start_solve_clause(Clause), sat(Tail).

% Clause solver
start_solve_clause([Var1, Var2 | Tail]) :- solve_clause(Tail, Result), or(Var1, Var2, Result).

solve_clause([X | []], Result) :- or(Result, X, true).
solve_clause([X | Tail], Result) :- solve_clause(Tail, Result2), or(Result, X, Result2).

我希望我前面有我的prolog解释器。。。但是为什么你不能写一条这样的规则呢

sat(Stmt) :-
  call(Stmt).
然后,您可以通过执行(顺便说一句)调用您的示例

也许你需要一些东西来约束它们是真是假,所以添加这些规则

is_bool(true).
is_bool(false).
和质疑

?- is_bool(A), is_bool(B), is_bool(C), sat(((A ; B), (B ; C))).

顺便说一句——这个impl只是在做一个DFS来寻找令人满意的术语。没有聪明的启发式或任何东西。

豪和金在(SICStus)序言中有一篇关于SAT求解的精彩论文(见)

条款在CNF中给出如下内容:

| ?- sat([[true-X,false-Y],[false-X,false-Y],[true-X,true-Z]],[X,Y,Z]).
 X = true,
 Y = false,
 Z = true ? ;
 X = false,
 Y = false,
 Z = true ? ;
 X = true,
 Y = false,
 Z = false ? ;
no
可以使用CLP(FD)解决SAT。只需从CNF开始 然后遵守以下条款:

x1 v .. v xn 
可以表示为约束:

x1 + .. + xn #> 0
对于负文本,进一步说明:

~x
只需使用:

1-x
您需要将变量限制为域0..1 并调用标签。一旦标签返回一些 对于变量值,您知道您的原始 公式是令人满意的

下面是一个运行示例,运行Joe Lehmann的测试:

Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 6.5.2)
Copyright (c) 1990-2013 University of Amsterdam, VU Amsterdam

?- use_module(library(clpfd)).

?- L = [X,Y,Z], L ins 0..1, X+1-Y #> 0, 1-X+1-Y #> 0, X+Z #> 0, label(L).
X = Y, Y = 0,
Z = 1 ;
X = 1,
Y = Z, Z = 0 ;
X = Z, Z = 1,
Y = 0.
再见

有限域上的约束逻辑编程

有时会发现以下编码。条款是
通过指定不同的正非零表示
命题变量的整数:

x1 v .. v xn --> [x1, .. , xn]
~x           --> -x
下面的Prolog代码似乎运行得很好:

% mem(+Elem, +List)
mem(X, [X|_]).
mem(X, [_|Y]) :-
    mem(X, Y).

% sel(+Elem, +List, -List)
sel(X, [X|Y], Y).
sel(X, [Y|Z], [Y|T]) :-
    sel(X, Z, T).

% filter(+ListOfList, +Elem, +Elem, -ListOfList)
filter([], _, _, []).
filter([K|F], L, M, [J|G]) :-
    sel(M, K, J), !,
    J \== [],
    filter(F, L, M, G).
filter([K|F], L, M, G) :-
    mem(L, K), !,
    filter(F, L, M, G).
filter([K|F], L, M, [K|G]) :-
    filter(F, L, M, G).

% sat(+ListOfLists, +List, -List)
sat([[L|_]|F], [L|V]):-
    M is -L,
    filter(F, L, M, G),
    sat(G, V).
sat([[L|K]|F], [M|V]):-
    K \== [],
    M is -L,
    filter(F, M, L, G),
    sat([K|G], V).
sat([], []).
以下是Joe Lehmanns测试用例的运行示例:

?- sat([[1,-2],[-1,-2],[1,3]], X).
X = [1,-2] ;
X = [-1,-2,3] ;
No
源于的代码。

我想这是now的一个变体。

而不是
sat(Stmt):-call(Stmt)。
您可以直接执行
sat(Stmt):-Stmt
。使用变量作为目标相当于使用变量作为参数调用/1。@arnsholt--ahhh,我不知道我为什么不这么做。那条sat/1的规则是多余的,我想它只是有一个好名字。非常好的建议!您还可以直接将SAT实例映射到整数上的约束问题,并使用SICStus、SWI和YAP中的示例库(clpfd)(以及GNU Prolog和B-Prolog等其他系统中的内置约束)来解决这些问题。约束解算器通常能够推断出更多的值,并且比这样一个简单的搜索(我不是说消极的!)执行得更快。SICStus还有一个专用的SAT约束求解器库(clpb)。@DaveEdelstein这个解决方案很有效,我一直在使用它。我一直在努力简化查询。我认为“is_bool(VAR),…,is_bool(AnotherVar),sat((子句);(AnotherClause))”查询对于具有许多变量的公式来说非常长。因此,我使用sat([ListOfVars],Stmnt)进行查询,然后prolog算法遍历变量列表,生成一个布尔值,缩短查询时间,并保持您想法的简单性。@Davidelstein关于此解决方案,我注意到的另一件事是,它多次重复相同的答案。例如,当查询is_bool(X)、is_bool(Y)、is_bool(Z)、sat(((X;Y)、(Y;Z))时。在给出另一个解决方案之前,它给出了X=true,Y=true,Z=true四次。也许在这里会有所帮助?上次我看triska的clp(b)时,我觉得它使用了另一种算法,即沿BDD(二进制决策图)的某种算法。这是一种代数方法,而不是一种更受逻辑启发的子句方法。