簡體   English   中英

在 Z3 或 Z3py 中部分描述 function

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

對於這種情況,最簡單的方法是使用 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) = 190A(12) = 1200A(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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM