通过加法减少z3中的整数集

通过加法减少z3中的整数集,z3,z3py,Z3,Z3py,我正在试验(并且失败了)在z3中减少集合,而不是像加法这样的操作。这个想法最终是为了证明关于在合理大小的固定集合上任意减少的东西 下面两个示例中的第一个似乎应该产生unsat,但实际并非如此。第二种方法确实有效,但我不想使用它,因为它需要逐步修改模型 def test_reduce(): LIM=5 VARS=10 poss=[Int('i%d'%x)表示范围内的x(VARS)] i=Int('i') s=解算器() arr=Array('arr',IntSort(),BoolSort()) s

我正在试验(并且失败了)在z3中减少集合,而不是像加法这样的操作。这个想法最终是为了证明关于在合理大小的固定集合上任意减少的东西

下面两个示例中的第一个似乎应该产生
unsat
,但实际并非如此。第二种方法确实有效,但我不想使用它,因为它需要逐步修改模型

def test_reduce():
LIM=5
VARS=10
poss=[Int('i%d'%x)表示范围内的x(VARS)]
i=Int('i')
s=解算器()
arr=Array('arr',IntSort(),BoolSort())
s、 加法(arr==Lambda(i,和(i=0)))
a=arr
对于范围内的x(len(poss)):
s、 添加(意味着(a!=EmptySet(IntSort()),arr[poss[x]]))
a=SetDel(a,poss[x])
def最终测试(l):
如果len(l)==0:返回0
返回If(Not(arr[l[0]])、0、l[0]+(如果len(l)==1,则返回0,否则返回final(l[1:]))
sm=最终测试(poss)
s、 推
s、 加(sm==1)
断言s.check()==unsat
有趣的是,下面的例子效果更好,但我不确定为什么

def test_reduce_with_loop_model():
s=解算器()
i=Int('i')
arr=Array('arr',IntSort(),BoolSort())
LIM=1000
s、 加法(arr==Lambda(i,和(i=0)))
sm=0
f=Int(str(uuid4())
尽管如此:
s、 推
s、 添加(arr[f])
chk=s.检查()
如果chk==unsat:
s、 流行音乐()
打破
tmp=s.model()[f]
sm=sm+tmp
s、 流行音乐()
s、 添加(f!=tmp)
s、 推
s、 相加(sm==总和(范围(LIM)))
断言s.check()==sat
s、 流行音乐()
s、 推
s、 加(sm==11)
断言s.check()==unsat

请注意,您的呼叫:

    f = Int(str(uuid4()))
在第一种情况下位于循环内部,在第二种情况下位于循环外部。因此,第二种情况只适用于一个变量,因此收敛速度很快。而第一种方法不断地创建变量,给z3带来了更困难的问题。这两种行为明显不同并不奇怪,因为它们编码的约束完全不同

一般来说,用一个操作减少元素数组对于z3来说不是一个容易的问题。首先,必须假设元素的上限。如果是这样的话,那为什么还要麻烦
Lambda
Array
?只需创建一个包含那么多变量的Python列表,并完全忽略数组逻辑。即:

elts = [Int("s%d"%i) for i in range(100)]
然后要访问“数组”的元素,只需使用Python访问器符号
elts[12]


请注意,这仅在所有访问都使用常量整数时有效;i、 例如,您的索引不能是符号性的。但是如果你想证明还原属性,那就足够了;而且会更有效率。

非常感谢,这很有意义!在我更大的上下文中,集合可以具有已知或未知长度,因此我将把已知长度集合编码为普通python对象,并且只对未知长度使用这种策略。