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.
Related
Given the following simple example:
s = Solver()
Z = IntSort()
a = Const('a', Z)
s.add(a >= 0)
s.add(a < 10)
print(s.check(a > 5)) # sat
Up until the last line, a has an implied range of 0 <= a < 10 - for which a > 5 does not satisfy. However, .check() tells z3 that "this is true" - which is not what I'm after.
Is there a way to ask z3 to test if a > 5 given the existing set of constraints, and have z3 interpret this as "make sure this is true given everything else we know about a"?
EDIT: Okay I think I figured it out. Since z3 tries to find a model that satisfies all constraints, I should instead check for the inverse to see if it finds a solution - in which case, my check would not hold.
In this case, my "test" function would become:
def test(s, expr):
return s.check(Not(expr)) == unsat
thus...
s = Solver()
Z = IntSort()
a = Const('a', Z)
s.add(a >= 0)
s.add(a < 10)
print(s.check(a > 5)) # sat
print(s.check(Not(a > 5)) == unsat) # false, test failed
s.add(a > 8)
print(s.check(Not(a > 5)) == unsat) # true, test passed
Is that correct?
What you are doing is essentially correct, though not idiomatic. When you issue s.check(formula), you're telling z3 to show the satisfiability of all the other constraints you add'ed, along with formula; i.e., their conjunction. So, the way you set it up, it gives you the correct result.
Here's some more detail. Since what you want to prove looks like:
Implies(And(lower, upper), required)
the typical way of doing this would be to assert its negation, and then check if it is satisfiable. That is, you'd check if:
Not(Implies(And(lower, upper), required))
is satisfiable. Recall that Implies(a, b) is equivalent to Or(Not(a), b), so a little bit of Boolean logic transforms the above to:
And(And(lower, upper), Not(required))
What you are doing is to add the first conjunct above (i.e., And(lower, upper)) to the solver itself, and then use the second conjunct Not(required) as an argument to check to see if you get unsat. If you do, then you get a "proof" that required always holds. Otherwise you get a counterexample.
I should add, however, that this is not idiomatic usage of z3py and calls to check with a formula. The latter is usually used with a list of assumptions, and figuring out which subset of them was unsatisfiable with a call to get-unsat-assumptions. These applications typically come from model-checking problems. For details, see Section 4.2.5 of https://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2021-05-12.pdf which discusses the semantics of check-sat-assuming, which is the SMTLib equivalent of calling check with extra assumptions.
To solve your problem in more idiomatic z3, one would instead write something like:
from z3 import *
s = Solver()
a = Int('a')
lower = a >= 0
upper = a < 10
required = a > 5
formula = Implies(And(lower, upper), required)
# assert the negation
s.add(Not(formula))
r = s.check()
if r == sat:
print("Not valid, counterexample:")
print(s.model())
elif r == unsat:
print("Valid!")
else:
print("Solver said:", r)
This prints:
Not valid, counterexample:
[a = 0]
And if you change to lower = a >= 8, it'll print:
Valid!
Bottom line, what you're doing is correct but not very idiomatic usage for check-sat-assuming. A simpler way is to simply assert the negation of the implication that your lower/upper bounds imply the required inequality and check if the result is unsat instead.
I want to find the range of valid values that a variable can have, given some constraints. Eg,
x = Int('x')
s = Solver()
s.add(x >= 1)
s.add(x < 5+2)
Is there some way that I can get z3 to print 1..6 for this variable?
I tried using the following, but range() applies only to declarations.
print("x.range():", x.range()) # this does not work
Note: 1. This question seems to ask the same, but I did not understand its answers, and I am looking for python answer.
in reply to #Malte: I am not looking for all the answers, I just want to simplify multiple constraints in to a valid range. If constraints on both sides of the variable cannot be merged, then at least only on one side as is mentioned in above mentioned question.
This question comes up occasionally, and the answer isn't very trivial, unfortunately. It really depends on what your constraints are and exactly what you are trying to do. See:
Is it possible to get a legit range info when using a SMT constraint with Z3
And
(Sub)optimal way to get a legit range info when using a SMT constraint with Z3
Essentially, the problem is too difficult (and I'd say not even well defined) if you have multiple variables. If you have exactly one variable, you can use the optimizer to some extent, assuming the variable is indeed bounded. In case you have multiple variables, one idea might be to fix all but one to satisfying constants, and compute the range of that last variable based on the constant assignment to the others. But again, it depends on what you're really trying to achieve.
Please take a look at the above two answers and see if it helps you. If not, please show us what you tried: Stack-overflow works the best when you post some code and see how it can be improved/fixed.
As a SAT/SMT solver, Z3 "only" needs to find a single model (satisfying assignment) to show that a formula is satisfiable. Finding all models is therefore not directly supported.
The question comes up regularly, though, and the solution is to repeatedly find and then block (assume in negated form) models until no further model can be found. For example, for your snippet of code:
x = Int('x')
s = Solver()
s.add(x >= 1)
s.add(x < 5+2)
result = s.check()
while result == sat:
m = s.model()
print("Model: ", m)
v_x = m.eval(x, model_completion=True)
s.add(x != v_x)
result = s.check()
print(result, "--> no further models")
Executing the script yields the solution you asked for, albeit in a less concise form:
Model: [x = 1]
Model: [x = 2]
Model: [x = 3]
Model: [x = 4]
Model: [x = 5]
Model: [x = 6]
unsat --> no further models
In general,
you would have iterate over all variables (here: just x)
model completion is necessary for variables whose value doesn't affect satisfiability; since any value will do, they won't be explicit in the model
Related questions whose answers provide additional details:
(Z3Py) checking all solutions for equation
Why Z3Py does not provide all possible solutions
Getting all solutions of a boolean expression in Z3Py never ends
Formula which I wanna solve looks like this in C:
#define foo(w,x,y) ((((w)*(x)*(y)+31) & ~31) / 8)
WORD w,x,y,z;
y = 24;
if( (foo(w,x,y) * z) == -1 )
printf("yeah!");
I rewrite it to z3py in the following way:
from z3 import *
w= BitVec('w',16)
x= BitVec('x',16)
z= BitVec('z',16)
y= BitVecVal(24,16)
solve( (UDiv( (w*x*y+31) & ~31, 8 )) * z == 0xffffffff)
Any suggestions ?
PS: Please notice that trying to solve formula in that form:
solve( (UDiv( (w*x*y+31), 8 )) * z == 0xffffffff)
is possible, so I can't belive that bit-wise operation causes this formula Unsatisfiable.
I don't see anything wrong in Z3 behavior. Why do you think the formula should be satisfiable?
A = (w*x*y+31) & ~31 -- imply that the 5 rightmost bits will be always zero
B = UDiv( A & ~31, 8 ) (equal to a logical shift right by 3) -- imply that the 2 rightmost bits will be always zero.
C = B * z -- this will always have the 2 rightmost bits zero
c == 0xffffffff -- that's impossible
If you change the constant to 0xfffffffc, then you'll get a solution.
The C program doesn't print anything for me. And Z3 says "no solution". So, it's consistent.
Does your C program prints "yeah!"? If so, aren't you on a big-endian machine? I've tried your example in an x86 machine.
I have been using Z3 to check if terms can be satisfied. But in addition I need to simplify terms for human consumption e.g. when n is an Int simplify And(n>4 , n != 5) to n > 5. Dose any one know how to do this in Z3 or via other tools?
As you probably already noticed Z3 has a simplifier exposed over the API and you can also use it from SMT-LIB. The tutorials on Z3 from rise4fun.com/z3 and rise4fun.com/z3py give several examples of the simplifier. However, the simplifier does not attempt any normal form conversions, so it will unlikely produce results of the style you hint you want. In particular it does not simplify the conjunction And(n > 4, n != 5) to n > 5.
Possible answer:
n = Int('n')
antecedent = And(n >4, n != 5)
claim1 = n > 5
prove(Implies(antecedent, claim1))
Output:
proved
Can I ask Z3 to search from certain starting values to satisfy the constraints ?
Say, If I have two RealExprs x and y, and I have x==y as the constraint.
Can I ask Z3 to search from x=-9999, y=-9997 such that Z3 might return to me a model with x=-9998 and y=-9998 and say "SAT" ?
As far as I understand your question, you are kind of looking for a solution to a maximisation/minimisation problem, namely, of the following function
f(x, y) = |x + 9999| + |y + 9997|
together with the constraint x = y. As stated in the answers to this question, Z3 currently doesn't support this directly. However, as also stated, you can try to solve such problems by querying Z3 inside a Python loop that adds previously found solutions as new constraints of the next query.