Unsatisfiable Cores in Z3 Python - z3

I am working with the Python API of Z3 in an attempt to include support for it in a research tool that I am writing. I have a question regarding extracting the unsatisfiable core using the Python interface.
I have the following simple query:
(set-option :produce-unsat-cores true)
(assert (! (not (= (_ bv0 32) (_ bv0 32))) :named __constraint0))
(check-sat)
(get-unsat-core)
(exit)
Running this query through the z3 executable (for Z3 4.1), I receive the expected result:
unsat
(__constraint0)
For Z3 4.3, I obtain a segmentation fault:
unsat
Segmentation fault
That isn't the main question, although that was an intriguing observation. I then modified the query (inside a file) as
(assert (! (not (= (_ bv0 32) (_ bv0 32))) :named __constraint0))
(exit)
Using a file handler, I passed the contents of this file (in a variable `queryStr') to the following Python code:
import z3
...
solver = z3.Solver()
solver.reset()
solver.add(z3.parse_smt2_string(queryStr))
querySatResult = solver.check()
if querySatResult == z3.sat:
...
elif querySatResult == z3.unsat:
print solver.unsat_core()
I receive the empty list from the `unsat_core' function: []. Am I using this function incorrectly? The docstring for the function suggests that I should instead be doing something similar to
solver.add(z3.Implies(p1, z3.Not(0 == 0)))
However, I was wondering if it were still possible to use the query as is, since it conforms to SMT-LIB v2.0 standards (I believe), and whether I was missing something obvious.

The crash you observed has been fixed, and the fix will be available in the next release. If you try the "unstable" (work-in-progress) branch, you should get the expected behavior.
You can retrieve the unstable branch using
git clone https://git01.codeplex.com/z3 -b unstable
The API parse_smt2_string provides only basic support for parsing formulas in SMT 2.0 format. It does not keep the annotations :named. We will address this and other limitations in future versions. In the meantime, we should use "answer literals" such as p1 and assertions of the form:
solver.add(z3.Implies(p1, z3.Not(0 == 0)))
In the "unstable" branch, we also support the following new API. It "simulates" the :named assertions used in the SMT 2.0 standard.
def assert_and_track(self, a, p):
"""Assert constraint `a` and track it in the unsat core using the Boolean constant `p`.
If `p` is a string, it will be automatically converted into a Boolean constant.
>>> x = Int('x')
>>> p3 = Bool('p3')
>>> s = Solver()
>>> s.set(unsat_core=True)
>>> s.assert_and_track(x > 0, 'p1')
>>> s.assert_and_track(x != 1, 'p2')
>>> s.assert_and_track(x < 0, p3)
>>> print(s.check())
unsat
>>> c = s.unsat_core()
>>> len(c)
2
>>> Bool('p1') in c
True
>>> Bool('p2') in c
False
>>> p3 in c
True
"""
...

Related

Z3 v4.1 does not accept negative integers as input

I have installed Z3 version 4.1 and I attempt to use it programmatically in a java application. My application is communicating with the Z3 via ProcessBuilder. The version of Z3 is verified as 4.1 by using the /version command line argument.
However, Z3 does not accept negative constants as part of expressions. When I attempt to provide a negative integers I get the following message:
(error "line 4 column 31: unknown constant -1")
This is the input I provide to Z3:
(push)
(declare-fun y () Int )
(define-fun x () Int y )
(assert (and (<= y 1000) (>= y -1) ) )
(assert (= x 42) )
(check-sat)
(pop)
I am using the following arguments to instantiate the Z3:
Z3 /smt2 /in /t:2
Any help is appreciated. Thank you in advance.
Try (- 1). See bottom of page 38 in http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2017-07-18.pdf

Using define-fun-rec in SMT

I'm currently trying to write an SMT script using define-fun-rec. I've tested with both Z3, version 4.4.2, and CVC4, version 1.4. As far as I can tell, these are the most recent versions of both, and both support the feature*. However, both do not seem to recognize the command.
(I made some changes to this based on Nikolaj's reply. It still gives the error messages.) Specifically, given:
(define-fun-rec
fac ((x Int)) Int
(
ite (<= x 1)
1
(* x (fac (- x 1)))
)
)
(assert (= (fac 4) 24))
(check-sat)
Z3 outputs:
unsupported
; define-fun-rec
(error "line 10 column 17: unknown function/constant fac")
sat
And CVC4 outputs:
(error "Parse Error: fac.smt2:1.15: expected SMT-LIBv2 command, got `define-fun-rec'.
(define-fun-rec
^
")
My best guess is that there is some sort of flag I need to set or I need to be using some specific logic, but I've had a lot of trouble finding any sort of detailed instructions or examples with define-fun-rec. Any advice would be appreciated. Thanks!
*Z3 has support: How to deal with recursive function in Z3?
CVC4 has support: http://lara.epfl.ch/~reynolds/pres-smt15.pdf
The latest version of CVC4 can be downloaded under "Development versions" (on the right hand side) of:
http://cvc4.cs.nyu.edu/downloads/
The latest development version has support for recursive function definitions. You can use the cvc4 command line option "--fmf-fun" to enable a technique that finds small models for problems involving recursive function applications, assuming definitions are admissible.
(Although, unfortunately your example with factorial also requires non-linear arithmetic, which CVC4 does not yet support.)
Don't set the logic to LIA. This is not in the LIA fragment and Z3 will use the wrong tactic to solve the problem.Just remove the set-logic line.
It helps to not use an undefined function "f" inside the definition of "fib".
I would suggest that you call the function "fac" and not "fib" since you are defining a factorial function.
Thus,
(define-fun-rec
fac ((x Int)) Int
(
ite (<= x 1)
1
(* x (fac (- x 1)))
)
)
(assert (= (fac 4) 24))
(check-sat)
z3 -version
Z3 version 4.4.2
z3 fac.smt2
sat
If you change 24 to 25 you get unsat.

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

Dynamically call get-value only when check-sat returns "sat"

The SMT2 standard states that calling get-value is only legal after a call to check-sat and only when check-sat returns "sat" or "unknown".
Here is a simple example of an unsat problem:
(set-option :produce-models true)
(set-logic QF_BV)
(set-info :smt-lib-version 2.0)
(declare-fun a ()(_ BitVec 4))
(declare-fun b ()(_ BitVec 4))
(declare-fun c ()(_ BitVec 4))
(declare-fun z ()(_ BitVec 4))
(assert (= #b1111 z))
(assert (= a b))
(assert (= (bvxor a z) c))
(assert (= b c))
(check-sat)
(get-value ( a ))
(get-value ( b ))
(get-value ( c ))
Since the problem is unsat, the get-value commands are illegal. Take out any one assert and it becomes sat and the get-value commands become legal. So my question is, how do you write a SMT2 script that checks the return value of check-sat and only calls get-value if it returned sat?
Illegally calling get-value is an issue for me as I am running different smt solvers in a flow and checking the program's return value and then parsing their output. CVC4 change's its return value to an error state if get-value is called illegally.
I don't think there's a good way, if what you want is to have one "SMT" file to rule the whole transaction.
This issue comes up often in interacting with SMT-solvers from other languages. The solution I adopted is that I keep an open pipe with the solver and feed it the lines of the script, read the responses, and decide on what to send next based on the responses I get. Essentially programmed interaction. (This is what the Haskell SBV library does, for instance.)
However, I do agree that this is a pain; and it would be nice if there was an SMT2-lib sanctioned way of handling such common interaction.
For CVC4 being run from the command line, add the flag
--dump-models output models after every SAT/INVALID/UNKNOWN
response [*]
This is not as specific as get-value. This option is non-standard and CVC4 currently does not support setting this flag from the SMT2 parser. (Let us know if you would like this to be supported.)

Z3Py: randomized results (phase-selection) not random?

I tried to use bit vectors to get randomized results in model values like suggested by de Moura here but then with Z3Py instead of SMTLIB. I translated his example to:
from z3 import *
s = Solver()
x = BitVec('x', 16)
set_option('auto_config', False)
set_option('smt.phase_selection',5)
s.add(ULT(x,100))
s.check()
s.model()
s.check()
s.model()
However, the result seems to always be the same, i.e.
- repetitive checking with s.check() does not alter the result.
- even after a restart of the python interactive shell the result of the execution will be the same
Adding a change of the random seed did not alter the results: set_option('smt.random_seed', 123)
Does anyone have an idea why is not working as desired?
Thanks in advance!
Carsten
This case is simply too simple. It's essentially solved by the preprocessor and never gets to a point where it needs to select a phase, so random phase selection has no effect. Leo's answer to the cited post is now a little bit out of date and Z3 has changed, so it doesn't immediately replicate using the latest unstable version because Z3 chooses to use a different solver. We can still get the random behavior if we force it to use the incremental solver by adding a (push) command though; here's an updated example that is seed dependent:
(set-option :auto_config false)
(set-option :smt.phase_selection 5)
(set-option :smt.random_seed 456)
(declare-const x (_ BitVec 16))
(assert (bvult x (_ bv100 16)))
(push)
(check-sat)
(get-model)
;; try again to get a different model
(check-sat)
(get-model)
;; try again to get a different model
(check-sat)
(get-model)

Resources