How to use soft constraints in Z3-Python to express 'abstract' biases in SAT search: such as 'I prefer half of the literals to be true and half false' - z3

I previously asked in How to bias Z3's (Python) SAT solving towards a criteria, such as 'preferring' to have more negated literals, whether there was a way in Z3 (Python) to 'bias' the SAT search towards a 'criteria'?
In that post, we learnt 'simple biases' such as I would like Z3 to obtain a model, but not any model: if possible, give me a model that has a great amount of negated literals.
This was performed using a new solver (Optimize instead of Solver) and soft constraints (add_soft instead of add). Concretely, for each literal lit_n and an optimized solver o_solver, this was added: o_solver.add_soft(Not(lit_n)); or, equivalently: o_solver.add_soft(Or(Not(lit1), Not(lit2), ...).
However, I would like to express a 'little more complicated biases'. Concretely: if possible: I prefer models with the half of literals to True and the half to False.
Is there any way I can express this and similar 'biases' using the Optimize tool?

Here’s a simple idea that might help. Count the number of positive literals and subtract from the count of negative ones. Take the absolute value of the difference and minimize it using the optimizer.
That should find the solution with as close a count of positive and negative literals, satisfying your “about half” soft constraint.
Here's a simple example. Let's say you have six literals and you want to satisfy their disjunction. The idiomatic solution would be:
from z3 import *
a, b, c, d, e, f = Bools("a b c d e f")
s = Solver()
s.add(Or(a, b, c, d, e, f))
print(s.check())
print(s.model())
If you run this, you'll get:
sat
[f = False,
b = False,
a = True,
c = False,
d = False,
e = False]
So, z3 simply made a True and all others False. But you wanted to have roughly the same count of positive and negative literals. So, let's encode that:
from z3 import *
a, b, c, d, e, f = Bools("a b c d e f")
s = Optimize()
s.add(Or(a, b, c, d, e, f))
def count(ref, xs):
s = 0
for x in xs:
s += If(x == ref, 1, 0)
return s
def sabs(x):
return If(x > 0, x, -x)
lits = [a, b, c, d, e, f]
posCount = count(True, lits)
negCount = count(False, lits)
s.minimize(sabs(posCount - negCount))
print(s.check())
print(s.model())
Note how we "symbolically" count the negative and positive literals and ask z3 to minimize the absolute value of the difference. If you run this, you'll get:
sat
[a = True,
b = False,
c = False,
d = True,
e = False,
f = True]
With 3 positive and 3 negative literals. If you had 7 literals to start with, it'd have found a 4-3 split. If you prefer more positive literals than negatives, you can additionally add a soft constraint of the form:
s.add_soft(posCount >= negCount)
to bias the solver that way. Hope this gets you started..

Related

How to check in Z3py whether the expression contains a specific variable or expression?

I'm using z3py, how do I check whether an expression contains a given variable or expression? For example,
x = Int('x')
expr = x + 1
So, expr should contains variable x.
I've checked the z3.py source code, but I didn't find a solution. Any idea? Thanks.
You can write a simple recursive descent walk over the expression:
from z3 import *
def contains(x, e):
return x.__repr__() == e.__repr__() or any([contains(x, c) for c in e.children()])
x, y, z = Ints('x y z')
expr = x + 2 * y
print(contains(x, expr))
print(contains(y, expr))
print(contains(z, expr))
print(contains(x+2, expr))
print(contains(2*y, expr))
print(contains(y*2, expr))
print(contains(1, IntVal(2)))
print(contains(1, IntVal(1)))
print(contains(x, x))
print(contains(x, y))
This prints:
True
True
False
False
True
False
False
True
True
False
However, I should caution that in typical z3 programming you already know what your variables are. (After all, you have to declare them explicitly!) So, unless you're writing some high-level library code, you should simply keep track of what variables you have and just check in this list. Recursive-descents like this can be expensive for large expressions.

add iteratively in z3

I want to check the value of a, b, c, and if value 'a' equals to 1, 'x' is added one. We continue the process for values 'b' and 'c'.
So if a=1, b=1, c=1, the result of x should be 3.
if a=1, b=1, c=0, so the result of x should be 2.
Any methods to be implemented in z3?
The source code looks like this:
from z3 import *
a, b, c = Ints('a b c')
x, y = Ints('x y')
s = Solver()
s.add(If(a==1, x=x + 1, y = y-1))
s.add(If(b==1, x=x + 1, y = y-1))
s.add(If(c==1, x=x + 1, y = y-1))
s.check()
print s.model()
Any suggestions about what I can do?
This sort of "iterative" processing is usually modeled by unrolling the assignments and creating what's known as SSA form. (Static single assignment.) In this format, every variable is assigned precisely once, but can be used many times. This is usually done by some underlying tool as it is rather tedious, but you can do it by hand as well. Applied to your problem, it'd look something like:
from z3 import *
s = Solver()
a, b, c = Ints('a b c')
x0, x1, x2, x3 = Ints('x0 x1 x2 x3')
s.add(x0 == 0)
s.add(x1 == If(a == 1, x0+1, x0))
s.add(x2 == If(b == 1, x1+1, x1))
s.add(x3 == If(c == 1, x2+1, x2))
# Following asserts are not part of your problem, but
# they make the output interesting
s.add(b == 1)
s.add(c == 0)
# Find the model
if s.check() == sat:
m = s.model()
print("a=%d, b=%d, c=%d, x=%d" % (m[a].as_long(), m[b].as_long(), m[c].as_long(), m[x3].as_long()))
else:
print "no solution"
SSA transformation is applied to the variable x, creating as many instances as necessary to model the assignments. When run, this program produces:
a=0, b=1, c=0, x=1
Hope that helps!
Note that z3 has many functions. One you could use here is Sum() for the sum of a list. Inside the list you can put simple variables, but also expression. Here an example for both a simple and a more complex sum:
from z3 import *
a, b, c = Ints('a b c')
x, y = Ints('x y')
s = Solver()
s.add(a==1, b==0, c==1)
s.add(x==Sum([a,b,c]))
s.add(y==Sum([If(a==1,-1,0),If(b==1,-1,0),If(c==1,-1,0)]))
if s.check() == sat:
print ("solution:", s.model())
else:
print ("no solution possible")
Result:
solution: [y = 2, x = 2, c = 1, b = 0, a = 1]
If your problem is more complex, using BitVecs instead of Ints can make it run a little faster.
edit: Instead of Sum() you could also simply use addition as in
s.add(x==a+b+c)
s.add(y==If(a==1,-1,0)+If(b==1,-1,0)+If(c==1,-1,0))
Sum() makes sense towards readability when you have a longer list of variables, or when the variables already are in a list.

Using closure results for Turing-decidable languages

I have a language L1 = {w in {0,1}*| w contains the same number of 1's and 0's} and i have a TM M that decides L1.
I want to prove that L2 = {w in {0,1}*| w contains more 1's than 0's} is Turing-decidable.
I have used the "closed under complement" approach and proven that M' decides the complement of L1 (~L1).
My question is, can I assume that the ~L1 = (L2 or ~L2) and conclude that since M' decides ~L1 that L2 and ~L2 are both decidable languages?
Thank you for any advice
(Sorry, haven't figured out how to use LaTex here yet...)
I just want to flesh out Wellbog's answer. Here is L1 (Read n1(w) as "number of 1's in w"):
L1 = {w∈
{0,1}*: n1(w) = n0(w)}
And here is L2:
L2 = {w∈
{0,1}*: n1(w) > n0(w)}
From the other side, L1-bar is:
L1-bar = {w∈
{0,1}*: n1(w) > n0(w) OR n1(w) < n0(w)}
And clearly, L1-bar and L2 are different.

Why is this (very simple) vectorized code orders of magnitude slower than Numpy?

I know very well Julia's philosophy concerning vectorization and the like, and I can accept having my code run even ten times slower than Numpy, but why does this code run much, much slower than Numpy? Maybe there is a mistake in the code; I can't imagine the issue is related to using vectorization rather than loops.
I am using vectorization because my requirements are not strong; furthermore memory allocation doesn't seem to be that incredible (and it proves to be very fast with Numpy). The code is also easy to read.
The following piece of code is written in Python; it computes a generalized continued fraction over a part of the complex plane. The continued fraction is defined by two different functions; I use this code for plotting pictures on this blog: https://kettenreihen.wordpress.com/
The Python code is below; it computes 640x640 values in about 2 seconds:
def K(a, b, C):
s = C.shape
P1 = np.ones(s, dtype=np.complex)
P2 = np.zeros(s, dtype=np.complex)
Q1 = np.zeros(s, dtype=np.complex)
Q2 = np.ones(s, dtype=np.complex)
for n in range(1, 65):
A, B = a(C, n), b(C, n)
P = A*P2 + B*P1
Q = A*Q2 + B*Q1
P1, P2 = P2, P
Q1, Q2 = Q2, Q
return P2/Q2
The following Julia code should do the same, but it takes 2 or 3 minutes for computing the same thing.
function K(a, b, C)
s = size(C)
P1 = ones(Complex, s)
P2 = zeros(Complex, s)
Q1 = zeros(Complex, s)
Q2 = ones(Complex, s)
for n = 1:64
println(n)
A, B = a(C, n), b(C, n)
P = A.*P2 + B.*P1
Q = A.*Q2 + B.*Q1
P1, P2 = P2, P
Q1, Q2 = Q2, Q
end
return P2./Q2
end
You are allocating matrices with an abstract element type: the Complex type is an abstract supertype for all specific Complex{T} types. What you want here is arrays of some concrete element type like Complex128 == Complex{Float64} or Complex64 == Complex{Float32}. Presumably in NumPy dtype=np.complex refers to a specific complex type, probably the equivalent of Complex128.
If you want to write code that is generic and will work for different kinds of C matrices, then assuming C is a complex matrix and what you want is to create matrices of ones and zeros of the same element type and shape, you can just call the ones and zeros functions on C to get matrices with the right element type and shape:
function K(a, b, C)
P1 = ones(C)
P2 = zeros(C)
Q1 = zeros(C)
Q2 = ones(C)
for n = 1:64
println(n)
A, B = a(C, n), b(C, n)
P = A.*P2 + B.*P1
Q = A.*Q2 + B.*Q1
P1, P2 = P2, P
Q1, Q2 = Q2, Q
end
return P2./Q2
end
Hopefully that helps the performance. You might be able to get even more performance by pre-allocating three matrices and doing operations in place, rotating through the matrices. However, the convenient syntax support for that hasn't made it into a stable release yet, so on Julia 0.5 it would still be a little verbose, but could get you a performance boost over the vectorized version.

SLR(1) parser with epsilon transitions in the grammar

I'm writing an SLR(1) parser from the following grammar:
1) S -> aSb
2) S -> cB
3) B -> cB
4) B -> ε
First of all, I started with finding the associated LR(0) automaton with the augmented grammar adding the S' -> S production and starting to compute the various states. The states that I found are:
I0 = {S'->•S, S->•aSb, S->•cB}
𝛿(I0, S) = I1; 𝛿(I0, a) = I2; 𝛿(I0, c) = I3;
I1 = {S'->S•}
I2 = {S->a•Sb, S->•aSb, S->•cB}
𝛿(I2, S) = I4; 𝛿(I2, a) = I2; 𝛿(I2, c) = I3
I3 = {S->c•B, B->•cB, B->•ε}
𝛿(I3, B) = I5; 𝛿(I3, ε) = I6; 𝛿(I3, c) = I7;
I4 = {S->aS•b}
𝛿(I4, b) = I8;
I5 = {S->cB•}
I6 = {B->ε•}
I7 = {B->c•B, B->•cB, B->•ε}
𝛿(I7, B) = I9; 𝛿(I7, ε) = I6; 𝛿(I7, c) = I7;
I8 = {S->aSb•}
I9 = {B->cB•}
And here there is the LR(0) automaton:
Automaton Picture
After that, I did the parser table (but I don't think it is needed in order to answer my question) so I have a doubt:
is the epsilon transition handled in the right way? I mean, I treated it as a normal character since we have to reduce by the rule number 4 at some point. If I'm wrong, how should I treat that transition? Thanks in advance, hoping this is helpful for other people as well.
no , there is no need to create the State I6
Confusion may have arise in Y->Ɛ . When you place a dot in the augmented productions for example S->A.B it means that A is completed and B is yet to be completed (by completion here means progress in parsing) . Similarly if you write Y->.Ɛ , it means Ɛ is yet to be over, but we also know that Ɛ is null string i.e nothing therefore Y->.Ɛ is interpreted as Y->.
you can use The JFLAP Software and see it's documentation about SLR(1)
NOT REQUIRED...
even i faced the same problem while removing left reccursion for the following grammar
E->E+T|E-T|T
the transformed rule looks like
E->T X
X->+TX|-TX|*e*
that doesnt matter as
x->.e and x->e. have no significance.Since moving the period before and after Epsilon is madman's job

Resources