-
Notifications
You must be signed in to change notification settings - Fork 0
/
DPLL.py
134 lines (121 loc) · 5.37 KB
/
DPLL.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
from copy import deepcopy
from functools import reduce
class DPLL:
def __init__(self, clauses, var_num):
self._var_num = var_num
self._clauses = deepcopy(clauses)
self._values = [None] * (var_num + 1)
self._is_clause_alive = [True] * len(clauses)
self._is_literal_alive = []
for clause in clauses:
self._is_literal_alive.append([True] * len(clause))
def _alive_clauses(self):
for clause_index in range(len(self._clauses)):
if not self._is_clause_alive[clause_index]:
continue
yield clause_index
def _alive_literals(self, clause_index):
for literal_index in range(len(self._clauses[clause_index])):
if not self._is_literal_alive[clause_index][literal_index]:
continue
yield literal_index
def solve(self):
return (True, self._values) if self._brute() else (False, None)
def add_clause(self, clause):
self._clauses.append(clause)
self._values = [None] * (self._var_num + 1)
self._is_clause_alive = [True] * len(self._clauses)
self._is_literal_alive = []
for clause in self._clauses:
self._is_literal_alive.append([True] * len(clause))
def _find_alone_literal(self):
for clause_index in self._alive_clauses():
candidate = 0
for literal_index in self._alive_literals(clause_index):
if candidate == 0:
candidate = self._clauses[clause_index][literal_index]
else:
candidate = 0
break
if candidate != 0:
return candidate
return 0
def _is_dead_propagation(self, literal):
for clause_index in self._alive_clauses():
if self._is_literal_alive[clause_index].count(True) == 1 and self._clauses[clause_index].count(
-literal) == 1:
return True
return False
def _rollback_propagation(self, literal, killed_clauses):
self._values[abs(literal)] = None
for clause_index in self._alive_clauses():
for literal_index in range(len(self._clauses[clause_index])):
if self._clauses[clause_index][literal_index] == -literal:
self._is_literal_alive[clause_index][literal_index] = True
for killed_clause in killed_clauses:
self._is_clause_alive[killed_clause] = True
def _propagate(self, literal):
self._values[abs(literal)] = literal > 0
killed_clauses = []
for clause_index in self._alive_clauses():
for literal_index in self._alive_literals(clause_index):
if self._clauses[clause_index][literal_index] == literal:
killed_clauses.append(clause_index)
self._is_clause_alive[clause_index] = False
break
if self._clauses[clause_index][literal_index] == -literal:
self._is_literal_alive[clause_index][literal_index] = False
break
return killed_clauses
def _find_homogenious_literal(self):
homogenity = [None] * (self._var_num + 1)
for clause_index in self._alive_clauses():
for literal_index in self._alive_literals(clause_index):
var = abs(self._clauses[clause_index][literal_index])
if homogenity[var] == 0:
continue
if homogenity[var] == None:
homogenity[var] = 1 if self._clauses[clause_index][literal_index] > 0 else -1
continue
if homogenity[var] * self._clauses[clause_index][literal_index] < 0:
homogenity[var] = 0
for var in range(1, self._var_num + 1):
if homogenity[var] == 1 or homogenity[var] == -1:
return var * homogenity[var]
return 0
def _find_any_var(self):
for clause_index in self._alive_clauses():
for literal_index in self._alive_literals(clause_index):
return self._clauses[clause_index][literal_index]
raise AssertionError("Illegal state: no alive var found")
def _brute(self):
if not any(self._is_clause_alive):
return True
alone_literal = self._find_alone_literal()
if alone_literal != 0:
if self._is_dead_propagation(alone_literal):
return False
killed_clauses = self._propagate(alone_literal)
if self._brute():
return True
else:
self._rollback_propagation(alone_literal, killed_clauses)
return False
homogenious_literal = self._find_homogenious_literal()
if homogenious_literal != 0:
killed_clauses = self._propagate(homogenious_literal)
if self._brute():
return True
else:
self._rollback_propagation(alone_literal, killed_clauses)
return False
any_var = self._find_any_var()
killed_clauses = self._propagate(-any_var)
if self._brute():
return True
self._rollback_propagation(-any_var, killed_clauses)
killed_clauses = self._propagate(any_var)
if self._brute():
return True
self._rollback_propagation(any_var, killed_clauses)
return False