Z3Py证明函数返回错误的反例

时间:2018-10-11 14:08:28

标签: python z3 z3py

我正在尝试使用Z3Py证明函数,但似乎返回了错误的反例。 问题是什么?? (Z3-4.7.1-x86-win,Python-2.7.15)

>>> import z3
>>> A = z3.BitVec('A', 8)
>>> B = z3.BitVec('B', 8)
>>> C = z3.BitVec('C', 8)
>>> z3.prove((A*B)/C == A*(B/C))
counterexample
[A = 67, B = 86, C = 2]
>>> ((67*86)%256)/2
65
>>> (67*(86/2))%256
65

2 个答案:

答案 0 :(得分:1)

让我们看看Z3在做什么:

AppbarLayout

运行此脚本时,您将得到:

import z3
A = z3.BitVec('A', 8)
B = z3.BitVec('B', 8)
C = z3.BitVec('C', 8)

s = z3.Solver()
s.add((A*B)/C == A*(B/C))
print s.sexpr()

啊,它在8位向量上使用$ python a.py (declare-fun C () (_ BitVec 8)) (declare-fun B () (_ BitVec 8)) (declare-fun A () (_ BitVec 8)) (assert (= (bvsdiv (bvmul A B) C) (bvmul A (bvsdiv B C)))) bvmul。事实证明,乘法对有符号的无符号无关紧要,但除法却重要。因此,实际上是完成了映射,以将结果映射到bvsdiv-128的范围内,而不是映射到1270的范围内(正如我怀疑的那样)。

因此,如果您进行数学运算,则左侧会减少到255,因为乘法会产生-63,它会以有符号8位表示形式映射到5762。但是,右侧减少为-126;从而给您合法的反例。

为避免这种情况,您可以使用旧的65类型;或通过使用Int告诉Python不要使用符号除法,请参见此处:https://z3prover.github.io/api/html/namespacez3py.html#a64c02a843a4ac8781dd666a991797906

如果使用UDiv,则可以得到更好的反例:

UDiv

这更符合您的预期。

答案 1 :(得分:0)

我认为您看到算术“模8”(8位宽度)存在问题:A * B(两个8位值)不能表示为8位值,导致某些环绕/剪切。

固定宽度数学通常不具备这些等式。