Trying to find all solutions to a boolean formula using Z3 in python - z3

I'm new to Z3, and trying to make a solver which returns every satisfiable solution to a boolean formula. Taking notes from other SO-posts, I've coded what I hoped would work, but isn't. The problem seems to that by adding the previous solutions, I remove some of the variables, but then they return in later solutions?
Currently I am just trying to solve a or b or c.
If I explained poorly, let me know and I will try to explain further.
Thanks in advance for the response :)
My code:
from z3 import *
a, b, c = Bools('a b c')
s = Solver()
s.add(Or([a, b, c]))
while (s.check() == sat):
print(s.check())
print(s)
print(s.model())
print(s.model().decls())
print("\n")
s.add(Or([ f() != s.model()[f] for f in s.model().decls() if f.arity() == 0]))
My output:
sat
[Or(a, b, c)]
[c = False, b = False, a = True]
[c, b, a]
sat
[Or(a, b, c), Or(c != False, b != False, a != True)]
[b = True, a = False]
[b, a]
sat
[Or(a, b, c),
Or(c != False, b != False, a != True),
Or(b != True, a != False)]
[b = True, a = True]
[b, a]
sat
[Or(a, b, c),
Or(c != False, b != False, a != True),
Or(b != True, a != False),
Or(b != True, a != True)]
[b = False, c = True]
[b, c]

The typical way to code such problems is as follows:
from z3 import *
a, b, c = Bools('a b c')
s = Solver()
s.add(Or([a, b, c]))
res = s.check()
while (res == sat):
m = s.model()
print(m)
block = []
for var in m:
block.append(var() != m[var])
s.add(Or(block))
res = s.check()
This prints:
[b = True, a = False, c = False]
[a = True]
[c = True, a = False]
You'll notice that not all models are "complete." This is because z3 will typically "stop" assigning variables once it decides the problem is sat, as the other variables are irrelevant.
I suppose your confusion is that there should be 7 models to your problem: Aside from the all-False assignment, you should have a model. If you want to get the values of all your variables in this way, then you should explicitly query for them, like this:
from z3 import *
a, b, c = Bools('a b c')
s = Solver()
s.add(Or([a, b, c]))
myvars = [a, b, c]
res = s.check()
while (res == sat):
m = s.model()
block = []
for var in myvars:
v = m.evaluate(var, model_completion=True)
print("%s = %s " % (var, v)),
block.append(var != v)
s.add(Or(block))
print("\n")
res = s.check()
This prints:
a = False b = True c = False
a = True b = False c = False
a = True b = True c = False
a = True b = True c = True
a = True b = False c = True
a = False b = False c = True
a = False b = True c = True
And there are exactly 7 models as you would've expected.
Note the model_completion parameter. This is a common pitfall for newcomers as there isn't a "out-of-the-box" method in z3 for getting all possible assignments, so you have to be careful coding it yourself like above. The reason why there isn't such a function is that it's really hard to implement it in general: Think about how it should work if your variables were functions, arrays, user-defined data-types, etc. as opposed to simple booleans. It can get really tricky to implement a generic all-sat function with all these possibilities handled correctly and efficiently. So, it's left to the user, as most of the time you only care about a specific notion of all-sat that's typically not hard to code once you learn the basic idioms.

Related

Get atoms of a Boolean formula in Z3

I was wondering if there is a method to get the atoms of a Boolean formula:
a = Bool('a')
b = Bool('b')
c = Bool('C')
d = Bool('D')
e = Bool('E')
f = Bool('F')
formula = And(Or(a, b), Or(c, d), Or(e, f))
I wonder if something like this exists:
formula.get_atoms() or get_atoms(formula)
to give me following desired output:
{A, B, C, D, E, F}
In pySMT, get_atoms() exists the provides the atoms. However, for some reason, I need to experiment on Z3.
You can traverse through the hierarchy of children() (documentation):
def atoms(expr):
a = set()
if not str(expr) in {'True', 'False'}:
c = expr.children()
if len(c):
for child in c:
a = a.union(atoms(child))
else:
a = {expr}
return a
a = Bool('a')
b = Bool('b')
c = Bool('C')
d = Bool('D')
e = Bool('E')
f = Bool('F')
formula = And(Or(a, b), Or(c, d), Or(e, f))
print(atoms(formula))

How to get_unsat_core in Z3?

I have the following python program.
from z3 import *
x = Bool("X")
y = Bool("Y")
s = Solver()
s.add(x==y)
s.add(x!=False)
s.add(y!=True)
s.check()
The last line gives output unsat.
But how to print the unsat core of this?
You can ask for an unsat core as follows:
from z3 import *
# https://z3prover.github.io/api/html/classz3py_1_1_solver.html#ad1255f8f9ba8926bb04e1e2ab38c8c15
x = Bool('X')
y = Bool('Y')
s = Solver()
s.set(unsat_core=True)
s.assert_and_track(x == y, 'a1')
s.assert_and_track(x != False, 'a2')
s.assert_and_track(y != True, 'a3')
result = s.check()
print(result)
if result == unsat :
c = s.unsat_core()
print(len(c))
print('a1 ', Bool('a1') in c)
print('a2 ', Bool('a2') in c)
print('a3 ', Bool('a3') in c)
print(c)
Resulting output:
unsat
3
a1 True
a2 True
a3 True
[a1, a2, a3]
This is a trivial unsat core as it contains all assertions. Look at a related discussion.

z3 cannot prove transitive identity

I am trying z3 what can it do.
So far so good, but I noticed that z3 fails on very trivial expression:
from z3 import *
a = Int("a")
b = Int("b")
c = Int("c")
prove(((a == b) and (b == c)) == ((a == c) and (c == b)))
$ python p.py
counterexample
[c = 1, b = 0, a = 0]
Python's and is not symbolic-aware. Instead, use z3's And method:
from z3 import *
a = Int("a")
b = Int("b")
c = Int("c")
prove(And(a == b, b == c) == (And(a == c, c == b)))
This prints:
proved

z3py optimization as variables chosen from a list

For the example, how to write code in z3py to maximize value of a+b+c+d as a,b,c,d are all chosen from list [1,2,3,4,5,6,7,8], which is given as the input. a, b, c, d are distinct values.
a, b, c, d = Ints("a b c d")
o = Optimize()
list = [1,2,3,4,5,6,7,8]
o.maximize(a+b+c+d)
how to write code corresponding to choose "a b c d" value from list. The correct out value of a+b+c+d is 26
Thanks!
Here's one way:
from z3 import *
a, b, c, d = Ints("a b c d")
o = Optimize()
list = [1,2,3,4,5,6,7,8]
vars = [a, b, c, d]
for v in vars:
o.add(Or([v == e for e in list]))
o.add(Distinct(*vars))
goal = Int("goal")
o.add(goal == a+b+c+d)
o.maximize(goal)
if o.check() == sat:
print o.model()
else:
print "not satisfiable"
When I run this, I get:
$ python a.py
[d = 5, c = 8, b = 6, a = 7, goal = 26]

Find logical conditions for 2 formulas to be equivalent?

I posted a related question, but then I think it was not very clear. I would like to rephrase the problem like this:
Two formulas a1 == a + b (1) and a1 == b (2) are equivalent if a == 0. Given these formulas (1) and (2), how can I use Z3 python to find out this required condition (a == 0) so the above formulas become equivalent?
I suppose that a1, a and b are all in the format of BitVecs(32).
Edit: I came up with the code like this:
from z3 import *
a, b = BitVecs('a b', 32)
a1 = BitVec('a1', 32)
s = Solver()
s.add(ForAll(b, a + b == b))
if s.check() == sat:
print 'a =', s.model()[a]
else:
print 'Not Equ'
The output is: a = 0, as expected.
However, when I modified the code a bit to use two formulas, it doesnt work anymore:
from z3 import *
a, b = BitVecs('a b', 32)
a1 = BitVec('a1', 32)
f = True
f = And(f, a1 == a * b)
g = True
g = And(g, a1 == b)
s = Solver()
s.add(ForAll(b, f == g))
if s.check() == sat:
print 'a =', s.model()[a]
else:
print 'Not Equ'
The output now is different: a = 1314914305
So the questions are:
(1) Why the second code produces different (wrong) result?
(2) Is there any way to do this without using ForAll (or quantifier) at all?
Thanks
The two codes produce the same correct answer a = 0. You have a typo: you are writing
a1 = a*b and it must be a1 = a + b . Do you agree?
Possible code without using ForAll:
a, b = BitVecs('a b', 32)
a1 = BitVec('a1', 32)
s = Solver()
s.add(a + b == b)
if s.check() == sat:
print 'a =', s.model()[a]
else:
print 'Not Equ'
s1 = Solver()
s1.add(a==0, Not(a + b == b))
print s1.check()
Output:
a = 0
unsat

Resources