Z3 常量和 python 'in' 运算符

Z3 constants and python 'in' operator

我想知道使用 python 内置集类型和 z3 常量的成员测试是否安全。

假设有如下例子:

a = Int('a')
a2 = Int('a')

s = set()
s.add(a)

print(a2 in s)

最后一行 return True,这是我想要的行为(当 name 相同时)。但是,ExpRef 中的 __eq__() 运算符被重新定义为 return 约束 'self == other',所以我不明白这个 True 来自哪里。当有两个具有不同 name 的常量时,in 运算符可能 return True 会发生吗?

是的,这样做是安全的。它之所以有效,是因为你实际上是在比较这些对象的底层表示(作为 AST),如果你有不同的名称,它们在这个意义上永远不会相等。

但我不得不说这很不正统。为了说明这一点,考虑一下:

from z3 import *

a = Int('a')
b = Int('b')
solver = Solver()
solver.add(a == b)

s = set()
s.add(a)
s.add(b)

print(s)

这将打印 {b, a},即使我们明确断言 ab 对求解器来说完全相同。这可能会导致混淆。

当然,这很可能正是您想要做的。也就是说,从语法上区分变量,而不考虑它们的值。如果你正在做 "meta" 级别的 z3 编程,我可以看到一些用例,即在它之上构建库,但一般来说,你应该避免在 z3py 中做任何检查对象身份的事情。如果您开始将对象身份和值身份混为一谈,它会变得非常混乱。人们通常需要符号编程中的值同一性,但这同样取决于您的用例。

__eq__ 实际上只是 returns 一个约束,但是 __bool__ 在该约束上 returns 一个布尔值,用于比较两个参数在语法上是否相等。所以基本上 __eq__a == a2 本身只是创建一个等式约束的方式重载,但在布尔上下文中使用它实际上使它比较 aa2在语法上是相同的。所以两个同名的常量将比较相等,但不同名称的常量则不会。

__hash__ 也使用相同的相等概念定义。所以在集合中使用是安全的(或作为字典中的键)。