OpenSMT1 is no longer actively developed. This page is for archival purposes.
Build your solver
OpenSMT was designed with the idea of easy extension and customization in mind. Building a new solver requires implementing a simple interface derived from TSolver class.
class TSolver { void inform ( Enode * ); bool assertLit ( Enode * ); bool check ( bool ); void pushBktPoint ( ); void popBktPoint ( ); bool belongsToT ( Enode * ); void computeModel ( ); vector < Enode * > & explanation; vector < Enode * > & deductions; vector < Enode * > & suggestions; }
The interface that T-solver is required to implement is minimalistic. inform is used to communicate the existence of a new T-atom to the T-solver. assertLit asserts a (previously informed) T-atom in the T-solver with the right polarity; it may also perform some cheap form of consistency check. check determines the T-satisfiability of the current set of asserted T-atoms. pushBktPoint and popBktPoint are used respectively to save and to restore the state of the T-solver, in order to cope with backtracking within the SAT-Solver. belongsToT is used to determine if a given T-atom belongs to the theory solved by the T-solver. Finally computeModel forces T-solverto save the model (if any) inside Enode's field.
Three vectors, explanation, deductions, suggestions, are shared among the T-solvers, and they are used to simplify the communication of conflicts, T-atoms to be deduced and "suggested" T-atoms. Suggestions are atoms consistent with the current state of the T-solver, but that they cannot be directly deduced. Suggestions are used to perform decisions in the SAT-Solver.
Explanations for deductions are computed on demand. When an explanation for a deduction l is required, the literal not(l) is pushed in the T-solver, and the explanation is computed by calling check. This process is completely transparent for the T-solverthus avoiding any burden for generating and tracking explanations for deductions on the T-solver side.
How-to extend OpenSMT with your solver
In this tutorial, we show how to extend OpenSMT with a new theory solver. For the sake of explanation, we will assume the following:
- we have an alternative decision procedure (X-solver) for a logic QF_X, defined as a class Xdpimplemented in Xdp.C and Xdp.h files
- the procedure implements the interface described above
- we are working in a common Unix/Linux environment
The integration of the new decision procedure can be executed in three simple macro steps.
Step 1: setting up the environment for the new solver.
This is usually the most tedious operation, as it requires understanding the software organization and compilation mechanism. However, we provide a script create_tsolver.sh that takes care of setting up the environment automatically.
In OpenSMT, the ordinary theory solvers are defined in the subdirectory src/tsolvers
user:~$ ls OpenSMT xsolver user:~$ cd OpenSMT user:OpenSMT$ ls src/tsolvers bvsolver dlsolver emptysolver lrasolver Makefile.am Makefile.in THandler.C THandler.h tsolver TSolver.h
We use the script create_tsolver.sh to create a wrapper for the X - solver as follows:
user:OpenSMT$ ./create_tsolver.sh XSolver xsolver Creating src/tsolvers/xsolver/XSolver.C src/tsolvers/xsolver/XSolver.h Creating src/tsolvers/xsolver/Makefile.am [Backing up src/tsolvers/Makefile.am as src/tsolvers/.Makefile.am.old] Modifying src/tsolvers/xsolver/Makefile.am [Backing up configure.ac as .configure.ac.old] Modifying configure.ac Reconfiguring
The script above created a wrapper XSolver.C , XSolver.h in a subdirectory xsolver, and it adjusted the makefiles to support the new files in the compilation. The configure script was also updated.
user:OpenSMT$ ls src/tsolvers bvsolver dlsolver emptysolver lrasolver Makefile.am Makefile.in THandler.C THandler.h tsolver TSolver.h xsolver user:OpenSMT$ ls src/tsolvers/xsolver Makefile.am Makefile.in XSolver.C XSolver.h
Step 2: integration with the new solver.
In this step, we link the wrapper with the actual implementation for the procedure. First, we copy the X-solver's files in the created subdirectory under src/tsolvers .
user:OpenSMT$ cp ../xsolver/Xdp.* src/tsolvers/xsolver
The connection with the methods of Xdp has to be specified inside XSolver.h and XSolver.C . InXSolver.h we add the right header file and a pointer to Xdp class
#include "Xdp.h" // Header file ... Xdp * xdp; // Pointer to dp class ...
In XSolver.C we link the methods of the wrapper with the ones of Xdp
... XSolver::XSolver( ... ) { xdp = new Xdp( ); } XSolver::~XSolver( ) { delete xdp; } ... bool XSolver::check( bool complete ) { return xdp->check( ); } ...
Then we edit src/tsolvers/xsolver/Makefile.am to include the compilation of Xdp.C and Xdp.h .
Step 3: implementation of translation methods.
This step is required to translate the data structures for representing terms of OpenSMT. These are the only functions whose implementation depends on the particular procedure to consider. Examples can be found in the already existing solvers under src/tsolvers . The initialization of the solver can be set up insrc/EgraphSolver.C .