如何从 Z3py 的求解器约束中提取 ArithRef 的值?

How to extract the value of ArithRef from within the solver constraint in Z3py?

我正在尝试从 Z3py 代码中添加一个约束,该约束需要提取 ArithRef 变量的值,但我无法这样做。我附上了下面的 Z3 片段:

from z3 import *
import random

R = 3
H = 4

Dest = [[2,3,4], [0,3,2,5], [1,4,5], [1,4,2], [3,1], [2,3,1]]

s = Solver()

T =[[ Int('r%d_t%d' % (k,t))
         for k in range (R)] for t in range (H)]


for t in range(H):
    for r in range(R):
        s.add(If(t==0, If(r==0, T[t][r]==0, T[t][r]==-1),
                 If(T[t-1][r]==0, T[t][r]==random.choice(Dest[0]), T[t][r]==-1)))

这里我得到的解决方法如下:

[[ 0  2 -1 -1]
 [-1 -1 -1 -1]
 [-1 -1 -1 -1]]

但是,我尝试将约束概括为以下内容,

for t in range(H):
        for r in range(R):
            s.add(If(t==0, If(r==0, T[t][r]==0, T[t][r]==-1),
                     If(T[t-1][r]==0, T[t][r]==random.choice(Dest[T[t-1][r]]), T[t][r]==-1)))

我收到错误:

list indices must be integers or slices, not ArithRef

如何解决这个问题?

一般来说,当涉及符号变量时,您不能混合和匹配索引到 Python 列表或在列表上随机调用。也就是说,当 k 是一个符号整数时,调用 A[k] 是非法的。这就是错误消息告诉您的内容:在您实际上 运行 求解器(通过调用 s.check())并从模型中获取值之前,您无法通过符号变量索引列表。同样,当您需要象征性地选择要从哪个列表中选择时,调用 random.choice 也不起作用。

相反,您需要做的是创建对应于您的随机值的符号索引值,并沿着列表进行符号遍历。像这样:

from z3 import *

R = 3
H = 4

Dest = [[2,3,4], [0,3,2,5], [1,4,5], [1,4,2], [3,1], [2,3,1]]

s = Solver()

T = [[Int('r%d_t%d' % (k,t)) for k in range (R)] for t in range (H)]

# Symbolically walk over a list, grabbing the ith element of it
# The idea here is that i is not just an integer, but can be a symbolic
# integer with other constraitns on it. We also take a continuation, k,
# which we call on the result, for convenience. It's assumed that the
# caller makes sure lst[i] is always within bounds; i.e., i >= 0, and
# i < len(lst).
def SymbolicWalk(i, lst, k):
   if len(lst) == 1:
       return k(lst[0])
   else:
       return If(i == 0, k(lst[0]), SymbolicWalk(i-1, lst[1:], k));

# Pick a random element of the list
# This is the symbolic version of random.choice
def SymbolicChoice(lst):
    i = FreshInt('internal_choice')
    s.add(i >= 0)
    s.add(i <  len(lst))
    return SymbolicWalk(i, lst, lambda x: x)

# Grab the element at given symbolic index, and then call the symbolic choice on it
def index(i, lst):
    return SymbolicWalk(i, lst, SymbolicChoice)

for t in range(H):
    for r in range(R):
        s.add(If(t==0, If(r==0, T[t][r]==0, T[t][r]==-1),
                 If(T[t-1][r]==0, T[t][r]==index(T[t-1][r], Dest), T[t][r]==-1)))

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

我在上面添加了一些评论,希望对您有所帮助。但是这里的 work-horse 是函数 SymbolicWalk ,它实现了对具有符号值的列表进行索引。注意通过调用 FreshInt.

创建“随机”索引

当我 运行 以上时,它会产生:

[ r2_t3 = -1,
 r1_t3 = -1,
 r0_t3 = -1,
 r2_t2 = -1,
 r1_t2 = -1,
 r0_t2 = -1,
 r2_t1 = -1,
 r1_t1 = -1,
 r0_t1 = 2,
 r2_t0 = -1,
 r1_t0 = -1,
 r0_t0 = 0]

这应该是您要查找的内容。请注意,我省略了变量 internal_choice!k 的输出,这些输出是在调用 FreshInt 时内部生成的;你不应该参考这些价值观;它们在内部用于从您的 Dest 列表中获取随机值。