We can now implement resolution of two particular clauses as follows:
%% Cell type:code id:33fc6271 tags:
``` prolog
:-use_module(library(lists)).
resolve(Clause1,Clause2,Resolvent):-
select(Lit1,Clause1,R1),negate(Lit1,NLit1),
select(NLit1,Clause2,R2),
append(R1,R2,Resolvent).
```
%% Cell type:markdown id:1d426bb1 tags:
The above predicate uses the predicate ```select/3``` from ```library(lists)```, which can be used to select an element from a list and returns a modified list with the element removed:
As you can see, the number of new clauses can grow considerably when applying resolution.
Below we study the DPLL algorithm to check satisfiability of a formula in CNF, using a simple form of resolution (where one clause is a single literal and the other clauses comes from the CNF of the problem).
%% Cell type:markdown id:d32921c9 tags:
### DPLL Algorithm
We now present bit by bit the DPLL algorithm as a Prolog program
manipulating the above clause database.
The algorithm works by selecting a literal and then making it true and checking whether this leads to a solution.
If not, the algorithm backtracks and makes the negated version of the literal true and tries to find a solution.
%% Cell type:code id:26924712 tags:
``` prolog
becomes_true(TrueLit,Clause):-
member(TrueLit,Clause).
```
%% Cell type:markdown id:17dd1525 tags:
The above checks if making a given literal true makes the second argument, a clause, true (i.e., the clause is satisfied):
%% Cell type:code id:7d90c4ad tags:
``` prolog
?-becomes_true(pos(b),[neg(a),pos(b)]).
```
%% Output
%% Cell type:code id:d4b4e71f tags:
``` prolog
?-becomes_true(neg(a),[neg(a),pos(b)]).
```
%% Output
%% Cell type:markdown id:62e13b8d tags:
The code below simplifies a clause given a literal ```TrueLit``` that has just become true.
This is done using resolution:
%% Cell type:code id:3b9c87e4 tags:
``` prolog
simplify(TrueLit,Clause,SimplifedClause):-
negate(TrueLit,FalseLit),
delete(Clause,FalseLit,SimplifedClause).% Resolution with TrueLit if possible
```
%% Cell type:markdown id:e8cee74e tags:
The code uses the ```delete/3``` predicate from ```library(lists)```. Unlike select it also succeeds when the element is not in the list:
%% Cell type:code id:0abd90f6 tags:
``` prolog
?-delete([a,b,c],d,R).
```
%% Output
%% Cell type:code id:cc81b404 tags:
``` prolog
?-delete([a,b,c],a,R).
```
%% Output
%% Cell type:markdown id:53d21e85 tags:
The above code simplifies a clause by resolution:
%% Cell type:code id:57df05f0 tags:
``` prolog
?-simplify(pos(c),[pos(a),neg(c)],SC).
```
%% Output
%% Cell type:markdown id:4c3eae55 tags:
If no resolution is possible the clause is returned unchanged:
%% Cell type:code id:a36a54a4 tags:
``` prolog
?-simplify(pos(b),[pos(a),neg(c)],SC).
```
%% Output
%% Cell type:markdown id:441c4145 tags:
We can now define the whole procedure to set a literal ```Lit``` to true (```Clauses|{Lit}```) by
- removing all clauses which have become true (and no longer need to be checked)
- simplifying the remaining clauses with resolution if possible.
%% Cell type:code id:95fcf64b tags:
``` prolog
set_literal(Lit,Clauses,NewClauses):-
exclude(becomes_true(Lit),Clauses,Clauses2),
maplist(simplify(Lit),Clauses2,NewClauses).
```
%% Cell type:markdown id:f0a8731d tags:
The predicate ```exclude/3``` from ```library(lists)``` is a higher-order predicate. It maps its first argument (a predicate) over the second argument (a list) and excludes all elements where the predicate succeeds.
```exclude``` will perform these two calls and hence remove the second clause and keep the first one:
%% Cell type:code id:56175b0d tags:
``` prolog
?- becomes_true(pos(a),[neg(b)]).
?- becomes_true(pos(a),[pos(a),pos(c)]).
```
%% Output
%% Cell type:markdown id:52063b72 tags:
The predicate ```maplist/3``` from ```library(lists)``` is another higher-order predicate. It maps its first argument (a predicate) over the elements in the second and third arguments (both lists).