[英]Describing a function partially in Z3 or Z3py
This is my first question in Stackoverflow.这是我在 Stackoverflow 上的第一个问题。 So please do offer advice if I'm breaking any house rules.
因此,如果我违反任何家规,请务必提供建议。
I have started learning Z3Py only recently.我最近才开始学习 Z3Py。 I found myself in a situation where I know the following about an Int->Int function A that I want to describe and leave it for Z3Py to solve:
我发现自己处于一种情况,我知道以下关于我想描述的 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
How can these constraints be described in Z3Py (Or Z3)?如何在 Z3Py(或 Z3)中描述这些约束?
There could be multiple ways to code this example in z3py.在 z3py 中可以有多种方法来编写这个示例。 With the constraints as you listed, you can use a symbolic array, an uninterpreted function or use separate variables for each of the 100 elements.
使用您列出的约束,您可以使用符号数组、未解释的 function 或为 100 个元素中的每一个使用单独的变量。
The simplest for this case would be the use of arrays: That is, model the Int -> Int
function as an array:对于这种情况,最简单的方法是使用 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))
When run, this prints:运行时,将打印:
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
You can sum up the values printed to ensure it indeed gives you 10000
.您可以总结打印的值以确保它确实为您提供
10000
。
You can also model A
as an uninterpreted function.您也可以将 model
A
作为未解释的 function。 The changes required is really trivial to the above:所需的更改对于上述内容来说确实微不足道:
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))
This prints:这打印:
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
The model is quite different in this case, but it's easy to see that it has A(3) = 190
, A(12) = 1200
, A(74) = 7543
, and all other entries are set to 11; model 在这种情况下完全不同,但很容易看出它有
A(3) = 190
, A(12) = 1200
, A(74) = 7543
,并且所有其他条目都设置为 11; giving you a total of 190 + 1200 + 7543 + 11 * 97 = 10000
.给你总共
190 + 1200 + 7543 + 11 * 97 = 10000
。
Yet a third method would be to allocate 100 integer elements in a python array, and assert the constraints on individual elements separately.第三种方法是在 python 数组中分配 100 个 integer 元素,并分别声明对各个元素的约束。 This would lead to the simplest model, as it would not use any quantification.
这将导致最简单的 model,因为它不会使用任何量化。 Of course, this would model the fact that elements outside the range
0..99
are 0 implicitly, so only use this if this constraint does not need to be explicitly mentioned.当然,这将使 model 范围
0..99
之外的元素隐式为 0,因此仅在不需要显式提及此约束时才使用它。 Again, the coding is almost identical:同样,编码几乎相同:
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))
I'm eliding the output of this for brevity.为简洁起见,我省略了 output 。 Note how we're using
A
as a python list in this case, instead of a symbolic array directly supported by z3py itself.请注意,在这种情况下,我们如何使用
A
作为 python 列表,而不是 z3py 本身直接支持的符号数组。
At the end of the day, the constraints you've described are simple enough that it can use all these three techniques.归根结底,您所描述的约束非常简单,可以使用所有这三种技术。 Which one is the best depends on what other constraints you'd want to model.
哪一个是最好的取决于你想要 model 的其他约束。 (In particular, you'd want to avoid anything that makes heavy use of quantifiers, like
ForAll
above since SMT solvers don't do all that well for quantifiers in general. This problem is simple enough so it doesn't pose an issue, but when your constraints get complicated, it can increase solving times or lead the solver to answer unknown
.) (特别是,您要避免任何大量使用量词的事情,例如上面的
ForAll
,因为 SMT 求解器通常不能很好地处理量词。这个问题很简单,所以不会造成问题,但是当您的约束变得复杂时,它可能会增加求解时间或导致求解器回答unknown
问题。)
Hope this gets you started.希望这能让你开始。 Best of luck!
祝你好运!
Below you'll find a straight-forward SMT encoding of your problem, except for the summation requirement.除了求和要求外,您将在下面找到问题的直接 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)
A few remarks:几点说明:
All SMT functions are total;所有 SMT 功能都是完整的; if you want to encode a partial function, you'll have to explicitly model the function's domain, and make definitional axioms conditional on whether or not an argument is in the domain.
如果要对部分 function 进行编码,则必须明确 model 函数的域,并根据参数是否在域中来定义定义公理。 Z3 will still give you a total model for the function, though.
不过,Z3 仍会为您提供 function 的总 model。
Arbitrary summation is non-trivial to encode in SMT, since there is no sum comprehension operator.任意求和在 SMT 中进行编码并非易事,因为没有求和运算符。 Your case is simpler, though, since your sum ranges over a statically known number of elements ( 0 < x < 100 ).
但是,您的情况更简单,因为您的总和范围是静态已知数量的元素( 0 < x < 100 )。
I'd not be surprised if Z3py offers a convenient source syntax to generate sums over statically-known many elements如果 Z3py 提供了一种方便的源语法来生成静态已知的许多元素的总和,我不会感到惊讶
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.