I am very new to z3py. I am trying to code the following logarithmic expressions in z3py .
log(x,y)
I did search stack overflow a lot and came across a similar question, but unfortunately I could not get a satisfactory enough answer. Please help me!
More generally, how can we define logs with Z3?
The only way I have gotten any traction at all is to use an approximate value for e, define exp(x) as (^ e x), and then define log as a total function that is the inverse of exp. In SMT-LIB 2:
(define-fun exp ((x Real)) Real (^ 2.718281828459045 x))
(declare-fun log (Real) Real)
(assert (forall ((x Real)) (= (log (exp x)) x)))
(assert (forall ((x Real)) (= (exp (log x)) x)))
In Z3Py:
from z3 import *
from math import e
# This is an approximation
def Z3_exp(x):
return e ** x
s = Solver()
# We define Z3_log as a total function that is the inverse of Z3_exp
Z3_log = Function('log', RealSort(), RealSort())
x = Real('x')
s.add(ForAll([x], Z3_log(Z3_exp(x)) == x))
s.add(ForAll([x], Z3_exp(Z3_log(x)) == x))
The obvious problem with this is that it introduces an approximation for e, which will cause some incorrect results depending on what you are trying to prove. Also, because it uses uninterpreted functions to define log, the most powerful nonlinear solver (nlsat) will not be used, and also, because functions are total in SMT-LIB, there will be the typical weird domain issues for negative arguments.
An alternative would be to simply bound e, but this is still not exact, and is likely to have worse behavior. There is also an undocumented built-in symbol euler in Z3, but at the moment it is essentially non-functional.
Related
I tried QF_NRA in z3 and it gave me an abstract value about root-obj.
(set-logic QF_NRA)
(declare-const x Real)
(assert (= 2 (* x x)))
(check-sat)
sat
(get-model)
(
(define-fun x () Real
(root-obj (+ (^ x 2) (- 2)) 1))
)
I don’t quite understand its meaning.
In addition, the x seems defined in recursion but not by define-fun-rec.
Thanks.
Algebraic reals
Z3's Real theory supports what's known as algebraic reals. That is, it can express solutions in terms of the roots of polynomials with rational (equivalently, integer) valued coefficients. Note that such a polynomial can have complex roots. Z3 only supports those roots that are real, i.e., those with an imaginary part of 0. An algebraic real is essentially the real-root of a univariate polynomial with integer coefficients.
Dealing with root-obj's
In the example you posted, you're asking z3 to find a satisfying model for x*x == 2. And it's telling you that the solution is "a" zero-of-the polynomial (+ (^ x 2) (- 2)), or written in more familiar notation P(x) = x^2 -2. The index you get is 1 (the second argument to the root-obj), which says it's the "first" real-root of this polynomial. If you ask z3 to give you another solution, it'll give you the next one:
(set-logic QF_NRA)
(declare-const x Real)
(assert (= 2 (* x x)))
(assert (distinct x (root-obj (+ (^ x 2) (- 2)) 1)))
(check-sat)
(get-model)
This prints:
sat
(
(define-fun x () Real
(root-obj (+ (^ x 2) (- 2)) 2))
)
As you see, the "next" solution is the second root. What if we assert we want yet another solution?
(set-logic QF_NRA)
(declare-const x Real)
(assert (= 2 (* x x)))
(assert (distinct x (root-obj (+ (^ x 2) (- 2)) 1)))
(assert (distinct x (root-obj (+ (^ x 2) (- 2)) 2)))
(check-sat)
This prints:
unsat
as expected.
Note that algebraic reals do not include numbers such as pi, e, etc., i.e., they do not include transcendentals. Only those real numbers that can be expressed as the root of polynomials with integer coefficients. Leonardo's paper from 2012 explains this in great detail.
Getting approximations
z3 also allows you to get an approximation for such a root-obj solution, with as arbitrary a precision as you like. To do so, use the incantation:
(set-option :pp.decimal true)
(set-option :pp.decimal_precision 20)
where 20 in the second line is how many digits of precision you'd like, and you can change it as you see fit. If you add these two lines to your original script, z3 will respond:
sat
(
(define-fun x () Real
(- 1.4142135623730950?))
)
Note the ? at the end of the number. This is z3's way of telling you that the number it printed is an "approximation" to the value, i.e., it isn't the precise result.
A note on "recursion"
Your question suggests maybe x is defined recursively. This isn't the case. It just happens that you picked the variable name to be x and z3 always uses the letter x for the polynomial as well. If you picked y as the variable, you'd still get the exact same answer; the parameter to the polynomial has nothing to the with the variables in your program.
I'm stuck on how to how to create a statement in SMTLIB2 that asserts something like
forall x < 100, f(x) = 100
This property would be check a function that adds 1 to all numbers less than 100 recursively:
(define-fun-rec incUntil100 ((x Int)) Int
(ite
(= x 100)
100
(incUntil100 (+ x 1))
)
)
I read through the Z3 tutorial on quantifiers and patterns, but that didn't seem to get me much anywhere.
In SMTLib, you'd write that property as follows:
(assert (forall ((x Int)) (=> (< x 100) (= (incUntil100 x) 100))))
(check-sat)
But if you try this, you'll see that z3 will loop forever and CVC4 will tell you unknown as the answer. While you can define and assert these sorts of functions in SMTLib, solver support for actual proofs is rather weak, as they do not do induction out-of-the box.
If proving properties of recursive functions is your goal, SMT-solvers are not a good choice; instead look into theorem provers such as Isabelle, HOL, Coq, Lean, ACL2, etc.; which are built for that very purpose.
I'm trying to create a function in Z3 that is transitive but not reflexive. I.e. if (transitive a b) and (transitive b c)hold then (transitive a c) should hold, but (transitive a a) should not.
I've tried to do it the following way, with 5 "tests". The first does what I expect, but the second one fails and results in unknown.
(declare-datatypes () ((T T1 T2 T3)))
(declare-fun f (T T) Bool)
(assert(f T1 T2))
(assert(f T2 T3))
; Make sure that f is not reflexive
(assert
(forall ((x T))
(not (f x x))))
; Now we create the transitivity function ourselves
(define-fun-rec transitive ((x T) (y T)) Bool
(or
(f x y)
(exists ((z T))
(and
(f x z)
(transitive z y)))))
; This works and gives sat
(push)
(assert (not (transitive T1 T1)))
(assert (not (transitive T2 T2)))
(assert (not (transitive T3 T3)))
(check-sat)
(pop)
; This fails with "unknown" and the verbose flag gives: (smt.mbqi "max instantiations 1000 reached")
(push)
(assert
(forall ((x T))
(not (transitive x x))))
(check-sat)
(pop)
My question is: how does the second test differ from the first? Why does the last one give unknown, whereas the one before that works just fine?
The "verbose" message is a hint here. mbqi stands for model-based-quantifier-instantiation. It's a method of dealing with quantifiers in SMT solving. In the first case, MBQI manages to find a model. But your transitive function is just too complicated for MBQI to handle, and thus it gives up. Increasing the limit will not likely address the problem, nor it's a long term solution.
Short story long, recursive definitions are difficult to deal with, and recursive definitions with quantifiers are even harder. The logic becomes semi-decidable, and you're at the mercy of heuristics. Even if you found a way to make z3 compute a model for this, it would be brittle. These sorts of problems are just not suitable for SMT solving; better use a proper theorem prover like Isabelle, Hol, Coq, Lean. Agda, etc. Almost all these tools offer "tactics" to dispatch subgoals to SMT solvers, so you have the best of both worlds. (Of course you lose full automation, but with quantifiers present, you can't expect any better.)
Using smtlib I would like to make something like modulo using QF_UFNRA. This disables me from using mod, to_int, to_real an such things.
In the end I want to get the fractional part of z in the following code:
(set-logic QF_UFNRA)
(declare-fun z () Real)
(declare-fun z1 () Real)
(define-fun zval_1 ((x Real)) Real
x
)
(declare-fun zval (Real) Real)
(assert (= z 1.5));
(assert (=> (and (<= 0.0 z) (< z 1.0)) (= (zval z) (zval_1 z))))
(assert (=> (>= z 1.0) (= (zval z) (zval (- z 1.0)))))
(assert (= z1 (zval z)))
Of course, as I am asking this question here, implies, that it didn't work out.
Has anybody got an idea how to get the fractional part of z into z1 using logic QF_UFNRA?
This is a great question. Unfortunately, what you want to do is not possible in general if you restrict yourself to QF_UFNRA.
If you could encode such functionality, then you can decide arbitrary Diophantine equations. You would simply cast a given Diophantine equation over reals, compute the "fraction" of the real solution with this alleged method, and assert that the fraction is 0. Since reals are decidable, this would give you a decision procedure for Diophantine equations, accomplishing the impossible. (This is known as Hilbert's 10th problem.)
So, as innocent as the task looks, it is actually not doable. But that doesn't mean you cannot encode this with some extensions, and possibly have the solver successfully decide instances of it.
If you allow quantifiers and recursive functions
If you allow yourself quantifiers and recursive-functions, then you can write:
(set-logic UFNRA)
(define-fun-rec frac ((x Real)) Real (ite (< x 1) x (frac (- x 1))))
(declare-fun res () Real)
(assert (= (frac 1.5) res))
(check-sat)
(get-value (res))
To which z3 responds:
sat
((res (/ 1.0 2.0)))
Note that we used the UFNRA logic allowing quantification, which is required here implicitly due to the use of the define-fun-rec construct. (See the SMTLib manual for details.) This is essentially what you tried to encode in your question, but instead using the recursive-function-definition facilities instead of implicit encoding. There are several caveats in using recursive functions in SMTLib however: In particular, you can write functions that render your system inconsistent rather easily. See Section 4.2.3 of http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.5-draft.pdf for details.
If you can use QF_UFNIRA
If you move to QF_UFNIRA, i.e., allow mixing reals and integers, the encoding is easy:
(set-logic QF_UFNIRA)
(declare-fun z () Real)
(declare-fun zF () Real)
(declare-fun zI () Int)
(assert (= z (+ zF zI)))
(assert (<= 0 zF))
(assert (< zF 1))
(assert (= z 1.5))
(check-sat)
(get-value (zF zI))
z3 responds:
sat
((zF (/ 1.0 2.0))
(zI 1))
(You might have to be careful about the computation of zI when z < 0, but the idea is the same.)
Note that just because the encoding is easy doesn't mean z3 will always be able to answer the query successfully. Due to mixing of Real's and Integer's, the problem remains undecidable as discussed before. If you have other constraints on z, z3 might very well respond unknown to this encoding. In this particular case, it happens to be simple enough so z3 is able to find a model.
If you have sin and pi:
This is more of a thought experiment than a real alternative. If SMTLib allowed for sin and pi, then you can check whether sin (zI * pi) is 0, for a suitably constrained zI. Any satisfying model to this query would ensure that zI is integer. You can then use this value to extract the fractional part by subtracting zI from z.
But this is futile as SMTLib neither allows for sin nor pi. And for good reason: Decidability would be lost. Having said that, maybe some brave soul can design a logic that supported sin, pi, etc., and successfully answered your query correctly, while returning unknown when the problem becomes too hard for the solver. This is already the case for nonlinear arithmetic and the QF_UFNIRA fragment: The solver may give up in general, but the heuristics it employs might solve problems of practical interest.
Restriction to Rationals
As a theoretical aside, it turns out that if you restrict yourself to rationals only (instead of actual reals) then you can indeed write a first-order formula to recognize integers. The encoding is not for the faint of heart, however: http://math.mit.edu/~poonen/papers/ae.pdf. Furthermore, since the encoding involves quantifiers, it's probably quite unlikely that SMT solvers will do well with a formulation based on this idea.
[Incidentally, I should extend thanks to my work colleagues; this question made for a great lunch-time conversation!]
I am trying to prove an inductive fact in Z3, an SMT solver by Microsoft. I know that Z3 does not provide this functionality in general, as explained in the Z3 guide (section 8: Datatypes), but it looks like this is possible when we constrain the domain over which we want to prove the fact. Consider the following example:
(declare-fun p (Int) Bool)
(assert (p 0))
(assert (forall ((x Int))
(=>
(and (> x 0) (<= x 20))
(= (p (- x 1)) (p x) ))))
(assert (not (p 20)))
(check-sat)
The solver responds correctly with unsat, which means that (p 20) is valid. The problem is that when we relax this constraint any further (we replace 20 in the previous example by any integer greater than 20), the solver responds with unknown.
I find this strange because it does not take Z3 long to solve the original problem, but when we increase the upper limit by one it becomes suddenly impossible. I have tried to add a pattern to the quantifier as follows:
(declare-fun p (Int) Bool)
(assert (p 0))
(assert (forall ((x Int))
(! (=>
(and (> x 0) (<= x 40))
(= (p (- x 1)) (p x) )) :pattern ((<= x 40)))))
(assert (not (p 40)))
(check-sat)
Which seems to work better, but now the upper limit is 40. Does this mean that I can better not use Z3 to prove such facts, or am I formulating my problem incorrectly?
Z3 uses many heuristics to control quantifier instantiation. One one them is based on the "instantiation depth". Z3 tags every expression with a "depth" attribute. All user supplied assertions are tagged with depth 0. When a quantifier is instantiated, the depth of the new expressions is bumped. Z3 will not instantiate quantifiers using expressions tagged with a depth greater than a pre-defined threshold. In your problem, the threshold is reached: (p 40) is depth 0, (p 39) is depth 1, (p 38) is depth 2, etc.
To increase the threshold, you should use the option:
(set-option :qi-eager-threshold 100)
Here is the example with this option: http://rise4fun.com/Z3/ZdxO.
Of course, using this setting, Z3 will timeout, for example, for (p 110).
In the future, Z3 will have better support for "bounded quantification". In most cases, the best approach for handling this kind of quantifier is to expand it.
With the programmatic API, we can easily "instantiate" expressions before we send them to Z3.
Here is an example in Python (http://rise4fun.com/Z3Py/44lE):
p = Function('p', IntSort(), BoolSort())
s = Solver()
s.add(p(0))
s.add([ p(x+1) == p(x) for x in range(40)])
s.add(Not(p(40)))
print s.check()
Finally, in Z3, patterns containing arithmetic symbols are not very effective. The problem is that Z3 preprocess the formula before solving. Then, most patterns containing arithmetic symbols will never match. For more information on how to use patterns/triggers effectively, see this article. The author also provides a slide deck.