\myheading{Simple sudoku in SMT} \label{sudoku_SMT} \leveldown{} \renewcommand{\CURPATH}{puzzles/sudoku/1} \myheading{The first idea} The only thing we must decide is that how to determine in one expression, if the input 9 variables has all 9 unique numbers? They are not ordered or sorted, after all. From the school-level arithmetic, we can devise this idea: \begin{equation} \underbrace{10^{i_1} + 10^{i_2} + \cdots + 10^{i_9}}_9 = 1111111110 \end{equation} Take each input variable, calculate $10^i$ and sum them all. If all input values are unique, each will be settled at its own place. Even more than that: there will be no holes, i.e., no skipped values. So, in case of Sudoku, 1111111110 number will be final result, indicating that all 9 input values are unique, in range of 1..9. Exponentiation is heavy operation, can we use binary operations? Yes, just replace 10 with 2: \begin{equation} \underbrace{2^{i_1} + 2^{i_2} + \cdots + 2^{i_9}}_9 = 1111111110_2 \end{equation} The effect is just the same, but the final value is in base 2 instead of 10. Now a working example: \lstinputlisting[style=custompy]{\CURPATH/sudoku_plus_Z3.py} ( \url{\RepoURL/\CURPATH/sudoku_plus_Z3.py} ) \begin{lstlisting} % time python sudoku_plus_Z3.py 1 4 5 3 2 7 6 9 8 8 3 9 6 5 4 1 2 7 6 7 2 9 1 8 5 4 3 4 9 6 1 8 5 3 7 2 2 1 8 4 7 3 9 5 6 7 5 3 2 9 6 4 8 1 3 6 7 5 4 2 8 1 9 9 8 4 7 6 1 2 3 5 5 2 1 8 3 9 7 6 4 real 0m11.717s user 0m10.896s sys 0m0.068s \end{lstlisting} Even more, we can replace summing operation to logical OR: \begin{equation} \underbrace{2^{i_1} \vee 2^{i_2} \vee \cdots \vee 2^{i_9}}_9 = 1111111110_2 \end{equation} % FIXME: только часть исходника \lstinputlisting[style=custompy]{\CURPATH/sudoku_or_Z3.py} ( \url{\RepoURL/\CURPATH/sudoku_or_Z3.py} ) Now it works much faster. Z3 handles OR operation over bit vectors better than addition? \begin{lstlisting} % time python sudoku_or_Z3.py 1 4 5 3 2 7 6 9 8 8 3 9 6 5 4 1 2 7 6 7 2 9 1 8 5 4 3 4 9 6 1 8 5 3 7 2 2 1 8 4 7 3 9 5 6 7 5 3 2 9 6 4 8 1 3 6 7 5 4 2 8 1 9 9 8 4 7 6 1 2 3 5 5 2 1 8 3 9 7 6 4 real 0m1.429s user 0m1.393s sys 0m0.036s \end{lstlisting} The puzzle I used as example is dubbed as one of the hardest known \footnote{\url{http://www.mirror.co.uk/news/weird-news/worlds-hardest-sudoku-can-you-242294}} (well, for humans). It took $\approx 1.4$ seconds on my Intel Core i3-3110M 2.4GHz notebook to solve it. \myheading{The second idea} My first approach is far from effective, I did what first came to my mind and worked. Another approach is to use \TT{distinct} command from SMT-LIB, which tells Z3 that some variables must be distinct (or unique). This command is also available in Z3 Python interface. I've rewritten my first Sudoku solver, now it operates over \emph{Int} \emph{sort}, it has \TT{distinct} commands instead of bit operations, and now also other constraint added: each cell value must be in 1..9 range, because, otherwise, Z3 will offer (although correct) solution with too big and/or negative numbers. % FIXME: label inside of listing \label{sudoku2_Z3} % FIXME: только часть исходника \lstinputlisting[style=custompy]{\CURPATH/sudoku2_Z3.py} ( \url{\RepoURL/\CURPATH/sudoku2_Z3.py} ) \begin{lstlisting} % time python sudoku2_Z3.py 1 4 5 3 2 7 6 9 8 8 3 9 6 5 4 1 2 7 6 7 2 9 1 8 5 4 3 4 9 6 1 8 5 3 7 2 2 1 8 4 7 3 9 5 6 7 5 3 2 9 6 4 8 1 3 6 7 5 4 2 8 1 9 9 8 4 7 6 1 2 3 5 5 2 1 8 3 9 7 6 4 real 0m0.382s user 0m0.346s sys 0m0.036s \end{lstlisting} That's much faster. \myheading{Conclusion} \ac{SMT}-solvers are so helpful, is that our Sudoku solver has nothing else, we have just defined relationships between variables (cells). \myheading{Homework} As it seems, true Sudoku puzzle is the one which has only one solution. The piece of code I've included here shows only the first one. Using the method described earlier (\ref{SMTEnumerate}, also called ``model counting''), try to find more solutions, or prove that the solution you have just found is the only one possible. \myheading{Further reading} \url{http://www.norvig.com/sudoku.html} \myheading{Sudoku as a \ac{SAT} problem} It's also possible to represent Sudoku puzzle as a huge \ac{CNF} equation and use \ac{SAT}-solver to find solution, but it's just trickier. Some articles about it: \emph{Building a Sudoku Solver with SAT}\footnote{\url{https://dspace.mit.edu/bitstream/handle/1721.1/106923/6-005-fall-2011/contents/assignments/MIT6_005F11_ps4.pdf}}, Tjark Weber, \emph{A SAT-based Sudoku Solver}\footnote{\url{https://www.lri.fr/~conchon/mpri/weber.pdf}}, Ines Lynce, Joel Ouaknine, \emph{Sudoku as a SAT Problem}\footnote{\url{http://sat.inesc-id.pt/~ines/publications/aimath06.pdf}}, Gihwon Kwon, Himanshu Jain, \emph{Optimized CNF Encoding for Sudoku Puzzles}\footnote{\url{http://www.cs.cmu.edu/~hjain/papers/sudoku-as-SAT.pdf}}. \ac{SMT}-solver can also use \ac{SAT}-solver in its core, so it does all mundane translating work. As a ``compiler'', it may not do this in the most efficient way, though. \levelup{}