是否有一种简便的方法来计算使用SMT 2输入格式在Z3中的BitVec中设置为1的位数?
该问题的可接受答案: Sum of all the bits in a Bit Vector of Z3 显示了使用Python的方法。
答案 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求解器脚本来避免此类样板代码的主要原因(尽管绝对不是唯一的原因!)。
您最好的选择是如上所述发布自己的版本。在Z3中使用的一个常见技巧是,您可以在某个时候使用链接和print s.sexpr()
的Python程序,并查看生成器产生了什么。然后,您可以根据需要将其剪切粘贴到SMTLib中。当然要当心通常的剪切和粘贴错误。