Z3 set default value of array to zero - z3

I am trying to solve models for array expressions, where default values for array is equal to 0.
For example, I am trying to solve this example, but I get unknown results all the time
(declare-const arr (Array Int Int))
(declare-const arr2 (Array Int Int))
(declare-const a Int)
(declare-const b Int)
(assert (forall ((x Int)) (= (select arr x) 0)))
(assert (> a 0))
(assert (<= a 10))
(assert (= arr2 (store arr a 1337)))
(assert (> b 0))
(assert (<= b 10))
(assert (= (select arr2 b) 0))
(check-sat)
(get-model)

Patrick's advice on not using quantifiers is spot on! They'll make your life harder. However, you're in luck, because z3 supports constant-arrays for your use case, which is quite common. The syntax is:
(assert (= arr ((as const (Array Int Int)) 0)))
This makes sure arr will have all its entries as 0; no quantification needed and z3 handles it internally just fine.
So, your benchmark will be:
(declare-const arr (Array Int Int))
(declare-const arr2 (Array Int Int))
(declare-const a Int)
(declare-const b Int)
(assert (= arr ((as const (Array Int Int)) 0)))
(assert (> a 0))
(assert (<= a 10))
(assert (= arr2 (store arr a 1337)))
(assert (> b 0))
(assert (<= b 10))
(assert (= (select arr2 b) 0))
(check-sat)
(get-model)
which is solved in no time. This way, you can have the entire array start with 0, and modify the range you're interested in; which can depend on variables as usual and is not required to be known ahead of time.

Related

Z3 Checking whether all values in array are unique

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.

Quantifier patterns in Z3

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))))

Three ways to assgin values to an array in z3

As far as I know, there are three ways to assgin values to an array in z3.
use assert to assgin values to some of the cells:
(declare-const a1 (Array Int Int))
(declare-const a2 (Array Int Int))
(assert (= 1 (select a1 0)))
(assert (= 2 (select a2 0)))
z3 returns unsat when the constraint (assert (= a1 a2)) is added.
use as const to initialize the array first and then assgin values to specific cells:
(declare-const a3 (Array Int Int))
(assert
(=
(store ((as const (Array Int Int)) 64) 0 3)
a3
)
)
(declare-const a4 (Array Int Int))
(assert
(=
(store ((as const (Array Int Int)) 64) 0 4)
a4
)
)
Add (assert (= a3 a4)) and we obtain unsat again.
define the array via a function:
(define-const a5 (Array Int Int)
(lambda ((i Int))
(ite (= i 0) 5 64)))
(define-const a6 (Array Int Int)
(lambda ((i Int))
(ite (= i 0) 6 64)))
But if we add (assert (= a5 a6)), z3 returns sat. Why?
By the way, is there any (better) way to assign values to an array in z3?
It's a bug. Check out this issue.

Guiding z3's proof search

I'm trying to get z3 to work (most of the time) for very simple non-linear integer arithmetic problems. Unfortunately, I've hit a bit of a wall with exponentiation. I want to be able handle problems like x^{a+b+2} = (x * x * x^{a} * x{b}). I only need to handle non-negative exponents.
I tried redefining exponentiation as a recursive function (so that it's just allowed to return 1 for any non-positive exponent) and using a pattern to facilitate z3 inferring that x^{a+b} = x^{a} * x^{b}, but it doesn't seem to work - I'm still timing out.
(define-fun-rec pow ((x!1 Int) (x!2 Int)) Int
(if (<= x!2 0) 1 (* x!1 (pow x!1 (- x!2 1)))))
; split +
(assert (forall ((a Int) (b Int) (c Int))
(! (=>
(and (>= b 0) (>= c 0))
(= (pow a (+ b c)) (* (pow a c) (pow a b))))
:pattern ((pow a (+ b c))))))
; small cases
(assert (forall ((a Int)) (= 1 (pow a 0))))
(assert (forall ((a Int)) (= a (pow a 1))))
(assert (forall ((a Int)) (= (* a a) (pow a 2))))
(assert (forall ((a Int)) (= (* a a a) (pow a 3))))
; Our problem
(declare-const x Int)
(declare-const i Int)
(assert (>= i 0))
; This should be provably unsat, by splitting and the small case for 2
(assert (not (= (* (* x x) (pow x i)) (pow x (+ i 2)))))
(check-sat) ;times out
Am I using patterns incorrectly, is there a way to give stronger hints to the proof search, or an easier way to do achieve what I want?
Pattern (also called triggers) may only contain uninterpreted functions. Since + is an interpreted function, you essentially provide an invalid pattern, in which case virtually anything can happen.
As a first step, I disabled Z3's auto-configuration feature and also MBQI-based quantifier instantiation:
(set-option :auto_config false)
(set-option :smt.mbqi false)
Next, I introduced an uninterpreted plus function and replaced each application of + by plus. That sufficed to make your assertion verify (i.e. yield unsat). You can of course also axiomatise plus in terms of +, i.e.
(declare-fun plus (Int Int) Int)
(assert (forall ((a Int) (b Int))
(! (= (plus a b) (+ a b))
:pattern ((plus a b)))))
but your assertion already verifies without the definitional axioms for plus.

Z3 solve-eq how to use

I'm trying to understand how to use solve-eq, I expected Z3 to solve this
(declare-const mem (Array Int Int))
(declare-const adr_a Int)
(declare-const a Int)
(assert (= (select mem adr_a) a))
(assert (<= 0 (select mem adr_a)))
(apply solve-eqs)
into
(<= 0 a)
but I get instead
(<= 0 (select mem adr_a))
can I specify what varibales should be simplified? any other tactique could do the job?
Simple example:
(declare-const a Int)
(declare-const b Int)
(assert (= b a))
(assert (<= 0 b))
(apply solve-eqs)
the output is:
(goals (goal (<= 0 a) :precision precise :depth 1) )

Resources