Simplify function interpretation in model - z3

In SMT: check uniqueness and totality of function I gave a function axiomatization and asked Z3 for a model. However because solving something with quantifiers in it is undecidable in general, Z3 times out.
Here is a modified version in which the "int" case is modelled as a single value:
(declare-datatypes () ((ABC int error none)))
(declare-fun f (ABC ABC) ABC)
(assert (forall ((x ABC)) (=> (or (= x int) (= x error) (= x none)) (= (f none x) none))))
(assert (forall ((x ABC)) (=> (or (= x int) (= x error) (= x none)) (= (f x none) none))))
(assert (forall ((x ABC)) (=> (or (= x int) (= x error)) (= (f error x) error))))
(assert (forall ((x ABC)) (=> (or (= x int) (= x error)) (= (f x error) error))))
(assert (forall ((x ABC) (y ABC)) (=> (and (= x int) (= y int)) (= (f x y) int))))
(check-sat)
(get-model)
Because there now are finitely many cases, Z3 gives an answer quickly:
sat
(model
(define-fun k!26 ((x!0 ABC)) ABC
(ite (= x!0 error) error
(ite (= x!0 int) int
none)))
(define-fun f!28 ((x!0 ABC) (x!1 ABC)) ABC
(ite (and (= x!0 error) (= x!1 int)) error
(ite (and (= x!0 int) (= x!1 error)) error
(ite (and (= x!0 error) (= x!1 error)) error
(ite (and (= x!0 int) (= x!1 int)) int
none)))))
(define-fun k!27 ((x!0 ABC)) ABC
(ite (= x!0 error) error
(ite (= x!0 int) int
none)))
(define-fun f ((x!0 ABC) (x!1 ABC)) ABC
(f!28 (k!27 x!0) (k!26 x!1)))
)
Both k!26 and k!27 actually just return their input (this is easily seen by checking all three cases). Is it possible to simplify the model by eliminating these two functions automatically?
Optimally I would like to have something like the following, although I see that might not be possible:
(define-fun f ((x!0 ABC) (x!1 ABC)) ABC
(ite (or (= x!0 none) (= x!1 none)) none
(ite (or (= x!0 error) (= x!1 error)) error
int)))
I'm using Z3Py, but both general Z3-specific and Z3Py-specific answers are welcome.

I don't think there's much you can do to guide Z3 to provide a "simpler" answer here; as the model generated depends on how the proof was done and even simple changes to the problem can have unpredictable results. In particular, the model you get can change with the next version of Z3.
Having said that, a common trick is to eval terms in the model. Since your current problem only involves a finite domain, you can enumerate it. If you add the following lines at the end of your script:
(eval (f int int))
(eval (f int error))
(eval (f int none))
(eval (f error int))
(eval (f error error))
(eval (f error none))
(eval (f none int))
(eval (f none error))
(eval (f none none))
Then Z3 will print:
int
error
none
error
error
none
none
none
none
Perhaps you can use that output to construct a "simpler" model yourself. Of course, this only works if the domain is finite; but you can use the same trick to evaluate "interesting" parts of the input domain, depending on your problem.

Related

Microsoft Z3 solution format understanding

I'm solving SAT problem with Z3. And I get this assignment form Z3:
(model
(define-fun B ((x!0 Int))
(ite (= x!0 1) false
(ite (= x!0 2) false
true)))
(define-fun D ((x!0 Int))
(or (= x!0 3) (= x!0 1))
(define-fun A ((x!0 Int))
(ite (= x!0 1) false
(ite (= x!0 4) false
true)))
(define-fun C ((x!0 Int))
(ite (= x!0 5) false
true))
I can understand it for B, D, C (B1,B2 are false and others(B3,B4,B5) are true).
But how can you meaningfully interpret this OR formula for D? It should be that D1 and D3 are true and D2,D4,D5 are false and it seems it gives right answer. But why it present it in such strange form?
Model printing is not standardized in SMTLib, and depending on what underlying types you use (functions, arrays, scalar types etc.) Z3 will print in some internal format.
To get individual values, you can always do:
(eval (D 0))
etc. to retrieve individual values.

How can I change the standard behavior of z3 functions?

I have a (get-model) query for Z3 which returns this function:
(define-fun rules ((x!0 Tree)) Bool
(ite (= x!0 (node "mann" (cons (node "adam" nil) nil))) true
(ite (= x!0 (node "mensch" (cons (node "adam" nil) nil))) true
true)))
When using this code:
(declare-datatypes () ((Tree leaf (node (value String) (children TreeList)))
(TreeList nil (cons (car Tree) (cdr TreeList)))))
(declare-const list TreeList)
(declare-const fact1 Tree)
(declare-const fact2 Tree)
(assert (not (is-leaf fact1)))
(assert (not (is-leaf fact2)))
(assert (not (= list nil)))
(assert (= (value fact1) "mann"))
(assert (= (value fact2) "adam"))
(assert (= (children fact1) list))
(assert (= fact2 (car list)))
(declare-const list2 TreeList)
(declare-const fact3 Tree)
(declare-const fact4 Tree)
(assert (not (is-leaf fact3)))
(assert (not (is-leaf fact4)))
(assert (not (= list2 nil)))
(assert (= (value fact3) "mensch"))
(assert (= (value fact4) "adam"))
(assert (= (children fact3) list2))
(assert (= fact4 (car list2)))
(declare-fun rules (Tree) Bool)
(assert (= (rules fact1) true))
(assert (=> (rules fact1) (rules fact3)))
(check-sat)
(get-model)
The problem is I need the function "rules" to return false, whenever the argument is not one of the trees I have asserted rules for it to be true, but I can't find a way to edit the last "else" in the function. (get-model) seems to always use the most common answer of the function as it's answer if none of the rules work and since I only have rules for trees which make the answer true it uses true for the else as well, but I can't use the function that way.
It seems you're trying to model Prolog like "closed-world" assumption here. This is not how SMT solvers work: They will find a model that will satisfy all the requirements, and everything else is fair game. That is, if you want no other value to satisfy your rules, then you have to state that explicitly.
You might want to look at datalog modeling though, which seems closer to what you are trying to express: https://rise4fun.com/z3/tutorialcontent/fixedpoints

Why does Z3 give no response on the following input?

I originally posted the question as shown below the dotted line, but since then I have an even simpler example:
(declare-fun f (Int) Int)
(assert (= (f 10) 1))
(check-sat)
(get-model)
produces an interpretation for f as expected. However change the constant to anything but 10, and Z3 just spins the arrowhead a couple of times but then prints nothing!
--------------------------------------- original question -----------------------------
I tried Z3 on the following input and the arrowhead turns a few times and stops but Z3 prints or says nothing. Why?
(declare-fun f (Int Int) Int)
(assert (>= (f 1 1) 1))
(assert (>= (f 1 2) 2))
(assert (>= (f 2 1) 2))
(assert (>= (f 2 2) 2))
(assert (= (f 1 1) 1))
(assert (= (f 2 2) 2))
(assert (or (= (f 1 2) 1) (= (f 1 2) 2)))
(assert (or (= (f 2 1) 1) (= (f 2 1) 2)))
(check-sat)
(get-model)
I feel like I'm missing something really obvious..
I am obtaining (using iZ3, Z3 unstable branch)
sat
(model
(define-fun f ((x!1 Int) (x!2 Int)) Int
(ite (and (= x!1 1) (= x!2 1)) 1
(ite (and (= x!1 2) (= x!2 2)) 2
(ite (and (= x!1 1) (= x!2 2)) 2
(ite (and (= x!1 2) (= x!2 1)) 2 2)))))
)
Run this example online here
I presume you're using Z3 on rise4fun? The version running there may be a little out of date. We have to manually update the binary there. If it doesn't reply, it's either because it times out, or because there was some other problem (e.g., segfault). It's quite possible that the version on rise4fun exhibits some bug that's already been fixed in other version of Z3 (e.g., unstable, iZ3, etc).

mysterious 'unknown' from Z3

I'm writing a proofchecker for a novel program logic, dealing with weak memory. Z3 does the heavy lifting: I translate all my checks into ASTs and throw them at Z3 using the ML binding. (But, see below, I've checked that Z3 online, via rise4fun, gives the same answer). Here's the implication I would like to check, pretty-printed so I can understand the operator nesting, with the names slightly simplified so it's easy to see what they are:
r1=1
=> y=1
/\ x=1
/\ xnew=x
/\ ynew=2
=> xnew=x
/\ ynew=y
\/ Exists(r1)
r1=1
=> y=1
/\ x=1
/\ xnew=x
/\ ynew=2
This translates into ASTs nicely (type declarations not shown, but see below for actual Z3 input):
(let ((a1 (and (=> (= r1 1) (and (= y 1) (= x 1)))
(= xnew x)
(= ynew 2)))
(a2 (exists ((r1 Int))
(and (=> (= r1 1) (and (= y 1) (= x 1)))
(= xnew x)
(= ynew 2)))))
(=> a1 (or
(and (= xnew x) (= ynew y)) a2)))
So that's all fine. But Z3 says 'unknown'. Oddly, this is the only one of many thousands of queries in all my tests which gives this result. So I investigated with the online version of Z3, via the rise4fun tutorial, which accepted this input
(declare-const r1 Int)
(declare-const y Int)
(declare-const x Int)
(declare-const xnew Int)
(declare-const ynew Int)
(define-fun a1 () Bool
(and (=> (= r1 1) (and (= y 1) (= x 1)))
(= xnew x)
(= ynew 2))
)
(define-fun a2 () Bool
(exists ((r1 Int))
(and (=> (= r1 1) (and (= y 1) (= x 1)))
(= xnew x)
(= ynew 2)))
)
(define-fun conjecture () Bool
(=> a1 (or (and (= xnew x) (= ynew y)) a2))
)
(assert (not conjecture))
(check-sat)
and said 'unknown'.
Am I making a simple error, or is this a bug, or what?
This seems to be a bug in the master branch and in the executable used online.
The behavior does not reproduce in the latest unstable branch.

Z3 will not case split on hand-crafted data types

I have defined my own booleans, called boolean is SMT2, and the AND function boolean_and over them.
My conjecture is that AND is commutative:
(declare-sort boolean)
(declare-const sk_x boolean)
(declare-const sk_y boolean)
(declare-const boolean_false boolean)
(declare-const boolean_true boolean)
(declare-fun boolean_and (boolean boolean) boolean)
;; axiomatize booleans: false /= true and every bool is true or false
(assert (forall ((x boolean)) (or (= x boolean_false)
(= x boolean_true))))
(assert (not (= boolean_false boolean_true)))
;; definition of AND
(assert (forall ((a boolean)) (= (boolean_and boolean_false a) boolean_false)))
(assert (forall ((a boolean)) (= (boolean_and boolean_true a) a)))
;; try to prove that AND is commutative
(assert (not (= (boolean_and sk_x sk_y)
(boolean_and sk_y sk_x))))
(check-sat)
However, z3 reports unknown on this problem after a while, even though I
thought it should be able to use my case split assertions on the skolemised
variables sk_x and sk_y.
Curiously, if I remove my boolean axiomatization and replace it with
declare-datatypes, z3 will report unsat:
(declare-datatypes () ((boolean (boolean_true) (boolean_false))))
(declare-const sk_x boolean)
(declare-const sk_y boolean)
(declare-fun boolean_and (boolean boolean) boolean)
(assert (forall ((a boolean)) (= (boolean_and boolean_false a) boolean_false)))
(assert (forall ((a boolean)) (= (boolean_and boolean_true a) a)))
(assert (not (= (boolean_and sk_x sk_y)
(boolean_and sk_y sk_x))))
(check-sat)
What am I doing wrong? How can I get z3 to case split using my axiomatization?
You are not doing anything wrong. The official release (v4.3.1) may fail on problems containing cardinality constraints such as
(assert (forall ((x boolean)) (or (= x boolean_false)
(= x boolean_true))))
This constraint is asserting that the uninterpreted sort boolean has at most two elements.
I fixed this problem. The fix is already available in the unstable branch.
Here are some instructions on how to compile the unstable branch.
Tomorrow, the nightly builds will also contain this fix.

Resources