I'm new to Z3 and I'm trying to understand how it works, and what it can and cannot do. I know that Z3 has at least some support for exponentials through the power (^) operator (see Z3py returns unknown for equation using pow() function, How to represent logarithmic formula in z3py, and Use Z3 and SMT-LIB to define sqrt function with a real number). What I'm unclear on is how extensive this support is, and what kind of inferences z3 can make about exponentials.
Here's a simple example involving exponentials which z3 can analyze. We define an exponential function, and then ask it to verify that exp(0) == 1:
(define-fun exp ((x Real)) Real
(^ 2.718281828459045 x))
(declare-fun x1 () Real)
(declare-fun y1 () Real)
(assert (= y1 (exp x1)))
(assert (not (=> (= x1 0.0) (= y1 1.0))))
(check-sat)
(exit)
Z3 returns unsat, as expected. On the other hand, here's a simple example which Z3 can't analyze:
(define-fun exp ((x Real)) Real
(^ 2.718281828459045 x))
(declare-fun x1 () Real)
(declare-fun y1 () Real)
(assert (= y1 (exp x1)))
(assert (not (< y1 0.0)))
(check-sat)
(exit)
This should be satisfiable, since literally any value for x1 would give y1 > 0. However, Z3 returns unknown. Naively I might have expected that Z3 would be able to analyze this, given that it could analyze the first example.
I realize this question is a bit broad, but: can anyone give me any insight into how Z3 handles exponentials, and (more specifically) why it can solve the first example I gave but not the second?
It is hard to say in general, since non-linear solving is challenging, but the case you presented is actually not so mysterious. You wrote:
(assert (= y (exp x)))
(assert (not (=> (= x 0) (= y 1))))
Z3 is going to simplify the second assertion, yielding:
(assert (= y (exp x)))
(assert (= x 0))
(assert (not (= y 1)))
Then it will propagate the first equality, yielding:
(assert (= y (exp 0)))
(assert (not (= y 1)))
Now when exp is expanded, you have a case of constant^constant, which Z3 can handle (for integer exponents, etc).
For the second case, you are asking it a very very basic question about variable exponents, and Z3 immediately barfs. That's not too odd, since so many questions about variable exponents are either known uncomputable or unknown but hard.
Related
Not Solvable in Z3. Why?
My Program:
;x = 2x + 2 (This on Underlaying DB is always increasing as X > Y in DB)
(declare-const x0 Real)
(declare-const xn Real)
(declare-const n Real)
(push)
(assert (= x0 42))
(assert (= xn (+ (* x0 (^ 2 n)) (* 2 (- (^ 2 n) 1)) ) )) ; recurrence relation
(assert (> xn 700))
(check-sat-using qfnra-nlsat)
(get-model); to find a satisfiable valuation
(pop); removes any assertion
-----------------------------
Z3 Answer:
-----------------------------
unknown
(model
(define-fun n () Real 0.0)
(define-fun xn () Real 42.0)
(define-fun x0 () Real 42.0)
)
I tried with integer also:
According to the values in database 'n' should come as 4, but it is coming as 0.
Please see into it and anyone please help me.
unknown means the model is "alleged," i.e., may or may not be correct. Since your problem contains non-linear terms (exponentiation), this is to be expected.
Indeed, the model suggests xn = 42, which contradicts the assumption xn > 700 in your program. The model given is bogus. But you cannot blame z3 for that, since it already told you unknown. It's beyond Z3's capabilities to solve your query.
Since disabling unsound simplification of root objects, Z3 will now fail on this simple model involving a square root:
(define-fun sqrt ((x Real)) Real (^ x 0.5))
(declare-fun y () Real)
(declare-fun x () Real)
(assert (= y (sqrt x)))
(check-sat)
This returns sat with Z3 4.4.1, but unknown with master.
If I change the problem definition to use is_sqrt as defined by Nikolaj in this question, then Z3 master will return sat. The approach using is_sqrt shows that all real roots can be pushed into QF_NRA by introducing auxiliary variables, so I think Z3 should be able to solve all problems involving roots over the reals.
How can I define a square-root function in the reals that will result in a decidable theory, assuming the rest of the model is in QF_NRA?
There is a subtle difference between (assert (= y (^ x 0.5))) and (assert (and (= x (* y y)) (> y 0.0))). The difference comes from the requirement that all functions in Z3 (and SMT-LIB) are total. This means, for example, that y=1/x, x=0 is considered satisfiable. Given that ^ is total in Z3, (assert (and (= y (^ x 0.5)) (< x 0.0))) is considered satisfiable. We can't convert (= y (^ x 0.5)) to (and (= x (* y y)) (> y 0.0)), because if x < 0 then the former is considered satisfiable but the latter is unsatisfiable. Similarly, any sqrt function defined within SMT-LIB would also be total, so we cannot define a sqrt function by any other means such that (assert (= y (sqrt x))) is equivalent to (assert (and (= x (* y y)) (> y 0.0))). In addition to the above difference as to whether or not y = sqrt(x), x < 0 (pseudocode) is considered satisfiable, it is also the case that (assert (and (= x (* y y)) (> y 0.0))) is decidable (it is in QF_NRA), while (assert (= y (^ x 0.5))) is not.
The solution for my purpose is to not use a Z3 or SMT-LIB function definition for the square-root. Instead, I will use statements of the form (assert (and (= x (* y y)) (> y 0.0))) to indicate that y is the square-root of x. Such assertions are within QF_NRA, so models built in this way will be decidable. Furthermore, this has the advantage that y = sqrt(x), x < 0 (pseudocode) will return unsat if it is represented in SMT-LIB via the statements (assert (and (= x (* y y)) (> y 0.0))) and (assert (< x 0.0)). To return unsat for this example is more in-line with my use case.
In fact, does the SMT-LIB standard have a rational (not just real) sort? Going by its website, it does not.
If x is a rational and we have a constraint x^2 = 2, then we should get back ``unsatisfiable''. The closest I could get to encoding that constraint is the following:
;;(set-logic QF_NRA) ;; intentionally commented out
(declare-const x Real)
(assert (= (* x x) 2.0))
(check-sat)
(get-model)
for which z3 returns a solution, as there is a solution (irrational) in the reals. I do understand that z3 has its own rational library, which it uses, for instance, when solving QF_LRA constraints using an adaptation of the Simplex algorithm. On a related note, is there an SMT solver that supports rationals at the input level?
I'm sure it's possible to define a Rational sort using two integers as suggested by Nikolaj -- I would be interested to see that. It might be easier to just use the Real sort, and any time you want a rational, assert that it's equal to the ratio of two Ints. For example:
(set-option :pp.decimal true)
(declare-const x Real)
(declare-const p Int)
(declare-const q Int)
(assert (> q 0))
(assert (= x (/ p q)))
(assert (= x 0.5))
(check-sat)
(get-value (x p q))
This quickly comes back with
sat
((x 0.5)
(p 1)
(q 2))
I've been searching the square root functionality provided by z3. For example, for adding a constraint about a Real number x , that x*x = 2, what is the best way to encode that?
I tried:
(declare-const x Real)
(assert (= 2 (* x x)))
(check-sat)
The result is unknown. The model is also, unavailable.
However, I am sure there should be a way to satisfy this. I am referring strictly to the extended version of smt-lib 2.0 language and not the python api.
You need to use the nonlinear solver. The reason your example did not autodetect and use this is because of the constant 2: this gets parsed into an integer and not a real, so it's technically in the combination theory of integers and reals, while the nonlinear solver may only involve reals unless you force it. To force its use, you can use check-sat-using and the nonlinear solver qfnra-nlsat (rise4fun link: http://rise4fun.com/Z3/fXDp ):
(declare-const x Real)
(push)
(assert (= 2 (* x x)))
(check-sat-using qfnra-nlsat) ; sat
(get-model)
; may have to play with printing options as this is irrational (or this may be a bug)
; (model
; (define-fun x () Real
; (/ 5.0 4.0))
;)
(pop)
; the reason you need to use check-sat-using is because the 2 gets parsed into an integer; to force it to be a real, use a decimal:
(push)
(assert (= 2.0 (* x x)))
(check-sat) ; sat
(get-model)
;(model
; (define-fun x () Real
; (root-obj (+ (^ x 2) (- 2)) 1))
;)
(pop)
For general exponents (square roots, etc.), you can use ^ for exponentiation:
; you can also use ^ for exponentiation
(push)
(assert (= 2.0 (^ x 2.0)))
(check-sat) ; sat
(get-model)
; (model
; (define-fun x () Real
; (root-obj (+ (^ x 2) (- 2)) 1))
;)
(pop)
; to represent square root, etc., you may use fractional or decimal exponents
(push)
(assert (= 25.0 (^ x 0.5))) ; square root: 2 = sqrt(x)
(check-sat) ; sat
(get-model)
; maybe a bug or have to tune the model printer
;(model
; (define-fun x () Real
; (- 1.0))
;)
(pop)
(push)
(assert (= 2.0 (^ x (/ 1.0 3.0))))
(check-sat) ; sat
(get-model)
;(model
; (define-fun x () Real
; 8.0)
;)
(pop)
(push)
(assert (= 10.0 (^ x 0.2)))
(check-sat) ; sat
(get-model)
;(model
; (define-fun x () Real
; 100000.0)
;)
(pop)
Here is an old, but related post: z3/python reals
Some of the printing issues, e.g., if you need decimal approximations, can be fixed by using:
(set-option :pp.decimal true)
In Non-linear arithmetic and uninterpreted functions, Leonardo de Moura states that the qfnra-nlsat tactic hasn't been fully integrated with the rest of Z3 yet. I thought that the situation has changed in two years, but apparently the integration is still not very complete.
In the example below, I use datatypes purely for "software engineering" purposes: to organize my data into records. Even though there are no uninterpreted functions, Z3 still fails to give me a solution:
(declare-datatypes () (
(Point (point (point-x Real) (point-y Real)))
(Line (line (line-a Real) (line-b Real) (line-c Real)))))
(define-fun point-line-subst ((p Point) (l Line)) Real
(+ (* (line-a l) (point-x p)) (* (line-b l) (point-y p)) (line-c l)))
(declare-const p Point)
(declare-const l Line)
(assert (> (point-y p) 20.0))
(assert (= 0.0 (point-line-subst p l)))
(check-sat-using qfnra-nlsat)
(get-model)
> unknown
(model
)
However, if I manually inline all the functions, Z3 finds a model instantly:
(declare-const x Real)
(declare-const y Real)
(declare-const a Real)
(declare-const b Real)
(declare-const c Real)
(assert (> y 20.0))
(assert (= 0.0 (+ (* a x) (* b y) c)))
(check-sat-using qfnra-nlsat)
(get-model)
> sat
(model
(define-fun y () Real
21.0)
(define-fun a () Real
0.0)
(define-fun x () Real
0.0)
(define-fun b () Real
0.0)
(define-fun c () Real
0.0)
)
My question is, is there a way to perform such an inlining automatically? I'm fine with either one of these workflows:
Launch Z3 with a tactic that says "Inline first, then apply qfnra-nlsat. I haven't found a way to do so, but maybe I wasn't looking well enough.
Launch Z3 using some version of simplify to do the inlining. Launch Z3 the second time on the result of the first invocation (the inlined version).
In other words, how to make qfnra-nlsat work with tuples?
Thank you!
That's correct, the NLSAT solver is still not integrated with the other theories. At the moment, we can only use it if we eliminate all datatypes (or elements of other theories) before running it. I believe there is no useful existing tactic inside of Z3 at the moment though, so this would have to be done beforehand. In general it's not hard to compose tactics, e.g., like this:
(check-sat-using (and-then simplify qfnra-nlsat))
but the simplifier is not strong enough to eliminate the datatype constants in this problem. (The respective implementation files are datatype_rewriter.cpp and datatype_simplifier_plugin.cpp.)