Reducing an integer set in z3 over addition - z3

I'm experimenting with (and failing at) reducing sets in z3 over operations like addition. The idea is eventually to prove stuff about arbitrary reductions over reasonably-sized fixed-sized sets.
The first of the two examples below seems like it should yield unsat, but it doesn't. The second does work, but I would prefer not to use it as it requires incrementally fiddling with the model.
def test_reduce():
LIM = 5
VARS = 10
poss = [Int('i%d'%x) for x in range(VARS)]
i = Int('i')
s = Solver()
arr = Array('arr', IntSort(), BoolSort())
s.add(arr == Lambda(i, And(i < LIM, i >= 0)))
a = arr
for x in range(len(poss)):
s.add(Implies(a != EmptySet(IntSort()), arr[poss[x]]))
a = SetDel(a, poss[x])
def final_stmt(l):
if len(l) == 0: return 0
return If(Not(arr[l[0]]), 0, l[0] + (0 if len(l) == 1 else final_stmt(l[1:])))
sm = final_stmt(poss)
s.push()
s.add(sm == 1)
assert s.check() == unsat
Interestingly, the example below works much better, but I'm not sure why...
def test_reduce_with_loop_model():
s = Solver()
i = Int('i')
arr = Array('arr', IntSort(), BoolSort())
LIM = 1000
s.add(arr == Lambda(i, And(i < LIM, i >= 0)))
sm = 0
f = Int(str(uuid4()))
while True:
s.push()
s.add(arr[f])
chk = s.check()
if chk == unsat:
s.pop()
break
tmp = s.model()[f]
sm = sm + tmp
s.pop()
s.add(f != tmp)
s.push()
s.add(sm == sum(range(LIM)))
assert s.check() == sat
s.pop()
s.push()
s.add(sm == 11)
assert s.check() == unsat

Note that your call to:
f = Int(str(uuid4()))
Is inside the loop in the first case, and is outside the loop in the second case. So, the second case simply works on one variable, and thus converges quickly. While the first one keeps creating variables and creates a much harder problem for z3. It's not surprising at all that these two behave significantly differently, as they encode entirely different constraints.
As a general note, reducing an array of elements with an operation is just not going to be an easy problem for z3. First, you have to assume an upper bound on the elements. And if that's the case, then why bother with Lambda or Array at all? Simply create a Python list of that many variables, and ignore the array logic completely. That is:
elts = [Int("s%d"%i) for i in range(100)]
And then to access the elements of your 'array', simply use Python accessor notation elts[12].
Note that this only works if all your accesses are with a constant integer; i.e., your index cannot be symbolic. But if you're looking for proving reduction properties, that should suffice; and would be much more efficient.

Related

Can somebody help to model this function (polynomial function) in SMT solver Z3?

F(x1) > a;
F(x2) < b;
∀t, F'(x) >= 0 (derivative) ;
F(x) = ∑ ci*x^i; (i∈[0,n] ; c is a constant)
Your question is quite ambiguous, and stack-overflow works the best if you show what you tried and what problems you ran into.
Nevertheless, here's how one can code your problem for a specific function F = 2x^3 + 3x + 4, using the Python interface to z3:
from z3 import *
# Represent F as a function. Here we have 2x^3 + 3x + 4
def F(x):
return 2*x*x*x + 3*x + 4
# Similarly, derivative of F: 6x^2 + 3
def dF(x):
return 6*x*x + 3
x1, x2, a, b = Ints('x1 x2 a b')
s = Solver()
s.add(F(x1) > a)
s.add(F(x2) < b)
t = Int('t')
s.add(ForAll([t], dF(t) >= 0))
r = s.check()
if r == sat:
print s.model()
else:
print ("Solver said: %s" % r)
Note that I translated your ∀t, F'(x) >= 0 condition as ∀t. F'(t) >= 0. I assume you had a typo there in the bound variable.
When I run this, I get:
[x1 = 0, x2 = 0, b = 5, a = 3]
This method can be generalized to arbitrary polynomials with constant coefficients in the obvious way, but that's mostly about programming and not z3. (Note that doing so in SMTLib is much harder. This is where the facilities of host languages like Python and others come into play.)
Note that this problem is essentially non-linear. (Variables are being multiplied with variables.) So, SMT solvers may not be the best choice here, as they don't deal all that well with non-linear operations. But you can deal with those problems as they arise later on. Hope this gets you started!

Getting all solutions of a boolean expression in Z3Py never ends

Probably a basic question related to Z3: i am trying to get all solutions of a boolean expression, e.g. for a OR b, i want to get {(true, true),(false,true),(true,false)}
Based on other responses found, e.g. Z3: finding all satisfying models, i have the following code:
a = Bool('a')
b = Bool('b')
f1=Or(a,b)
s=Solver()
s.add(f1)
while s.check() == sat:
print s
s.add(Not(And(a == s.model()[a], b == s.model()[b])))
The issue is that it enters an infinite loop as at the second iteration: the constraint a == s.model()[a] is evaluated to false b/c s.model()[a] does not exist anymore.
Can someone tell what i am doing wrong?
I would advice you to try writing your loop like this instead:
from z3 import *
a = Bool('a')
b = Bool('b')
f1 = Or(a,b)
s = Solver()
s.add(f1)
while s.check() == sat:
m = s.model()
v_a = m.eval(a, model_completion=True)
v_b = m.eval(b, model_completion=True)
print("Model:")
print("a := " + str(v_a))
print("b := " + str(v_b))
bc = Or(a != v_a, b != v_b)
s.add(bc)
The output is:
Model:
a := True
b := False
Model:
a := False
b := True
Model:
a := True
b := True
The argument model_completion=True is necessary because otherwise m.eval(x) behaves like the identity relation for any x Boolean variable with a don't care value in the current model m and it returns x as a result instead of True/False. (See related Q/A)
NOTE: since z3 kindly marks don't care Boolean variables, an alternative option would be to write your own model generator that auto-completes any partial model. This would reduce the number of calls to s.check(). The performance impact of this implementation is hard to gauge, but it might be slightly faster.

z3py: Retrieve branching conditions from z3 formula

Let's say I have a z3py program like this one:
import z3
a = z3.Int("a")
input_0 = z3.Int("input_0")
output = z3.Int("output")
some_formula = z3.If(a < input_0, 1, z3.If(a > 1, 4, 2))
s = z3.Solver()
s.add(output == some_formula)
s.check()
m = s.model()
print(m)
Is there an elegant way for me to retrieve the branching conditions from some_formula?
So get a list like [a < input_0, a > 1]. It should work for arbitrarily deep nesting of if expressions.
I know there is some way to use cubes, but I am not able to retrieve more than two cube expressions. I am not sure how to configure the solver.
My ultimate goal is to force the solver to give me different outputs based on the constraints I push and pop. The constraints are the set of conditions I have inferred from this formula.
You can print the cubes using:
for cube in s.cube():
print cube
But this isn't going to really help you. For your example, it prints:
[If(a + -1*input_0 >= 0, If(a <= 1, 2, 4), 1) == 1]
[Not(If(a + -1*input_0 >= 0, If(a <= 1, 2, 4), 1) == 1)]
which isn't quite what you were looking for.
The easiest way to go about your problem would be to directly walk down the AST of the formula yourself, and grab the conditions as you walk along the expressions. Of course, Z3 AST is quite a hairy object (pun intended!), so this will require quite a bit of programming. But reading through the constructors (If, Var etc.) in this file can get you started: https://z3prover.github.io/api/html/z3py_8py_source.html
Alright,thanks #alias! I came up with a custom version, which gets the job done. If someone knows a more elegant way to do this, please let me know.
import z3
a = z3.Int("a")
input_0 = z3.Int("input_0")
output = z3.Int("output")
some_formula = z3.If(a < input_0, 1, z3.If(a > 1, 4, 2))
nested_formula = z3.If(some_formula == 1, 20, 10)
s = z3.Solver()
s.add(output == some_formula)
s.check()
m = s.model()
print(m)
def get_branch_conditions(z3_formula):
conditions = []
if z3.is_app_of(z3_formula, z3.Z3_OP_ITE):
# the first child is usually the condition
cond = z3_formula.children()[0]
conditions.append(cond)
for child in z3_formula.children():
conditions.extend(get_branch_conditions(child))
return conditions
conds = get_branch_conditions(some_formula)
print(conds)
conds = get_branch_conditions(nested_formula)
print(conds)

Initial value for variables

I would like to set the initial value for variables in z3py in an efficient way.
x,y = Ints(x,y)
s = Solver()
s.add(x>10)
s.check()
s.model()
I would expect the output value is e.g., x = 11, y = 0, not the result x = 11, y = 7.
One way to do it is:
x,y = Ints(x,y)
s = Optimize()
s.add_soft(x==0)
s.add_soft(y==0)
s.add(x>10)
s.check()
s.model()
But it takes much computation time as my program contains many of variables. Any better way to do it?
The slow-down is because you're forcing the optimizer to run, which is an overkill for this purpose. (The optimizing solver can handle max-sat problems, which does the job here, but it is costly and not needed for this case.)
Instead, simply walk over the model and see if there's an assignment for it:
from z3 import *
def model_with_zeros(s, vs):
m = s.model()
result = []
for v in vs:
val = m.eval(v)
if val.eq(v):
result.append((v, 0))
else:
result.append((v, val))
return result
x, y = Ints('x y')
s = Solver()
s.add(x > 10)
print s.check()
print model_with_zeros(s, [x, y])
This prints:
sat
[(x, 11), (y, 0)]
Note that you have to explicitly pass the solver and the variables you are interested in to the model_with_zeros function; as the trick here is precisely to see which variables the solver left untouched.
If you want a different initial value, then you can modify model_with_zeros to account for that for each variable separately.

Find how many of the first n elements of an Array satisfy a condition in z3

I have a z3 Array:
x = Array('x', IntSort(), IntSort())
A fixed number n:
n = 10
And a filtering condition based on simple arithmetic:
lambda i: Or(i == 0, i > 2)
What I want is to know the total number of elements from index 0 to index n which satisfy this condition (something that, if this were a normal python list, would look like len(filter(lambda i: i == 0 or i > 2, x)).
I can't figure out how to do this in z3. I tried
y == Int('y')
solver.add(y == sum([1 if Or(x[i] == 0, x[i] > 2) else 0 for i in range(0,n)]))
but get the following error:
z3.z3types.Z3Exception: Symbolic expressions cannot be cast to concrete Boolean values.
Is there a way to proceed? Many thanks!
It'd be best to post the exact code you tried. For one thing, the if-then-else should be coded using the If construct and the sum is best expressed using Sum. The following works fine, for instance:
from z3 import *
x = Array ('x', IntSort(), IntSort())
solver = Solver()
n = 10
y = Int('y')
solver.add(y == Sum([If(Or(x[i] == 0, x[i] > 2), 1, 0) for i in range(0,n)]))
print solver.check()
print solver.model()
But this'll be satisfiable for all values of y since there is no constraint on the contents of the array x.

Resources