Skip to content

Commit 9d23694

Browse files
committed
Initial Commit
0 parents  commit 9d23694

File tree

8 files changed

+213
-0
lines changed

8 files changed

+213
-0
lines changed

README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# SAT Solver using DPLL
2+
3+
This code was for assignment for the course **EE677: Foundations of VLSI CAD** at IIT Bombay. The code attempts to solve a satisfiabilty problem in Conjuctive Normal Form (CNF). If the problem is satisfiable, one possible solution is returned.
4+
5+
## Algorithm
6+
The code is written in Python 3, it might not be compatible with previous versions. I have used DPLL Algorithm to solve the SAT problem. The problem is defined in CNF form. The algorithm can be explained by the following pseudocode.
7+
8+
```python
9+
def solve_dpll(cnf)
10+
while(cnf has a unit clause {X}):
11+
delete clauses contatining {X}
12+
delete {!X} from all clauses
13+
if null clause exists:
14+
return False
15+
if CNF is null:
16+
return True
17+
select a literal {X}
18+
cnf1 = cnf + {X}
19+
cnf2 = cnf + {!X}
20+
return solve_dpll(cnf1)+solve_dpll(cnf2)
21+
```
22+
23+
## How to Use
24+
- Please write the CNF form problem in a text file in the following way.
25+
- For Example: (!B+A+!C)(B+A+!C)(!B+!A+!C)(B)(C) will be written as
26+
27+
```
28+
!B A !C
29+
B A !C
30+
!B !A !C
31+
B
32+
C
33+
```
34+
- Save it in \<filename\> (example input.txt).
35+
- Run the following command
36+
```bash
37+
python3 DPLL.py <filename>
38+
```
39+
```
40+
python3 DPLL.py input.txt
41+
```
42+
43+
44+
45+
46+
## Example
47+
For CNF = (!B+A+!C)(B+A+!C)(!B+!A+!C)(B)(C), we get
48+
```bash
49+
50+
CNF = (!B+A+!C)(B+A+!C)(!B+!A+!C)(B)(C)
51+
Units = ['C', 'B']
52+
CNF after unit propogation = (!A)(A)
53+
54+
CNF = (!A)(A)(A)
55+
Units = ['!A', 'A']
56+
CNF after unit propogation = ()
57+
Null clause found, backtracking...
58+
59+
CNF = (!A)(A)(!A)
60+
Units = ['!A', 'A']
61+
CNF after unit propogation = ()
62+
Null clause found, backtracking...
63+
64+
Reached starting node!
65+
Number of Splitss = 3
66+
Unit Propogations = 6
67+
68+
Result: UNSATISFIABLE
69+
70+
```

SATSolver.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import sys
2+
from copy import deepcopy
3+
4+
assign_true = set()
5+
assign_false = set()
6+
n_props, n_splits = 0, 0
7+
8+
9+
def print_cnf(cnf):
10+
s = ''
11+
for i in cnf:
12+
if len(i) > 0:
13+
s += '(' + i.replace(' ', '+') + ')'
14+
if s == '':
15+
s = '()'
16+
print(s)
17+
18+
19+
def solve(cnf, literals):
20+
print('\nCNF = ', end='')
21+
print_cnf(cnf)
22+
new_true = []
23+
new_false = []
24+
global assign_true, assign_false, n_props, n_splits
25+
assign_true = set(assign_true)
26+
assign_false = set(assign_false)
27+
n_splits += 1
28+
cnf = list(set(cnf))
29+
units = [i for i in cnf if len(i)<3]
30+
units = list(set(units))
31+
if len(units):
32+
for unit in units:
33+
n_props += 1
34+
if '!' in unit:
35+
assign_false.add(unit[-1])
36+
new_false.append(unit[-1])
37+
i = 0
38+
while True:
39+
if unit in cnf[i]:
40+
cnf.remove(cnf[i])
41+
i -= 1
42+
elif unit[-1] in cnf[i]:
43+
cnf[i] = cnf[i].replace(unit[-1], '').strip()
44+
i += 1
45+
if i >= len(cnf):
46+
break
47+
else:
48+
assign_true.add(unit)
49+
new_true.append(unit)
50+
i = 0
51+
while True:
52+
if '!'+unit in cnf[i]:
53+
cnf[i] = cnf[i].replace('!'+unit, '').strip()
54+
if ' ' in cnf[i]:
55+
cnf[i] = cnf[i].replace(' ', ' ')
56+
elif unit in cnf[i]:
57+
cnf.remove(cnf[i])
58+
i -= 1
59+
i += 1
60+
if i >= len(cnf):
61+
break
62+
print('Units =', units)
63+
print('CNF after unit propogation = ', end = '')
64+
print_cnf(cnf)
65+
66+
if len(cnf) == 0:
67+
return True
68+
69+
if sum(len(clause)==0 for clause in cnf):
70+
for i in new_true:
71+
assign_true.remove(i)
72+
for i in new_false:
73+
assign_false.remove(i)
74+
print('Null clause found, backtracking...')
75+
return False
76+
literals = [k for k in list(set(''.join(cnf))) if k.isalpha()]
77+
78+
x = literals[0]
79+
if solve(deepcopy(cnf)+[x], deepcopy(literals)):
80+
return True
81+
elif solve(deepcopy(cnf)+['!'+x], deepcopy(literals)):
82+
return True
83+
else:
84+
for i in new_true:
85+
assign_true.remove(i)
86+
for i in new_false:
87+
assign_false.remove(i)
88+
return False
89+
90+
91+
def dpll():
92+
global assign_true, assign_false, n_props, n_splits
93+
input_cnf = open(sys.argv[1], 'r').read()
94+
literals = [i for i in list(set(input_cnf)) if i.isalpha()]
95+
cnf = input_cnf.splitlines()
96+
if solve(cnf, literals):
97+
print('\nNumber of Splits =', n_splits)
98+
print('Unit Propogations =', n_props)
99+
print('\nResult: SATISFIABLE')
100+
print('Solution:')
101+
for i in assign_true:
102+
print('\t\t'+i, '= True')
103+
for i in assign_false:
104+
print('\t\t'+i, '= False')
105+
else:
106+
print('\nReached starting node!')
107+
print('Number of Splitss =', n_splits)
108+
print('Unit Propogations =', n_props)
109+
print('\nResult: UNSATISFIABLE')
110+
print()
111+
112+
if __name__=='__main__':
113+
dpll()

sampleCNF/7-20.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
!A B E
2+
A !B
3+
A !E
4+
!E D
5+
!C !F !B
6+
!E B
7+
!B F
8+
!B C

sampleCNF/input.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
A B C
2+
A !B C
3+
!A B !C
4+
!C

sampleCNF/output.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
B C !B
2+
C D !D
3+
!A !C !D

sampleCNF/sample1.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
!B A !C
2+
B A !C
3+
!B !A !C
4+
B
5+
C

sampleCNF/sample2.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
!A B
2+
!B !C
3+
C !D
4+
!D A
5+
A B !C

sampleCNF/sample3.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
A B !C !D
2+
D !C !A
3+
B C D
4+
C !D
5+
!A !B C

0 commit comments

Comments
 (0)