Optimising z3 input - z3

I am trying to optimize z3 python input that is generated from my models. I am able to run it on models up 15k constraints (200 states) and then z3 stops finishing in reasonable time (<10 minutes). Is there a way to optimize the constraints that are generated from my models ?
Model for 3 states:
http://pastebin.com/EHZ1P20C

The performance of the script http://pastebin.com/F5iuhN42 can be improved by using a custom strategy. Z3 allows users to define custom strategies/solvers. This tutorial shows how to define strategies/tactics using the Z3 Python API. In the script http://pastebin.com/F5iuhN42, if we replace the line
s = Solver()
with
s = Then('simplify', 'elim-term-ite', 'solve-eqs', 'smt').solver()
the runtime will decrease from 30 secs to 1 sec (on my machine).
The procedure Then is creating a strategy/tactic composed of 4 steps:
Simplifier (i.e., a rewriter that applies rules such as x + 1 - x + y ==> 1 + y
Elimination of expressions of the form If(a, b, c) where b and c are not Boolean. The script makes extensive use this kind of expression. The tactic elim-term-ite will apply transformations that eliminate this kind of expression.
Equational solver. It applies transformations such as x = a And F[x] ==> F[a]. In the script above, this tactic can eliminate more than 1000 variables.
The tactic smt invokes a general purpose SMT solver in Z3.
The method .solver() converts a Z3 tactic/strategy into a solver object that provides the add and check methods. The tutorial that I included in the beginning of the message has more details.

Related

How to bias Z3's (Python) SAT solving towards a criteria, such as 'preferring' to have more negated literals

In Z3 (Python) is there any way to 'bias' the SAT search towards a 'criteria'?
A case example: I would like Z3 to obtain a model, but not any model: if possible, give me a model that has a great amount of negated literals.
Thus, for instance, if we have to search A or B a possible model is [A = True, B = True], but I would rather have received the model [A = True, B = False] or the model [A = False, B = True], since they have more False assignments.
Of course, I guess the 'criteria' must be much more concrete (say, if possible: I prefer models with the half of literals to False ), but I think the idea is understandable.
I do not care whether the method is native or not. Any help?
There are two main ways to handle this sort of problems in z3. Either using the optimizer, or manually computing via multiple-calls to the solver.
Using the optimizer
As Axel noted, one way to handle this problem is to use the optimizing solver. Your example would be coded as follows:
from z3 import *
A, B = Bools('A B')
o = Optimize()
o.add(Or(A, B))
o.add_soft(Not(A))
o.add_soft(Not(B))
print(o.check())
print(o.model())
This prints:
sat
[A = False, B = True]
You can add weights to soft-constraints, which gives a way to associate a penalty if the constraint is violated. For instance, if you wanted to make A true if at all possible, but don't care much for B, then you'd associate a bigger penalty with Not(B):
from z3 import *
A, B = Bools('A B')
o = Optimize()
o.add(Or(A, B))
o.add_soft(Not(A))
o.add_soft(Not(B), weight = 10)
print(o.check())
print(o.model())
This prints:
sat
[A = True, B = False]
The way to think about this is as follows: You're asking z3 to:
Satisfy all regular constraints. (i.e., those you put in with add)
Satisfy as many of the soft constraints as possible (i.e., those you put in with add_soft.) If a solution isn't possible that satisfies them all, then the solver is allowed to "violate" them, trying to minimize the total cost of all violated constraints, computed by summing the weights up.
When no weights are given, you can assume it is 1. You can also group these constraints, though I doubt you need that generality.
So, in the second example, z3 violated Not(A), because doing so has a cost of 1, while violating Not(B) would've incurred a cost of 10.
Note that when you use the optimizer, z3 uses a different engine than the one it uses for regular SMT solving: In particular, this engine is not incremental. That is, if you call check twice on it (after introducing some new constraints), it'll solve the whole problem from scratch, instead of learning from the results of the first. Also, the optimizing solver is not as optimized as the regular solver (pun intended!), so it usually performs worse on straight satisfiability as well. See https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/nbjorner-nuz.pdf for details.
Manual approach
If you don't want to use the optimizer, you can also do this "manually" using the idea of tracking variables. The idea is to identify soft-constraints (i.e., those that can be violated at some cost), and associate them with tracker variables.
Here's the basic algorithm:
Make a list of your soft constraints. Int the above example, they'll be Not(A) and Not(B). (That is, you'd like these to be satisfied giving you negative literals, but obviously you want these to be satisfied only if possible.) Call these S_i. Let's say you have N of them.
For each such constraint, create a new tracker variable, which will be a boolean. Call these t_i.
Assert N regular constraints, each of the form Implies(t_i, S_i), for each soft-constraint.
Use a pseudo-boolean constraint, of the form AtMostK, to force that at most K of these tracker variables t_i are false. Then use a binary-search like schema to find the optimal value of K. Note that since you're using the regular solver, you can use it in the incremental mode, i.e., with calls to push and pop.
For a detailed description of this technique, see https://stackoverflow.com/a/15075840/936310.
Summary
Which of the above two methods will work is problem dependent. Using the optimizer is easiest from an end-user point of view, but you're pulling in heavy machinery that you may not need and you can thus suffer from a performance penalty. The second method might be faster, at the risk of more complicated (and thus error prone!) programming. As usual, do some benchmarking to see which works the best for your particular problem.
Z3py features an optimizing solver Optimize. This has a method add_soft with the following description:
Add soft constraint with optional weight and optional identifier.
If no weight is supplied, then the penalty for violating the soft constraint
is 1.
Soft constraints are grouped by identifiers. Soft constraints that are
added without identifiers are grouped by default.
A small example can be found here:
The Optimize context provides three main extensions to satisfiability checking:
o = Optimize()
x, y = Ints('x y')
o.maximize(x + 2*y) # maximizes LIA objective
u, v = BitVecs('u v', 32)
o.minimize(u + v) # minimizes BV objective
o.add_soft(x > 4, 4) # soft constraint with
# optional weight

Obtaining representation of SMT formula as SAT formula

I've come up with an SMT formula in Z3 which outputs one solution to a constraint solving problem using only BitVectors and IntVectors of fixed length. The logic I use for the IntVectors is only simple Presburger arithmetic (of the form (x[i] - x[i + 1] <=/>= z) for some x and z). I also take the sum of all of the bits in the bitvector (NOT the binary value), and set that value to be within a range of [a, b].
This works perfectly. The only problem is that, as z3 works by always taking the easiest path towards determining satisfiability, I always get the same answer back, whereas in my domain I'd like to find a variety of substantially different solutions (I know for a fact that multiple, very different solutions exist). I'd like to use this nifty tool I found https://bitbucket.org/kuldeepmeel/weightgen, which lets you uniformly sample a constrained space of possibilities using SAT. To use this though, I need to convert my SMT formula into a SAT formula.
Do you know of any resources that would help me learn how to perform Presburger arithmetic and adding the bits of a bitvector as a SAT instance? Alternatively, do you know of any SMT solver which as an intermediate step outputs a readable description of the problem as a SAT instance?
Many thanks!
[Edited to reflect the fact that I really do need the uniform sampling feature.]

Optimize Solver Tactics for Circuit SAT

I am using the Z3 solver with Python API to tackle a Circuit SAT problem.
It consists of many Xor expressions with up to 21 inputs and three-input And expressions. Z3 is able to solve my smaller examples but does not cope with the bigger ones.
Rather than creating the Solver object with
s = Solver()
I tried to optimize the solver tactics like in
t = Then('simplify', 'symmetry-reduce', 'aig', 'tseitin-cnf', 'sat' )
s = t.solver()
I got the tactics list via describe_tactics()
Unfortunately, my attempts have not been fruitful. The default sequence of tactics seems to do a pretty good job. The tactics tutorial previously available in rise4fun is no longer accessible.
Another attempt - without visible effect - was to set the phase parameter, as I am expecting the majority of my variables to have false values. (cf related post)
set_option("sat.phase", "always-false")
What sequence of tactics is recommended for Circuit SAT problems?

Z3 times out on (presumably) decidable logic

We are experimenting with a relational logic for functional program verification. Our logic is equipped with relations over algebraic datatypes along with equality and subset-inclusion predicates over relations. Our verification procedure performs inductive program analysis (structural induction) and generates verification conditions (VCs) with sufficiently strong inductive hypotheses. VCs generated by our verification procedure adhere to the following format:
bindings <var-type bindings> in <antecedent-predicate> => <consequent-predicate> end
Here is an example VC generated by our procedure : http://pastebin.com/exncPHDA
We encode VCs thus generated in SMT2 language using following rules:
Each concrete type (eg: 'a list) translates to an uninterpreted sort.
Relations are encoded as uninterpreted n-ary functions from uninterpreted sorts to bool.
Relational assertions (eg: R = R1 U R2, R = R1 X R2) are encoded as prenex-quantified assertions over uninterpreted functions.
The result of above encoding is (presumably) a formula in effectively propositional (EPR) first-order logic. With help of Z3, we were able to assert validity (unsatisfiability of negation) of many VCs. However, in some cases when VC is invalid (negation is SAT), Z3 loops. The example given above (http://pastebin.com/exncPHDA) is one such VC, whose SMT2 encoding is given here : http://pastebin.com/s8ezha7D . Z3 doesn't seem to terminate while asserting this formula.
Given that deciding quantified boolean formulas is NEXPTIME hard, non-termination of decision procedure is not very surprising. Nonetheless, we would like to know if there are any optimizations that we can do while encoding the formula in Z3 so as to make non-termination least likely -
Our current encoding creates many empty sets (i.e., one assertion of form forall x:T, f(x)=false) and many instances of same singleton sets (i.e., forall x:T, (f(x) = true) <=> (x = v)). Does reducing such duplication help?
Due to program elaboration, we currently have many variables and transitive equalities. Does reduction in number of variables help?
Also, how likely is it that Z3 loops while deciding an unsatisfiable quantified boolean formula?
In Z3, we say a quantifier of the form forall X, f(X) = T[X], where X is vector of variables, f is an uninterpreted function, and T is a term/formula that does not contain f, is a macro. Z3 can eliminate these quantifiers in a preprocessing step by simply replacing all occurrences of f. The option :macro-finder turns on this feature.
(set-option :macro-finder true)
If we apply this preprocessing step, the example can be solved instantaneously.
Here is a link with the updated script: http://rise4fun.com/Z3/z2UJ
Remark: in the work-in-progress (unstable) branch at http://z3.codeplex.com, this option is called :smt.macro-finder.

Z3 strategy for solving system with conditional integer additions

I'm using Z3 to solve a system that consists of Boolean constraints on variables Vi as well as a constraint of the following form:
L < If(V0, T0, F0) + If(V1, T1, F1) + ... + If(Vn, Tn, Fn) <= H
where L, H, and the Ti and Fi are integer constants.
Although all the variables are Boolean, I found that the QF_LIA solver was somewhat faster than the generic one, so I'm using the former. My assumption was that Z3 was handling the constraint above by introducing new variables and clauses to implement adders in the obvious way. However, doing that conversion myself (using MiniSat+) and passing the result to a SAT solver takes an order of magnitude longer than Z3 does. Thus, I'm wondering what strategy Z3 uses to solve systems of the type described above - is it something other than the conversion using adders?
Z3 uses a reduction to SAT to solve this kind of problem. If you are using the shell, you can provide the option -v:10 (verbosity messages). Z3 will display several messages describing what it is doing. For the kind of problem you described, Z3 will probably display verbose messages of the form:
(lia2pb :num-exprs 9 :num-asts 185 ...)
(pb2bv :num-exprs 9 :num-asts 185 ...)
lia2pb means that Z3 is converting a linear integer arithmetic problem into a pseudo boolean constraint problem. And pb2bv means that it is reducing the problem to bit-vector arithmetic.
The lia2pb transformation is implemented in the file:
http://z3.codeplex.com/SourceControl/latest#src/tactic/arith/lia2pb_tactic.cpp
and pb2bv transformation is implemented in the file:
http://z3.codeplex.com/SourceControl/latest#src/tactic/arith/pb2bv_tactic.cpp

Resources