使用SMT 2输入格式在Z3中的BitVec中计数

时间:2018-07-02 13:45:04

标签: z3

是否有一种简便的方法来计算使用SMT 2输入格式在Z3中的BitVec中设置为1的位数?

该问题的可接受答案: Sum of all the bits in a Bit Vector of Z3 显示了使用Python的方法。

1 个答案:

答案 0 :(得分:1)

暂时没有直接在SMTLib中直接执行此操作的简便方法。您真正能做的最好的事情就是为每个位向量大小滚动自己的代码。相当丑陋,但易于生成代码:

(set-logic QF_BV)
(set-option :produce-models true)

(define-fun popCount8 ((x (_ BitVec 8))) (_ BitVec 8)
                      (bvadd (ite (= #b1 ((_ extract 0 0) x)) #x01 #x00)
                             (ite (= #b1 ((_ extract 1 1) x)) #x01 #x00)
                             (ite (= #b1 ((_ extract 2 2) x)) #x01 #x00)
                             (ite (= #b1 ((_ extract 3 3) x)) #x01 #x00)
                             (ite (= #b1 ((_ extract 4 4) x)) #x01 #x00)
                             (ite (= #b1 ((_ extract 5 5) x)) #x01 #x00)
                             (ite (= #b1 ((_ extract 6 6) x)) #x01 #x00)
                             (ite (= #b1 ((_ extract 7 7) x)) #x01 #x00)))


; test
(define-fun x () (_ BitVec 8) #xAB)
(declare-fun result () (_ BitVec 8))
(assert (= result (popCount8 x)))
(check-sat)
; Should be 5!
(get-value (result))

此打印:

sat
((result #x05))

使用递归

SMTLib标准的最新版本允许使用递归函数,这些递归函数可以“以编程方式”执行,但是当涉及到递归函数时,求解器支持仍然很粗略。以下内容适用于z3,但其他求解器的效果可能不太好。有了该警告,这是一种使用递归的理想方法:

(set-logic BV)
(set-option :produce-models true)

(define-fun-rec popCount8_rec ((x (_ BitVec 8)) (i (_ BitVec 8)) (accum (_ BitVec 8))) (_ BitVec 8)
    (ite (= i #x08)
         accum
         (popCount8_rec (bvshl x #x01)
                        (bvadd i #x01)
                        (bvadd accum (ite (= #b1 ((_ extract 7 7) x)) #x01 #x00)))))

(define-fun popCount8 ((x (_ BitVec 8))) (_ BitVec 8) (popCount8_rec x #x00 #x00))

; test
(define-fun x () (_ BitVec 8) #xAB)
(declare-fun result () (_ BitVec 8))
(assert (= result (popCount8 x)))
(check-sat)
; Should be 5!
(get-value (result))

这也会打印:

sat
((result #x05))

参数多态性

请注意,无论选择哪种方法,都必须在N中为每种大小popCountN编写一个单独的函数。 SMTLib不允许用户定义适用于“参数”类型的函数。这是逻辑的基本限制,也是许多人偏爱使用高级语言编写SMT求解器脚本来避免此类样板代码的主要原因(尽管绝对不是唯一的原因!)。

Python技巧

您最好的选择是如上所述发布自己的版本。在Z3中使用的一个常见技巧是,您可以在某个时候使用链接和print s.sexpr()的Python程序,并查看生成器产生了什么。然后,您可以根据需要将其剪切粘贴到SMTLib中。当然要当心通常的剪切和粘贴错误。