I wanted to encode partial maps in Z3, with support for asking whether the map is defined for a certain key.
It should also support the operation (update_map m1 m2)
, which updates m1
with the mappings in m2
such that the mappings of m2
override those of m1
.
I tried to encode it using arrays, and a custom option
datatype, and I axiomatically specified the update_map
function. However, it seems that Z3 can not even deal with my specification of update_map
: It returns unknown
on the following code:
(declare-datatypes (T) ((option None (Some (option-value T)))))
(define-sort map (K V) (Array K (option V)))
(declare-sort V)
(declare-sort K)
(define-const empty_map (map K V)
((as const (Array K (option V))) None))
(define-fun get ((m (map K V)) (k K)) (option V)
(select m k))
(define-fun put ((m (map K V)) (k K) (v V)) (map K V)
(store m k (Some v)))
(declare-fun update_map ((map K V) (map K V)) (map K V))
(assert (forall ((m1 (map K V)) (m2 (map K V)) (k K))
(=> (= (get m2 k) None)
(= (get (update_map m1 m2) k) (get m1 k)))))
(assert (forall ((m1 (map K V)) (m2 (map K V)) (k K) (v V))
(=> (= (get m2 k) (Some v))
(= (get (update_map m1 m2) k) (Some v)))))
(check-sat)
So I have two questions:
- Is there a better way to encode maps which would enable me to prove facts about
update_map
? - Can anyone share some intuition on why Z3 doesn't understand this specification? As in, what's the "core feature" making this hard for Z3? [I already know that quantifiers are considered hard and that first-order logic is undecidable, I'm looking for something more specific ;-)]