将变量限制在 z3 中的域
Restricting variables to a domain in z3
将 BitVec 限制为列表的值并没有像我预期的那样工作,至少没有使用 in
。
from z3 import *
s = Solver()
lst = [7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 35, 37, 38, 41, 42, 44, 49, 50]
BV = [BitVec(f"bv1{j + 1}", 8) for j in range(11)]
lst_as_domain = [bv in lst for bv in BV]
s.add(lst_as_domain)
print(lst_as_domain) #[False, False, False, False, False, False, False, False, False, False, False]
print(s.check()) #unsat
如果我按如下方式使用列表理解,它会起作用。
from z3 import *
s = Solver()
lst = [7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 35, 37, 38, 41, 42, 44, 49, 50]
BV = [BitVec(f"bv{j + 1}", 8) for j in range(11)]
lst_as_domain = [Or([B[k] == li for li in lst]) for k in range(11)]
s.add(lst_as_domain)
print(lst_as_domain) #[Or(bv1 == 7, bv1 == 11,... ,bv1 == 50), Or(bv2 == 7,...)..]
print(s.check()) #sat
print(s.model()) #[bv4 = 42, bv7 = 37,..., bv11 = 41]
为什么第一个代码没有产生我想要的限制?我如何使用 in
来断言变量的域,或者是否有一个简短的命令来实现这个?
Python 的内置 in
方法没有按照您认为它应该对符号表达式执行的操作进行操作。这是 z3 python 绑定的类型非常松散的问题:它不是进行符号相等,而是检查对象相等,并且总是得到 False
作为您在打印时找到的答案lst_as_domain
.
解决方案就是您已经找到的。 不要 使用in
。出于重用目的,我将定义一个函数,如:
def member(x, es):
return Or([x == e for e in es])
然后将其用作:
lst_as_domain = [member(bv, lst) for bv in BV]
这会做正确的事情,并且足够“接近”您最初想要写的内容。
不幸的是,这是 Python 绑定的一个常见陷阱。虽然它试图使符号 z3 表达式看起来和表现得像 Python 表达式本身,但由于 Python 和 z3-Python API 本身的限制,它并不总是有效;这使得使用起来容易出错,除非你非常小心重载哪些方法来处理符号表达式,哪些不是。
旁白:不幸的是,没有简单的方法可以判断哪些结构可以开箱即用地处理符号值。您必须研究它们是如何在内部实施的。经验法则:任何 Python 不允许您重载的东西,您都不能用于符号值。但不可否认,这不是一个简单的测试。
将 BitVec 限制为列表的值并没有像我预期的那样工作,至少没有使用 in
。
from z3 import *
s = Solver()
lst = [7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 35, 37, 38, 41, 42, 44, 49, 50]
BV = [BitVec(f"bv1{j + 1}", 8) for j in range(11)]
lst_as_domain = [bv in lst for bv in BV]
s.add(lst_as_domain)
print(lst_as_domain) #[False, False, False, False, False, False, False, False, False, False, False]
print(s.check()) #unsat
如果我按如下方式使用列表理解,它会起作用。
from z3 import *
s = Solver()
lst = [7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 35, 37, 38, 41, 42, 44, 49, 50]
BV = [BitVec(f"bv{j + 1}", 8) for j in range(11)]
lst_as_domain = [Or([B[k] == li for li in lst]) for k in range(11)]
s.add(lst_as_domain)
print(lst_as_domain) #[Or(bv1 == 7, bv1 == 11,... ,bv1 == 50), Or(bv2 == 7,...)..]
print(s.check()) #sat
print(s.model()) #[bv4 = 42, bv7 = 37,..., bv11 = 41]
为什么第一个代码没有产生我想要的限制?我如何使用 in
来断言变量的域,或者是否有一个简短的命令来实现这个?
Python 的内置 in
方法没有按照您认为它应该对符号表达式执行的操作进行操作。这是 z3 python 绑定的类型非常松散的问题:它不是进行符号相等,而是检查对象相等,并且总是得到 False
作为您在打印时找到的答案lst_as_domain
.
解决方案就是您已经找到的。 不要 使用in
。出于重用目的,我将定义一个函数,如:
def member(x, es):
return Or([x == e for e in es])
然后将其用作:
lst_as_domain = [member(bv, lst) for bv in BV]
这会做正确的事情,并且足够“接近”您最初想要写的内容。
不幸的是,这是 Python 绑定的一个常见陷阱。虽然它试图使符号 z3 表达式看起来和表现得像 Python 表达式本身,但由于 Python 和 z3-Python API 本身的限制,它并不总是有效;这使得使用起来容易出错,除非你非常小心重载哪些方法来处理符号表达式,哪些不是。
旁白:不幸的是,没有简单的方法可以判断哪些结构可以开箱即用地处理符号值。您必须研究它们是如何在内部实施的。经验法则:任何 Python 不允许您重载的东西,您都不能用于符号值。但不可否认,这不是一个简单的测试。