I was playing with a small multi-objective integer programming problem:
In Z3 (using the Python bindings) we can state this very elegantly:
from z3 import *
x1,x2 = Ints('x1 x2')
z1,z2 = Reals('z1 z2')
opt = Optimize()
opt.set(priority='pareto')
opt.add(x1 >= 0, x2 >=0, x1 <= 2, x2 <= 2)
opt.add(x1 <= 2*x2)
# this version is ok:
# opt.add(z1 == x1 - 2*x2, z2 == -x1 + 3*x2)
# this truncates coefficients (round down to integer):
# opt.add(z1 == 0.5*x1 - 1.0*x2, z2 == -0.5*x1 + 1.5*x2)
# this one seems to work:
# opt.add(z1 == 0.5*ToReal(x1) - 1.0*ToReal(x2), z2 == -0.5*ToReal(x1) + 1.5*ToReal(x2))
opt.add(z1 == x1 - 2*x2, z2 == -x1 + 3*x2)
f1 = opt.maximize(z1)
f2 = opt.maximize(z2)
while opt.check() == sat:
print(opt.model())
This solves correctly and gives:
[x1 = 2, x2 = 1, z2 = 1, z1 = 0]
[x1 = 0, x2 = 2, z2 = 6, z1 = -4]
[x1 = 2, x2 = 2, z2 = 4, z1 = -2]
[x1 = 1, x2 = 1, z2 = 2, z1 = -1]
[x1 = 1, x2 = 2, z2 = 5, z1 = -3]
As my real problem has floating point coefficients for the objectives, I divided the objectives by 2:
opt.add(z1 == 0.5*x1 - 1.0*x2, z2 == -0.5*x1 + 1.5*x2)
This model should give the same five solutions for the x variables. However, when we run it, we see some wrong results:
[x1 = 0, x2 = 0, z2 = 0, z1 = 0]
[x1 = 0, x2 = 2, z2 = 2, z1 = -2]
[x1 = 0, x2 = 1, z2 = 1, z1 = -1]
When I print opt I can see where things go wrong:
(assert (= z1 (to_real (- (* 0 x1) (* 1 x2)))))
(assert (= z2 (to_real (+ (* 0 x1) (* 1 x2)))))
The coefficients are silently truncated and converted to integers: 0.5 arrived as 0 and 1.5 became 1.
A workaround seems to be:
opt.add(z1 == 0.5*ToReal(x1) - 1.0*ToReal(x2), z2 == -0.5*ToReal(x1) + 1.5*ToReal(x2))
This converts the floating point coefficient to their rational equivalents:
(assert (= z1 (- (* (/ 1.0 2.0) (to_real x1)) (* 1.0 (to_real x2)))))
(assert (= z2 (+ (* (- (/ 1.0 2.0)) (to_real x1)) (* (/ 3.0 2.0) (to_real x2)))))
Now 0.5 becomes (/ 1.0 2.0) and 1.5 is represented by (/ 3.0 2.0).
My questions are:
Is this truncation "as designed"?
Is my workaround the correct way to go about this? Or should I avoid floating point coefficients altogether?
The printed rational number (/ 1.0 2.0) seems to hint there are still floating point numbers involved. Is this really (/ 1 2)? (I assume these are actually bigints).
I think you essentially answered your own question. Bottom line is that Python is an untyped language, so when you mix-and-match different typed operands to arithmetic operators, you are at the mercy of the library as it will "match" these types for you, and it is not surprising that it does the wrong thing here. In SMT-Lib2, or any other more strongly-typed binding, you'd instead get a type error.
Never mix types in arithmetic, and always be explicit. Or, better yet, use an interface that enforces this in its type system, instead of implicitly coercing constants. So, short answer is, yes; this is by design, but not because of any deep reason, but rather how the Python bindings behave.
Here's a simpler demo:
>>> from z3 import *
>>> x = Int('x')
>>> y = Real('y')
>>> x*2.5
x*2
>>> y*2.5
y*5/2
So, it appears that once you have a declared variable, then the constants that interact with them automatically coerce to the type of that variable. But I wouldn't count on that at all: It's best to be always explicit when you are working in an untyped setting.
Related
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.
Is there any way of get the specific domain of an Integer variable with z3 (assuming the variable belong to a finite domain)?
I have the following set of constraints:
1 <= X <= 5
2 <= Y <= 8
X + Y == T
and I would like to obtain:
3 <= T <= 13
Or even a simpler case:
1 <= X <= 10
5 <= X <= 15
I want to get:
5 <= X <= 10
This seems to be pretty trivial, but I didn't find a way to obtain such an answer with z3.
You can use Z3's optimization routines to solve these sorts of constraints. Your first problem can be coded as:
(declare-const X Int)
(declare-const Y Int)
(declare-const T Int)
(assert (<= 1 X 5))
(assert (<= 2 Y 8))
(assert (= (+ X Y) T))
(push)
(minimize T)
(check-sat)
(pop)
(maximize T)
(check-sat)
To which z3 responds:
sat
(objectives
(T 3)
)
sat
(objectives
(T 13)
)
Which, if you squint right, is saying 3 <= T <= 13; as you were trying to find out.
You can also use the Python interface to do the same. Your second example can be coded in z3py as follows:
from z3 import *
X = Int('X')
s = Optimize()
s.add(1 <= X); s.add(X <= 10)
s.add(5 <= X); s.add(X <= 15)
s.push()
s.minimize(X)
s.check()
print s.model()
s.pop()
s.maximize(X)
s.check()
print s.model()
which produces:
[X = 5]
[X = 10]
indicating 5 <= X <= 10.
Getting min/max with one call
If you want to avoid two calls to the solver, then you can use the box parameter to optimization, which optimizes the objectives independently:
(declare-const X Int)
(declare-const Y Int)
(declare-const T Int)
(assert (<= 1 X 5))
(assert (<= 2 Y 8))
(assert (= (+ X Y) T))
(minimize T)
(maximize T)
(set-option:opt.priority box)
(check-sat)
Now, z3 responds:
sat
(objectives
(T 3)
(T 13)
)
which contains the results in the order given, i.e, 3 for minimize and 13 for maximize.
I'm a total newbie with Z3 (started today). So far liking it a lot. Great tool. Unfortunately the syntax confuses me a bit.
I want to prove that if:
a^3 = xyz = m ( with a, x, y, z, m (0..1) )
then:
3a <= (x+y+z)
I do so by trying to find a model satisfying that:
3a > (x+y+z)
Here is the Z3 code:
(declare-const a Real)
(declare-const x Real)
(declare-const y Real)
(declare-const z Real)
(declare-const m Real)
(assert (> a 0))
(assert (< a 1))
(assert (> x 0))
(assert (< x 1))
(assert (> y 0))
(assert (< y 1))
(assert (> z 0))
(assert (< z 1))
(assert (> m 0))
(assert (< m 1))
(assert (= (* (* a a) a) m))
(assert (= (* (* x y) z) m))
(assert (> (* 3.0 a) (+ (+ z y) x) ))
(check-sat)
The model is unsatisfied.
Have I successfully proved what I wanted? As I said, the syntax confuses me since I'm a total newbie.
Your solution is correct.
Explanation: What you wrote is equivalent to:
0 < x < 1
0 < y < 1
0 < z < 1
0 < m < 1
a * a * a = m
x * y * z = m
3 * a > x + y + z
Z3 says this is unsatisfiable. Thus, if
a^3 = xyz = m ( with a, x, y, z, m (0..1) )
then it cannot be the case that:
3a > (x+y+z)
because, if this did occur, then the SMT problem you posed would be satisfiable, which would be a contradiction with the claim by Z3 that the SMT problem is unsatisfiable. If it cannot be the case that 3a > (x+y+z), then it must be the case that 3a <= (x+y+z), which is the statement you originally wanted to prove.
I think that your solution is correct. Let me explain a bit about using Z3 to prove validity of a statement A. The key idea is that, in the classical logic, e.g., propositional logic and predicate logic:
A is Valid iff negation(A) is Unsatisfiable.
This is a pretty well-known result. You can find it in many textbooks and materials, for example, in page 4 of this slide. So, validity of P -> Q can be proved via checking for unsatisfiability of its negation: P /\ negation(Q).
In particular, for your example,
(a^3 = x*y*z = m) -> (3a <= x+y+z) is Valid,
iff
(a^3 = m) /\ (x*y*z = m) /\ (3a > x+y+z) is Unsatifiable.
My apologies if this question is ill-phrased but I'm trying to use z3 (in python with the language binding) to solve some nonlinear equations, but unfortunately neither the qfnra-nlsat nor the general solver could solve the following system unless a, b and c are all given:
y == 0.001 * (a ** 2.07) * (b ** 0.9) * (c ** 0.7) + 0.002
y > 0.0
I tried with the following tactic:
t = z3.Then('simplify', 'qfnra-nlsat')
and I also tried substituting the nonlinear parts with some intermediate names and add the exponential parts back in later with incremental solver using push(). But z3 basically gets stuck (longer than 1 hour as far as I tried) in both cases.
I'm a newbie to CSP and the theoretical background involved, sorry if this is a dumb question but I'm wondering if such nonlinearity is beyond (empirically) solvable by z3 or I'm not using it correctly? Thanks!
Edit:
Here's the python code that fails on my machine:
import z3
a = z3.Real('a')
b = z3.Real('b')
c = z3.Real('c')
y = z3.Real('y')
eq = [
y == 0.001 * (a ** 2.07) * (b ** 0.9) * (c ** 0.7) + 0.002,
y >= 0.0
]
t = z3.Then('simplify', 'qfnra-nlsat')
s = t.solver()
s.add(eq)
r = s.check()
print r
m = s.model()
print m
Here's the output:
unknown
[y = 1/500 ]
Edit:
It seems that the latest code from z3 git repo is kinda broken. I tried with 4.4.1 release and it all worked out.
A follow up question though, if I just add one more constraint below:
a == 16.0
And z3 gets stuck, which I could not understand...It seems that the additional constraint above is pretty trivial, an initial guess of b and c being both 1s should solve the system, but I guess that's not how z3 works? Any idea on how to solve the system with this new constraint?
Presuming I didn't make some translation mistake, I tried this out in the pure SMT-LIB interface and it seems to work fine.
If you still have some problems after looking at this, please encode your entire example that is failing, as maybe you have some constraints that you didn't include that is causing it to fail. Or, possibly the overloaded Python operators (e.g., **) are not being interpreted properly (although that does seem to be the right usage for power), so you may want to use the Z3 Python API's functions for various expressions.
I included this x variable that's extra just to double check I was using ^ correctly as power, and it seems right (rise4fun link: http://rise4fun.com/Z3/plLQJ ):
(declare-const x Real)
(declare-const y Real)
(declare-const a Real)
(declare-const b Real)
(declare-const c Real)
; y == 0.001 * (a ** 2.07) * (b ** 0.9) * (c ** 0.7) + 0.002
(assert (= y (+ (* 0.001 (^ a 2.07) (^ b 0.9) (^ c 0.7)) 0.002)))
(assert (> y 0.0))
(check-sat-using qfnra-nlsat)
(get-model)
(assert (> x 1.0))
(assert (= x (^ 5.0 2.5))) ; check ^ means pow
(check-sat-using qfnra-nlsat)
(get-model)
This yields:
sat
(model
(define-fun a () Real
(- 1.0))
(define-fun b () Real
(- 1.0))
(define-fun c () Real
(- 1.0))
(define-fun y () Real
(+ (/ 1.0 500.0)
(* (- (/ 69617318994479297159441705182250977318952641791835914067365099344218850343780027694073822279020999411953209540560859156221731465694293028234177768119402105034869871366755227547291324996387.0
4000.0))
(^ (/ 1.0 8.0) 207.0))))
)
sat
(model
(define-fun a () Real
(- 1.0))
(define-fun b () Real
(- 1.0))
(define-fun c () Real
(- 1.0))
(define-fun x () Real
(root-obj (+ (^ x 2) (- 3125)) 2))
(define-fun y () Real
(+ (/ 1.0 500.0)
(* (- (/ 69617318994479297159441705182250977318952641791835914067365099344218850343780027694073822279020999411953209540560859156221731465694293028234177768119402105034869871366755227547291324996387.0
4000.0))
(^ (/ 1.0 8.0) 207.0))))
)
Suppose I read the SMTLIB formula using the API:
context ctx;
...
expr F = to_expr(ctx, Z3_parse_smtlib2_file(ctx,argv[1],0,0,0,0,0,0));
The expression F is a conjunction of assertions of the form:
(and (< (+ x y) 3)
(> (- x1 x2) 0)
(< (- x1 x2) 4)
(not (= (- x1 x2) 1))
(not (= (- x1 x2) 2))
(not (= (- x1 x2) 3)))
I'd like to extract each individual assertion from this conjunction using the following code fragment from post: How to use z3 split clauses of unsat cores & try to find out unsat core again
F = F.simplify();
for (unsigned i = 0; i < F.num_args(); i++) {
expr Ai = F.arg(i);
// ... Do something with Ai, just printing in this example.
std::cout << Ai << "\n";
}
After utilizing the F.arg(i), the original clause (< (+ x y) 3) has been changed into (not (<= 3 (+ x y))). Here is my
a) question : How can I place the clause (not (<= 3 (+ x y))) to (< (+ x y) 3) ?
b) question : I consider the symbol <= mean to imply in this case, not mean to less than. Am I right?
c) question : Because the clause (not (<= 3 (+ x y))) model is true or false, how can I get arithmetic values such as x = 1, y = -1?
It's very grateful for any suggestion.
Thank you very much.
The expression (< (+ x y) 3) is transformed into (not (<= 3 (+ x y))) when F = F.simplify().
In the code fragment you used, the method simplify() is used to "flat" nested "and"s. That is, a formula (and (and A B) (and C (and D E))) is flattened into (and A B C D E). Then, all conjuncts can be easily traversed using the for-loop. However, the simplify() will also perform other transformations in the input formula. Keep in mind, that all transformation preserve equivalence. That is, the input and output formula are logically equivalent. If the transformations applied by simplify() are not desirable, I suggest you avoid this method. If you still want to traverse nested "and"s, you can use an auxiliary todo vector. Here is an example:
expr_vector todo(c);
todo.push_back(F);
while (!todo.empty()) {
expr current = todo.back();
todo.pop_back();
if (current.decl().decl_kind() == Z3_OP_AND) {
// it is an AND, then put children into the todo list
for (unsigned i = 0; i < current.num_args(); i++) {
todo.push_back(current.arg(i));
}
}
else {
// do something with current
std::cout << current << "\n";
}
}