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.
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
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(...)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With