如果 none 存在则断言一个值

Asserting a value if none exist

我正在尝试用 Z3 解决一个相当棘手的问题。它不太相关,但我正在使用 .NET 绑定以及 Z3 的最新夜间版本。

我已经总结了问题,但请记住,实际问题比这更复杂。

在一个非常简短的语句中,数组的任何索引都可以被 selected。然后我给它加 1,结果存储在数组的任何其他索引中。根据需要重复此操作。在这个过程结束时,一个索引被 selected,我们断言它等于一个特定的值——这就是问题的症结所在。

如果用户没有为计算中使用的索引赋值,则最终断言将始终成功。例如:

(declare-const index1 Int)
(declare-const index2 Int)
(declare-const index3 Int)

;Index2 is assigned a value according to user selections.
(assert (= index2 2))
;Index3 is assigned a value according to user selections.
(assert (= index3 5))   
;User chooses index3 to hold a result. 
(assert (= index3 (+ index1 index2)))

(check-sat)
(get-model)

这个问题是可以解决的,导致 index1 的值为 3 (index1 + 2 = 5),但用户从未指定 index1 的值 - 它是只是暗示。

我不能断言 index1 的初始值应该是 0,因为在运行时,用户可以为 index1 分配一个不同的值。

所以,当我 select 来自数组的索引,或 select 或记录的函数时,我想说,这个元素应该是 0,除非它被覆盖。这应该意味着上面的例子不满足。

您可以使用数组存储值,并确保初始值为0。在每次更新时,您都会得到一个具有该修改的新数组:

(declare-const array0 (Array Int Int))
(assert (= array0 ((as const (Array Int Int)) 0)))

(declare-const index1 Int)
(declare-const index2 Int)
(declare-const index3 Int)

;; Index2 is assigned a value according to user selections:
(declare-const array1 (Array Int Int))
(assert (= array1 (store array0 index2 2)))

;; Index3 is assigned a value according to user selections:
(declare-const array2 (Array Int Int))
(assert (= array2 (store array1 index3 5)))

;; final assert:
(assert (= (select array2 index3) (+ (select array2 index1) (select array2 index2))))

以下代码将"extract"相关值:

(check-sat)
(get-value (index1 index2 index3 (select array2 index1) (select array2 index2) (select array2 index3)))

请注意我们如何使用 array2 因为您有 "two" 笔交易。一般来说,如果你有 N user-choices,你就会有 arrayN。 (这也称为单一静态赋值形式,如果您想阅读的话。)

如果你尝试这个,z3 会说:

sat
((index1 3)
 (index2 1)
 (index3 1)
 ((select array2 index1) 0)
 ((select array2 index2) 5)
 ((select array2 index3) 5))

啊,z3太聪明了!它通过确保 index2index3 相同来找到模型。我怀疑您打算让索引不同。让我们告诉z3确实如此:

(assert (distinct index1 index2 index3))

现在(check-sat)returns:

unsat

请注意,这只是解决此问题的一种方法。您还可以保持简单并通过仅跟踪用户未为其分配的索引并将它们显式归零来摆脱数组。但是我觉得array-based这个方法一般来说比较好用。