Z3不变检查

时间:2016-06-20 16:53:44

标签: z3

我想要一种方法,给定一个不变量和一个或多个操作的效果,检查在操作执行后,不变量是否仍然存在。

关于如何实现这一目标的任何想法?

使用Z3我想做类似于

的事情
(declare-const a Int)
(declare-const b Int)
(declare-const c Int)
(declare-const d Int)

(define-fun invariant () Bool
  (= a b c d 2)
)

(assert invariant)
(assert (= a 1)) ;operation1
(assert (= b 2)) ;operation2
(assert (not invariant))
(check-sat)

如果(check-sat)返回不满,那么我得出结论,操作后系统的状态是有效的。

我显然无法做到以上

(assert invariant)
(assert (not invariant))

总是使定理不饱和。

但是我需要声明初始状态是有效的,这样当我运行时(断言(不是不变)),操作未改变的系统部分是有效的。

1 个答案:

答案 0 :(得分:2)

我假设您的操作会改变某种状态(局部变量,程序堆,......),因此您的不变量应该是 状态的函数。

作为一个小例子,考虑这个带有局部变量的假设命令式程序:

var start: Int := 0
var end: Int := 0
var arr: Array[Int] := new Array(10) // Array of ints, size 10
fill(arr, 0) // Fill the array with zeros

def invariant() =
     (0 < start <= end)
  && forall i in [start, end - 1) :: arr(i) < arr(i + 1) // Sorted

assert invariant() // holds
end := end + 1
assert invariant() // holds
end := end + 1
assert invariant() // fails
arr(start + 1) := arr(start + 1) + 1
assert invariant() // holds

它可以编码如下,其中变异的局部变量以静态单一赋值形式表示:

(define-fun invariant ((start Int) (end Int) (arr (Array Int Int))) Bool
  (and
    (<= 0 start)
    (<= start end)
    (forall ((i Int))
      (implies
        (and (<= start i) (< i (- end 1)))
        (< (select arr i) (select arr (+ i 1)))))))

(declare-const start0 Int)
(declare-const end0 Int)
(declare-const arr0 (Array Int Int))

(assert (= start0 0))
(assert (= end0 0))
(assert (= arr0 ((as const (Array Int Int)) 0)))

(push)
  (assert (not (invariant start0 end0 arr0)))
  (check-sat) ;; UNSAT --> Invariant holds
(pop)

;; Operation: end := end + 1

(declare-const end1 Int)
(assert (= end1 (+ end0 1)))

(push)
  (assert (not (invariant start0 end1 arr0)))
  (check-sat) ; UNSAT --> Invariant still holds
(pop)

;; Operation: end := end + 1

(declare-const end2 Int)
(assert (= end2 (+ end1 1)))

(push)
  (assert (not (invariant start0 end2 arr0)))
  (check-sat) ; SAT --> Invariant has been broken!
(pop)

;; Operation: arr[start + 1] := arr[start + 1] + 1

(declare-const arr1 (Array Int Int))
(assert (= arr1 (store arr0 (+ start0 1) (+ (select arr0 (+ start0 1)) 1))))

(push)  
  (assert (not (invariant start0 end2 arr1)))
  (check-sat) ; UNSAT --> Invariant has been restored
(pop)