<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>Smt-Switch: a solver-agnostic C++ API for SMT solving (Extended Abstract)</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Makai Mann</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Amalee Wilson</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Cesare Tinelli</string-name>
          <xref ref-type="aff" rid="aff1">1</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Clark Barrett</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Stanford University Stanford</institution>
          ,
          <country country="US">USA</country>
        </aff>
        <aff id="aff1">
          <label>1</label>
          <institution>The University of Iowa Iowa City</institution>
          ,
          <country country="US">USA</country>
        </aff>
      </contrib-group>
      <pub-date>
        <year>2020</year>
      </pub-date>
      <fpage>48</fpage>
      <lpage>58</lpage>
      <abstract>
        <p>This extended abstract describes work in progress on Smt-Switch, an open-source, solver-agnostic API for SMT solving. Smt-Switch provides an abstract interface, which can be implemented by di erent SMT solvers. Smt-Switch provides simple, uniform, and high-performance access to SMT solving for applications in areas such as automated reasoning, planning, and formal veri cation. The interface allows the user to create, traverse, and manipulate terms, as well as to dynamically dispatch queries to di erent underlying SMT solvers.</p>
      </abstract>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>Introduction</title>
      <p>2</p>
    </sec>
    <sec id="sec-2">
      <title>Design</title>
      <p>
        Smt-Switch is designed to be a lightweight wrapper on the C or C++ API of the underlying
SMT solvers. It intentionally delegates as much of the functionality to the underlying solvers
as possible. This reduces redundancy, and results in simpler implementations and lower
memory overhead. The API is implemented in C++11 and also provides Python bindings using
Cython [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ]. The Python bindings can be used directly in a Python project, but the intended
usage is for tools that use Smt-Switch in C++, but want to expose Smt-Switch functionality
in Cython-generated Python bindings for that tool.
      </p>
      <p>
        Architecture. Smt-Switch provides abstract classes which must be implemented by a
wrapper for each underlying solver. The implementations satisfy the interface requirements of
the abstract classes and wrap the relevant objects needed for that underlying solver's own API.
Throughout this abstract, we use underlying solver to refer to the SMT solver we are wrapping
and backend to refer to the Smt-Switch wrapper. Any solver with a C or C++ API can be
added to Smt-Switch. At the Smt-Switch API level, the user interacts with smart pointers
to the abstract classes. The virtual method functionality of C++ allows the pointer to
dynamically call the relevant method of the derived class (the backend) that is pointed to. This
architecture allows the interface to be agnostic to the underlying solver. The three primary
abstract classes are: (i) AbsSort; (ii) AbsTerm; and (iii) AbsSmtSolver. The interface and
method names are based on SMT-LIB version 2 [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ]. Figure 1 shows a representative selection
of the AbsSmtSolver header le which details the abstract interface. Many methods were
removed for space. The Op class is not abstract and does not need to be implemented by the
backend. However, the backend's AbsSmtSolver implementation must interpret an Op when
building terms.
      </p>
      <p>
        Building and Linking. Smt-Switch uses CMake [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ]. The build infrastructure is
designed to be modular with respect to backend solvers. By default, the con guration script does
not add any solvers. Smt-Switch will build but has no functionality. To add a solver, the user
must rst obtain the underlying solver's library. Smt-Switch provides convenience scripts for
obtaining several of the underlying solvers and instructions for the rest. Then, a command
line ag to the Smt-Switch con guration script will add the solver to the build. Each solver
backend results in a separate library, e.g. on Linux there will be a libsmt-switch.so le
as well as a libsmt-switch-cvc4.so le if con gured with --cvc4. This allows the user
to build Smt-Switch once, but only link solver backends to their project as needed. The
con guration script also has options to enable static and debug builds.
      </p>
      <p>
        Testing. We use GoogleTest [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ] for the C++ test infrastructure and Pytest [
        <xref ref-type="bibr" rid="ref12">12</xref>
        ] for the
Python test infrastructure. Tests are parameterized by solver so that one test can easily be run
over all solvers.
      </p>
      <p>Unde ned Behavior. Each backend implementation of a solver needs to recover its
relevant objects from a generic abstract object. This is done with a static pointer cast.
This results in unde ned behavior if the cast is not valid. In particular, this means that sharing
Sorts and Terms between di erent SmtSolvers results in unde ned behavior. To move a
Sort or Term between solvers, it must explicitly be transferred. There is a class provided in
the API which can transfer terms between solvers. Smt-Switch is intentionally lightweight
and thus does not perform much error checking. This design decision was made to reduce
overhead and redundancy, since most SMT solvers do error checking already. However, the class
hierarchy allows users to extend classes or build wrappers if they would like to insert their own
error checking at the Smt-Switch level.
1 /** Abstract solver class to be implemented by each supported solver. */
2 class AbsSmtSolver
3 {
4 public:
5 /* Add an assertion to the solver
6 * SMTLIB: (assert &lt;t&gt;)
7 * @param t a boolean term to assert */
8 virtual void assert_formula(const Term &amp; t) = 0;
9 /* Check satisfiability of the current assertions
10 * SMTLIB: (check-sat)
11 * @return a result object - see result.h */
12 virtual Result check_sat() = 0;
13 /* Get the value of a term after check_sat returns a satisfiable result
14 * SMTLIB: (get-value (&lt;t&gt;))
15 * @param t the term to get the value of
16 * @return a value term */
17 virtual Term get_value(const Term &amp; t) const = 0;
18 /* Create a sort
19 * @param sk the SortKind (BOOL, INT, REAL)
20 * @return a Sort object */
21 virtual Sort make_sort(const SortKind sk) const = 0;
22 /* Create a sort
23 * @param sk the SortKind (BV)
24 * @param size (e.g. bitvector width for BV SortKind)
25 * @return a Sort object */
26 virtual Sort make_sort(const SortKind sk, uint64_t size) const = 0;
27 /* Create a sort
28 * @param sk the SortKind (FUNCTION)
29 * @param sorts a vector of sorts (last sort is return type)
30 * @return a Sort object
31 * Note: This is the only way to make a function sort */
32 virtual Sort make_sort(const SortKind sk, const SortVec &amp; sorts) const = 0;
33 /* Make a boolean value term
34 * @param b boolean value
35 * @return a value term with Sort BOOL and value b */
36 virtual Term make_term(bool b) const = 0;
37 /* Make a symbolic constant or function term
38 * SMTLIB: (declare-fun &lt;name&gt; (s1 ... sn) s) where sort = s1x...xsn -&gt; s
39 * @param name the name of constant or function
40 * @param sort the sort of this constant or function
41 * @return the symbolic constant or function term */
42 virtual Term make_symbol(const std::string name, const Sort &amp; sort) = 0;
43 /* Make a new term
44 * @param op the operator to use
45 * @param terms vector of children
46 * @return the created term */
47 virtual Term make_term(const Op op, const TermVec &amp; terms) const = 0;
48 };</p>
      <p>Custom Exceptions. Smt-Switch de nes its own set of exceptions that inherit from
std::exception. Each of them take a std::string message for describing the problem
that can be accessed with the what method.</p>
      <p>1. SmtException : the generic Smt-Switch exception - all other custom exceptions
inherit from it.
2. NotImplementedException : the exception for an unimplemented feature in a
backend solver.
3. IncorrectUsageException : an exception that is thrown when incorrect usage on
the users' part is detected.
4. InternalSolverException : an exception that is thrown when there is an error in
the underlying solver.
3
We now describe the abstract interface in more detail. We start by describing the AbsSort
class which illustrates the supported theories. This is followed by the non-abstract struct for
representating operators: Op. Next, we describe the other two important abstract classes:
AbsTerm and AbsSmtSolver. Figure 2 depicts the class hierarchy for an AbsSmtSolver.
The AbsSort and AbsTerm classes have analogous architectures. Finally, we describe the
Result struct which is returned after a satis ability query, and the solver factories that are
used to instantiate solvers.
3.1</p>
      <sec id="sec-2-1">
        <title>AbsSort</title>
        <p>The AbsSort abstract class represents the type of Terms created in Smt-Switch. Sorts are
characterized by an enum, SortKind, which categorizes it and additional parameters based on
the SortKind. AbsSort has virtual methods for querying the sort for its SortKind and
parameters. This abstract class is implemented by each backend solver and wraps the backend's
representation of a sort. For example, the CVC4 backend has a CVC4Sort class which wraps a
sort object from CVC4's C++ API. A Sort is a pointer to an AbsSort. Currently supported
SortKinds and associated parameters are the following:
1. BOOL: booleans
2. INT: integer numbers
3. REAL: real numbers
4. BV: xed-width bitvectors</p>
        <p>(a) parameter: positive integer width</p>
        <sec id="sec-2-1-1">
          <title>5. FUNCTION: uninterpreted function sort</title>
          <p>(a) parameter: vector of domain Sorts
(b) parameter: the codomain Sort</p>
        </sec>
        <sec id="sec-2-1-2">
          <title>6. ARRAY: arrays parameterized by index and element sorts</title>
          <p>3.2</p>
          <p>Op
(a) parameter : index Sort
(b) parameter : element Sort</p>
        </sec>
        <sec id="sec-2-1-3">
          <title>7. UNINTERPRETED: an uninterpreted sort</title>
          <p>(a) parameter: non-negative integer arity</p>
          <p>Op is a struct used to represent builtin operators for constructing terms in Smt-Switch.
These can be split into two categories: primitive operators and indexed operators. For unity
of representation, an Op is used for both. An Op stores a PrimOp enum and up to two integer
indices. Primitive operators are de ned only by the PrimOp and take no indices. Indexed
operators have both a PrimOp and one or two indices. For convenience, the Op constructor
can be applied implicitly by the compiler. Thus, building terms with a primitive operator
can be accomplished by using a PrimOp directly, without explicitly building an Op from it.
Smt-Switch uses a straightforward naming scheme such that the PrimOp enums have
oneto-one correspondence with SMT-LIB operators.</p>
          <p>Ops can be null. All Terms that are a symbol or value have a null operator. Note that
terms with null operators are not necessarily leaf nodes. For example, one such edge case is
constant arrays (arrays where every element has been set to a given value). Constant arrays
are themselves values and thus have a null operator. However, they still have one child which
is the value assigned to every element.
3.3</p>
        </sec>
      </sec>
      <sec id="sec-2-2">
        <title>AbsTerm</title>
        <p>The AbsTerm abstract class represents expressions built through the API. Constructing the
term uses methods from the SmtSolver because most underlying solvers use a solver or context
object for registering terms. However, once the term is created, the Smt-Switch interface
assumes that it can be queried for information. For example, a term has virtual methods
for accessing the Sort, the Op used to create it, and the children of the Term. Querying the
children is implemented as an iterator. Thus, Terms have a begin and end method that
each return a TermIter, which is a class that wraps an abstract class, TermIterBase. Each
backend solver must implement a derived class for AbsTerm that wraps its relevant expression
representation(s). If the backend solver supports accessing the children of a term, it must
also implement a derived class for TermIterBase. For example, the CVC4 backend has
both a CVC4Term and CVC4TermIter object that implement the Term and TermIterBase
interfaces and store the relevant term and term iteration objects from the CVC4 C++ API.
A Term is a pointer to an AbsTerm. Smt-Switch also has type declarations for convenient
data structures such as TermVec which is a vector of Terms.</p>
        <p>A given Term can be a symbol (uninterpreted constant or function), a value (theory values
such as the number 1), or an expression built from symbols and values using operators. All
SMT expressions in Smt-Switch are represented as terms. In particular, we take a
higherorder logic perspective and represent uninterpreted functions as terms. Thus, applying an
uninterpreted function uses an \Apply" operator on the function and the arguments. Some
SMT solvers are starting to add higher-order logic features, and this representation is often
convenient. For example, an invariant maintained by Smt-Switch is that any term with a
non-null operator can always be rebuilt using its operator and children. For a given Term t
with a non-null operator, the backend solver implementation should guarantee that the following
always returns true:</p>
        <p>t == solver-&gt;make term(t-&gt;get op(), TermVec(t-&gt;begin(), t-&gt;end()))
If the API instead had di erent methods for applying an uninterpreted function versus creating
terms with a builtin operator, this invariant would not be maintained.
3.4</p>
      </sec>
      <sec id="sec-2-3">
        <title>AbsSmtSolver</title>
        <p>AbsSmtSolver declares the main interface that a user interacts with. It has methods
for declaring Sorts, building Terms, asserting formulas and checking for satis ability.
SmtSolver is a pointer to an AbsSmtSolver. The bulk of the implementation for a
backend solver will likely be its implementation of AbsSmtSolver. The interface methods closely
match the commands of SMT-LIB. The naming scheme simply replaces \-" with \ ". For
example, some methods of AbsSmtSolver include set opt, check sat, and get value. One
notable exception is that assertions are added with the assert formula method (as opposed
to \assert" as in SMT-LIB), to avoid clashing with the C assert macro.</p>
        <p>Each backend solver must implement a derived class for AbsSmtSolver. For example,
the CVC4 backend has a CVC4Solver object that inherits AbsSmtSolver. This derived
class must store the relevant information for that solver and implement each of the virtual
AbsSmtSolver methods in the underlying solver's API. The AbsSmtSolver methods all
operate over pointers to the abstract objects as shown in Figure 1. For example, the method
at line 47 has signature: make term(Op, const TermVec &amp;). The derived class
implementation must cast each of the Term pointers in the TermVec to its own derived class
implementation of AbsTerm to be able to access relevant wrapped members. Thus, the
CVC4Solver implementation of that method would cast each of the Terms to a CVC4Term
with static pointer cast&lt;CVC4Term&gt;(t) for Term t. Then, it would intepret the Op,
perform the corresponding operation over the CVC4 objects, and nally wrap the result in a
CVC4Term and return it as a Term.
3.5</p>
      </sec>
      <sec id="sec-2-4">
        <title>Result</title>
        <p>Result is a struct for representing the return value of a call to check sat or check sat assuming.
It currently has three possible values: SAT, UNSAT, and UNKNOWN. In the case of UNKNOWN,
the backend solver can optionally provide a std::string with an explanation of the reason
for the unknown result.
3.6</p>
      </sec>
      <sec id="sec-2-5">
        <title>Solver Factories</title>
        <p>A solver factory is a simple class that de nes a single static method: create(bool
logging). Each backend solver implementation de nes a factory and has a dedicated header
le. The create function is used to create a SmtSolver of that type. The single boolean
parameter is to choose whether or not the term DAG is tracked at the Smt-Switch level.</p>
        <p>If logging is set to false, the SmtSolver relies on the underlying solver API for querying
a term for its Op, Sort and children (e.g. term traversal) by translating back to Smt-Switch
objects.</p>
        <p>If logging is set to true, the method returns the backend solver but wrapped by a
LoggingSolver. This is an implementation of AbsSmtSolver that forwards commands to
another backend SmtSolver. Additionally, it keeps a term DAG at the Smt-Switch level.
This is accomplished by wrapping every Sort and Term created through the LoggingSolver
in a LoggingSort and LoggingTerm, respectively. In addition to storing the underlying
objects, these classes also keep relevant data for tracking the expression DAG as it was
constructed. For example, a LoggingSort keeps the SortKind and parameters used to create it.
A LoggingTerm keeps the Op, (Logging) Sort, and children (Logging) Terms. This optional
feature can be useful for underlying solvers that perform on-the- y rewriting or alias sorts (e.g.,
do not distinguish between bitvectors of width one and booleans). The logging infrastructure
ensures that a created term has exactly the same Op, Sort, and children that were used to
create it. The implicit assumption is that even though creating a term through a solver API
might result in a rewritten term, creating the term again with the same Op and children will
result in the same rewritten term. Thus, the logging infrastructure hides the underlying solver's
rewriting from the user. To contend with sort aliasing, the LoggingSolver also performs sort
inference to compute the expected sort when building terms. The logging infrastructure
simplies transferring terms between di erent solvers (which might not alias sorts in the same way)
and can be more intuitive. Additionally, some solver backends (currently the Yices2 backend)
rely on the logging infrastructure for term traversal. A Yices2 SmtSolver created without
logging will create Terms that do not support iterating over the children.
4</p>
      </sec>
    </sec>
    <sec id="sec-3">
      <title>Examples</title>
      <p>In this section we demonstrate the Smt-Switch API with a simple example using both the
C++ API and the Python bindings. Figure 3 uses Smt-Switch with the CVC4 backend to
solve two simple queries over bitvectors and uninterpreted functions. Lines 1-2 include the
necessary Smt-Switch headers, and lines 3-8 are standard C++ includes, using declarations
and main function. Line 9 declares a SmtSolver using CVC4 as the backend without logging.
In line 10 the solver is set to incremental mode. Lines 11 and 12 declare a bitvector sort of
width 9 and a function sort from a width 9 bitvector to a width 9 bitvector. Lines 13-17 declare
two bitvector symbolic constants, an uninterpreted function and then applies the function to
each of the bitvector symbols. Line 20 uses a C assert to check that the operator of an applied
uninterpreted function term is Apply. Line 21 populates a vector with the children of term
fx. Line 22 asserts that there are two children (in some solvers this term would have only one
child: x). Lines 25 and 26 check that the children are the function, f, and the bitvector, x.
Line 29 asserts to the SmtSolver that the returned values from the function applied to x and
y are di erent. Lines 30 and 31 extract the bottom 8 bits from x and y, respectively. Line 33
asserts to the SmtSolver that the bottom bits of x and y are equivalent. Line 35 checks the
satis ability of the current assertions and line 36 checks that the solver found SAT as expected.
The query is satis able because x and y can have di erent most signi cant bits, and thus the
function applications could return di erent values. Line 38 asserts to the SmtSolver that
the most signi cant bits of x and y are also equivalent. Checking satis ability in line 41 and
checking the result in line 42 con rms that the current set of assertions are now unsatis able
because of uninterpreted function axioms. Figure 4 shows exactly the same example but through
the Python API.</p>
      <p>It is very simple to change the solver in these two examples, assuming that the relevant
solver libraries have already been built. In the C++ example this amounts to including the
relevant solver factory le (similar to line 2), updating line 9 to use a di erent solver factory
create function, and nally recompiling and relinking with the new solver library. Assuming the
Python bindings were built with the relevant solver, changing the solver in the Python example
only requires using a di erent create function in line 5 of Figure 4.
5</p>
    </sec>
    <sec id="sec-4">
      <title>License</title>
      <p>The Smt-Switch code is distributed under the BSD 3-clause license. However, not all solvers
have BSD-compatible licenses. For these solvers, the user must obtain the solver libraries
themselves and ensure they meet all the requirements for the license. There are then instructions
for how to properly build smt-switch with that solver as the backend, in which case the license
assumes that of the solver. The BSD-compatible backend solvers are Boolector and CVC4.
6</p>
    </sec>
    <sec id="sec-5">
      <title>Related Work</title>
      <p>
        The most closely related work is smt-kit [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ], another C++ API for SMT solving. This API
utilizes templates to be solver agnostic, and has a term representation that is separate from the
underlying solver, as opposed to Smt-Switch which only provides an abstract interface and
a light wrapper around the underlying solvers. This design choice reduces overhead and keeps
maintenance simple. smt-kit does not appear to be under active development since 2014.
      </p>
      <p>
        Two other related tools are PySMT [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ] and sbv [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ]. PySMT is a solver-agnostic SMT solving
API for Python. PySMT has its own term representation and translates formulas to the backend
solvers dynamically once they are asserted. It also uses a class hierarchy to support swapping
underlying solvers. sbv is a solver-agnostic SMT-based veri cation tool for Haskell. It provides
its own datatypes for representing various SMT queries and communicates with solvers through
SMT-LIB with pipes.
      </p>
      <p>
        SmtSolver s = CVC4SolverFactory::create(false);
s-&gt;set_opt("incremental", "true");
Sort bvsort9 = s-&gt;make_sort(BV, 9);
Sort funsort = s-&gt;make_sort(FUNCTION, {bvsort9, bvsort9});
Term x = s-&gt;make_symbol("x", bvsort9);
Term y = s-&gt;make_symbol("y", bvsort9);
Term f = s-&gt;make_symbol("f", funsort);
Term fx = s-&gt;make_term(Apply, f, x);
Term fy = s-&gt;make_term(Apply, f, y);
// Functions are terms
assert(fx-&gt;get_op() == Apply);
TermVec fx_children(fx-&gt;begin(), fx-&gt;end());
assert(fx_children.size() == 2);
// These equalities are structural e.g. the first child *is* f
// These are not SMT equalities
assert(fx_children[0] == f);
assert(fx_children[
        <xref ref-type="bibr" rid="ref1">1</xref>
        ] == x);
// (assert (distinct (f x) (f y)))
s-&gt;assert_formula(s-&gt;make_term(Distinct, fx, fy));
Term x_7_0 = s-&gt;make_term(Op(Extract, 7, 0), x);
Term y_7_0 = s-&gt;make_term(Op(Extract, 7, 0), y);
// (assert (= ((_ extract 7 0) x) ((_ extract 7 0) y)))
s-&gt;assert_formula(s-&gt;make_term(Equal, x_7_0, y_7_0));
Result r = s-&gt;check_sat();
assert(r.is_sat()); // the MSB of x and y can be different
// (assert (= ((_ extract 8 8) x) ((_ extract 8 8) y)))
s-&gt;assert_formula(s-&gt;make_term(Equal,
s-&gt;make_term(Op(Extract, 8, 8), x),
s-&gt;make_term(Op(Extract, 8, 8), y)));
1 import smt_switch as ss
2 from smt_switch.primops import Apply, Distinct, Equal, Extract
3
4 if __name__ == "__main__":
5 s = ss.create_cvc4_solver(False)
6 s.set_opt(’incremental’, ’true’)
7 bvsort9 = s.make_sort(ss.sortkinds.BV, 9)
8 funsort = s.make_sort(ss.sortkinds.FUNCTION, [bvsort9, bvsort9])
9 x = s.make_symbol(’x’, bvsort9)
10 y = s.make_symbol(’y’, bvsort9)
11 f = s.make_symbol(’f’, funsort)
12 fx = s.make_term(Apply, f, x)
13 fy = s.make_term(Apply, f, y)
14
15 assert fx.get_op() == Apply
16 fx_children = [c for c in fx]
17 assert len(fx_children) == 2
18 assert fx_children[0] == f
19 assert fx_children[
        <xref ref-type="bibr" rid="ref1">1</xref>
        ] == x
20
21 s.assert_formula(s.make_term(Distinct, fx, fy))
22 x_7_0 = s.make_term(ss.Op(Extract, 7, 0), x)
23 y_7_0 = s.make_term(ss.Op(Extract, 7, 0), y)
24 s.assert_formula(s.make_term(Equal, x_7_0, y_7_0))
25
26 r = s.check_sat()
27 assert r.is_sat()
28 s.assert_formula(s.make_term(Equal,
29 s.make_term(ss.Op(Extract, 8, 8), x),
30 s.make_term(ss.Op(Extract, 8, 8), y)))
31 r = s.check_sat()
32 assert r.is_unsat()
      </p>
    </sec>
    <sec id="sec-6">
      <title>7 Conclusion</title>
      <p>
        We have presented work in progress on Smt-Switch, a solver-agnostic API for performant
prototyping with SMT solvers in C++. This system is available for use on GitHub and has
already been used in projects [
        <xref ref-type="bibr" rid="ref13 ref15">13, 15</xref>
        ]. Future work includes adding a backend for Z3 [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ], adding
support for quanti ers and inductive datatypes, as well as investigating possible performance
improvements, such as optimized data structures and alternatives to smart pointers.
      </p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [1]
          <string-name>
            <given-names>Clark</given-names>
            <surname>Barrett</surname>
          </string-name>
          , Christopher L. Conway, Morgan Deters, Liana Hadarean, Dejan Jovanovi'c, Tim King,
          <string-name>
            <given-names>Andrew</given-names>
            <surname>Reynolds</surname>
          </string-name>
          , and Cesare Tinelli. CVC4. In Ganesh Gopalakrishnan and Shaz Qadeer, editors,
          <source>Proceedings of the 23rd International Conference on Computer Aided Veri cation (CAV '11)</source>
          , volume
          <volume>6806</volume>
          of Lecture Notes in Computer Science, pages
          <volume>171</volume>
          {
          <fpage>177</fpage>
          . Springer,
          <year>July 2011</year>
          . Snowbird, Utah.
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [2]
          <string-name>
            <given-names>Clark</given-names>
            <surname>Barrett</surname>
          </string-name>
          , Pascal Fontaine, and
          <string-name>
            <given-names>Cesare</given-names>
            <surname>Tinelli</surname>
          </string-name>
          .
          <source>The SMT-LIB Standard: Version 2.6. Technical report</source>
          , Department of Computer Science, The University of Iowa,
          <year>2017</year>
          . Available at www.
          <source>SMT-LIB.org.</source>
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [3]
          <string-name>
            <given-names>Stefan</given-names>
            <surname>Behnel</surname>
          </string-name>
          , Robert Bradshaw, Craig Citro, Lisandro Dalcin, Dag Sverre Seljebotn, and
          <string-name>
            <given-names>Kurt</given-names>
            <surname>Smith</surname>
          </string-name>
          . Cython:
          <article-title>The best of both worlds</article-title>
          .
          <source>Computing in Science &amp; Engineering</source>
          ,
          <volume>13</volume>
          (
          <issue>2</issue>
          ):
          <volume>31</volume>
          {
          <fpage>39</fpage>
          ,
          <year>2011</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [4]
          <string-name>
            <given-names>Alessandro</given-names>
            <surname>Cimatti</surname>
          </string-name>
          , Alberto Griggio, Bastiaan Schaafsma, and
          <string-name>
            <given-names>Roberto</given-names>
            <surname>Sebastiani</surname>
          </string-name>
          .
          <article-title>The MathSAT5 SMT Solver</article-title>
          . In Nir Piterman and Scott Smolka, editors,
          <source>Proceedings of TACAS</source>
          , volume
          <volume>7795</volume>
          <source>of LNCS</source>
          . Springer,
          <year>2013</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [5]
          <string-name>
            <given-names>Leonardo</given-names>
            <surname>Mendonca de Moura</surname>
          </string-name>
          and
          <article-title>Nikolaj Bj rner. Z3: an e cient SMT solver</article-title>
          .
          <source>In TACAS</source>
          , volume
          <volume>4963</volume>
          of Lecture Notes in Computer Science, pages
          <volume>337</volume>
          {
          <fpage>340</fpage>
          . Springer,
          <year>2008</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [6]
          <string-name>
            <given-names>Bruno</given-names>
            <surname>Dutertre</surname>
          </string-name>
          .
          <article-title>Yices 2.2</article-title>
          . In Armin Biere and Roderick Bloem, editors, Computer-Aided Veri - cation (CAV'
          <year>2014</year>
          ), volume
          <volume>8559</volume>
          of Lecture Notes in Computer Science, pages
          <volume>737</volume>
          {
          <fpage>744</fpage>
          . Springer,
          <year>July 2014</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [7]
          <string-name>
            <given-names>Levent</given-names>
            <surname>Erkok</surname>
          </string-name>
          .
          <article-title>Sbv: Smt based veri cation in haskell</article-title>
          . http://leventerkok.github.io/sbv/.
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [8]
          <string-name>
            <given-names>Marco</given-names>
            <surname>Gario</surname>
          </string-name>
          and
          <string-name>
            <given-names>Andrea</given-names>
            <surname>Micheli</surname>
          </string-name>
          .
          <article-title>Pysmt: a solver-agnostic library for fast prototyping of smtbased algorithms</article-title>
          .
          <source>In Proceedings of the 13th International Workshop on Satis ability Modulo Theories (SMT)</source>
          , pages
          <fpage>373</fpage>
          {
          <fpage>384</fpage>
          ,
          <year>2015</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          [9]
          <string-name>
            <surname>Google</surname>
          </string-name>
          . Googletest.
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          [10]
          <string-name>
            <given-names>Alex</given-names>
            <surname>Horn.</surname>
          </string-name>
          smt-kit: C+
          <article-title>+11 library for many sorted logics</article-title>
          . http://ahorn.github.io/ smt-kit/.
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          [11]
          <string-name>
            <surname>KitWare</surname>
          </string-name>
          . Cmake. https://cmake.org.
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          [12]
          <string-name>
            <surname>Holger</surname>
            <given-names>Krekel</given-names>
          </string-name>
          , Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe,
          <source>Brianna Laugher, and Florian Bruhin. pytest 5.4.2</source>
          ,
          <year>2004</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          [13]
          <string-name>
            <surname>Makai</surname>
            <given-names>Mann</given-names>
          </string-name>
          , Ahmed Irfan, Florian Lonsing, and
          <string-name>
            <given-names>Clark</given-names>
            <surname>Barrett</surname>
          </string-name>
          .
          <article-title>Pono: an smt-based model checker</article-title>
          . https://github.com/upscale-project/pono.
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          [14]
          <string-name>
            <surname>Aina</surname>
            <given-names>Niemetz</given-names>
          </string-name>
          , Mathias Preiner,
          <article-title>Cli ord Wolf, and Armin Biere. Btor2 , btormc and boolector 3.0</article-title>
          .
          <source>In CAV (1)</source>
          , volume
          <volume>10981</volume>
          of Lecture Notes in Computer Science, pages
          <volume>587</volume>
          {
          <fpage>595</fpage>
          . Springer,
          <year>2018</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          [15]
          <string-name>
            <surname>Yoni</surname>
            <given-names>Zohar</given-names>
          </string-name>
          , Ahmed Irfan, Makai Mann,
          <string-name>
            <surname>Andres</surname>
            <given-names>N</given-names>
          </string-name>
          otzli, Andrew Reynolds, and
          <string-name>
            <given-names>Clark</given-names>
            <surname>Barrett</surname>
          </string-name>
          .
          <year>lazybv2int</year>
          . https://github.com/yoni206/lazybv2int.
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>