I need to write the following sentence using SMT2/Z3, not sure of the difference.
For every person who has a parent, he/she must love his/her parent.
So far, I've written
(declare-const x Bool)
(declare-const y Bool)
(declare-const z Bool)
(declare-fun love () Bool)
(assert =>
((forall (x) (y x) )
(exists z)))
(check-sat)
But this is just giving me an error on arguments which I can't seem to fix.
My predicates are
Person(x) x is a person.
Parent(x, y) x is a parent of y.
Love(x, y) x loves y.
Any help greatly appreciated.
Here's one way:
(declare-sort Person 0)
(declare-fun parentOf (Person Person) Bool)
(declare-fun loves (Person Person) Bool)
(assert
(forall ((x Person) (y Person))
(=> (parentOf x y)
(loves x y))))
(check-sat)
(get-model)
z3 says:
sat
(model
;; universe for Person:
;; Person!val!0
;; -----------
;; definitions for universe elements:
(declare-fun Person!val!0 () Person)
;; cardinality constraint:
(forall ((x Person)) (= x Person!val!0))
;; -----------
(define-fun loves ((x!0 Person) (x!1 Person)) Bool
false)
(define-fun parentOf ((x!0 Person) (x!1 Person)) Bool
false)
)
Essentially, z3 is telling us that our constraints are satisfiable (that's the meaning of the output sat) and a (note: not the) satisfying assignment is a universe where there's:
Precisely one person, named Person!val!0
Nobody loves anyone
Nobody is the parent of anyone else
Which clearly satisfies all the constraints, but perhaps not the most interesting model out there. If you assert further facts, you can get richer models. (For instance, you can say there're at least 5 people, that nobody is their own parent, parenting relationship is not symmetric, everybody loves themselves, etc. depending on exactly what you're trying to model.)
Keep in mind that SMT solvers are not good for dealing with quantifiers. While statements like this will work just fine, extensive use of quantifiers and first-order logic will put theories into the semi-decidable territory, i.e., z3 can end up saying unknown. SMT solvers are best for quantifier-free combinations of theories such as arithmetic, arrays, datatypes, etc. For problems such as these, Prolog is probably your best bet for modeling purposes.
Related
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.
I'm trying to create a function in Z3 that is transitive but not reflexive. I.e. if (transitive a b) and (transitive b c)hold then (transitive a c) should hold, but (transitive a a) should not.
I've tried to do it the following way, with 5 "tests". The first does what I expect, but the second one fails and results in unknown.
(declare-datatypes () ((T T1 T2 T3)))
(declare-fun f (T T) Bool)
(assert(f T1 T2))
(assert(f T2 T3))
; Make sure that f is not reflexive
(assert
(forall ((x T))
(not (f x x))))
; Now we create the transitivity function ourselves
(define-fun-rec transitive ((x T) (y T)) Bool
(or
(f x y)
(exists ((z T))
(and
(f x z)
(transitive z y)))))
; This works and gives sat
(push)
(assert (not (transitive T1 T1)))
(assert (not (transitive T2 T2)))
(assert (not (transitive T3 T3)))
(check-sat)
(pop)
; This fails with "unknown" and the verbose flag gives: (smt.mbqi "max instantiations 1000 reached")
(push)
(assert
(forall ((x T))
(not (transitive x x))))
(check-sat)
(pop)
My question is: how does the second test differ from the first? Why does the last one give unknown, whereas the one before that works just fine?
The "verbose" message is a hint here. mbqi stands for model-based-quantifier-instantiation. It's a method of dealing with quantifiers in SMT solving. In the first case, MBQI manages to find a model. But your transitive function is just too complicated for MBQI to handle, and thus it gives up. Increasing the limit will not likely address the problem, nor it's a long term solution.
Short story long, recursive definitions are difficult to deal with, and recursive definitions with quantifiers are even harder. The logic becomes semi-decidable, and you're at the mercy of heuristics. Even if you found a way to make z3 compute a model for this, it would be brittle. These sorts of problems are just not suitable for SMT solving; better use a proper theorem prover like Isabelle, Hol, Coq, Lean. Agda, etc. Almost all these tools offer "tactics" to dispatch subgoals to SMT solvers, so you have the best of both worlds. (Of course you lose full automation, but with quantifiers present, you can't expect any better.)
I'm attempting to get Z3 to find all possible permutations of a sequence of fixed size that satisfy some constraints. However, I've run into a timeout error with the code I've developed so far:
(set-option :produce-unsat-cores true)
(set-option :produce-models true)
; --------------- Basic Definitions -------------------
(declare-datatypes () ((Obj A B C)))
; --------------- Predicates -------------------------------
(define-sort MyList () (Seq Obj))
(define-fun in_list ((o Obj) (l MyList)) Bool (seq.contains l (seq.unit o)))
(define-fun permutation ((l1 MyList) (l2 MyList)) Bool
(forall ((o Obj)) (= (in_list o l1) (in_list o l2))))
; Two difference permutations of the same list
(declare-const l0 MyList)
(declare-const l1 MyList)
(assert (= 2 (seq.len l0)))
(assert (= 2 (seq.len l1)))
(assert (not (= l1 l0)))
(assert (permutation l0 l1))
; --------------- Verify -------------------
(check-sat)
(get-model)
It seems like this should be a pretty trivial solve (even a brute force should take milliseconds), so I'm pretty baffled what is causing the timeout. Any help?
You're running into limits of what Z3 can do when quantifiers are present.
You might want to look at this question: Defining a Theory of Sets with Z3/SMT-LIB2
In this case, the question is about general set operations, but I think you'll find the answers to apply to your case as well. (In short, disable MBQI, and see if you can use functions instead of sequences.)
I noticed some strange behavior with Z3 4.3.1 when working with .smt2 files.
If I do (assert (= 0 0.5)) it will be satisfiable. However, if I switch the order and do (assert (= 0.5 0)) it's not satisfiable.
My guess as to what is happening is that if the first parameter is an integer, it casts both of them to integers (rounding 0.5 down to 0), then does the comparison. If I change "0" to "0.0" it works as expected. This is in contrast to most programming languages I've worked with where if either of the parameters is a floating-point number, they are both cast to floating-point numbers and compared. Is this really the expected behavior in Z3?
I think this is a consequence of lack of type-checking; z3 is being too lenient. It should simply reject such queries as they are simply not well formed.
According to the SMT-Lib standard, v2 (http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.0-r10.12.21.pdf); page 30; the core theory is defined thusly:
(theory Core
:sorts ((Bool 0))
:funs ((true Bool) (false Bool) (not Bool Bool)
(=> Bool Bool Bool :right-assoc) (and Bool Bool Bool :left-assoc)
(or Bool Bool Bool :left-assoc) (xor Bool Bool Bool :left-assoc)
(par (A) (= A A Bool :chainable))
(par (A) (distinct A A Bool :pairwise))
(par (A) (ite Bool A A A))
)
:definition
"For every expanded signature Sigma, the instance of Core with that signature
is the theory consisting of all Sigma-models in which:
- the sort Bool denotes the set {true, false} of Boolean values;
- for all sorts s in Sigma,
- (= s s Bool) denotes the function that
returns true iff its two arguments are identical;
- (distinct s s Bool) denotes the function that
returns true iff its two arguments are not identical;
- (ite Bool s s) denotes the function that
returns its second argument or its third depending on whether
its first argument is true or not;
- the other function symbols of Core denote the standard Boolean operators
as expected.
"
:values "The set of values for the sort Bool is {true, false}."
)
So, by definition equality requires the input sorts to be the same; and hence the aforementioned query should be rejected as invalid.
There might be a switch to z3 or some other setting that forces more strict type-checking than it does by default; but I would've expected this case to be caught even with the most relaxed of the implementations.
Do not rely on the implicit type conversion of any solver. Instead,
use to_real and to_int to do explicit type conversions. Only send
well-typed formulas to the solver. Then Mohamed Iguernelala's examples become the following.
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= (to_real x) 1.5))
(check-sat)
(exit)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= 1.5 (to_real x)))
(check-sat)
(exit)
Both of these return UNSAT in Z3 and CVC4. If instead, you really
wanted to find the model where x = 1 you should have instead used one
of the following.
(set-option :produce-models true)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= (to_int 1.5) x))
(check-sat)
(get-model)
(exit)
(set-option :produce-models true)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= x (to_int 1.5)))
(check-sat)
(get-model)
(exit)
Both of these return SAT with x = 1 in Z3 and CVC4.
Once you make all the type conversions explicit and deal only in well-typed formulas, the order of arguments to equality no longer matters (for correctness).
One of our interns, who worked on a conservative extension of SMT2 with polymorphism has noticed the same strange behavior, when he tried the understand how formulas mixing integers and reals are type-checked:
z3 (http://rise4fun.com/z3) says that the following example is SAT, and finds a model x = 1
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= x 1.5))
(check-sat)
(get-model)
(exit)
But, it says that the following "equivalent" example in UNSAT
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= 1.5 x))
(check-sat)
(exit)
So, this does not comply with the symmetric property of equality predicate. So, I think it's a bug.
Strictly speaking, Z3 is not SMT 2.0 compliant by default, and this is one of those cases. We can add
(set-option :smtlib2-compliant true)
and then this query is indeed rejected correctly.
Z3 is not the unique SMT solver that type-checks these examples:
CVC4 accepts them as well (even with option --smtlib-strict), and answers UNSAT in both cases of my formulas above.
Yices accepts them and answers UNSAT (after changing the logic to QF_LIA, because it does not support AUFLIRA).
With (set-logic QF_LIA), Z3 emits an error: (error "line 3 column 17: logic does not support reals").
Alt-Ergo says "typing error: Int and Real cannot be unified" in both cases. But Alt-Ergo's SMT2 parser is very limited and not heavily tested, as we concentrated on its native polymorphic language. So, it should not be taken as a reference.
I think that developers usually assume an "implicit" sub-typing relation between Int and Real. This is why these examples are successfully type-checked by Z3, CVC4 and Yices (and probably others as well).
Jochen Hoenicke gived the answer (on SMT-LIB mailing list) regarding "mixing reals and integers". Here it is:
I just wanted to point out, that the syntax may be officially correct.
There is an extension in AUFLIRA and AUFNIRA.
From http://smtlib.cs.uiowa.edu/logics/AUFLIRA.smt2
"For every operator op with declaration (op Real Real s) for some
sort s, and every term t1, t2 of sort Int and t of sort Real, the
expression
- (op t1 t) is syntactic sugar for (op (to_real t1) t)
- (op t t1) is syntactic sugar for (op t (to_real t1))
- (/ t1 t2) is syntactic sugar for (/ (to_real t1) (to_real t2)) "
One possible solution is
(declare-fun x () Real)
(declare-fun y () Real)
(assert (= x 0))
(assert (= y 0.5))
(check-sat)
(push)
(assert (= x y) )
(check-sat)
(pop)
and the output is
sat
unsat
Assume that I have a Z3 preamble that includes several function declarations and definitional axioms (with explicit patterns), e.g., my own sequence axioms:
(declare-sort $Seq)
(declare-fun $Seq.nil () $Seq)
(declare-fun $Seq.len ($Seq) Int)
(declare-fun $Seq.con (Int $Seq) $Seq)
(declare-fun $Seq.at ($Seq Int) Int)
(declare-fun $Seq.in ($Seq Int) Bool)
...
(assert (forall ((xs $Seq)) (! ... )
(assert (forall ((xs $Seq) (x Int)) (! ... )
...
After this preamble has been emitted a lot of assertions are pushed to Z3, interspersed with calls to check-set to see whether certain negated formulas can be shown unsat (FYI: my context is software verification using symbolic execution).
Most of these assertions are simple and don't refuting them doesn't require the sequence axioms. However, from a few simple tests I get the impression that their presence nevertheless slows Z3 down.
I thus guarded the definitional axioms by an implication with a dummy boolean constant as the left-hand side of the implication (as suggested by this answer), e.g.,
(declare-const $useSeq Bool)
(assert (=> ($useSeq (forall ((xs $Seq)) (! ... )
and changed every check-sat that needs to reason about sequences into one that assumes $useSeq, i.e.,
(check-sat $useSeq)
Question: Is there a tactic/way to make Z3 use certain assertions only after a time-out? E.g.,
(check-sat-using (or-else (try-for smt 500) (smt $useSeq)))
I could of course manually emit a time-bounded check-sat first, followed by a check-sat useSeq $useSeq if needed, but it would be nice if it could be done with some kind of tactics.
Unfortunately, this cannot be done with the current set of tactics available in Z3.