Z3 BitVector bug? - z3

There seems to be a bug in the bitvector theory of Z3. Creating a bitvector constant using Expr.mk_numeral_string in ML interface and then reading the expression using BitVector.get_string or BitVector.get_int results in amismatch.
Here are the details:
let create_bv_const ctx bv_str width =
let bv_sort = BitVector.mk_sort ctx width in
Expr.mk_numeral_string ctx bv_str bv_sort
Now
let bv1 = create_bv_const ctx "1111" 4.
Reading bv1 using Expr.to_string returns "7" when it should be "15".
Similar error occurs when using Expr.to_int. If
let bv1 = create_bv_const ctx "0010" 4
reading bv1 should give "2" but Z3 returns "10". "0011" gives "11" when it should be "3". I tried with widths 5, 8 bit vectors and there were similar issues. But with width <=3 bitvectors it works fine.
I tried an older version of Z3 (v. 4) and there is similar problem there as well.
Hope I am not missing something. I want to create formulas with bitvector variables and consts and read out the bitvector values.
Thanks

1111 mod 16 = 7, so this is correct. Note that argument 1111 is read as a decimal, not binary number.

Related

How to construct Empty BitVec in z3

Algorithm:
if BitVecA > 0
BitVecB = Concat(BitVecA, BitVecB)
I want to Concat two conditional bitvec and with no else condition by using If
I want to using
BitVecB = Contact(BitVecA, If(BitVecA>0, BitVecA, EmptyBitVec )),
but len of BitVec cannot be zero
It isn't clear what your question is. But if you look at https://smtlib.cs.uiowa.edu/theories-FixedSizeBitVectors.shtml you'll see that SMTLib only allows bit-vectors that have strictly positive lengths. (i.e., zero-length bitvectors are not part of the logic.)
So, if you need to reason with 0-length bit vectors, you'll have to write your code to handle it outside of the SMTLib fragment; i.e., in your wrapper code. But without knowing what your context is, hard to answer in any further detail.

Save and reload z3py solver constraints

Can I save the constraints I created for a z3 solver and later reload them to continue looking for more solutions?
I have learned there is the SMT-LIB2 format for such things and that z3 and z3py have an API for saving and loading in that format. Unfortunately I cannot make it work.
Here's my example program which pointlessly saves and reloads:
import z3
filename = 'z3test.smt'
# Make a solver with some arbitrary useless constraint
solver = z3.Solver()
solver.add(True)
# Save to file
smt2 = solver.sexpr()
with open(filename, mode='w', encoding='ascii') as f: # overwrite
f.write(smt2)
f.close()
# Load from file
solver.reset()
solver.from_file(filename)
It fails with:
Exception has occurred: ctypes.ArgumentError
argument 3: <class 'TypeError'>: wrong type
File "C:\Users\Marian Aldenhövel\Desktop\FridgeIQ\z3\z3-4.8.4.d6df51951f4c-x64-win\bin\python\z3\z3core.py", line 3449, in Z3_solver_from_file
_elems.f(a0, a1, _to_ascii(a2))
File "C:\Users\Marian Aldenhövel\Desktop\FridgeIQ\z3\z3-4.8.4.d6df51951f4c-x64-win\bin\python\z3\z3.py", line 6670, in from_file
_handle_parse_error(e, self.ctx)
File "C:\Users\Marian Aldenhövel\Desktop\FridgeIQ\src\z3test.py", line 17, in <module>
solver.from_file(filename)
Is this a problem with my understanding or my code? Can it be done like this? Are sexpr() and from_file() the right pair of API calls?
I am using z3 and z3py 4.8.4 from https://github.com/z3prover/z3/releases on Windows 10 64bit.
More detail if required:
I am playing with z3 in Python to find solutions for a large disection-puzzle.
To find all solutions I am calling solver.check(). When it returns a sat verdict I interpret the model as image of my puzzle solution. I then add a blocking clause ruling out that specific solution and call solver.check() again.
This works fine and I am delighted.
The runtime to find all solutions will be on the order of many days or until I get bored. I am concerned that my machine will not be running continuously for that long. It may crash, run out of power, or be rebooted for other reasons.
I can easily recreate the initial constraints which is the whole point of the program. But the blocking clauses are a runtime product and a function of how far we have gotten.
I thought I could save the state of the solver and if at runtime I find such a file restart by loading that with the blocking clauses intact and go on finding more solutions instead of having to start over.
Thank you for taking your time reading and thinking.
Marian
With z3 4.4.1 and z3 4.8.5, I would dump (and reload) the constraints in smt2 format as follows:
import z3
filename = "z3test.smt2"
x1 = z3.Real("x1")
x2 = z3.Real("x2")
solver = z3.Solver()
solver.add(x1 != x2)
#
# STORE
#
with open(filename, mode='w') as f:
f.write(solver.to_smt2())
#
# RELOAD
#
solver.reset()
constraints = z3.parse_smt2_file(filename, sorts={}, decls={})
solver.add(constraints)
print(solver)
output:
~$ python t.py
[And(x1 != x2, True)]
file z3test.smt2:
(set-info :status unknown)
(declare-fun x2 () Real)
(declare-fun x1 () Real)
(assert
(and (distinct x1 x2) true))
(check-sat)
I have no idea whether the API changed in the version you are using. Feedback is welcome.

Printing to specific (runtime-determined) precision in Julia

Given a value x and an integer n (assigned at runtime), I want to print x to exactly n digits after the decimal (after rounding if needed).
print(round(x, n)) works fine for (x,n)=(3.141592, 3) but for (x,n)=(2.5,5), it prints just 2.5, not 2.50000 (5 digits after decimal point).
If I knew n at runtime, say 5, I could do
#printf("%.5f", x)
But #printf being a macro needs n to be known at compile time.
Is this possible using some show magic or something else?
Using the fresh new Format.jl package:
using Format
function foo(x, n)
f = FormatSpec(".$(n)f")
pyfmt(f, x)
end
foo(2.5, 5)
Unfortunately, for some reason the julia version of #printf / #sprintf do not support the "width" sub-specifier as per the c printf standard (see man 3 printf).
If you're feeling brave, you can rely on the c sprintf which supports the "dynamic width" modifier, to collect a string that you then just print as normal.
A = Vector{UInt8}(100); # initialise array of 100 "chars"
ccall( :sprintf, Int32, (Ptr{UInt8}, Cstring, Int64, Float64), A, "%.*f", 4, 0.1 )
print( unsafe_string(pointer(A)) ) #> 0.1000
Note the asterisk in %.*f, and the extra input 4 serving as the dynamic width modifier.

Z3 - how assumptions works

I have the following code in Z3py
import z3
x = z3.BitVec('x', 32)
a = z3.BitVec('a', 32)
solver=z3.Solver()
solver.set(unsat_core=True)
d=z3.Bool('d')
solver.assert_and_track(x!=a,d)
solver.add(x==a)
print solver.check(d)
print solver.check(z3.Not(d))
I would expect it to print unsat and sat. However it prints always unsat. Should the call solver.check(z3.Not(d)) effectively disable the assertion x!=a?
assert_and_track simply associates the answer-literal d with the formula x!=a in your example. Since the context contains x==a and x!=a at the same time, it is unsat. No assumptions will make it satisfiable.
But I do agree that this is very confusing. I think the issue goes back to the fact that assert_and_track is not really intended for what you are trying to do, but merely to make unsat-core-extraction possible. See the discussion here: https://stackoverflow.com/a/14565535/936310
To really achieve what you want, simply assert the implication yourself. That is, use:
solver.add(Implies(d, x!=a))
For instance, the following script:
from z3 import *
x = z3.BitVec('x', 32)
a = z3.BitVec('a', 32)
solver=z3.Solver()
solver.set(unsat_core=True)
d=z3.Bool('d')
solver.add(Implies(d, x!=a))
solver.add(x==a)
print solver.check(d)
print solver.unsat_core()
print solver.check(z3.Not(d))
print solver.model()
produces:
unsat
[d]
sat
[a = 0, d = False, x = 0]
which is what you are trying to achieve, I believe.

Check overflow with Z3

I'm new to Z3 and I was checking the online python tutorial.
Then I thought I could check overflow behavior in BitVecs.
I wrote this code:
x = BitVec('x', 3)
y = Int('y')
solve(BV2Int(x) == y, Not(BV2Int(x + 1) == (y + 1)))
and I was expecting [y = 7, x = 7] (i.e. when values are equal but successors are not because x + 1 will be 0 and y + 1 will be 8)
But Z3 answers [y = 0, x = 0].
What am I doing wrong?
I don't think you're doing anything wrong, looks like BV2Int is buggy:
x = BitVec('x', 3)
prove(x <= 3)
prove(BV2Int(x) <= 3)
Z3py proves the first one, but gives the counter-example x=0 for the second. That doesn't sound right. (The only explanation might be some weird Python thing, but I don't see how.)
Also note that the model you get will depend on whether + treats the bit-vector as a signed number in the Python bindings, which I believe is the case. However, BV2Int might not do so, treating it as an unsigned value. This would further complicate the matters.
In any case, looks like BV2Int is not quite kosher; I'd stay away from it until there's an official answer from the Z3 folks.
For others who are concerned by this, this appears to have been solved at some point. I just re-ran this example with the latest version of z3 (a few years after initial post), and it does return 7,7.

Resources