Can options change `sat` into `unsat`? - z3

Another question from a Z3 newbie. Can options change the behavior of Z3? I might expect them to affect termination, or change sat or unsat into unknown but not sat into unsat or vice versa.
This example:
(set-option :smt.macro-finder true)
(declare-datatypes () ((Option (none) (some (Data Int)))))
(define-sort Set () (Array Option Option))
(declare-fun filter1 (Option) Option)
(declare-fun filter2 (Option) Option)
(declare-var s1 Set)
(declare-var s2 Set)
(declare-var x1 Option)
(declare-var x2 Option)
(declare-var x3 Option)
(declare-var x4 Option)
(assert (not (= x1 none)))
(assert (not (= x2 none)))
(assert (not (= x3 none)))
(assert (not (= x4 none)))
(assert (= (select s1 x1) x2))
(assert (= (select s2 x3) x4))
(assert (forall ((x Option)) (= (filter1 x) (ite (or (= none x) (= (Data x) 1)) x none))))
(assert (forall ((x Option)) (= (filter2 x) (ite (or (= none x) (= (Data x) 2)) x none))))
(assert (= ((_ map filter1) s1) s2))
(assert (= ((_ map filter2) s1) s2))
(check-sat)
(get-model)
returns sat with the first line and unsat without it.
Is this a bug or am I missing something fundamental?

This is a bug. The two quantifiers are essentially providing "definitions" for filter1 and filter2.
The option smt.macro-finder is used to eliminate functions symbols by expanding these definitions. It is essentially performing "macro expansion". However, there is a bug in the macro expander. It does not expand the occurrences of filter1 and filter2 in the map constructs: (_ map filter1) and (_ map filter2).
This bug will be fixed.
In the meantime, we should not use the map construct and smt.macro-finder option simultaneously.

Related

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

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

How to obtain a non-trivial model of an idempotent quasigroup using Z3

I am trying to obtain a non-trivial model of an idempotent quasigroup using Z3 with the following code
(set-logic AUFNIRA)
(set-option :macro-finder true)
(set-option :mbqi true)
(set-option :pull-nested-quantifiers true)
(declare-sort S 0)
(declare-fun prod (S S) S)
(declare-fun left (S S) S)
(declare-fun right (S S) S)
(assert (forall ((x S) (y S))
(= (prod (left x y) y) x)))
(assert (forall ((x S) (y S))
(= (prod x (right x y) ) y)))
(assert (forall ((x S) (y S))
(= (left (prod x y) y ) x)))
(assert (forall ((x S) (y S))
(= (right x (prod x y)) y)))
(assert (forall ((x S)) (= (prod x x) x) ))
(check-sat)
(get-model)
but I am obtaining only a trivial model:
sat
(model
;; universe for S:
;; S!val!0
;; -----------
;; definitions for universe elements:
(declare-fun S!val!0 () S)
;; cardinality constraint:
(forall ((x S)) (= x S!val!0))
;; -----------
(define-fun elem!3 () S
S!val!0)
(define-fun elem!2 () S
S!val!0)
(define-fun elem!0 () S
S!val!0)
(define-fun elem!1 () S
S!val!0)
(define-fun left ((x!1 S) (x!2 S)) S
S!val!0)
(define-fun right ((x!1 S) (x!2 S)) S
S!val!0)
(define-fun prod ((x!1 S) (x!2 S)) S
x!1)
)
Run this example online here
Please let me know how we can obtain a non-trivial model. Many thanks.
If I understand right, you want to find more than one sat model for the original assertions.
I have a dull solution here. You can define another set of functions in the same way as prod, left and right, which are named prod2, left2 and right2. Add assertions for them similarly. Then, you want prod2 to differ from prod.
Like this:
(assert (exists ((x S) (y S)) (not (= (prod x y) (prod2 x y)))))
or maybe expression meaning or(prod != prod2, left != left2, right != right2) will be more proper.
I took a little attempt to run that online, but returned 'time out'. I think you have to do it on your machine.
This may be not a best answer, but best regards!

Sort name issue in Z3

In a previous post Z3 group some group axioms were proved using a sort named S to represent the group. Please run the code code with sort named S But now when the name of the sort is changed to G the code does not work. Please look the issue on line code with sort named G It is necessary to use the name S for the sort or it is an issue of Z3? Please let me know.
A simplified version of the issue.
$ z3 -version
Z3 version 4.3.1
Using the name S:
$ cat S.smt
(declare-sort S)
(declare-fun f (S S) S)
(declare-const a S)
(declare-const b S)
(assert (= (f a a) a))
(assert (= (f a b) b))
(assert (= (f b a) b))
(assert (= (f b b) a))
(check-sat)
;; Restrict the search to models of size at most 2.
(assert (forall ((x S)) (or (= x a) (= x b))))
;; Associativity
(assert (not (forall ((x S) (y S) (z S)) (= (f x (f y z)) (f (f x y) z)))))
(check-sat)
$ z3 -smt2 S.smt
sat
unsat
Using the name G:
$ cat G.smt
(declare-sort G)
(declare-fun f (G G) G)
(declare-const a G)
(declare-const b G)
(assert (= (f a a) a))
(assert (= (f a b) b))
(assert (= (f b a) b))
(assert (= (f b b) a))
(check-sat)
;; Restrict the search to models of size at most 2
(assert (forall ((x G)) (or (= x a) (= x b))))
;; Associativity
(assert (not (forall ((x G) (y G) (z G)) (= (f x (f y z)) (f (f x y) z)))))
(check-sat)
$ z3 -smt2 G.smt
sat
unknown
Please let ne know if the following code with the sort named G is correct. Many thanks
(declare-sort G)
(declare-fun f (G G) G)
(declare-const a G)
(declare-const b G)
(declare-const c G)
(assert (forall ((x G) (y G))
(= (f x y) (f y x))))
(assert (forall ((x G))
(= (f x a) x)))
(assert (= (f b b) c))
(assert (= (f b c) a))
(assert (= (f c c) b))
(check-sat)
(get-model)
(push)
;; prove the left-module axiom
(assert (not (forall ((x G)) (= (f a x) x ))) )
(check-sat)
(pop)
(push)
;; prove the right-module axiom
(assert (not (forall ((x G)) (= (f x a) x ))) )
(check-sat)
(pop)
(declare-fun x () G)
(declare-fun y () G)
(declare-fun z () G)
(push)
;; prove the right-inverse axiom
(assert (not (=> (and (or (= x a) (= x b) (= x c))) (exists ((y G)) (= (f x y) a)))))
(check-sat)
(pop)
(push)
;; prove the left-inverse axiom
(assert (not (=> (and (or (= x a) (= x b) (= x c))) (exists ((y G)) (= (f y x ) a)))))
(check-sat)
(pop)
(push)
;; prove the associativity axiom
(assert (not (=> (and (or (= x a) (= x b) (= x c)) (or (= y a) (= y b) (= y c))
(or (= z a) (= z b) (= z c)))
(= (f x (f y z)) (f (f x y) z)))))
(check-sat)
(pop)
(push)
;; prove the commutative property
(assert (not (=> (and (or (= x a) (= x b) (= x c)) (or (= y a) (= y b) (= y c)))
(= (f x y ) (f y x )))))
(check-sat)
(pop)
and the corresponding output is the expected
sat unsat unsat unsat unsat unsat unsat
Please run this code online here

Defining injective functions in Z3

My goal is to define an injective function f: Int -> Term, where Term is some new sort. Having referred to the definition of the injective function, I wrote the following:
(declare-sort Term)
(declare-fun f (Int) Term)
(assert (forall ((x Int) (y Int))
(=> (= (f x) (f y)) (= x y))))
(check-sat)
This causes a timeout. I suspect that this is because the solver tries to validate the assertion for all values in the Int domain, which is infinite.
I also checked that the model described above works for some custom sort instead of Int:
(declare-sort Term)
(declare-sort A)
(declare-fun f (A) Term)
(assert (forall ((x A) (y A))
(=> (= (f x) (f y)) (= x y))))
(declare-const x A)
(declare-const y A)
(assert (and (not (= x y)) (= (f x) (f y))))
(check-sat)
(get-model)
The first question is how to implement the same model for Int sort instead of A. Can solver do this?
I also found the injective function example in the tutorial in multi-patterns section. I don't quite get why :pattern annotation is helpful. So the second question is why :pattern is used and what does it brings to this example particularly.
I am trying this
(declare-sort Term)
(declare-const x Int)
(declare-const y Int)
(declare-fun f (Int) Term)
(define-fun biyect () Bool
(=> (= (f x) (f y)) (= x y)))
(assert (not biyect))
(check-sat)
(get-model)
and I am obtaining this
sat
(model
;; universe for Term:
;; Term!val!0
;; -----------
;; definitions for universe elements:
(declare-fun Term!val!0 () Term)
;; cardinality constraint:
(forall ((x Term)) (= x Term!val !0))
;; -----------
(define-fun y () Int
1)
(define-fun x () Int
0)
(define-fun f ((x!1 Int)) Term
(ite (= x!1 0) Term!val!0
(ite (= x!1 1) Term!val!0
Term!val!0)))
)
What do you think about this
(declare-sort Term)
(declare-fun f (Int) Term)
(define-fun biyect () Bool
(forall ((x Int) (y Int))
(=> (= (f x) (f y)) (= x y))))
(assert (not biyect))
(check-sat)
(get-model)
and the output is
sat
(model
;; universe for Term:
;; Term!val!0
;; -----------
;; definitions for universe elements:
(declare-fun Term!val!0 () Term)
;; cardinality constraint:
(forall ((x Term)) (= x Term!val!0))
;; -----------
(define-fun x!1 () Int 0)
(define-fun y!0 () Int 1)
(define-fun f ((x!1 Int)) Term
(ite (= x!1 0) Term!val!0
(ite (= x!1 1) Term!val!0
Term!val!0)))
)

Resources