[英]Describing a function partially in Z3 or Z3py
这是我在 Stackoverflow 上的第一个问题。 因此,如果我违反任何家规,请务必提供建议。
我最近才开始学习 Z3Py。 我发现自己处于一种情况,我知道以下关于我想描述的 Int->Int function A并将其留给 Z3Py 解决的情况:
The summation of A(x) = 10000 where 0<x<100
A(x) > 10 where 0<x<100
A(x) = 0 where x>= 100
A(3) = 190
A(12) = 1200
如何在 Z3Py(或 Z3)中描述这些约束?
在 z3py 中可以有多种方法来编写这个示例。 使用您列出的约束,您可以使用符号数组、未解释的 function 或为 100 个元素中的每一个使用单独的变量。
对于这种情况,最简单的方法是使用 arrays:即 model Int -> Int
function 作为数组:
from z3 import *
A = Array('A', IntSort(), IntSort())
s = Solver()
total = 0
for i in range(100):
s.add(A[i] > 10)
total = total + A[i]
s.add(total == 10000)
s.add(A[ 3] == 190)
s.add(A[12] == 1200)
k = Int('k')
s.add(ForAll(k, (Implies(Or(k < 0, k >= 100), A[k] == 0))))
if s.check() == sat:
m = s.model()
for i in range(100):
v = m.evaluate(A[i]).as_long()
print("%3d: %d" % (i, v))
运行时,将打印:
0: 131
1: 19
2: 436
3: 190
4: 12
5: 11
6: 19
7: 24
8: 11
9: 13
10: 133
11: 134
12: 1200
13: 39
14: 132
15: 134
16: 134
17: 134
18: 30
19: 132
20: 132
21: 38
22: 16
23: 132
24: 22
25: 132
26: 134
27: 27
28: 134
29: 76
30: 130
31: 15
32: 132
33: 134
34: 31
35: 123
36: 35
37: 58
38: 123
39: 64
40: 49
41: 20
42: 139
43: 24
44: 134
45: 11
46: 132
47: 132
48: 22
49: 11
50: 134
51: 134
52: 134
53: 132
54: 132
55: 11
56: 134
57: 11
58: 11
59: 132
60: 11
61: 71
62: 134
63: 58
64: 132
65: 132
66: 134
67: 134
68: 39
69: 74
70: 132
71: 134
72: 134
73: 11
74: 18
75: 134
76: 16
77: 132
78: 17
79: 132
80: 132
81: 132
82: 15
83: 132
84: 132
85: 134
86: 15
87: 132
88: 134
89: 18
90: 132
91: 132
92: 132
93: 132
94: 12
95: 132
96: 22
97: 121
98: 24
99: 11
您可以总结打印的值以确保它确实为您提供10000
。
您也可以将 model A
作为未解释的 function。 所需的更改对于上述内容来说确实微不足道:
from z3 import *
A = Function('A', IntSort(), IntSort())
s = Solver()
total = 0
for i in range(100):
s.add(A(i) > 10)
total = total + A(i)
s.add(total == 10000)
s.add(A( 3) == 190)
s.add(A(12) == 1200)
k = Int('k')
s.add(ForAll(k, (Implies(Or(k < 0, k >= 100), A(k) == 0))))
if s.check() == sat:
m = s.model()
for i in range(100):
v = m.evaluate(A(i)).as_long()
print("%3d: %d" % (i, v))
这打印:
0: 11
1: 11
2: 11
3: 190
4: 11
5: 11
6: 11
7: 11
8: 11
9: 11
10: 11
11: 11
12: 1200
13: 11
14: 11
15: 11
16: 11
17: 11
18: 11
19: 11
20: 11
21: 11
22: 11
23: 11
24: 11
25: 11
26: 11
27: 11
28: 11
29: 11
30: 11
31: 11
32: 11
33: 11
34: 11
35: 11
36: 11
37: 11
38: 11
39: 11
40: 11
41: 11
42: 11
43: 11
44: 11
45: 11
46: 11
47: 11
48: 11
49: 11
50: 11
51: 11
52: 11
53: 11
54: 11
55: 11
56: 11
57: 11
58: 11
59: 11
60: 11
61: 11
62: 11
63: 11
64: 11
65: 11
66: 11
67: 11
68: 11
69: 11
70: 11
71: 11
72: 11
73: 11
74: 7543
75: 11
76: 11
77: 11
78: 11
79: 11
80: 11
81: 11
82: 11
83: 11
84: 11
85: 11
86: 11
87: 11
88: 11
89: 11
90: 11
91: 11
92: 11
93: 11
94: 11
95: 11
96: 11
97: 11
98: 11
99: 11
model 在这种情况下完全不同,但很容易看出它有A(3) = 190
, A(12) = 1200
, A(74) = 7543
,并且所有其他条目都设置为 11; 给你总共190 + 1200 + 7543 + 11 * 97 = 10000
。
第三种方法是在 python 数组中分配 100 个 integer 元素,并分别声明对各个元素的约束。 这将导致最简单的 model,因为它不会使用任何量化。 当然,这将使 model 范围0..99
之外的元素隐式为 0,因此仅在不需要显式提及此约束时才使用它。 同样,编码几乎相同:
from z3 import *
A = [Int('A_%d' % i) for i in range(100)]
s = Solver()
total = 0
for i in range(100):
s.add(A[i] > 10)
total = total + A[i]
s.add(total == 10000)
s.add(A[ 3] == 190)
s.add(A[12] == 1200)
if s.check() == sat:
m = s.model()
for i in range(100):
v = m.evaluate(A[i]).as_long()
print("%3d: %d" % (i, v))
为简洁起见,我省略了 output 。 请注意,在这种情况下,我们如何使用A
作为 python 列表,而不是 z3py 本身直接支持的符号数组。
归根结底,您所描述的约束非常简单,可以使用所有这三种技术。 哪一个是最好的取决于你想要 model 的其他约束。 (特别是,您要避免任何大量使用量词的事情,例如上面的ForAll
,因为 SMT 求解器通常不能很好地处理量词。这个问题很简单,所以不会造成问题,但是当您的约束变得复杂时,它可能会增加求解时间或导致求解器回答unknown
问题。)
希望这能让你开始。 祝你好运!
除了求和要求外,您将在下面找到问题的直接 SMT 编码。
(set-option :smt.mbqi true) ; also try false (e-matching instead of MBQI)
(declare-fun A (Int) Int)
(assert
(=
10000
(+
(A 1)
(A 2)
(A 3)
; ...
(A 99))))
; A(x) > 10 where 0<x<100
(assert (forall ((x Int))
(implies
(and (< 0 x) (< x 100))
(> (A x) 10))))
; A(x) = 0 where x>= 100
(assert (forall ((x Int))
(implies
(>= x 100)
(> (A x) 10))))
; A(3) = 190
(assert (= (A 3) 190))
; A(12) = 1200
(assert (= (A 12) 1200))
(check-sat)
几点说明:
所有 SMT 功能都是完整的; 如果要对部分 function 进行编码,则必须明确 model 函数的域,并根据参数是否在域中来定义定义公理。 不过,Z3 仍会为您提供 function 的总 model。
任意求和在 SMT 中进行编码并非易事,因为没有求和运算符。 但是,您的情况更简单,因为您的总和范围是静态已知数量的元素( 0 < x < 100 )。
如果 Z3py 提供了一种方便的源语法来生成静态已知的许多元素的总和,我不会感到惊讶
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.