Q3B: An Efficient BDDbased SMT Solver for Quantified BitVectors
Abstract
We present the first stable release of our tool Q3B for deciding satisfiability of quantified bitvector formulas. Unlike other stateoftheart solvers for this problem, Q3B is based on translation of a formula to a bdd that represents models of the formula. The tool also employs advanced formula simplifications and approximations by effective bitwidth reduction and by abstraction of bitvector operations. The paper focuses on the architecture and implementation aspects of the tool, and provides a brief experimental comparison with its competitors.
1 Introduction
Advances in solving formula satisfiability modulo theories (smt) achieved during the last few decades enabled significant progress and practical applications in the area of automated analysis, testing, and verification of various systems. In the case of software and hardware systems, the most relevant theory is the theory of fixedsized bitvectors, as these systems work with inputs expressed as bitvectors (i.e., sequences of bits) and perform bitwise and arithmetic operations on bitvectors. The quantifierfree fragment of this theory is supported by many generalpurpose smt solvers, such as CVC4 [1], MathSAT [7], Yices [10], or Z3 [9] and also by several dedicated solvers, such as Boolector [21] or STP [12]. However, there are some usecases where quantifierfree formulas are not natural or expressive enough. For example, formulas containing quantifiers arise naturally when expressing loop invariants, ranking functions, loop summaries, or when checking equivalence of two symbolically described sets of states [8, 13, 17, 18, 24]. In the following, we focus on smt solvers for quantified bitvector formulas. In particular, this paper describes the stateoftheart smt solver Q3B including its implementation and the inner workings.
Solving of quantified bitvector formulas was first supported by Z3 in 2013 [25] and for a limited set of exists/forall formulas with only a single quantifier alternation by Yices in 2015 [11]. Both of these solvers decide quantified formulas by quantifier instantiation, in which universally quantified variables in the Skolemized formula are repeatedly instantiated by ground terms until the resulting quantifierfree formula is unsatisfiable or a model of the original formula is found. In 2016, we proposed a different approach for solving quantified bitvector formulas: by using binary decision diagrams (bdds) and approximations [14]. For evaluation of this approach, we implemented an experimental smt solver called Q3B, which outperformed both Z3 and Yices. Next solver that was able to solve quantified bitvector formulas was Boolector in 2017, using also an approach based on quantifier instantiation [22]. Unlike Z3, in which the universally quantified variables are instantiated only by constants or subterms of the original formula, Boolector uses a counterexampleguided synthesis approach, in which a suitable ground term for instantiation is synthesized based on the defined grammar. Thanks to this, Boolector was able to outperform Q3B and Z3 on certain classes of formulas. More recently, in 2018, support of quantified bitvector formulas has also been implemented into CVC4 [20]. The approach of CVC4 is also based on quantifier instantiation, but instead of synthesizing terms given by the grammar as Boolector, CVC4 uses predetermined rules based on invertibility conditions, which directly give terms that can prune many spurious models without using potentially expensive counterexampleguided synthesis. The authors of CVC4 have shown that this approach outperforms Z3, CVC4, and the original Q3B. However, Q3B has been substantially improved since the original experimental version. In 2017, we extended it with simplifications of quantified bitvector formulas using unconstrained variables [15]. Further, in 2018, we added the experimental implementation of abstractions of bitvector operations [16]. With these techniques, Q3B is able to decide more formulas than Z3, Boolector, and CVC4. Besides the theoretical improvements, Q3B was also improved in terms of stability, ease of use, technical parts of the implementation, and compliance with the smtlib standard. This tool paper presents the result of these improvements: Q3B 1.0, the first stable version of Q3B.
2 Architecture

SMTLIB Interpreter (implemented in SMTLIBInterpreter.cpp) reads the input file in the smtlib format [3], which is the standard input format for smt solvers. The interpreter executes all the commands from the file. In particular, it maintains the assertion stack and the options set by the user, calls solver when checksat command is issued, and queries Solver if the user requires the model with the command getmodel.

Formula Simplifier (implemented in FormulaSimplifier.cpp) provides interface for all applied formula simplifications, in particular miniscoping, conversion to negation normal form, pure literal elimination, equality propagation, constructive equality resolution (cer) [14], destructive equality resolution (der) [25], simple theoryrelated rewriting, and simplifications using unconstrained variables. Most of these simplifications are implemented directly in this component; only cer, der, and majority of the theoryrelated rewritings are performed by calling Z3 api and simplifications using unconstrained variables are implemented in a separate component of Q3B. The simplifier also converts toplevel existential variables to uninterpreted constants, so their values are also included in a model. Some simplifications that could change models of the formula are disabled if the user enables model generation, i.e., sets :producemodels to true.

Unconstrained Variable Simplifier (implemented in UnconstrainedVariableSimplifier.cpp) provides simplifications of formulas that contain unconstrained variables, i.e., variables that occur only once in the formula. Besides previously published unconstrained variable simplifications [15], which were present in the previous versions of Q3B, this component now also provides new goaldirected simplifications of formulas with unconstrained variables. In these simplifications, we aim to determine whether a subterm containing an unconstrained variable should be minimized, maximized, sign minimized, or sign maximized in order to satisfy the formula. If the subterm should be minimized and contains an unconstrained variable, the term is replaced by a simpler term that gives the minimal result that can be achieved by any value of the unconstrained variable. Similarly for maximization, sign minimization, and sign maximization.

Solver (implemented in Solver.cpp) is the central component of our tool. It calls formula simplifier and then creates three threads for the precise solver, the underapproximating solver, and the overapproximating solver. It also controls the approximation refinement loops of the approximating solvers. Finally, it returns the result of the fastest thread and stores the respective model, if the result was sat.

Formula to BDD Transformer (implemented in the file ExprToBDDTransformer.cpp) performs the actual conversion of a formula to a bdd. Each subterm of the input formula is converted to a vector of bdds (if the subterm’s sort is a bitvector of width n then the constructed vector contains n bdds, each bdd represents one bit of the subterm). Further, each subformula of the input formula is converted to a bdd. These conversions proceed by a straightforward bottomup recursion on the formula syntax tree. The transformer component calls an external library to compute the effect of logical and bitvector operations on bdds and vectors of bdds, respectively. Besides the precise conversion, the transformer can also construct overapproximating and underapproximating bdds. Precision of approximations depends on parameters set by the solver component.

Cache (implemented as a part of ExprToBDDTransformer.cpp) maintains for each converted subformula and subterm the corresponding bdd or a vector of bdds, respectively. Each of the three solvers has its own cache. When an approximating solver increases precision of the approximation, entries of its cache that can be affected by the precision change are invalidated. All the caches are internally implemented by hashtables.
3 Implementation
Q3B is implemented in C++17, is opensource and available under MIT license on GitHub: https://github.com/martinjonas/Q3B. The project development process includes continuous integration and automatic regression tests.
Q3B relies on several external libraries and tools. For representation and manipulation with bdds, Q3B uses the opensource library cudd 3.0 [23]. Since cudd does not support bitvector operations, we use the library by Peter Navrátil [19] that implements bitvector operations on top of cudd. The algorithms in this library are inspired by the ones in the bdd library BuDDy^{1} and they provide a decent performance. Nevertheless, we have further improved its performance by several modifications. In particular, we added a specific code for handling expensive operations like bitvector multiplication and division when arguments contain constant bdds. This for example considerably speeds up multiplication whenever one argument contains many constant zero bits, which is a frequent case when we use the variable bitwidth approximation fixing some bits to zero. Further, we have fixed few incorrectly implemented bitvector operations in the original library. Finally, we have extended the library with the support for donotknow bits in inputs of the bitvector operations and we have implemented abstract versions of arithmetic operations that can produce donotknow bits when the result exceeds a given number of bdd nodes.
For parsing the input formulas in smtlib format, Q3B uses antlr parser generated from the grammar^{2} for smtlib 2.6 [2]. We have modified the grammar to correctly handle bitvector numerals and to support push and pop commands without numerical argument. The parser allows Q3B to support all bitvector operations and almost all smtlib commands except getassertions, getassignment, getproof, getunsatassumptions, getunsatcore, and all the commands that work with algebraic datatypes. This is in sharp contrast with the previous experimental versions of Q3B, which only collected all the assertions from the input file and performed the satisfiability check regardless of the rest of the commands and of the presence of the checksat command. The reason for this was that the older versions parsed the input file using the Z3 C++ api, which can provide only the list of assertions, not the rest of the smtlib script. Thanks to the new parser, Q3B 1.0 can also provide the user with a model of a satisfiable formula after calling getmodel; this important aspect of other smt solvers was completely missing in the previous versions.
On the other hand, C++ api of the solver Z3 is still used for internal representation of parsed formulas. The Z3 C++ api is also used to perform manipulations with formulas, such as substitution of values for variables, and some of the formula simplifications. Note that these are the only uses of Z3 api in Q3B during solving the formula; no actual smt or satsolving capabilities of Z3 are used during the solving process.
Some classes of Q3B, in particular Solver, FormulaSimplifier, and UnconstrainedVariableSimplifier, expose a public C++ api that can be used by external tools for smt solving or just performing formula simplifications. For example, Solver exposes method Solve(formula, approximationType), which can be used to decide satisfiability by the precise solver, the underapproximating solver, or the overapproximating solver. Solver also exposes the method SolveParallel(formula), which simplifies the input formula and runs all three of these solvers in parallel and returns the first result as depicted in Fig. 1.
4 Experimental Evaluation
For each solver and benchmark family, the table shows the number of benchmarks from the given family solved by the given solver. The column Total shows the total number of benchmarks in the given family. The last line provides the total cpu times for the benchmarks solved by all four solvers.
Family  Total  Boolector  CVC4  Q3B  Z3 

2017Preinerkeymaera  4035  4022  3998  4009  4031 
2017Preinerpsyco  194  193  190  182  194 
2017Preinerschollsmt08  374  312  248  319  272 
2017Preinertptp  73  69  73  73  73 
2017PreinerUltimateAutomizer  153  152  151  153  153 
20170501HeizmannUltimateAutomizer  131  30  128  124  32 
2018Preinercav18  600  553  565  565  553 
Wintersteiger  191  163  174  185  163 
Total  5751  5494  5527  5610  5471 
cpu time [s]  7794  5877  19853  4055 
For all pairs of the solvers, the table shows the number of benchmarks that were solved by the solver in the corresponding row, but not by the solver in the corresponding column. The column Uniquely solved shows the number of benchmarks that were solved only by the given solver.
Boolector  CVC4  Q3B  Z3  Uniquely solved  

Boolector  0  123  69  78  8 
CVC4  156  0  60  171  6 
Q3B  185  143  0  208  25 
Z3  55  115  69  0  6 
Table 1 shows the numbers of benchmarks in each benchmark family solved by the individual solvers. Q3B is able to solve the most benchmarks in benchmark families 2017Preinerschollsmt08, 2017Preinertptp, 2017PreinerUltimateAutomizer, 2018Preinercav18, and wintersteiger, and it is competitive in the remaining families. In total, Q3B also solves more formulas than each of the other solvers: 116 more than Boolector, 83 more than CVC4, and 139 more than Z3. Although the numbers of solved formulas for the solvers seem fairly similar, the crosscomparison in Table 2 shows that the differences among the individual solvers are actually larger. For each other solver, there are at least 143 benchmarks that can be solved by Q3B but not by the other solver. We think this shows the importance of developing an smt solver based on bdds and approximations besides the solvers based on quantifier instantiation.
5 Conclusions and Future Work
We have described the architecture and inner workings of the first stable version of the stateoftheart smt solver Q3B. Experimental evaluation on all quantified bitvector formulas from smtlib repository shows that this solver slightly outperforms other stateoftheart solvers for such formulas.
As future work, we would like to drop the dependency on the Z3 api: namely to implement our own representation of formulas and reimplement all the simplifications currently outsourced to Z3 api directly in Q3B. We also plan to extend some simplifications with an additional bookkeeping needed to construct a model of the original formula. With these extensions, all simplifications could be used even if the user wants to get a model of the formula. We would also like to implement production of unsatisfiable cores since they are also valuable for software verification.
Footnotes
References
 1.Barrett, C., et al.: CVC4. In: Gopalakrishnan, G., Qadeer, S. (eds.) CAV 2011. LNCS, vol. 6806, pp. 171–177. Springer, Heidelberg (2011). https://doi.org/10.1007/9783642221101_14CrossRefGoogle Scholar
 2.Barrett, C., Stump, A., Tinelli, C.: The SMTLIB Standard: Version 2.6. Technical report, Department of Computer Science, The University of Iowa (2017). www.SMTLIB.org
 3.CBarrett, C., Stump, A., Tinelli, C.: The SMTLIB standard: version 2.0. In: Gupta, A., Kroening, D. (eds.) Proceedings of the 8th International Workshop on Satisfiability Modulo Theories, Edinburgh, UK (2010)Google Scholar
 4.Beyer, D., Löwe, S., Wendler, P.: Benchmarking and resource measurement. In: Fischer, B., Geldenhuys, J. (eds.) SPIN 2015. LNCS, vol. 9232, pp. 160–178. Springer, Cham (2015). https://doi.org/10.1007/9783319234045_12CrossRefGoogle Scholar
 5.Bryant, R.E.: On the complexity of VLSI implementations and graph representations of boolean functions with application to integer multiplication. IEEE Trans. Comput. 40(2), 205–213 (1991)MathSciNetCrossRefGoogle Scholar
 6.Bryant, R.E., Kroening, D., Ouaknine, J., Seshia, S.A., Strichman, O., Brady, B.A.: An abstractionbased decision procedure for bitvector arithmetic. STTT 11(2), 95–104 (2009)CrossRefGoogle Scholar
 7.Cimatti, A., Griggio, A., Schaafsma, B.J., Sebastiani, R.: The MathSAT5 SMT solver. In: Piterman, N., Smolka, S.A. (eds.) TACAS 2013. LNCS, vol. 7795, pp. 93–107. Springer, Heidelberg (2013). https://doi.org/10.1007/9783642367427_7CrossRefzbMATHGoogle Scholar
 8.Cook, B., Kroening, D., Rümmer, P., Wintersteiger, C.M.: Ranking function synthesis for bitvector relations. Form. Methods Syst. Des. 43(1), 93–120 (2013)CrossRefGoogle Scholar
 9.de Moura, L., Bjørner, N.: Z3: an efficient SMT solver. In: Ramakrishnan, C.R., Rehof, J. (eds.) TACAS 2008. LNCS, vol. 4963, pp. 337–340. Springer, Heidelberg (2008). https://doi.org/10.1007/9783540788003_24CrossRefGoogle Scholar
 10.Dutertre, B.: Yices 2.2. In: Biere, A., Bloem, R. (eds.) CAV 2014. LNCS, vol. 8559, pp. 737–744. Springer, Cham (2014). https://doi.org/10.1007/9783319088679_49CrossRefGoogle Scholar
 11.Dutertre, B.: Solving exists/forall problems with Yices. In: Workshop on satisfiability Modulo Theories (2015)Google Scholar
 12.Ganesh, V., Dill, D.L.: A decision procedure for bitvectors and arrays. In: Damm, W., Hermanns, H. (eds.) CAV 2007. LNCS, vol. 4590, pp. 519–531. Springer, Heidelberg (2007). https://doi.org/10.1007/9783540733683_52CrossRefGoogle Scholar
 13.Gulwani, S., Srivastava, S., Venkatesan, R.: Constraintbased invariant inference over predicate abstraction. In: Jones, N.D., MüllerOlm, M. (eds.) VMCAI 2009. LNCS, vol. 5403, pp. 120–135. Springer, Heidelberg (2008). https://doi.org/10.1007/9783540939009_13CrossRefGoogle Scholar
 14.Jonáš, M., Strejček, J.: Solving quantified bitvector formulas using binary decision diagrams. In: Creignou, N., Le Berre, D. (eds.) SAT 2016. LNCS, vol. 9710, pp. 267–283. Springer, Cham (2016). https://doi.org/10.1007/9783319409702_17CrossRefGoogle Scholar
 15.Jonáš, M., Strejček, J.: On simplification of formulas with unconstrained variables and quantifiers. In: Gaspers, S., Walsh, T. (eds.) SAT 2017. LNCS, vol. 10491, pp. 364–379. Springer, Cham (2017). https://doi.org/10.1007/9783319662633_23CrossRefzbMATHGoogle Scholar
 16.Jonáš, M., Strejček, J.: Abstraction of bitvector operations for BDDbased SMT solvers. In: Fischer, B., Uustalu, T. (eds.) ICTAC 2018. LNCS, vol. 11187, pp. 273–291. Springer, Cham (2018). https://doi.org/10.1007/9783030025083_15CrossRefzbMATHGoogle Scholar
 17.Kroening, D., Lewis, M., Weissenbacher, G.: Underapproximating loops in C programs for fast counterexample detection. In: Sharygina, N., Veith, H. (eds.) CAV 2013. LNCS, vol. 8044, pp. 381–396. Springer, Heidelberg (2013). https://doi.org/10.1007/9783642397998_26CrossRefGoogle Scholar
 18.Mrázek, J., Bauch, P., Lauko, H., Barnat, J.: SymDIVINE: tool for controlexplicit datasymbolic state space exploration. In: Bošnački, D., Wijs, A. (eds.) SPIN 2016. LNCS, vol. 9641, pp. 208–213. Springer, Cham (2016). https://doi.org/10.1007/9783319325828_14CrossRefGoogle Scholar
 19.Navrátil, P.: Adding support for bitvectors to BDD libraries CUDD and Sylvan. Bachelor’s thesis, Masaryk University, Faculty of Informatics, Brno (2018)Google Scholar
 20.Niemetz, A., Preiner, M., Reynolds, A., Barrett, C., Tinelli, C.: Solving quantified bitvectors using invertibility conditions. In: Chockler, H., Weissenbacher, G. (eds.) CAV 2018. LNCS, vol. 10982, pp. 236–255. Springer, Cham (2018). https://doi.org/10.1007/9783319961422_16CrossRefGoogle Scholar
 21.Niemetz, A., Preiner, M., Wolf, C., Biere, A.: Btor2, BtorMC and Boolector 3.0. In: Chockler, H., Weissenbacher, G. (eds.) CAV 2018. LNCS, vol. 10981, pp. 587–595. Springer, Cham (2018). https://doi.org/10.1007/9783319961453_32CrossRefGoogle Scholar
 22.Preiner, M., Niemetz, A., Biere, A.: Counterexampleguided model synthesis. In: Legay, A., Margaria, T. (eds.) TACAS 2017. LNCS, vol. 10205, pp. 264–280. Springer, Heidelberg (2017). https://doi.org/10.1007/9783662545775_15CrossRefzbMATHGoogle Scholar
 23.Somenzi, F.: CUDD: CU Decision Diagram Package Release 3.0.0. University of Colorado at Boulder (2015)Google Scholar
 24.Srivastava, S., Gulwani, S., Foster, J.S.: From program verification to program synthesis. In: Proceedings of the 37th ACM SIGPLANSIGACT Symposium on Principles of Programming Languages, POPL 2010, Madrid, Spain, 17–23 January 2010, pp. 313–326 (2010)Google Scholar
 25.Wintersteiger, C.M., Hamadi, Y., de Moura, L.M.: Efficiently solving quantified bitvector formulas. Form. Methods Syst. Des. 42(1), 3–23 (2013)CrossRefGoogle Scholar
Copyright information
Open Access This chapter is licensed under the terms of the Creative Commons Attribution 4.0 International License (http://creativecommons.org/licenses/by/4.0/), which permits use, sharing, adaptation, distribution and reproduction in any medium or format, as long as you give appropriate credit to the original author(s) and the source, provide a link to the Creative Commons license and indicate if changes were made.
The images or other third party material in this chapter are included in the chapter's Creative Commons license, unless indicated otherwise in a credit line to the material. If material is not included in the chapter's Creative Commons license and your intended use is not permitted by statutory regulation or exceeds the permitted use, you will need to obtain permission directly from the copyright holder.