Get atoms of a Boolean formula in Z3 - 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))

Related

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

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.

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]

Erlang Mnesia Select result not same as read, foldl

I have a situation with 3 use cases for returning data from an mnesia table
1. return all values of a table so I use a foldl,
2. return 1 row so I use read
3. return a variable number of records based on criteria so I use select.
I would like to use the same code to manage the results, but the select returns a different data structure. I am hoping someone can help me restructure my select to return the same as the others.
below is sample code of the issue and the results. The issue is the select does not return the record name for the table as does read and foldl.
-module(testselect2).
-export([runtest/0]).
-record(record_a, {b, c, d}).
-record(record_b, {record_a, e}).
-record(record_c, {record_b, f, intval}).
runtest() ->
mnesia:create_schema([node()]),
mnesia:start(),
mnesia:create_table(record_c, [{attributes, record_info(fields, record_c)}]),
A1 = #record_a{b = "R1", c = "T1", d = "C1"},
B1 = #record_b{record_a = A1, e = "E1"},
C1 = #record_c{record_b = B1, f = "F1", intval = 100},
A2 = #record_a{b = "R2", c = "T2", d = "C2"},
B2 = #record_b{record_a = A2, e = "E2"},
C2 = #record_c{record_b = B2, f = "F2", intval = 200},
A3 = #record_a{b = "R3", c = "T3", d = "C3"},
B3 = #record_b{record_a = A3, e = "E3"},
C3 = #record_c{record_b = B3, f = "F3", intval = 300},
{atomic, Rw} = mnesia:transaction(
fun () ->
mnesia:write(C1),
mnesia:write(C2),
mnesia:write(C3)
end),
io:fwrite("Result write = ~w~n", [Rw]),
{atomic, Rr} = mnesia:transaction(
fun () ->
mnesia:read({record_c, B1})
end),
io:fwrite("Result read = ~w~n", [Rr]),
{atomic, Rf} =
mnesia:transaction(fun () ->
mnesia:foldl(fun (Rec, Acc) -> [Rec | Acc] end,
[],
record_c)
end),
io:fwrite("Result foldl = ~w~n", [Rf]),
MatchHead = #record_c{record_b='$1', f='$2', intval='$3'},
Guard = {'>', '$3', 100},
Result = {{'$1', '$2', '$3'}},
{atomic, Rs} = mnesia:transaction(
fun () ->
mnesia:select(record_c, [{MatchHead, [Guard], [Result]}])
end),
io:fwrite("Result select = ~w~n", [Rs]).
=====
RESULTS
44> testselect2:runtest().
Result write = ok
Result read = [{record_c,{record_b,{record_a,[82,49],[84,49],[67,49]},[69,49]},[70,49],100}]
Result foldl = [{record_c,{record_b,{record_a,[82,49],[84,49],[67,49]},[69,49]},[70,49],100},{record_c,{record_b,{record_a,[82,51],[84,51],[67,51]},[69,51]},[70,51],300},{record_c,{record_b,{record_a,[82,50],[84,50],[67,50]},[69,50]},[70,50],200}]
Result select = [{{record_b,{record_a,[82,51],[84,51],[67,51]},[69,51]},[70,51],300},{{record_b,{record_a,[82,50],[84,50],[67,50]},[69,50]},[70,50],200}]
ok
As you can see above read and foldl records start with {record_c,{... where select is missing the record_c and just has {{...
I have been unable to find a way to get select to return the same structure so my processing code can work for all 3 use cases. Any suggestions would be greatly appreciated.
I'm no mnesia expert, but I know when you use an ETS match expression, you determine what the result looks like. You use Result = {{'$1', '$2', '$3'}} to create your result terms, which makes them come out as three-tuples in a one-tuple, as we see in your output. Per ets:select/1, you want to use the special variable '$_' to return the whole matched object, so this should work in place of your Result = ... line:
Result = '$_',

Correctness of a grammar for propositional logic

I am trying to write a grammar for propositional logic for the purpose of creating a LL parser (lexical analysis).
I tried the following grammar:
F = F and F
F = F or F
F = F => F
F = F <=> F
F = not F
F = (F)
D = a
but I discovered that it is ambiguous. I tried the following to remove the ambiguity:
F = F and A
F = A
A = F or B
A = B
B = F => C
B = C
C = F <=> C
C=D
D = not F
D = (F)
D = a
Is this grammar correct? Was I successful in removing the ambiguity?
The grammar is still ambiguous. Here are two derivations for
not a and a:
Derivation 1:
F
F and A
A and A
B and B
C and C
not F and a
not A and a
not B and a
not C and a
not D and a
not a and a
Derivation 2:
F
A
B
C
D
not F
not F and A
not A and A
not B and B
not C and C
not D and D
not a and a
You need to put parentheses around your derivations, e.g.
F = (F and A)
Another possibility if you don't want to use parentheses is to use prefix notation.

Hindley Milner Type Inference in F#

Can somebody explain step by step type inference in following F# program:
let rec sumList lst =
match lst with
| [] -> 0
| hd :: tl -> hd + sumList tl
I specifically want to see step by step how process of unification in Hindley Milner works.
Fun stuff!
First we invent a generic type for sumList:
x -> y
And get the simple equations:
t(lst) = x;
t(match ...) = y
Now you add the equation:
t(lst) = [a] because of (match lst with [] ...)
Then the equation:
b = t(0) = Int; y = b
Since 0 is a possible result of the match:
c = t(match lst with ...) = b
From the second pattern:
t(lst) = [d];
t(hd) = e;
t(tl) = f;
f = [e];
t(lst) = t(tl);
t(lst) = [t(hd)]
Guess a type (a generic type) for hd:
g = t(hd); e = g
Then we need a type for sumList, so we'll just get a meaningless function type for now:
h -> i = t(sumList)
So now we know:
h = f;
t(sumList tl) = i
Then from the addition we get:
Addable g;
Addable i;
g = i;
t(hd + sumList tl) = g
Now we can start unification:
t(lst) = t(tl) => [a] = f = [e] => a = e
t(lst) = x = [a] = f = [e]; h = t(tl) = x
t(hd) = g = i /\ i = y => y = t(hd)
x = t(lst) = [t(hd)] /\ t(hd) = y => x = [y]
y = b = Int /\ x = [y] => x = [Int] => t(sumList) = [Int] -> Int
I skipped some trivial steps, but I think you can get how it works.

Resources