Z3 и DIMACS выход
Z3 в настоящее время поддерживает формат DIMACS для ввода. Есть ли способ вывести формат DIMACS для проблемы до ее решения? Я имею в виду преобразование проблемы в системные CNF и вывод ее в формате DIMACS. Если нет, то любые идеи в этом направлении будут более чем полезными.
2 ответа
Формат DIMACS очень примитивен, он поддерживает только логические переменные. Z3 не сводит все проблемы в SAT. Некоторые проблемы решаются с помощью пропозиционального SAT-решателя, но это не правило. Обычно это происходит только в том случае, если входные данные содержат только логические и / или битовые векторные переменные. Более того, даже если входная задача содержит только логические и битовые переменные, нет гарантии, что Z3 будет использовать для ее решения чисто SAT-решатель.
При этом вы можете использовать тактические рамки для управления Z3. Например, для задач с бит-вектором следующая тактика преобразует ее в формулу высказываний в формате CNF. Преобразовать его в DIMACS должно быть просто. Вот пример. Вы можете попробовать это онлайн на: http://rise4fun.com/Z3Py/E1s
x, y, z = BitVecs('x y z', 16)
g = Goal()
g.add(x == y, z > If(x < 0, x, -x))
print g
# t is a tactic that reduces a Bit-vector problem into propositional CNF
t = Then('simplify', 'bit-blast', 'tseitin-cnf')
subgoal = t(g)
assert len(subgoal) == 1
# Traverse each clause of the first subgoal
for c in subgoal[0]:
print c
Благодаря ответу Леонардо я придумал этот код, который будет делать то, что вы хотите:
private static void Output(Context ctx,Solver slv)
{
var goal = ctx.MkGoal();
goal.Add(slv.Assertions);
var applyResult = ctx.Then(ctx.MkTactic("simplify"),
ctx.MkTactic("bit-blast"),
ctx.MkTactic("tseitin-cnf")).Apply(goal);
Debug.Assert(applyResult.Subgoals.Length==1);
var map = new Dictionary<BoolExpr,int>();
foreach (var f in applyResult.Subgoals[0].Formulas)
{
Debug.Assert(f.IsOr);
foreach (var e in f.Args)
if (e.IsNot)
{
Debug.Assert(e.Args.Length==1);
Debug.Assert(e.Args[0].IsConst);
map[(BoolExpr)e.Args[0]] = 0;
}
else
{
Debug.Assert(e.IsConst);
map[(BoolExpr)e] = 0;
}
}
var id = 1;
foreach (var key in map.Keys.ToArray())
map[key] = id++;
using (var fos = File.CreateText("problem.cnf"))
{
fos.WriteLine("c DIMACS file format");
fos.WriteLine($"p cnf {map.Count} {applyResult.Subgoals[0].Formulas.Length}");
foreach(var f in applyResult.Subgoals[0].Formulas)
{
foreach (var e in f.Args)
if (e.IsNot)
fos.Write($"{map[(BoolExpr)e.Args[0]]} ");
else
fos.Write($"-{map[(BoolExpr)e]} ");
fos.WriteLine("0");
}
}
}
Чтобы это работало, вы должны добавить все свои ограничения в решатель напрямую, вызвав slv.Assert(...)
,