How to get_unsat_core in Z3? - z3

I have the following python program.
from z3 import *
x = Bool("X")
y = Bool("Y")
s = Solver()
s.add(x==y)
s.add(x!=False)
s.add(y!=True)
s.check()
The last line gives output unsat.
But how to print the unsat core of this?

You can ask for an unsat core as follows:
from z3 import *
# https://z3prover.github.io/api/html/classz3py_1_1_solver.html#ad1255f8f9ba8926bb04e1e2ab38c8c15
x = Bool('X')
y = Bool('Y')
s = Solver()
s.set(unsat_core=True)
s.assert_and_track(x == y, 'a1')
s.assert_and_track(x != False, 'a2')
s.assert_and_track(y != True, 'a3')
result = s.check()
print(result)
if result == unsat :
c = s.unsat_core()
print(len(c))
print('a1 ', Bool('a1') in c)
print('a2 ', Bool('a2') in c)
print('a3 ', Bool('a3') in c)
print(c)
Resulting output:
unsat
3
a1 True
a2 True
a3 True
[a1, a2, a3]
This is a trivial unsat core as it contains all assertions. Look at a related discussion.

Related

Why is Z3 giving me unsat for the following formula?

I have the following formula and Python code trying to find the largest n satisfying some property P:
x, u, n, n2 = Ints('x u n n2')
def P(u):
return Implies(And(2 <= x, x <= u), And(x >= 1, x <= 10))
nIsLargest = ForAll(n2, Implies(P(n2), n2 <= n))
exp = ForAll(x, And(P(n), nIsLargest))
s = SolverFor("LIA")
s.reset()
s.add(exp)
print(s.check())
if s.check() == sat:
print(s.model())
My expectation was that it would return n=10, yet Z3 returns unsat. What am I missing?
You're using the optimization API incorrectly; and your question is a bit confusing since your predicate P has a free variable x: Obviously, the value that maximizes it will depend on both x and u.
Here's a simpler example that can get you started, showing how to use the API correctly:
from z3 import *
def P(x):
return And(x >= 1, x <= 10)
n = Int('n')
opt = Optimize()
opt.add(P(n))
maxN = opt.maximize(n)
r = opt.check()
print(r)
if r == sat:
print("maxN =", maxN.value())
This prints:
sat
maxN = 10
Hopefully you can take this example and extend it your use case.

add iteratively in z3

I want to check the value of a, b, c, and if value 'a' equals to 1, 'x' is added one. We continue the process for values 'b' and 'c'.
So if a=1, b=1, c=1, the result of x should be 3.
if a=1, b=1, c=0, so the result of x should be 2.
Any methods to be implemented in z3?
The source code looks like this:
from z3 import *
a, b, c = Ints('a b c')
x, y = Ints('x y')
s = Solver()
s.add(If(a==1, x=x + 1, y = y-1))
s.add(If(b==1, x=x + 1, y = y-1))
s.add(If(c==1, x=x + 1, y = y-1))
s.check()
print s.model()
Any suggestions about what I can do?
This sort of "iterative" processing is usually modeled by unrolling the assignments and creating what's known as SSA form. (Static single assignment.) In this format, every variable is assigned precisely once, but can be used many times. This is usually done by some underlying tool as it is rather tedious, but you can do it by hand as well. Applied to your problem, it'd look something like:
from z3 import *
s = Solver()
a, b, c = Ints('a b c')
x0, x1, x2, x3 = Ints('x0 x1 x2 x3')
s.add(x0 == 0)
s.add(x1 == If(a == 1, x0+1, x0))
s.add(x2 == If(b == 1, x1+1, x1))
s.add(x3 == If(c == 1, x2+1, x2))
# Following asserts are not part of your problem, but
# they make the output interesting
s.add(b == 1)
s.add(c == 0)
# Find the model
if s.check() == sat:
m = s.model()
print("a=%d, b=%d, c=%d, x=%d" % (m[a].as_long(), m[b].as_long(), m[c].as_long(), m[x3].as_long()))
else:
print "no solution"
SSA transformation is applied to the variable x, creating as many instances as necessary to model the assignments. When run, this program produces:
a=0, b=1, c=0, x=1
Hope that helps!
Note that z3 has many functions. One you could use here is Sum() for the sum of a list. Inside the list you can put simple variables, but also expression. Here an example for both a simple and a more complex sum:
from z3 import *
a, b, c = Ints('a b c')
x, y = Ints('x y')
s = Solver()
s.add(a==1, b==0, c==1)
s.add(x==Sum([a,b,c]))
s.add(y==Sum([If(a==1,-1,0),If(b==1,-1,0),If(c==1,-1,0)]))
if s.check() == sat:
print ("solution:", s.model())
else:
print ("no solution possible")
Result:
solution: [y = 2, x = 2, c = 1, b = 0, a = 1]
If your problem is more complex, using BitVecs instead of Ints can make it run a little faster.
edit: Instead of Sum() you could also simply use addition as in
s.add(x==a+b+c)
s.add(y==If(a==1,-1,0)+If(b==1,-1,0)+If(c==1,-1,0))
Sum() makes sense towards readability when you have a longer list of variables, or when the variables already are in a list.

Z3Python: ForAll causes my code hangup, or returns Unsat, why?

I am still struggling with the problem of findiong a value so that a * b == b with all value of b. The expected result is a == 1. I have two solutions below.
(A) I implemented this with ForAll quantifier in below code (correct me if there is a solution without using any quantifier). The idea is to prove f and g are equivalent.
from z3 import *
a, b, a1, tmp1 = BitVecs('a b a1 tmp1', 32)
f = True
f = And(f, tmp1 == b)
f = And(f, a1 == a * tmp1)
g= True
g = And(g, a1 == b)
s = Solver()
s.add(ForAll([b, tmp1, a1], f == g))
if s.check() == sat:
print 'a =', s.model()[a]
else:
print 'Unsat'
However, this simple code runs forever without giving back result. I think that is because of the ForAll. Any idea on how to fix the problem?
(B) I tried again with another version. This time I dont prove two formulas to be equivalent, but put them all into one formula f. Logically, I think this is true, but please correct me if I am wrong here:
from z3 import *
a, b, a1, tmp = BitVecs('a b a1 tmp', 32)
f = True
f = And(f, tmp == b)
f = And(f, a1 == a * tmp)
f = And(f, a1 == b)
s = Solver()
s.add(ForAll([b, a1], f))
if s.check() == sat:
print 'a =', s.model()[a]
else:
print 'Unsat'
This time the code does not hang, but immediately returns 'Unsat'. Any idea on how to fix this?
Thanks a lot.
The direct formulation of your problem provides the answer you were expecting: http://rise4fun.com/Z3Py/N07sW
The versions you propose use auxiliary variables, a1, tmp, tmp1 and you
use universal quantification over these variables. This does not correspond
to the formula you intended.

Find logical conditions for 2 formulas to be equivalent?

I posted a related question, but then I think it was not very clear. I would like to rephrase the problem like this:
Two formulas a1 == a + b (1) and a1 == b (2) are equivalent if a == 0. Given these formulas (1) and (2), how can I use Z3 python to find out this required condition (a == 0) so the above formulas become equivalent?
I suppose that a1, a and b are all in the format of BitVecs(32).
Edit: I came up with the code like this:
from z3 import *
a, b = BitVecs('a b', 32)
a1 = BitVec('a1', 32)
s = Solver()
s.add(ForAll(b, a + b == b))
if s.check() == sat:
print 'a =', s.model()[a]
else:
print 'Not Equ'
The output is: a = 0, as expected.
However, when I modified the code a bit to use two formulas, it doesnt work anymore:
from z3 import *
a, b = BitVecs('a b', 32)
a1 = BitVec('a1', 32)
f = True
f = And(f, a1 == a * b)
g = True
g = And(g, a1 == b)
s = Solver()
s.add(ForAll(b, f == g))
if s.check() == sat:
print 'a =', s.model()[a]
else:
print 'Not Equ'
The output now is different: a = 1314914305
So the questions are:
(1) Why the second code produces different (wrong) result?
(2) Is there any way to do this without using ForAll (or quantifier) at all?
Thanks
The two codes produce the same correct answer a = 0. You have a typo: you are writing
a1 = a*b and it must be a1 = a + b . Do you agree?
Possible code without using ForAll:
a, b = BitVecs('a b', 32)
a1 = BitVec('a1', 32)
s = Solver()
s.add(a + b == b)
if s.check() == sat:
print 'a =', s.model()[a]
else:
print 'Not Equ'
s1 = Solver()
s1.add(a==0, Not(a + b == b))
print s1.check()
Output:
a = 0
unsat

z3python: no XOR operator?

I have this code in Z3 python:
x = Bool('x')
y = Bool('y')
z = Bool('z')
z == (x xor y)
s = Solver()
s.add(z == True)
print s.check()
But this code reports below error when running:
c.py(4): error: invalid syntax
If I replace xor with and, there is no problem. So this means XOR is not supported?
You should use Xor(a, b). Moreover, to create the Z3 expression that represents the formula a and b, we must use And(a, b). In Python, we can't overload the operators and and or.
Here is an example with the Xor (available online at rise4fun).
x = Bool('x')
y = Bool('y')
z = Xor(x, y)
s = Solver()
s.add(z)
print s.check()
print s.model()

Resources