z3py: How to improve the time efficiency of the following code - z3
This is a simplified code using the similar implementation idea as the z3py code for another problem I am trying to solve which is more complex and takes about 1 minute to run.
The intuition of the following code is to translate the array of integers in the inputArray into the array of months defined as EnumSort, which is essentially to infer the model of monthArray.
from z3 import *
s = Solver()
Month,(Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)=EnumSort('Month',['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'])
monthArray = Array('monthArray',IntSort(), Month)
inputArray = Array('inputArray',IntSort(),IntSort())
tempArray = Array('tempArray',IntSort(),IntSort())
intArray = [1,3,6,7,8,3,5,6,3,12,11,5,2,5,7,3,7,3,2,7,12,4,5,1,10,9]
for idx,num in enumerate(intArray):
tempArray = Store(tempArray,idx,num)
s.add(inputArray==tempArray)
length = Int('length')
s.add(length == len(intArray))
i = Int('i')
s.add(ForAll(i,Implies(And(i>=0,i<length),And(
Implies(inputArray[i]==1,monthArray[i]==Jan),
Implies(inputArray[i]==2,monthArray[i]==Feb),
Implies(inputArray[i]==3,monthArray[i]==Mar),
Implies(inputArray[i]==4,monthArray[i]==Apr),
Implies(inputArray[i]==5,monthArray[i]==May),
Implies(inputArray[i]==6,monthArray[i]==Jun),
Implies(inputArray[i]==7,monthArray[i]==Jul),
Implies(inputArray[i]==8,monthArray[i]==Aug),
Implies(inputArray[i]==9,monthArray[i]==Sep),
Implies(inputArray[i]==10,monthArray[i]==Oct),
Implies(inputArray[i]==11,monthArray[i]==Nov),
Implies(inputArray[i]==12,monthArray[i]==Dec)
))))
print s.check()
print s.model()
Could anyone give me some suggestions about the ways to improve the time efficiency using this code as an example? Thanks.
Edit:
SMT language output by calling Solver.to_smt2()
(set-info :status unknown)
(declare-datatypes () ((Month (Jan ) (Feb ) (Mar ) (Apr ) (May ) (Jun ) (Jul ) (Aug ) (Sep ) (Oct ) (Nov ) (Dec ))))
(declare-fun inputArray () (Array Int Int))
(declare-fun length () Int)
(declare-fun monthArray () (Array Int Month))
(assert
(= (select inputArray 0) 1))
(assert
(= (select inputArray 1) 3))
(assert
(= (select inputArray 2) 6))
(assert
(= (select inputArray 3) 7))
(assert
(= (select inputArray 4) 8))
(assert
(= (select inputArray 5) 3))
(assert
(= (select inputArray 6) 5))
(assert
(= (select inputArray 7) 6))
(assert
(= (select inputArray 8) 3))
(assert
(= (select inputArray 9) 12))
(assert
(= (select inputArray 10) 11))
(assert
(= (select inputArray 11) 5))
(assert
(= (select inputArray 12) 2))
(assert
(= (select inputArray 13) 5))
(assert
(= (select inputArray 14) 7))
(assert
(= (select inputArray 15) 3))
(assert
(= (select inputArray 16) 7))
(assert
(= (select inputArray 17) 3))
(assert
(= (select inputArray 18) 2))
(assert
(= (select inputArray 19) 7))
(assert
(= (select inputArray 20) 12))
(assert
(= (select inputArray 21) 4))
(assert
(= (select inputArray 22) 5))
(assert
(= (select inputArray 23) 1))
(assert
(= (select inputArray 24) 10))
(assert
(= (select inputArray 25) 9))
(assert
(= length 26))
(assert
(forall ((i Int) )(let (($x172 (=> (= (select inputArray i) 12) (= (select monthArray i) Dec))))
(let (($x175 (=> (= (select inputArray i) 11) (= (select monthArray i) Nov))))
(let (($x178 (=> (= (select inputArray i) 10) (= (select monthArray i) Oct))))
(let (($x181 (=> (= (select inputArray i) 9) (= (select monthArray i) Sep))))
(let (($x184 (=> (= (select inputArray i) 8) (= (select monthArray i) Aug))))
(let (($x187 (=> (= (select inputArray i) 7) (= (select monthArray i) Jul))))
(let (($x190 (=> (= (select inputArray i) 6) (= (select monthArray i) Jun))))
(let (($x193 (=> (= (select inputArray i) 5) (= (select monthArray i) May))))
(let (($x196 (=> (= (select inputArray i) 4) (= (select monthArray i) Apr))))
(let (($x199 (=> (= (select inputArray i) 3) (= (select monthArray i) Mar))))
(let (($x202 (=> (= (select inputArray i) 2) (= (select monthArray i) Feb))))
(let (($x205 (=> (= (select inputArray i) 1) (= (select monthArray i) Jan))))
(=> (and (>= i 0) (< i length)) (and $x205 $x202 $x199 $x196 $x193 $x190 $x187 $x184 $x181 $x178 $x175 $x172)))))))))))))))
)
(check-sat)
I find using 'qflia' (quantifier-free linear integer arithmetic) solver, instead of the general solver 'Solver()', improve the efficiency by about 3x in my case.
Related
Why does Z3 not solve this simple script with arrays and quantifiers?
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
How to code this in Z3
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.
Z3 C api : multidimensional array type variable cause invalid result
here is the Z3 context: (forall ((X (Array Int (Array Int Real))) (i Int) (j Int)) (let ((a!1 (* (- 1) (to_int (select (select X i) j))))) (= (+ (testArr X i j) a!1) 0)))) this means: forall X,i,j. testArr(X,i,j) == X[i][j] now, i try to prove two similar assert: 1 (=> (= (select (select Z i1) j1) (select (select X i) j)) (= (select (select Z i1) j1) (testArr X i j))) and 2 (=> (= v (select (select X i) j)) (= v (to_real (testArr X i j)))) the second assert Z3 return valid, but the 1st assert Z3 return invalid,and in other example Z3 sometimes return unknown. why??
Implement a formula that simulate the string Contains method
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.
Arrays and Quantifier
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)