all, I am a newer to use Z3. I wrote this smt2 file, but the result return unknown, what is wrong in my file?
(set-option :fixedpoint.engine datalog)
(define-sort site () (_ BitVec 3))
(declare-rel pointsto (Int Int)) ;used to get all points-to relation
(declare-rel dcall (Int Int)) ;used to label all function call or assignment
(declare-rel derived (Int Int)) ;used to get h1->hk
(declare-rel assign (Int Int))
(declare-var vs Int)
(declare-var vd Int)
(declare-var ss Int)
(declare-var sd Int)
(declare-var sm Int)
;;;;; definition of derived ;;;
(rule (=> (dcall vs vd) (pointsto vs vd)))
(rule (=> (and (dcall vs vd) (pointsto vs ss) (pointsto vd sd) ) (derived ss sd)))
(rule (=> (and (derived ss sm) (derived sm sd)) (derived ss sd)))
;facts 0-999 for var, 999** for addr
;(rule (dcall 3 6));src and sink
(rule (dcall 3 4))
(rule (dcall 4 6))
(rule (pointsto 0 9992))
(rule (pointsto 1 9991))
(rule (pointsto 2 9991))
(rule (pointsto 3 99948))
(rule (pointsto 4 99950))
(rule (pointsto 5 99928))
(rule (pointsto 6 9999))
(query (derived 99948 9999))
As a different post explains, the datalog engine should only use finite sorts.
THe newest unstable version of Z3 will reject the input above and indicate that arguments to predicates should be over a finite domain type.
Here is the example rewritten:
(set-option :fixedpoint.engine datalog)
(define-sort site () (_ BitVec 3))
(define-sort Loc () (_ BitVec 16))
(declare-rel pointsto (Loc Loc)) ;used to get all points-to relation
(declare-rel dcall (Loc Loc)) ;used to label all function call or assignment
(declare-rel derived (Loc Loc)) ;used to get h1->hk
(declare-rel assign (Loc Loc))
(declare-var vs Loc)
(declare-var vd Loc)
(declare-var ss Loc)
(declare-var sd Loc)
(declare-var sm Loc)
;;;;; definition of derived ;;;
(rule (=> (dcall vs vd) (pointsto vs vd)))
(rule (=> (and (dcall vs vd) (pointsto vs ss) (pointsto vd sd) ) (derived ss sd)))
(rule (=> (and (derived ss sm) (derived sm sd)) (derived ss sd)))
;facts 0-999 for var, 999** for addr
;(rule (dcall (_ bv3 16) (_ bv6 16)));src and sink
(rule (dcall (_ bv3 16) (_ bv4 16)))
(rule (dcall (_ bv4 16) (_ bv6 16)))
(rule (pointsto (_ bv0 16) (_ bv9992 16)))
(rule (pointsto (_ bv1 16) (_ bv9991 16)))
(rule (pointsto (_ bv2 16) (_ bv9991 16)))
(rule (pointsto (_ bv3 16) (_ bv99948 16)))
(rule (pointsto (_ bv4 16) (_ bv99950 16)))
(rule (pointsto (_ bv5 16) (_ bv9992 16)))
(rule (pointsto (_ bv6 16) (_ bv9999 16)))
(query (derived (_ bv99948 16) (_ bv9999 16)))
Z3 reports "sat", in other words, the query can be derived
Related
I am using Z3 and the extended SMT-LIB2 syntax to solve my horn clauses.
I know that head of a horn clause should be an uninterpreted predicate; but, I wonder how I should rewrite the following clauses to be a set of horn clauses.
(declare-rel inv (Int Int ))
(declare-var k Int)
(declare-var k_p Int)
(declare-var a Int)
(declare-var a_p Int)
(rule (=> (and (= a 0) (= k 0)) (inv a k)))
(rule (=> (and (inv a k) (= a_p (+ a 1))(= k_p (+ k 1))) (inv a_p k_p)))
(rule (=> (and (inv a k) (> k 0) ) (> a 0)))
(query inv )
Z3 complains that (> a 0) cannot be head of a horn clause.
I can rewrite the last clause as the following:
(rule (=> (and (inv a k) (> k 0) ) (gtz a)))
(rule (=> (> a 0) (gtz a)))
But, then the clauses become so weak that I don't get the intended model for the invariant inv. I wonder if there is a better way to do this.
Maybe you want to say
(declare-rel inv (Int Int ))
(declare-rel q ())
(declare-var k Int)
(declare-var k_p Int)
(declare-var a Int)
(declare-var a_p Int)
(rule (=> (and (= a 0) (= k 0)) (inv a k)))
(rule (=> (and (inv a k) (= a_p (+ a 1))(= k_p (+ k 1))) (inv a_p k_p)))
(rule (=> (and (inv a k) (> k 0) (not (> a 0))) q))
(query q )
Here is my program which return SAT when there exists a cycle in the graph and UNSAT when there is no cycle:
(set-option :fixedpoint.engine datalog)
(define-sort s () Int)
(declare-rel edge (s s))
(declare-rel path (s s))
(declare-var a s)
(declare-var b s)
(declare-var c s)
(rule (=> (edge a b) (path a b)))
(rule (=> (and (path a b) (path b c)) (path a c)))
(rule (edge 1 2))
(rule (edge 2 3))
(declare-rel cycle (s))
(rule (=> (path a a) (cycle a)))
(query cycle :print-answer true)
I want to get the model when there is no cycle ( UNSAT ). I realised that i should use the command (get-unsat-core) and set the option to (set-option :produce-unsat-cores true) :
(set-option :fixedpoint.engine datalog)
(set-option :produce-unsat-cores true)
(define-sort s () Int)
(declare-rel edge (s s))
(declare-rel path (s s))
(declare-var a s)
(declare-var b s)
(declare-var c s)
(rule (=> (edge a b) (path a b)) P-1)
(rule (=> (and (path a b) (path b c)) (path a c)) P-2)
(rule (edge 1 2) E-1)
(rule (edge 2 3) E-2)
(rule (edge 3 1) E-3)
(declare-rel cycle (s))
(rule (=> (path a a) (cycle a)))
(query cycle :print-answer true)
(get-unsat-core)
I get this error:
unsat
(error "line 24 column 15: unsat core is not available")
Getting a model in the unsat case doesn't make sense. Unsatisfiable literally means there's no model that satisfies your constraints. Please post a more clear question of precisely what you're trying to achieve.
An unsat core is a subset of the assertions that are conflicting. This set is by definition not satisfiable, and does not constitute model as you are seeking. Furthermore, I very much doubt the fixed-point engine supports unsat-cores, so the error message you're getting simply means they are not computed.
If I may intrude, AFAIK one needs to name the constraints when one wants to retrieve the unsat core.
The smtlib website provides the following example:
; Getting unsatisfiable cores
(set-option :produce-unsat-cores true)
(set-logic QF_UF)
(declare-const p Bool) (declare-const q Bool) (declare-const r Bool)
(declare-const s Bool) (declare-const t Bool)
(assert (! (=> p q) :named PQ))
(assert (! (=> q r) :named QR))
(assert (! (=> r s) :named RS))
(assert (! (=> s t) :named ST))
(assert (! (not (=> q s)) :named NQS))
(check-sat)
; unsat
(get-unsat-core)
; (QR RS NQS)
(exit)
As #LeventErkok points out, a model is only available when the formula is sat and the unsat core is only available when the formula is unsat.
For the datalog program in Z3 at the bottom, the result of query
(query (CallGraph invo heap):print-answer true)
given by Z3 is:
sat
(and (= (:var 0) #b011) (= (:var 1) #b1))
However, the answer should be
sat
(and (= (:var 0) #b1) (= (:var 1) #b011))
am I right? is it a bug in Z3?
(set-option :fixedpoint.engine datalog)
(declare-rel VarPointsTo ( (_ BitVec 4) (_ BitVec 3)))
(declare-rel Reachable ( (_ BitVec 3)))
(declare-rel Alloc ( (_ BitVec 4) (_ BitVec 3) (_ BitVec 3)))
(declare-rel Move ( (_ BitVec 4) (_ BitVec 4)))
(declare-rel FldPointsTo ( (_ BitVec 3) (_ BitVec 1) (_ BitVec 3)))
(declare-rel Store ( (_ BitVec 4) (_ BitVec 4) (_ BitVec 4)))
(declare-rel StrMap ( (_ BitVec 4) (_ BitVec 1)))
(declare-rel Load ( (_ BitVec 4) (_ BitVec 4) (_ BitVec 4)))
(declare-rel VCall ( (_ BitVec 4) (_ BitVec 1) (_ BitVec 3)))
(declare-rel CallGraph ( (_ BitVec 1) (_ BitVec 3)))
(declare-rel InterProcAssign ( (_ BitVec 4) (_ BitVec 4)))
(declare-rel FormalArg ( (_ BitVec 3) (_ BitVec 1) (_ BitVec 4)))
(declare-rel ActualArg ( (_ BitVec 1) (_ BitVec 1) (_ BitVec 4)))
(declare-rel FormalReturn ( (_ BitVec 3) (_ BitVec 4)))
(declare-rel ActualReturn ( (_ BitVec 1) (_ BitVec 4)))
(declare-var var (_ BitVec 4))
(declare-var heap (_ BitVec 3))
(declare-var methHeap (_ BitVec 3))
(declare-var to (_ BitVec 4))
(declare-var from (_ BitVec 4))
(declare-var baseH (_ BitVec 3))
(declare-var fld (_ BitVec 1))
(declare-var base (_ BitVec 4))
(declare-var toMethHeap (_ BitVec 3))
(declare-var invo (_ BitVec 1))
(declare-var inMethHeap (_ BitVec 3))
(declare-var n (_ BitVec 1))
(rule (=> (and (Reachable methHeap) (Alloc var heap methHeap) )(VarPointsTo var heap)))
(rule (=> (and (Move to from) (VarPointsTo from heap) )(VarPointsTo to heap)))
(rule (=> (and (Store base var from) (and (VarPointsTo from heap) (and (VarPointsTo base baseH) (StrMap var fld) )))(FldPointsTo baseH fld heap)))
(rule (=> (and (Load to var base) (and (VarPointsTo base baseH) (and (FldPointsTo baseH fld heap) (StrMap var fld) )))(VarPointsTo to heap)))
(rule (=> (and (VCall var invo inMethHeap) (and (Reachable inMethHeap) (VarPointsTo var toMethHeap) ))(Reachable toMethHeap)))
(rule (=> (and (VCall var invo inMethHeap) (and (Reachable inMethHeap) (VarPointsTo var toMethHeap) ))(CallGraph invo toMethHeap)))
(rule (=> (and (CallGraph invo methHeap) (and (FormalArg methHeap n to) (ActualArg invo n from) ))(InterProcAssign to from)))
(rule (=> (and (CallGraph invo methHeap) (and (FormalReturn methHeap from) (ActualReturn invo to) ))(InterProcAssign to from)))
(rule (=> (and (InterProcAssign to from) (VarPointsTo from heap) )(VarPointsTo to heap)))
(rule (Alloc #b0001 #b001 #b010))
(rule (Alloc #b0010 #b001 #b010))
(rule (Reachable #b001))
(rule (Reachable #b010))
(rule (Alloc #b0011 #b011 #b001))
(rule (Alloc #b0100 #b100 #b011))
(rule (Move #b0101 #b0100))
(rule (StrMap #b0110 #b1))
(rule (Store #b0001 #b0110 #b0011))
(rule (StrMap #b0111 #b1))
(rule (Load #b1000 #b0111 #b0001))
(rule (VCall #b1000 #b1 #b001))
(rule (ActualReturn #b1 #b1001))
(query (VarPointsTo var heap):print-answer true)
(query (CallGraph invo heap):print-answer true)
(query (Reachable heap):print-answer true)
This does not appear to reproduce in the version of Z3 checked into GitHub/z3prover/z3 master branch.
The way the engine associates variable indices with variable names has been brittle and there might still be a way to trigger this bug with the newest version of Z3, although I cannot reproduce it.
The binary API exposes a more reliable API: one poses a query given one or more predicate declarations (The function from the C API is called Z3_fixedpoint_query_relations, and the other supported programming languages support similarly named functions).
Can someone kindly point out why the final query doesn't have output?
Basically I tell Z3 if vs-)vd and vs->ss and vd->sd, then sd is derived from ss.
(set-option :fixedpoint.engine datalog)
(define-sort site () (_ BitVec 3))
(declare-rel pointsto (Int site))
(declare-rel dcall (Int Int))
(declare-rel derived (site site))
(declare-var vs Int)
(declare-var vd Int)
(declare-var ss site)
(declare-var sd site)
;;;;; definition of derived ;;
(rule (=> (and (dcall vs vd) (pointsto vs ss) (pointsto vd sd)) (derived ss sd)))
(rule (dcall 11 12))
(rule (pointsto 11 #b001))
(rule (pointsto 12 #b010))
(query (derived #b001 #b010))
This example exposes a few things. I will try to go through these.
The query returns "sat" or "unsat". In the "sat" case there is a set of tuples corresponding to the free variables in the query such that the query is derivable. To print these tuples you can specify ":print-answer true" as an option.
Your particular query does not contain any free variables, so there are no tuples to print.
I added another example that contains free variables and Z3 prints a solution.
The datalog engine doesn't really support infinite domains. You should use relations over Booleans, bit-vectors or finite domain values (a special sort used for programs entered in datalog format). I have changed your example to use bit-vectors.
(set-option :fixedpoint.engine datalog)
(define-sort site () (_ BitVec 3))
(define-sort Loc () (_ BitVec 8))
(declare-rel pointsto (Loc site))
(declare-rel dcall (Loc Loc))
(declare-rel derived (site site))
(declare-var vs Loc)
(declare-var vd Loc)
(declare-var ss site)
(declare-var sd site)
;;;;; definition of derived ;;
(rule (=> (and (dcall vs vd) (pointsto vs ss) (pointsto vd sd)) (derived ss sd)))
(rule (dcall (_ bv11 8) (_ bv12 8)))
(rule (pointsto (_ bv11 8) #b001))
(rule (pointsto (_ bv12 8) #b010))
(query (derived #b001 #b010)
:print-answer true)
(query (derived #b001 ss)
:print-answer true)
I have the following piece of code:
(declare-const L4 (_ BitVec 6))
(declare-const L1 (_ BitVec 6))
(declare-const L0 (_ BitVec 6))
(declare-const l2 (_ BitVec 6))
(assert (= l2 (_ bv8 6)))
;; All is encoding the set that contains {0, 1, 2, 3, 4, 5}
(define-const All (_ BitVec 6) #b111111)
;; Empty is encoding the empty set
(define-const Empty (_ BitVec 6) #b000000)
(define-fun LT_l ((S (_ BitVec 6)) (l (_ BitVec 6))) Bool
;; True if for all x in S x < l
(= (bvand (bvshl All l) S) Empty))
(define-fun is_in ((e (_ BitVec 6)) (S (_ BitVec 6))) Bool
;; True if e is an element of the "set" S.
(not (= (bvand (bvshl (_ bv1 6) e) S) Empty)))
(define-fun is_minimal ((e (_ BitVec 6)) (S (_ BitVec 6))) Bool
;; True if e is the minimal element of S
(and (is_in e S) ;; S contains e
;; (1 << e) - 1 represents the set of elements that are smaller than e
(= (bvand (bvsub (bvshl (_ bv1 6) e) (_ bv1 6)) S) Empty)))
;; To encode that forall x in L0 and forall y in L1. x < y
(define-fun LT ((L0 (_ BitVec 6)) (L1 (_ BitVec 6))) Bool
; True if forall x in L0 and forall y in L1, x < y
(or (= L0 Empty)
(= L1 Empty)
(exists ((min (_ BitVec 6))) (and (is_minimal min L1) (LT_l L0 min)))))
(assert (not (= L0 Empty)))
(assert (not (= L1 Empty)))
(assert (not (= L4 Empty)))
(assert (LT_l L4 l2))
(assert (LT L0 L1))
(check-sat)
(get-model)
(assert (LT L1 L0))
(check-sat)
When I run this code I get the model is:
sat
(model
(define-fun min!0 () (_ BitVec 6)
#b000011)
(define-fun L1 () (_ BitVec 6)
#b001000)
(define-fun L0 () (_ BitVec 6)
#b000100)
(define-fun L4 () (_ BitVec 6)
#b000100)
(define-fun l2 () (_ BitVec 6)
#b001000)
)
unsat
Why is the result of min is:
(define-fun min!0 () (_ BitVec 6)
#b000011)
and not b001000 since the smallest value of L1 is this and not b000011.
Someone can explain me?
Finally, I define the function Lt_l that checks if for all x in S x < l, but now I wanted to do GT_l that checks if for all x in S l < x. I have the following code:
(define-fun GT_l ((S (_ BitVec 6)) (l (_ BitVec 6))) Bool
(= (bvand (bvneg (bvshl (_ bv0 6) l)) S) Empty))
But this does not work why?
Thanks
In your example, you are representing sets using bit-vectors. For example, the bit-vector #b101000 represents the set {5, 3}. The output (define-fun L1 () (_ BitVec 6) #b001000) is essentially saying that L1 is the "set" {3}. One possible confusion is that bit-vectors are being used to represent sets and elements. The bit-vector min!0 represents an element. The output (define-fun min!0 () (_ BitVec 6) #b000011) is saying that min!0 is the value 3, and it is indeed the "minimal value" in L1.