Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Z3 and DIMACS output

Tags:

z3

Z3 currently supports the DIMACS format for input. Is there any way to output the DIMACS format for the problem before solution? I mean converting the problem to a system CNFs and output it in a DIMACS format. If not, any ideas towards this direction would be more than helpful.

like image 743
absinthe_minded Avatar asked Oct 24 '12 22:10

absinthe_minded


2 Answers

The DIMACS format is very primitive, it supports only Boolean variables. Z3 does not reduce every problem into SAT. Some problems are solved using a propositional SAT solver, but this is not the rule. This usually only happens if the input contains only Boolean and/or Bit-vector variables. Moreover, even if the input problem contains only Boolean and Bit-vector variables, there is no guarantee that Z3 will use a pure SAT solver to solve it.

That being said, you can use the tactic framework to control Z3. For example, for Bit-vector problems, the following tactic will convert it into a propositional formula in CNF format. It should be straightforward to convert it into DIMACS. Here is the example. You can try it online at: 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
like image 73
Leonardo de Moura Avatar answered Nov 20 '22 19:11

Leonardo de Moura


Thanks to Leonardo's answer I came up with this code that will do what you want:

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");
        }
    }
}

For it to work you should add all your constraints to the solver directly, by calling slv.Assert(...).

like image 2
Simon Avatar answered Nov 20 '22 17:11

Simon