Python Z3求解器未正确报告指数约束的可满足性



我注意到python的Z3解算器库没有正确地报告我正在处理的涉及指数的问题的可满足性。特别是,它报告说,在我知道有效解算器的情况下,没有找到任何解算器——除非我有效地添加了";告诉它答案";。

我简化了这个问题来隔离它。在下面的代码中,我要求它找到qm,这样q^m == 100。有了约束0 <= q < 100,当然就有了q=10, m=2。但使用下面的代码,它报告没有找到解决方案(raise Z3Exception("model is not available")(:

import z3.z3 as z
slv = z.Solver()
m = z.Int('m')
q = z.Int('q')
slv.add(100 == (q ** m))
slv.add(q >= 0)
slv.add(q < 100)
slv.add(m >= 0)
slv.add(m <= 100)
slv.check()

但是,如果将slv.add(m <= 100))替换为slv.add(m <= 2)(或slv.add(m == 2)!(,则可以找到(q=10, m=2的(解决方案。

  1. 我是不是用错了Z3?

  2. 我认为只有当它证明没有解决方案时,它才会报告不可满足性("模型不可用"(,否则在搜索解决方案时就会挂起。这错了吗?我没想到只有当你缩小搜索空间足够大的时候,它才能找到解决方案。

除了幂运算(例如加法、模运算等(之外,我在任何其他运算中都没有遇到过这个问题。

您误解了z3告诉您的内容。更改线路:

slv.check()

至:

print(slv.check())
print(slv.reason_unknown())

你会看到它打印:

unknown
smt tactic failed to show goal to be sat/unsat (incomplete (theory arithmetic))

所以,z3不知道你的问题是sat还是unsat;所以你不能要求模特。原因是幂算子:它引入了非线性,非线性整数方程的理论在一般情况下是不可判定的。也就是说,z3的求解器对于这个问题是不完整的。在实践中,这意味着z3将应用一系列启发式方法,并有望为您解决问题。但正如你所观察到的,你也可以得到unknown

毫不奇怪,如果添加额外的约束,就会帮助解算器,从而找到答案。你只是在进一步帮助它,这些启发法会更容易。使用不同版本的z3,您可以观察到不同的行为。(也就是说,在未来,他们可能能够开箱即用地解决这个问题,或者启发式会变得更糟,而你这样帮助它也无法解决问题。(这就是用不可判定理论自动证明定理的本质。

底线:对check的任何调用都可以返回satunsatunknown。您的程序应该检查所有三种可能性,并相应地解释输出。

最新更新