I’m currently computing the weight of bitvectors using the python api for z3.
After searching through the python API for more straight forward method, I’m implementing the weight function for a bitvector st1 in the following manner:
Sum([( (st1 & (2**(i)))/(2**(i)) ) for i in range(bits)])
My question is relatively straight-forward, is there an easier/more efficient way?
I have problems which contain 1500+ of these weight constraints and would like to make sure I’m doing things as efficiently as possible.
Edit: I’ll add the following clarification, what I’m attempting to calculate has a name (it’s the Hamming Weight), I know there are ultra efficient ways of implementing the functionality in imperative languages, but ultimately what I’m looking for is if there are any underlying methods to access individual bits of a z3 bitvector.
I played a little bit with the example you posted in the question:
I believe the unsat instances are hard to solve because the problem seems to have many symmetries.
If that is the case, we can improve the performance by including “symmetry breaking constraints”.
Z3 can’t break the symmetries automatically for this kind of problem.
Here is a minor encoding improvement. The expression
((st1 & (2**(i)))/(2**(i))is essentially extracting the i-th bit. We can useExtract(i, i, st1)to extract the i-th bit. The result is a Bit-vector of size 1. Then, we have to “expand” it to avoid overflows. The bit-vectors in your problem have at most 28 bits. So, 5 bits is enough to avoid overflows. Therefore, we can useZeroExt(4, Extract(i, i, st1)). That is, we replacewith
I get a modest 2x speedup. So, Z3 still cannot solve the 6 bits unsat instance 🙁