我看到来自ctx-solver-simplify
的相当令人惊讶的行为,其中z3.And()的参数顺序似乎很重要,使用来自https://git01.codeplex.com/z3的主分支的最新版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)
产生
And(Not(a), Or(a, b)) -> [[Not(a), Or(a, b)]]
And(Or(a, b), Not(a)) -> [[b, Not(a)]]
这是Z3中的错误吗?
答案 0 :(得分:2)
不,这不是错误。策略ctx-solver-simplify
非常昂贵并且本质上是不对称的。也就是说,访问子公式的顺序会影响最终结果。此策略在文件src/smt/tactic/ctx_solver_simplify_tactic.cpp
中实现。代码非常易读。请注意,它使用“SMT”解算器(m_solver
),并在遍历输入公式时对m_solver.check()
进行多次调用。这些电话中的每一个都非常昂贵。对于特定问题域,我们可以实现更昂贵的此策略版本,并避免问题中描述的不对称性。
修改强>
你也可以考虑战术ctx-simplify
,它比ctx-solver-simplify
便宜,但它是对称的。策略ctx-simplify
将基本上应用以下规则:
A \/ F[A] ==> A \/ F[false]
x != c \/ F[x] ==> F[c]
其中F[A]
是可能包含A
的公式。它比ctx-solver-simplify
便宜,因为它在遍历公式时不会调用SMT求解器。以下是使用此策略的示例(也可用online):
a, b = Bools('a b')
p = Not(a)
q = Or(a, b)
c = Bool('c')
t = Then('simplify', 'propagate-values', 'ctx-simplify')
for e in Or(c, And(p, q)), Or(c, And(q, p)):
print e, '->', t(e)
关于人类可读性,在实施任何策略时,这绝不是目标。请告诉我们上述策略是否不足以满足您的目的。
答案 1 :(得分:2)
我认为写一个自定义策略会更好,因为有 当你基本上要求正规性时的其他权衡。 Z3没有任何将公式转换为规范形式的策略。 所以,如果你想要的东西总能产生相同的公式答案 相当于地面,你将不得不写一个新的规范化器 确保这一点。
ctx_solver_simplify_tactic在简化公式时还会进行一些权衡: 它避免了多次简化相同的子公式。如果确实如此,它可能会增加 所得公式的大小显着(指数)。