Introduction: Sudoku and Mathematics #

Sudoku is a popular logic puzzle with simple rules. Each row, column, and 3×3 box in a 9×9 grid must contain the digits 1 through 9 exactly once. These puzzles are often solved through trial and error or more systematic backtracking algorithms.

But what if we modeled Sudoku using more abstract mathematics, such as algebraic geometry? This article explores how to turn Sudoku constraints into polynomial equations and use computer algebra to approach the puzzle differently. We will also look at a practical Python solver alongside the theoretical model.

Turning Sudoku Rules into Polynomials #

The basic idea is to represent each of the 81 cells with a variable x_i, where i runs from 1 to 81. We want a system of equations that forces those variables to obey the rules.

Constraint 1: Every Cell Must Contain a Digit from 1 to 9

How can we require each x_i to belong to the set {1, 2, …, 9}? Define a polynomial for each variable:

F_i(x_i) = (x_i - 1)(x_i - 2)...(x_i - 9)

The value is one of the permitted digits exactly when F_i(x_i) = 0. For example, when x_i = 5, one factor is (5 - 5) = 0, making the whole product zero. When x_i = 10, none of the factors is zero.

Constraint 2: Uniqueness in Rows, Columns, and Boxes

Two different cells in the same row, column, or 3×3 box must not contain the same value. How can we express this uniqueness constraint?

First, define a set containing all pairs of cells that share one of these groups:

E = {(i, j) | 1 <= i < j <= 81, x_i and x_j share a group}

For every pair (i, j) in E, we need an equation ensuring that x_i and x_j differ. The original article defined a polynomial called G_ij, although the mathematical validity and practical applicability of that part are debatable.

A more standard approach introduces an auxiliary variable y_ij and writes y_ij * (x_i - x_j) - 1 = 0. This requires x_i - x_j to be nonzero, so the two cells must differ.

The Algebraic Model: Ideals and Varieties #

An ideal brings the polynomial constraints together. We work over a field K, typically the rational or complex numbers, with polynomial variables for the cells and the auxiliary variables introduced above.

The ideal I is generated by all the value-constraint polynomials F_i(x_i) and the uniqueness polynomials y_ij * (x_i - x_j) - 1 for pairs in E.

The common zero set of these polynomials is the variety V(I). Its cell coordinates (x_1, ..., x_81) satisfy the Sudoku rules. The digit constraints already restrict those coordinates to the integers 1 through 9.

Solving a Particular Puzzle #

A Sudoku puzzle begins with some cells filled in. Let L be the subset of cell indices for which an initial value a_i is given. Add these clues to the model by adjoining the equations x_i - a_i = 0 for every i in L. Call the resulting ideal I_S.

For a puzzle with a unique solution, the cell-coordinate part of the reduced Gröbner basis takes the form:

{x_1 - a_1, x_2 - a_2, ..., x_81 - a_81}

The auxiliary variables also have determined values in the extended system.

Gröbner bases are powerful tools for solving polynomial systems and can be computed with computer algebra systems.

Theory and Practice: Computational Cost #

This algebraic approach is elegant, but computing a Gröbner basis for a system with 81 cell variables is computationally expensive. In practice, much more efficient Sudoku-solving methods are available.

One of the most common is backtracking.

A Practical Approach: Backtracking in Python #

Here is a simple Python program using standard backtracking:

sudoku_solver.py
N = 9
EMPTY = 0
def print_board(board):
print("-------------------------")
for i in range(N):
print("| ", end="")
for j in range(N):
print(". " if board[i][j] == EMPTY else f"{board[i][j]} ", end="")
if (j + 1) % 3 == 0:
print("| ", end="")
print()
if (i + 1) % 3 == 0:
print("-------------------------")
def is_valid(board, row, col, num):
if num in board[row]:
return False
if num in [board[i][col] for i in range(N)]:
return False
start_row, start_col = row - row % 3, col - col % 3
for i in range(3):
for j in range(3):
if board[i + start_row][j + start_col] == num:
return False
return True
def find_empty_cell(board):
for row in range(N):
for col in range(N):
if board[row][col] == EMPTY:
return row, col
return None
def solve_sudoku(board):
cell = find_empty_cell(board)
if cell is None:
return True
row, col = cell
for num in range(1, 10):
if is_valid(board, row, col, num):
board[row][col] = num
if solve_sudoku(board):
return True
board[row][col] = EMPTY
return False
if __name__ == "__main__":
board = [
[5, 3, 0, 0, 7, 0, 0, 0, 0],
[6, 0, 0, 1, 9, 5, 0, 0, 0],
[0, 9, 8, 0, 0, 0, 0, 6, 0],
[8, 0, 0, 0, 6, 0, 0, 0, 3],
[4, 0, 0, 8, 0, 3, 0, 0, 1],
[7, 0, 0, 0, 2, 0, 0, 0, 6],
[0, 6, 0, 0, 0, 0, 2, 8, 0],
[0, 0, 0, 4, 1, 9, 0, 0, 5],
[0, 0, 0, 0, 8, 0, 0, 7, 9],
]
print("Initial Sudoku:")
print_board(board)
print("\nSolving...\n")
if solve_sudoku(board):
print("Solved Sudoku:")
print_board(board)
else:
print("No solution found.")

The algorithm finds an empty cell, tries valid digits from 1 to 9, and continues recursively. If it reaches a dead end, it returns to an earlier choice and tries another digit.

Conclusion #

Modeling Sudoku with algebraic geometry offers a different and mathematically rich perspective. Polynomials, ideals, and Gröbner bases reveal the structure behind the puzzle. In computational efficiency, however, the theoretical method falls behind standard algorithms such as backtracking. It is still fascinating to see the abstract mathematics hidden inside a simple logic puzzle.