-
Notifications
You must be signed in to change notification settings - Fork 0
/
dimacs.py
170 lines (121 loc) · 4.79 KB
/
dimacs.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
from common import CNFFormula
from StringIO import StringIO
# The number of assignments per "v" group in the DIMACS output
DIMACS_SOLUTION_WRAP = 10
def parseDIMACSHeader(inputFile):
crtLine = inputFile.readline()
# Return a None header at EOF
if len(crtLine) == 0:
return (None, None)
crtLine = crtLine.strip() # Remove the surrounding whitespace
# Return an empty header for blank lines
if len(crtLine) == 0:
return ("", None)
lineTokens = crtLine.split(None, 1)
assert len(lineTokens) == 2, "Invalid DIMACS header format"
assert len(lineTokens[0]) == 1, "Invalid DIMACS header format"
return (lineTokens[0], lineTokens[1])
def parseDIMACSFormula(inputFile):
varCount = 0
clauseCount = 0
# Parsing the header
while True:
(hType, hContents) = parseDIMACSHeader(inputFile)
if hType == "c":
pass # Ignore the comments, for now
elif hType == "p":
formatTokens = hContents.split()
assert len(formatTokens) == 3, "Invalid formula format specifications"
assert formatTokens[0] == "cnf", "Invalid formula format - cnf is requested"
varCount = int(formatTokens[1])
clauseCount = int(formatTokens[2])
break
else:
#Ignore any additional header, but don't accept EOF
assert hType is not None, "Invalid formula format"
# Read up until the end of the file, and parse the contents
clauseText = inputFile.read()
clauseTokens = clauseText.split()
clauseData = [int(tok) for tok in clauseTokens]
formula = CNFFormula(varCount)
crtClause = []
for elem in clauseData:
if elem == 0:
assert len(crtClause) > 0, "Only non-empty clauses allowed"
formula.clauses.append(crtClause)
crtClause = []
else:
negate = False
if elem < 0:
negate = True
elem = -elem
assert elem <= varCount, "Gaps in the variable numbering not allowed"
crtClause.append((elem, negate))
assert len(crtClause) == 0, "Unterminated clause encountered"
assert len(formula.clauses) == clauseCount, "Clause count inconsistency"
return formula
def parseDIMACSSolution(inputFile):
solution = []
sat = None # We don't know yet
while True:
(hType, hContents) = parseDIMACSHeader(inputFile)
if hType == "s":
if hContents == "UNSATISFIABLE":
sat = False
else:
assert hContents == "SATISFIABLE", "Invalid satisfiability solution"
sat = True
elif hType == "v":
dataValues = [int(tok) for tok in hContents.split()]
for x in dataValues:
if x == 0:
pass
elif x > 0:
solution.append((x, False))
else:
solution.append((-x, True))
elif hType is None:
break
# At this point the end of the response was reached, and we expect
# a clear answer
assert sat is not None, "Incomplete answer"
if sat:
assert len(solution) > 0, "Inconsistent results"
return solution
def emitDIMACSFormula(outputFile, formula, comments=None):
if comments is not None:
for comment in comments:
outputFile.write("c %s\n" % comment)
outputFile.write("p cnf %d %d\n" % (formula.varCount, len(formula.clauses)) )
for clause in formula.clauses:
for lit in clause:
value = lit[0]
if lit[1]:
value = -value
outputFile.write("%d " % value)
outputFile.write("0\n")
def emitDIMACSSolution(outputFile, solution):
if len(solution) == 0:
outputFile.write("s UNSATISFIABLE\n")
return
outputFile.write("s SATISFIABLE\n")
wrapCounter = 0
for elem in solution:
value = elem[0]
if elem[1]:
value = -value
if wrapCounter == 0:
outputFile.write("v ")
outputFile.write("%d " % value)
wrapCounter = (wrapCounter + 1) % DIMACS_SOLUTION_WRAP
if wrapCounter == 0:
outputFile.write("\n")
if wrapCounter == 0:
outputFile.write("v ")
outputFile.write("0\n")
def getDIMACSFormula(formula, comments=None):
strFile = StringIO()
emitDIMACSFormula(strFile, formula, comments)
dimacsFormula = strFile.getvalue()
strFile.close()
return dimacsFormula