Control the solving strategy of Z3 - z3

So lets assume I have a large Problem to solve in Z3 and if i try to solve it in one take, it would take too much time. So i divide this problem in parts and solve them individually.
As a toy example lets assume that my complex problem is to solve those 3 equations:
eq1: x>5
eq2: y<6
eq3: x+y = 10
So my question is whether for example it would be possible to solve eq1 and eq2 first. And then using the result solve eq3.
assert eq1
assert eq2
(check-sat)
assert eq3
(check-sat)
(get-model)
seems to work but I m not sure whether it makes sense performancewise?
Would incremental solving maybe help me out there? Or is there any other feature of z3 that i can use to partition my problem?

The problems considered are usually satisfiability problems, i.e., the goal is to find one solution (model). A solution (model) that satisfies eq1 does not necessarily satisfy eq3, thus you can't just cut the problem in half. We would have to find all solutions (models) for eq1 so that we can replace x in eq3 with that (set of) solutions. (For example, this is what happens in Gaussian elimination after the matrix is diagonal.)

Related

Some questions about incremental SAT in Z3: can it be deactivated? Which techniques are used inside?

I am still in the process of learning the guts of Z3 (Python).
It was brought to my attention that Z3 performs incremental SAT solving by default (see SAT queries are slowing down in Z3-Python: what about incremental SAT?): specifically, every time you use the s.add command (where s is a solver), it means that it adds that clause to s, but it does not forget everything you have learned before.
First question: can non-incremental SAT solving be done in Z3? That is, somehow 'deactivate' the incremental solving. What would this mean? That we are creating a new solver for each enlarged formula?
For instance, this approach would be Z3-default-incremental:
...
phi = a_formula
s = Solver()
s.add(phi)
while s.check() == sat:
s.check()
m = s.model()
phi = add_modelNegation(m)
s.add(phi) #in order not to explore the same model again
...
That is, once we get a model, we attach the negated model to the same solver.
While this one is 'forcing' Z3 to be non-incremental:
...
phi_st = a_formula
s = Solver()
s.add(phi_st)
negatedModelsStack = []
while s.check() == sat:
m = s.model()
phi_n = add_modelNegation(m)
negatedModelsStack.append(phi_n)
original_plus_negated = And(phi_st, And(negatedModelsStack))
s = Solver()
s.add(original_plus_negated) #in order not to explore the same model again
...
That is, once we get a model, we attach the obtained models to a new solver.
Am I right?
On the other hand, in the attached link, the following is stated:
Compare this to, for instance, CVC4; which is by default not incremental. If you want to use CVC4 in incremental mode, you have to pass a specific command line argument
Does this mean in CVC4 you must create a new solver every time? Like in the second code?
Second question: how can I know exactly what techniques I am using to do incremental solving in Z3? I have been reading about incremental SAT theory and I see that one of those techniques is 'CDCL' (http://www.cril.univ-artois.fr/~audemard/slidesMontpellier2014.pdf), is this used in Z3's incremental search?
References: In order not to inundate Stack with similar questions, which readings do you recommend for incremental SAT in general and Z3's incremental SAT in particular? Also, is the incremental SAT of Z3 similar to the ones of other solvers such as MiniSAT or PySAT?
I'm not sure why you're trying to get z3 to act in a non-incremental way. But, if that's your goal, simply do not call check more than once: That's equivalent to being non-incremental. (Think of being incremental an "additional feature." You don't have to use it. The only difference between z3 and cvc4 is that the latter requires you to tell it ahead of time that you intend to use it in an incremental fashion, while the former is incremental by default.) As an end user you don't really need to know or care about the difference.
Side note If you start cvc4 without telling it to be incremental and call check twice, it'll complain. z3 won't. But otherwise the experience should be the same.
I don't think knowing how solvers implement incrementally is really helpful from a programming perspective. (It's of course paramount if you are implementing your own SMT solver.) There are many papers online for many aspects of SMT, though if you want to study the topic from scratch I recommend Daniel and Ofer's book on decision procedures: http://www.decision-procedures.org

Obtaining representation of SMT formula as SAT formula

I've come up with an SMT formula in Z3 which outputs one solution to a constraint solving problem using only BitVectors and IntVectors of fixed length. The logic I use for the IntVectors is only simple Presburger arithmetic (of the form (x[i] - x[i + 1] <=/>= z) for some x and z). I also take the sum of all of the bits in the bitvector (NOT the binary value), and set that value to be within a range of [a, b].
This works perfectly. The only problem is that, as z3 works by always taking the easiest path towards determining satisfiability, I always get the same answer back, whereas in my domain I'd like to find a variety of substantially different solutions (I know for a fact that multiple, very different solutions exist). I'd like to use this nifty tool I found https://bitbucket.org/kuldeepmeel/weightgen, which lets you uniformly sample a constrained space of possibilities using SAT. To use this though, I need to convert my SMT formula into a SAT formula.
Do you know of any resources that would help me learn how to perform Presburger arithmetic and adding the bits of a bitvector as a SAT instance? Alternatively, do you know of any SMT solver which as an intermediate step outputs a readable description of the problem as a SAT instance?
Many thanks!
[Edited to reflect the fact that I really do need the uniform sampling feature.]

Optimize Solver Tactics for Circuit SAT

I am using the Z3 solver with Python API to tackle a Circuit SAT problem.
It consists of many Xor expressions with up to 21 inputs and three-input And expressions. Z3 is able to solve my smaller examples but does not cope with the bigger ones.
Rather than creating the Solver object with
s = Solver()
I tried to optimize the solver tactics like in
t = Then('simplify', 'symmetry-reduce', 'aig', 'tseitin-cnf', 'sat' )
s = t.solver()
I got the tactics list via describe_tactics()
Unfortunately, my attempts have not been fruitful. The default sequence of tactics seems to do a pretty good job. The tactics tutorial previously available in rise4fun is no longer accessible.
Another attempt - without visible effect - was to set the phase parameter, as I am expecting the majority of my variables to have false values. (cf related post)
set_option("sat.phase", "always-false")
What sequence of tactics is recommended for Circuit SAT problems?

z3py: What is a correct way of asserting a constraint of "something does not exist"

I want to assert a constraint of "something must not exist" in z3py. I tried using "Not(Exists(...))". A simple example is as follows. I want to find a assignment for a and b, so that such c does not exist.
from z3 import *
s = Solver()
a = Int('a')
b = Int('b')
c = Int('c')
s.add(a+b==5)
s.add(Not(Exists(c,And(c>0,c<5,a*b+c==10))))
print s.check()
print s.model()
The output is
sat
[b = 5, a = 0]
Which seems to be correct.
But when I write "Not(Exists(...))" constraint in a more complex problem, it would take hours without generating a solution.
I wonder if this is the correct and the most efficient way to assert "not exist" constraint? Or such problems with quantifiers are intrinsically hard to solve by any solver?
The way you wrote that constraint is just fine. And it is not surprising that Z3 (or any other solver) would have a hard time solving such problems as you have both quantifiers and non-linear arithmetic. Such problems are intrinsically hard to solve.
You might look into Z3's nlsat tactic, which might provide some relief here: How does Z3 handle non-linear integer arithmetic?
Or, you can try reals instead of integers, or bit-vectors (i.e., machine integers). Of course, whether you can actually use these types would depend on your problem domain. (Reals will have "fractional" values obviously, and bitvectors are subject to modular-arithmetic.)

Z3: Function Expansion and Encoding in QBVF

I am trying to encode formulas with functions in Z3 and I have an encoding problem. Consider the following example:
f(x) = x + 42
g(x1, x2) = f(x1) / f(x2)
h(x1, x2) = g(x1, x2) % g(x2, x1)
k(x1, x2, x3) = h(x1, x2) - h(x2, x3)
sat( k(y1, y2, y3) == 42 && k(y3, y2, y1) == 42 * 2 && ... )
I would like my encoding to be both efficient (no expression duplication) and allow Z3 to re-use lemmas about functions across subproblems. Here is what I have tried so far:
Inline the functions for every free variable instantiation y1, y2, etc. This introduces duplication and performance is not as good as I hoped for.
Assert the function declarations with universal quantifiers. This works for very specific examples - from the solving times it seems that Z3 can (?) re-use results from previous queries that involve the same functions. However, solving times vary greatly and in many cases (1) turns out to be faster.
Use function definitions (i.e., quantifiers + the MACRO_FINDER option). If my understanding of the documentation is correct, this should expand the functions and thus should be close to (1). However, in terms of performance the results were a bit surprising (">" means faster):
For problems where (1) > (2) I get: (1) > (3) > (2)
For problems where (2) > (1) I get: (2) > (1) = (3)
I have also tried tweaking the MBQI option (and others) with most of the above. However, it is not clear what is the best combination. I am using Z3 4.0.
The question is: What is the "right" way to encode the problem? Note that I only have interpreted functions (I do not really need UF). Could I use this fact for a more efficient encoding and avoid function expansion?
Thanks
I think there's no clear answer to this question. Some techniques work better for one type of benchmarks and other techniques work better for others. For the QBVF benchmarks we've looked at so far, we found macros give us the best combination of small benchmark size and small solving times, but this may not apply in this case.
Your understanding of the documentation is correct, the macro finder will identify quantifiers that look like function definitions and replace all other calls to that function with its definition. It's possible that not all of your macros are picked up or that you are using quasi-macros which aren't detected correctly, either of which could go towards explaining why the performance is sometimes worse than your (1). How much is the difference in the case that (1) > (3)? A little overhead is to be expected, but vast variations in runtime are probably due to some macros being malformed or not being detected.
In general, the is no "right" way to encode these problems. Function expansion can not always be avoided. The trade-off is essentially between expanding eagerly (1, 3), or doing it lazily (2). It may be that there is a correlation of the type SAT (1, 3 faster) and UNSAT (2 faster), but this is also not guaranteed to be the case.

Resources