Z3 SMT 和 Python 的结果不正确
Incorrect result with Z3 SMT and Python
我正在尝试从此处的 Whosebug 答案中复制另一个用户给出的脚本
我认为大部分内容都可以使它与 python 绑定一起使用,但是我没有得到正确的答案。这是 python 脚本:
from z3 import *
mask = BitVec('mask', 64)
multiplicand = BitVec('multiplicand', 64)
x = BitVec('x', 64)
y = BitVec('y', 64)
s = SolverFor("BV")
F = [
ForAll(x, (y == (mask & x) * multiplicand)),
And(Extract(63, 63, x) == Extract(63, 63, y),
Extract(55, 55, x) == Extract(62, 62, y),
Extract(47, 47, x) == Extract(61, 61, y),
Extract(39, 39, x) == Extract(60, 60, y),
Extract(31, 31, x) == Extract(59, 59, y),
Extract(23, 23, x) == Extract(58, 58, y),
Extract(15, 15, x) == Extract(57, 57, y),
Extract(7, 7, x) == Extract(56, 56, y))
]
print F[0].sexpr()
print F[1].sexpr()
s.add(F)
if s.check() == sat:
print "ok"
print s.model()
我的结果如下:
(forall ((x (_ BitVec 64))) (= y (bvmul (bvand mask x) multiplicand)))
(and (= ((_ extract 63 63) x) ((_ extract 63 63) y))
(= ((_ extract 55 55) x) ((_ extract 62 62) y))
(= ((_ extract 47 47) x) ((_ extract 61 61) y))
(= ((_ extract 39 39) x) ((_ extract 60 60) y))
(= ((_ extract 31 31) x) ((_ extract 59 59) y))
(= ((_ extract 23 23) x) ((_ extract 58 58) y))
(= ((_ extract 15 15) x) ((_ extract 57 57) y))
(= ((_ extract 7 7) x) ((_ extract 56 56) y)))
[掩码 = 0,被乘数 = 0,y = 0,x = 0]
这显然是不正确的。我看到的主要区别是我生成的 SMT 代码似乎对 'y' 进行了赋值,而在另一个 StackExchange 答案中他有一个 let 表达式。有人可以在这里为我指出正确的方向吗?
通过 Python API 和 parse_smt2_string
( http://research.microsoft.com/en-us/um/redmond/projects/z3/z3.html#-parse_smt2_string ):
解析 SMT2 字符串,您可能会喜欢这个技巧
from z3 import *
s = SolverFor("BV")
#s.set(':pp.bv_literals', True) # gives error for some reason
mask = BitVec('mask', 64)
multiplicand = BitVec('multiplicand', 64)
x = BitVec('x', 64)
y = BitVec('y', 64)
F = parse_smt2_string(' \
(set-option :pp.bv_literals true) \
(declare-const mask (BV64)) \
(declare-const multiplicand (BV64)) \
(assert (forall ((x (BV64))) \
(let ((y (bvmul (bvand mask x) multiplicand))) \
(and \
(= ((_ extract 63 63) x) ((_ extract 63 63) y)) \
(= ((_ extract 55 55) x) ((_ extract 62 62) y)) \
(= ((_ extract 47 47) x) ((_ extract 61 61) y)) \
(= ((_ extract 39 39) x) ((_ extract 60 60) y)) \
(= ((_ extract 31 31) x) ((_ extract 59 59) y)) \
(= ((_ extract 23 23) x) ((_ extract 58 58) y)) \
(= ((_ extract 15 15) x) ((_ extract 57 57) y)) \
(= ((_ extract 7 7) x) ((_ extract 56 56) y)) \
) \
) \
))', sorts={ 'BV64' : BitVecSort(64) })
print F
s.add(F)
print s.to_smt2()
if s.check() == sat:
print "ok"
print s.model()
m = s.model()
print hex(m[mask].as_long())
print hex(m[multiplicand].as_long())
输出为:
[mask = 9259542123273814144, multiplicand = 567382630219905]
0x8080808080808080L
0x2040810204081L
你对 let 表达式的编码有问题。对于主要断言,您需要在所有 x
上使用通用量词,而您正试图使用它来定义 let 表达式。以下基本上适用于您的原始编码,只需创建一个指向适当表达式 y
的指针并复制它:
from z3 import *
mask = BitVec('mask', 64)
multiplicand = BitVec('multiplicand', 64)
x = BitVec('x', 64)
y = BitVec('y', 64)
y = ((mask & x) * multiplicand)
s = SolverFor("BV")
F = [
ForAll(x,
And(Extract(63, 63, x) == Extract(63, 63, y),
Extract(55, 55, x) == Extract(62, 62, y),
Extract(47, 47, x) == Extract(61, 61, y),
Extract(39, 39, x) == Extract(60, 60, y),
Extract(31, 31, x) == Extract(59, 59, y),
Extract(23, 23, x) == Extract(58, 58, y),
Extract(15, 15, x) == Extract(57, 57, y),
Extract(7, 7, x) == Extract(56, 56, y)))
]
print F[0].sexpr()
s.add(F)
if s.check() == sat:
print "ok"
print s.model()
m = s.model()
print hex(m[mask].as_long())
print hex(m[multiplicand].as_long())
输出为:
[mask = 9259542123273814144, multiplicand = 567382630219905]
0x8080808080808080L
0x2040810204081L
问题实际上是关于 Z3 Python 绑定的。但这是一个有趣的。在不引发任何语言战争的情况下,我只是想将 Haskell 解决方案放在这里以供参考,再次使用 Z3 作为底层求解器:
import Data.SBV
main :: IO ()
main = print =<< satWith z3{printBase=16} find
where find = do mask <- exists "mask"
mult <- exists "mult"
inp <- forall "inp"
let res = (mask .&. inp) * (mult :: SWord64)
x `grab` is = map (sbvTestBit x) is
solve [inp `grab` [7, 15 .. 63] .== res `grab` [56 .. 63]]
我们得到:
*Main> main
Satisfiable. Model:
mask = 0x8080808080808080 :: Word64
mult = 0x0002040810204081 :: Word64
我正在尝试从此处的 Whosebug 答案中复制另一个用户给出的脚本
我认为大部分内容都可以使它与 python 绑定一起使用,但是我没有得到正确的答案。这是 python 脚本:
from z3 import *
mask = BitVec('mask', 64)
multiplicand = BitVec('multiplicand', 64)
x = BitVec('x', 64)
y = BitVec('y', 64)
s = SolverFor("BV")
F = [
ForAll(x, (y == (mask & x) * multiplicand)),
And(Extract(63, 63, x) == Extract(63, 63, y),
Extract(55, 55, x) == Extract(62, 62, y),
Extract(47, 47, x) == Extract(61, 61, y),
Extract(39, 39, x) == Extract(60, 60, y),
Extract(31, 31, x) == Extract(59, 59, y),
Extract(23, 23, x) == Extract(58, 58, y),
Extract(15, 15, x) == Extract(57, 57, y),
Extract(7, 7, x) == Extract(56, 56, y))
]
print F[0].sexpr()
print F[1].sexpr()
s.add(F)
if s.check() == sat:
print "ok"
print s.model()
我的结果如下:
(forall ((x (_ BitVec 64))) (= y (bvmul (bvand mask x) multiplicand)))
(and (= ((_ extract 63 63) x) ((_ extract 63 63) y))
(= ((_ extract 55 55) x) ((_ extract 62 62) y))
(= ((_ extract 47 47) x) ((_ extract 61 61) y))
(= ((_ extract 39 39) x) ((_ extract 60 60) y))
(= ((_ extract 31 31) x) ((_ extract 59 59) y))
(= ((_ extract 23 23) x) ((_ extract 58 58) y))
(= ((_ extract 15 15) x) ((_ extract 57 57) y))
(= ((_ extract 7 7) x) ((_ extract 56 56) y)))
[掩码 = 0,被乘数 = 0,y = 0,x = 0]
这显然是不正确的。我看到的主要区别是我生成的 SMT 代码似乎对 'y' 进行了赋值,而在另一个 StackExchange 答案中他有一个 let 表达式。有人可以在这里为我指出正确的方向吗?
通过 Python API 和 parse_smt2_string
( http://research.microsoft.com/en-us/um/redmond/projects/z3/z3.html#-parse_smt2_string ):
from z3 import *
s = SolverFor("BV")
#s.set(':pp.bv_literals', True) # gives error for some reason
mask = BitVec('mask', 64)
multiplicand = BitVec('multiplicand', 64)
x = BitVec('x', 64)
y = BitVec('y', 64)
F = parse_smt2_string(' \
(set-option :pp.bv_literals true) \
(declare-const mask (BV64)) \
(declare-const multiplicand (BV64)) \
(assert (forall ((x (BV64))) \
(let ((y (bvmul (bvand mask x) multiplicand))) \
(and \
(= ((_ extract 63 63) x) ((_ extract 63 63) y)) \
(= ((_ extract 55 55) x) ((_ extract 62 62) y)) \
(= ((_ extract 47 47) x) ((_ extract 61 61) y)) \
(= ((_ extract 39 39) x) ((_ extract 60 60) y)) \
(= ((_ extract 31 31) x) ((_ extract 59 59) y)) \
(= ((_ extract 23 23) x) ((_ extract 58 58) y)) \
(= ((_ extract 15 15) x) ((_ extract 57 57) y)) \
(= ((_ extract 7 7) x) ((_ extract 56 56) y)) \
) \
) \
))', sorts={ 'BV64' : BitVecSort(64) })
print F
s.add(F)
print s.to_smt2()
if s.check() == sat:
print "ok"
print s.model()
m = s.model()
print hex(m[mask].as_long())
print hex(m[multiplicand].as_long())
输出为:
[mask = 9259542123273814144, multiplicand = 567382630219905]
0x8080808080808080L
0x2040810204081L
你对 let 表达式的编码有问题。对于主要断言,您需要在所有 x
上使用通用量词,而您正试图使用它来定义 let 表达式。以下基本上适用于您的原始编码,只需创建一个指向适当表达式 y
的指针并复制它:
from z3 import *
mask = BitVec('mask', 64)
multiplicand = BitVec('multiplicand', 64)
x = BitVec('x', 64)
y = BitVec('y', 64)
y = ((mask & x) * multiplicand)
s = SolverFor("BV")
F = [
ForAll(x,
And(Extract(63, 63, x) == Extract(63, 63, y),
Extract(55, 55, x) == Extract(62, 62, y),
Extract(47, 47, x) == Extract(61, 61, y),
Extract(39, 39, x) == Extract(60, 60, y),
Extract(31, 31, x) == Extract(59, 59, y),
Extract(23, 23, x) == Extract(58, 58, y),
Extract(15, 15, x) == Extract(57, 57, y),
Extract(7, 7, x) == Extract(56, 56, y)))
]
print F[0].sexpr()
s.add(F)
if s.check() == sat:
print "ok"
print s.model()
m = s.model()
print hex(m[mask].as_long())
print hex(m[multiplicand].as_long())
输出为:
[mask = 9259542123273814144, multiplicand = 567382630219905]
0x8080808080808080L
0x2040810204081L
问题实际上是关于 Z3 Python 绑定的。但这是一个有趣的。在不引发任何语言战争的情况下,我只是想将 Haskell 解决方案放在这里以供参考,再次使用 Z3 作为底层求解器:
import Data.SBV
main :: IO ()
main = print =<< satWith z3{printBase=16} find
where find = do mask <- exists "mask"
mult <- exists "mult"
inp <- forall "inp"
let res = (mask .&. inp) * (mult :: SWord64)
x `grab` is = map (sbvTestBit x) is
solve [inp `grab` [7, 15 .. 63] .== res `grab` [56 .. 63]]
我们得到:
*Main> main
Satisfiable. Model:
mask = 0x8080808080808080 :: Word64
mult = 0x0002040810204081 :: Word64