How much nonlinearity could z3 handle in practice? - z3

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))))
)

Related

Z3 optimization Issue?

I wanted to find the maximum value of a variable under some simple constraints. But the result is not the optimum (max). Indeed, we can add another constraint and the solver still find another solution...
I also tried this example in python with the Optimize solver and maximize(r), but I get the same result. I also checked the upper bound (with the upper method) and I get the same erroneous result (4).
I'm not used to playing with the optimization feature of Z3, I generally only make proof; that's why I'm almost sure that the mistake is mine...
For now, I use a loop over the check-sat in python and iteratively add a constraint (r > result). It's working but it's neither elegant nor efficient...
; (set-logic QF_LIA)
(define-const x Int 9)
(define-const a Int 3)
(define-const b Int 4)
(define-const c Int 4)
(define-const d Int 5)
(declare-const i Int)
(declare-const j Int)
(declare-const t Int)
(declare-const r Int)
(assert (>= i 0))
(assert (>= j 0))
(assert (= t (+ (* i b) (* j d) 1)))
(assert (= r (+ (* i a) (* j c) c)))
(assert (<= t x))
(maximize r)
(check-sat)
;sat
(get-model)
;(model
; (define-fun i () Int
; 0)
; (define-fun j () Int
; 0)
; (define-fun r () Int
; 4)
; (define-fun t () Int
; 1)
;)
(get-value (r))
;((r 4))
(assert (> r 4))
(check-sat)
;sat
(get-model)
;(model
; (define-fun i () Int
; 2)
; (define-fun j () Int
; 0)
; (define-fun r () Int
; 10)
; (define-fun t () Int
; 9)
;)
$ z3 --version
Z3 version 4.8.7 - 64 bit
I cannot replicate this. When I run your program, it gives me r = 10, and if I then further assert (> r 10), then I get unsat.
However, I'm using z3 4.8.13, and I noticed that your z3 version is rather old, 4.8.7; which dates to late 2019. See if you can upgrade: https://github.com/Z3Prover/z3/releases
(The latest released version is 4.8.12; though you can also directly build from their GitHub sources, which will be tagged 4.8.13.)
Please report back if you still see the issue after upgrading.

Which nonlinear assert is complete in smt/z3 optimize?

I list some assert about Quadratic function:
(declare-fun H () Int)
(assert (>= H 8000))
(assert (<= H 12000))
(minimize (- (^ H 2) H))
(check-sat)
but the answer is "unknown" and the reason for unknown is (incomplete (theory arithmetic)); I can't understand which is the lost one
In general z3 cannot deal with non-linear terms. (A term is non-linear if you multiply two variables together. In your case, that'd be (^ H 2).
This is especially true of the optimization engine: Nonlinear constraints over integers is most likely going to be beyond reach. But you're in luck: Your formula is rather simple so it can handle it fine. Rewrite it using multiplication:
(declare-fun H () Int)
(assert (>= H 8000))
(assert (<= H 12000))
(minimize (- (* H H) H))
(check-sat)
(get-model)
This prints:
sat
(model
(define-fun H () Int
8000)
)

trying an example from rise4fun / z3 / tutorial / strategies

some example from the rise4fun-site:
(declare-const x Int)
(declare-const y Int)
(declare-const z Int)
(declare-const a Int) ; this is added
(assert (= a 3 )) ; this is added: a := 3
(assert (< 0 x 10)) ; rewritten, but same constraint
(assert (< 0 y 10))
(assert (< 0 z 10))
(assert (= (+ (* 3 y) (* 2 x)) z)) ; plain function from rise4fun
;(assert (= (+ (* a y) (* 2 x)) z)) ; here literal 3 is replaced by a
(check-sat-using (then (using-params simplify :arith-lhs true :som true)
normalize-bounds
lia2pb
pb2bv
bit-blast
sat))
(get-model)
(get-info :version)
when i comment the plain function from rise4fun and uncomment my function, the solver will fail to produce a result and respond with 'unknown' (tried with 4.8.0). Isn't the solver or some preprocessor smart enough to see that 'a' is just a constant with fixed value 3?
That's right, the simplify tactic is not smart enough to propagate values because it would be too expensive in general. However, ctx-simplify or propagate-values do the job. For instance:
(check-sat-using (then (using-params simplify :arith-lhs true :som true)
propagate-values
normalize-bounds
lia2pb
pb2bv
bit-blast
sat))

Z3 to show that if a^3=x*y*z then 3a <= x+y+z

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.

Can z3 always give result when handling nonlinear real arithmetic

I have a problem required to solve a set of nonlinear polynomial constraints. Can z3 always give a result (sat or unsat) when handling nonlinear real arithmetic.
Is the result also sound?
Yes, it is complete assuming (1) availability of resources, and (2) you only use real constraints so that the nlsat tactic is used, as the last I checked, it wasn't full integrated with the other solvers, see the below questions/answers for more details. Here's a simple example illustrating this (at least by default, rise4fun link: http://rise4fun.com/Z3/SRZ8 ):
(declare-fun x () Real)
(declare-fun y () Real)
(declare-fun z () Real)
(assert (>= (* 2 (^ x 2)) (* y z)))
(assert (> x 100))
(assert (< y 0))
(assert (< z 0))
(assert (> (^ y 2) 1234))
(assert (< (^ z 3) -25))
(check-sat) ; sat
(get-model)
(declare-fun b () Int)
(assert (> b x))
(check-sat) ; unknown
Z3 Theorem Prover: Pythagorean Theorem (Non-Linear Artithmetic)
mixing reals and bit-vectors
z3 produces unknown for assertions without quantifiers
z3 existential theory of the reals
Combining nonlinear Real with linear Int
Z3 support for nonlinear arithmetic
Encoding returns "unknown"
For the incremental question, it may be possible to use nlsat with incremental solving, but in this simple example applying a standard method (rise4fun link: http://rise4fun.com/Z3/Ce1F and see: Soft/Hard constraints in Z3 ) there is an unknown, although a model assignment is made, so it may be useful for your purposes. If not, you can try push/pop: Incremental solving in Z3 using push command
(set-option :produce-unsat-cores true)
(set-option :produce-models true)
(declare-const p1 Bool)
(declare-const p2 Bool)
(declare-const p3 Bool)
(declare-const p4 Bool)
(declare-const p5 Bool)
(declare-const p6 Bool)
(declare-const p7 Bool)
(declare-fun x () Real)
(declare-fun y () Real)
(declare-fun z () Real)
(assert (=> p1 (>= (* 2 (^ x 2)) (* y z))))
(assert (=> p2 (> x 100)))
(assert (=> p3 (< y 0)))
(assert (=> p4 (< z 0)))
(assert (=> p5 (> (^ y 2) 1234)))
(assert (=> p6 (< (^ z 3) -25)))
(assert (=> p7 (< x 50)))
(check-sat p1 p2 p3 p4 p5 p6 p7) ; unsat
(get-unsat-core) ; (p2 p7)
(check-sat p1 p2 p3 p4 p5 p6) ; unknown, removed one of the unsat core clauses
(get-model)
(declare-fun b () Int)
(assert (> b x))
(check-sat) ; unknown

Resources