Can you limit a real variable between two bounds? - z3

Can you limit a real variable between two bounds?
s = Solver()
input = Reals('input')
s.add(input >= -2, input <= 2)
This example return unsat for me.

In cases like this, the sexpr method of the Solver class is your friend!
You're tripping up because of the extremely weakly typed nature of the z3py bindings. The call Reals returns multiple results, which you are assigning to a single element. That is, your input variable is now a list containing one variable. This, in turn, makes the whole program meaningless, as you can observe yourself:
from z3 import *
s = Solver()
input = Reals('input')
s.add(input >= -2, input <= 2)
print s.sexpr()
This prints:
(assert true)
(assert false)
Why? Because your variable input is a list, and the bizarre rules of type promotion decided that a list is greater than or equal to -2 but less than 2. (This is totally meaningless, just the way the bindings work. There's no rhyme or reason it should be this way. One can argue it should do more type-checking and give you a proper error. But I digress.)
To solve, simply change your call of Reals to Real:
from z3 import *
s = Solver()
input = Real('input')
s.add(input >= -2, input <= 2)
print s.sexpr()
print s.check()
print s.model()
This prints:
(declare-fun input () Real)
(assert (>= input (- 2.0)))
(assert (<= input 2.0))
sat
[input = 0]
which is exactly what you wanted to say.

Related

Lambda Functions for Z3Py

My goal is to find a construct within Z3Py which allows me to:
(1) Write propositions as a function of a variable. For eg theoretically, if I define P(x) = x < 3, then the code should allow me to access P(u) for some other variable u.
(2) And Z3 should be able to solve and find a model for such a construct.
I thought Z3's 'Lambda' function theoretically made sense. However with this construct neither can I do (1) or (2). As a concrete eg, suppose I have the following code:
u, x = Ints('u x')
P = Lambda( [x], x < 5 )
I = Lambda ([x], x < 3)
C1 = Not(Implies(P.body(), I.body() ))
s = Solver()
s.add(C1)
r = s.check()
print(r.__repr__())
s.add( Implies(P(u), u == 2) )
Run this code to get the output:
unknown
Traceback (most recent call last):
File "testfile.py", line 20, in <module>
s.add( Implies(P(u), u == 2) )
TypeError: 'QuantifierRef' object is not callable
There are two issues to fix here:
(1) Why does r._ repr_() have 'unknown' stored and not 'sat' i.e. Why isn't Z3 solving this system?
(2) In the final line, how can I get the predicate u < 5 from P i.e. in lambda calculus terminology, how do I do application of a function to a variable in Z3Py? Clearly P(u) does not work.
For this sort of modeling, you should simply use a regular python function:
from z3 import *
def P(x):
return x < 5
def I(x):
return x < 3
Then, to do the proof Q(x) => P(x), you'd use a quantifier:
dummy = Int('dummy')
C1 = ForAll([dummy], Implies(I(dummy), P(dummy)))
prove(C1)
This prints:
proved
Regarding your specific questions:
(1) Adding Implies(P.body(), Q.body()) means something completely different. If you run:
from z3 import *
x = Int('x')
P = Lambda( [x], x < 5 )
I = Lambda( [x], x < 3 )
s = Solver()
s.add(Implies(P.body(), I.body()))
print(s.sexpr())
You'll see it prints:
(assert (=> (< (:var 0) 5) (< (:var 0) 3)))
where :var is an internal free-variable generating function. This isn't an object you should be passing back and forth to z3; in fact, I think you're becoming a victim of the loosely typed nature of z3; this isn't a construct that really make much sense at all. Long story short, you should never look at P.body() or I.body() in your own code. I'd ignore the unknown result in this context; the input is more or less meaningless, and z3 spits out a nonsensical answer. A better system should've checked and complained about this; but this is not a strong point for z3's Python API.
(2) If you use a regular function, this isn't really a problem at all; because you're just doing regular application at the Python level. You can apply a lambda-bound value by directly calling it as well, though you need the notation P[u]. (Lambda's are similar to arrays in z3.) So, something like:
from z3 import *
u, x = Ints('u x')
P = Lambda([x], x < 5)
I = Lambda([x], x < 3)
s = Solver()
s.add(Implies(P[u], u == 2))
print(s.check())
print(s.model())
will print:
sat
[u = 2]
which is what you were looking for I think.
Multiple arguments
If you want to model a lambda with multiple arguments, the easiest way is to think of it as a nested construct. That is, you store a new lambda at each index. Here's an example:
from z3 import *
dummy1 = FreshInt()
dummy2 = FreshInt()
P = Lambda([dummy1], Lambda([dummy2], dummy1 < dummy2))
s = Solver()
x, y = Ints('x y')
s = Solver()
s.add(P[x][y])
print(s.check())
print(s.model())
This prints:
sat
[y = 1, x = 0]
Note that the above also demonstrates the use of the FreshInt function, which avoids name-clashes by providing a unique name each time it is called.

Power and logarithm in Z3

I'm trying to learn Z3 and the following example baffles me:
from z3 import *
a = Int("a")
b = Int("b")
print(solve(2**a <= b))
print(solve(a > 0, b > 0, 2**a <= b))
I would expect it returns "[a = 1, b = 2]" but it instead returns "failed to solve".
Why cannot it be solved?
Is it possible to compute with powers and logarithms in Z3 at all? How do I find, say, the length of binary string representation of a number (log base 2)?
Long story short, z3 (or SMT solvers in general) cannot deal with non-linear constraints like this. Exponentiation/Logs etc are difficult to deal with, and there are no decision procedures for them over the integers. Even over reals they are difficult to handle. That is, the solver will apply some heuristics, which may or may not work. But for these sorts of constraints, SMT solvers are just not the right tool.
For an earlier answer on non-linear arithmetic in z3, see this answer: https://stackoverflow.com/a/13898524/936310
Here're some more details if you are interested. First, there is no power-operator for integers in SMTLib or z3. If you look at the generated program, you'll see that it's actually over real values:
from z3 import *
a = Int("a")
b = Int("b")
s = Solver()
s.add(2**a <= b)
print(s.sexpr())
print(s.check())
This prints:
(declare-fun b () Int)
(declare-fun a () Int)
(assert (<= (^ 2 a) (to_real b)))
unknown
Note the conversion to to_real. The ^ operator automatically creates a real. The way this would be solved is if the solver can come up with a solution over reals, and then checks to see if the result is an integer. Let's see what happens if we try with Reals:
from z3 import *
a = Real("a")
b = Real("b")
s = Solver()
s.add(2**a <= b)
print(s.check())
print(s.model())
This prints:
sat
[b = 1, a = 0]
Great! But you also wanted a > 0, b > 0; so let's add that:
from z3 import *
a = Real("a")
b = Real("b")
s = Solver()
s.add(2**a <= b)
s.add(a > 0)
s.add(b > 0)
print(s.check())
This prints:
unknown
So, the solver can't handle this case either. You can play around with tactics (qfnra-nlsat), but it's unlikely to handle problems of this sort in general. Again, refer to https://stackoverflow.com/a/13898524/936310 for details.

Change Sort after defining a variable

Is it possible to change the domain of a variable after it has been defined and used in statements?. Example
s = Solver()
x = Real('x')
s.add(x < 1)
Now I want to change the domain of x to Int or Bool.
thanks!
The short answer is no.
But why do you want to do this? SMTLib is based on a many-sorted first-order logic, and variables can only have one sort. So, even if you can change the domain, it would be meaningless. (Essentially a type-error.)
Having said that, there's nothing stopping you from saying:
x = Int ('x')
at the end of that script. But the new x would be totally independent of the old x; i.e., a different name with a different sort and you'd lose access to the first one. Clearly, this is neither useful nor advisable. To wit:
from z3 import *
s = Solver ()
x = Real ('x')
s.add (x < 1)
x = Bool ('x')
s.add (x)
print s.sexpr()
print s.check()
print s.model()
This prints:
(declare-fun x () Real)
(declare-fun x () Bool)
(assert (< x 1.0))
(assert x)
sat
[x = True, x = 0]
This is very confusing to read, till you realize those two xs are totally independent of each other. (And I'd say the s.sexpr() method is rather buggy since it doesn't print out valid smt2-lib, as what it prints would be rejected by a compliant SMT-solver, but that's a different issue.)
I suspect, perhaps, you're trying to ask for something else. If you describe what you are trying to do in detail, you might get a better answer!

Z3: eliminate don't care variables

I have a test.smt2 file:
(set-logic QF_IDL)
(declare-const a Int)
(declare-const b Int)
(declare-const c Int)
(assert (or (< a 2) (< b 2 )) )
(check-sat)
(get-model)
(exit)
Is there anyway to tell Z3 to only output a=1 (or b=1)? Because when a is 1, b's value does not matter any more.
I executed z3 smt.relevancy=2 -smt2 test.smt2
(following How do I get Z3 to return minimal model?, although smt.relevancy seems has default value 2), but it still outputs:
sat
(model
(define-fun b () Int
2)
(define-fun a () Int
1)
)
Thank you!
The example given in the answer to the question referred to is slightly out of date. A Solver() will pick a suitable tactic to solve the problem, and it appears that it picks a different one now. We can still get that behavior by using a SimpleSolver() (at a possibly significant performance loss). Here's an updated example:
from z3 import *
x, y = Bools('x y')
s = SimpleSolver()
s.set(auto_config=False,relevancy=2)
s.add(Or(x, y))
print s.check()
print s.model()
Note that the (check-sat) command will not execute the same tactic as the SimpleSolver(); to get the same behavior when solving SMT2 files, we need to use the smt tactic, i.e., use (check-sat-using smt). In many cases it will be beneficial to additionally run the simplifier on the problem first which we can achieve by constructing a custom tactic, e.g., (check-sat-using (then simplify smt))

how to eliminate constraint in Z3

I have a constraint like (t>=0 or t>=1) and (t<=2 or t>=2),in fact the constraint can be simplified into "t>=0", how to use z3 to get the simplified result in CNF form by using z3?
(declare-const t Int)
(assert (and
(or
(>= t 0)
(>= t 1)
)
(or
(>= t 2)
(<= t 2)
)
(>= t 0)
(<= t 1)
)
)
(apply (par-then (! simplify :elim-and true) tseitin-cnf))
However, the script doesn't work.
The simplify tactic only perform "local simplifications". That is, when simplifying an expression t, it will ignore the context of t. For example, it can simplify a + 1 - a into 1, but it will not simplify a != 0 or b = a + 1 into a != 0 or b = 1.
Contextual simplification is expensive, the simplify tactic is meant to be efficient and simple. Other tactics may be used to achieve what you want.
The tactic propagate-ineqs will propagate inequalities. However, it will not process terms nested in the formula. The tactic split-clause can be used to break the formula in cases\goals. The tactic propagate-values will propagate the value of an assertion, example: a = 0 and b >= a is simplified to a = 0 and b >= 0.
The command (help-tactic) will display all available tactics.
Here is a strategy for simplifying your example into t >= 0 and t <= 1.
(apply (then simplify propagate-values split-clause propagate-ineqs))
Note that the combinator par-then is only useful for combining tactics that produce many sub-goals.
(par-then t1 t2) applies t1 to the input goal, and applies t2 (in parallel) to every subgoal produced by t1. The split-clause tactic produces more than one subgoal. Then (for bigger examples) it may be more efficient to use:
(apply (then simplify propagate-values (par-then split-clause propagate-ineqs)))

Resources