MODELING SUDOKU PUZZLES WITH PYTHON 85>>> d = {1: 2, 2: 5, 5: 3, 7: 9, 9: 1,... 11: 1, 15: 4, 19: 4, 21: 7, 25: 2,... 27: 8, 30: 5, 31: 2, 41: 9, 42: 8,... 43: 1, 47: 4, 51: 3, 58: 3, 59: 6,... 62: 7, 63: 2, 65: 7, 72: 3, 73: 9,... 75: 3, 79: 6, 81: 4}A <strong>Sudoku</strong> puzzle object can be built from such a dictionary.Note that the boxsize is a parameter of the Puzzle objectconstructor.>>> from sudoku import Puzzle>>> p = Puzzle(d, 3)>>> p2 5 . . 3 . 9 . 1. 1 . . . 4 . . .4 . 7 . . . 2 . 8. . 5 2 . . . . .. . . . 9 8 1 . .. 4 . . . 3 . . .. . . 3 6 . . 7 2. 7 . . . . . . 39 . 3 . . . 6 . 4In practice, however, the user mainly interacts <strong>with</strong>sudoku.py either by creating specific puzzles instancesthrough input of puzzle strings, directly or from a text file,or by using generator functions.The string representation of a <strong>Sudoku</strong> puzzle of boxsize nis a string of ascii characters of length n 4 . In such a stringa period character represents an empty cell and other asciicharacters are used to specify assigned values. Whitespacecharacters and newlines are ignored when Puzzle objectsare built from strings.A possible string representation of the puzzle from theintroduction is:>>> s = """... 2 5 . . 3 . 9 . 1... . 1 . . . 4 . . .... 4 . 7 . . . 2 . 8... . . 5 2 . . . . .... . . . . 9 8 1 . .... . 4 . . . 3 . . .... . . . 3 6 . . 7 2... . 7 . . . . . . 3... 9 . 3 . . . 6 . 4"""A Puzzle object can be built from a puzzle string byproviding the keyword argument format = ’s’>>> p = Puzzle(s, 3, format = ’s’)Random puzzles can be created in sudoku.py by therandom_puzzle function.>>> from sudoku import random_puzzle>>> q = random_puzzle(15, 3)>>> q. . . . 5 . . . 1. 5 . . . . . . 7. . 1 9 . 7 . . .. . . . . . . . .. . 5 . . . 7 . .. . 6 . . . . 9 .. . . . . 5 . . .5 . . . . . 4 . .1 . . . . . . . .The first argument to random_puzzle is the number ofprescribed cells in the puzzle.Solving of puzzles in sudoku.py is handled by thesolve function. This function can use a variety of differentalgorithms, specified by an optional model keywordargument, to solve the puzzle. Possible values are CP forconstraint propagation, lp for linear programming, graphto use a node coloring algorithm on a graph puzzle modeland groebner to solve a polynomial system model viaa Groebner basis algorithm. The default behavior is to useconstraint propagation.>>> from sudoku import solve>>> s = solve(q)>>> s7 3 2 8 5 6 9 4 18 5 9 4 2 1 6 3 76 4 1 9 3 7 8 5 29 7 8 5 4 3 1 2 63 2 5 6 1 9 7 8 44 1 6 7 8 2 5 9 32 9 4 1 6 5 3 7 85 6 3 2 7 8 4 1 91 8 7 3 9 4 2 6 5<strong>Sudoku</strong> puzzles of boxsize other than 3 can also be modeled<strong>with</strong> sudoku.py. <strong>Puzzles</strong> of boxsize 2 are often calledShidoku.>>> q2 = random_puzzle(7, 2)>>> q24 . . .2 1 . .. 4 . 2. . 3 4>>> solve(q2)4 3 2 12 1 4 33 4 1 21 2 3 4<strong>Sudoku</strong> puzzles of boxsize greater than three are less commonlystudied in the literature. In sudoku.py we use printablecharacters (from string.printable) for the symbolsof puzzles <strong>with</strong> boxsize greater than 3>>> q4 = random_puzzle(200, 4)>>> q4. . e d . . a 9 8 . . 5 . 3 2 1c b a 9 4 . 2 1 g . e d 8 7 6 .8 . 6 5 g f e d 4 3 2 1 c b a 9. . 2 1 8 7 6 5 c . a . g f e df d g . 9 8 7 c 3 6 . b . 2 . .2 6 . . 1 d g b f 4 c . 9 . 8 7. 4 1 8 3 6 . 2 9 e 7 . . . 5 c9 c 7 b e a 5 . 2 1 . 8 f g 3 6e g 9 f 7 . 8 a 6 d 3 4 5 1 b .b a . 7 . 2 9 e 5 . 1 f . 8 c .3 8 . 6 5 1 4 f . 9 b 2 7 a d g. . 4 . d g b 3 7 a 8 c e 6 9 f. e f c 2 9 3 8 a 5 g 7 6 4 . b7 9 . 4 a . 1 6 d 8 . e 2 c g 36 2 8 g b . d . . c 9 3 . . f .5 1 3 a f e c g b 2 4 6 . . 7 8Solving puzzles of this size is still feasible by constraintpropogation>>> solve(q4)g f e d c b a 9 8 7 6 5 4 3 2 1c b a 9 4 3 2 1 g f e d 8 7 6 58 7 6 5 g f e d 4 3 2 1 c b a 94 3 2 1 8 7 6 5 c b a 9 g f e df d g e 9 8 7 c 3 6 5 b 1 2 4 a2 6 5 3 1 d g b f 4 c a 9 e 8 7a 4 1 8 3 6 f 2 9 e 7 g b d 5 c
86 PROC. OF THE 9th PYTHON IN SCIENCE CONF. (SCIPY 2010)9 c 7 b e a 5 4 2 1 d 8 f g 3 6e g 9 f 7 c 8 a 6 d 3 4 5 1 b 2b a d 7 6 2 9 e 5 g 1 f 3 8 c 43 8 c 6 5 1 4 f e 9 b 2 7 a d g1 5 4 2 d g b 3 7 a 8 c e 6 9 fd e f c 2 9 3 8 a 5 g 7 6 4 1 b7 9 b 4 a 5 1 6 d 8 f e 2 c g 36 2 8 g b 4 d 7 1 c 9 3 a 5 f e5 1 3 a f e c g b 2 4 6 d 9 7 8ModelsIn this section we introduce several models of <strong>Sudoku</strong> andshow how to use existing <strong>Python</strong> components to implementthese models. The models introduced here are all implementedin sudoku.py. Implementation details are discussed in thissection and demonstrations of the components of sudoku.pycorresponding to each of the different models are given.Constraint modelsConstraint models for <strong>Sudoku</strong> puzzles are discussed in[Sim05]. A simple model uses the AllDifferent constraint.A constraint program is a collection of constraints. Aconstraint restricts the values which can be assigned to certainvariables in a solution of the constraint problem. The AllDifferentconstraint restricts variables to having mutually differentvalues.<strong>Modeling</strong> <strong>Sudoku</strong> puzzles is easy <strong>with</strong> the AllDifferentconstraint. To model the empty <strong>Sudoku</strong> puzzle (i.e. the puzzle<strong>with</strong> no clues) a constraint program having an AllDifferentconstraint for every row, column and box is sufficient.For example, if we let x i 2 f1;:::;n 2 g for 1 i n 4 ,where x i = j means that cell i gets value j then the constraintmodel for a <strong>Sudoku</strong> puzzle of boxsize n = 3 would includeconstraints:AllDifferent(x 1 ;x 2 ;x 3 ;x 4 ;x 5 ;x 6 ;x 7 ;x 8 ;x 9 )AllDifferent(x 1 ;x 10 ;x 19 ;x 28 ;x 37 ;x 46 ;x 55 ;x 64 ;x 73 )AllDifferent(x 1 ;x 2 ;x 3 ;x 10 ;x 11 ;x 12 ;x 19 ;x 20 ;x 21 )These constraints ensure that, respectively, the variables inthe first row, column and box get different values.The <strong>Sudoku</strong> constraint model in sudoku.py is implementedusing python-constraint v1.1 by GustavoNiemeyer. This open-source library is available at http://labix.org/python-constraint.With python-constraint a Problem having variablesfor every cell f1;:::;n 4 g of the <strong>Sudoku</strong> puzzle isrequired. The list of cell labels is given by the functioncells in sudoku.py. Every variable has the same domainf1;:::;n 2 g of symbols. The list of symbols in sudoku.pyis given by the symbols function.The Problem member function addVariables providesa convenient method for adding variables to a constraintproblem object.>>> from constraint import Problem>>> from sudoku import cells, symbols>>> cp = Problem()>>> cp.addVariables(cells(n), symbols(n))The AllDifferent constraint in python-constraintis implemented as AllDifferentConstraint(). TheaddConstraint(constraint, variables) memberfunction is used to add a constraint on variables toa constraint Problem object. So, to build an empty <strong>Sudoku</strong>puzzle constraint model we can do the following.>>> from constraint import AllDifferentConstraint>>> from sudoku import \... cells_by_row, cells_by_col, cells_by_box>>> for row in cells_by_row(n):... cp.addConstraint(AllDifferentConstraint(), row)>>> for col in cells_by_col(n):... cp.addConstraint(AllDifferentConstraint(), col)>>> for box in cells_by_box(n):... cp.addConstraint(AllDifferentConstraint(), box)Here the functions cells_by_row, cells_by_col andcells_by_box give the cell labels of a <strong>Sudoku</strong> puzzleordered, respectively, by row, column and box. These threeloops, respectively, add to the constraint problem object thenecessary constraints on row, column and box variables.To extend this model to a <strong>Sudoku</strong> puzzle <strong>with</strong> clues requiresadditional constraints to ensure that the values assigned to cluevariables are fixed. One possibility is to use an ExactSumconstraint for each clue.The ExactSum constraint restricts the sum of a set ofvariables to a precise given value. We can slightly abuse theExactSum constraint to specify that certain individual variablesare given certain specific values. In particular, if the puzzleclues are given by a dictionary d then we can complete ourmodel by adding the following constraints.>>> from constraint import ExactSumConstraint as Exact>>> for cell in d:... cp.addConstraint(Exact(d[cell]), [cell])To solve the <strong>Sudoku</strong> puzzle now can be done by solvingthe constraint model cp. The constraint propogation algorithmof python-constraint can be invoked by thegetSolution member function.>>> s = Puzzle(cp.getSolution(), 3)>>> s2 5 8 7 3 6 9 4 16 1 9 8 2 4 3 5 74 3 7 9 1 5 2 6 83 9 5 2 7 1 4 8 67 6 2 4 9 8 1 3 58 4 1 6 5 3 7 2 91 8 4 3 6 9 5 7 25 7 6 1 4 2 8 9 39 2 3 5 8 7 6 1 4The general solve function of sudoku.py knows how tobuild the constraint model above, find a solution via the propogationalgorithm of python-constraint and translatethe solution into a completed <strong>Sudoku</strong> puzzle.>>> s = solve(p, model = ’CP’)Here, p is a Puzzle instance. In fact, the model = ’CP’keyword argument in this case is redundant, as ’CP’ is thedefault value of model.Graph modelsA graph model for <strong>Sudoku</strong> is presented in [Var05]. In thismodel, every cell of the <strong>Sudoku</strong> grid is represented by a