Does Z3 have troubles with division? - z3

During a project, I encountered a phenomenon I can't explain. It is boiled down in the following minimal example (using Z3Py) which should be unsat but returns a model.
from z3 import *
solver = Solver()
x = Int("x")
# The next proposition is clearly unsatisfiable
solver.add(And(x > 0, (x + 1) * (1 / (x + 1)) != 1))
solver.add(x == 1)
# Still, Z3 provides a "model"
print(solver.check())
print(solver.model())
Is there anything I am missing? Is it forbidden to use division in certain situations?
Z3 version: 4.8.14
Python version: 3.9

Note that when you use / over integers, than the result is an integer itself. That is, we use integer division; which in SMTLib is defined to be the Euclidian one. See https://smtlib.cs.uiowa.edu/theories-Ints.shtml for details.
This means that the expression 1 / (1+1) reduces to 0, since division produces an integer. So you end up with 0 != 1, which is true, and thus your problem is satisfiable.
If you want division to produce reals, then you should either start with a real x (i.e., x = Real("x")) in which case your problem will be unsat; or convert the arguments to be over the reals, via an expression of the form ToReal(x); which again will produce unsat for your problem.
So, in the first case, your modification will be:
x = Real('x')
casting the problem over reals. Or, if you want to keep x an integer, yet the division to be over the reals, you should use:
solver.add(And(x > 0, ToReal(x + 1) * (1 / ToReal(x + 1)) != 1))
which does the conversion.
I should note that mixing integers and reals in this way can lead to hard problems in general, and the solver might end up reporting unknown. But that's besides the point for your particular question here.

Related

Do you know how to set "weak" initial values to each of z3 Array element?

For example, is there a something like below weak_Store function in Z3?
from z3 import *
a = Array('a', IntSort(), IntSort())
a = weak_Store(a, 0, 0)
a = weak_Store(a, 1, 1)
s = Solver()
s.add(a[0] == 100)
print(s.check()) # should print "sat"
print(s.model().eval(a[0])) # should print "100"
print(s.model().eval(a[1])) # should print "1" which is stored as weak_Store.
Since a[1] is not involved in the above constraint solving, this should not be computed and changed even after s.check().
I think this is related to model_completion variable in z3_model_eval,
but z3_model_eval does not work for z3 Array element.
Although the example is written in Python, I would like to do it with z3 C api.
Can anybody help me?
Thank you in advance.
This sort of constraints are called "soft" constraints, i.e., those that can be violated if necessary, but the solver will try to satisfy them otherwise. Note that you have to use the Optimize object, (not Solver), which has diminished capacity in general. (i.e., slower, more likely to say unknown etc.)
To add a soft constraint, use add_soft instead of add in z3py. You can code your example in Python like this:
from z3 import *
a = Array('a', IntSort(), IntSort())
s = Optimize()
s.add_soft(a[0] == 0)
s.add_soft(a[1] == 1)
s.add(a[0] == 100)
print(s.check())
print(s.model().eval(a[0]))
print(s.model().eval(a[1]))
This prints:
sat
100
1
as you requested.
In the C-API, the corresponding call is Z3_optimize_assert_soft.

Normal form of formula returned by Z3's qe tactic

I'm using Z3's quantifier elimination tactic via Z3py and have tried the following examples.
from z3 import *
x,y,xp,yp = Ints('x y xp yp')
t = Tactic('qe')
t(Exists((xp, yp), And(xp==x+1, yp==y+2, xp<=8, xp >=1, yp<=12, yp>=2)))
#returns: [[y <= 10, y >= 0, x <= 7, x >= 0]]
t(Exists((xp, yp), Implies(x<10 , And(xp==x+1, yp==y+2, xp<=8, xp >=1, yp<=12, yp>=2))))
#returns: [[Or(10 <= x, And(y <= 10, y >= 0, And(x <= 7, x >= 0)))]]
I think that the resultant formulas are in quantifier-free DNF(which is what I need), but I could not find anything in the API documentation that guarantees it. Does anyone know if qe always returns formulas in DNF?
Where can I(if at all) find such details regarding tactics without having to dig through the original source code?
EDIT: All formulas are restricted to linear integer arithmetic.
By design, tactics make "best effort." That is, while qe is designed to eliminate quantifiers, it may end up failing to do so, returning the goal stack unchanged.
Note that quantifier elimination is not just one tactic, but it is a whole collection of them, depending on what other theories are involved in your benchmark. See the directory: https://github.com/Z3Prover/z3/tree/master/src/qe

Signed division not working in z3py

I was trying to work with z3py. I came across a strange problem. I read that the operation / is treated as signed division for bit vectors in z3py. I was trying to give the following commands:
a = z3.BitVec('a',2)
b = z3.BitVec('b',2)
solver = z3.Solver()
solver.add((a + b)/2 == 3)
solver.check()
The result z3 gives is unsat
In my views this is not correct because it has a solution a = 2, b = 0, a = 2 in 2's complement means a = -2, so (a+b)/2 must be equal to -1 i.e. 3 by signed representation.
Can anyone please help me what is wrong here?
I finally found the solution myself!
The problem is in expression (a+b)/2. Here a and b are Bit Vectors of size 2. So the denominator 2 of the expression is also treated as a 2-bit Bit Vector by z3. So the 2 in denominator is actually -2. Thus the constraint I was trying to solve was (a+b)/(-2) == -1 This is actually unsat.

Simplifying integer formulas in Z3

After applying quantifier elimination in Z3 to a linear arithmetic formula h, I'm getting a 30-line or so formula. It turns out this formula is equivalent to h2=And(n>2, i>=0, i<=n-2), which I would much prefer as an output.
I tried ctx-solver-simplify; I'm getting:
And(Not(n <= 2), Or(Not(i >= 1), Not(n + -1*i <= 1)), i >= 0)
Now, Not(n<=2) can be more succinctly expressed as n>=3, Not(n + -1*i <= 1) as n-i>=2, and in this formula i >= 1 is not needed.
Repeat(Then('nnf','ctx-solver-simplify')) does a little better (by getting rid of i>=1).
Is there a better simplification tactic?
Similarly, is there a tactic that would transform Or(x==0, x==1, x==2, x==3) into And(x>=0,x<=3)?
My current best solution is to use Repeat(Then(OrElse('split-clause', 'nnf'), 'propagate-ineqs', 'ctx-solver-simplify')), with the latest unstable version of Z3 (where the bug in ctx-solver-simplify has been corrected).

Minimum and maximum values of integer variable

Let's assume a very simple constraint: solve(x > 0 && x < 5).
Can Z3 (or any other SMT solver, or any other automatic technique)
compute the minimum and maximum values of (integer) variable x that satisfies the given constraints?
In our case, the minimum is 1 and the maximum is 4.
Z3 has not support for optimizing (maximizing/minimizing) objective functions or variables.
We plan to add this kind of capability, but it will not happen this year.
In the current version, we can "optimize" an objective function by solving several problems where in each iteration we add additional constraints. We know we found the optimal when the problem becomes unsatisfiable. Here is a small Python script that illustrates the idea. The script maximizes the value of a variable X. For minimization, we just have to replace s.add(X > last_model[X]) with s.add(X < last_model[X]). This script is very naive, it performs a "linear search". It can be improved in many ways, but it demonstrates the basic idea.
You can also try the script online at: http://rise4fun.com/Z3Py/KI1
See the following related question: Determine upper/lower bound for variables in an arbitrary propositional formula
from z3 import *
# Given formula F, find the model the maximizes the value of X
# using at-most M iterations.
def max(F, X, M):
s = Solver()
s.add(F)
last_model = None
i = 0
while True:
r = s.check()
if r == unsat:
if last_model != None:
return last_model
else:
return unsat
if r == unknown:
raise Z3Exception("failed")
last_model = s.model()
s.add(X > last_model[X])
i = i + 1
if (i > M):
raise Z3Exception("maximum not found, maximum number of iterations was reached")
x, y = Ints('x y')
F = [x > 0, x < 10, x == 2*y]
print max(F, x, 10000)
As Leonardo pointed out, this was discussed in detail before: Determine upper/lower bound for variables in an arbitrary propositional formula. Also see: How to optimize a piece of code in Z3? (PI_NON_NESTED_ARITH_WEIGHT related).
To summarize, one can either use a quantified formula, or go iteratively. Unfortunately, these techniques are not equivalent:
Quantified approach needs no iteration, and can find global min/max in a single call to the solver; at least in theory. However, it does give rise to harder formulas. So, the backend solver can time-out, or simply return "unknown".
Iterative approach creates simple formulas for the backend solver to deal with, but it can loop forever if there's no optimal value; simplest example being trying to find the largest Int value. Quantified version can solve this problem nicely by quickly telling you that there is no such value, while the iterative version would go on indefinitely. This can be a problem if you don't know ahead of time that your constraints do have an optimal solution. (Needless to say, the "sufficient" iteration count is typically hard to guess, and might depend on random factors, like the seed used by the solver.)
Also keep in mind that if there is a custom optimization algorithm for the problem domain at hand, it's unlikely that a general purpose SMT solver can outperform it.
z3 now supports optimization.
from z3 import *
o = Optimize()
x = Int( 'x' )
o.add(And(x > 0, x < 5))
o.maximize(x)
print(o.check()) # prints sat
print(o.model()) # prints [x = 4]
This particular problem is an integer program.

Resources