I have been experimenting with z3 (version '4.8.7' obtained through pip3) and found this (apparent) discrepancy.
t, s0, s, u, a, v = Reals('t s0 s u a v')
equations = [v == u + a*t, s == s0 + u*t + a*t**2/2,
v**2 - u**2 == 2*a*s]
problem = [t == 10, s0 == 0, u == 0, a == 9.81]
solve(equations+problem)
This gives the correct output for s:
[a = 981/100, u = 0, s0 = 0, t = 10, s = 981/2, v = 981/10]
But when I use the Solver, the result is different:
solver = Solver()
solver.check(equations+problem)
solver.model()
This gives a wrong output for s, though it gets v right.
[t = 10, u = 0, s0 = 0, s = 0, a = 981/100, v = 981/10]
s should be (1/2) * (981/100) * 100 which is the result in solve.
Am I missing something obvious in z3's Solver or is this a bug? Thank you.
The issue here is that the argument to solver.check are extra assumptions the solver can make as it solves the constraints, not the actual constraints to check. See the documentation here: https://z3prover.github.io/api/html/z3py_8py_source.html#l06628
The correct call would be:
solver = Solver()
solver.add(equations+problem)
print solver.check()
print solver.model()
that is, you add the constraints, and then call check with no arguments. This would match what solve does. The argument to check are used if you want to check validity under some extra assumptions only.
Related
I am using z3 to do bit blasting. I then solve the problem in a SAT solver, and do reverse bit blasting in order to find out what value the varibles take. However, I find that the solutions I get after doing reverse bit balsting do not live up to the constraints. As z3 does not save which values corrospond to what in the bit blasted reslult, I have used a piece of code from How can I access the variable mapping used when bit-blasting? to do that. I suspect that the problem might be here, as I get more varibles and constraints when using a bitmap than when I don't do it.
I have the following code:
x1 = BitVec('x1', 2)
x2 = BitVec('x2', 2)
g = Goal()
bitmap = {}
for i in range(2):
bitmap[(x1,i)] = Bool('x1'+str(i))
mask = BitVecSort(2).cast(math.pow(2,i))
g.add(bitmap[(x1,i)] == ((x1 & mask) == mask))
bitmap[(x2,i)] = Bool('x2'+str(i))
mask = BitVecSort(2).cast(math.pow(2,i))
g.add(bitmap[(x2,i)] == ((x2 & mask) == mask))
g.add(x1 + x2 == 3)
t = Then('simplify', 'bit-blast', 'tseitin-cnf')
subgoal = t(g)
For which I get the following solutions (x1 = 2, x2 =2), (x1 = 0, x2 = 0), (x1 = 1, x2 = 1) and (x1 = 3, x2 = 3).
For different constraints I get different solutions(x1 and x2 and not always the same), but they don't live up to the constraints.
There's nothing wrong with this encoding, and while it's hard to decipher the tseitin output from z3, I'd assume it's correct as well.
What you haven't shown us is the output of this "other" SAT solver, and more importantly, how you translate that back to z3. I suspect the bug is in there somewhere. But without seeing that code, it's impossible to answer your question. But as a guide, I'd look at the code that translates back the SAT output to your z3py variables. What code are you using for that purpose?
Consider a set of constraints F = [a + b > 10, a*a + b + 10 < 50].
When I run it using:
s = Solver()
s.add(F)
s.check()
I get sat solution.
If I run it with:
s = Solver()
s.check(F)
I get an unknown solution. Can someone explain why this is happening?
Let's see:
from z3 import *
a = Int('a')
b = Int('b')
F = [a + b > 10, a*a + b + 10 < 50]
s = Solver()
s.add(F)
print (s.check())
print (s.model())
This prints:
sat
[b = 15, a = -4]
That looks good to me.
Let's try your second variant:
from z3 import *
a = Int('a')
b = Int('b')
F = [a + b > 10, a*a + b + 10 < 50]
s = Solver()
print (s.check(F))
print (s.model())
This prints:
sat
[b = 7, a = 4]
That looks good to me too.
So, I don't know how you're getting the unknown answer. Maybe you have an old version of z3; or you've some other things in your program you're not telling us about.
The important thing to note, however, is that s.add(F); s.check() AND s.check(F) are different operations:
s.add(F); s.check() means: Assert the constraints in F; check that they are satisfiable.
s.check(F) means: Check that all the other constraints are satisfiable, assuming F is. In particular, it does not assert F. (This is important if you do further asserts/checks later on.)
So, in general these two different ways of using check are used for different purposes; and can yield different answers. But in the presence of no other assertions around, you'll get a solution for both, though of course the models might be different.
Aside One reason you can get unknown is in the presence of non-linear constraints. And your a*a+b+10 < 50 is non-linear, since it does have a multiplication of a variable by itself. You can deal with that either by using a bit-vector instead of an Int (if applicable), or using the nonlinear-solver; which can still give you unknown, but might perform better. But just looking at your question as you asked it, z3 is just fine handling it.
To find out what is going on within s.check(F), you can do the following:
from z3 import *
import inspect
a = Int('a')
b = Int('b')
F = [a + b > 10, a*a + b + 10 < 50]
s = Solver()
print (s.check(F))
print (s.model())
source_check = inspect.getsource(s.check)
print(source_check)
The resulting output:
sat
[b = 10, a = 1]
def check(self, *assumptions):
"""Check whether the assertions in the given solver plus the optional assumptions are consistent or not.
>>> x = Int('x')
>>> s = Solver()
>>> s.check()
sat
>>> s.add(x > 0, x < 2)
>>> s.check()
sat
>>> s.model().eval(x)
1
>>> s.add(x < 1)
>>> s.check()
unsat
>>> s.reset()
>>> s.add(2**x == 4)
>>> s.check()
unknown
"""
s = BoolSort(self.ctx)
assumptions = _get_args(assumptions)
num = len(assumptions)
_assumptions = (Ast * num)()
for i in range(num):
_assumptions[i] = s.cast(assumptions[i]).as_ast()
r = Z3_solver_check_assumptions(self.ctx.ref(), self.solver, num, _assumptions)
return CheckSatResult(r)
The semantics of assumptions vs. assertions are discussed here and here. But if have to admit that they are not really clear to me yet.
F(x1) > a;
F(x2) < b;
∀t, F'(x) >= 0 (derivative) ;
F(x) = ∑ ci*x^i; (i∈[0,n] ; c is a constant)
Your question is quite ambiguous, and stack-overflow works the best if you show what you tried and what problems you ran into.
Nevertheless, here's how one can code your problem for a specific function F = 2x^3 + 3x + 4, using the Python interface to z3:
from z3 import *
# Represent F as a function. Here we have 2x^3 + 3x + 4
def F(x):
return 2*x*x*x + 3*x + 4
# Similarly, derivative of F: 6x^2 + 3
def dF(x):
return 6*x*x + 3
x1, x2, a, b = Ints('x1 x2 a b')
s = Solver()
s.add(F(x1) > a)
s.add(F(x2) < b)
t = Int('t')
s.add(ForAll([t], dF(t) >= 0))
r = s.check()
if r == sat:
print s.model()
else:
print ("Solver said: %s" % r)
Note that I translated your ∀t, F'(x) >= 0 condition as ∀t. F'(t) >= 0. I assume you had a typo there in the bound variable.
When I run this, I get:
[x1 = 0, x2 = 0, b = 5, a = 3]
This method can be generalized to arbitrary polynomials with constant coefficients in the obvious way, but that's mostly about programming and not z3. (Note that doing so in SMTLib is much harder. This is where the facilities of host languages like Python and others come into play.)
Note that this problem is essentially non-linear. (Variables are being multiplied with variables.) So, SMT solvers may not be the best choice here, as they don't deal all that well with non-linear operations. But you can deal with those problems as they arise later on. Hope this gets you started!
Let's say I have a z3py program like this one:
import z3
a = z3.Int("a")
input_0 = z3.Int("input_0")
output = z3.Int("output")
some_formula = z3.If(a < input_0, 1, z3.If(a > 1, 4, 2))
s = z3.Solver()
s.add(output == some_formula)
s.check()
m = s.model()
print(m)
Is there an elegant way for me to retrieve the branching conditions from some_formula?
So get a list like [a < input_0, a > 1]. It should work for arbitrarily deep nesting of if expressions.
I know there is some way to use cubes, but I am not able to retrieve more than two cube expressions. I am not sure how to configure the solver.
My ultimate goal is to force the solver to give me different outputs based on the constraints I push and pop. The constraints are the set of conditions I have inferred from this formula.
You can print the cubes using:
for cube in s.cube():
print cube
But this isn't going to really help you. For your example, it prints:
[If(a + -1*input_0 >= 0, If(a <= 1, 2, 4), 1) == 1]
[Not(If(a + -1*input_0 >= 0, If(a <= 1, 2, 4), 1) == 1)]
which isn't quite what you were looking for.
The easiest way to go about your problem would be to directly walk down the AST of the formula yourself, and grab the conditions as you walk along the expressions. Of course, Z3 AST is quite a hairy object (pun intended!), so this will require quite a bit of programming. But reading through the constructors (If, Var etc.) in this file can get you started: https://z3prover.github.io/api/html/z3py_8py_source.html
Alright,thanks #alias! I came up with a custom version, which gets the job done. If someone knows a more elegant way to do this, please let me know.
import z3
a = z3.Int("a")
input_0 = z3.Int("input_0")
output = z3.Int("output")
some_formula = z3.If(a < input_0, 1, z3.If(a > 1, 4, 2))
nested_formula = z3.If(some_formula == 1, 20, 10)
s = z3.Solver()
s.add(output == some_formula)
s.check()
m = s.model()
print(m)
def get_branch_conditions(z3_formula):
conditions = []
if z3.is_app_of(z3_formula, z3.Z3_OP_ITE):
# the first child is usually the condition
cond = z3_formula.children()[0]
conditions.append(cond)
for child in z3_formula.children():
conditions.extend(get_branch_conditions(child))
return conditions
conds = get_branch_conditions(some_formula)
print(conds)
conds = get_branch_conditions(nested_formula)
print(conds)
Over the years I keep track of solving technology - and I maintain a blog post about applying them to a specific puzzle - the "crossing ladders".
To get to the point, I accidentally found out about z3, and tried putting it to use in the specific problem. I used the Python bindings, and wrote this:
$ cat laddersZ3.py
#!/usr/bin/env python
from z3 import *
a = Int('a')
b = Int('b')
c = Int('c')
d = Int('d')
e = Int('e')
f = Int('f')
solve(
a>0, a<200,
b>0, b<200,
c>0, c<200,
d>0, d<200,
e>0, e<200,
f>0, f<200,
(e+f)**2 + d**2 == 119**2,
(e+f)**2 + c**2 == 70**2,
e**2 + 30**2 == a**2,
f**2 + 30**2 == b**2,
a*d == 119*30,
b*c == 70*30,
a*f - 119*e + a*e == 0,
b*e - 70*f + b*f == 0,
d*e == c*f)
Unfortunately, z3 reports...
$ python laddersZ3.py
failed to solve
The problem does have at least this integer solution: a=34, b=50, c=42, d=105, e=16, f=40.
Am I doing something wrong, or is this kind of system of equations / range constraints beyond what z3 can solve?
Thanks in advance for any help.
UPDATE, 5 years later: Z3 now solves this out of the box.
You can solve this using Z3 if you encode the integers as reals, which will force Z3 to use the nonlinear real arithmetic solver. See this for more details on the nonlinear integer vs. real arithmetic solvers: How does Z3 handle non-linear integer arithmetic?
Here's your example encoded as reals with the solution (z3py link: http://rise4fun.com/Z3Py/1lxH ):
a,b,c,d,e,f = Reals('a b c d e f')
solve(
a>0, a<200,
b>0, b<200,
c>0, c<200,
d>0, d<200,
e>0, e<200,
f>0, f<200,
(e+f)**2 + d**2 == 119**2,
(e+f)**2 + c**2 == 70**2,
e**2 + 30**2 == a**2,
f**2 + 30**2 == b**2,
a*d == 119*30,
b*c == 70*30,
a*f - 119*e + a*e == 0,
b*e - 70*f + b*f == 0,
d*e == c*f) # yields [a = 34, b = 50, c = 42, d = 105, e = 16, f = 40]
While the result is integer as you noted, and as what Z3 finds, Z3 apparently needs to use the real arithmetic solver to handle it.
Alternatively, you can leave the variables declared as integers and do the following from the suggestion at the referenced post:
t = Then('purify-arith','nlsat')
s = t.solver()
solve_using(s, P)
where P is the conjunction of the constraints (z3py link: http://rise4fun.com/Z3Py/7nqN ).
Rather than asking Z3 for a solution in reals, you could ask the solver of the Microsoft Solver Foundation:
using Microsoft.SolverFoundation.Services;
static Term sqr(Term t)
{
return t * t;
}
static void Main(string[] args)
{
SolverContext context = SolverContext.GetContext();
Domain range = Domain.IntegerRange(1, 199); // integers ]0; 200[
Decision a = new Decision(range, "a");
Decision b = new Decision(range, "b");
Decision c = new Decision(range, "c");
Decision d = new Decision(range, "d");
Decision e = new Decision(range, "e");
Decision f = new Decision(range, "f");
Model model = context.CreateModel();
model.AddDecisions(a, b, c, d, e, f);
model.AddConstraints("limits",
sqr(e+f) + d*d == 119*119,
sqr(e+f) + c*c == 70*70,
e*e + 30*30 == a*a,
f*f + 30*30 == b*b,
a*d == 119*30,
b*c == 70*30,
a*f - 119*e + a*e == 0,
b*e - 70*f + b*f == 0,
d*e == c*f);
Solution solution = context.Solve();
Report report = solution.GetReport();
Console.WriteLine("a={0} b={1} c={2} d={3} e={4} f={5}", a, b, c, d, e, f);
Console.Write("{0}", report);
}
The solver comes up with the solution you mentioned within fractions of a second. The Express Edition used to be free, but I am not sure about the current state.
a: 34
b: 50
c: 42
d: 105
e: 16
f: 40
There is no algorithm that, in general, can answer whether a multivariate polynomial equation (or a system thereof, as in your case) has integer solution (this is the negative answer to Hilbert's tenth problem). Thus, all solving methods for integers are either restricted to certain classes (e.g. linear equations, polynomials in one variable...) or use incomplete tricks, such as:
Linearizing expressions
Encoding equations into finite-bitwidth
numbers (ok for searching for "small" solutions).
This is why Z3 needs to be told to use the real number solver.