@@ -14,18 +14,26 @@ class Clause():
14
14
A clause is a set of literals, either complemented or otherwise.
15
15
For example:
16
16
{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
18
29
"""
19
30
20
- def __init__ (self , no_of_literals , literals ):
31
+ def __init__ (self , literals ):
21
32
"""
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."
23
34
"""
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 )
29
37
30
38
def __str__ (self ):
31
39
"""
@@ -34,7 +42,7 @@ def __str__(self):
34
42
"""
35
43
clause = "{ "
36
44
for i in range (0 , self .no_of_literals ):
37
- clause += ( self .literals [i ] + " " )
45
+ clause += str ( list ( self .literals . keys ()) [i ]) + " "
38
46
if i != self .no_of_literals - 1 :
39
47
clause += ", "
40
48
clause += "}"
@@ -47,16 +55,16 @@ def assign(self, model):
47
55
"""
48
56
i = 0
49
57
while i < self .no_of_literals :
50
- symbol = self .literals [i ][:2 ]
58
+ symbol = list ( self .literals . keys ()) [i ][:2 ]
51
59
if symbol in model .keys ():
52
60
val = model [symbol ]
53
61
else :
54
62
i += 1
55
63
continue
56
64
if val != None :
57
- if self .literals [i ][- 1 ] == "'" :
65
+ if list ( self .literals . keys ()) [i ][- 1 ] == "'" :
58
66
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
60
68
i += 1
61
69
62
70
def evaluate (self , model ):
@@ -68,24 +76,24 @@ def evaluate(self, model):
68
76
3. Return None(unable to complete evaluation) if a literal has no assignment.
69
77
4. Compute disjunction of all values assigned in clause.
70
78
"""
71
- for l in self .literals :
79
+ for l in list ( self .literals . keys ()) :
72
80
if len (l ) == 2 :
73
81
symbol = l + "'"
74
- if symbol in self .literals :
82
+ if symbol in list ( self .literals . keys ()) :
75
83
return True
76
84
else :
77
85
symbol = l [:2 ]
78
- if symbol in self .literals :
86
+ if symbol in list ( self .literals . keys ()) :
79
87
return True
80
88
81
89
self .assign (model )
82
90
result = False
83
- for j in self .literal_values .values ():
91
+ for j in self .literals .values ():
84
92
if j == True :
85
93
return True
86
94
elif j == None :
87
95
return None
88
- for j in self .literal_values .values ():
96
+ for j in self .literals .values ():
89
97
result = result or j
90
98
return result
91
99
@@ -95,13 +103,21 @@ class Formula():
95
103
A formula is a set of clauses.
96
104
For example,
97
105
{{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 } }
98
114
"""
99
- def __init__ (self , no_of_clauses , clauses ):
115
+ def __init__ (self , clauses ):
100
116
"""
101
117
Represent the number of clauses and the clauses themselves.
102
118
"""
103
- self .no_of_clauses = no_of_clauses
104
119
self .clauses = [c for c in clauses ]
120
+ self .no_of_clauses = len (self .clauses )
105
121
106
122
def __str__ (self ):
107
123
"""
@@ -137,7 +153,7 @@ def generate_clause():
137
153
else :
138
154
literals .append (var_name )
139
155
i += 1
140
- clause = Clause (no_of_literals , literals )
156
+ clause = Clause (literals )
141
157
return clause
142
158
143
159
def generate_formula ():
@@ -154,7 +170,7 @@ def generate_formula():
154
170
else :
155
171
clauses .append (clause )
156
172
i += 1
157
- formula = Formula (no_of_clauses , clauses )
173
+ formula = Formula (set ( clauses ) )
158
174
return formula
159
175
160
176
def generate_parameters (formula ):
@@ -165,11 +181,21 @@ def generate_parameters(formula):
165
181
Symbol of A3 is A3.
166
182
Symbol of A5' is A5.
167
183
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']
168
194
"""
169
195
clauses = formula .clauses
170
196
symbols_set = []
171
197
for clause in formula .clauses :
172
- for literal in clause .literals :
198
+ for literal in clause .literals . keys () :
173
199
symbol = literal [:2 ]
174
200
if symbol not in symbols_set :
175
201
symbols_set .append (symbol )
@@ -185,6 +211,17 @@ def find_pure_symbols(clauses, symbols, model):
185
211
1. Ignore clauses that have already evaluated to be True.
186
212
2. Find symbols that occur only in one form in the rest of the clauses.
187
213
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}
188
225
"""
189
226
pure_symbols = []
190
227
assignment = dict ()
@@ -193,7 +230,7 @@ def find_pure_symbols(clauses, symbols, model):
193
230
for clause in clauses :
194
231
if clause .evaluate (model ) == True :
195
232
continue
196
- for l in clause .literals :
233
+ for l in clause .literals . keys () :
197
234
literals .append (l )
198
235
199
236
for s in symbols :
@@ -220,21 +257,34 @@ def find_unit_clauses(clauses, model):
220
257
1. Find symbols that are the only occurences in a clause.
221
258
2. Find symbols in a clause where all other literals are assigned to be False.
222
259
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}
223
273
"""
224
274
unit_symbols = []
225
275
for clause in clauses :
226
276
if clause .no_of_literals == 1 :
227
- unit_symbols .append (clause .literals [0 ])
277
+ unit_symbols .append (list ( clause .literals . keys ()) [0 ])
228
278
else :
229
279
Fcount , Ncount = 0 , 0
230
- for l ,v in clause .literal_values .items ():
280
+ for l ,v in clause .literals .items ():
231
281
if v == False :
232
282
Fcount += 1
233
283
elif v == None :
234
284
sym = l
235
285
Ncount += 1
236
286
if Fcount == clause .no_of_literals - 1 and Ncount == 1 :
237
- unit .append (sym )
287
+ unit_symbols .append (sym )
238
288
assignment = dict ()
239
289
for i in unit_symbols :
240
290
symbol = i [:2 ]
@@ -246,14 +296,27 @@ def find_unit_clauses(clauses, model):
246
296
247
297
return unit_symbols , assignment
248
298
249
- def DPLL (clauses , symbols , model ):
299
+ def dpll_algorithm (clauses , symbols , model ):
250
300
"""
251
301
Returns the model if the formula is satisfiable, else None
252
302
This has the following steps:
253
303
1. If every clause in clauses is True, return True.
254
304
2. If some clause in clauses is False, return False.
255
305
3. Find pure symbols.
256
306
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}
257
320
"""
258
321
check_clause_all_true = True
259
322
for clause in clauses :
@@ -278,7 +341,7 @@ def DPLL(clauses, symbols, model):
278
341
tmp_symbols = [i for i in symbols ]
279
342
if P in tmp_symbols :
280
343
tmp_symbols .remove (P )
281
- return DPLL (clauses , tmp_symbols , tmp_model )
344
+ return dpll_algorithm (clauses , tmp_symbols , tmp_model )
282
345
283
346
unit_symbols , assignment = find_unit_clauses (clauses , model )
284
347
P = None
@@ -290,25 +353,27 @@ def DPLL(clauses, symbols, model):
290
353
tmp_symbols = [i for i in symbols ]
291
354
if P in tmp_symbols :
292
355
tmp_symbols .remove (P )
293
- return DPLL (clauses , tmp_symbols , tmp_model )
356
+ return dpll_algorithm (clauses , tmp_symbols , tmp_model )
294
357
P = symbols [0 ]
295
358
rest = symbols [1 :]
296
359
tmp1 , tmp2 = model , model
297
360
tmp1 [P ], tmp2 [P ] = True , False
298
361
299
- return DPLL (clauses , rest , tmp1 ) or DPLL (clauses , rest , tmp2 )
362
+ return dpll_algorithm (clauses , rest , tmp1 ) or dpll_algorithm (clauses , rest , tmp2 )
300
363
301
364
if __name__ == "__main__" :
302
- #import doctest
303
- #doctest.testmod()
365
+ import doctest
366
+ doctest .testmod ()
367
+
304
368
formula = generate_formula ()
305
- print (formula )
369
+ print (f'The formula { formula } is' , end = " " )
306
370
307
371
clauses , symbols = generate_parameters (formula )
308
372
309
- solution , model = DPLL (clauses , symbols , {})
373
+ solution , model = dpll_algorithm (clauses , symbols , {})
310
374
311
375
if solution :
376
+ print (" satisfiable with the assignment: " )
312
377
print (model )
313
378
else :
314
- print ("Not satisfiable" )
379
+ print (" not satisfiable" )
0 commit comments