How to encode a fixed number of true variables? - z3

I have say 10 boolean variables. I want the model to be satisfiable if exactly 3 of them are true.
How would I encode this as a SAT problem? One way would to create the all the possible combinations and then or them together. Is there a better or more concise way to express this?

If your application allows, I would suggest using a different encoding (e.g., bitvectors or ints), as this makes things much easier and avoids the permutation part at the encoding level. For example, use ints and restrict the values to be 0 or 1, then assert their sum is 3.
Here's an encoding (rise4fun link: http://rise4fun.com/Z3/wswe ):
(declare-fun b0 () Int)
(declare-fun b1 () Int)
(declare-fun b2 () Int)
(declare-fun b3 () Int)
(declare-fun b4 () Int)
(declare-fun b5 () Int)
(declare-fun b6 () Int)
(declare-fun b7 () Int)
(declare-fun b8 () Int)
(declare-fun b9 () Int)
(assert (= (+ b0 b1 b2 b3 b4 b5 b6 b7 b8 b9) 3))
(assert (or (= b0 0) (= b0 1)))
(assert (or (= b1 0) (= b1 1)))
(assert (or (= b2 0) (= b2 1)))
(assert (or (= b3 0) (= b3 1)))
(assert (or (= b4 0) (= b4 1)))
(assert (or (= b5 0) (= b5 1)))
(assert (or (= b6 0) (= b6 1)))
(assert (or (= b7 0) (= b7 1)))
(assert (or (= b8 0) (= b8 1)))
(assert (or (= b9 0) (= b9 1)))
(check-sat)
(get-model)
Result is:
sat
(model
(define-fun b6 () Int
0)
(define-fun b5 () Int
0)
(define-fun b9 () Int
1)
(define-fun b3 () Int
0)
(define-fun b2 () Int
0)
(define-fun b7 () Int
0)
(define-fun b1 () Int
0)
(define-fun b8 () Int
1)
(define-fun b4 () Int
0)
(define-fun b0 () Int
1)
)
EDIT: added bitvector example for completeness, can be improved by doing padding so we can compare bitvectors of different sizes (rise4fun link: http://rise4fun.com/Z3/UsldZ ):
(declare-fun b0 () (_ BitVec 3))
(declare-fun b1 () (_ BitVec 3))
(declare-fun b2 () (_ BitVec 3))
(declare-fun b3 () (_ BitVec 3))
(declare-fun b4 () (_ BitVec 3))
(declare-fun b5 () (_ BitVec 3))
(declare-fun b6 () (_ BitVec 3))
(declare-fun b7 () (_ BitVec 3))
(declare-fun b8 () (_ BitVec 3))
(declare-fun b9 () (_ BitVec 3))
(assert (= (bvadd b0 b1 b2 b3 b4 b5 b6 b7 b8 b9) #b011))
; can probably avoid the next by using a length 1 bitvector and padding, but not sure how to do padding
(assert (or (= b0 #b000) (= b0 #b001)))
(assert (or (= b1 #b000) (= b1 #b001)))
(assert (or (= b2 #b000) (= b2 #b001)))
(assert (or (= b3 #b000) (= b3 #b001)))
(assert (or (= b4 #b000) (= b4 #b001)))
(assert (or (= b5 #b000) (= b5 #b001)))
(assert (or (= b6 #b000) (= b6 #b001)))
(assert (or (= b7 #b000) (= b7 #b001)))
(assert (or (= b8 #b000) (= b8 #b001)))
(assert (or (= b9 #b000) (= b9 #b001)))
(check-sat)
(get-model)
Result is:
sat
(model
(define-fun b6 () (_ BitVec 3)
#b000)
(define-fun b5 () (_ BitVec 3)
#b000)
(define-fun b9 () (_ BitVec 3)
#b001)
(define-fun b3 () (_ BitVec 3)
#b000)
(define-fun b0 () (_ BitVec 3)
#b001)
(define-fun b2 () (_ BitVec 3)
#b000)
(define-fun b7 () (_ BitVec 3)
#b000)
(define-fun b1 () (_ BitVec 3)
#b001)
(define-fun b8 () (_ BitVec 3)
#b000)
(define-fun b4 () (_ BitVec 3)
#b000)
)

Related

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.

Z3 returns model not available

If possible I'd like a second opinion on my code.
The constraints of the problem are:
a,b,c,d,e,f are non-zero integers
s1 = [a,b,c] and s2 = [d,e,f] are sets
The sum s1_i + s2_j for i,j = 0..2 has to be a perfect square
I don't understand why but my code returns model not available. Moreover, when commenting out the following lines:
(assert (and (> sqrtx4 1) (= x4 (* sqrtx4 sqrtx4))))
(assert (and (> sqrtx5 1) (= x5 (* sqrtx5 sqrtx5))))
(assert (and (> sqrtx6 1) (= x6 (* sqrtx6 sqrtx6))))
(assert (and (> sqrtx7 1) (= x7 (* sqrtx7 sqrtx7))))
(assert (and (> sqrtx8 1) (= x8 (* sqrtx8 sqrtx8))))
(assert (and (> sqrtx9 1) (= x9 (* sqrtx9 sqrtx9))))
The values for d, e, f are negative. There is no constraint that requires them to do so. I'm wondering if perhaps there are some hidden constraints that sneaked in and mess up the model.
A valid expected solution would be:
a = 3
b = 168
c = 483
d = 1
e = 193
f = 673
Edit: inserting (assert (= a 3)) and (assert (= b 168)) results in the solver finding the correct values. This only puzzles me further.
Full code:
(declare-fun sqrtx1 () Int)
(declare-fun sqrtx2 () Int)
(declare-fun sqrtx3 () Int)
(declare-fun sqrtx4 () Int)
(declare-fun sqrtx5 () Int)
(declare-fun sqrtx6 () Int)
(declare-fun sqrtx7 () Int)
(declare-fun sqrtx8 () Int)
(declare-fun sqrtx9 () Int)
(declare-fun a () Int)
(declare-fun b () Int)
(declare-fun c () Int)
(declare-fun d () Int)
(declare-fun e () Int)
(declare-fun f () Int)
(declare-fun x1 () Int)
(declare-fun x2 () Int)
(declare-fun x3 () Int)
(declare-fun x4 () Int)
(declare-fun x5 () Int)
(declare-fun x6 () Int)
(declare-fun x7 () Int)
(declare-fun x8 () Int)
(declare-fun x9 () Int)
;all numbers are non-zero integers
(assert (not (= a 0)))
(assert (not (= b 0)))
(assert (not (= c 0)))
(assert (not (= d 0)))
(assert (not (= e 0)))
(assert (not (= f 0)))
;both arrays need to be sets
(assert (not (= a b)))
(assert (not (= a c)))
(assert (not (= b c)))
(assert (not (= d e)))
(assert (not (= d f)))
(assert (not (= e f)))
(assert (and (> sqrtx1 1) (= x1 (* sqrtx1 sqrtx1))))
(assert (and (> sqrtx2 1) (= x2 (* sqrtx2 sqrtx2))))
(assert (and (> sqrtx3 1) (= x3 (* sqrtx3 sqrtx3))))
(assert (and (> sqrtx4 1) (= x4 (* sqrtx4 sqrtx4))))
(assert (and (> sqrtx5 1) (= x5 (* sqrtx5 sqrtx5))))
(assert (and (> sqrtx6 1) (= x6 (* sqrtx6 sqrtx6))))
(assert (and (> sqrtx7 1) (= x7 (* sqrtx7 sqrtx7))))
(assert (and (> sqrtx8 1) (= x8 (* sqrtx8 sqrtx8))))
(assert (and (> sqrtx9 1) (= x9 (* sqrtx9 sqrtx9))))
;all combinations of sums need to be squared
(assert (= (+ a d) x1))
(assert (= (+ a e) x2))
(assert (= (+ a f) x3))
(assert (= (+ b d) x4))
(assert (= (+ b e) x5))
(assert (= (+ b f) x6))
(assert (= (+ c d) x7))
(assert (= (+ c e) x8))
(assert (= (+ c f) x9))
(check-sat-using (then simplify solve-eqs smt))
(get-model)
(get-value (a))
(get-value (b))
(get-value (c))
(get-value (d))
(get-value (e))
(get-value (f))
Nonlinear integer arithmetic is undecidable. This means that there is no decision procedure that can decide arbitrary non-linear integer constraints to be satisfiable. This is what z3 is telling you when it says "unknown" as the answer your query.
This, of course, does not mean that individual cases cannot be answered. Z3 has certain tactics it applies to solve such formulas, but it is inherently limited in what it can handle. Your problem falls into that category: One that Z3 is just not capable of solving.
Z3 has a dedicated NRA (non-linear real arithmetic) tactic that you can utilize. It essentially treats all variables as reals, solves the problem (nonlinear real arithmetic is decidable and z3 can find all algebraic real solutions), and then checks if the results are actually integer. If not, it tries another solution over the reals. Sometimes this tactic can handle non-linear integer problems, if you happen to hit the right solution. You can trigger it using:
(check-sat-using qfnra)
Unfortunately it doesn't solve your particular problem in the time I allowed it to run. (More than 10 minutes.) It's unlikely it'll ever hit the right solution.
You really don't have many options here. SMT solvers are just not a good fit for nonlinear integer problems. In fact, as I alluded to above, there is no tool that can handle arbitrary nonlinear integer problems due to undecidability; but some tools fare better than others depending on the algorithms they use.
When you tell z3 what a and b are, you are essentially taking away much of the non-linearity, and the rest becomes easy to handle. It is possible that you can find a sequence of tactics to apply that solves your original, but such tricks are very brittle in practice and not easily discovered; as you are essentially introducing heuristics into the search and you don't have much control over how that behaves.
Side note: Your script can be improved slightly. To express that a bunch of numbers are all different, use the distinct predicate:
(assert (distinct (a b c)))
(assert (distinct (d e f)))

Z3 Solver outputting the satisfying model?

In Z3, if the input script is written in SMTLib format, is it possible to output the model (value assignments satisfying the model)? The get-model returns an interpretation satisfying the constraints. Is there any way to extract the concrete values from these interpretations. I am aware that we can use the python/C++ API to get model values.
You probably want to use get-value, here's a minimal example (rise4fun link: http://rise4fun.com/Z3/wR81 ):
(declare-fun x () Int)
(declare-fun y () Int)
(declare-fun z () Int)
(assert (>= (* 2 x) (+ y z)))
(declare-fun f (Int) Int)
(declare-fun g (Int Int) Int)
(assert (< (f x) (g x x)))
(assert (> (f y) (g x x)))
(check-sat) ; sat
(get-model) ; returns:
; (model
; (define-fun z () Int
; 0)
; (define-fun y () Int
; (- 38))
; (define-fun x () Int
; 0)
; (define-fun g ((x!1 Int) (x!2 Int)) Int
; (ite (and (= x!1 0) (= x!2 0)) 0
; 0))
; (define-fun f ((x!1 Int)) Int
; (ite (= x!1 0) (- 1)
; (ite (= x!1 (- 38)) 1
; (- 1))))
;)
(get-value (x)) ; returns ((x 0))
(get-value ((f x))) ; returns (((f x) (- 1)))
You'd potentially then have to parse this depending on what you're trying to do, etc.
For more details, check out the SMT-LIB standard:
http://smtlib.cs.uiowa.edu/language.shtml
The latest version is: http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.0-r12.09.09.pdf
You can see some examples of get-value on page 39 / figure 3.5.

How can I write a long smt-lib expression with an existential quantifier?

I have the following expression
(declare-fun x00 () Real)
(declare-fun x01 () Real)
(declare-fun x10 () Real)
(declare-fun x11 () Real)
(declare-fun t0init () Real)
(declare-fun z0init0 () Real)
(declare-fun z0init1 () Real)
(assert (>= t0init 0))
(assert (= (+ x00 z0init0) x10))
(assert (= (+ x01 z0init1) x11))
(assert (< (+ (* 1 x00)(* 0 x01)) 0.0))
(assert (= (+ (* 0 x00)(* 1 x01)) 0.0))
(assert (< (+ (* 1 x10)(* 0 x11)) 0.0))
(assert (= (+ (* 0 x10)(* 1 x11)) 0.0))
...
(assert (< (+ (* 1 x40)(* 0 x41)) 0.0))
(assert (= (+ (* 0 x40)(* 1 x41)) 0.0))
(assert (= (+ (* 1 z4end0)(* 0 z4end1)) (* t4end 1)))
(assert (= (+ (* 0 z4end0)(* 1 z4end1)) (* t4end -2)))
and I would like to express as a simple formula in order to express the following:
(assert exists (x00 x01) ("the above expression"))
and then perform a quantifier elimination.
Is there anyone who knows how to proceed?
I know how to do it with z3py but I need some faster solution.
Thank you very much for any hint.
One possible solution is as follows
(declare-fun x00 () Real)
(declare-fun x01 () Real)
(declare-fun x10 () Real)
(declare-fun x11 () Real)
(declare-fun t0init () Real)
(declare-fun z0init0 () Real)
(declare-fun z0init1 () Real)
(define-fun conjecture () Bool
(and (>= t0init 0) (= (+ x00 z0init0) x10) (= (+ x01 z0init1) x11)))
(assert (exists ((x00 Real) (x01 Real)) conjecture))
(check-sat)
and the corresponding output is
sat
I am not sure if the quantifier elimination that you need will work with Z3. Maybe for your problem "Redlog" of "Reduce" is the better option. All the best.

soundness issue with integer/bv mixed benchmarks?

I've the following SMT-Lib2 script:
(set-option :produce-models true)
(declare-fun s0 () Int)
(declare-fun table0 (Int) (_ BitVec 8))
(assert (= (table0 0) #x00))
(assert
(let ((s3 (ite (or (< s0 0) (<= 1 s0)) #x01 (table0 s0))))
(let ((s5 (ite (bvuge s3 #x02) #b1 #b0)))
(= s5 #b1))))
(check-sat)
(get-model)
With Z3 v3.2 running on the Mac, I get:
sat
(model
;; universe for (_ BitVec 8):
;; bv!val!2 bv!val!3 bv!val!0 bv!val!1
;; -----------
;; definitions for universe elements:
(declare-fun bv!val!2 () (_ BitVec 8))
(declare-fun bv!val!3 () (_ BitVec 8))
(declare-fun bv!val!0 () (_ BitVec 8))
(declare-fun bv!val!1 () (_ BitVec 8))
;; cardinality constraint:
(forall ((x (_ BitVec 8)))
(and (= x bv!val!2) (= x bv!val!3) (= x bv!val!0) (= x bv!val!1)))
;; -----------
(define-fun s0 () Int
(- 1))
(define-fun table0 ((x!1 Int)) (_ BitVec 8)
(ite (= x!1 0) bv!val!0
(ite (= x!1 (- 1)) bv!val!3
bv!val!0)))
)
Which states that s0 = -1 is a model. However, with s0 = -1, we have s3 = 1 and s5 = #b0, which makes the assertion false. In fact, I'm quite sure the benchmark as stated is unsatisfiable.
One thing I noticed in the Z3 output is the quantified formula it gives for the cardinality constraint. It says:
;; cardinality constraint:
(forall ((x (_ BitVec 8)))
(and (= x bv!val!2) (= x bv!val!3) (= x bv!val!0) (= x bv!val!1)))
The assertion is a conjunction, which sounds rather weird; shouldn't that be a disjunction? I'm not sure if this is the root-cause of the problem, but it sure sounds fishy.
There are two problems in Z3.
First, you are correct, there is a typo in the model printer. It should be a "or" instead of an "and". The second problem is that Z3 did not install the bit-vector theory and treated (_ BitVec 8) as a uninterpreted sort. This was a bug in the preprocessor that is used to decide in which logic the problem is in. You can workaround this bug by adding the following command in the beginning of the file:
(set-option :auto-config false)
These bugs have been fixed, and the fix will be available in the next release.

Resources