Understanding the index of all constants of a model - z3

I guess my issue is linked with Read func interp of a z3 array from the z3 model, but still I can't understand how to fix it.
Edit: I think it is also linked with de bruijn index: Understanding the indexing of bound variables in Z3
Here is the small example I have built to explain the problem:
#include <iostream>
#include <sstream>
#include <cassert>
#include "z3++.h"
using namespace z3;
int main(void)
{
context ctx;
params p(ctx);
p.set("MACRO_FINDER",true);
expr_vector v(ctx);
sort_vector sv(ctx);
for(int i = 0; i < 3; i++)
{
std::ostringstream o;
o << "c[" << i << "]";
expr c = ctx.bv_const(o.str().c_str(),1);
v.push_back(c);
sv.push_back(ctx.bv_sort(1));
}
expr x = ctx.bv_const("x",8);
v.push_back(x);
sv.push_back(ctx.bv_sort(8));
expr one_bit = ctx.bv_val(1,1);
expr two = ctx.bv_val(2,8);
expr one = ctx.bv_val(1,8);
expr zero = ctx.bv_val(0,8);
expr fcore = x + ite(v[1] == one_bit , one, zero) + ite(v[2] == one_bit, two, zero);
func_decl f = ctx.function("f",sv,ctx.bv_sort(8));
solver s(ctx);
s.set(p);
s.add(forall(v,f(v) == fcore));
expr_vector t1(ctx);
expr_vector t2(ctx);
t1.push_back(v[0]); t1.push_back(v[1]); t1.push_back(v[2]); t1.push_back(ctx.bv_val(0,8));
t2.push_back(v[0]); t2.push_back(v[1]); t2.push_back(v[2]); t2.push_back(ctx.bv_val(1,8));
expr constraints = (f(t1) == ctx.bv_val(1,8)) && (f(t2) == ctx.bv_val(2,8));
s.add(exists(v[0],v[1],v[2],constraints));
std::cout << "Solver: " << s << "\n\n";
if(s.check()==sat)
{
model m = s.get_model();
std::cout << "Model: " << m << "\n\n";
std::cout << "Number of constants: " << m.num_consts() << "\n";
expr F = m.eval(f(v),true);
for(size_t i = 0; i < m.num_consts(); ++i)
std::cout << "\t constant " << i << ": " << "(" << m.get_const_decl(i).name() << ") " << m.get_const_interp(m.get_const_decl(i)) << "\n";
std::cout << "Number of functions: " << m.num_funcs() << "\n";
std::cout << "\t" << F << "\n";
}
else
std::cout << "unsat\n";
return 0;
}
By runing this program, I get the following output:
Solver: (solver
(forall ((|c[0]| (_ BitVec 1))
(|c[1]| (_ BitVec 1))
(|c[2]| (_ BitVec 1))
(x (_ BitVec 8)))
(= (f |c[0]| |c[1]| |c[2]| x)
(bvadd x (ite (= |c[1]| #b1) #x01 #x00) (ite (= |c[2]| #b1) #x02 #x00))))
(exists ((|c[0]| (_ BitVec 1)) (|c[1]| (_ BitVec 1)) (|c[2]| (_ BitVec 1)))
(and (= (f |c[0]| |c[1]| |c[2]| #x00) #x01)
(= (f |c[0]| |c[1]| |c[2]| #x01) #x02))))
Model: (define-fun |c[2]!0| () (_ BitVec 1)
#b0)
(define-fun |c[1]!1| () (_ BitVec 1)
#b1)
(define-fun f ((x!1 (_ BitVec 1))
(x!2 (_ BitVec 1))
(x!3 (_ BitVec 1))
(x!4 (_ BitVec 8))) (_ BitVec 8)
(bvadd x!4 (ite (= #b1 x!3) #x02 #x00) (ite (= #b1 x!2) #x01 #x00)))
Number of constants: 2
constant 0: (c[2]!0) #b0
constant 1: (c[1]!1) #b1
constant 2: (c[0]) #b0
constant 3: (c[1]) #b0
constant 4: (c[2]) #b0
constant 5: (x) #x00
Number of functions: 1
#x00
I don't get:
Why it enumerates 6 constants and not 3 ?
How to retrieve the value of the nth constant of vector "v" without parsing their name, which is not the nth constant of the model "m" ?
Why c[1] evaluates to 0 while I would have expected it to evaluate to 1 ?
What "!x" means in the name of the constant c[2]!0 and c[1]!1 ?
I would like to re-inject evaluations of c[0], c[1] and c[2] into the function f() in order to simplify its expression (I expect to get x+1)
Note: c[0] is not used on purpose...

Thanks Tushar for answering the post. You are right that the additional variables come from the existential quantifier. Z3 will skolemize these variables and as it currently stands, the model returned by Z3 includes constants from skolemized existential quantifiers.
This is evidently confusing and we may in the future filter
such variables (and functions) away from the model construction. On the other hand, the naming conventions used for the existential variables retain the names from the quantifiers so that it may be possible, at least manually, to track back the origin of those extra variables.

Related

Handling quoted expressions in Z3

I'm currently working with Z3's unsat_core functionality in the context of a model checking class at university.
The issues arises when trying to work with the assumptions that Z3 provides me with in the core:
E.g.:
z3::expr_vector unsat_core = exp_solver.unsat_core();
for(auto const c : unsat_core) {
DEBUG << "\n" << c;
}
prints a list containing, for example, such an expression:
|(let ((a!1 (bvnot (ite (= current_state_V0 ((_ zero_extend 1) #b11)) #b1 #b0))))
(let ((a!2 (bvnot (bvand a!1 (bvnot ((_ extract 2 2) current_state_V0))))))
(let ((a!3 (bvor a!2
(ite (= next_state_V0 (bvadd current_state_V0 #b001)) #b1 #b0)
(bvnot #b1))))
(= a!3 #b1))))|
We add and track expressions via this wrapper:
void add_and_track(z3::solver& s, z3::expr_vector const &v)
{
check_context(s, v);
for (unsigned i = 0; i < v.size(); ++i)
{
s.add(v[i], v[i].to_string().c_str());
}
}
I now need to encode these assumptions with my primed variables and I intend to use z3::expr::substitute for that, but that does not seem to work.
DEBUG << unsat_core[0];
z3::expr foo = unsat_core[0].substitute(V0, V1);
DEBUG << unsat_core[0];
DEBUG << foo;
all DEBUG calls print out the exact same (quoted) expression from above.
V0 and V1 are z3::expr_vectors containing the variables and the primed variables, and DEBUG is a wrapper around std::cout.
My best guess is that these expressions are 'quoted' https://www.lri.fr/~conchon/TER/2013/2/SMTLIB2.pdf#page=22 Is this correct?
What I would like to achieve is either to be able to substitute or the extract the expression that is, as I am guessing, quoted.

Having assertions inside definitions in SMT

I want to capture the assertion inside fac.
int f( x )
{
if( x == 1) return 1;
else{
assert( x > 0 );
return 2;
}
}
int g (x)
{ assert( x > 5 );
return f(x-1) + f(x-2);
}
I want an smt2 code for this.
I can do this by striping the argument and making it global with unique name (also rename inside f), then do this 3 times each with a different name for function. Like below :
( declare-const x1 Int )
(define-fun f1 () Int
( ite ( x1 > 0) 1 2 )
)
(assert (> x1 0))
( declare-const x2 Int )
(define-fun f2 () Int
( ite ( x2 > 0) 1 2 )
)
(assert (> x2 0))
( declare-const x3 Int )
(define-fun g1 () Int
( + f1 f2 )
)
(assert (> x3 5))
I don't want to this. Is there any other way to do this without repeating ?
EDIT
My purpose is to find values violating the asserts.
As far as I know, it is not possible to embed assertions within function definitions.
What I would try to do is to separate the expected behavior, the input assumptions and the output guarantees (if any).
Example:
(define-fun f ((x Int)) Int
(ite (= x 1) 1 2)
)
(define-fun f-helper ((x Int)) Bool
(< 0 x)
)
(define-fun g ((x Int)) Int
(+ (f (- x 1)) (f (- x 2)))
)
(define-fun g-helper ((x Int)) Bool
(and (< 5 x)
(f-helper (- x 1))
(f-helper (- x 2))
)
)
(declare-const x Int)
(declare-const y Int)
(assert (and (= y (g x))
(g-helper x)
))
(check-sat)
(get-model)
In this example we use f to model the behavior of the original function f, and f-helper to model the assumptions of f. The output, using the online Z3 tool, is as follows:
sat
(model
(define-fun x () Int
6)
(define-fun y () Int
4)
)
I would conclude saying that this approach could become tricky as soon as f and g are used inside both positive and negative contexts.. in this case one should pay extra attention that the polarity of the assertions is correct wrt. the expected result.

Converting Z3 QBF formula directly to pcnf

I'm using Z3 theorem prover (using Z3Py: the Z3 API in Python) to create QBF (Quantified Boolean formula).
Is there any way in Z3 to directly convert your qbf formula into Prenex normal form ?
I don't think there's a tactic to convert to Prenex, but you can surely apply the quantifier-elimination tactic and further process your formulas. Note that the transformed formulas will not really look like the originals, as they are mechanically generated.
Here's an example:
from z3 import *
f = Function('f', IntSort(), IntSort(), IntSort())
x, y = Ints('x y')
p = ForAll(x, Or(x == 2, Exists(y, f (x, y) == 0)))
print Tactic('qe')(p)
Here qe is the quantifier elimination tactic. This produces:
[[Not(Exists(x!0,
Not(Or(x!0 == 2,
Exists(x!1,
And(f(x!0, x!1) <= 0,
f(x!0, x!1) >= 0))))))]]
For a nice tutorial on tactics, see here: http://ericpony.github.io/z3py-tutorial/strategies-examples.htm
You could use the skolemize tactic (snf) which will by definition be in prenex form. However it will also eliminate existential quantifiers which is not what you want. Here's an example.
(declare-fun a (Int) Bool)
(declare-fun b (Int) Bool)
(declare-fun c (Int) Bool)
(assert
(forall ((x Int))
(or
(exists ((y Int))
(a y)
)
(exists ((z Int))
(=>
(b z)
(c x)
)
)
)
)
)
(apply
(and-then
; mode (symbol) NNF translation mode: skolem (skolem normal form), quantifiers (skolem normal form + quantifiers in NNF), full (default: skolem)
(using-params snf :mode skolem)
)
:print_benchmark true
:print false
)
When Z3 is given the above it will responds with something like
(declare-fun c (Int) Bool)
(declare-fun b (Int) Bool)
(declare-fun a (Int) Bool)
(assert (forall ((x Int))
(or (exists ((y Int)) (a y)) (exists ((z Int)) (=> (b z) (c x))))))
(check-sat)
You can see the available tactics by running
echo "(help-tactic)" | ./z3 -in | less
from a bash shell.
Unfortunately I can't see one that states it does conversion to prenex.

Implicit vs explicit existential quantification in SMT formulas

Given the following code:
from z3 import *
a,b,c = BitVecs('a b c', 32)
f1 = Exists([a, b, c], And(a + b == c, a < b, c == 1337))
f2 = And(a + b == c, a < b, c == 1337)
prove(f1 == f2)
I would assume that z3 implicitly existential quantifies a, b and c, in this example. Why aren't the two formulas equal, what is the difference?
The way you formulated your query doesn't really check whether f1 equals f2. Your query is essentially asking the solver to find a, b, c such that the following fails to hold:
Exists([a, b, c], And(a + b == c, a < b, c == 1337))
=
And(a + b == c, a < b, c == 1337))
And indeed, you can instantiate the outer a, b, and c such that the right hand-side is false; but the left hand side is an existential which is true; thus failing the equivalence you asked for.
It might be easier to see this with a simpler example; with just one boolean variable. You're essentially asking:
x == (Exists [x], x)
You see that those xs are actually different, so we can rename the inner one to (say) y; we get:
x == (Exist [y]. y)
Now, the right-hand-side is clearly true since there is a y that makes (Exist [y]. y) true. So, you are essentially asking the prover to establish that no matter what x you pick, it is true. Which is definitely not the case when you pick x to be false.
Indeed, you can ask Z3 to give you the formula it's trying to prove, and this is what it returns for your original query:
(set-info :status unknown)
(declare-fun c () (_ BitVec 32))
(declare-fun b () (_ BitVec 32))
(declare-fun a () (_ BitVec 32))
(assert
(let (($x24 (exists ((a (_ BitVec 32))
(b (_ BitVec 32))
(c (_ BitVec 32)) )
(and (= (bvadd a b) c) (bvslt a b) (= c (_ bv1337 32))))))
(let (($x57 (= $x24 (and (= (bvadd a b) c) (bvslt a b) (= c (_ bv1337 32))))))
(and $x57))))
(check-sat)
Which is clearly satisfiable, by the above reasoning.
(See Z3: convert Z3py expression to SMT-LIB2 from Solver object for the code that converts a z3-python query to smt-lib.)

function to get nibbles using Z3 and bitvector theory

I'm trying to learn a little about z3 and the bit vector theory.
My intention is to make a function to get the nibble from a position of the bitvector
This code returns the nibble:
(define-fun g_nibble(
(l ( _ BitVec 12))
(idx (Int))
) ( _ BitVec 4)
(ite
(= idx 1) ((_ extract 11 8) l)
(ite
(= idx 2) ((_ extract 7 4) l)
(ite
(= idx 3) ((_ extract 3 0) l)
(_ bv0 4)
)
)
))
the problem is that i want avoid the multiples ite calls.
I tried to replace ((_ extract 3 0) l) for somthing like ((_ extract (+ 4 idx) idx l) but it doesn't work.
Thanks
P.S: The idea is use z3 from command line (without using any library).
The extract function only takes numerals as arguments, not arbitrary expressions. However, we can shift the expression to one direction and then extract the first or last four bits, e.g. along the lines of
((_ extract 11 8) (bvshl l (bvmul idx four)))
(where idx and four are bit-vector expressions of size 12).

Resources