\myheading{Simple adder in SAT/SMT} \label{simple_adder} Let's solve the following equation $a+b=4 \equiv 2^4$ on the 4-bit CPU (hence, modulo $2^4$): \lstinputlisting[style=customsmt]{\CURPATH/adder/bvadd_example.smt} There are 16 possible solutions (easy to check even by hand): \begin{lstlisting} (model (define-fun a () (_ BitVec 4) (_ bv0 4)) ; 0x0 (define-fun b () (_ BitVec 4) (_ bv4 4)) ; 0x4 ) (model (define-fun a () (_ BitVec 4) (_ bv12 4)) ; 0xc (define-fun b () (_ BitVec 4) (_ bv8 4)) ; 0x8 ) ... (model (define-fun a () (_ BitVec 4) (_ bv9 4)) ; 0x9 (define-fun b () (_ BitVec 4) (_ bv11 4)) ; 0xb ) Model count: 16 \end{lstlisting} How I implemented this in my toy-level SMT solver? First, we need an electronic adder, like it's implemented in digital circuits. Take a look at a full adder: \ref{fig:full_adder}. % FIXME: rendered as ?? And this is how full adders gathered together to form a simple 4-bit carry-ripple adder: \ref{fig:four_bit_adder}. More info from wikipedia: \url{https://en.wikipedia.org/wiki/Adder_(electronics)}. I'm implementing full-adder like this: \begin{lstlisting}[style=customc,label=MK85_adder] void add_Tseitin_XOR(int v1, int v2, int v3) { add_comment ("%s %d=%d^%d", __FUNCTION__, v3, v1, v2); add_clause3 (-v1, -v2, -v3); add_clause3 (v1, v2, -v3); add_clause3 (v1, -v2, v3); add_clause3 (-v1, v2, v3); }; void add_Tseitin_OR2(int v1, int v2, int var_out) { add_comment ("%s %d=%d|%d", __FUNCTION__, var_out, v1, v2); add_clause("%d %d -%d", v1, v2, var_out); add_clause2(-v1, var_out); add_clause2(-v2, var_out); }; void add_Tseitin_AND(int a, int b, int out) { add_comment ("%s %d=%d&%d", __FUNCTION__, out, a, b); add_clause3 (-a, -b, out); add_clause2 (a, -out); add_clause2 (b, -out); }; void add_FA(int a, int b, int cin, int s, int cout) { add_comment("%s inputs=%d, %d, cin=%d, s=%d, cout=%d", __FUNCTION__, a, b, cin, s, cout); // allocate 3 "joint" variables: int XOR1_out=next_var_no++; int AND1_out=next_var_no++; int AND2_out=next_var_no++; // add gates and connect them. // order doesn't matter, BTW: add_Tseitin_XOR(a, b, XOR1_out); add_Tseitin_XOR(XOR1_out, cin, s); add_Tseitin_AND(XOR1_out, cin, AND1_out); add_Tseitin_AND(a, b, AND2_out); add_Tseitin_OR2(AND1_out, AND2_out, cout); }; \end{lstlisting} ( \url{\MKURL} ) |add\_Tseitin*()| functions makes logic gates in CNF form: \url{https://en.wikipedia.org/wiki/Tseytin_transformation}. Then I connect logic gates to make full-adder. Then I connect full-adders to create a n-bit adder: \begin{lstlisting} void generate_adder(struct variable* a, struct variable* b, struct variable *carry_in, // inputs struct variable** sum, struct variable** carry_out) // outputs { ... *sum=create_internal_variable("adder_sum", TY_BITVEC, a->width); int carry=carry_in->var_no; // the first full-adder could be half-adder, but we make things simple here for (int i=0; iwidth; i++) { *carry_out=create_internal_variable("adder_carry", TY_BOOL, 1); add_FA(a->var_no+i, b->var_no+i, carry, (*sum)->var_no+i, (*carry_out)->var_no); // newly created carry_out is a carry_in for the next full-adder: carry=(*carry_out)->var_no; }; }; \end{lstlisting} ( \url{\MKURL} ) Let's take a look on output CNF file: \lstinputlisting[style=customsat]{\CURPATH/adder/tmp.cnf} Filter out comments: \lstinputlisting[style=customsat]{\CURPATH/adder/tmp.cnf.comments} I make these functions add variable numbers to comments. And you can see how all the signals are routed inside each full-adder. |generate\_EQ()| function makes two bitvectors equal by XOR-ing two bitvectors. Resulting bitvector is then OR-ed, and result must be zero. % TODO \ref{} Again, this SAT instance is small enough to be handled by my simple SAT backtracking solver: \begin{lstlisting} SAT -1 2 -3 -4 -5 -6 -7 -8 9 -10 -11 -12 13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 24 -25 -26 -27 -28 -29 -30 -31 -32 33 -34 -35 -36 -37 -38 -39 40 0 SAT -1 2 -3 -4 -5 6 -7 -8 9 10 -11 -12 13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 24 -25 -26 27 -28 -29 30 -31 -32 33 -34 -35 -36 -37 -38 -39 40 0 ... SAT -1 2 3 4 5 -6 7 -8 9 10 -11 -12 13 -14 15 -16 -17 18 19 20 21 -22 23 -24 -25 26 27 28 29 -30 -31 -32 33 -34 -35 -36 -37 -38 -39 40 0 SAT -1 2 3 4 5 6 7 -8 9 -10 -11 -12 13 -14 15 -16 -17 18 19 20 21 -22 23 -24 -25 26 27 28 29 -30 -31 -32 33 -34 -35 -36 -37 -38 -39 40 0 UNSAT solutions= 16 \end{lstlisting} %Another post in my blog where I write about adders in SAT: _HTML_LINK_AS_IS(`https://yurichev.com/blog/factor_SAT/').