将变量限制在 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 不允许您重载的东西,您都不能用于符号值。但不可否认,这不是一个简单的测试。