1 背景:
针对 SMT(Satisfiability Modulo Theories)和SAT (Boolean Satisfiability Problem)中,经常需要使用不同 的SAT和SMT solver (求解器),这时候会经常有需求将SAT与SMT case文件互转。
所以写了python脚本自动化实现该功能。
需要注意的是, SAT只能与Bit-Vector的SMT相互转换,而针对int等则不能正确转换,这也是为什么有SMT的原因
1.1 SAT /.cnf
SAT 通过使用CNF(Commutative Normal Form,format: DIMACS) 来表示,既.cnf文件:
来看下cnf 是这个样子:
1.2 SMT / .smt2
SMT是SAT更high-level的一种,文件格式为.smt2
好,背景不多说,本文就是实现的.cnf与.smt2文件相互转换,直接上脚本:
2 SAT --> SMT 脚本
既.cnf 转换为.smt2文件
convertSAT2SMT.py:
#coding: utf-8
import sys
def Convert_decl(line, ous):
decls = line.split()
nvars = int(decls[2])
for i in range(nvars):
ous.write("(declare-const p%d Bool)\n" % (i + 1))
def Convert_clause(line, ous):
literals = line.split()
assert (literals[-1] == '0')
ous.write("(assert (or ")
for p in literals:
if p == '0':
break
if p[0] == '-':
ous.write("(not p")
ous.write(p[1:])
ous.write(") ")
else:
ous.write("p")
ous.write(p)
ous.write(" ")
ous.write("))\n")
def ConvertSATFile(file):
ins = open(file)
ous = open("%s.smt2" % file, 'w')
ous.write("(set-logic QF_BV)\n")
line = ''
while True:
line = ins.readline()
if line.startswith('p'): break
Convert_decl(line, ous)
line = ins.readline()
while line:
Convert_clause(line, ous)
line = ins.readline()
ous.write("(check-sat)")
ins.close()
ous.close()
if __name__ == "__main__":
ConvertSATFile((sys.argv[1]))
使用示例如下:
python convertSAT2SMT.py test.cnf
转换成功后,在该目录下,就会创建一个.smt2文件如下:
转换后的内容:
3 SMT --> SAT 脚本
既.smt2转换为.cnf文件
convertSMT2SAT.py:
#coding: utf-8
import sys
import re
def Convert_Assert(line,ous):
if line.startswith("(assert"):
notconv = re.sub(r"not ", "-", line)
#print(notconv)
findrst = re.sub(r"[a-z()]", "", notconv)
cvtrst = findrst.strip() + " 0\n"
#print(cvtrst)
ous.write(cvtrst)
def ConvertSMTFile(file):
ins = open(file, 'r+')
insrB = open(file, 'rb')
ous = open("%s.cnf" % file, 'w')
line = ''
while True:
prevLine = line
line = ins.readline()
if line.startswith("(assert"):break
#print(line)
maxnum = prevLine.split()[1]
maxnumrst = re.sub(r"[p]", "", maxnum)
# ous.write("p cnf "+maxnumrst +'\n')
linNum = 0
while line:
Convert_Assert(line, ous)
line = ins.readline()
linNum += 1
linNum -= 1
with open("%s.cnf" % file, 'r+') as f:
content = f.read()
f.seek(0,0)
# f.write("Generated by SMTGenerator\n")
f.write("p cnf "+maxnumrst + " "+str(linNum) +'\n' + content)
ins.close()
ous.close()
if __name__ == "__main__":
ConvertSMTFile((sys.argv[1]))
使用示例如下:
python convertSMT2SAT.py bitvecor_case2.smt2
同理,转换后同目录生成xxx.smt2