z3smtcvc4optimathsatmathsat

What conversion operators are available in Z3 and CVC4 for Bit-Vectors?


I am writing a BV encoding of a problem which requires converting some Int to BitVec and viceversa.

In mathsat/optimathsat one can use:

((_ to_bv BITS) <int_term>) ; Int => BitVec
(sbv_to_int <bv_term>)      ; Signed BitVec => Int
(ubv_to_int <bv_term>)      ; Unsigned BitVec => Int

In z3 one can use:

((_ int2bv BITS) <int_term>) ; Int => BitVec
???                          ; Signed BitVec => Int   
(bv2int <bv_term>)           ; Unsigned BitVec => Int

In CVC4 one can use:

((_ int2bv BITS) <int_term>) ; Int => BitVec
???                          ; Signed BitVec => Int   
???                          ; Unsigned BitVec => Int

Q:

note: I am limited by the text-based SMT-LIB interface (no API solution).


Solution

  • SMTLib does define bv2nat and nat2bv:

    bv2nat, which takes a bitvector b: [0, m) → {0, 1} with 0 < m, and returns an integer in the range [0, 2^m), and is defined as follows:

       bv2nat(b) := b(m-1)*2^{m-1} + b(m-2)*2^{m-2} + ⋯ + b(0)*2^0
    

    o nat2bv[m], with 0 < m, which takes a non-negative integer n and returns the (unique) bitvector b: [0, m) → {0, 1} such that

       b(m-1)*2^{m-1} + ⋯ + b(0)*2^0 = n rem 2^m
    

    See here: http://smtlib.cs.uiowa.edu/theories-FixedSizeBitVectors.shtml

    Both CVC4 and z3 should support these two operations. (If not, you should report it to them!)

    For everything else, you'll have to do the math yourself. SMTLib is decidedly agnostic about "sign" of a bit-vector; it attributes no sign to a given vector, but instead it provides signed and unsigned version of arithmetic operators when they are different. (For instance, there's only one version of addition since it doesn't matter if you have signed or unsigned bit-vectors for that operation, but for comparisons we get bvult, bvslt etc.)

    From these two functions, you can define your other variants. For instance, to do signed-bitvector x of length 8 to integer, I'd go:

    (ite (= ((_ extract 7 7) x) #b0)
               (bv2nat ((_ extract 6 0) x))
            (- (bv2nat ((_ extract 6 0) x)) 128)))
    

    That is, you check the top bit of x:

    One gotcha: You cannot make an SMTLib function that does this for you for all bit-vector sizes. This is because SMTLib does not allow users to define size-polymorphic functions. You can, however, generate as many of such functions as you want by declaring them on the fly, or simply generate the corresponding expressions whenever needed.

    Other operations are similarly encodable using similar tricks. Please ask specific questions if you run into issues.