z3 "more than" totally ordered relation - z3

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

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.

Why does Z3 return Unknown for these horn clauses

I am using Z3 to solve my horn clauses. In the body of Horn clauses uninterpreted predicates should be positive. However, I need negation of some of uninterpreted predicates.
I have seen some examples in which negation works fine. For instance Z3 would return sat for the following example:
(set-logic HORN)
(declare-fun inv (Int) Bool)
(assert (inv 0))
(assert (forall ((k Int)) (or (> k 10) (not (inv k)) (inv (+ k 1)))))
(check-sat)
But my example looks like the following for which Z3 returns unknown.
(set-logic HORN)
(declare-fun inv (Int ) Bool)
(declare-fun s ( Int ) Bool)
(assert (forall ((k Int) (pc Int))(=>(and (= pc 1)(= k 0)) (inv k ))))
(assert (forall ((k Int)(k_p Int)(pc Int)(pc_p Int))
(=>(and (inv k )(= pc 1)(= pc_p 2)(= k_p (+ k 1))(not (s pc ))(s pc_p ))
(inv k_p ))))
(check-sat)
I wonder if there is a way to rewrite my clauses to Horn clause fragment of Z3.
Your clauses are not in the Horn fragment because the predicate s is used with both polarities in the last assertion. So there are two occurrences of a predicate with positive polarity (both (s pc) and (inv k_p) are positive polarity).
A basic method to avoid polarity issues is to introduce an extra argument to s of type Bool. Consequently, you would also have to say what is the specification of s using Horn clauses so it all makes sense. The typical scenario is that s encodes the behavior of a recursive procedure and the extra Boolean argument to s would be the return value of the procedure s. Of course this encoding doesn't ensure that s is total or functional.
There is a second approach, which is to add an extra argument to "inv", where you let 's' be an array. Then the occurrences (not (s pc)) becomes (not (select s pc)), etc.
It all depends on the intent of your encoding for what makes sense.

Datatypes and quantifier patterns/triggers

I observed a difference in Z3's quantifier triggering behaviour (I tried 4.4.0 and 4.4.2.3f02beb8203b) that I cannot explain. Consider the following program:
(set-option :auto_config false)
(set-option :smt.mbqi false)
(declare-datatypes () ((Snap
(Snap.unit)
(Snap.combine (Snap.first Snap) (Snap.second Snap))
)))
(declare-fun fun (Snap Int) Bool)
(declare-fun bar (Int) Int)
(declare-const s1 Snap)
(declare-const s2 Snap)
(assert (forall ((i Int)) (!
(> (bar i) 0)
:pattern ((fun s1 i))
)))
(assert (fun s2 5))
(assert (not (> (bar 5) 0)))
(check-sat) ; unsat
As far as my understanding goes, the unsat is unexpected: Z3 should not be able to trigger the forall since it is guarded by the pattern (fun s1 i), and Z3 should not be able (and actually isn't) to prove that s1 = s2.
In contrast, if I declare Snap to be an uninterpreted sort, then the final check-sat yields unknown - which is what I would expect:
(set-option :auto_config false)
(set-option :smt.mbqi false)
(declare-sort Snap 0)
...
(check-sat) ; unknown
If I assume s1 and s2 to be different, i.e.
(assert (not (= s1 s2)))
then the final check-sat yields unknown in both cases.
For convenience, here is the example on rise4fun.
Q: Is the difference in behaviour a bug, or is it intended?
The assertion (not (= s1 s2)) is essential. With pattern based quantifier instantiation, the pattern matches if the current state of the search satisfies s1 = s2. In the case of algebraic data-types, Z3 tries to satisfy formulas with algebraic data-types by building a least model in terms of constructor applications. In the case of Snap as an algebraic data-type the least model for s1, s2 have them both as Snap.unit. At that point, the trigger is enabled because the terms E-match. In other words, modulo the congruences, the variable I can be instantiated such that (fun s1 I) matches (fun s2 5), but setting I <- 5. After the trigger is enabled, the quantifier is instantiated and the axiom
(=> (forall I F(I)) (F(5)))
is added (where F is the formula under the quantifier).
This then enables to infer the contradiction and infer unsat.
When Snap is uninterpreted, Z3 attempts to construct a model where terms s1 and s2 are different. Since there is nothing to force these terms to be equal they remain distinct
It's not a bug since z3 doesn't say unsat for a sat formula (or sat for an unsat one). In presence of quantified formulas, SMT solvers are (in general) not complete. So they sometimes answer unknown when they are not sure that the input formula in sat.
For your example:
a - It's normal that, with matching techniques, z3 does not prove the formula when you assume that s1 and s2 are different. In fact, there is no ground term of the form (fun s1 5) that matches the pattern (fun s1 i), and that would allow the generation of the useful instance (> (bar 5) 0) from your quantified formula;
b - When you don't assume that s1 and s2 are different, you would not be able to get the proof too. Except that z3 probably assumes internally that s1 = s2 when Snap is a datatype. This is correct as long as there is nothing that contradicts s1 = s2. Thanks to this and to matching modulo equality, the ground term (fun s2 5) matches the pattern (fun s1 i), and the needed instance to prove unsatisfiability is generated.

Getting concrete array values from a model

I am using Z3 to check the satisfiability of a formula in the array property fragment. The models for array variables that Z3 returns are usually expressed using other if-expressions, if-then-else case analysis, etc. I want to somehow parse the model that Z3 outputs and create the array, which satisfies the input SMT-LIB formula, explicitly.
For example I want to be able to somehow always simplify the model that Z3 outputs to the following form:
A -> {
1 -> 3
2 -> 4
else -> 6
}
Is there some easy way to traverse the model (using C API?) and create an explicit array representing the model ?
Unfortunately, the output format described in your message is not expressive enough to describe models for every satisfiable formula in the array-property fragment. For example, consider the following simple example.
(declare-fun f (Int) Int)
(declare-const a Int)
(declare-const b Int)
(assert (forall ((i Int) (j Int)) (=> (<= i j) (<= (f i) (f j)))))
(assert (< (f a) (f b)))
(check-sat)
(get-model)
The formula f is non-decreasing, and it has two points a and b s.t. f(a) < f(b). In any model, we must have that for all values i <= a, f(i) <= f(a), and for all values j >= b, f(b) <= f(j). That is,
f(i) <= f(a) < f(b) <= f(j).
A single else will not work. Z3 produces an interpretation for f that is essentially a "step-function". You can try the example above here.

Difference between macro and quantifier in Z3

I would like to know what is the difference between following 2 statements -
Statement 1
(define-fun max_integ ((x Int) (y Int)) Int
(ite (< x y) y x))
Statement 2
(declare-fun max_integ ((Int)(Int)) Int)
(assert (forall ((x Int) (y Int)) (= (max_integ x y) (if (< x y) y x))))
I observed that when I use Statement1, my z3 constraints give me a result in 0.03 seconds. Whereas when I used Statement2, it does not finish in 2 minutes and I terminate the solver.
I would like also to know how achieve it using C-API.
Thanks !
Statement 1 is a macro. Z3 will replace every occurrence of max_integ with the ite expression. It does that during parsing time. In the second statement, by default, Z3 will not eliminate max_integ, and to be able to return sat it has to build an interpretation for the uninterpreted symbol max_integ that will satisfy the quantifier for all x and y.
Z3 has an option called :macro-finder, it will detect quantifiers that are essentially encoding macros, and will eliminate them. Here is an example (also available online here):
(set-option :macro-finder true)
(declare-fun max_integ ((Int)(Int)) Int)
(assert (forall ((x Int) (y Int)) (= (max_integ x y) (if (< x y) y x))))
(check-sat)
(get-model)
That being said, we can easily simulate macros in a programmatic API by writing a function that given Z3 expressions return a new Z3 expression. Here in an example using the Python API (also available online here):
def max(a, b):
# The function If builds a Z3 if-then-else expression
return If(a >= b, a, b)
x, y = Ints('x y')
solve(x == max(x, y), y == max(x, y), x > 0)
Yet another option is to use the C API: Z3_substitute_vars. The idea is to an expression containing free variables. Free variables are created using the API Z3_mk_bound. Each variable represents an argument. Then, we use Z3_substitute_vars to replace the variables with other expressions.

Resources