You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Z3(Py)数组技术疑问:模型解读、函数实现及与序列差异

Z3Py数组与序列相关问题解答

背景

我在Z3Py中实现了公式:Exists i::Integer s.t. (0<=i<|arr|) & (avg(arr)+t<arr[i]),用于判断数组中是否存在索引i(满足0<=i<|arr|),使得arr[i]大于数组平均值avg(arr)加阈值t。对应的Z3Py代码如下:

t = Int('t')
avg_arr = Int('avg_arr')
len_arr = Int('len_arr')

arr = Array('arr', IntSort(), IntSort())

phi_1 = And(0 <= i, i< len_arr)
phi_2 = (t+avg_arr<arr[i])

phi = Exists(i, And(phi_1, phi_2))

s = Solver()
s.add(phi)
print(s.check())
print(s.model())

该公式可满足,但每次执行会得到不同模型,例如:[avg_a = 0, t = 7718, len_arr = 1, arr = K(Int, 7719)]。


疑问解答

1. arr = K(Int, 7719)的含义

K(Int, 7719)表示常量数组:即这个数组的所有索引位置对应的取值都是7719。这里因为模型中len_arr=1,有效索引只有0,看起来像是单个元素的数组,但本质上Z3的数组是无限定义域的映射,不管索引取什么值,返回的都是7719。其中K是Z3用来标记常量数组的符号,全称是"constant array"。

2. 关联数组的avg和len函数

原代码中avg_arr、len_arr是独立的整数变量,和数组arr没有约束关联,因此求解器可以随意赋值。要实现真正关联数组的长度和平均值,有两种方案:

方案1:改用序列(推荐)

Z3的序列(Sequence)是有限元素集合,内置长度、求和等函数,更贴合日常对"数组"的认知:

from z3 import *

t = Int('t')
seq = Seq('seq', IntSort())
len_seq = Length(seq)
sum_seq = Sum(seq)
# 用实数类型避免整数除法精度问题
avg_seq = ToReal(sum_seq) / ToReal(len_seq)

s = Solver()
# 约束序列长度至少为1,避免除以0
s.add(len_seq >= 1)
# 断言存在符合条件的索引
s.add(Exists(i, And(0 <= i, i < len_seq, seq[i] > avg_seq + ToReal(t))))

print(s.check())
print(s.model())

方案2:用数组显式约束

Z3的数组是无限映射,需要手动约束有效索引范围和总和:

from z3 import *

t = Int('t')
len_arr = Int('len_arr')
arr = Array('arr', IntSort(), IntSort())
sum_arr = Int('sum_arr')
avg_arr = ToReal(sum_arr) / ToReal(len_arr)

s = Solver()
# 约束长度至少为1
s.add(len_arr >= 1)
# 用量化断言总和为有效索引元素的和
s.add(ForAll(k, Implies(And(0 <= k, k < len_arr), sum_arr == sum_arr + arr[k])))
# 断言存在符合条件的索引
s.add(Exists(i, And(0 <= i, i < len_arr, arr[i] > avg_arr + ToReal(t))))

print(s.check())
print(s.model())

这种方式较为繁琐,因为数组没有内置的长度和求和能力,需要手动通过量化约束模拟。

3. 模型中没有索引i的原因

i是被Exists(存在量词)绑定的局部变量,Z3的模型只会输出自由变量(即未被量词约束的变量,比如t、avg_arr、len_arr、arr)。求解器只需要证明存在这样的i即可,不需要在模型中给出具体的i值。如果需要获取具体的i,可以将Exists替换为引入自由变量i,再添加对应约束求解。


Z3Py数组与序列的差异

  • 数组:属于无限定义域的映射(全函数),没有内置长度概念,所有索引(包括超出定义的"有效范围")都有对应值。适合表示内存、寄存器这类无限或固定大小的映射场景。
  • 序列:属于有限元素的有序集合,内置Length()、Sum()、Concat()等操作函数,索引访问仅对有效范围(0到长度-1)有效。更符合日常开发中对"数组/列表"的认知,适合处理有限元素的集合操作。

内容的提问来源于stack exchange,提问作者Theo Deep

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 00:25:26