How to force z3py to show multiple answers if that the case? - z3py

from z3 import *
p = Int('p')
q = Int('q')
solve(Or(p==1,p==2,p==3), Or(q==1,q==2), Not(p==q), q==1)
Gives me [p = 2, q = 1], but p could be 2 or 3. So the answer should be {2,3}. How can I tell z3 to inform me about multiple answers?

This question comes up often, and there are a few caveats. Essentially, you have to write a loop to "reject" earlier models and keep querying for satisfiability. For your particular problem, you can code it like this:
from z3 import *
p = Int('p')
q = Int('q')
s = Solver()
s.add(Or(p==1,p==2,p==3), Or(q==1,q==2), Not(p==q), q==1)
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()
When I run this, I get:
[p = 2, q = 1]
[p = 3, q = 1]
Note that z3 doesn't always produce a "full" model: It'll stop producing assignments once it determines the problem is sat. So, you might have to track your variables and use model-completion explicitly. See Trying to find all solutions to a boolean formula using Z3 in python for details on how to do that.

Related

Loop over fsolve Scilab

Just as a silly example, say that I wish to solve for the following nonlinear equation x^2 - F(c)=0, where c can take different values between zero and one and F is a standard normal CDF. If I wish to solve for one particular value of c, I would use the following code:
c = linspace(0,1,100);
L = length(c);
x0 = c;
function Y = eq(x)
Y = x^2 - cdfnor("PQ",x-c(1),0,1)
endfunction
xres = fsolve(x0(1),eq);
My question is: Is there a way to solve for the equation for each value of c (and not only c(1))? Specifically, if I can use a loop over fsolve? If so, how?
Just modify your script like this:
c = linspace(0,1,100);
L = length(c);
x0 = c;
function Y = eq(x)
Y = x^2 - cdfnor("PQ",x-c,zeros(c),ones(c))
endfunction
xres = fsolve(x0,eq);

How to assert all variables equal in z3py?

To assert all elements of a list equal, is there no "Equal()" in z3py? There is for example Distinct().
Using numpy works:
from z3 import *
import numpy as np
s = Solver()
B = [BitVec(f"b{j}", 7) for j in range(11)]
C_eq = [B[i] == B[j] for i in range(3) for j in range(3) if i != j]
s.add(C_eq)
print(s.check())
print(s.model())
Indeed z3py supports Distinct, but not Equals. The reason is that a straightforward encoding of Distinct requires quadratic number of constraints, and it can bog the solver down. Having a Distinct primitive allows the solver to avoid this bottleneck. Equals, however, only requires a linear number of constraints in the number of variables and typically doesn't need any special help to be efficient.
To simplify your programming, you can define it yourself, however. Something like this:
from z3 import *
def Equals(*xs):
constr = True
if xs:
base = xs[0]
for x in xs[1:]:
constr = And(constr, base == x)
return constr
And then use it like this:
x, y, z = Ints('x y z')
print(Equals())
print(Equals(x))
print(Equals(x, y))
print(Equals(x, y, z))
which prints:
True
True
And(True, x == y)
And(And(True, x == y), x == z)

Iterating through and operating on Sympy Matrices

My modified block of code from here works for XOR'ing python lists via using functions (XOR and AND) of the Sympy library (first block of code below). However, I am stumped on how to iterate via sympy matrices (second block of code below).
The python lists code that works is:
from sympy import And, Xor
from sympy.logic import SOPform, simplify_logic
from sympy import symbols
def LogMatrixMult (A, B):
rows_A = len(A)
cols_A = len(A[0])
rows_B = len(B)
cols_B = len(B[0])
if cols_A != rows_B:
print ("Cannot multiply the two matrices. Incorrect dimensions.")
return
# Create the result matrix
# Dimensions would be rows_A x cols_B
C = [[0 for row in range(cols_B)] for col in range(rows_A)]
for i in range(rows_A):
for j in range(cols_B):
for k in range(cols_A):
# I can add Sympy's in simplify_logic(-)
C[i][j] = Xor(C[i][j], And(A[i][k], B[k][j]))
return C
b, c, d, e, f, w, x, y, z = symbols('b c d e f w x y z')
m1 = [[b,c,d,e]]
m2 = [[w,x],[x,z],[y,z],[z,w]]
result = simplify_logic(LogMatrixMult(m1, m2)[0][0])
print(result)
In the block below using Sympy matrices note that the i,j,k and C, A, B definitions is from me trying to modify to use the iterator, I don't know if this needed or correct.
from sympy import And, Xor
from sympy.matrices import Matrix
from sympy.logic import SOPform, simplify_logic
from sympy import symbols, IndexedBase, Idx
from sympy import symbols
def LogMatrixMultArr (A, B):
rows_A = A.rows
cols_A = A.cols
rows_B = B.rows
cols_B = B.cols
i,j,k = symbols('i j k', cls=Idx)
C = IndexedBase('C')
A = IndexedBase('A')
B = IndexedBase('B')
if cols_A != rows_B:
print ("Cannot multiply the two matrices. Incorrect dimensions.")
return
# Create the result matrix
# Dimensions would be rows_A x cols_B
C = [[0 for row in range(cols_B)] for col in range(rows_A)]
for i in range(rows_A):
for j in range(cols_B):
for k in range(cols_A):
# I can add Sympy's in simplify_logic(-)
C[i,j] = Xor(C[i,j], And(A[i,k], B[k,j]))
# C[i][j] = Xor(C[i][j],And(A[i][k],B[k][j]))
return C
b, c, d, e, f, w, x, y, z = symbols('b c d e f w x y z')
P = Matrix([w,x]).reshape(1,2)
Q = Matrix([y,z])
print(LogMatrixMultArr(P,Q))
The error I get is: TypeError: list indices must be integers or slices, not tuple
C[i,j] = Xor(C[i,j], And(A[i,k], B[k,j]))
Now I believe I have to do something with some special way of sympy's iterating but am stuck on how to get it to work in the code - if I do even need this methodology.
Also, if anyone knows how to do something such as the above using XOR and And (non-bitwise) instead of + and * operators in a faster way, please do share.
Thanks.
I think the problem is with IndexedBase objects. I'm not competent on these but it seems you do not use them right. If you replace
i,j,k = symbols('i j k', cls=Idx)
C = IndexedBase('C')
A = IndexedBase('A')
B = IndexedBase('B')
by
C = zeros(rows_A, cols_B)
and remove C = [[0 for row in range(cols_B)] for col in range(rows_A)], then it works.

Are Z3 caches additive?

I'm aware that Z3 has stack-based caching, where additional formulas can be added and cached. Is there a built-in way or extension that allows two Z3 caches to be combined?
Example (Z3 py)
from z3 import Solver
solver = Solver()
solver.push()
solver2 = Solver()
# solver.combine(solver2) ?
Not quite cleear what you mean by "combine." But, you can get the assertions from one and add it to the other:
from z3 import *
i = Int('x')
s1 = Solver()
s1.add(i == 3)
s1.push()
s2 = Solver()
s2.add(s1.assertions())
print s2.check()
print s2.model()
This prints:
sat
[x = 3]
You can use this trick to do your own combinations I suppose.

Maple solve system of equation showing "RootOf"

I'm trying to solve the following system:
gx:=2*x*exp(x^2+y^2)-4*y
gy:=2*y*exp(x^2+y^2)-4*x
sys:={gx=0,gy=0}:
solve(sys,{x,y})
It then displays the following output:
{x = 0, y = 0}, {x = RootOf(2*_Z^2-ln(2)), y = RootOf(2*_Z^2-ln(2))}, {x = -RootOf(2*_Z^2-ln(2)-I*Pi), y = RootOf(2*_Z^2-ln(2)-I*Pi)}
The first "root" (0,0) is correct, however how do i remove that root of and whatever Z that is? Is it possible to get the correct answer out of it?
This is a great scenario for the function allvalues.
From the help page:
compute all possible values of expressions involving RootOfs
gx:=2*x*exp(x^2+y^2)-4*y;
gy:=2*y*exp(x^2+y^2)-4*x;
sys:={gx=0,gy=0}:
sol := solve(sys,{x,y}):
seq(allvalues(sol[i]), i= 1..numelems([sol])):
print~([%])[];
Notice, however, that you are not getting all solutions this way. There are infinitely many solutions to the problem; to get all solutions, use the optional argument allsolutions = true in the solve command:
sol2 := solve(sys,{x,y},allsolutions = true):
seq(allvalues(sol2[i]), i= 1..numelems([sol2])):
print~([%])[];
If you run this, you will see a new variable _Z1 that has a trailing tilde (~) - this tilde means there are assumptions on the variable. To see these assumptions use
about(_Z1);
Originally _Z1, renamed _Z1~:
is assumed to be: integer
This means that the above solutions work for any integer _Z1. Those are all your solutions and written in the expected way.
You can use fsolve to final numerical solutions,
restart;
gx:=2*x*exp(x^2+y^2)-4*y;
gy:=2*y*exp(x^2+y^2)-4*x;
sys:={gx=0,gy=0}:
fsolve(sys,{x,y})
{x = .5887050113, y = .5887050113}
sys:={gx=0.,gy=0.}:
solve(sys,{x,y})
{x = 0., y = 0.}, {x = .5887050112, y = .5887050112}, {x = -.5887050112, y = -.5887050112}, {x = -.9887236333-.7943556085*I, y = .9887236333+.7943556085*I}, {x = .9887236333+.7943556085*I, y = -.9887236333-.7943556085*I}

Resources