Why does this transitive closure of z3 produce different results? - z3

I am running the following program about transitive closure of z3:
from z3 import *
def main():
A = DeclareSort('A')
R = Function('R', A, A, BoolSort())
TC_R = TransitiveClosure(R)
# TRC_R = TransitiveReflexiveClosure(R)
s = Solver()
a, b, c = Consts('a b c', A)
s.add(R(a, b))
s.add(R(b, c))
s.add(Not(TC_R(a, c)))
print(s.check())
if __name__ == "__main__":
main()
The output the above program on my computer is 'sat'. However, the documents says it should produce 'unsat' and I agree with this https://theory.stanford.edu/~nikolaj/programmingz3.html#sec-transitive-closure. But I don't know why my output is different? Here is the screenshot.

This looks like a bug. Please report it at: https://github.com/Z3Prover/z3/issues

Related

How to get_unsat_core in 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.

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.

Understanding quantifier traversing in Z3

I'm trying to understand traversing quantified formula in z3 (i'm using z3py). Have no idea how to pickup the quantified variables. For example in code shown below i'm trying to print the same formula and getting error.
from z3 import *
def traverse(e):
if is_quantifier(e):
var_list = []
if e.is_forall():
for i in range(e.num_vars()):
var_list.append(e.var_name(i))
return ForAll (var_list, traverse(e.body()))
x, y = Bools('x y')
fml = ForAll(x, ForAll (y, And(x,y)))
same_formula = traverse( fml )
print same_formula
With little search i got to know that z3 uses De Bruijn index and i have to get something like Var(1, BoolSort()). I can think of using var_sort() but how to get the formula to return the variable correctly. Stuck here for some time.
var_list is a list of strings, but ForAll expects a list of constants. Also, traverse should return e when it's not a quantifier. Here's a modified example:
from z3 import *
def traverse(e):
if is_quantifier(e):
var_list = []
if e.is_forall():
for i in range(e.num_vars()):
c = Const(e.var_name(i) + "-traversed", e.var_sort(i))
var_list.append(c)
return ForAll (var_list, traverse(e.body()))
else:
return e
x, y = Bools('x y')
fml = ForAll(x, ForAll (y, And(x,y)))
same_formula = traverse( fml )
print(same_formula)

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

Resources