Efficiency of constraint strengthening in SMT solvers - z3

One way to solve optimisation problems is to use an SMT solver to ask whether a (bad) solution exists, then to progressively add tighter cost constraints until the proposition is no longer satisfiable. This approach is discussed in, for example, http://www.lsi.upc.edu/~oliveras/espai/papers/sat06.pdf and http://isi.uni-bremen.de/agra/doc/konf/08_isvlsi_optprob.pdf.
Is this approach efficient, though? i.e. will the solver re-use information from previous solutions when attempting to solve with additional constraints?

The solver can reuse lemmas learned when trying to solve previous queries. Just keep in mind than in Z3 whenever you execute a pop all lemmas (created since the corresponding push) are forgotten. So, to accomplish that you must avoid push and pop commands and use "assumptions" if you need to retract assertions. In the following question, I describe how to use "assumptions" in Z3:
Soft/Hard constraints in Z3
Regarding efficiency, this approach is not the most efficient one for every problem domain. On the other hand, it can be implemented on top of most SMT solvers. Moreover, Pseudo-Boolean solvers (solver for 0-1 integer problems) successfully use a similar approach for solving optimization problems.

Related

z3 hangs for ever?

Consider the following smt2 file generated with the help of Klee.
I am trying to evaluate it using z3. However, z3 hangs forever. Specifically, when the formula is UNSAT, z3 runs for ever and does not produce any result.
Is formula size is big?
Is there any issue while using logic theory AUFBV?
May I get some suggestions to improve the z3 performance.
Each assert statement having some common subexpression. Is it possible to improve the z3 performance by solving subexpression separately?
This is going to be impossible to answer as the SMT-lib file you've linked is undecipherable for a non-KLEE user. I recommend asking KLEE folks directly using your original program that gave rise to this. Failing that, try to reduce the SMT2Lib to a minimum and see if you can at least hand-annotate to see what it's trying to do.
Regarding your question for common subexpressions: You have to experiment to find out. But the way most such solvers are constructed, they /will/ discover common subexpressions themselves and reuse lemmas about them automatically as they convert your input to an internal representation. So, it'd surprise me if it helped in any significant way to do this by hand; unless the input is really massive. (The example you linked isn't really that big so I doubt that's an issue.)

Should imposing additional constraints improve solving time for SMT solvers?

I have a SMT application (built on Haskell SBV library), which solves some complex equation against single s variable in Real logic using Z3. Finding solution takes about 30 seconds in my case.
Trying to speed things up, I added additional constraint s < 40000, as I have some estimation of solution. I was thinking that such constraint would shrink the search space and make solver return the result faster. However, this only made it slower (it didn't even finished in 10 minutes, actually).
The question is: can it be assumed that additional constraints always slows down/speeds up solution process, or there are no general rules and it always depends on circumstances?
I'm worried that even my 30-seconds algorithm may contain some extra constraint that isn't necessarily needed, but just slows the process.
I don't think you can make any general assumptions about this. It may or may not impact solving time, assuming sat/unsat status doesn't change.
Equalities usually help (as they propagate freely), but for anything else, it's anybody's guess. Also, different solvers can exhibit differing behavior for the same addition.
One way to think about this is that the underlying DPLL(T) algorithm is essentially a very smart glorified search algorithm. It keeps producing "learned lemmas" with the hope that it will find a contradiction with a previously known fact. The new "constraint" you add might cause it to generate a ton of correct but irrelevant lemmas that makes it go down the deep-end with no useful result. (Quantified formulae are usually like this: You can instantiate them in a million different ways; but unless you find the "correct" instantiation, all they do is end up polluting your search space.)
At least that's been my experience!

Z3 performance: many assertions vs large conjunction

In my research I automatically generate SMT2, which I then pass to Z3. The generated code is basically one very large conjunction (and ...) of many different constraints.
Will I be losing (or gaining?) any significant performance by doing this, as opposed to generating many assertions?
You won't be losing or gaining. In almost all settings, Z3 splits any conjunction into multiple assertions and the time it takes to do so is negligible.
This questions has also come up before: Which is better practice in SMT: to add multiple assertions or single and?

Incremental solving in Z3 using push command

I am using Z3's python api to do some kind of incremental solving. I push constraints to the solver iteratively while checking for unsatisfiability at each step using solver.push() command. I want to understand whether Z3 would use the learned lemmas from previous constraints or the satisfying solution previously obtained when solving with a newly added constraint. I never use the solver.pop() command. Where can I get more details about how the work done in previous iterations is used?
Z3 has multiple solvers, but only one of them really supports incremental solving and reuse work from previous calls. By default, Z3 will automatically switch to the incremental solver whenever you execute a solver.push(). This solver alsos reuse previously learned clauses. The learned clauses are deleted when a solver.pop() is executed. Z3 also support another mechanism for incremental solving that is not based on push and pop. Here are some related posts:
Soft/Hard constraints in Z3
How to use z3 incrementally and model without propositional value ?
Incremental calls to Z3 on UFBV with and without push calls

Z3/SMT: When should I prefer push/pop to reset?

I am using Z3 to solve the path conditions produced by a symbolic executor, which explores the state space in depth-first order, quite similarly to CUTE, DART or (possibly) SAGE. We are experimenting different ways of using Z3. At one extreme, we send every query to Z3 and (reset) it right after. At the other, we (push) every additional branch constraint, and (pop) (pop) upon backtrack the minimum necessary to correctly weaken the path condition. The problem is, no strategy seems to work better than any other in all the circumstances. Pushing seems to offer the best advantage, but we met a few cases where resetting Z3 after every query is more than one order of magnitude faster than doing push/pop. Note that communication overhead is negligible: almost all the time is spent inside check-sat.
Does anyone have any experience to share, or some indication on the state kept internally by Z3 (lemmas, etc), which can help clarifying its behavior? And what about the behavior of other SMT solvers?
The next release (v4.3.2) will expose a feature that may be useful for you. In Z3, the default solver combines a non-incremental solver and an incremental one. When push/pop are used (or multiple checks are used without invoking reset), Z3 will use the incremental solver. In the next release, we can provide a timeout for the incremental solver. If the incremental solver can't solve the problem in the given timeout, Z3 will automatically switch to the non-incremental one. Perhaps, if you use this feature, you will be able to get the best of "both worlds". To get the source code for the next release candidate, you should use
git clone https://git01.codeplex.com/z3 -b rc
To compile it, we have use
cd z3
python scripts/mk_make.py
cd build
make
To set the timeout for the incremental solver, we have to provide the following command line option:
combined_solver.solver2_timeout=<time in milliseconds>
If you are using the programmatic APIs, you can the new API:
Z3_global_param_set(Z3_string param_id, Z3_string param_value)
Note that, the next release will have a new framework for setting parameters. It allows the user to set parameters for internal Z3 modules.

Resources