1

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?

  • 1
    The Python API is not optimized for speed, it's quite possible that it wastes a bunch of time in unnecessarily deeply nested functions and in assertion/exception/type checks. For peak performance during construction, it's probably best to use the C API directly. – Christoph Wintersteiger Apr 28 '19 at 12:43

1 Answers1

3

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

Marco
  • 326
  • 1
  • 3