I want to trigger the running time of theory solver to see how much time does each theory checking take. Does anyone know which file and which variable do I need to look at? I don't know if the statistics method has this option.
According to this answer, Christoph Wintersteiger "expect[s] this to be nontrivial as it's not clear what exactly should and shouldn't be counted."
For the special case of Z3's SAT solver, this answer by Leonardo de Moura mentions several methods (such as bcp() and decide()) in a particular C++ file (smt_context.cpp) of Z3's sources that belong to this particular sub-solver.
Related
In constraint solver like Gecode , We can control the exploration of search space with help of branching function. for e.g. branch(home , x , INT_VAL_MIN ) This will start exploring the search space from the minimum possible value of variable x in its domain and try to find solution.(There are many such alternatives .)
For z3, do we have this kind of flexibility in-built ?? Any alternative possible??
SMT solvers usually do not allow for these sorts of "hints" to be given, they act more as black-boxes.
Having said that, each solver uses a ton of internal heuristics, and z3 itself has a number of settings that you can play with to give it hints. If you run:
z3 -pd
it will display all the options you can provide, and there are literally over 600 of them! Unfortunately, these options are not really well documented, and how they impact the solver is rather cryptic. The only reliable way to find out would be to study the source code and see what they do, which isn't for the faint of heart. But in any case, it will not be as obvious as the branch feature you cite for gecode.
There are, however, other tricks one can use to speed up solving for SMT-solvers, unfortunately, these things are usually very problem-specific. If you post specific instances, you might get better suggestions.
I am using the python API of the Z3 solver to search for optimized schedules. It works pretty well apart from that it sometimes is very slow even for small graphs (sometimes its very quick though). The reason for that is probably that the constraints of my scheduling problem are quite complex.
I am trying to speed things up and stumbled on some articles about incremental solving.
As far I understood, you can use incremental solving to prune some of the search space by only applying parts of the constraints.
So my original code was looking like that:
for constraint in constraint_set:
self._opt_solver.add(constraint)
self._opt_solver.minimize(some_objective)
self._opt_solver.check()
model = self._opt_solver.mode()
I changed it now to the following:
for constraint in constraint_set:
self._opt_solver.push(constraint)
self._opt_solver.check()
self._opt_solver.minimize(some_objective)
self._opt_solver.check()
model = self._opt_solver.mode()
I basically substituted the "add" command by the "push" command and added a check() after each push.
So first of all: is my general approach correct?
Furthermore, I get an exception which I can't get rid of:
self._opt_solver.push(constraint) TypeError: push() takes 1 positional argument but 2 were given
Can anyone give me a hint, what I am doing wrong. Also is there maybe a z3py tutorial that explains (with some examples maybe) how to use incremental solving with the python api.
My last question is: Is that at all the right way of minimizing the execution time of the solver or is there a different/better way?
The function push doesn't take an argument. It creates a "backtracking" point that you can pop to later on. See here: http://z3prover.github.io/api/html/classz3py_1_1_solver.html#abc4ae989afee7ad164844640537107d9
So, it seems push isn't really what you want/need here at all. You should simply add your constraints one-by-one and call check. However, I very much doubt checking after each addition is going to speed anything up significantly. The optimizing solver (as opposed to the regular one), in particular, usually solves everything from scratch. (See the relevant discussion here: https://github.com/Z3Prover/z3/issues/1577)
Regarding incremental: The python API is automatically "incremental." Incremental simply means the ability to call the command check() multiple times, without the solver forgetting what it has seen before. (i.e., call check, assert more facts, call check again; the second check will take into account all the assertions from the very beginning.) You shouldn't make any assumptions regarding this will give you speed over calling check just once at the very end: It entirely depends on the heuristics and the decision procedures involved, which is dependent on the problem at hand.
I'm trying to find the c++ file for Z3 where the algorithm backtraces if it can't find a solution on the current branch. I've been looking through all the files and tried debug mode on the python files, but no luck so far. I just want to add a print statement to the method, so I can tell when it is returning to a previous node and trying a new path.
Thanks!
It depends on which solver Z3 uses for your problem. It typically uses smt_context.cpp in src/smt. The relevant backjump can be traced in the context::pop_scope method. Other solvers exist too: the src/sat/sat_solver is used for bit-vector and Boolean problems. It has a similar pop method. Finally, nlsat is used for non-linear polynomial arithmetic over the reals.
I notice that the Z3 C++ (and C) API allows you to supply the logic to be used.
I have two questions about this that I couldn't answer by looking online:
Are these supposed to be the standard SMT-LIB logics i.e. QF_LRA
When are these worth supplying i.e. when will Z3 actually use this information
My context is mainly QF no BV but everything else possible, I am using the SMT solver incrementally and I can always work out what logic I will be in at the start.
Z3 will also try to figure out what the logic is (when run with default options), but it doesn't have custom tactics for all combinations of theories (see default_tactic.cpp and smt_strategic_solver.cpp). When you are not sure what Z3 will decide to do, then it's best to set the tactic right up front, so that you will get errors if you try to use things that are not in that logic. It will also use that information to set up the smt kernel, e.g., enabling various preprocessors, various solver features, and chosing heuristics (see e.g., smt_setup.cpp).
Try it out and see!
Usually it does make a big difference. Setting the logic means the solver will use a specialized tactic to solve the formula, instead of going through the generic loop. Z3 will also try to guess the logic, but it's usually better to just provide it upfront.
I obtained several statistics from runs of Z3. I need to understand what these mean.
I am rather rusty and non up to date for the recent developments of sat and SMT solving, for this reason I tried to find explanations myself and I might be dead wrong.
So my questions are mainly:
1) What do the measures' names mean?
2) If wrong, can you give me pointers to understand better to what they refer to?
Other observations are made below and conceptually belong to the two questions above.
Thanks in advance!
My interpretation follows.
DPLL. All the metrics below refer to the jargon of the DPLL algorithm which is the foundation of most solvers.
:decisions
Number of decisions
:propagations
Number of propagations (I guess unit propagations)
:binary-propagations, :ternary-propagations
Propagations of two and three literals at once
:conflicts
Number of conflicts
RESOLUTION. Operations made interpreting clauses as sets, roughly speaking; techniques taken from resolution which is another paradigm for solving SAT.
:subsumed
:subsumption-resolution
What is the difference between the above two?
:dyn-subsumption-resolution
Should be described here: Learning for Dynamic Subsumption, by Hamadi et al.
OTHER TECHNIQUES
:minimized-lits
No clear idea. Is it probably related with clause learning?
:probing-assigned
I guess it counts the number of assignment made when "probing", which I guess is some kind of lookahead technique.
:del-clause
Number of deleted clauses (for what reason? Redundant?)
:elim-literals :elim-clauses :elim-bool-vars :elim-blocked-clauses
Number of entities after the elim- eliminated.
These metrics refer to particular SAT solving techniques
(see for reference Blocked Clause Elimination, by M.Järvisalo et al.)
:restarts
Number of restarts.
OTHER ASPECTS
:mk-bool-var :mk-binary-clause :mk-ternary-clause :mk-clause
Number of boolean variables and binary,ternary and generic clauses created.
:memory
Maximum amount of memory used.
:gc-clause
Garbage-collected clauses ...?
This interpretation is plausible according to my experiments since it's always the case that
:gc-clause <= :del-clause ; in my case the disequality is strict.
It is not always the case that
:gc-clause<=:elim-clauses; it can also be :gc-clause > :elim-clauses
I am afraid this is an open-ended question.
Z3 exposes many counters that are collected in many different ways.
While many capture abstract concepts, their meanings are ultimately
based on implementation behaviors of the code.
Fortunately the source code is available and provides the full context
for understanding the behavior of each counter. So there is no single
document that tracks the meaning of the counters, but the source code
is made available to give the full context.