Is there a compact way of counting the number of bits that are set to 1 in a BitVec in Z3 using SMT 2 input format?
The accepted answer for this question: Sum of all the
There's really no easy way to do this directly in SMTLib for the time being.The best you can really do is to roll-your-own for each bit-vector size; rather ugly, but easy to generate code:
(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))
This prints:
sat
((result #x05))
Recent versions of the SMTLib standard allow for recursive functions which might be employed to do this "programmatically," but solver support remains rather sketchy when recursive functions are involved. The following works with z3, but other solvers may not fare so well. With that warning, here's a fancy way of doing it using recursion:
(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))
This also prints:
sat
((result #x05))
Note that whichever method you choose, you have to write a separate function for each size N
, in popCountN
. SMTLib doesn't allow users to define functions that work on "parametric" types. This is a fundamental limitation of the logic, and also one of the main reasons (though definitely not the only one!) why many people prefer scripting SMT solvers from higher level languages to avoid such boilerplate code.
Your best bet is to unroll your own version as outlined above. A common trick to use in Z3 is that you can use the Python program you linked and print s.sexpr()
at some point and look at what the generator produced. You can then cut-paste that into SMTLib if you like; though of course beware the usual cut-and-paste errors.