指定Z3和类型的构造函数的无量词方法

时间:2019-03-24 17:52:25

标签: z3 smt

比方说,我在Z3中有一个简单的求和类型,其中包含几个不同Arities的构造函数:

(declare-datatypes ()
  ((Foo bar
        (baz (unbaz String))
        (quux (unquux1 String) (unquux2 Int)))))

如何断定我知道类型Foo的值是quux?我可以在quux1quux2上引入一个存在性,但是我对引入似乎不必要的量词保持谨慎。有没有更好的方法来断言呢?

1 个答案:

答案 0 :(得分:0)

假设存在时,存在是相当无害的,因为直接量化存在量化的变量,因此仅需要附加符号。也就是说,摘要的后半部分

(declare-datatypes ()
  ((Foo bar
        (baz (unbaz String))
        (quux (unquux1 String) (unquux2 Int)))))

(declare-const f Foo)

(assert (exists ((s String) (i Int)) ;; Let f be a quux
  (= f (quux s i))
))

(assert (= f (baz "test"))) ;; Also let f be a baz
(check-sat) ;; UNSAT - as expected

等同于

...
(declare-const _s String)
(declare-const _i Int)
(assert (= f (quux _s _i))) ;; Let f be a quux

(assert (= f (baz "test"))) ;; Also let f be a baz
(check-sat) ;; UNSAT - as expected

如果您对存在性而不是包容所有的事物保持警惕,则可以通过Foo构造函数到不同标签的映射公理化方法来标记 Foo值:

(set-option :smt.mbqi false)

(declare-datatypes ()
  ((Foo bar
        (baz (unbaz String))
        (quux (unquux1 String) (unquux2 Int)))))

;; Declare a finite sort Foo_tag with three distinct elements
(declare-datatypes () ((Foo_tag Foo_tag.bar Foo_tag.baz Foo_tag.quux)))

;; Alternatively, three distinct elements from an infinite sort such 
;; as Int can be used. Either by choosing distinct but unspecified 
;; values, as done below, or by directly choosing concrete values,
;; e.g. 1, 2, 3.
; (define-sort Foo_tag () Int)
; (declare-const Foo_tag.bar Foo_tag)
; (declare-const Foo_tag.baz Foo_tag)
; (declare-const Foo_tag.quux Foo_tag)
; (assert (distinct Foo_tag.bar Foo_tag.baz Foo_tag.quux))

;; Tagging function
(declare-fun tag_of (Foo) Foo_tag)

;; Tagging axiom for bar ...
(assert (= (tag_of bar) Foo_tag.bar))

;; ... baz ...
(assert (forall ((s String)) (! 
  (= (tag_of (baz s)) Foo_tag.baz)
  :pattern ((baz s))
)))

;; ... and quux
(assert (forall ((s String) (i Int)) (! 
  (= (tag_of (quux s i)) Foo_tag.quux)
  :pattern ((quux s i))
)))

;; Let's do some testing

(declare-const f Foo)

(assert (= (tag_of f) Foo_tag.quux)) ;; Tag f as a quux

(push)
  (assert (= f bar))
  (check-sat) ;; UNSAT - as expected
(pop)

(push)
  (assert (= f (baz "test")))
  (check-sat) ;; UNSAT - as expected
(pop)