z3 datatype matching without a quantifier - z3

Say I make a datatype A in z3:
(declare-datatypes () ((A (b (bx Int)) (c (cx Int)))))
Now, I can declare a variable t, and then, say, assert that t is a c type:
(declare-fun t () A)
(assert (exists ((x Int)) (= t (c x))))
However, this requires an existential quantifier. My question is: is it possible to do this without a quantifier?
Specifically, I'd like an expression, like is_c t or something, which is equivalent to (exists ((x Int)) (= t (c x))).
I had expected this to be straightforward, since in most functional programming languages with sum types, there's an elimination form for them, usually pattern matching, like match t of b x => false; c x => true. But I haven't been able to find anything of this nature in the z3 documentation. Is there something I'm missing?

You automatically get a tester, as an indexed identifier: (_ is c) for each constructor c.
See Section 4.2.3 of http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2017-07-18.pdf. The relevant part is on page 61 (the second paragraph):
On successfully executing this command, for each constructor c in a
declared datatype δ, the solver will also automatically declare a
tester with rank δ Bool. The tester’s name is an indexed identifier
(see Section 3.3) of the form (_ is c).

Related

Modeling a small programming language and analysis in SMT-LIB using datatypes and forall

I am trying to model a small programming language in SMT-LIB 2.
My intent is to express some program analysis problems and solve them with Z3.
I think I am misunderstanding the forall statement though.
Here is a snippet of my code.
; barriers.smt2
(declare-datatype Barrier ((barrier (proc Int) (rank Int) (group Int) (complete-time Int))))
; barriers in the same group complete at the same time
(assert
(forall ((b1 Barrier) (b2 Barrier))
(=> (= (group b1) (group b2))
(= (complete-time b1) (complete-time b2)))))
(check-sat)
When I run z3 -smt2 barriers.smt2 I get unsat as the result.
I am thinking that an instance of my analysis problem would be a series of forall assertions like the above and a series of const declarations with assertions that describe the input program.
(declare-const b00 Barrier)
(assert (= (proc b00) 0))
(assert (= (rank b00) 0))
...
But apparently I am using the forall expression incorrectly because I expected z3 to decide that there was a satisfying model for that assertion. What am I missing?
When you declare a datatype like this:
(declare-datatype Barrier
((barrier (proc Int)
(rank Int)
(group Int)
(complete-time Int))))
you are generating a universe that is "freely" generated. That's just a fancy word for saying there is a value for Barrier for each possible element in the cartesian product Int x Int x Int x Int.
Later on, when you say:
(assert
(forall ((b1 Barrier) (b2 Barrier))
(=> (= (group b1) (group b2))
(= (complete-time b1) (complete-time b2)))))
you are making an assertion about all possible values of b1 and b2, and you are saying that if groups are the same then completion times must be the same. But remember that datatypes are freely generated so z3 tells you unsat, meaning that your assertion is clearly violated by picking up proper values of b1 and b2 from that cartesian product, which have plenty of inhabitant pairs that violate this assertion.
What you were trying to say, of course, was: "I just want you to pay attention to those elements that satisfy this property. I don't care about the others." But that's not what you said. To do so, simply turn your assertion to a function:
(define-fun groupCompletesTogether ((b1 Barrier) (b2 Barrier)) Bool
(=> (= (group b1) (group b2))
(= (complete-time b1) (complete-time b2))))
then, use it as the hypothesis of your implications. Here's a silly example:
(declare-const b00 Barrier)
(declare-const b01 Barrier)
(assert (=> (groupCompletesTogether b00 b01)
(> (rank b00) (rank b01))))
(check-sat)
(get-model)
This prints:
sat
(model
(define-fun b01 () Barrier
(barrier 3 0 2437 1797))
(define-fun b00 () Barrier
(barrier 2 1 1236 1796))
)
This isn't a particularly interesting model, but it is correct nonetheless. I hope this explains the issue and sets you on the right path to model. You can use that predicate in conjunction with other facts as well, and I suspect in a sat scenario, that's really what you want. So, you can say:
(assert (distinct b00 b01))
(assert (and (= (group b00) (group b01))
(groupCompletesTogether b00 b01)
(> (rank b00) (rank b01))))
and you'd get the following model:
sat
(model
(define-fun b01 () Barrier
(barrier 3 2436 0 1236))
(define-fun b00 () Barrier
(barrier 2 2437 0 1236))
)
which is now getting more interesting!
In general, while SMTLib does support quantifiers, you should try to stay away from them as much as possible as it renders the logic semi-decidable. And in general, you only want to write quantified axioms like you did for uninterpreted constants. (That is, introduce a new function/constant, let it go uninterpreted, but do assert a universally quantified axiom that it should satisfy.) This can let you model a bunch of interesting functions, though quantifiers can make the solver respond unknown, so they are best avoided if you can.
[Side note: As a rule of thumb, When you write a quantified axiom over a freely-generated datatype (like your Barrier), it'll either be trivially true or will never be satisfied because the universe literally will contain everything that can be constructed in that way. Think of it like a datatype in Haskell/ML etc.; where it's nothing but a container of all possible values.]
For what it is worth I was able to move forward by using sorts and uninterpreted functions instead of data types.
(declare-sort Barrier 0)
(declare-fun proc (Barrier) Int)
(declare-fun rank (Barrier) Int)
(declare-fun group (Barrier) Int)
(declare-fun complete-time (Barrier) Int)
Then the forall assertion is sat. I would still appreciate an explanation of why this change made a difference.

z3 "more than" totally ordered relation

I wanted to create a SMT sequence, such that I have a total ordering which should be complete.
example 1:
a < b and b < c should be satisfiable
example 2:
a < b and c < d should be unsatisfiable.
By adding b < c we will get satisfiability.
Does anyone have any idea if this is even possible in general?
So far I tried the following:
(declare-fun my_rel (Int Int) (Bool))
(assert (forall ((i Int)(j Int)) (implies (my_rel i j) (> i j))))
(declare-const a Int)
(declare-const b Int)
(declare-const c Int)
(declare-const d Int)
(assert (my_rel a b))
(assert (my_rel c d))
(check-sat)
This should return UNSAT. By adding (assert (my_rel b c)) it should satisfy.
I believe that what you want is a way to check if a transitive order over a finite set of elements x_1 ... x_n must be or is entailed to be complete and total because of a set of user assertions P about the order.
The < relation appears to be implicitly transitive in your example. The easy way to hack together an implicitly transitive binary relation is to use an uninterpreted function to embed any arbitrary domain into a totally ordered interpreted domain. Make sure the uninterpreted function added for this purpose appears only in this "embed into an order" sense.
(declare-fun foo (U) (Int))
(define-fun my_rel_strict ((i U) (j U)) (Bool) (> (foo i) (foo j)))
(define-fun my_rel_nonstrict ((i U) (j U)) (Bool)
(or (= (foo i) (foo j)) (my_rel_strict i j))
Both of the my_rel relations will transitive and my_rel_strict has the totality condition (either (my_real_nonstrict i j) or (my_rel_nonstrict j i) holds). (See http://en.wikipedia.org/wiki/Total_order) Neither is a total order as my_rel does not have antisymmetry. To avoid potential problems, the cardinality of the domain should be at least that of the codomain (or both are infinite). (The encoding for my_rel_nonstrict is not great. I'd try <= in practice.)
Next I believe what you want is an entailment check. Given a set of assertions P, does the user defined transitive order (which I now write as <) have to be total? We invent a formula total(x_1 ... x_n) for a finite set of elements:
total(x_1 ... x_n) = (and_{for all i,j} (or (< x_i x_j) (= x_i x_j) (> x_i x_j)))
(Not a very pleasant encoding of total, but an encoding all the same.) To check that P entails total(...), we query the smt solver with:
(assert P) (assert (not total(...)))
; You may also need (assert (distinct x_1 ... x_n))
If it is unsatisfiable the entailment holds. If it is satisfiable, the entailment has a counter example and does not hold.
Orders can be tricky to encode so my advice may not apply to your application. (Also take the above with a grain of salt. I am not 100% about it.)

How to define enumerated types in SMT-LIB for Z3

I previously used Z3's API to define an enumerated type like so
let T = ctx.MkEnumSort("T", [| "a"; "b"; "c"|])
which enumerates the elements of a type T as being "a" "b" and "c" (and nothing else). However I am now trying to do something similar but via SMT-LIB rather than the API and I am running into a problem of Z3 complaining about quantifiers. The program I am using (Boogie) generates the following smt
...
(declare-sort T#T 0)
(declare-fun a() T#T)
(declare-fun b() T#T)
(declare-fun c() T#T)
(assert (forall ((x T#T) )
(! (or
(= x a)
(= x b)
(= x c)
)
:qid |gen.28:15|
:skolemid |1|
)))
...
The assertion is the type closure axiom that asserts that the type has no other members. But when I send this (along with other stuff) to Z3, after thinking about it a bit, returns
WARNING: relevacy must be enabled to use option CASE_SPLIT=3, 4 or 5
unknown
(:reason-unknown (incomplete quantifiers))
Notes: 1. I have MBQI turned on. 2. Boogie has an option called "z3types" but it doesn't seem to make any difference
What is the SMT-LIB equivalent of the MkEnumSort API call?
thanks
P.S. I have tried with RELEVANCY set to both 1 and 2 and I still get the warning about relevancy (CASE_SPLIT is set to 3)
Use
(declare-datatypes () ((T#T (a) (b) (c)))
There is a tutorial with more details: http://rise4fun.com/z3/tutorialcontent/guide#h27
Use this for SMTLib v2:
(declare-datatypes ((T#T 0)) (((a) (b) (c))))
where T#T is the name of your type, and a, b, c its possible values.

does the 'double arrow' => really mean 'implies'?

Does
(=> (f g))
always mean the same thing as
(or (not f) g))
?
The two expressions behave differently in my model. While using => gives me UNSAT, using the other variant does not yield any result (timeout). I would be content just having a list of operators and their meanings. I am aware of the SMTLIB standard, but the documents don't explicitly talk about the meanings of operators. Specifically '=>' seems to double as an alias for the 'ite' (if_then_else) operator if used in a ternary expression and I'm quite confused about that.
I set the AUFLIA logic, if that's relevant.
I'm looking for a simple yes or no answer first. And a proper documentation about SMT2 (maybe a book) second.
I have this rather large model generated from Daniel Jackson's marksweep model for alloy4 of those of you who are willing to see for yourself.
Your expressions are incorrect/unwellformed.
=> indeed means 'implies'. In other words, (=> f g) is equivalent to (or (not f) g).
If in doubt, you could prove it using Z3. The below query is unsat:
(declare-const p Bool)
(declare-const q Bool)
(define-fun conjecture () Bool
(= (=> p q)
(or (not p) q)))
(assert (not conjecture))
(check-sat)

Does not 'check-sat' support Boolean function as assumption?

In the following example, I tried to use uninterpreted Boolean function like "(declare-const p (Int) Bool)" rather than single Boolean constant for each assumption. But it does not work (it gives compilation error).
(set-option :produce-unsat-cores true)
(set-option :produce-models true)
(declare-fun p (Int) Bool)
;(declare-const p1 Bool)
;(declare-const p2 Bool)
; (declare-const p3 Bool)
;; We assert (=> p C) to track C using p
(declare-const x Int)
(declare-const y Int)
(assert (=> (p 1) (> x 10)))
;; An Boolean constant may track more than one formula
(assert (=> (p 1) (> y x)))
(assert (=> (p 2) (< y 5)))
(assert (=> (p 3) (> y 0)))
(check-sat (p 1) (p 2) (p 3))
(get-unsat-core)
Output
Z3(18, 16): ERROR: invalid check-sat command, 'not' expected, assumptions must be Boolean literals
Z3(19, 19): ERROR: unsat core is not available
I understand that it is not possible (unsupported) to use Boolean function. Is there any reason behind that? Is there different way to do that?
We have this restriction because Z3 applies many simplifications before it solves a problem. Some of them will rewrite formulas and terms. The problem that is actually solved by Z3 is very often quite different from the input problem. We would have trace back the simplified assumptions to the original assumptions, or introduce auxiliary variables. Restricting to Boolean literals avoids this issue, and makes the interface very clean. Note that this restriction does not limit the expressiveness. If you think it is too annoying to declare many Boolean variables to track different assertions. I suggest you take a look at the new Python front-end for Z3 called Z3Py. It is much more convenient to use than SMT 2.0. Here is your example in Z3Py: http://rise4fun.com/Z3Py/cL
In this example, instead of creating an uninterpreted predicate p, a "vector" (actually, it is a Python list) o Boolean constants is created.
The Z3Py online tutorial contains many examples.
It is also possible to implement in Z3Py the approach that creates auxiliary variables.
Here is the script that does the trick. I defined a function check_ext that does all the plumbing. http://rise4fun.com/Z3Py/B4

Resources