Z3 Java API - get unsat core - z3

I am trying to figure out how to get the unsat core using the Java API for Z3. Our scenario is as follows (code is underneath, which works in rise4fun):
We create the SMT2 input programtically
The input contains function definitions, datatype declarations, and assertions
We parse this using the parseSMTLIB2String API
We ensure that the context and the solver have unsat_core -> true
Z3 returns UNSAT for the provided input, which is correct
The UNSAT core is always empty though.
The same input produces an UNSAT core correctly on rise4fun (x1 x3)
I am guessing I am misusing the API somehow... but not quite sure how/why.
I have noticed that I cannot set the unsat core option in the SMT string that I pass to parseSMTLIB2String, because that is not allowed. I am guessing that is expected.
Can someone point me in the right direction please?
Thanks!!
(set-option :smt.macro-finder true)
;; The following is only for rise4fun, i cannot get it
;; to work with the parse SMT Java API
(set-option :produce-unsat-cores true)
(define-sort Ref () Int)
(declare-datatypes (T1 T2) ((Tuple2 (mk-Tuple2 (_1 T1)(_2 T2)))))
(declare-datatypes (T1 T2 T3) ((Tuple3 (mk-Tuple3 (_1 T1)(_2 T2)(_3 T3)))))
(define-sort Set (T) (Array T Bool))
(define-sort Bag (T) (Array T Int))
(declare-const emptySetOf_Int (Set Int))
(assert (!(forall ((x Int)) (= (select emptySetOf_Int x) false)) :named AXIOM1))
(declare-sort TopLevelDeclarations) (declare-const mk-TopLevelDeclarations TopLevelDeclarations)
(declare-datatypes () ((A (mk-A (x Int)(y Int)))))
(declare-datatypes () ((Any
(lift-TopLevelDeclarations (sel-TopLevelDeclarations TopLevelDeclarations))
(lift-A (sel-A A))
null))
)
(declare-const heap (Array Ref Any))
(define-fun deref ((ref Ref)) Any
(select heap ref)
)
(define-fun deref-is-TopLevelDeclarations ((this Ref)) Bool
(is-lift-TopLevelDeclarations (deref this))
)
(define-fun deref-TopLevelDeclarations ((this Ref)) TopLevelDeclarations
(sel-TopLevelDeclarations (deref this))
)
(define-fun deref-is-A ((this Ref)) Bool
(is-lift-A (deref this))
)
(define-fun deref-A ((this Ref)) A
(sel-A (deref this))
)
(define-fun deref-isa-TopLevelDeclarations ((this Ref)) Bool
(deref-is-TopLevelDeclarations this)
)
(define-fun deref-isa-A ((this Ref)) Bool
(deref-is-A this)
)
(define-fun A!x ((this Ref)) Int
(x (deref-A this))
)
(define-fun A!y ((this Ref)) Int
(y (deref-A this))
)
(define-fun TopLevelDeclarations.inv ((this Ref)) Bool
true
)
(assert (! (forall ((this Ref))
(=> (deref-is-TopLevelDeclarations this) (TopLevelDeclarations.inv this))
) :named x0))
(define-fun A.inv ((this Ref)) Bool
(and
(> (A!x this) 0)
(> (A!y this) 0)
(< (A!x this) 0)
)
)
(assert (! (forall ((this Ref))
(=> (deref-is-A this) (A.inv this))
) :named x1))
(assert (!(deref-is-TopLevelDeclarations 0) :named TOP))
(assert (!(exists ((instanceOfA Ref)) (deref-is-A instanceOfA)) :named x3))
(check-sat)
(get-unsat-core)

You're not using the Java API, except for the call to parseSMTLIB2String. This function does not execute any SMT commands and there is no function that would do that for you. parseSMTLIB2String exists exclusively to parse assertions, it will ignore everything else. For this particular problem, I recommend to simply pass the problem file to z3.exe either as a command line argument or via stdin (use -in option). This produces
unsat
(x1 x3)
If the intent is to use the Java API for other things at a later point, see the Java API unsat core example.

I just had the same problem and found that it depends on how you pass the parsed input to the solver.
While the following approach produces an empty unsat-core...:
BoolExpr[] program = context.parseSMTLIB2File(input_file, null, null, null, null);
solver.add(program);
solver.check();
solver.getUnsatCore();
... the unsat-core is produced correctly if you give the parsed input file to the solver as follows:
BoolExpr[] program = context.parseSMTLIB2File(input_file, null, null, null, null);
solver.check(program);
solver.getUnsatCore();
I therefore assume that everything that is passed via solver.add() belongs to the assumptions and therefore presumably does not belong to the unsat-core according to Z3.

Related

Possible Z3 bug with pattens/triggers

I tried running Z3 on the following smt2 file
(set-option :print-success false)
(set-info :smt-lib-version 2.6)
(set-option :smt.AUTO_CONFIG false)
(set-option :smt.PHASE_SELECTION 0)
(set-option :smt.RESTART_STRATEGY 0)
(set-option :smt.RESTART_FACTOR 1.5)
(set-option :smt.ARITH.RANDOM_INITIAL_VALUE true)
(set-option :smt.CASE_SPLIT 3)
(set-option :smt.DELAY_UNITS true)
(set-option :NNF.SK_HACK true)
(set-option :smt.MBQI false)
(set-option :smt.QI.EAGER_THRESHOLD 100)
(set-option :smt.BV.REFLECT true)
(set-option :smt.qi.max_multi_patterns 1000)
(set-option :smt.mbqi false)
(set-option :model.compact false)
(set-option :model.v2 true)
(set-option :pp.bv_literals false)
; done setting options
(declare-sort Ref 0)
(declare-sort Field 0)
(declare-sort Mask 0)
(declare-fun select_mask (Mask Ref Field) Real)
(declare-fun zero_mask () Mask)
(declare-sort Heap 0)
(declare-fun length (Heap Ref) Int)
(declare-fun length* (Heap Ref) Int)
(declare-fun select_heap (Heap Ref Field) Ref)
(declare-fun next () Field)
(declare-fun null () Ref)
(declare-fun this () Ref)
(declare-fun mask () Mask)
(declare-fun store_mask (Mask Ref Field Real) Mask)
(assert (forall ( ( ?x0 Mask) ( ?x1 Ref) ( ?x2 Field) ( ?x3 Real)) (! (= (select_mask (store_mask ?x0 ?x1 ?x2 ?x3) ?x1 ?x2) ?x3) :weight 0)))
(assert (forall ( ( ?x0 Mask) ( ?x1 Ref) ( ?y1 Ref) ( ?x2 Field) ( ?y2 Field) ( ?x3 Real)) (! (=> (or (not (= ?x1 ?y1)) (not (= ?x2 ?y2))) (= (select_mask (store_mask ?x0 ?x1 ?x2 ?x3) ?y1 ?y2) (select_mask ?x0 ?y1 ?y2))) :weight 0)))
(assert (forall ((o_2 Ref) (f_4 Field) ) (! (= (select_mask zero_mask o_2 f_4) 0.0)
:pattern ( (select_mask zero_mask o_2 f_4))
)))
(assert (forall ((heap Heap) (this Ref) ) (! (= (length heap this) (length* heap this))
:pattern ( (length heap this))
)))
(assert (forall ((heap Heap) (this Ref) ) (! (= (length heap this) (ite (= (select_heap heap this next) null) 1 (+ 1 (length* heap (select_heap heap this next)))))
:pattern ( (length heap this))
)))
(assert (not (= this null)))
(assert (= mask (store_mask zero_mask this next 1.0)))
(declare-fun heap () Heap)
(declare-fun valid-next () Field)
(push 1)
(set-info :boogie-vc-id test2)
(set-option :timeout 0)
(set-option :rlimit 0)
(assert
(or (<= (select_mask mask this next) 0.0)
(and (= (select_heap heap this next) this)
(or (> 1.0 (select_mask zero_mask null valid-next))
(and (<= 1.0 (select_mask zero_mask null valid-next))
(>= (length heap this) (length heap (select_heap heap this next))))))))
(check-sat)
(pop 1)
Of the Z3 versions I tried, 4.8.6 - 4.8.9 returned unknown but 4.8.10 - 4.9.1 returned unsat. The unsat result seems to come from triggering the length axioms, but it seems like if disjuncts were looked at in order, Z3 should find a partial model where (= (select_heap heap this next) this) and (> 1.0 (select_mask zero_mask null valid-next)) without triggering the length axioms and return unknown. Is this a bug in Z3, or does Z3 not provide gaurentees about the order disjuncts are looked at.
I also tried removing the push and pop lines which caused all the versions of Z3 I tried to return unsat.
After trimming z3 specific settings, Both CVC4 and CVC5 also return unsat for this query. Note that unknown isn't incompatible with unsat: It's perfectly OK for the solver to now return unsat for something it previously said unknown. (Or vice-versa.)
Given CVC4/CVC4 and z3 all agree on unsat, the way to debug this would be:
See if you can get an unsat core, and if that makes sense
Assert extra conditions that tie the model to what it should be according to your expectations. Hopefully doing that will show you why it is unsatisfiable.
If you need more help from this community, you'll have to specify exactly what model you'd consider would satisfy this formula, and debug it first to remove as much of the problem as you possibly can. Best of luck!

Z3 Checking whether all values in array are unique

So I'm trying to check whether all values in an array is unique with the following Z3 code.
(declare-const A (Array Int Int))
(declare-const n Int)
(assert (forall ((i Int) (j Int)) (and (and (and (>= i 0) (< i n)) (and (>= j 0) (< j n)))
(implies (= (select A i) (select A j)) (= i j)))))
(check-sat)
I'm quite new to Z3 so I don't quite understand the grammar and stuff, but can anyone tell me whether this code is right, and if not, where's the problem?
The problem as you wrote is unsat, because it says whenever 0 <= i < n and 0 <= j < n, if A[i] = A[j], then i = j. There is no array and a particular n you can pick to satisfy this constraint.
What you really want to write is the following instead:
(declare-const A (Array Int Int))
(declare-const n Int)
(assert (forall ((i Int) (j Int)) (implies (and (>= i 0) (< i n)
(>= j 0) (< j n)
(= (select A i) (select A j)))
(= i j))))
(check-sat)
(get-model)
The above says If it's the case that i and j are within bounds, and array elements are the same, then i must equal j. And this variant would be satisifiable for any n; and indeed here's what z3 reports:
sat
(
(define-fun n () Int
0)
(define-fun A () (Array Int Int)
((as const (Array Int Int)) 0))
)
But note that z3 simply picked n = 0, which made it easy to satisfy the formula. Let's make sure we get a more interesting model, by adding:
(assert (> n 2))
Now we get:
sat
(
(define-fun n () Int
3)
(define-fun A () (Array Int Int)
(lambda ((x!1 Int))
(let ((a!1 (ite (and (<= 1 x!1) (not (<= 2 x!1))) 7 8)))
(ite (<= 1 x!1) (ite (and (<= 1 x!1) (<= 2 x!1)) 6 a!1) 5))))
)
and we see that z3 picked the array to have 3 elements with distinct values at positions we care about.
Note that this sort of reasoning with quantifiers is a soft-spot for SMT solvers; while z3 is able to find models for these cases, if you keep adding quantified axioms you'll likely get unknown as the answer, or z3 (or any other SMT solver for that matter) will take longer and longer time to respond.

Is it possible to define a function with an all quantified assertion in z3 (with SMT-LIB2 interface)?

My goal is to define a function, which takes an input integer sequence and outputs an integer sequence with the same length, but containing only the first element of the input sequence. For example (in pseudo-code):
f([7,5,6]) = [7,7,7]
For this I declare a function in z3 as:
(declare-fun f ((Seq Int)) (Seq Int))
and try to force the expected behavior with the assertion:
(assert
(forall ((arr (Seq Int)))
(and
(=
(seq.len arr)
(seq.len (f arr))
)
(forall ((i Int))
(implies
(and
(>= i 0)
(< i (seq.len arr))
)
(=
(seq.at arr 0)
(seq.at (f arr) i)
)
)
)
)
))
The problem is that the program does not terminate, which I suspect is caused by the all-quantifier. To test whether my conditions are correct I declared two constants and saw that for concrete values the conditions are correct:
(define-const first (Seq Int)
(seq.++ (seq.unit 1) (seq.unit 2))
)
(declare-const second (Seq Int))
(assert
(and
(=
(seq.len first)
(seq.len second)
)
(forall ((i Int))
(implies
(and
(>= i 0)
(< i (seq.len first))
)
(=
(seq.at first 0)
(seq.at second i)
)
)
)
)
)
(check-sat)
(get-model)
My question: How would it be possible to integrate the conditions in the assertions with the expected behavior of the f function? The function should be total, which means it should be defined for all possible input sequences, but this leads me to think that an all quantifier is definitely needed in my case.
Reasoning with such recursive data-types/values is not a strong suit for SMT solvers. Most problems will require induction and SMT-solvers don't do induction out-of-the box.
Having said that, you can code what you want using the new declare-fun-rec construct:
(define-fun-rec copyHeadAux ((x (Seq Int)) (l (Seq Int))) (Seq Int)
(ite (= 0 (seq.len l))
(as seq.empty (Seq Int))
(seq.++ x (copyHeadAux x (seq.extract l 1 (seq.len l))))))
(define-fun copyHead ((l (Seq Int))) (Seq Int)
(ite (= 0 (seq.len l))
(as seq.empty (Seq Int))
(copyHeadAux (seq.at l 0) l)))
(define-fun test () (Seq Int) (seq.++ (seq.unit 7) (seq.unit 5) (seq.unit 6)))
(declare-const out (Seq Int))
(assert (= out (copyHead test)))
(check-sat)
(get-model)
When I run this, I get:
sat
(
(define-fun out () (Seq Int)
(seq.++ (seq.unit 7) (seq.unit 7) (seq.unit 7)))
(define-fun test () (Seq Int)
(seq.++ (seq.unit 7) (seq.unit 5) (seq.unit 6)))
(define-fun copyHead ((x!0 (Seq Int))) (Seq Int)
(ite (= 0 (seq.len x!0))
(as seq.empty (Seq Int))
(copyHeadAux (seq.at x!0 0) x!0)))
)
which is the correct answer you're looking for. But unless your constraints only involve "constant-folding" cases (i.e., where copyHead is always applied to a constant known value), you're likely to get unknown as the answer, or have the solver go into an infinite e-matching loop.
It's best to use a proper theorem prover (Isabelle, HOL, Lean, ACL2 etc.) for reasoning with these sorts of recursive definitions. Of course, SMT solvers get better over time and maybe one day they'll be able to handle more problems like this out-of-the-box, but I wouldn't hold my breath.

Guiding z3's proof search

I'm trying to get z3 to work (most of the time) for very simple non-linear integer arithmetic problems. Unfortunately, I've hit a bit of a wall with exponentiation. I want to be able handle problems like x^{a+b+2} = (x * x * x^{a} * x{b}). I only need to handle non-negative exponents.
I tried redefining exponentiation as a recursive function (so that it's just allowed to return 1 for any non-positive exponent) and using a pattern to facilitate z3 inferring that x^{a+b} = x^{a} * x^{b}, but it doesn't seem to work - I'm still timing out.
(define-fun-rec pow ((x!1 Int) (x!2 Int)) Int
(if (<= x!2 0) 1 (* x!1 (pow x!1 (- x!2 1)))))
; split +
(assert (forall ((a Int) (b Int) (c Int))
(! (=>
(and (>= b 0) (>= c 0))
(= (pow a (+ b c)) (* (pow a c) (pow a b))))
:pattern ((pow a (+ b c))))))
; small cases
(assert (forall ((a Int)) (= 1 (pow a 0))))
(assert (forall ((a Int)) (= a (pow a 1))))
(assert (forall ((a Int)) (= (* a a) (pow a 2))))
(assert (forall ((a Int)) (= (* a a a) (pow a 3))))
; Our problem
(declare-const x Int)
(declare-const i Int)
(assert (>= i 0))
; This should be provably unsat, by splitting and the small case for 2
(assert (not (= (* (* x x) (pow x i)) (pow x (+ i 2)))))
(check-sat) ;times out
Am I using patterns incorrectly, is there a way to give stronger hints to the proof search, or an easier way to do achieve what I want?
Pattern (also called triggers) may only contain uninterpreted functions. Since + is an interpreted function, you essentially provide an invalid pattern, in which case virtually anything can happen.
As a first step, I disabled Z3's auto-configuration feature and also MBQI-based quantifier instantiation:
(set-option :auto_config false)
(set-option :smt.mbqi false)
Next, I introduced an uninterpreted plus function and replaced each application of + by plus. That sufficed to make your assertion verify (i.e. yield unsat). You can of course also axiomatise plus in terms of +, i.e.
(declare-fun plus (Int Int) Int)
(assert (forall ((a Int) (b Int))
(! (= (plus a b) (+ a b))
:pattern ((plus a b)))))
but your assertion already verifies without the definitional axioms for plus.

Defining functions on enumeration types in Z3

I have an enumeration type BoolT that contains Bool and Bot
(declare-datatypes () ((BoolT Bool Bot)))
and I want to define an equality function eq that given two BoolT returns Bot if one of the arguments is Bot, otherwise the equality between the two Bool arguments. However, I am not able to define the actual comparison between the boolean values. Until now I get the function
(define-fun eq ((x1 BoolT) (x2 BoolT)) BoolT
(ite (or (= x1 Bot) (= x2 Bot)) Bot Bool))
while I need something like
(define-fun eq ((x1 BoolT) (x2 BoolT)) BoolT
(ite (or (= x1 Bot) (= x2 Bot)) Bot
(or (and (= x1 true)(= x2 true)) (and (= x1 false)(= x2 false)))
)
or at least a correct definition of the following predicate
(define-fun is-True ((x1 BoolT)) Bool
(ite (= x1 true) true false)
)
Is there a way to model the eq function or the previous predicate on BoolT?
You will need tagged unions in Z3, similar to ML data-types. You can't just take the union of an existing type and included it in a datatype declaration.
So you will need to write something like:
(declare-datatypes () ((BoolT True False Bot)))
or
(declare-datatypes () ((BoolT (mkB (tf B)) Bot) (B True False)))
Then you can write:
(define-fun is-True1 ((x BoolT)) Bool
(= (mkB True) x))
or
(define-fun is-True2 ((x BoolT)) Bool
(and (is-mkB x) (= True (tf x))))
and assert
(declare-const a BoolT)
(assert (is-True2 a))
Declaring (B True False)
automatically declares predicates is-True and is-False
(declare-const b B)
(assert (is-True b))

Resources