I'm trying to use array and quantifier in Z3 in order to find substring in a given text.
My code is the following:
(declare-const a (Array Int Int))
(declare-const x Int)
;; a|A
(assert (or (= (select a 0) 61) (= (select a 0) 41)))
;; b|B
(assert (or (= (select a 1) 62) (= (select a 1) 42)))
;; c|C
(assert (or (= (select a 2) 63) (= (select a 2) 43)))
(assert (>= x 0))
(assert (< x 3))
(assert (exists ((i Int)) (= (select a i) 72) ))
(check-sat)
Z3 say that is SAT when it shouldn't be. I'm rather new to Z3 and SMT theory, and I'm not able to figure out what is wrong with my code.
In your example, it is actually satisfiable by taking i to be any natural number outside the range 0, 1, 2. So, if you let i = 3 for example, since you have not constrained the array at index 3 in any way, it is possible that a[3] is 72.
Here is a link showing the satisfying assignment (model) to your example at the Z3#Rise interface, along with the fix described next: http://rise4fun.com/Z3/E6YI
To prevent this from occurring, one way is to restrict the range of i to be one of the array indices you've already assigned. That is, restrict i to be between 0 and 2.
(declare-const a (Array Int Int))
(declare-const x Int)
;; a|A
(assert (or (= (select a 0) 61) (= (select a 0) 41)))
;; b|B
(assert (or (= (select a 1) 62) (= (select a 1) 42)))
;; c|C
(assert (or (= (select a 2) 63) (= (select a 2) 43)))
(assert (>= x 0))
(assert (< x 3))
(assert (exists ((i Int)) (= (select a i) 72)))
(check-sat)
(get-model) ; model gives i == 3 with a[i] == 72
(assert (exists ((i Int)) (and (>= i 0) (<= i 2) (= (select a i) 72) )))
(check-sat)
Related
So I'm trying to check whether all values in an array is unique with the following Z3 code.
(declare-const A (Array Int Int))
(declare-const n Int)
(assert (forall ((i Int) (j Int)) (and (and (and (>= i 0) (< i n)) (and (>= j 0) (< j n)))
(implies (= (select A i) (select A j)) (= i j)))))
(check-sat)
I'm quite new to Z3 so I don't quite understand the grammar and stuff, but can anyone tell me whether this code is right, and if not, where's the problem?
The problem as you wrote is unsat, because it says whenever 0 <= i < n and 0 <= j < n, if A[i] = A[j], then i = j. There is no array and a particular n you can pick to satisfy this constraint.
What you really want to write is the following instead:
(declare-const A (Array Int Int))
(declare-const n Int)
(assert (forall ((i Int) (j Int)) (implies (and (>= i 0) (< i n)
(>= j 0) (< j n)
(= (select A i) (select A j)))
(= i j))))
(check-sat)
(get-model)
The above says If it's the case that i and j are within bounds, and array elements are the same, then i must equal j. And this variant would be satisifiable for any n; and indeed here's what z3 reports:
sat
(
(define-fun n () Int
0)
(define-fun A () (Array Int Int)
((as const (Array Int Int)) 0))
)
But note that z3 simply picked n = 0, which made it easy to satisfy the formula. Let's make sure we get a more interesting model, by adding:
(assert (> n 2))
Now we get:
sat
(
(define-fun n () Int
3)
(define-fun A () (Array Int Int)
(lambda ((x!1 Int))
(let ((a!1 (ite (and (<= 1 x!1) (not (<= 2 x!1))) 7 8)))
(ite (<= 1 x!1) (ite (and (<= 1 x!1) (<= 2 x!1)) 6 a!1) 5))))
)
and we see that z3 picked the array to have 3 elements with distinct values at positions we care about.
Note that this sort of reasoning with quantifiers is a soft-spot for SMT solvers; while z3 is able to find models for these cases, if you keep adding quantified axioms you'll likely get unknown as the answer, or z3 (or any other SMT solver for that matter) will take longer and longer time to respond.
I am having trouble attempting to prove this fairly simple Z3 query.
(set-option :smt.auto-config false) ; disable automatic self configuration
(set-option :smt.mbqi false) ; disable model-based quantifier instantiation
(declare-fun sum (Int) Int)
(declare-fun list () (Array Int Int))
(declare-fun i0 () Int)
(declare-fun s0 () Int)
(declare-fun i1 () Int)
(declare-fun s1 () Int)
(assert (forall ((n Int))
(! (or (not (<= n 0)) (= (sum n) 0))
:pattern ((sum n)))))
(assert (forall ((n Int))
(! (let ((a1 (= (sum n)
(+ (select list (- n 1))
(sum (- n 1))))))
(or (<= n 0) a1))
:pattern ((sum n)))))
(assert (>= i0 0))
(assert (= s0 (sum i0)))
(assert (= i1 (+ 1 i0)))
(assert (= s1 (+ 1 s0 (select list i0))))
(assert (not (= s1 (sum i1))))
(check-sat)
Seems to me that the final assertion should instantiate the second quantified statement for i1 while the assert involving s0 should instantiate the quantifiers for i0. These two should should easily lead to UNSAT.
However, Z3 returns unknown. What am I missing?
Never mind, there was an silly error in my query.
This code:
(assert (= s1 (+ 1 s0 (select list i0))))
should have been:
(assert (= s1 (+ s0 (select list i0))))
Here is a small Z3 problem that returns unknown (timeout), both in a locally built Z3 4.6.0 and on https://rise4fun.com/z3/tutorial:
(declare-const m1 (Array String Int))
(declare-const m2 (Array String Int))
(declare-const c Int)
(assert (or (= c 11) (= c 12)))
(assert (forall ((x String)) (= (select m1 x) 0)))
(assert (= (select m2 "0") 42))
(assert (forall ((x String)) (or (= x "0") (= (select m2 x) 0))))
(assert (= m2 (ite (= c 11) (store m1 "1" 100) (store m1 "0" 42))))
(check-sat)
I'm curious why z3 is not able to prove it. How is Z3 processing this problem and is there a way I can determine what Z3 is trying to do? When I run with -v:15, I see output like this:
(smt.restarting :propagations 0 :decisions 903 :conflicts 1 :restart 100 :agility 0.00)
(smt.mbqi)
(smt.propagate-values)
(smt.nnf-cnf)
(smt.reduce-asserted)
(smt.lift-ite)
(smt.maximizing-bv-sharing)
(smt.reduce-asserted)
(smt.simplifier-done)
(smt.searching)
(smt.simplifying-clause-set :num-deleted-clauses 84)
(smt.propagate-values)
(smt.nnf-cnf)
(smt.reduce-asserted)
(smt.lift-ite)
(smt.maximizing-bv-sharing)
(smt.reduce-asserted)
(smt.simplifier-done)
(smt.searching)
(smt.mbqi :failed k!8)
(smt.propagate-values)
(smt.nnf-cnf)
(smt.reduce-asserted)
(smt.lift-ite)
(smt.maximizing-bv-sharing)
(smt.reduce-asserted)
(smt.simplifier-done)
(smt.searching)
(smt.simplifying-clause-set :num-deleted-clauses 82)
(smt.propagate-values)
(smt.nnf-cnf)
(smt.reduce-asserted)
(smt.lift-ite)
(smt.maximizing-bv-sharing)
(smt.reduce-asserted)
(smt.simplifier-done)
(smt.searching)
(smt.mbqi :failed k!10)
(smt.restarting :propagations 0 :decisions 946 :conflicts 1 :restart 100 :agility 0.00)
^C(tactic-exception "canceled")
I'm not entirely sure what to make of that output. Is there a way to see more info on Z3's state at each of these points?
When I change the problem slightly to the following, it finishes immediately:
(declare-const m1 (Array String Int))
(declare-const m2 (Array String Int))
(declare-const c Int)
(assert (= c 12)) ; or (= c 11)
(assert (forall ((x String)) (= (select m1 x) 0)))
(assert (= (select m2 "0") 42))
(assert (forall ((x String)) (or (= x "0") (= (select m2 x) 0))))
(assert (= m2 (ite (= c 11) (store m1 "1" 100) (store m1 "0" 42))))
(check-sat)
Can the first problem be fixed (while letting c be indeterminate to solve for), while still requiring that m1 is 0 for all values and m2 is 0 on all values other than "0", e.g. by applying appropriate tactics or quantifier patterns?
For declaring constant arrays, you should prefer the const struct, instead of going through quantifiers. That is, replace:
(assert (forall ((x String)) (= (select m1 x) 0)))
with:
(assert (= m1 ((as const (Array String Int)) 0)))
You'll notice that z3 can now handle your query with ease.
Constant arrays are explained in the Z3 guide: https://rise4fun.com/z3/tutorialcontent/guide#h26
I'm trying to code in Z3 a very simple problem but I got confuse and I don't know how to solve it properly.
So I have an Array with these elements (Python syntax style code):
array = [0, -1, 1, 8, 43]
And I have an access to this array using an index:
x = array[index]
And finally I want to ask z3 what index I need to use to get the element 8, in my example the solution is index = 3 (starting at 0).
I am trying to code this problem in Z3, I wrote the next lines:
(declare-const x Int)
(declare-const index Int)
(assert (= x
(ite (= index 0)
0
(ite (= index 1)
-1
(ite (= index 2)
1
(ite (= index 3)
8
(ite (= index 4)
43
999999)))))))
(assert (= x 8))
(check-sat)
(get-model)
And it is working, I had this solution:
sat
(model
(define-fun index () Int
3)
(define-fun x () Int
8)
)
But I don't like the last else, the 999999. I needed to use a magic number to know when the value is not found. I tried to see if there is a "it" construction without the else, or a NULL/None/UNSAT or any special value to don't have this problem.
What is the correct way to solve this problem?
Thank you for the help!
I know nothing about the "correct" way to solve this problem, since one should probably define "correct" in the first place.
However, there are many ways in which you can encode it as an smt2 formula.
Example 0.
By simply forcing index to fall within the domain [0, 4], you can get the ite do what you want it to do without the need for any magic number.
(declare-const x Int)
(declare-const index Int)
(assert (= x
(ite (= index 0)
0
(ite (= index 1)
-1
(ite (= index 2)
1
(ite (= index 3)
8
43))))))
(assert (and (<= 0 index) (<= index 4)))
(assert (= x 8))
(check-sat)
(get-model)
which returns you the desired model:
~$ z3 example_00.smt2
sat
(model
(define-fun index () Int
3)
(define-fun x () Int
8)
)
Example 1.
(declare-const x Int)
(declare-const index Int)
(assert (ite (= index 0) (= x 0) true))
(assert (ite (= index 1) (= x (- 1)) true))
(assert (ite (= index 2) (= x 1) true))
(assert (ite (= index 3) (= x 8) true))
(assert (ite (= index 4) (= x 43) true))
(assert (and (<= 0 index) (<= index 4)))
(assert (= x 8))
(check-sat)
(get-model)
which returns you the desired model:
~$ z3 example_01.smt2
sat
(model
(define-fun index () Int
3)
(define-fun x () Int
8)
)
Example 2.
(declare-const x Int)
(declare-const index Int)
(assert (or (not (= index 0)) (= x 0))) ;; (= index 0) -> (= x 0)
(assert (or (not (= index 1)) (= x (- 1))))
(assert (or (not (= index 2)) (= x 1)))
(assert (or (not (= index 3)) (= x 8)))
(assert (or (not (= index 4)) (= x 43)))
(assert (and (<= 0 index) (<= index 4)))
(assert (= x 8))
(check-sat)
(get-model)
which returns you the desired model:
~$ z3 example_02.smt2
sat
(model
(define-fun index () Int
3)
(define-fun x () Int
8)
)
Example 3.
Using the Theory of Arrays
(declare-fun x () Int)
(declare-fun index () Int)
(declare-const ar (Array Int Int))
; array's locations initialization
(assert (= (store ar 0 0) ar))
(assert (= (store ar 1 (- 1)) ar))
(assert (= (store ar 2 1) ar))
(assert (= (store ar 3 8) ar))
(assert (= (store ar 4 43) ar))
; x = ar[index]
(assert (= (select ar index) x))
; bound index to fall within specified locations
(assert (and (<= 0 index) (<= index 4)))
; x = 8
(assert (= x 8))
; check
(check-sat)
(get-model)
which returns you the desired model:
~$ z3 example_03.smt2
sat
(model
(define-fun x () Int
8)
(define-fun ar () (Array Int Int)
(_ as-array k!0))
(define-fun index () Int
3)
(define-fun k!0 ((x!0 Int)) Int
(ite (= x!0 2) 1
(ite (= x!0 3) 8
(ite (= x!0 1) (- 1)
(ite (= x!0 0) 0
(ite (= x!0 4) 43
5))))))
)
Other examples are possible.
Ideally one would pick the encoding for which z3 has the best performance in solving your formula. On this regard I can not help you, since I typically deal with other SMT solvers.
In general, using more complex theories (e.g. Theory of Arrays) results in the run-time executing more expensive routines so one could think that it's best to avoid it. However, I would say that in my experience this is not a general rule of thumb, since even slight variations of the encoding can result in significant performance differences and very poor or naive encodings can perform pretty bad. Therefore, it's always best to perform extensive bench-marking on various candidate encodings.
I'm trying to implement the String.Containts function.
I have written some simple tests case, but the following one (which should return UNSAT) return SAT.
The test try to match the substring 'bd' in the string 'abcd' by comparig all possible substrings with the string wanted (text taken from the Z3 output):
{(exists ((i Int))
(let ((a!1 (forall ((k Int))
(and (>= k i)
(<= k (+ i 1))
(= (select stringToScan k) (select substring (- k i)))
(= (select stringToScan 0) #x0061)
(= (select stringToScan 1) #x0062)
(= (select stringToScan 2) #x0063)
(= (select stringToScan 3) #x0064)
(= (select stringToSearch 0) #x0062)
(= (select stringToSearch 1) #x0064)))))
(and (>= i 0)
(< i 2)
a!1
(= (select substring 0) (select stringToSearch 0))
(= (select substring 1) (select stringToSearch 1)))))}
I have tried various implementation, but without any success.
If you assert the formula, it returns UNSAT.
http://rise4fun.com/Z3/szN
The part:
(forall ((k Int))
(and (>= k i)
(<= k (+ i 1)) ...)))
is false becuase you can set k to i + 2 or i - 1.
You probably mean to write an implication instead of a conjunction.
Sometimes using arrays for strings is not the best way to perform the encoding.
The automata toolkit (see: http://rise4fun.com/Rex ) uses sequences.