2

How can I access the last element in Z3 list?

(declare-const lst (List Int))
(assert (not (= lst nil)))
(assert (= (head lst) 1))
(assert (= (last_element lst) 2))
(check-sat)

1 Answers1

0

AFAIK, Z3 has no built-in function to access the last element of a list. Since SMT-Lib2 does not support recursive functions (see this answer), you have to declare and axiomatise an uninterpreted last_element function yourself.

Declaration:

(declare-fun last_element ((List Int) (Int)) Bool)

Axiom "nil has no last element":

(assert (forall ((x Int)) (!
  (not (last_element nil x))
  :pattern ((last_element nil x))
)))

Axiom "If xs is the list x:nil then x is the last element of xs":

(assert (forall ((xs (List Int)) (x Int)) (!
  (implies
    (= xs (insert x nil))
    (last_element xs x))
  :pattern ((last_element xs x))
)))

Axiom "If x is the last element of the tail of xs, then it is also the last element of xs itself":

(assert (forall ((xs (List Int)) (x Int)) (!
  (implies
    (last_element (tail xs) x)
    (last_element xs x))
  :pattern ((last_element xs x))
)))

See this rise4fun-link for an example.


Please note: The linked example switches of model based quantifier instantiation (MBQI, see the Z3 guide) and thus relies on E-matching. This is also the reason why explicit patterns are provided, see this question. If you want to give MBQI a try you might have to change the axiomatisation, but I hardly know anything about MBQI.

Community
  • 1
  • 1
Malte Schwerhoff
  • 12,684
  • 4
  • 41
  • 71
  • 1
    Thanks for your answer! But if we change `(assert (not (last_element xs 3)))` to `(assert (last_element xs 3))` we shall obtain UNSAT too. Why? – user2475120 Jun 13 '13 at 10:03
  • @user2475120 Sorry, my bad. The third axiom used `iff` instead of `implies`, which let to a contradiction with the first axiom in case `xs = x:nil`. – Malte Schwerhoff Jun 13 '13 at 13:34