In the following working example , How to retrieve the matched model?
S, (cl_3,cl_39,cl_11, me_32,m_59,m_81) =
EnumSort('S', ['cl_3','cl_39','cl_11','me_32','me_59','me_81'])
h1, h2 = Consts('h1 h2', S)
def fun(h1 , h2):
conds = [
(cl_3, me_32),
(cl_39, me_59),
(cl_11, me_81),
# ...
]
and_conds = (And(h1==a, h2==b) for a,b in conds)
return Or(*and_conds)
For Example:
as the following solver
s = Solver()
x1 = Const('x1', S)
x2 = Const('x2', S)
s.add(fun(x1,x2))
print s.check()
print s.model()
I'm assuming that you want the value of x1 and x2 in the model produced by Z3. If that is the case, you can retrieve them using:
m = s.model()
print m[x1]
print m[x2]
Here is the complete example (also available online here). BTW, note that we don't need h1, h2 = Consts('h1 h2', S).
S, (cl_3, cl_39, cl_11, me_32, me_59, me_81) =
EnumSort('S', ['cl_3','cl_39','cl_11','me_32','me_59','me_81'])
def fun(h1 , h2):
conds = [
(cl_3, me_32),
(cl_39, me_59),
(cl_11, me_81),
]
and_conds = (And(h1==a, h2==b) for a,b in conds)
return Or(*and_conds)
s = Solver()
x1 = Const('x1', S)
x2 = Const('x2', S)
s.add(fun(x1,x2))
print s.check()
m = s.model()
print m
print m[x1]
print m[x2]
Related
I have the following python program.
from z3 import *
x = Bool("X")
y = Bool("Y")
s = Solver()
s.add(x==y)
s.add(x!=False)
s.add(y!=True)
s.check()
The last line gives output unsat.
But how to print the unsat core of this?
You can ask for an unsat core as follows:
from z3 import *
# https://z3prover.github.io/api/html/classz3py_1_1_solver.html#ad1255f8f9ba8926bb04e1e2ab38c8c15
x = Bool('X')
y = Bool('Y')
s = Solver()
s.set(unsat_core=True)
s.assert_and_track(x == y, 'a1')
s.assert_and_track(x != False, 'a2')
s.assert_and_track(y != True, 'a3')
result = s.check()
print(result)
if result == unsat :
c = s.unsat_core()
print(len(c))
print('a1 ', Bool('a1') in c)
print('a2 ', Bool('a2') in c)
print('a3 ', Bool('a3') in c)
print(c)
Resulting output:
unsat
3
a1 True
a2 True
a3 True
[a1, a2, a3]
This is a trivial unsat core as it contains all assertions. Look at a related discussion.
I have the following formula and Python code trying to find the largest n satisfying some property P:
x, u, n, n2 = Ints('x u n n2')
def P(u):
return Implies(And(2 <= x, x <= u), And(x >= 1, x <= 10))
nIsLargest = ForAll(n2, Implies(P(n2), n2 <= n))
exp = ForAll(x, And(P(n), nIsLargest))
s = SolverFor("LIA")
s.reset()
s.add(exp)
print(s.check())
if s.check() == sat:
print(s.model())
My expectation was that it would return n=10, yet Z3 returns unsat. What am I missing?
You're using the optimization API incorrectly; and your question is a bit confusing since your predicate P has a free variable x: Obviously, the value that maximizes it will depend on both x and u.
Here's a simpler example that can get you started, showing how to use the API correctly:
from z3 import *
def P(x):
return And(x >= 1, x <= 10)
n = Int('n')
opt = Optimize()
opt.add(P(n))
maxN = opt.maximize(n)
r = opt.check()
print(r)
if r == sat:
print("maxN =", maxN.value())
This prints:
sat
maxN = 10
Hopefully you can take this example and extend it your use case.
I want to verify a formula of the form:
Exists p . ForAll x != 0 . f(x, p) > 0
An implementation (that isn't working) is the following:
def f0(x0, x1, x, y):
return x1 ** 2 * y + x0 ** 2 * x
s = Solver()
x0, x1 = Reals('x0 x1')
p0, p1 = Reals('p0 p1')
s.add(Exists([p0, p1],
ForAll([x0, x1],
f0(x0, x1, p0, p1) > 0
)
))
#s.add(Or(x0 != 0, x1 != 0))
while s.check() == sat:
m = s.model()
m.evaluate(x0, model_completion=True)
m.evaluate(x1, model_completion=True)
m.evaluate(p0, model_completion=True)
m.evaluate(p1, model_completion=True)
print m
s.add(Or(x0 != m[x0], x1 != m[x1]))
The formula isn't satisfied.
With f0() >= 0, the only output is (0, 0).
I want to have f0() > 0 and constrain (x0, x1) != (0, 0).
Something I'd expect is: p0, p1 = 1, 1 or 2, 2 for instance, but I don't know how to remove 0, 0 from the possible values for x0, x1.
Following up on Levent's reply. During the first check, Z3 uses a custom decision procedure that works with the quantifiers. In incremental mode it falls back to something that isn't a decision procedure. To force the one-shot solver try the following:
from z3 import *
def f0(x0, x1, x, y):
return x1 * x1 * y + x0 * x0 * x
p0, p1 = Reals('p0 p1')
x0, x1 = Reals('x0 x1')
fmls = [ForAll([x0, x1], Implies(Or(x0 != 0, x1 != 0), f0(x0, x1, p0, p1) > 0))]
while True:
s = Solver()
s.add(fmls)
res = s.check()
print res
if res == sat:
m = s.model()
print m
fmls += [Or(p0 != m[p0], p1 != m[p1])]
else:
print "giving up"
break
You'd simply write that as an implication inside the quantification. I think you're also mixing up some of the variables in there. The following seems to capture your intent:
from z3 import *
def f0(x0, x1, x, y):
return x1 * x1 * y + x0 * x0 * x
s = Solver()
p0, p1 = Reals('p0 p1')
x0, x1 = Reals('x0 x1')
s.add(ForAll([x0, x1], Implies(Or(x0 != 0, x1 != 0), f0(x0, x1, p0, p1) > 0)))
while True:
res = s.check()
print res
if res == sat:
m = s.model()
print m
s.add(Or(p0 != m[p0], p1 != m[p1]))
else:
print "giving up"
break
Of course, z3 isn't guaranteed to find you any solutions; though it seems to manage one:
$ python a.py
sat
[p1 = 1, p0 = 1]
unknown
giving up
Once you use quantifiers all bets are off, as the logic becomes semi-decidable. Z3 is doing a good job here and returning one solution, and then it's giving up. I don't think you can expect anything better, unless you use some custom decision procedures.
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
What is the best way to substitute a function symbol (with another function) in a formula?
Z3py's substitute seems to only work with expressions, and what I do now is I try to guess all possible combinations of consts/vars to which the function could be applied and then substitute those with an application of another function. Is there a better way to do that?
We can implement a simple bottom-up rewriter that given a term s, a function f and term t will replace every f-application f(r_1, ..., r_n) in s with t[r_1, ..., r_n]. I'm using the notation t[r_1, ..., r_n] to denote the term obtained by replacing the free-variables in t with the terms r_1, ..., r_n.
The rewriter can be implemented the Z3 API. I use an AstMap to cache results, and a todo list to store expressions that still have to be processed.
Here is a simple example that replaces f-applications of the form f(t) with g(t+1) in s.
x = Var(0, IntSort())
print rewrite(s, f, g(x + 1))
Here is the code and more examples. Beware, I only tested the code in a small set of examples.
from z3 import *
def update_term(t, args):
# Update the children of term t with args.
# len(args) must be equal to the number of children in t.
# If t is an application, then len(args) == t.num_args()
# If t is a quantifier, then len(args) == 1
n = len(args)
_args = (Ast * n)()
for i in range(n):
_args[i] = args[i].as_ast()
return z3._to_expr_ref(Z3_update_term(t.ctx_ref(), t.as_ast(), n, _args), t.ctx)
def rewrite(s, f, t):
"""
Replace f-applications f(r_1, ..., r_n) with t[r_1, ..., r_n] in s.
"""
todo = [] # to do list
todo.append(s)
cache = AstMap(ctx=s.ctx)
while todo:
n = todo[len(todo) - 1]
if is_var(n):
todo.pop()
cache[n] = n
elif is_app(n):
visited = True
new_args = []
for i in range(n.num_args()):
arg = n.arg(i)
if not arg in cache:
todo.append(arg)
visited = False
else:
new_args.append(cache[arg])
if visited:
todo.pop()
g = n.decl()
if eq(g, f):
new_n = substitute_vars(t, *new_args)
else:
new_n = update_term(n, new_args)
cache[n] = new_n
else:
assert(is_quantifier(n))
b = n.body()
if b in cache:
todo.pop()
new_n = update_term(n, [ cache[b] ])
cache[n] = new_n
else:
todo.append(b)
return cache[s]
f = Function('f', IntSort(), IntSort())
a, b = Ints('a b')
s = Or(f(a) == 0, f(a) == 1, f(a+a) == 2)
# Example 1: replace all f-applications with b
print rewrite(s, f, b)
# Example 2: replace all f-applications f(t) with g(t+1)
g = Function('g', IntSort(), IntSort())
x = Var(0, IntSort())
print rewrite(s, f, g(x + 1))
# Now, f and g are binary functions.
f = Function('f', IntSort(), IntSort(), IntSort())
g = Function('g', IntSort(), IntSort(), IntSort())
# Example 3: replace all f-applications f(t1, t2) with g(t2, t1)
s = Or(f(a, f(a, b)) == 0, f(b, a) == 1, f(f(1,0), 0) == 2)
# The first argument is variable 0, and the second is variable 1.
y = Var(1, IntSort())
print rewrite(s, f, g(y, x))
# Example 4: quantifiers
s = ForAll([a], f(a, b) >= 0)
print rewrite(s, f, g(y, x + 1))