I am very new to SAT and Z3 (Have not even started with SMT yet). I have been playing around with gophersat (A nice Go implementation which works for a good set of SAT problems) and I discovered DIMACS format there. Although I agree that it is not the best way to work with variables, but for some simple testing I found it pretty handy. I tried to check if there is a direct way to read, parse, and construct a SAT formula from a DIMACS file in Z3. I didn't find any (as mentioned, I am very new, so I may not know the existence of one). So I ended up coding the following. I would like to know what people think about it and whether there is a better way to achieve the same.
(N.B.: I have not put any checks on the number of clauses and/or number of variables for the formula)
from z3 import *
def read_dimacs_and_make_SAT_formula(file_name: str):
vars = dict()
base_name = "x"
with open(file_name, "r") as f:
for idx, line in enumerate(f):
if line.strip() != "\n" and line.strip() != "" and line.strip() != "\r" and line.strip() != None and idx > 0:
splitted_vals = line.split()
for element in splitted_vals:
if int(element) != 0:
if int(element) > 0 and vars.get(element) is None:
# pure variable which never seen
vars[element] = Bool(base_name+element)
elif int(element) > 0 and vars.get("-"+element) is not None:
# pure variable we have seen the negetion before.
vars[element] = Not(vars["-"+element])
elif int(element) < 0 and vars.get("-"+element) is None:
# negetion of a variable and we have not seen it before.
vars[element] = Not(Bool(base_name+element.replace("-", "")))
elif int(element) < 0 and vars.get(element.replace("-", "")) is not None:
# Negetion, we have seen the pure variable before.
vars[element] = Not(vars[element.replace("-", "")])
f.seek(0)
disjunctions = []
for idx, line in enumerate(f):
clauses = []
if line.strip() != "\n" and line.strip() != "" and line.strip() != "\r" and line.strip() != None and idx > 0:
splitted_vals = line.split()
for element in splitted_vals:
if int(element) != 0:
clauses.append(vars[element])
disjunctions.append(Or([*clauses]))
# print(disjunctions)
if disjunctions:
return And([*disjunctions])
return None
The way you use it is simple. Like so -
if __name__== "__main__":
s = Solver()
disjunctions = read_dimacs_and_make_SAT_formula("dimacs_files/empty.cnf")
if disjunctions is not None:
s.add(disjunctions)
print(s.check())
if s.check().r != -1:
print(s.model())
If called that way, the result looks like the following
python test_1.py ✔ │ SAT Py
sat
[x3 = False, x2 = True, x1 = True, x4 = False]
So the question is, again, what do you think? And can I do something else? Is there a better way?
Thanks in advance