我想要一种方法,给定一个不变量和一个或多个操作的效果,检查在操作执行后,不变量是否仍然存在。
关于如何实现这一目标的任何想法?
使用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))
总是使定理不饱和。
但是我需要声明初始状态是有效的,这样当我运行时(断言(不是不变)),操作未改变的系统部分是有效的。
答案 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)