Why does the type change to Real in z3 python? - z3

I was checking the sort for some operations in z3py and ran into the following:
x = Int('x')
y = Int('y')
print((1 + (2 + (x*(y**2)))).sort())
which outputs
Real
Why does the type of the expression result in a Real?

It's because the ** (exponentiation) operator always returns a Real in z3, even if the arguments are integers. Note that if the second argument is negative, then the result will not be an integer.
Compare:
>>> from z3 import *
>>> x, y, z = Ints('x y z')
>>> s = Solver()
>>> s.add(And(x == 2, y == -1, z == x ** y))
>>> print(s.check())
unsat
to:
>>> from z3 import *
>>> x, y = Ints('x y')
>>> z = Real('z')
>>> s = Solver()
>>> s.add(And(x == 2, y == -1, z == x ** y))
>>> print(s.check())
sat
>>> print(s.model())
[z = 1/2, y = -1, x = 2]
If you want an integer-only producing version of exponentiation, you can code it yourself by enforcing all results to be equal to some existential Int.
Note that the power operator is usually difficult to deal with in SMT solvers due to non-linearity, and undecidable in general due to the undecidability of Diophantine equations. So unless the constraints are easy enough you'll most likely get unknown as an answer at best, or the solver will loop forever.

Related

A model of a simple formula 'Exists([y],ForAll([x],Phi))' should be 'y=2' but Z3 it is returning '[]'

Note the following Z3-Py code:
x, y = Ints('x y')
negS0= (x >= 2)
s1 = (y > 1)
s2 = (y <= x)
s = Solver()
phi = Exists([y],ForAll([x], Implies(negS0, And(s1,s2))))
s.add(phi)
print(s.check())
print(s.model())
This prints:
sat
[]
My question is: why is the model empty? I mean, I think y=2 should be a model...
Note that the same result happens with x and y being Real.
z3 will not include any quantified variable (in your case neither y nor x) in its model. Note that you cannot put x in a model anyhow, because the formula is true for all x: That's the meaning of universal quantification. For the outer-most existentials (like your y), z3 can indeed print the model value for that, but it chooses not to do so since it can be confusing: Imagine you had a phi2, which also had an outer-most existential named y: How would you know which y it would be that it prints in the model?
So, z3 keeps things simple and simply prints the top-level declared variables in the model. And since a top-level declaration is equivalent to an outermost existential, you can simply drop it:
from z3 import *
x, y = Ints('x y')
negS0= (x >= 2)
s1 = (y > 1)
s2 = (y <= x)
s = Solver()
phi = ForAll([x], Implies(negS0, And(s1,s2)))
s.add(phi)
print(s.check())
print(s.model())
This prints:
sat
[y = 2]
like you predicted. Note that this y is unambiguous, since it's declared at the top-level. (Of course, you can redefine it to be something else due to the loosely typed nature of Python bindings and still get yourself confused, but that's a different 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.

Incorrect model of max value in Z3Py

I want to find a maximal interval in which an expression e is true for all x. A way to write such a formula should be: Exists d : ForAll x in (-d,d) . e and ForAll x not in (-d,d) . !e.
To get such a d, the formula f in Z3 (looking at the one above) could be the following:
from __future__ import division
from z3 import *
x = Real('x')
delta = Real('d')
s = Solver()
e = And(1/10000*x**2 > 0, 1/5000*x**3 + -1/5000*x**2 < 0)
f = ForAll(x,
And(Implies(And(delta > 0,
-delta < x, x < delta,
x != 0),
e),
Implies(And(delta > 0,
Or(x > delta, x < -delta),
x != 0),
Not(e))
)
)
s.add(Not(f))
s.check()
print s.model()
Which outputs [d = 1/4].
To check it, I set delta = RealVal('1/4'), drop the ForAll quantifier from f and I get x = 1/2. I replace delta with 1/2 and get 3/4, then 7/8 and so on. The bound should be 1. Can I get Z3 to output that immediately?
If you do the math yourself, you can see that the solution is x != 0, x < 1. Or you can simply ask Wolfram Alpha to do it for you. So, there's no such delta.
The issue you're having is that you're asserting:
s.add(Not(f))
This turns the universal quantification on x into an existential; asking z3 to find a delta such that there is some x that fits the bill. (That is, you're negating your whole formula.) Instead, you should do:
s.add(delta > 0, f)
which also makes sure that delta is positive. With that change, z3 will correctly respond:
unsat
(And then you'll get an error for the call to s.model(), you should only call s.model() if the previous call to s.check() returns sat.)

How to define piece-wise functions in Z3py

I would like to define a piece-wise (linear) function in Z3py, for example, the function f(x) has the form
f(x) = a*x + b when 0 <= x <= 1
f(x) = exp(c*x) when 1 < x <= 2
f(x) = 1/(1+10^x) when 2 < x <= 3
etc.
where a, b and c are constants.
I guess the z3.If() function will be relevant, but as the number of pieces grows, the expression gets convoluted.
My questions is, does Z3pyprovides the if-else statement, or is there an elegant way to define piece-wise function in Z3py?
Yes, Z3 supports if-then-elses and in Python they can be constructed using the If function. An example from the documentation of If:
>>> x = Int('x')
>>> y = Int('y')
>>> max = If(x > y, x, y)
max = If(x > y, x, y)

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