z3py optimization as variables chosen from a list - z3

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]

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))

F# unclear function effects

I'm reading the F# for C# developers book and there's this function that I can't seem to understand what are the effects of this function
let tripleVariable = 1, "two", "three"
let a, b, c = tripleVariable
let l = [(1,2,3); (2,3,4); (3,4,5)]
for a,b,c in l do
printfn "triple is (%d,%d,%d)" a b c
the output is
triple is (1,2,3)
triple is (2,3,4)
triple is (3,4,5)
why a, b, c are initialized with tripleVariable? Is it because it was needed in the for loop to know their type (or its type, since it's a Tuple)?
The code snippet is using variable shadowing when defining the variables a, b and c. The variables are first initialized to the values of tripleVariable (line 2), but then they are shadowed by a new definition inside the for loop (line 4).
You can think of these as different variables - the code is equivalent to the following:
let tripleVariable = 1, "two", "three"
let a1, b1, c1 = tripleVariable
let l = [(1,2,3); (2,3,4); (3,4,5)]
for a2, b2, c2 in l do
printfn "triple is (%d,%d,%d)" a2 b2 c2
Variable shadowing simply lets you define a variable with a name that already exists in the scope. It hides the old variable and all subsequent code will only see the new one. In the above code snippet, the old (shadowed) variables b and c even have different types than the new ones.
The code contains 2 samples. The first one is
let tripleVariable = 1, "two", "three"
let a, b, c = tripleVariable
The 2nd one
let l = [(1,2,3); (2,3,4); (3,4,5)]
for a,b,c in l do
printfn "triple is (%d,%d,%d)" a b c
They can be run independently.
The values a, b, and c in the for loop hide the a, b, and c defined outside of the loop. You can print a, b, and c after the loop to see that they still contain the values from tripleVariable:
let tripleVariable = 1, "two", "three"
let a, b, c = tripleVariable
let l = [(1,2,3); (2,3,4); (3,4,5)]
for a,b,c in l do
printfn "triple is (%d,%d,%d)" a b c
printfn "tripleVariable is (%A,%A,%A)" a b c
Result:
triple is (1,2,3)
triple is (2,3,4)
triple is (3,4,5)
tripleVariable is (1,"two","three")

Lua can't unpack a table starts with two nil assigned elementwise

I tried the following code in Lua. The first four cases work well but the last two fail. I get nil as results in those two. What is the problem?
v = {nil, 10, nil}
a, b, c = unpack(v)
-- Output: a, b, c = nil 10 nil
print('a, b, c = ', a, b, c)
v = {nil, nil, 10}
a, b, c = unpack(v)
-- Output: a, b, c = nil nil 10
print('a, b, c = ', a, b, c)
v = {}
v[2] = 10
a, b, c = unpack(v)
-- Output: a, b, c = nil 10 nil
print('a, b, c = ', a, b, c)
v = {}
v[1] = nil
v[2] = 10
v[3] = nil
a, b, c = unpack(v)
-- Output: a, b, c = nil 10 nil
print('a, b, c = ', a, b, c)
v = {}
v[3] = 10
a, b, c = unpack(v)
-- Output: a, b, c = nil nil nil
print('a, b, c = ', a, b, c)
v = {}
v[1] = nil
v[2] = nil
v[3] = 10
a, b, c = unpack(v)
-- Output: a, b, c = nil nil nil
print('a, b, c = ', a, b, c)
When using a table as an array, all elements are required to have values different than nil.
Setting the value for a key to nil effectively removes that key from the table. But in an array all integer keys from 1 to the length of that array must be set. “Holes” are not allowed. So the behaviour in all your cases is unspecified.
You can verify by printing all key/value pairs in the table:
t = {0, nil, 2, 3}
print("pairs:")
for k, v in pairs(t) do
print("["..k.."]", v)
end
And note how ipairs breaks, since it stops at the first nil element.
print("ipairs:")
for k, v in ipairs(t) do
print("["..k.."]", v)
end
Workaround in your case is described in an answer here: Lua unpack bug?

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

why this code returns Unsat?

Given c == a + 4 and t == c + b, if b == -4, then t == a. I am trying to do the opposite, meaning given the above 2 equations and t == a, I try to find value of b.
This is pretty similar to the related question, but this time I only switch a and b, and I am really confused that the code returns different result.
Following the code posted at above link, I have below code (similar, only a and b swiched):
#!/usr/bin/python
from z3 import *
a, b, c, t = BitVecs('a b c t', 32)
g = True
g = And(g, c == (a + 4))
g = And(g, t == (c + b))
s = Solver()
s.add(ForAll([t, a, c], Implies(t == a, g)))
if s.check() == sat:
print s.model()[b]
else:
print 'Unsat'
However, on Ubuntu, running the above code returns unexpected result Unsat, but not value -4 (or 0xfffffffc)
Any idea why this is wrong?
Thanks so much.
Z3 is actually returning unknown. The method check returns: sat, unsat or unknown.
Here is a custom tactic that shows that the formula is indeed unsat.
#!/usr/bin/python
from z3 import *
a, b, c, t = BitVecs('a b c t', 32)
g = True
g = And(g, c == (a + 4))
g = And(g, t == (c + b))
s = Goal()
s.add(ForAll([t, a, c], Implies(t == a, g)))
T = Then("simplify", "der", "distribute-forall")
# print the simplified formula. Note that it is unsat
print T(s)
# Create a solver using the tactic above and qe
s = Then("simplify", "der", "distribute-forall", "qe", "smt").solver()
s.add(ForAll([t, a, c], Implies(t == a, g)))
print s.check()
Update
The formula is of the form
forall t, a, c: t == a ==> c == (a + 4) and t == (c + b).
This formula is logically equivalent to:
forall a, c: c == (a + 4) and a == (c + b).
which is logically equivalent to
(forall a, c: c == (a + 4)) and (forall a, c: a == (c + b)).
Both subformulas are logically equivalent to false.
This is why the formula is unsatisfiable.
The comment you wrote suggests that you believe you created the slightly different formula
forall t, a, c: t == a ==> c == (a + 4) ==> t == (c + b).
This formula is sat. To create this formula we have to replace
g = True
g = And(g, c == (a + 4))
g = And(g, t == (c + b))
with
g = Implies(c == (a + 4), t == (c + b))
The updated example is available here.

Resources