I wish to get the constraint of the element in the fixedpoint phi, in the following example, the constraint should be c2<=c1+5.0, c1>=5.0 it should be how to realize it in Z3? Or is there any way to do it not using fixedpoint in Z3
(set-option :produce-models true)
(set-option :dl_engine 1)
(set-option :dl_pdr_use_farkas true)
(declare-var c1 Real)
(declare-var c2 Real)
(declare-var lambda Real)
(declare-rel phi(Real Real))
(rule
(=>
(and
(>= lambda 0.0)
(phi c1 c2)
)
(phi (+ c1 lambda) (+ c2 lambda))
)
)
(rule
(=>
(>= c1 5.0)
(<= c2 10.0)
(phi c1 c2)
)
)
(query (phi c1 c2))
Z3 does not attempt to compute a least fixed-point.
It attempts to establish reachability (derivability) or establish a post fixed-point that
entails that a query is not reachable (derivable).
So it does not provide a way to obtain a least fixed-point from a set of rules.
By specifying
(query (phi c1 c2) :print-certificate true)
Z3 will print what corresponds to a member of the least fixed-point which satisfies the query.
Related
I am using Z3 to solve my horn clauses. In the body of Horn clauses uninterpreted predicates should be positive. However, I need negation of some of uninterpreted predicates.
I have seen some examples in which negation works fine. For instance Z3 would return sat for the following example:
(set-logic HORN)
(declare-fun inv (Int) Bool)
(assert (inv 0))
(assert (forall ((k Int)) (or (> k 10) (not (inv k)) (inv (+ k 1)))))
(check-sat)
But my example looks like the following for which Z3 returns unknown.
(set-logic HORN)
(declare-fun inv (Int ) Bool)
(declare-fun s ( Int ) Bool)
(assert (forall ((k Int) (pc Int))(=>(and (= pc 1)(= k 0)) (inv k ))))
(assert (forall ((k Int)(k_p Int)(pc Int)(pc_p Int))
(=>(and (inv k )(= pc 1)(= pc_p 2)(= k_p (+ k 1))(not (s pc ))(s pc_p ))
(inv k_p ))))
(check-sat)
I wonder if there is a way to rewrite my clauses to Horn clause fragment of Z3.
Your clauses are not in the Horn fragment because the predicate s is used with both polarities in the last assertion. So there are two occurrences of a predicate with positive polarity (both (s pc) and (inv k_p) are positive polarity).
A basic method to avoid polarity issues is to introduce an extra argument to s of type Bool. Consequently, you would also have to say what is the specification of s using Horn clauses so it all makes sense. The typical scenario is that s encodes the behavior of a recursive procedure and the extra Boolean argument to s would be the return value of the procedure s. Of course this encoding doesn't ensure that s is total or functional.
There is a second approach, which is to add an extra argument to "inv", where you let 's' be an array. Then the occurrences (not (s pc)) becomes (not (select s pc)), etc.
It all depends on the intent of your encoding for what makes sense.
(set-option :smt.mbqi true)
(declare-fun R(Int) Int)
(declare-const a Int)
(assert (= (R 0) 0))
(assert (forall ((n Int)) (=> (> n 0) (= (R n ) (+ (R (- n 1)) 1)))))
(assert (not (= a 5)))
(assert (not (= (R a) 5)))
(check-sat)
I have tried the above code in Z3,But Z3 unable to answer.Can you please guide me where i have made the mistake ?
As a general pattern don't expect MBQI to produce models
involving functions that
only have an infinite range of different values.
If you really must, then you can use the define-fun-rec construct to define
a recursive function. Z3 currently trusts that the definition
is well-formed (e.g., that the equation corresponding to the function
definition is satisfiable).
(set-option :smt.mbqi true)
(declare-fun F (Int) Int)
(define-fun-rec R ((n Int)) Int
(if (= n 0) 0
(if (> n 0) (+ (R (- n 1)) 1)
(F n))))
(declare-const a Int)
(assert (not (= a 5)))
(assert (not (= (R a) 5)))
(check-sat)
(get-model)
Z3 uses recursively defined functions passively during search: whenever
there is a candidate model for the ground portion of the constraints, it
checks that the function graph is adequately defined on the values of the candidate model. If it isn't, then the function definition is instantiated on the selected values until it is well defined on the values that are relevant
to the ground constraints.
While trying to solve large nonlinear real arithmetic problems, I track every assertion using answer literals and explicit implications, as recommended in other posts. It should be equivalent to using the (! (...) :named p1) syntax of the SMT2 format. It seems, though, that both methods are handled differently internally.
The following SMT2 code gives an UNKNOWN result, with explanation "(incomplete (theory arithmetic))":
(set-option :print-success false)
(set-option :produce-unsat-cores true) ; enable generation of unsat cores
(set-option :produce-models true) ; enable model generation
(declare-const p1 Bool)
(declare-const p2 Bool)
(declare-const p3 Bool)
(declare-const p4 Bool)
(declare-const p5 Bool)
(declare-const x1 Real)
(declare-const x2 Real)
(declare-const x3 Real)
(assert (=> p1 (= x1 (/ 1.0 (* x2 x2)))))
(assert (=> p2 (not (= x2 0.0))))
(assert (=> p3 (= x3 (* 2.0 x1))))
(assert (=> p4 (= x3 5.0)))
(assert (=> p5 (< x3 0.0)))
(check-sat p1 p2 p3)
(get-info:reason-unknown)
On the other hand, the following SMT2 code gives the correct answer, UNSAT, and produces an informative unsat core (p4, p5):
(set-option :print-success false)
(set-option :produce-unsat-cores true) ; enable generation of unsat cores
(set-option :produce-models true) ; enable model generation
(declare-const x1 Real)
(declare-const x2 Real)
(declare-const x3 Real)
(assert (! (= x1 (/ 1.0 (* x2 x2))) :named p1))
(assert (! (not (= x2 0.0)) :named p2))
(assert (! (= x3 (* 2.0 x1)) :named p3))
(assert (! (= x3 5.0) :named p4))
(assert (! (< x3 0) :named p5))
(check-sat)
(get-unsat-core)
;(get-model)
My specific questions are:
How can this differing behavior be explained? What is recommended practice for tracking nonlinear real equations and inequalities?
What would be the equivalent OCaml API call for the (! (...) :named p1) syntax of SMT2? Is it assert_and_track?
I am using Z3 version 4.3.2 from the ml-ng branch under Linux.
Many thanks!
The new ML API has been integrated into the unstable branch a couple months ago, and the ml-ng branch has been removed. A few bugfixes/extensions were added to it's worth updating.
assert_and_track does exactly what you suspect and it is internally translated to the first example given.
The difference in behavior is explained by (check-sat p1 p2 p3) which is missing p4 and p5. Once those are added, the two versions behave exactly the same and they produce the same unsat core.
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).
How do I express soft and hard constraints in Z3? I know from the API that it is possible to have assumptions (soft constraints), but I can't express this when using the command line tool. I am calling it using z3 /smt2 /si
Assumptions are available in the SMT 2.0 frontend. They are used to extract unsatisfiable cores. They may be also used to “retract” assumptions.
Note that, assumptions are not really “soft constraints”, but they can be used to implement them. See the maxsat example (subdir maxsat) in the Z3 distribution.
That being said, here is an example on how to use assumptions in the Z3 SMT 2.0 frontend.
;; Must enable unsat core generation
(set-option :produce-unsat-cores true)
(set-option :produce-models true)
;; Declare three Boolean constants to "assumptions"
(declare-const p1 Bool)
(declare-const p2 Bool)
(declare-const p3 Bool)
;; We assert (=> p C) to track C using p
(declare-const x Int)
(declare-const y Int)
(assert (=> p1 (> x 10)))
;; An Boolean constant may track more than one formula
(assert (=> p1 (> y x)))
(assert (=> p2 (< y 5)))
(assert (=> p3 (> y 0)))
(check-sat p1 p2 p3)
(get-unsat-core) ;; produce core (p1 p2)
(check-sat p1 p3) ;; "retrack" p2
(get-model)