3

I'm running the following test in Z3/Python:

def test_converting_word_into_byte_array():
    bytes_in_word = 4
    word_size = 8 * bytes_in_word
    word = BitVec('word', word_size)
    word_in_bytes = Array('bytes(word)', BitVecSort(word_size), BitVecSort(8))
    read = BitVec('read', word_size)
    pointer = BitVecVal(0, word_size)
    answer_array = Array('final(word)', BitVecSort(word_size), BitVecSort(8))

    solver = Solver()
    solver.add(word == BitVecVal(2, word_size))
    for byte in range(bytes_in_word):
        solver.add(Select(word_in_bytes, byte) == Extract(word_size - 1 - 8 * byte, word_size - 1 - 7 - 8 * byte, word))
    new_array = Lambda([read],
        If(
            And(ULE(pointer, read), ULE(read, pointer + bytes_in_word - 1)),
            Select(word_in_bytes, read - pointer),
            Select(K(BitVecSort(word_size), BitVecVal(0, 8)), read)))
    solver.add(answer_array == new_array)

    assert str(solver.check()) == "sat"
    print(solver.model())

While the solution is satisfactory, ultimately the solver model seems wrong:

[final(word) = Lambda(k!0, 2),
 bytes(word) = Lambda(k!0, If(k!0 == 3, 2, 0)),
 word = 2]

Question

Why is final(word) taking on the value of 2 when it should be equivalent to bytes(word) due to how the If condition is set up?

Peteris
  • 3,548
  • 4
  • 28
  • 44

1 Answers1

3

You are using arrays as lambdas in your program. Lambda's are not part of the official SMTLib language, (http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2017-07-18.pdf), so it's hard to exactly say if this should be allowed and what the consequences would be. But, as you found out, this seems to be a supported z3 extension, and you have found a bug!

Please report this at their issues site: https://github.com/Z3Prover/z3/issues.

NB. The Python encoding is really conflating the issue and making it really hard to read. Here's what I was able to create as a much simpler to read SMTLib benchmark:

(set-logic ALL)

(declare-fun inp () (Array Int Int))
(declare-fun out () (Array Int Int))

(assert (= (select inp 0) 0))
(assert (= (select inp 1) 0))
(assert (= (select inp 2) 1))

(assert (= out (lambda ((i Int))
                       (ite (and (<= 0 i) (<= i 2))
                            (select inp i)
                            0))))

(check-sat)

(get-value ((select inp 0)))
(get-value ((select inp 1)))
(get-value ((select inp 2)))
(get-value ((select out 0)))
(get-value ((select out 1)))
(get-value ((select out 2)))

For this, z3 reports:

sat
(((select inp 0) 0))
(((select inp 1) 0))
(((select inp 2) 1))
(((select out 0) 2))
(((select out 1) 2))
(((select out 2) 2))

But clearly, we're expecting equivalence in the range 0-2. I'd strongly recommend you report this SMTLib version of the problem instead of the original Python.

NB. This mixing of lambda's and arrays is definitely a Z3 extension. For instance, this is what CVC4 says on the benchmark:

(error "Subexpressions must have a common base type:
Equation: (= out (lambda ((i Int)) (ite (and (<= 0 i) (<= i 2)) (select inp i) 0)))
Type 1: (Array Int Int)
Type 2: (-> Int Int)
")

So, you're using an extension that is z3-specific. While that's not a bad thing, it is something to keep in mind.

alias
  • 28,120
  • 2
  • 23
  • 40
  • Thank you for the elaborate response. This is completely valid syntax according to: https://theory.stanford.edu/~nikolaj/programmingz3.html. The following example was listed: ``` m, m1 = Array('m', Z, Z), Array('m1', Z, Z) def memset(lo,hi,y,m): return Lambda([x], If(And(lo <= x, x <= hi), y, Select(m, x))) solve([m1 == memset(1, 700, z, m), Select(m1, 6) != z]) Lambda ``` – Peteris Feb 20 '19 at 08:00
  • I'd like to accept your answer, but the current one needs some corrections. It seems that model generation doesn't work for lambda expressions, but simple satisfiability does. – Peteris Feb 20 '19 at 09:57
  • Cool. Apparently, this is a z3 extension that is still being worked out. I've updated my answer to reflect that, and also put in a note about the error message CVC4 issues. – alias Feb 20 '19 at 11:04