Z3 randomness of generated model values - z3

I'm trying to influence the randomness of results for model values generated by Z3. As far as I understand, the options for this are very limited: in case of linear arithmetic, the simplex solver does not allow for random results that still satisfy the given constraints. However, there is an option smt.arith.random_initial_value ("use random initial values in the simplex-based procedure for linear arithmetic (default: false)") which I don't seem to get working:
from z3 import *
set_option('smt.arith.random_initial_value',True)
x = Int('x')
y = Int('y')
s = Solver()
s.add( x+y > 0)
s.check()
s.model()
This seems to always produce [y = 0, x = 1] as a result. Even model completion for variables unused in the given constraints seems to produce deterministic results all the time.
Any ideas or hints about how this option works?

Thanks for catching that! There was indeed a bug that caused the random seed not to be passed through to the arithmetic theory. This is now fixed in the unstable branch (fix here).
This example:
(set-option :smt.arith.random_initial_value true)
(declare-const x Int)
(declare-const y Int)
(assert (> (+ x y) 0))
(check-sat-using (using-params qflra :random_seed 1))
(get-model)
(check-sat-using (using-params qflra :random_seed 2))
(get-model)
(check-sat-using (using-params qflra :random_seed 3))
(get-model)
Now produces three different models:
sat
model
(define-fun y () Int
4294966763)
(define-fun x () Int
4294966337)
)
sat
(model
(define-fun y () Int
216)
(define-fun x () Int
4294966341)
)
sat
(model
(define-fun y () Int
196)
(define-fun x () Int
4294966344)
)
It looks like there may be another place where this option isn't passed through correctly (e.g., when using set-logic instead of calling the qflra tactic directly), we're still looking into that.

Related

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

Converting Z3 QBF formula directly to pcnf

I'm using Z3 theorem prover (using Z3Py: the Z3 API in Python) to create QBF (Quantified Boolean formula).
Is there any way in Z3 to directly convert your qbf formula into Prenex normal form ?
I don't think there's a tactic to convert to Prenex, but you can surely apply the quantifier-elimination tactic and further process your formulas. Note that the transformed formulas will not really look like the originals, as they are mechanically generated.
Here's an example:
from z3 import *
f = Function('f', IntSort(), IntSort(), IntSort())
x, y = Ints('x y')
p = ForAll(x, Or(x == 2, Exists(y, f (x, y) == 0)))
print Tactic('qe')(p)
Here qe is the quantifier elimination tactic. This produces:
[[Not(Exists(x!0,
Not(Or(x!0 == 2,
Exists(x!1,
And(f(x!0, x!1) <= 0,
f(x!0, x!1) >= 0))))))]]
For a nice tutorial on tactics, see here: http://ericpony.github.io/z3py-tutorial/strategies-examples.htm
You could use the skolemize tactic (snf) which will by definition be in prenex form. However it will also eliminate existential quantifiers which is not what you want. Here's an example.
(declare-fun a (Int) Bool)
(declare-fun b (Int) Bool)
(declare-fun c (Int) Bool)
(assert
(forall ((x Int))
(or
(exists ((y Int))
(a y)
)
(exists ((z Int))
(=>
(b z)
(c x)
)
)
)
)
)
(apply
(and-then
; mode (symbol) NNF translation mode: skolem (skolem normal form), quantifiers (skolem normal form + quantifiers in NNF), full (default: skolem)
(using-params snf :mode skolem)
)
:print_benchmark true
:print false
)
When Z3 is given the above it will responds with something like
(declare-fun c (Int) Bool)
(declare-fun b (Int) Bool)
(declare-fun a (Int) Bool)
(assert (forall ((x Int))
(or (exists ((y Int)) (a y)) (exists ((z Int)) (=> (b z) (c x))))))
(check-sat)
You can see the available tactics by running
echo "(help-tactic)" | ./z3 -in | less
from a bash shell.
Unfortunately I can't see one that states it does conversion to prenex.

How much nonlinearity could z3 handle in practice?

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

Distinct in z3 SMT and python

My question is that Does "Distinct" works in z3 python?. I've compared the following code and it seem not giving the same results:
(declare-const x Int)
(declare-const y Int)
(assert (distinct x y))
(check-sat)
(get-model)
The result was:
sat
(model
(define-fun y () Int
0)
(define-fun x () Int
1)
)
I've added negative assertion just to test and the result was unsat which is correct:
(assert (= x y))
unsat
Z3(6, 10): ERROR: model is not available
But when I use z3 in python it give me always sat as follows:
x = Int('x')
y = Int('y')
Distinct(x, y)
s = Solver
s = Solver()
s.check()
when I add the following assertion It should give me unsat but It returns sat:
s.add(x == y)
[y = 0, x = 0]
Is this means that I used wrong syntax ?
The `Distinct' function only creates a term, it doesn't add itself to the solver. Here's an example that works for me:
x = Int('x')
y = Int('y')
d = Distinct(x, y)
s = Solver()
s.add(d) # SAT without this one, UNSAT with
s.add(x == y)
print s
print s.check()

Skolemization in Z3

I am trying to remove existential quantifiers in my theory using Skolemization. This means that I replace existential quantifiers with functions that are parameterized by the universally quantified variables in the scope of the existential quantifiers.
Here I found an explanation how to do this in Z3, but I am still having troubles doing it. Suppose the following two functions:
(define-fun f1 ((t Int)) Bool (= t 3))
(define-fun f2 () Bool (exists ((t Int)) (f1 t)))
I believe that f2 should be true, because there exists an integer t such that (f1 t) is true, namely t=3. I apply Skolemization by introducing a constant for the existentially quantified formula:
(define-const c Int)
Then the formula with the existential quantifier is rewritten to:
(define-fun f2 () Bool (f1 c))
This does not work, that is, the constant c does not have the value 3. I suspect it is because we have not given an interpretation to the constant c, because if we add (assert (= c 3)) it works fine, but this takes away the whole idea of the existential quantifier. Is there a way in which I give a less explicit interpretation to c so that this will work?
So, I think you have it about right actually, here's the script I used with automatic (via Z3's SNF tactic) and manual (via adding the constant c) skolemization, which gave the value 3 in the model for the skolem constant as expected (smt-lib script: http://rise4fun.com/Z3/YJy2 ):
(define-fun f1 ((t Int)) Bool (= t 3))
(define-fun f2 () Bool (exists ((t Int)) (f1 t)))
(declare-const c Int)
(define-fun f2a () Bool (f1 c))
(push)
(assert f2)
(check-sat) ; sat
(get-model) ; model gives t!0 = 3 (automatic skolemization in Z3)
(pop)
(push)
(assert f2a)
(check-sat) ; sat
(get-model) ; model gives c = 3 after manual skolemization
(pop)
Also, note that Z3 has a Skolem normal form (SNF) conversion tactic built in, and here's an example in z3py (link to script: http://rise4fun.com/Z3Py/ZY2D ):
s = Solver()
f1 = Function('f1', IntSort(), BoolSort())
t = Int('t')
f2 = Exists(t, f1(t))
f1p = ForAll(t, f1(t) == (t == 3)) # expanded define-fun macro (define-fun f1 ((t Int)) Bool (= t 3))
s.add(f1p)
s.add(f2)
print f1p
print f2
print s.check()
print s.model() # model has skolem constant = 3
g = Goal()
g.add(f1p)
g.add(f2)
t = Tactic('snf') # use tactic to convert to SNF
res = t(g)
print res.as_expr()
s = Solver()
s.add( res.as_expr() )
print s.check()
print s.model() # model has skolem constant = 3

Resources