问题
I'm trying to write a max function that operates on Seq Int
.
It should return the index with maximal value. Here is what I have:
(declare-fun max ((Seq Int)) Int)
(assert (forall ((A (Seq Int)))
(=>
(> (seq.len A) 0)
(and
(<= 0 (max A))
(< (max A) (seq.len A))
(forall ((i Int))
(=>
(and
(<= 0 i)
(< i (seq.len A)))
(<= (seq.nth A i) (seq.nth A (max A))))))))
)
(assert (= (max (seq.++ (seq.unit 8) (seq.unit 3))) 0))
;(assert (= (max (seq.++ (seq.unit 8) (seq.unit 3))) 1))
(check-sat)
When I run it like this, Z3 gets stuck. If I use the commented line instead, Z3 immediately answers unsat (like it should). Am I missing something here? Is there a way to define max properly?
回答1:
This sort of quantified problems are just not a good match for z3. (Or any other SMT solver.) To prove properties of such recursive predicates, you need induction. Traditional SMT solvers have no induction capabilities.
Having said that, you can help z3 by making your quantified assertions separated out, like this:
(declare-fun max ((Seq Int)) Int)
(assert (forall ((A (Seq Int))) (=> (> (seq.len A) 0) (<= 0 (max A)))))
(assert (forall ((A (Seq Int))) (=> (> (seq.len A) 0) (< (max A) (seq.len A)))))
(assert (forall ((A (Seq Int)) (i Int)) (=> (and (> (seq.len A) 0) (<= 0 i) (< i (seq.len A)))
(<= (seq.nth A i) (seq.nth A (max A))))))
(assert (= (max (seq.++ (seq.unit 8) (seq.unit 3))) 0))
;(assert (= (max (seq.++ (seq.unit 8) (seq.unit 3))) 1))
(check-sat)
If you run this, it succesfully says:
sat
While this is correct, don't be fooled into thinking you've completely specified how max
should work or z3 can handle all such problems. To wit, let's add (get-model)
and see what it says:
sat
(model
(define-fun max ((x!0 (Seq Int))) Int
(ite (= x!0 (seq.++ (seq.unit 7718) (seq.++ (seq.unit 15) (seq.unit 7719))))
2
0))
)
Oh look, it simply found an interpretation of max
that doesn't even satisfy the quantified axioms you've given. Looks like this is a z3 bug and should probably be reported. But the moral of the story is the same: Sequence logic and quantifiers are a soft spot, and I wouldn't count on the solver response even if you got a sat
answer.
Long story short Recursion requires induction, and if that's what your specification requires, use a tool that understands induction. Isabelle, HOL, Coq, Agda, Lean; to name a few. There are many choices. And most of those tools automatically call z3 (or other SMT solvers) under the hood to establish properties as necessary (or as guided by the user) anyhow; so you have the best of both worlds.
来源:https://stackoverflow.com/questions/57242139/max-element-in-z3-seq-int