I want to find a maximal interval in which an expression e is true for all x. A way to write such a formula should be: Exists d : ForAll x in (-d,d) . e and ForAll x not in (-d,d) . !e.
To get such a d, the formula f in Z3 (looking at the one above) could be the following:
from __future__ import division
from z3 import *
x = Real('x')
delta = Real('d')
s = Solver()
e = And(1/10000*x**2 > 0, 1/5000*x**3 + -1/5000*x**2 < 0)
f = ForAll(x,
And(Implies(And(delta > 0,
-delta < x, x < delta,
x != 0),
e),
Implies(And(delta > 0,
Or(x > delta, x < -delta),
x != 0),
Not(e))
)
)
s.add(Not(f))
s.check()
print s.model()
Which outputs [d = 1/4].
To check it, I set delta = RealVal('1/4'), drop the ForAll quantifier from f and I get x = 1/2. I replace delta with 1/2 and get 3/4, then 7/8 and so on. The bound should be 1. Can I get Z3 to output that immediately?
If you do the math yourself, you can see that the solution is x != 0, x < 1. Or you can simply ask Wolfram Alpha to do it for you. So, there's no such delta.
The issue you're having is that you're asserting:
s.add(Not(f))
This turns the universal quantification on x into an existential; asking z3 to find a delta such that there is some x that fits the bill. (That is, you're negating your whole formula.) Instead, you should do:
s.add(delta > 0, f)
which also makes sure that delta is positive. With that change, z3 will correctly respond:
unsat
(And then you'll get an error for the call to s.model(), you should only call s.model() if the previous call to s.check() returns sat.)
Related
Note the following Z3-Py code:
x, y = Ints('x y')
negS0= (x >= 2)
s1 = (y > 1)
s2 = (y <= x)
s = Solver()
phi = Exists([y],ForAll([x], Implies(negS0, And(s1,s2))))
s.add(phi)
print(s.check())
print(s.model())
This prints:
sat
[]
My question is: why is the model empty? I mean, I think y=2 should be a model...
Note that the same result happens with x and y being Real.
z3 will not include any quantified variable (in your case neither y nor x) in its model. Note that you cannot put x in a model anyhow, because the formula is true for all x: That's the meaning of universal quantification. For the outer-most existentials (like your y), z3 can indeed print the model value for that, but it chooses not to do so since it can be confusing: Imagine you had a phi2, which also had an outer-most existential named y: How would you know which y it would be that it prints in the model?
So, z3 keeps things simple and simply prints the top-level declared variables in the model. And since a top-level declaration is equivalent to an outermost existential, you can simply drop it:
from z3 import *
x, y = Ints('x y')
negS0= (x >= 2)
s1 = (y > 1)
s2 = (y <= x)
s = Solver()
phi = ForAll([x], Implies(negS0, And(s1,s2)))
s.add(phi)
print(s.check())
print(s.model())
This prints:
sat
[y = 2]
like you predicted. Note that this y is unambiguous, since it's declared at the top-level. (Of course, you can redefine it to be something else due to the loosely typed nature of Python bindings and still get yourself confused, but that's a different 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.
Suppose I have the following CHC system (I(x) is an unkown predicate):
(x = 0) -> I(x)
(x < 5) /\ I(x) /\ (x' = x + 1) -> I(x')
I(x) /\ (x >= 5) -> x = 5
Now suppose I guess a solution for I(x) as x < 2 (actually an incorrect guess). Can I write code for Z3Py to (i) check if it is a valid solution and (ii) if it's incorrect find a counterexample, i.e. a value which satisfies x < 2 but does not satisfy atleast one of the above 3 equations? (For eg: x = 1, is a counterexample as it does not satisfy the 2nd equation?)
Sure. The way to do this sort of reasoning is to assert the negation of the conjunction of all your constraints, and ask z3 if it can satisfy it. If the negation comes back satisfiable, then you have a counter-example. If it is unsat, then you know that your invariant is good.
Here's one way to code this idea, in a generic way, parameterized by the constraint generator and the guessed invariant:
from z3 import *
def Check(mkConstraints, I):
s = Solver()
# Add the negation of the conjunction of constraints
s.add(Not(mkConstraints(I)))
r = s.check()
if r == sat:
print("Not a valid invariant. Counter-example:")
print(s.model())
elif r == unsat:
print("Invariant is valid")
else:
print("Solver said: %s" % r)
Given this, we can code up your particular case in a function:
def System(I):
x, xp = Ints('x xp')
# (x = 0) -> I(x)
c1 = Implies(x == 0, I(x))
# (x < 5) /\ I(x) /\ (x' = x + 1) -> I(x')
c2 = Implies(And(x < 5, I(x), xp == x+1), I(xp))
# I(x) /\ (x >= 5) -> x = 5
c3 = Implies(And(I(x), x >= 5), x == 5)
return And(c1, c2, c3)
Now we can query it:
Check(System, lambda x: x < 2)
The above prints:
Not a valid invariant. Counter-example:
[xp = 2, x = 1]
showing that x=1 violates the constraints. (You can code so that it tells you exactly which constraint is violated as well, but I digress.)
What happens if you provide a valid solution? Let's see:
Check(System, lambda x: x <= 5)
and this prints:
Invariant is valid
Note that we didn't need any quantifiers, as top-level variables act as existentials in z3 and all we needed to do was to find if there's an assignment that violated the constraints.
I want to find a maximal interval in which an expression e is true for all x. A way to write such a formula should be: Exists d : ForAll x in (-d,d) . e and ForAll x not in (-d,d) . !e.
To get such a d, the formula f in Z3 (looking at the one above) could be the following:
from z3 import *
x = Real('x')
delta = Real('d')
s = Solver()
e = And(1/10000*x**2 > 0, 1/5000*x**3 + -1/5000*x**2 < 0)
f = ForAll(x,
And(Implies(And(delta > 0,
-delta < x, x < delta,
x != 0),
e),
Implies(And(delta > 0,
Or(x > delta, x < -delta),
x != 0),
Not(e))
)
)
s.add(Not(f))
s.check()
print s.model()
It prints: [d = 2]. This is surely not true (take x = 1). What's wrong?
Also: by specifying delta = RealVal('1'), a counterexample is x = 0, even when x = 0 should be avoided.
Your constants are getting coerced to integers. Instead of writing:
1/5000
You should write:
1.0/5000.0
You can see the generated expression by:
print s.sexpr()
which would have alerted you to the issue.
NB. Being explicit about types is always important when writing constants. See this answer for a variation on this theme that can lead to further problems: https://stackoverflow.com/a/46860633/936310
This script
from z3 import *
solver = z3.Solver()
x = Int('x')
def f(y):
return y+y
solver.add(x >= 0, x < 10, Exists(x, f(x) == 4) )
print solver.check()
print solver.model()
gives me
sat
[x = 0]
as an answer. This is not what I want or expect. As an answer I would like to see
sat
[x = 2]
I found two other posts going in a similar direction((Z3Py) declaring function and Quantifier in Z3), but something doesn't work out.
How do you use the existantial quantifier in this case to get an adequate answer?
The existential binds a different x whose scope is limited to the body of the formula. Hence, your constraints are effectively (0 ≤ x < 10) ∧ (∃ x' . f(x') == 4). Both conjuncts are satisfied by a model in which x = 0; in particular, the second conjunct is satisfied in this model because x' could be 2.
It seems that you want to constrain x further, not only by the inequality. Try the following (not tested)
solver.add(x >= 0, x < 10, f(x) == 4)
and then print the model.