I am developing a insert method in Z3 for a list. But, I have to meet some requirements:
The item is not inserted,if it is already in the list
the item is not inserted,if the list (the set) is full
First of all, I define the datatype:
(declare-datatypes (T) ((Lst nil (cons (hd T) (tl Lst)))))
I define the functions isFull to know if the list maximum capacity exceeded and IsMember to know if the list contains a number.
(define-fun isFull ((l (Lst Int))) Bool
(ite
(<= (len l) 10)
false
true
)
)
(define-fun-rec isMember((i Int) (l (Lst Int))) Bool
(ite
(= l nil)
false
(or (= i (hd l)) (isMember i (tl l)))
)
)
Then I tried to define a insert method but something is wrong:
(define-fun insert ((i Int) (l (Lst Int))) (l (Lst Int))
(ite (= false (isMember i l ) )
(ite (= false (isFull l ))
(ite(= l nil)
(= (hd l) i)
)
)
)
)
You haven't shown us your definition of len, and there are a bunch of syntactic errors in your code. But you seem to be on the right track. I'd code your spec as follows:
(declare-datatypes (T) ((Lst nil (cons (hd T) (tl Lst)))))
(define-fun-rec len ((l (Lst Int))) Int
(ite (= l nil) 0 (+ 1 (len (tl l)))))
(define-fun isFull ((l (Lst Int))) Bool
(> (len l) 10))
(define-fun-rec isMember ((i Int) (l (Lst Int))) Bool
(and (distinct l nil)
(or (= i (hd l))
(isMember i (tl l)))))
(define-fun funnyInsert ((i Int) (l (Lst Int))) (Lst Int)
(ite (or (isMember i l) (isFull l))
l
(cons i l)))
I've called your insert funnyInsert, since what it does is rather funny.
Note that while z3 will accept this program as is, it's unlikely you can prove anything interesting with these definitions. Properties of recursive functions are usually proven using induction, and SMT-solvers generally don't perform induction. At least not out-of-the box without a lot of tinkering with tactics and such. Best of luck!
Related
My goal is to define a function, which takes an input integer sequence and outputs an integer sequence with the same length, but containing only the first element of the input sequence. For example (in pseudo-code):
f([7,5,6]) = [7,7,7]
For this I declare a function in z3 as:
(declare-fun f ((Seq Int)) (Seq Int))
and try to force the expected behavior with the assertion:
(assert
(forall ((arr (Seq Int)))
(and
(=
(seq.len arr)
(seq.len (f arr))
)
(forall ((i Int))
(implies
(and
(>= i 0)
(< i (seq.len arr))
)
(=
(seq.at arr 0)
(seq.at (f arr) i)
)
)
)
)
))
The problem is that the program does not terminate, which I suspect is caused by the all-quantifier. To test whether my conditions are correct I declared two constants and saw that for concrete values the conditions are correct:
(define-const first (Seq Int)
(seq.++ (seq.unit 1) (seq.unit 2))
)
(declare-const second (Seq Int))
(assert
(and
(=
(seq.len first)
(seq.len second)
)
(forall ((i Int))
(implies
(and
(>= i 0)
(< i (seq.len first))
)
(=
(seq.at first 0)
(seq.at second i)
)
)
)
)
)
(check-sat)
(get-model)
My question: How would it be possible to integrate the conditions in the assertions with the expected behavior of the f function? The function should be total, which means it should be defined for all possible input sequences, but this leads me to think that an all quantifier is definitely needed in my case.
Reasoning with such recursive data-types/values is not a strong suit for SMT solvers. Most problems will require induction and SMT-solvers don't do induction out-of-the box.
Having said that, you can code what you want using the new declare-fun-rec construct:
(define-fun-rec copyHeadAux ((x (Seq Int)) (l (Seq Int))) (Seq Int)
(ite (= 0 (seq.len l))
(as seq.empty (Seq Int))
(seq.++ x (copyHeadAux x (seq.extract l 1 (seq.len l))))))
(define-fun copyHead ((l (Seq Int))) (Seq Int)
(ite (= 0 (seq.len l))
(as seq.empty (Seq Int))
(copyHeadAux (seq.at l 0) l)))
(define-fun test () (Seq Int) (seq.++ (seq.unit 7) (seq.unit 5) (seq.unit 6)))
(declare-const out (Seq Int))
(assert (= out (copyHead test)))
(check-sat)
(get-model)
When I run this, I get:
sat
(
(define-fun out () (Seq Int)
(seq.++ (seq.unit 7) (seq.unit 7) (seq.unit 7)))
(define-fun test () (Seq Int)
(seq.++ (seq.unit 7) (seq.unit 5) (seq.unit 6)))
(define-fun copyHead ((x!0 (Seq Int))) (Seq Int)
(ite (= 0 (seq.len x!0))
(as seq.empty (Seq Int))
(copyHeadAux (seq.at x!0 0) x!0)))
)
which is the correct answer you're looking for. But unless your constraints only involve "constant-folding" cases (i.e., where copyHead is always applied to a constant known value), you're likely to get unknown as the answer, or have the solver go into an infinite e-matching loop.
It's best to use a proper theorem prover (Isabelle, HOL, Lean, ACL2 etc.) for reasoning with these sorts of recursive definitions. Of course, SMT solvers get better over time and maybe one day they'll be able to handle more problems like this out-of-the-box, but I wouldn't hold my breath.
I'm trying to use Z3 to solve equations involving unknown projection functions, to find a valid interpretation of the functions that satisfy the equation. So for example for the equation: snd . f = g . fst a valid interpretation would be f = \(x,y) -> (y,x) and g = id. I know that Z3 isn't higher order so I've been trying to encode the problem in first order form. So for example for f = g.fst I use:
(declare-datatypes (T) ((Tree (leaf (value T)) (node (children TreeList)))
(TreeList nil (cons (head Tree) (tail TreeList)))))
(define-fun fst ((x (Tree Int))) (Tree Int) (head (children x)))
(define-fun snd ((x (Tree Int))) (Tree Int) (head (tail (children x))))
(declare-fun f ((Tree Int)) (Tree Int))
(declare-fun g ((Tree Int)) (Tree Int))
(assert (forall ((x (Tree Int))) (= (f x) (g (fst x)))))
(check-sat)
(get-model)
Which sort of works returning:
(define-fun g ((x!1 (Tree Int))) (Tree Int)
(leaf 0))
(define-fun f ((x!1 (Tree Int))) (Tree Int)
(g (head (children x!1))))
However for snd . f = g . fst (I've simplified trees to pairs to try and help):
(declare-datatypes (T) ((Pair (leaf (value T)) (pair (fst Pair) (snd Pair)))))
(declare-fun f ((Pair Int)) (Pair Int))
(declare-fun g ((Pair Int)) (Pair Int))
(assert (forall ((x (Pair Int))) (= (snd (f x)) (g (fst x)))))
I get unknown.
I've also tried to encode a similar problem without the ADT just using booleans or ints as parameters, but then the model just assigns constant values to the functions. I've also tried to define a simple ADT for function constants, the identity function, and pairwise and sequential composition, and then define an "equals" function that can simplify expressions like f.id = f, but this either involves a recursive function like:
(declare-datatypes () (
(Fun id
(fun (funnum Int))
(seq (after Fun) (before Fun))
(pair (fst Fun) (snd Fun)) )))
(define-fun eq ((x Fun) (y Fun)) Bool (or
(= x y)
(eq x (seq y id)) ; id neutral for seq
(eq x (seq id y))
(eq y (seq x id))
(eq y (seq id x))))
(declare-const f Fun)
(declare-const g Fun)
(assert (eq f (seq id g)))
(check-sat)
(get-model)
Which is obviously invalid. Or if I use an uninterpretted function, it makes "eq" a constant function i.e.
(declare-fun eq (Fun Fun) Bool)
(assert (forall ((x Fun) (y Fun)) ; semantic equality
(= (eq x y) (or
(= x y) ; syntactic eq
(eq x (seq y id)) ; id neutral for seq
(eq x (seq id y))
(eq y (seq x id))
(eq y (seq id x))
))
))
=>
(define-fun eq ((x!1 Fun) (x!2 Fun)) Bool
true)
And similarly with equations involving functions with type Int -> Int, this returns constant functions for f and g:
(declare-fun f (Int) Int)
(declare-fun g (Int) Int)
(assert (forall ((x Int)) (= (+ (f x) 1) (+ (g x) 2)) ))
and adding these times out:
(assert (forall ((x Int) (y Int)) (=>
(not (= x y))
(not (= (g x) (g y))))))
(assert (forall ((x Int) (y Int)) (=>
(not (= x y))
(not (= (f x) (f y))))))
Any ideas how I can get this sort of thing to work?
Many thanks!
Z3 searches for essentially finite models so isn't well suited for solving functional equations directly. The main trick for finding models of these kinds is to strengthen the formulas by providing a finite set of alternative interpretations of functions that can be composed. For example, you can allow f(x) to be either identity, permutation, or repeat x or y, or return a constant value in one of the fields, This may be composed with functions that perform simple arithmetical operations. You will have to bound the number of compositions you are willing to admit. You assert a similar set of templates for g. So far this has worked best for bit-vectors.
The search space for such interpretations can easily get overwhelming. I tried your example with algebraic data-types and templates. Z3 is not able to find an interpretation in this case, at least not by stating the problem directly as a template search.
The problem in relational algebra REL051+1.p reads
File : REL051+1 : TPTP v6.1.0. Released v4.0.0.
% Domain : Relation Algebra
% Problem : Dense linear ordering
Using TPTP syntax with fof the corresponding code is
fof(f01,axiom,(
! [A] : o(A,A) )).
fof(f02,axiom,(
! [A,B] :
( ( A != B
& o(A,B) )
=> ~ o(B,A) ) )).
fof(f03,axiom,(
! [A,B,C] :
( ( o(A,B)
& o(B,C) )
=> o(A,C) ) )).
fof(f04,axiom,(
! [A,B] :
( ( A != B
& o(A,B) )
=> ( o(A,f(A,B))
& o(f(A,B),B) ) ) )).
fof(f05,axiom,(
! [A,B] :
( f(A,B) != A
& f(A,B) != B ) )).
fof(f06,axiom,(
! [A,B] :
( o(A,B)
| o(B,A) ) )).
As you can see in TPTP all ATPs are unable to prove such problem.
This theorem was refuted with Z3 using the following SMT-LIB
(declare-sort S)
(declare-fun o (S S) Bool)
(declare-fun f (S S) S)
(assert (forall ((A S)) (o A A) ))
(assert (forall ((A S) (B S)) (implies (and (distinct A B) (o A B))
(not (o B A))) ) )
(assert (forall ((A S) (B S) (C S)) (implies (and (o A B) (o B C))
(o A C)) ) )
(assert (forall ((A S) (B S)) (implies (and (distinct A B) (o A B))
(and (o A (f A B)) (o (f A B) B))) ) )
(declare-fun B () S)
(assert (forall ((A S)) (and (distinct (f A B) A)
(distinct (f A B) B)) ) )
(assert (not (forall ((A S)) (or (o A B) (o B A)) ) ))
(check-sat)
(get-model)
and the corresponding output is
sat
(model
;; universe for S:
;; S!val!0 S!val!3 S!val!1 S!val!2
;; -----------
;; definitions for universe elements:
(declare-fun S!val!0 () S)
(declare-fun S!val!3 () S)
(declare-fun S!val!1 () S)
(declare-fun S!val!2 () S)
;; cardinality constraint:
(forall ((x S)) (or (= x S!val!0) (= x S!val!3) (= x S!val!1) (= x S!val!2)))
;; -----------
(define-fun B () S
S!val!1)
(define-fun A!0 () S
S!val!0)
(define-fun f!47 ((x!1 S) (x!2 S)) S
(ite (and (= x!1 S!val!2) (= x!2 S!val!1)) S!val!3
S!val!2))
(define-fun k!46 ((x!1 S)) S
(ite (= x!1 S!val!2) S!val!2
(ite (= x!1 S!val!0) S!val!0
(ite (= x!1 S!val!3) S!val!3
S!val!1))))
(define-fun f ((x!1 S) (x!2 S)) S
(f!47 (k!46 x!1) (k!46 x!2)))
(define-fun o!48 ((x!1 S) (x!2 S)) Bool
(ite (and (= x!1 S!val!1) (= x!2 S!val!1)) true
(ite (and (= x!1 S!val!0) (= x!2 S!val!0)) true
(ite (and (= x!1 S!val!2) (= x!2 S!val!2)) true
(ite (and (= x!1 S!val!3) (= x!2 S!val!3)) true
false)))))
(define-fun o ((x!1 S) (x!2 S)) Bool
(o!48 (k!46 x!1) (k!46 x!2)))
)
Please run this example online here
My question is: This refutation with Z3 is correct?
In Z3, if the input script is written in SMTLib format, is it possible to output the model (value assignments satisfying the model)? The get-model returns an interpretation satisfying the constraints. Is there any way to extract the concrete values from these interpretations. I am aware that we can use the python/C++ API to get model values.
You probably want to use get-value, here's a minimal example (rise4fun link: http://rise4fun.com/Z3/wR81 ):
(declare-fun x () Int)
(declare-fun y () Int)
(declare-fun z () Int)
(assert (>= (* 2 x) (+ y z)))
(declare-fun f (Int) Int)
(declare-fun g (Int Int) Int)
(assert (< (f x) (g x x)))
(assert (> (f y) (g x x)))
(check-sat) ; sat
(get-model) ; returns:
; (model
; (define-fun z () Int
; 0)
; (define-fun y () Int
; (- 38))
; (define-fun x () Int
; 0)
; (define-fun g ((x!1 Int) (x!2 Int)) Int
; (ite (and (= x!1 0) (= x!2 0)) 0
; 0))
; (define-fun f ((x!1 Int)) Int
; (ite (= x!1 0) (- 1)
; (ite (= x!1 (- 38)) 1
; (- 1))))
;)
(get-value (x)) ; returns ((x 0))
(get-value ((f x))) ; returns (((f x) (- 1)))
You'd potentially then have to parse this depending on what you're trying to do, etc.
For more details, check out the SMT-LIB standard:
http://smtlib.cs.uiowa.edu/language.shtml
The latest version is: http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.0-r12.09.09.pdf
You can see some examples of get-value on page 39 / figure 3.5.
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)))
)