Defining a function in Z3 by its Java implementation? - z3

So here's what I am trying to do.
Let's say that I want to find the value of op using Z3 (and its Java binding) in an expression similar to this:
((exists (op Int)) (= (foo op) 2)
So I want to call a function foo on the op variable and check for which values of op will the function return 2. I want to define a function foo in Java and thought that there exists a way for Z3 to access these function definitions. I want to do it like this because the functions are actually look-ups in a HashMap which was easy to implement in Java.
Since I am a beginner to SMT solvers in general it might be possible that I want to do something which cannot be done. So I am open to all suggestions regarding the topic.
Thanks in advance for your time and answers!

That would be very nice to have, but at the moment Z3 can't use function definitions from other languages/APIs. For the case of lookup-tables it should be easy though, because they can easily be encoded as if-then-else cascades, for instance as follows:
;; define foo
(define-fun foo ((x Int)) Int
(ite (= x 1) 42
(ite (= x 2) 43
;; ...
78)))
;; use foo
(assert (exists ((op Int)) (= (foo op) 43)))
(apply skip)
produces
(goal
(exists ((op Int)) (= (ite (= op 1) 42 (ite (= op 2) 43 78)) 43))
:precision precise :depth 0)
)
(and it is solved quickly, too.)
The easiest way to do this via the API is to set up the problem with the function declaration and then to provide a macro definition via a universal quantifier that is recognized by the macro-finder tactic:
;; declare foo
(declare-fun foo ((Int)) Int)
;; define foo
(assert (forall ((x Int)) (= (foo x)
(ite (= x 1) 42
(ite (= x 2) 43
;; ...
78)))))
;; use foo
(assert (exists ((op Int)) (= (foo op) 43)))
(apply macro-finder) ;; replaces foo with it's definition
For the macro-finder to pick up the function definition, the quantifier has to have the form
(forall ((x ...)) (= (foo x) (... definition ...))

Related

How to express set membership in SMTLIB format in Z3?

I'm trying to use the SMTLIB format to express set membership in Z3:
(declare-const a (Set Int))
;; the next two lines parse correctly in CVC4, but not Z3:
(assert (= a (as emptyset (Set Int))))
(assert (member 12 a))
;; these work in both solvers
(assert (= a (union a a)))
(assert (subset a a))
(assert (= a (intersection a a)))
(check-sat)
The functions emptyset and member seem to parse as expected in CVC4, but not in Z3.
From checking the API (e.g., here: https://z3prover.github.io/api/html/group__capi.html), Z3 does support empty sets and membership programatically, but how does one express these in SMTLIB syntax?
It's indeed annoying z3 and CVC4 use slightly different notations for sets. In z3, a set is essentially an array with the range of bool. Based on this analogy, your program is coded as:
(declare-const a (Set Int))
(assert (= a ((as const (Set Int)) false)))
(assert (select a 12))
(assert (= a (union a a)))
(assert (subset a a))
(assert (= a (intersection a a)))
(check-sat)
which z3 accepts as is and produces unsat. But you'll find that CVC4 doesn't like this program now.
It would be great if the SMTLib movement standardized the theory of sets (http://smtlib.cs.uiowa.edu/) and there has indeed been a proposal along these lines (https://www.kroening.com/smt-lib-lsm.pdf) but I don't think it has been adopted by solvers nor sanctioned by the SMTLib committee yet.

Z3; Simplify with if-then-else

Is there a way to simplify the following expression to "6 < var"?
According to Z3, these expressions are equivalent but simplification does not produce the latter.
I have tried the three parameters since they seem to be related to if-then-else but this also did not help.
(declare-fun var () Int)
(simplify
(exists ((bx Int))
(and
(exists ((byX Int))
(ite (> bx 5) (= byX 0) (&& (> bx 2) (= byX (+ byX 4)))))
(= bx (+ var 1))
(> var 6)
)
)
:push_ite_arith true
:pull_cheap_ite true
:ite_extra_rules true
)
(assert
(not
(iff
(exists ((bx Int))
(and
(exists ((by Int))
(ite (> bx 5) (= by 0) (&& (> bx 2) (= by (+ by 4)))))
(= bx (+ var 1))
(> var 6)
)
)
(< 6 var)
)
)
)
(check-sat)
Not in general, no.
Z3's simplifications and what you would consider "simple" are typically not the same, and it works more or less as a black-box. It won't produce output like what you would get from a symbolic math package or alike: The simplifications are more geared towards making the input "simpler" for further solving; not for "presenting it back to the user" purpose.
You can find many similar questions on stack-overflow, see: https://stackoverflow.com/search?q=%5Bz3%5D+simplify and in particular this answer from Leo: simplification in Z3

z3 4.3.2 fails to find a model for Why3-generated (satisfiable) goals

I'm trying to use Why3's Z3 back-end in order to retrieve models that can then be used to derive test cases exhibiting bugs in programs. However, Z3 version 4.3.2 seems unable to answer sat for any Why3 goal. It looks like some of the axiomatic definitions used by Why3 somehow confuse Z3. For instance, the following example (which is a tiny part of what Why3 generates)
(declare-fun abs1 (Int) Int)
;; abs_def
(assert
(forall ((x Int)) (ite (<= 0 x) (= (abs1 x) x) (= (abs1 x) (- x)))))
(check-sat)
results in timeout with the following command line:
z3 -smt2 model.partial=true file.smt2 -T:10
On the other hand, changing the definition to
(declare-fun abs1 (Int) Int)
;; abs_def
(assert
(forall ((x Int)) (=> (<= 0 x) (= (abs1 x) x))))
(assert
(forall ((x Int)) (=> (> 0 x) (= (abs1 x) (- x)))))
will get me a model (which looks pretty reasonable)
(model
(define-fun abs1 ((x!1 Int)) Int
(ite (>= x!1 0) x!1 (* (- 1) x!1)))
)
but if I try to add the next axiom present in the original Why3 file, namely
;; Abs_pos
(assert (forall ((x Int)) (<= 0 (abs1 x))))
again Z3 answers timeout.
Is there something I'm missing in the configuration of Z3? Moreover, in previous versions of Why3, there was an option MODEL_ON_TIMEOUT, which allowed to retrieve a model in such circumstances. Even though there was no guarantee that this was a real model since Z3 could not finish to check it, in practice such models generally contained all the information I needed. However, I haven't found a similar option in 4.3.2. Does it still exist?
Update The last axiom Abs_pos was wrong (I toyed a bit with Why3's output before posting here and ended up pasting an incorrect version of the issue). This is now fixed.
The additional axiom
(assert (not (forall ((x Int)) (<= 0 (abs1 x)))))
makes the problem unsatisfiable, since abs1 always returns a non-negative integer and with the additional axiom you require the existence of a negative result for abs1 for some x. The web version of Z3 returns unsat as expected, see here.

Can Z3 output "anything" for unconstrained values of UF?

Some values of uninterpreted functions can be unconstrained during the search. For example, if in smt query only f(1) is called, then f(2), f(3) can be anything. Is there a way (some option may be) to know which values were not used during the solving and therefore can be anything?
For quantifier free problems, you can achieve that by using the option :model-partial to true.
Here is an example (also available here):
(set-option :model-partial true)
(declare-fun f (Int) Int)
(assert (> (f 0) 0))
(assert (< (f 1) 0))
(check-sat)
(get-model)
In this example, we get the output:
sat
(model
(define-fun f ((x!1 Int)) Int
(ite (= x!1 0) 1
(ite (= x!1 1) (- 1)
#unspecified)))
)
BTW, in the next release (Z3 4.3.2), this option is renamed to :model.partial. In the next release, the options are grouped in modules.

a datatype contains a set in Z3

how can I make a datatype that contains a set of another objects. Basically, I am doing the following code:
(define-sort Set(T) (Array Int T))
(declare-datatypes () ((A f1 (cons (value Int) (b (Set B))))
(B f2 (cons (id Int) (a (Set A))))
))
But Z3 tells me unknown sort for A and B. If I remove "Set" it works just as the guide states.
I was trying to use List instead but it does not work. Anyone knows how to make it work?
You are addressing a question that comes up on a regular basis:
how can I mix data-types and arrays (as sets, multi-sets or
data-types in the range)?
As stated above Z3 does not support mixing data-types
and arrays in a single declaration.
A solution is to develop a custom solver for the
mixed datatype + array theory. Z3 contains programmatic
APIs for developing custom solvers.
It is still useful to develop this example
to illustrate the capabilities and limitations
of encoding theories with quantifiers and triggers.
Let me simplify your example by just using A.
As a work-around you can define an auxiliary sort.
The workaround is not ideal, though. It illustrates some
axiom 'hacking'. It relies on the operational semantics
of how quantifiers are instantiated during search.
(set-option :model true) ; We are going to display models.
(set-option :auto-config false)
(set-option :mbqi false) ; Model-based quantifier instantiation is too powerful here
(declare-sort SetA) ; Declare a custom fresh sort SetA
(declare-datatypes () ((A f1 (cons (value Int) (a SetA)))))
(define-sort Set (T) (Array T Bool))
Then define bijections between (Set A), SetA.
(declare-fun injSA ((Set A)) SetA)
(declare-fun projSA (SetA) (Set A))
(assert (forall ((x SetA)) (= (injSA (projSA x)) x)))
(assert (forall ((x (Set A))) (= (projSA (injSA x)) x)))
This is almost what the data-type declaration states.
To enforce well-foundedness you can associate an ordinal with members of A
and enforce that members of SetA are smaller in the well-founded ordering:
(declare-const v Int)
(declare-const s1 SetA)
(declare-const a1 A)
(declare-const sa1 (Set A))
(declare-const s2 SetA)
(declare-const a2 A)
(declare-const sa2 (Set A))
With the axioms so far, a1 can be a member of itself.
(push)
(assert (select sa1 a1))
(assert (= s1 (injSA sa1)))
(assert (= a1 (cons v s1)))
(check-sat)
(get-model)
(pop)
We now associate an ordinal number with the members of A.
(declare-fun ord (A) Int)
(assert (forall ((x SetA) (v Int) (a A))
(=> (select (projSA x) a)
(> (ord (cons v x)) (ord a)))))
(assert (forall ((x A)) (> (ord x) 0)))
By default quantifier instantiation in Z3 is pattern-based.
The first quantified assert above will not be instantiated on all
relevant instances. One can instead assert:
(assert (forall ((x1 SetA) (x2 (Set A)) (v Int) (a A))
(! (=> (and (= (projSA x1) x2) (select x2 a))
(> (ord (cons v x1)) (ord a)))
:pattern ((select x2 a) (cons v x1)))))
Axioms like these, that use two patterns (called a multi-pattern)
are quite expensive. They produce instantiations for every pair
of (select x2 a) and (cons v x1)
The membership constraint from before is now unsatisfiable.
(push)
(assert (select sa1 a1))
(assert (= s1 (injSA sa1)))
(assert (= a1 (cons v s1)))
(check-sat)
(pop)
but models are not necessarily well formed yet.
the default value of the set is 'true', which
would mean that the model implies there is a membership cycle
when there isn't one.
(push)
(assert (not (= (cons v s1) a1)))
(assert (= (projSA s1) sa1))
(assert (select sa1 a1))
(check-sat)
(get-model)
(pop)
We can approximate more faithful models by using
the following approach to enforce that sets that are
used in data-types are finite.
For example, whenever there is a membership check on a set x2,
we enforce that the 'default' value of the set is 'false'.
(assert (forall ((x2 (Set A)) (a A))
(! (not (default x2))
:pattern ((select x2 a)))))
Alternatively, whenever a set occurs in a data-type constructor
it is finite
(assert (forall ((v Int) (x1 SetA))
(! (not (default (projSA x1)))
:pattern ((cons v x1)))))
(push)
(assert (not (= (cons v s1) a1)))
(assert (= (projSA s1) sa1))
(assert (select sa1 a1))
(check-sat)
(get-model)
(pop)
Throughout the inclusion of additional axioms,
Z3 produces the answer 'unknown' and furthermore
the model that is produced indicates that the domain SetA
is finite (a singleton). So while we could patch the defaults
this model still does not satisfy the axioms. It satisfies
the axioms modulo instantiation only.
This is not supported in Z3. You can use arrays in datatype declarations, but they can't contain "references" to the datatypes you are declaring. For example, it is ok to use (Set Int).

Resources