How to get multiple constraints in Z3 Fixedpoint? - z3

When running the fragment
(declare-rel mypred (Int Int))
(declare-var A Int)
(declare-var B Int)
(declare-var C Int)
(rule (mypred 1 0))
(rule (mypred 2 1))
(rule (mypred 3 2))
(rule (mypred 4 3))
(rule (mypred 5 4))
(rule (=> (and (mypred C B) (mypred A C)) (mypred A B)))
(query (and (mypred C 2) (mypred 2 B) (mypred B A))
:print-answer true
)
(query (mypred A 2)
:print-answer true
)
in z3 (for example on rise4fun http://rise4fun.com/Z3/ ), I get an answers:
sat
(and (query!0 1 1 3) (mypred 2 1) (mypred 3 2) (mypred 1 0))
sat
(and query!16!slice!18 (mypred!slice!17 2))
As expected both queries can be satisfied and Z3 correctly reports that, but I would also like to find out for which values of A,B,C they are satisfied, yet the answer does not provide a direct answer to this.
The arguments of "query!0" do not seem to be the same as those used in the original query and the second part of the answer matches the original query only after reordering. I'm actually coding this with the .NET API, so I can inspect the AST, but I want to avoid trying to match every element of the original query with each of those in the answer (so for example if there was a way to preserve the order, I would be quite happy).
The second query can be satisfied in multiple ways. I'm not currently interested in finding one of them (although this could come useful too), but I would like to know a way to automatically distinguish it from the case where the query has a unique solution.
Is this possible to achieve with Z3 Fixedpoints? How can I do that?
(I've seen multiple questions getting the constraints, but I was unable to figure out the exact symbol<->value matching)

There are two things to say about what you bring up:
The version of Z3 that you used on rise4fun provides non-informative answers in cases like the ones you give. The version checked into the unstable branch (built automatically on different platforms) produces the answer:
sat
(and (mypred 3 2) (mypred 1 0) (mypred 2 1))
sat
(mypred 3 2)
I don't have a satisfactory solution to display bindings of the form A |-> 3. Sorry.

Related

How to use tactics in z3's SMT2 syntax?

I am interacting with z3 through its smt2 interface. Suppose, I write the following commands:
(declare-fun p () Int)
(declare-fun q () Int)
(declare-fun r () Int)
(assert (and (<= (+ (* 4 p) (* 3 q)) (- r 10)) (<= (+ (* 4 p) (* 3 q)) (- r 12))))
(apply simplify)
Now, I get a list of goals in the form
(goals
(goal …)
(goal …)
…
)
What do I do with it?
Another question, is there any documentation on this? Where should I look for it?
Tactics are a z3 invention; so you will not find any official documentation on how they should be used from an SMTLib perspective.
In general, you don't just use apply. Instead, you use the method check-sat-using, that takes a tactic as an argument. In general, check-sat is equivalent to (check-sat-using smt), i.e., using the smt tactic.
For your example, you can say:
(check-sat-using (then simplify smt))
this would reduce the problem to sat. The idea is that you can use these "tactics" to guide the solver to find a solution (or go faster).
Tactics are usually intended to be used from higher-level interfaces, such as C/C++/Java etc., and unfortunately they aren't all that well documented. Read through http://www.cs.tau.ac.il/~msagiv/courses/asv/z3py/strategies-examples.htm, which is using the Python interface, but you can use the same ideas directly from smtLib as well.
Tactics are also documented at https://theory.stanford.edu/~nikolaj/programmingz3.html#sec-tactics, though again it uses the Python interface not SMTLib.

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.

Multi-element subtraction in Z3

I'm using Z3 to solve a problem that needs subtraction and I've run into the fact that subtraction in Z3 allows multiple arguments.
This seems odd to me as subtraction is not an associative operation.
This can be seen from the following script.
(declare-fun a () Int)
(declare-fun b () Int)
(declare-fun c () Int)
(assert (= a (- 1 2 3)))
(assert (= b (- 1 (- 2 3))))
(assert (= c (- (- 1 2) 3)))
which is satisfied by a=c=-4 and b=2
So this means that subtraction in Z3 is defined by applying the binary operation from left to right?
This is actually a feature of SMT-Lib, z3 is simply implementing that. See here: http://smtlib.cs.uiowa.edu/theories-Ints.shtml
And yes, if you have multiple elements, it simply associates to the left. That is:
(- 1 2 3 4)
means exactly the same thing as:
(- (- (- 1 2) 3) 4)
This is indeed confusing as we only want to do for associative operators where parenthesization doesn't matter (like + and *), but SMTLib is liberal in this sense. This does not mean subtraction is associative in SMT-Lib, it just means if you have multiple arguments it's parsed as described above. Hope that helps!

Cyclic relation in Datalog using SMTLib for z3

I would like to express this problem in the SMTLib Format and evaluate it using Z3.
edge("som1","som3").
edge("som2","som4").
edge("som4","som1").
edge("som3","som4").
path(x,y) :- edge(x,y). % x and y are strings
path(x,z) :- edge(x,y), path(y,z).
:- path(x,y), path(y,x). %cyclic path.
My question is how to write the rule (or query) which detect the existence of a cycle in the relation path (this rule in basic datalog : :- path(x,y), path(y,x) ).
The tutorial Levent Erkok pointed out actually contains all the right information (I think). Knowing neither Datalog nor Z3's fixpoint features, I was still able to piece together the following:
(set-option :fixedpoint.engine datalog)
(define-sort s () Int)
(declare-rel edge (s s))
(declare-rel path (s s))
(declare-var a s)
(declare-var b s)
(declare-var c s)
(rule (=> (edge a b) (path a b)) P-1)
(rule (=> (and (path a b) (path b c)) (path a c)) P-2)
(rule (edge 1 2) E-1)
(rule (edge 2 3) E-2)
(rule (edge 3 1) E-3)
(declare-rel cycle (s))
(rule (=> (path a a) (cycle a)))
(query cycle :print-answer true)
Z3 4.8.0 nightly reports sat, indicating that there is a cycle, but unsat if any of the E-rules is removed.
I had to use ints instead of strings, though, since (my version of) Z3 aborts with the error Rule contains infinite sorts in rule P-1 if strings are used.

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

Resources