我试图用Z3解决一个相当棘手的问题。它不太相关,但我正在使用.NET绑定以及最新的Z3夜间版本。
我已经总结了这个问题,但请记住,实际问题比这更令人费解。
在一个非常简短的语句中,可以选择数组的任何索引。然后我向它添加1,结果存储在数组的任何其他索引中。根据需要经常重复这一过程。在这个过程的最后选择一个索引,我们断言它等于一个特定的值 - 这就是问题的症结所在。
如果用户没有为计算中使用的索引赋值,那么最终断言将始终成功。例如:
(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
的值 - 它&#39 ; s只是暗示。
我无法断言index1
的初始值应为0
,因为在运行时,用户可能会为index1
分配不同的值。
因此,当我从数组或记录的选择器函数中选择索引时,我希望能够说,除非被覆盖,否则此元素应为0。这应该意味着上面的例子不满意。
答案 0 :(得分:1)
您可以使用数组存储值,并确保初始值为(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))))
。在每次更新时,您都会得到一个包含该修改的新数组:
(check-sat)
(get-value (index1 index2 index3 (select array2 index1) (select array2 index2) (select array2 index3)))
以下代码将“提取”相关值:
array2
请注意我们如何使用arrayN
,因为您有“两个”交易。一般情况下,如果您有N
个用户选择,则会sat
((index1 3)
(index2 1)
(index3 1)
((select array2 index1) 0)
((select array2 index2) 5)
((select array2 index3) 5))
。 (这也称为单一的静态赋值形式,如果你想阅读它。)
如果你试试这个,z3会说:
index2
啊,z3太聪明了!它通过确保index3
和(assert (distinct index1 index2 index3))
相同来找到模型。我怀疑你打算这些指数是截然不同的。让我们告诉z3确实如此:
(check-sat)
现在unsat
返回:
{{1}}
请注意,这只是解决此问题的一种方法。您还可以通过仅跟踪用户未进行分配的索引并将其明确归零来保持简单并摆脱阵列。但我认为基于数组的方法通常更容易使用。