有没有人知道一个好的程序,将CNF文件转换为每个子句的任意数量的变量到CNF文件,每个子句(3-CNF)只有3个变量?我已经在计算机科学书籍中看到过这种算法,但是无法在任何地方找到实现,并且如果其他人已经做过,就不愿意浪费时间自己实现它。谢谢!
答案 0 :(得分:2)
SAT在多项式时间内无法解决(根据现有知识)。 2-SAT在多项式时间内是可解的。
因此从通用SAT到2-SAT的转换不会很快(不是在多项式时间内),否则我们会找到SAT的多项式时间算法。
换句话说,将SAT转换为2-SAT所需的时间与解决SAT的时间大致相同。
也许你的意思是3-SAT,而不是2-SAT?
答案 1 :(得分:2)
我也不知道有任何程序可以做到这一点,但算法非常简单,所以我写了下面的python脚本(download),它以DIMACS格式读取一般CNF并写入CNF DIMACS格式的等效3-SAT问题:
from __future__ import print_function
import fileinput
cnf = list()
cnf.append(list())
maxvar = 0
for line in fileinput.input():
tokens = line.split()
if len(tokens) == 0 or tokens[0] == "p" or tokens[0] == "c":
continue
for tok in tokens:
lit = int(tok)
maxvar = max(maxvar, abs(lit))
if lit == 0:
cnf.append(list())
else:
cnf[-1].append(lit)
assert len(cnf[-1]) == 0
cnf.pop()
new_cnf = list()
for clause in cnf:
while len(clause) > 3:
new_clause = list()
for i in range(0, len(clause), 2):
if i+1 < len(clause):
new_cnf.append(list())
new_cnf[-1].append(clause[i])
new_cnf[-1].append(clause[i+1])
maxvar += 1
new_cnf[-1].append(-maxvar)
new_clause.append(maxvar)
else:
new_clause.append(clause[i])
clause = new_clause
new_cnf.append(clause)
print("p cnf %d %d" % (maxvar, len(new_cnf)))
for clause in new_cnf:
print(" ".join([ "%d" % lit for lit in clause ]) + " 0")
有趣的一点当然是for clause in cnf:
循环,它将cnf
中存储的一般sat问题转换为存储在new_cnf
中的3-sat实例。它通过翻译诸如
(A[1] or A[2] or A[3] or A[4] or A[5] or A[6] or A[7])
进入以下一组条款。
(A[1] or A[2] or ~X[1])
(A[3] or A[4] or ~X[2])
(A[5] or A[6] or ~X[3])
(X[1] or X[2] or X[3] or A[7])
前三个条款已添加到new_cnf
。最后一个子句不是3-sat,因此算法在最后一个子句上重新运行,产生以下新子句:
(X[1] or X[2] or ~Y[1])
(X[3] or A[7] or ~Y[2])
(Y[1] or Y[2])
这是所有3-sat子句,因此它们被添加到new_cnf
,算法将继续cnf
的下一个子句。 (如果最后一个子句不是3-sat,算法将继续处理它,直到只留下3-sat子句。最后一个子句的长度在每次迭代时大约减半。)