Reasoning with such recursive data-types/values is not a strong suit for SMT solvers. Most problems will require induction and SMT-solvers don't do induction out-of-the box.
Having said that, you can code what you want using the new declare-fun-rec
construct:
(define-fun-rec copyHeadAux ((x (Seq Int)) (l (Seq Int))) (Seq Int)
(ite (= 0 (seq.len l))
(as seq.empty (Seq Int))
(seq.++ x (copyHeadAux x (seq.extract l 1 (seq.len l))))))
(define-fun copyHead ((l (Seq Int))) (Seq Int)
(ite (= 0 (seq.len l))
(as seq.empty (Seq Int))
(copyHeadAux (seq.at l 0) l)))
(define-fun test () (Seq Int) (seq.++ (seq.unit 7) (seq.unit 5) (seq.unit 6)))
(declare-const out (Seq Int))
(assert (= out (copyHead test)))
(check-sat)
(get-model)
When I run this, I get:
sat
(
(define-fun out () (Seq Int)
(seq.++ (seq.unit 7) (seq.unit 7) (seq.unit 7)))
(define-fun test () (Seq Int)
(seq.++ (seq.unit 7) (seq.unit 5) (seq.unit 6)))
(define-fun copyHead ((x!0 (Seq Int))) (Seq Int)
(ite (= 0 (seq.len x!0))
(as seq.empty (Seq Int))
(copyHeadAux (seq.at x!0 0) x!0)))
)
which is the correct answer you're looking for. But unless your constraints only involve "constant-folding" cases (i.e., where copyHead
is always applied to a constant known value), you're likely to get unknown
as the answer, or have the solver go into an infinite e-matching loop.
It's best to use a proper theorem prover (Isabelle, HOL, Lean, ACL2 etc.) for reasoning with these sorts of recursive definitions. Of course, SMT solvers get better over time and maybe one day they'll be able to handle more problems like this out-of-the-box, but I wouldn't hold my breath.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…