如何从 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
列表中获取随机值。
我正在尝试从 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
列表中获取随机值。