I’m seeing rather surprising behavior from ctx-solver-simplify, where the order of parameters to z3.And() seems to matter, using the latest version of Z3 from the master branch of https://git01.codeplex.com/z3 (89c1785b):
#!/usr/bin/python
import z3
a, b = z3.Bools('a b')
p = z3.Not(a)
q = z3.Or(a, b)
for e in z3.And(p, q), z3.And(q, p):
print e, '->', z3.Tactic('ctx-solver-simplify')(e)
produces:
And(Not(a), Or(a, b)) -> [[Not(a), Or(a, b)]]
And(Or(a, b), Not(a)) -> [[b, Not(a)]]
Is this a bug in Z3?
No, this is not a bug. The tactic
ctx-solver-simplifyis very expensive and inherently asymmetric. That is, the order the sub-formulas are visited affect the final result. This tactic is implemented in the filesrc/smt/tactic/ctx_solver_simplify_tactic.cpp. The code is quite readable. Note that, it uses a “SMT” solver (m_solver), and makes several calls tom_solver.check()while traversing the input formula. Each one of these calls can be quite expensive. For particular problem domains, we can implement a version of this tactic that is even more expensive, and avoids the asymmetry described in your question.EDIT:
You may also consider the tactic
ctx-simplify, it is cheaper thanctx-solver-simplify, but it is symmetric. The tacticctx-simplifywill essentially applies rules such as:Where
F[A]is a formula that may containA. It is cheaper thanctx-solver-simplifybecause it does not invoke a SMT solver when it is traversing the formula. Here is an example using this tactic (also available online):Regarding humand-readability, this was never a goal when implementing any tactic. Please, tell us if the tactic above is not good enough for your purposes.