繁体   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