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.
Related
Is there an equivalent to define-const in the Z3 Python API? I am trying to rewrite the example below (similar to this example) in Python:
(define-const a String "hello")
(define-const b String "world")
(simplify (= a b))
(check-sat)
(get-model)
whose output is
false
sat
(
(define-fun b () String
"world")
(define-fun a () String
"hello")
)
I tried replacing define-const with a constant declaration followed by an assertion, but the result was not quite the same:
from z3 import *
a = String('a')
b = String('b')
s = Solver()
s.add(a == 'hello')
s.add(b == 'world')
print(simplify(a == b))
print(s.check())
print(s.model())
output:
a == b
sat
[a = "hello", b = "world"]
I also tried using StringVal() but the result was also not the same:
from z3 import *
a = StringVal('hello')
b = StringVal('world')
s = Solver()
s.add(a == 'hello')
s.add(b == 'world')
print(simplify(a == b))
print(s.check())
print(s.model())
output:
False
sat
[]
I have tried searching documentation and elsewhere but was unsuccessful.
This is a bit of a strange thing to do, since define-const is simply a macro. If you're using the Python API, you'd simply use a StringVal. But then, those variables don't show up in the solver, because there's no connection between the Python level object, and what gets asserted in the solver. This is what you are seeing in the last example you tried.
And this is perfectly fine: In SMTLib, constants live together with all the other variables; but in z3py you get two different worlds. A better question to ask is, perhaps, what exactly are you trying to achieve? Trying to simulate SMTLib exactly by the Python interface isn't an explicit goal. In particular, the Python interface allows for easier programming and access to z3 internals that are not available in the SMTLib world. Don't try to equate them!
Having said all this, the most "faithful" way to simulate the SMTLib you have in z3py would be:
from z3 import *
a = StringVal("hello")
b = StringVal("world")
print(simplify(a == b))
s = Solver()
print(s.check())
m = s.model()
print("a =", m.evaluate(a))
print("b =", m.evaluate(b))
This prints:
False
sat
a = "hello"
b = "world"
This matches the output you're expecting, but then again it's not really the best use of the API. Instead of trying to simulate SMTLib exactly, "what problem are you trying to solve" is a better goal to focus on.
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)
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.
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.
I have a vector X of 20 real numbers and a vector Y of 20 real numbers.
I want to model them as
y = ax^2+bx + c
How to find the value of 'a' , 'b' and 'c'
and best fit quadratic equation.
Given Values
X = (x1,x2,...,x20)
Y = (y1,y2,...,y20)
i need a formula or procedure to find following values
a = ???
b = ???
c = ???
Thanks in advance.
Everything #Bartoss said is right, +1. I figured I just add a practical implementation here, without QR decomposition. You want to evaluate the values of a,b,c such that the distance between measured and fitted data is minimal. You can pick as measure
sum(ax^2+bx + c -y)^2)
where the sum is over the elements of vectors x,y.
Then, a minimum implies that the derivative of the quantity with respect to each of a,b,c is zero:
d (sum(ax^2+bx + c -y)^2) /da =0
d (sum(ax^2+bx + c -y)^2) /db =0
d (sum(ax^2+bx + c -y)^2) /dc =0
these equations are
2(sum(ax^2+bx + c -y)*x^2)=0
2(sum(ax^2+bx + c -y)*x) =0
2(sum(ax^2+bx + c -y)) =0
Dividing by 2, the above can be rewritten as
a*sum(x^4) +b*sum(x^3) + c*sum(x^2) =sum(y*x^2)
a*sum(x^3) +b*sum(x^2) + c*sum(x) =sum(y*x)
a*sum(x^2) +b*sum(x) + c*N =sum(y)
where N=20 in your case. A simple code in python showing how to do so follows.
from numpy import random, array
from scipy.linalg import solve
import matplotlib.pylab as plt
a, b, c = 6., 3., 4.
N = 20
x = random.rand((N))
y = a * x ** 2 + b * x + c
y += random.rand((20)) #add a bit of noise to make things more realistic
x4 = (x ** 4).sum()
x3 = (x ** 3).sum()
x2 = (x ** 2).sum()
M = array([[x4, x3, x2], [x3, x2, x.sum()], [x2, x.sum(), N]])
K = array([(y * x ** 2).sum(), (y * x).sum(), y.sum()])
A, B, C = solve(M, K)
print 'exact values ', a, b, c
print 'calculated values', A, B, C
fig, ax = plt.subplots()
ax.plot(x, y, 'b.', label='data')
ax.plot(x, A * x ** 2 + B * x + C, 'r.', label='estimate')
ax.legend()
plt.show()
A much faster way to implement solution is to use a nonlinear least squares algorithm. This will be faster to write, but not faster to run. Using the one provided by scipy,
from scipy.optimize import leastsq
def f(arg):
a,b,c=arg
return a*x**2+b*x+c-y
(A,B,C),_=leastsq(f,[1,1,1])#you must provide a first guess to start with in this case.
That is a linear least squares problem. I think the easiest method which gives accurate results is QR decomposition using Householder reflections. It is not something to be explained in a stackoverflow answer, but I hope you will find all that is needed with this links.
If you never heard about these before and don't know how it connects with you problem:
A = [[x1^2, x1, 1]; [x2^2, x2, 1]; ...]
Y = [y1; y2; ...]
Now you want to find v = [a; b; c] such that A*v is as close as possible to Y, which is exactly what least squares problem is all about.