[英]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.