I'm trying to collect all the variables in a formula (quantified formula in Z3py). A small example
w, x, y, z = Bools('w x y z')
fml = And( ForAll(x, ForAll(y, And(x, y))), ForAll(z, ForAll(w, And(z, w))) )
varSet = traverse( fml )
The code i use to traverse is
def traverse(e):
r = set()
def collect(e):
if is_quantifier(e):
# Lets assume there is only one type of quantifier
if e.is_forall():
collect(e.body())
else:
if ( is_and(e) ):
n = e.num_args()
for i in range(n):
collect( e.arg(i) )
if ( is_or(e) ):
n = e.num_args()
for i in range(n):
collect( e.arg(i) )
if ( is_not(e) ):
collect( e.arg(0) )
if ( is_var(e) ):
r.add( e )
collect(e)
return r
And I'm getting: set( [Var(0), Var(1)] ). As i understand this is due to Z3 uses De Bruijn index. Is it possible to avoid this and get the desired set: set( [Var(0), Var(1), Var(2), Var(3)] ).
Your code is correct; there is no Var(2) or Var(3) in this example. There are two top-level quantifiers and the de-Bruijn indices in each of them are 0 and 1. Those two quantifiers do not appear within the body of another quantifier, so there can be no confusion.
Related
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.
I'm trying to learn how to write code for giving a counterexample to a horn clause and it's guessed interpretation. In the below code, let I be the uninterpreted function (it's a trivial loop invariant). The first 3 s.add() add the condition requirements for I(x), and the fourth one is a guess candidate for I. I try to use the s.prove directive to get a counterexample to my guessed candidate for I. I seem to be getting a huge error log on running this code, could anyone tell me what's wrong?
s = SolverFor("HORN")
I = Function('I', IntSort(), BoolSort())
x, x2 = Ints('x x2')
s.set("produce-proofs", True)
s.add( ForAll( [x] ,Implies( x == 0 , I(x))) )
s.add( ForAll( [x, x2] , Implies ( And( I(x), x2 == x + 1 , x < 5) , I(x2) ) ) )
s.add( ForAll( [x] ,Implies( And( I(x), Not(x < 5) ) , x == 5 ) ) )
s.add( ForAll( [x], And( Implies( I(x) , (x == 2) ), Implies( (x == 2) , I(x) ) ) ) ) #Adding guessed invariant here!
assert unsat == s.check()
print(s.proof())
You've a couple of mistakes in the script; perhaps this dates back from a while ago with a different version of z3? In any case, the following goes through with z3 version 4.8.14:
from z3 import *
s = SolverFor("HORN")
I = Function('I', IntSort(), BoolSort())
x, x2 = Ints('x x2')
s.set("proof", True)
s.add( ForAll( [x] ,Implies( x == 0 , I(x))) )
s.add( ForAll( [x, x2] , Implies ( And( I(x), x2 == x + 1 , x < 5) , I(x2) ) ) )
s.add( ForAll( [x] ,Implies( And( I(x), Not(x < 5) ) , x == 5 ) ) )
s.add( ForAll( [x], And( Implies( I(x) , (x == 2) ), Implies( (x == 2) , I(x) ) ) ) ) #Adding guessed invariant here!
print(s.check())
Unfortunately it prints:
unknown
This means the solver wasn't able to determine if the input is satisfiable or not; it gave up and said unknown. An earlier version of the solver might've been able to solve this successfully, providing an unsatisfiability proof, or a model should it be satisfiable.
I recommend tracking down where you got this example from and find out which version of z3 they were using. Going back to that version might help you make progress. Or, if you think the problem should be solvable as is, you can file a bug report at https://github.com/Z3Prover/z3/issues
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.
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)
Solver.model() sometimes returns an assignment with a seemingly-needless Var(), whereas I was (perhaps naively) expecting Solver.model() to always return a concrete value for each variable. For example:
#!/usr/bin/python
import z3
x, y = z3.Ints('x y')
a = z3.Array('a', z3.IntSort(), z3.IntSort())
e = z3.Not(z3.Exists([x], z3.And(x != y, a[x] == a[y])))
solver = z3.Solver()
solver.add(e)
print solver.check()
print solver.model()
produces
sat
[k!1 = 0,
a = [else -> k!5!7(k!6(Var(0)))],
y = 1,
k!5 = [else -> k!5!7(k!6(Var(0)))],
k!5!7 = [1 -> 3, else -> 2],
k!6 = [1 -> 1, else -> 0]]
What's going on here? Is Var(0) in a's "else" referring to the 0th argument to the a array, meaning a[i] = k!5!7[k!6[i]]? Is it possible to get a concrete satisfying assignment for a out of Z3, such as a = [1 -> 1, else -> 0]?
This is the intended output. The interpretation for functions and arrays should be viewed as function definitions. Keep in mind that the assertion
z3.Not(z3.Exists([x], z3.And(x != y, a[x] == a[y])))
is essentially a universal quantifier. For quantifier free problems, Z3 does generate the "concrete assignments" suggested in your post. However, this kind of representation is not expressive enough. In the end of the message, I attached an example that cannot be encoded using "concrete assignments".
The following post has additional information about how models are encoded in Z3.
understanding the z3 model
You can find more details regarding the encoding used by Z3 at http://rise4fun.com/Z3/tutorial/guide
Here is an example that produces a model that can't be encoded using "concrete" assignments (available online at http://rise4fun.com/Z3Py/eggh):
a = Array('a', IntSort(), IntSort())
i, j = Ints('i j')
solver = Solver()
x, y = Ints('x y')
solver.add(ForAll([x, y], Implies(x <= y, a[x] <= a[y])))
solver.add(a[i] != a[j])
print solver.check()
print solver.model()