Prolog SAT Solver

前端 未结 4 1688
独厮守ぢ
独厮守ぢ 2021-01-01 19:51

I\'m trying to build a simple Prolog SAT solver. My idea is that the user should enter the boolean formula to be solved in CNF (Conjuctive Normal Form) using Prolog lists, f

相关标签:
4条回答
  • 2021-01-01 20:19

    Sometimes the following coding is found. Clauses are
    represented by assigning distinct positive non-zero
    integers to propositional variables:

    x1 v .. v xn --> [x1, .. , xn]
    ~x           --> -x
    

    It seems that the following Prolog code works quite well:

    % 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([], []).
    

    Here is an example run for Joe Lehmanns test case:

    ?- sat([[1,-2],[-1,-2],[1,3]], X).
    X = [1,-2] ;
    X = [-1,-2,3] ;
    No
    

    Code inspired by https://gist.github.com/rla/4634264 .
    I guess it is a variant of the DPLL algorithm now.

    0 讨论(0)
  • 2021-01-01 20:21

    i wish i had my prolog interpreter in front of me... but why cant you write a rule like

    sat(Stmt) :-
      call(Stmt).
    

    and then you would invoke your example by doing (btw ; is or)

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

    maybe you need something to constrain that they are either true or false so add these rules...

    is_bool(true).
    is_bool(false).
    

    and querying

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

    BTW -- this impl simply would simply be doing a DFS to find satisfying terms. no smart heuristic or anything.

    0 讨论(0)
  • 2021-01-01 20:26

    One can use CLP(FD) to solve SAT. Just start with a CNF and then observe that a clause:

    x1 v .. v xn 
    

    Can be represented as a constraint:

    x1 + .. + xn #> 0
    

    Further for a negative literal:

    ~x
    

    Simply use:

    1-x
    

    You need to restrict the variables to the domain 0..1 and invoke labeling. As soon as labeling returns some value for the variables, you know that your original formula is satisfiable.

    Here is an example run, running the test of 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.
    

    Bye

    Constraint Logic Programming over Finite Domains
    http://www.swi-prolog.org/man/clpfd.html

    0 讨论(0)
  • 2021-01-01 20:30

    There is a wonderful paper by Howe and King about SAT Solving in (SICStus) Prolog (see http://www.soi.city.ac.uk/~jacob/solver/index.html).

    sat(Clauses, Vars) :- 
        problem_setup(Clauses), elim_var(Vars). 
    
    elim_var([]). 
    elim_var([Var | Vars]) :- 
        elim_var(Vars), (Var = true; Var = false). 
    
    problem_setup([]). 
    problem_setup([Clause | Clauses]) :- 
        clause_setup(Clause), 
        problem_setup(Clauses). 
    
    clause_setup([Pol-Var | Pairs]) :- set_watch(Pairs, Var, Pol). 
    
    set_watch([], Var, Pol) :- Var = Pol. 
    set_watch([Pol2-Var2 | Pairs], Var1, Pol1):- 
        watch(Var1, Pol1, Var2, Pol2, Pairs). 
    
    :- block watch(-, ?, -, ?, ?). 
    watch(Var1, Pol1, Var2, Pol2, Pairs) :- 
        nonvar(Var1) -> 
            update_watch(Var1, Pol1, Var2, Pol2, Pairs); 
            update_watch(Var2, Pol2, Var1, Pol1, Pairs). 
    
    update_watch(Var1, Pol1, Var2, Pol2, Pairs) :- 
        Var1 == Pol1 -> true; set_watch(Pairs, Var2, Pol2).
    

    The clauses are given in CNF like this:

    | ?- 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
    
    0 讨论(0)
提交回复
热议问题