I am trying to use Z3 to reason about substrings, and have come across some non-intuitive behavior. Z3 returns sat when asked to determine if xy appears within xy , but it returns unknown when asked if x is in x , or x is in xy .
I ve commented the following code to illustrate this behavior:
(set-logic AUFLIA)
(declare-sort Char 0)
;characters to build strings are _x_ and _y_
(declare-fun _x_ () Char)
(declare-fun _y_ () Char)
(assert (distinct _x_ _y_))
;string literals
(declare-fun findMeX () (Array Int Char))
(declare-fun findMeXY () (Array Int Char))
(declare-fun x () (Array Int Char))
(declare-fun xy () (Array Int Char))
(declare-fun length ( (Array Int Char) ) Int )
;set findMeX = x
(assert (= (select findMeX 0) _x_))
(assert (= (length findMeX) 1))
;set findMeXY = xy
(assert (= (select findMeXY 0) _x_))
(assert (= (select findMeXY 1) _y_))
(assert (= (length findMeXY) 2))
;set x = x
(assert (= (select x 0) _x_))
(assert (= (length x) 1))
;set xy = xy
(assert (= (select xy 0) _x_))
(assert (= (select xy 1) _y_))
(assert (= (length xy) 2))
Now that the problem is set up, we try to find the substrings:
;search for findMeX= x in x= x
(push 1)
(assert
(exists
((offset Int))
(and
(<= offset (- (length x) (length findMeX)))
(>= offset 0)
(forall
((index Int))
(=>
(and
(< index (length findMeX))
(>= index 0))
(=
(select x (+ index offset))
(select findMeX index)))))))
(check-sat) ; sat expected, unknown returned
(pop 1)
If we instead search for findMeXY
in xy
, the solver returns sat , as expected. It would seem that since the solver can handle this query for xy , it should be able to handle it for x . Further, if searching for findMeX= x
in xy= xy
, it returns unknown .
Can anyone suggest an explanation, or perhaps an alternate model for expressing this problem within a SMT solver?