1. 程式人生 > >Z3求解器指南(一)

Z3求解器指南(一)

申明:本文翻譯自rise4fun,翻譯與原文存在一些差異。

z3是由微軟公司開發的一個優秀的SMT求解器(也就定理證明器),它能夠檢查邏輯表示式的可滿足性。

使用方式

z3是一個底層的工具,它最好是作為一個元件應用到其它需要求解邏輯公式的工具中。為了方便使用,z3提供了很多的API,這些api支援的語言有C, .NET, and OCaml。當然,z3也可以通過命令列的方式來執行。(最新版本的z3可以到這裡下載,微軟官網上只更新到4.1)

基本命令

Z3的輸入格式是SMT-LIB2.0標準(想進一步瞭解smt-lib標準,可以參考這個網站)的一個拓展,一個Z3指令碼就是一個命令序列。你可以使用help

命令去檢視一系列可用的命令。echo命令用於顯示一個資訊。Z3的內部維持著一個棧,這個棧裡面儲存著使用者輸入的公式和申明(常量的和函式的)。declare-const命令用於申明一個給定型別的常量,declare-fun命令則用於申明一個函式。

(echo "starting Z3...")
(declare-const a Int)
(declare-fun f (Int Bool) Int)

這個例子中申明瞭一個函式,有兩個引數,分別為Int型和Bool型,返回一個Int型的值

命令assert用於新增一個公式到z3的棧中,如果對於輸入的所有公式,z3能夠給出一種解釋(對於使用者定義的常量和函式),使得所有的公式都成立,那麼我麼說這個公式集是可滿足的。看下面這個例子:

(declare-const a Int)
(declare-fun f (Int Bool) Int)
(assert (> a 10))
(assert (< (f a true) 100))
(check-sat)

這個例子中第一個斷言表示常量a必須大於10,第二個斷言表示引數為a和true的函式f必須返回一個小於100的值。check-sat命令告訴求解器去求解當前z3棧中公式的可滿足性。如果棧中的公式是可滿足的,z3返回sat;如果不滿足,z3返回unsat;當求解器無法判斷當前公式是不是可滿足的就返回unknown。

如果命令集是可滿足的,我們可以使用get-model

命令去獲取一個使z3棧中所有公式整合立解釋。

(declare-const a Int)
(declare-fun f (Int Bool) Int)
(assert (> a 10))
(assert (< (f a true) 100))
(check-sat)
(get-model)

我們用z3去求解這個公式集,得到的結果如下:

sat
(model 
  (define-fun a () Int
    11)
  (define-fun f ((x!1 Int) (x!2 Bool)) Int
    (ite (and (= x!1 11) (= x!2 true)) 0
      0))
)

結果中sat指的是該公式集是可滿足的,而model中的內容則是對公式集的一個解釋,看起來不太好理解,我們下面對model中的解釋方式進行說明。

model中的解釋是通過定義的方式給定的,例如

(define-fun a () Int [val])

這個定義申明函式a的返回值為[val]

(define-fun f ((x!1 Int) (x!2 Bool)) Int
   ...
)

這個定義跟程式語言中的函式申明類似。其中x1和x2是z3給出的函式f的引數解釋。在上面的例子中,對f的定義使用了ite(if-than-else)的方式。

(ite (and (= x!1 11) (= x!2 false)) 21 0)

這個表示式是說當x1=11並且x2=false的時候函式返回21,否則返回0。這樣就給出了一個使得公式集滿足的解。

使用範圍

有時候在解決一些相似的問題的時候,我們希望去複用一些定義和斷言,z3提供了pushpop命令去實現這個功能。上面也提到了,z3會維持一個全域性的棧,定義和斷言就儲存在棧中。Push命令通過儲存當前棧大小的方式建立一個範圍。Pop命令則是移除與之相匹配的push之間的所有斷言和申明。

(declare-const x Int)
(declare-const y Int)
(declare-const z Int)
(push)
(assert (= (+ x y) 10))
(assert (= (+ x (* 2 y)) 20))
(check-sat)
(pop) ; remove the two assertions
(push) 
(assert (= (+ (* 3 x) y) 10))
(assert (= (+ (* 2 x) (* 2 y)) 21))
(check-sat)
(declare-const p Bool)
(pop)
(assert p) ; error, since declaration of p was removed from the stack

未完待續。。。。。。