Scenario
In the world of mathematical optimization, the need to model inequality g_k(...) constraints arises. g_k(...) can sometimes be a function call to an external program that is, for all intents and purposes, a blackbox. Simply finding satisfactory answers can be beneficial for certain engineering analysis.
Example
An example application of the above scenario for Reals, but could also be Ints or Booleans:
min f(x,y)
g1(x,y) <= 25
g2(x,y) >= 7.7
x,y ε Real
x >= 0
x <= 50.0
y >= 0
y <= 5.0
g1 and g2 are Python functions that call an external program. The functions return a real number. Following this Z3 format to find a model that simply satisfies the constraints would be represented as:
from z3 import *
from ExternalCodes import Code1, Code2 #For example, these could be Python wrappers to C++ codes
def g_1(x, y):
return Code1(x, y) #isinstance(Code1(x,y), float) == True
def g_2(x, y):
return Code2(x, y) #isinstance(Code2(x,y), float) == True
s = Solver()
x, y = Reals('x y')
s.add(g_1(x, y) <= 25.0)
s.add(g_2(x, y) >= 7.7)
s.add(x <= 0)
s.add(50.0 <= x)
s.add(y <= 0)
s.add(5.0 <= y)
m = s.model()
print(m)
Questions
I understand that the type returned by Code1 and Code2 need to be Z3
datatypes. How do I convert Python types to Z3 types like mentioned in the 1st
comment
How is Z3 used to find a sat model when constraints may need to be
evaluated in external code, i.e. declare functions? I understand it
may be inefficient, I would loose heuristics, etc., because it is undecidable,
but for certain engineering applications, enumerating a sat solution, if it
exists, is more advantageous than employing an optimizer from the get-go.
Relevant answers
z3python: using math library
-Not quite the same application. I'm curious if, 4 years later, is this answer still the case, but this is not my question.
Can Z3 call an externally defined function?
-In essence, the same question. No Z3Py answer, and unfortunately, the Rise4fun link is broken. I also cannot find the mentioned F#/.NET example in the Github repo
You're looking for uninterpreted functions.
Search for the term "uninterpreted functions" in http://ericpony.github.io/z3py-tutorial/advanced-examples.htm
Your question seems to make some assumptions about how SMT solvers can be used; which don't quite reflect the current state-of-the-art. A great resource to read about the use of SMT solvers is: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/nbjorner-smt-application-chapter.pdf It would be well worth your time to go over it to see how it applies in practice.
Some general comments:
Z3py
Z3py is not a system for reasoning about Python programs. Z3py is a collection of libraries so you can script Z3 in a much more clearer and easier way. There are many such bindings from many languages: C/C++/Java/Haskell/Scala, you name it. The advantage of Z3py is that it is easier to learn and use. But you shouldn't think of it as a system to reason about Python itself. It's merely a way of scripting Z3 in a lightweight form.
Solver logics
SMT solvers essentially work on decidable fragments of (mostly quantifier-free) many-sorted logics of various theories. You can find these in detail at: http://smtlib.cs.uiowa.edu/logics.shtml
SMTLib
Most solvers accept input in the so-called SMT-Lib format, detailed here: http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2017-07-18.pdf
Note that any "binding" at the C/Python/Java etc. level is merely a programmers convenience. While many solvers also provide extended features, the SMTLib language is what you should think of. In your particular case, uninterpreted functions are well described in the above document.
Types
SMTLib understands a set of types: Integers, Reals, Bit-vectors (machine integers), Floating-point, etc. It also allows composite types such as algebraic data types, which can even be recursive. (Though solver support varies.) You have to "map" your external function types to these types: Hopefully, there's something close enough. If not, feel free to ask specific questions about types you are interested in.
"Importing" functions
It is impossible to import functions written in other languages (Python/C/C++ etc.) into SMTLib and reason about them. There's no mechanism for doing so, neither there ever will be. This isn't the goal of an SMT solver. If you want to reason about programs written in a particular language, then you should look for tools that are specifically designed to work on those languages. (For instance Dafny for general imperative programs, Klee/CBMC for C programs, LiquidHaskell for Haskell programs, etc.) These tools vary in their capabilities, and what they allow you to specify and prove. Note that these tools themselves can use SMT-solvers underneath to accomplish their tasks---and they often do, not the other way around.
Sticking to SMTLib
If there are no other tools available (and unfortunately this is likely the case for most languages out there, especially legacy ones), you're essentially stuck with whatever the SMTLib language provides. In your case, the best method for modeling such "external" functions using SMTLib is to use uninterpreted functions, together with axioms. In general, you need axioms to restrict the behavior of the uninterpreted functions themselves, to model your external functions. On the flip side, if the axioms are quantified (which in general they will be), the solver might return unknown.
Summary
While SMT solvers are great tools, you should always keep in mind that the language they operate on is SMTLib, not Python/C or anything else. Those bindings are simply means of accessing the solver as you might incorporate it in a bigger project. I hope that clears the expected use case.
Asking specific questions about what you've tried and what you're trying to achieve (code samples) is the best way to get mileage out of this forum!
Related
It is often said that compiled languages such as C perform better than interpreted languages such as Python. Therefore, I might be interested in migrating Python implementations to C/C++ (assuming they also have access to some Z3 API that is in use and maintenance).
However, this migration only makes sense in one case: if my performance loss is due to the language and not due to Z3. Therefore, I would like to know if there is any way to know what percentage of execution is being executed by Z3 and what percentage by pure Python.
A very naive possibility would be to use a timer just before and after each call to Z3 in my implementation and add up those times to finally see how much of the total those times represent. A sketch of this idea (pseudo-code):
timer_total = 0
time_z3 = 0
while executing:
time_local = take_time()
call_z3()
time_z3 += take_time() - time_local
print(time_z3/time_total)
This, even though it is an ugly solution, would answer my first question: how long does Z3 take over the total execution.
However, I would want to get even more information, if possible: I want to know not only how long Z3 takes to do its computations, but also whether using Python causes Z3 to have to do large data transformations before the information arrives "pure" (i.e., as if I wrote it in Z3) to Z3 and that, therefore, Z3's time has been considerably more than it would be if it didn't have to do them. In other words: I would like to know how long Z3 is only with the part of doing the logical calculations (not transformations and other processes), but only looking for models.
Specifically: I want to know if other languages like C++ do these transformations cheaper and therefore is the Z3 API of some other language more recommended/effective/optimized than Python.
I know it's abstract, but I hope the question was understood, and if not, we can discuss it in the comments.
I'm new to z3 smt solver.I'm using the python API z3py.
I have a quick question concerning the output of the z3.solve() function.what does it mean when I call z3.solve() on some constraints and I get [] as an output?
Also could someone refer me to a good documentation please
You really need to provide an input that causes this, as it really depends on your constraints. But here's the simplest way to illustrate this behavior:
from z3 import *
z3.solve([])
When I run this, I get:
[]
which is what you're seeing, I presume. This essentially means that your system is trivially satisfiable for all variables; i.e., either you have no constraints, or they do not constrain the model in any particular way. In the above, there are no constraints, so we have the "trivial" model. If you do something more interesting, say:
from z3 import *
a, b = Ints('a b')
z3.solve([a > b, b > 3])
then you'll see a more interesting model:
[b = 4, a = 5]
There's plenty of documentation on z3, z3py, and SMTLib in general (which describes the underlying language all SMT solvers speak):
For z3, start with https://rise4fun.com/z3/tutorial
For z3 python bindings, use: https://ericpony.github.io/z3py-tutorial/guide-examples.htm
General SMTLib info: http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2021-05-12.pdf
Note that z3 is scriptable from many other languages as well, including C, C++, Java, Scala, and Haskell to name a few. Usually it's much easier to work in a higher-level language than directly with SMTLib or the bare-bones C-bindings. Python and Haskell (in my opinion) provide the highest-level of abstractions to simplify programming z3, but which environment you should choose really depends on what your overall goals are. (While most bindings support general constraint programming, they have different levels of automation and access to different z3 facilities.)
I've been trying to achieve the exact same goal as this post.
Z3 randomness of generated model values
Except, the answer is in smt, how do I use the check-sat-using in z3py in python?
Can someone please help me translate this code into python code?
(set-option :smt.arith.random_initial_value true)
(declare-const x Int)
(declare-const y Int)
(assert (> (+ x y) 0))
(check-sat-using (using-params qflra :random_seed 1))
(get-model)
(check-sat-using (using-params qflra :random_seed 2))
(get-model)
(check-sat-using (using-params qflra :random_seed 3))
(get-model)
In the SMTLib interface, check-sat-using is a way of telling z3 which tactics to use. When you use z3py, you directly use the tactic language and explicitly create solvers. So, in a sense, there is no corresponding call in z3py to check-sat-using. Instead, you get an entire tactic language, which is much more flexible and powerful.
For examples see: http://www.cs.tau.ac.il/~msagiv/courses/asv/z3py/strategies-examples.htm
Note also that check-sat-using combines tactics and settings in a sense, in z3py you use set_param to achive parameter settings, and the tactic language to express what strategy you want to use.
As a general rule of thumb, do not try to "translate" between SMTLib and Z3 Python interfaces. While both can express same queries, the programming model is different and trying to translate "command-by-command" would lead you to non-idiomatic and hard-to-maintain code. Instead, if you want to use Z3py, simply learn how things are done there, keeping in mind they can look quite different from the SMTLib land. This is a great resource to read through to get you started: http://www.cs.tau.ac.il/~msagiv/courses/asv/z3py/
I currently solve optimization problems with complex variables using CVX + Mosek, on MATLAB. I'm now considering switching to Gurobi + Python for some applications.
Is there a way to declare complex values (both inside constraints and as optimization variables) directly into Gurobi's Python interface?
If not, which are good modeling languages, with Python interface, that automates the reduction of the problem to real variables before calling the solver?
I know, for instance, that YALMIP does this reduction (though no Python interface), and newer versions of CVXPY also (but I haven't used it extensively, and don't know if it already has good performance, is stable, and reasonably complete). Any thoughts on these issues and recommendations of other interfaces are thus welcome.
The only possible variables in Gurobi are:
Integer;
Binary;
Continuous;
Semi-Continuous and;
Semi-Integer.
Also, I don't know the problem you're trying to solve, but complex number are quite strange for linear optimization.
The complex plane isn't a ordered field, so that is not possible to say that a given complex number z1 > z2
You'll probably have to model your problem in such way that you can decompose the constraints with real and imaginary parts, so that you can work only with real numbers.
I use Z3Py to build large formulas (~1500 Bool variables, ~90k assertions) and I am currently using Solver.add to add the assertions, which are mostly small (eg. implications on 2 variables).
My code looks something like this, with about 10 outer for loops in sequence. The loop nesting depth varies from 2 to 6.
s = Solver()
for i in range(A):
for j in range(B):
...
s.add(Implies(vars[i,j,...], vars[k,l,...]))
The problem is that building the solver takes ~11 seconds (with __debug__ == False), while finding a solution only takes about 8.
Profiling shows that a lot of time is spent in Z3_sort_to_ast, z3code.Elementaries.Check (called by the former), and other methods which seem like they could be inlined at least, if not somehow eliminated.
How does one optimize the creation of the Z3 Solver? Maybe there is a more low-level, internal interface which could speed things up?
I see 3 options:
Use the SMT-LIB interface
Skip the high-level API of Z3
Rewrite the code using the C API directly
If the interaction with Z3 is minimal (solve and get a model), SMT-LIB might be the best option.
If the python code is quite complex to rewrite in C, please give pySMT a try. The way we integrate with Z3 skips the high-level API, and calls directly the underlying C-functions exposed at the python level. There would be the overhead from pySMT itself, but typically it pays out. You can have a look at [1] for some ideas on how we do it.
[1] https://github.com/pysmt/pysmt/blob/master/pysmt/solvers/z3.py#L853