Skip to content

Commit be92721

Browse files
committed
Corrections complete
1 parent dde4611 commit be92721

File tree

1 file changed

+100
-35
lines changed

1 file changed

+100
-35
lines changed

other/dpll.py

Lines changed: 100 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,26 @@ class Clause():
1414
A clause is a set of literals, either complemented or otherwise.
1515
For example:
1616
{A1, A2, A3'} is the clause (A1 v A2 v A3')
17-
{A5', A2', A1} is the clause (A5' v A2' v A1)
17+
{A5', A2', A1} is the clause (A5' v A2' v A1)
18+
19+
Create a set of literals and a clause with them
20+
>>> literals = ["A1", "A2'", "A3"]
21+
>>> clause = Clause(literals)
22+
>>> print(clause)
23+
{ A1 , A2' , A3 }
24+
25+
Create model
26+
>>> model = {"A1": True}
27+
>>> clause.evaluate(model)
28+
True
1829
"""
1930

20-
def __init__(self, no_of_literals, literals):
31+
def __init__(self, literals):
2132
"""
22-
Represent the number of literals, the literals themselves, and an assignment in a clause."
33+
Represent the literals and an assignment in a clause."
2334
"""
24-
self.no_of_literals = no_of_literals
25-
self.literals = [l for l in literals]
26-
self.literal_values = dict()
27-
for l in self.literals:
28-
self.literal_values[l] = None # Assign all literals to None initially
35+
self.literals = {literal : None for literal in literals} # Assign all literals to None initially
36+
self.no_of_literals = len(self.literals)
2937

3038
def __str__(self):
3139
"""
@@ -34,7 +42,7 @@ def __str__(self):
3442
"""
3543
clause = "{ "
3644
for i in range(0, self.no_of_literals):
37-
clause += (self.literals[i] + " ")
45+
clause += str(list(self.literals.keys())[i]) + " "
3846
if i != self.no_of_literals - 1:
3947
clause += ", "
4048
clause += "}"
@@ -47,16 +55,16 @@ def assign(self, model):
4755
"""
4856
i = 0
4957
while i < self.no_of_literals:
50-
symbol = self.literals[i][:2]
58+
symbol = list(self.literals.keys())[i][:2]
5159
if symbol in model.keys():
5260
val = model[symbol]
5361
else:
5462
i += 1
5563
continue
5664
if val != None:
57-
if self.literals[i][-1] == "'":
65+
if list(self.literals.keys())[i][-1] == "'":
5866
val = not val #Complement assignment if literal is in complemented form
59-
self.literal_values[self.literals[i]] = val
67+
self.literals[list(self.literals.keys())[i]] = val
6068
i += 1
6169

6270
def evaluate(self, model):
@@ -68,24 +76,24 @@ def evaluate(self, model):
6876
3. Return None(unable to complete evaluation) if a literal has no assignment.
6977
4. Compute disjunction of all values assigned in clause.
7078
"""
71-
for l in self.literals:
79+
for l in list(self.literals.keys()):
7280
if len(l) == 2:
7381
symbol = l + "'"
74-
if symbol in self.literals:
82+
if symbol in list(self.literals.keys()):
7583
return True
7684
else:
7785
symbol = l[:2]
78-
if symbol in self.literals:
86+
if symbol in list(self.literals.keys()):
7987
return True
8088

8189
self.assign(model)
8290
result = False
83-
for j in self.literal_values.values():
91+
for j in self.literals.values():
8492
if j == True:
8593
return True
8694
elif j == None:
8795
return None
88-
for j in self.literal_values.values():
96+
for j in self.literals.values():
8997
result = result or j
9098
return result
9199

@@ -95,13 +103,21 @@ class Formula():
95103
A formula is a set of clauses.
96104
For example,
97105
{{A1, A2, A3'}, {A5', A2', A1}} is the formula ((A1 v A2 v A3') and (A5' v A2' v A1))
106+
107+
Create two clauses and a formula with them
108+
>>> c1 = Clause(["A1", "A2'", "A3"])
109+
>>> c2 = Clause(["A5'", "A2'", "A1"])
110+
111+
>>> f = Formula([c1, c2])
112+
>>> print(f)
113+
{ { A1 , A2' , A3 } , { A5' , A2' , A1 } }
98114
"""
99-
def __init__(self, no_of_clauses, clauses):
115+
def __init__(self, clauses):
100116
"""
101117
Represent the number of clauses and the clauses themselves.
102118
"""
103-
self.no_of_clauses = no_of_clauses
104119
self.clauses = [c for c in clauses]
120+
self.no_of_clauses = len(self.clauses)
105121

106122
def __str__(self):
107123
"""
@@ -137,7 +153,7 @@ def generate_clause():
137153
else:
138154
literals.append(var_name)
139155
i+=1
140-
clause = Clause(no_of_literals, literals)
156+
clause = Clause(literals)
141157
return clause
142158

143159
def generate_formula():
@@ -154,7 +170,7 @@ def generate_formula():
154170
else:
155171
clauses.append(clause)
156172
i += 1
157-
formula = Formula(no_of_clauses, clauses)
173+
formula = Formula(set(clauses))
158174
return formula
159175

160176
def generate_parameters(formula):
@@ -165,11 +181,21 @@ def generate_parameters(formula):
165181
Symbol of A3 is A3.
166182
Symbol of A5' is A5.
167183
184+
>>> c1 = Clause(["A1", "A2'", "A3"])
185+
>>> c2 = Clause(["A5'", "A2'", "A1"])
186+
187+
>>> f = Formula([c1, c2])
188+
>>> c, s = generate_parameters(f)
189+
>>> l = [str(i) for i in c]
190+
>>> print(l)
191+
["{ A1 , A2' , A3 }", "{ A5' , A2' , A1 }"]
192+
>>> print(s)
193+
['A1', 'A2', 'A3', 'A5']
168194
"""
169195
clauses = formula.clauses
170196
symbols_set = []
171197
for clause in formula.clauses:
172-
for literal in clause.literals:
198+
for literal in clause.literals.keys():
173199
symbol = literal[:2]
174200
if symbol not in symbols_set:
175201
symbols_set.append(symbol)
@@ -185,6 +211,17 @@ def find_pure_symbols(clauses, symbols, model):
185211
1. Ignore clauses that have already evaluated to be True.
186212
2. Find symbols that occur only in one form in the rest of the clauses.
187213
3. Assign value True or False depending on whether the symbols occurs in normal or complemented form respectively.
214+
215+
>>> c1 = Clause(["A1", "A2'", "A3"])
216+
>>> c2 = Clause(["A5'", "A2'", "A1"])
217+
218+
>>> f = Formula([c1, c2])
219+
>>> c, s = generate_parameters(f)
220+
221+
>>> model = {}
222+
>>> p, v = find_pure_symbols(c, s, model)
223+
>>> print(p, v)
224+
['A1', 'A2', 'A3', 'A5'] {'A1': True, 'A2': False, 'A3': True, 'A5': False}
188225
"""
189226
pure_symbols = []
190227
assignment = dict()
@@ -193,7 +230,7 @@ def find_pure_symbols(clauses, symbols, model):
193230
for clause in clauses:
194231
if clause.evaluate(model) == True:
195232
continue
196-
for l in clause.literals:
233+
for l in clause.literals.keys():
197234
literals.append(l)
198235

199236
for s in symbols:
@@ -220,21 +257,34 @@ def find_unit_clauses(clauses, model):
220257
1. Find symbols that are the only occurences in a clause.
221258
2. Find symbols in a clause where all other literals are assigned to be False.
222259
3. Assign True or False depending on whether the symbols occurs in normal or complemented form respectively.
260+
261+
>>> c1 = Clause(["A4", "A3", "A5'", "A1", "A3'"])
262+
>>> c2 = Clause(["A4"])
263+
>>> c3 = Clause(["A3"])
264+
265+
>>> f = Formula([c1, c2, c3])
266+
>>> c, s = generate_parameters(f)
267+
268+
>>> model = {}
269+
>>> u, v = find_unit_clauses(c, model)
270+
271+
>>> print(u, v)
272+
['A4', 'A3'] {'A4': True, 'A3': True}
223273
"""
224274
unit_symbols = []
225275
for clause in clauses:
226276
if clause.no_of_literals == 1:
227-
unit_symbols.append(clause.literals[0])
277+
unit_symbols.append(list(clause.literals.keys())[0])
228278
else:
229279
Fcount, Ncount = 0, 0
230-
for l,v in clause.literal_values.items():
280+
for l,v in clause.literals.items():
231281
if v == False:
232282
Fcount += 1
233283
elif v == None:
234284
sym = l
235285
Ncount += 1
236286
if Fcount == clause.no_of_literals - 1 and Ncount == 1:
237-
unit.append(sym)
287+
unit_symbols.append(sym)
238288
assignment = dict()
239289
for i in unit_symbols:
240290
symbol = i[:2]
@@ -246,14 +296,27 @@ def find_unit_clauses(clauses, model):
246296

247297
return unit_symbols, assignment
248298

249-
def DPLL(clauses, symbols, model):
299+
def dpll_algorithm(clauses, symbols, model):
250300
"""
251301
Returns the model if the formula is satisfiable, else None
252302
This has the following steps:
253303
1. If every clause in clauses is True, return True.
254304
2. If some clause in clauses is False, return False.
255305
3. Find pure symbols.
256306
4. Find unit symbols.
307+
308+
>>> c1 = Clause(["A4", "A3", "A5'", "A1", "A3'"])
309+
>>> c2 = Clause(["A4"])
310+
>>> c3 = Clause(["A3"])
311+
312+
>>> f = Formula([c1, c2, c3])
313+
>>> c, s = generate_parameters(f)
314+
315+
>>> model = {}
316+
>>> soln, model = dpll_algorithm(c, s, model)
317+
318+
>>> print(soln, model)
319+
True {'A4': True, 'A3': True}
257320
"""
258321
check_clause_all_true = True
259322
for clause in clauses:
@@ -278,7 +341,7 @@ def DPLL(clauses, symbols, model):
278341
tmp_symbols = [i for i in symbols]
279342
if P in tmp_symbols:
280343
tmp_symbols.remove(P)
281-
return DPLL(clauses, tmp_symbols, tmp_model)
344+
return dpll_algorithm(clauses, tmp_symbols, tmp_model)
282345

283346
unit_symbols, assignment = find_unit_clauses(clauses, model)
284347
P = None
@@ -290,25 +353,27 @@ def DPLL(clauses, symbols, model):
290353
tmp_symbols = [i for i in symbols]
291354
if P in tmp_symbols:
292355
tmp_symbols.remove(P)
293-
return DPLL(clauses, tmp_symbols, tmp_model)
356+
return dpll_algorithm(clauses, tmp_symbols, tmp_model)
294357
P = symbols[0]
295358
rest = symbols[1:]
296359
tmp1, tmp2 = model, model
297360
tmp1[P], tmp2[P] = True, False
298361

299-
return DPLL(clauses, rest, tmp1) or DPLL(clauses, rest, tmp2)
362+
return dpll_algorithm(clauses, rest, tmp1) or dpll_algorithm(clauses, rest, tmp2)
300363

301364
if __name__ == "__main__":
302-
#import doctest
303-
#doctest.testmod()
365+
import doctest
366+
doctest.testmod()
367+
304368
formula = generate_formula()
305-
print(formula)
369+
print(f'The formula {formula} is', end = " ")
306370

307371
clauses, symbols = generate_parameters(formula)
308372

309-
solution, model = DPLL(clauses, symbols, {})
373+
solution, model = dpll_algorithm(clauses, symbols, {})
310374

311375
if solution:
376+
print(" satisfiable with the assignment: ")
312377
print(model)
313378
else:
314-
print("Not satisfiable")
379+
print(" not satisfiable")

0 commit comments

Comments
 (0)