Z3Py: constraint of not equal tuples - z3

I've got bunch of Bools:
a=Bool('a')
...
z=Bool('z')
How to pack some of these bools to tuples and then to add constraint about their non-equality?
I tried:
tuple1=(a,b,c,d)
tuple2=(e,f,g,h)
# so far so good
s=Solver()
s.add(tuple1 != tuple2)
But that doesn't work.

The python tuple does not get reflected to Z3 tuples.
You can create a tuple type for Z3 in the following wayL
from z3 import *
a,b,c,d,e,f,g,h = Ints('a b c d e f g h')
tuple = Datatype('tuple')
tuple.declare('tuple',('1', IntSort()), ('2', IntSort()), ('3', IntSort()), ('4', IntSort()))
tuple = tuple.create()
tuple1=tuple.tuple(a,b,c,d)
tuple2=tuple.tuple(e,f,g,h)
# so far so good
s=Solver()
s.add(tuple1 != tuple2)
print s.check()
print s.model()
In this case you get tuple disequality that Z3 understands.
Z3 does not understand the != or == operator between python tuples.
Perhaps it is possible to extend the python support to such data-types
but the distribution does not support such extensions.

Related

What does a model mean in a universally quantified formula? Is it a function?

Consider these two formulae:
Exists y. Forall x. (y>x), which is unsat.
Forall x. Exists y. (y>x), which is sat.
Note that we cannot find “models” for the sat formula, e.g., using Z3 it outputs Z3Exception: model is not available for the following code:
phi = ForAll([x],Exists([y], lit))
s_def = Solver()
s_def.add(phi)
print(s_def.model())
Also, quantifier elimination does not output an elimination, but a satisfiability result
[[]] (i.e., True):
x, y = Reals('x, y')
t = Tactic("qe")
lit = (y>x)
ae = Goal()
ae.add(ForAll([x],Exists([y], lit)))
ae_qe = t(ae)
print(ae_qe)
I think this happens because the value of y fully depends on x (e.g., if x is 5 then y can be 6). Thus, I have some questions:
Am I right with this interpretation?
What would be the meaning of “a model of a universally quantified formula”?
Do we say a formula accepts quantifier elimination even if it never eliminates the quantifier but "only: evaluate to True or False?
Is there a way to synthetise or construct a model/function that represents a y that holds the constraint (y>x); e.g. f(x)=x+1. In other words, does it make sense that the quantifier elimination of a Forall x. Exists y. Phi(x,y) like the example would be Forall x. Phi(x,f(x))?
You get a model-not-available, because you didn't call check. A model is only available after a call to check. Try this:
from z3 import *
x, y = Ints('x y')
phi = ForAll([x], Exists([y], y > x))
s = Solver()
s.add(phi)
print(s.check())
print(s.model())
This prints:
sat
[]
Now, you're correct that you won't get a meaningful/helpful model when you have a universal-quantifier; because the model will depend on the choice of x in each case. (You only get values for top-level existentials.) This is why the model is printed as the empty-list.
Side Note In certain cases, you can use the skolemization trick (https://en.wikipedia.org/wiki/Skolem_normal_form) to get rid of the nested existential and get a mapping function, but this doesn't always work with SMT solvers as they can only build "finite" skolem functions. (For your example, there isn't such a finite function; i.e., a function that can be written as a case-analysis on the inputs, or an if-then-else chain.)
For your specific questions:
Yes; value of y depends on x and thus cannot be displayed as is. Sometimes skolemization will let you work around this, but SMT solvers can only build finite skolem-functions.
Model of a universally quantified formula is more or less meaningless. It's true for all values of the universally quantified variables. Only top-level existentials are meaningful in a model.
Quantifier elimination did work here; it got rid of the whole formula. Note that QE preserves satisfiability; so it has done its job.
This is the skolem function. As you noted, this skolem function is not finite (can't be written as a chain of finite if-then-elses on concrete values), and thus existing SMT solvers cannot find/print them for you. If you try, you'll see that the solver simply loops:
from z3 import *
x = Int('x')
skolem = Function('skolem', IntSort(), IntSort())
phi = ForAll([x], skolem(x) > x)
s = Solver()
s.add(phi)
print(s)
print(s.check())
print(s.model())
The above never terminates, unfortunately. This sort of problem is simply too complicated for the push-button approach of SMT solving.

Lambda Functions for Z3Py

My goal is to find a construct within Z3Py which allows me to:
(1) Write propositions as a function of a variable. For eg theoretically, if I define P(x) = x < 3, then the code should allow me to access P(u) for some other variable u.
(2) And Z3 should be able to solve and find a model for such a construct.
I thought Z3's 'Lambda' function theoretically made sense. However with this construct neither can I do (1) or (2). As a concrete eg, suppose I have the following code:
u, x = Ints('u x')
P = Lambda( [x], x < 5 )
I = Lambda ([x], x < 3)
C1 = Not(Implies(P.body(), I.body() ))
s = Solver()
s.add(C1)
r = s.check()
print(r.__repr__())
s.add( Implies(P(u), u == 2) )
Run this code to get the output:
unknown
Traceback (most recent call last):
File "testfile.py", line 20, in <module>
s.add( Implies(P(u), u == 2) )
TypeError: 'QuantifierRef' object is not callable
There are two issues to fix here:
(1) Why does r._ repr_() have 'unknown' stored and not 'sat' i.e. Why isn't Z3 solving this system?
(2) In the final line, how can I get the predicate u < 5 from P i.e. in lambda calculus terminology, how do I do application of a function to a variable in Z3Py? Clearly P(u) does not work.
For this sort of modeling, you should simply use a regular python function:
from z3 import *
def P(x):
return x < 5
def I(x):
return x < 3
Then, to do the proof Q(x) => P(x), you'd use a quantifier:
dummy = Int('dummy')
C1 = ForAll([dummy], Implies(I(dummy), P(dummy)))
prove(C1)
This prints:
proved
Regarding your specific questions:
(1) Adding Implies(P.body(), Q.body()) means something completely different. If you run:
from z3 import *
x = Int('x')
P = Lambda( [x], x < 5 )
I = Lambda( [x], x < 3 )
s = Solver()
s.add(Implies(P.body(), I.body()))
print(s.sexpr())
You'll see it prints:
(assert (=> (< (:var 0) 5) (< (:var 0) 3)))
where :var is an internal free-variable generating function. This isn't an object you should be passing back and forth to z3; in fact, I think you're becoming a victim of the loosely typed nature of z3; this isn't a construct that really make much sense at all. Long story short, you should never look at P.body() or I.body() in your own code. I'd ignore the unknown result in this context; the input is more or less meaningless, and z3 spits out a nonsensical answer. A better system should've checked and complained about this; but this is not a strong point for z3's Python API.
(2) If you use a regular function, this isn't really a problem at all; because you're just doing regular application at the Python level. You can apply a lambda-bound value by directly calling it as well, though you need the notation P[u]. (Lambda's are similar to arrays in z3.) So, something like:
from z3 import *
u, x = Ints('u x')
P = Lambda([x], x < 5)
I = Lambda([x], x < 3)
s = Solver()
s.add(Implies(P[u], u == 2))
print(s.check())
print(s.model())
will print:
sat
[u = 2]
which is what you were looking for I think.
Multiple arguments
If you want to model a lambda with multiple arguments, the easiest way is to think of it as a nested construct. That is, you store a new lambda at each index. Here's an example:
from z3 import *
dummy1 = FreshInt()
dummy2 = FreshInt()
P = Lambda([dummy1], Lambda([dummy2], dummy1 < dummy2))
s = Solver()
x, y = Ints('x y')
s = Solver()
s.add(P[x][y])
print(s.check())
print(s.model())
This prints:
sat
[y = 1, x = 0]
Note that the above also demonstrates the use of the FreshInt function, which avoids name-clashes by providing a unique name each time it is called.

Using sets and SetHasSize on intersections in z3

I've been trying to enumerate solutions to the following problem. I've started with simple approach first.
Below I have two sets of size k, intersection between them is of size 1 and I want to see how sets A and B look:
Els, elems = EnumSort('Els',['a1', 'a2', 'a3'])
A, B = Consts('A B', SetSort(Els))
k, c = Ints('k c')
s = Solver()
s.add(SetHasSize(A, k))
s.add(SetHasSize(B, k))
s.add(k == 2, c == 1)
s.add(SetHasSize(SetIntersect(A, B), c))
s.check()
s.model()
Here, the solution should be A == ['a1', 'a2'] and B == ['a2', 'a3'] but satisfiability was not reached.
Even a simple task like one below results in never ending execution:
V, _ = EnumSort('Els',['a1', 'a2', 'a3'])
A = Const('A', SetSort(V))
k = Int('k')
s = SimpleSolver()
s.add(SetHasSize(A, k))
s.add(k == IntVal(2))
s.check()
s.model()
Changing k == IntVal(2) to k <= IntVal(2) makes the problem satisfiable and returns [A = ∃k!0 : k!0 = a1 ∨ k!0 = a2, k = 2] as a model of the set. I'm not sure if there is a faster approach.
If I run your program, I get:
WARNING: correct handling of finite domains is TBD
WARNING: correct handling of finite domains is TBD
WARNING: correct handling of finite domains is TBD
before it starts looping. This is a known issue in the implementation: Z3 cannot really deal with sets that have a finite domain.
Alas, replacing it with an infinite domain doesn't help either. Making this change:
A, B = Consts('A B', SetSort(IntSort()))
You get:
unsat
which is clearly bogus. I strongly suspect this is related to the following issue: https://github.com/Z3Prover/z3/issues/3854 (In short, the SMTLib frontend does not support set-has-size. For whatever reason, they left it in the Python and C/C++ interfaces, but clearly it's not really functional.)
So, strictly speaking, this is a bug. But more realistic answer is that set-has-size is no longer supported by z3. You should file an issue at https://github.com/Z3Prover/z3/issues so the authors are aware of this problem and perhaps remove it from the API completely if it won't ever be supported.
UPDATE:
As of this commit, z3 no longer accepts the set-has-size predicate; it is no longer supported.

partial assignments in Z3

I have a Boolean formula (format: CNF) whose satisfiablity I check using the Z3 SAT solver. I am interested in obtaining partial assignments when the formula is satisfiable. I tried model.partial=true on a simple formula for an OR gate and did not get any partial assignment.
Can you suggest how this can be done? I have no constraints on the assignment other than that it be partial.
Z3's partial model mode are just for models of functions. For propositional formulas there is no assurance that models use a minimal number of assignments. On the contrary, the default mode of SAT solvers is that they find complete assignments.
Suppose you are interested in a minimized number of literals, such that the conjunction of the literals imply the formula. You can use unsat cores to get such subsets. The idea is that you first find a model of your formula F as a conjunction of literals l1, l2, ..., ln. Then given that this is a model of F we have that l1 & l2 & ... & ln & not F is unsatisfiable.
So the idea is to assert "not F" and check satisfiability of "not F" modulo assumptions l1, l2, .., ln. Since the result is unsat, you can query Z3 to retrieve an unsat core among l1, l2, .., ln.
From python what you would do is to create two solver objects:
s1 = Solver()
s2 = Solver()
Then you add F, respectively, Not(F):
s1.add(F)
s2.add(Not(F))
then you find a reduced model for F using both solvers:
is_Sat = s1.check()
if is_Sat != sat:
# do something else, return
m = s1.model()
literals = [sign(m, m[idx]()) for idx in range(len(m)) ]
is_sat = s2.check(literals)
if is_Sat != unsat:
# should not happen
core = s2.unsat_core()
print core
where
def sign(m, c):
val = m.eval(c)
if is_true(val):
return c
else if is_false(val):
return Not(c)
else:
# should not happen for propositional variables.
return BoolVal(True)
There are of course other ways to get reduced set of literals. A partial cheap way is to eagerly evaluate each clause and add literals from the model until each clause is satisfied by at least one literal in the model. In other words, you are looking for a minimal hitting set. You would have to implement this outside of Z3.

UNKNOWN when using def's

This simple example generates UNKNOWN for me, I suppose there is something that I don't understand about def's.
from z3 import *
s = Solver()
def Min(b, r):
return If(b, r, 1)
a = Real('a')
b = Bool('b')
s.add(a==0.9)
s.add(a<=Min(b,0.9))
s.check()
print "Presenting result "
m = s.model()
print "traversing model..."
for d in m.decls():
print "%s = %s" % (d.name(), m[d])
You did not make any mistake. This is a problem in one of Z3 solvers. Your problem is in a fragment of arithmetic called "difference-logic". A problem in in this fragment, if the arithmetic atoms can be written as x - y <= k, where k is a numeral. When a problem is in this fragment, Z3 will use a specialized solver for it. However, this solver may fail (returns unknown) when the input problem also contains if-then-else terms (the If in your Min).
The bug has been fixed, and will be available in the next release. In the meantime, you can try one of the following workarounds:
Force Z3 to eliminate if-then-else terms before invoking the solver. You just have to replace s = Solver() with s = Then('elim-term-ite', 'smt').solver(). Here is the modified script at rise4fun.
We can add a redundant assertion that is not in the different logic fragment. Example: z + w > 2. Here is the modified script at rise4fun.

Resources