Copying Z3 Solver - z3

I have seen in the post: Is it possible to clone Z3_context? that the ability to copy/clone the solver was planned for addition to Z3, to facilitate some backtracking behaviour. I have looked in the C API documentation and I could not currently find a way to do this.
Is it now possible to copy the solver through the C API?

The API does not have a method for copying a Solver object, but it can be simulated using Z3_solver_get_assertions and Z3_solver_assert. The idea is to create a new Solver object, and copy the assertions from the old to the new.

Related

Procedural Attachment in Z3

I am using z3py I have a predicate over two integers that needs to be evaluated using a custom algorithm. I have been trying to get it implemented, without much success. Apparently, what I need is a procedural attachment, which is now deprecated. Could anybody tell me how I might impelement this in z3py? I understand that it involves use of Tactics, but I am afraid I haven't managed to figure out how to use them. I wouldn't mind using the deprecated way either, as long as it works.
There is no procedural attachment tactic. All tactics are implemented inside of Z3;
you can compose tactics from outside.
Previous versions of Z3 exposed a way to register a "user theory".
This was deprecated since (1) the source of Z3 is now available so users can compile with their custom theories directly, (2) the user-theory abstraction lacked proper support
for model generation. You can of course try previous versions of Z3 that have the user theory extension, but it is not supported.

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.

Using theory plugins with solvers

Recent versions of Z3 have decoupled the notions of Z3_context and Z3_solver. The API mostly reflects these changes; for instance push is deprecated on contexts and respecified as taking a solver as an extra argument.
The interface for theories has not been updated, however. Theories are still created from contexts, and as far as I can tell, never explicitly attached to solvers.
One could think that a theory created from a context will always be attached to all solvers created from the context, but it seems from our experience that this is not the case. Instead, user-defined theories seem to be ignored entirely.
What is the exact status of the combination of Z3_solvers with Z3_theorys ?
The theory plugins were introduced a long time ago (version 2.8), since then Z3 has changed a lot.
They are considered deprecated in Z3 4.x. They can still be used with the old API, but can't be used with new features and in particular with Z3 solver objects (Z3_solver).
In the current Z3, we have many different solvers. The oldest one (implemented in the folder src/smt) is called smt::context. The theory plugins are actually extensions for this old solver.
We say smt::context is a general purpose solver as it supports many theories and quantifiers.
Actually, in Z3 4.3.1, it is the only general purpose solver available.
However, I believe it is based on an obsolete architecture that is not adequate for the new features we are planning for Z3. My plan is to replace it in the future with a solver based on the architecture described here.
Moreover, we don't really work on smt::context anymore. We are essentially just maintaining it and fixing bugs.
After we released the Z3 source code, I imagined the theory plugin support was not necessary anymore since users would be able to add their extensions inside the Z3 code base. However, this view is too simplistic since it prevents users from writing extensions in different programming languages.
So, the current plan is to eventually have theory plugins for the new solver that will be eventually available in Z3. The goal is to have an API such as:
Z3_solver Z3_mk_mcsat_solver(Z3_context ctx, Z3_mcsat_ext ext);
This API would create a new solver object using the given extension ext.
In the meantime, we could also extend the API with a function such as:
Z3_solver Z3_mk_smt_solver(Z3_context ctx, Z3_theory t);
That would create a new solver object based on smt::context using the given theory plugin.
This solution is conceptually simple, but there is a lot of "plumbing" needed to make it happen.
We have to adjust the Z3_theory object, fix some limitations that prevent theory plugins to be used with features that create copies of smt::context (e.g., MBQI), etc. If someone is very interested in this interface, I would invest cycles on it (remark: we had only a handful of users for the theory plugins). I'm not super excited about it because the plan is to eventually replace smt::context.

Z3 Context serialization/deserialization?

Is it possible to serialize/deserialize a Z3 context (from C#)?
If not, is this feature planned ?
I think this feature is important for real world applications.
This is not directly supported in the current API. The next release will support multiple solvers, and we will provide commands for copying the assertions from one solver to another, and retrieving the assertions. With these commands, one can implement serialization by dumping the expressions in a file (in SMT 2.0 format). To deserialize, we just read the file back.
Note that, this solution can already be implemented using the current API if you keep track of the assertions you asserted into the logical context.
That being said, I've seen the following approach used in many projects that use Z3. They have their own representation for formulas. When they invoke Z3, they translate their representation into Z3's representation. In most cases the performance overhead is minimal. This approach gives them a lot of flexibility. Serialization is a good example. Some programming environment (e.g., Python) already provide some built-in support for serialization.

Resources