Satisfiability Problem · SAT solvers

Lesson 3

Nikolai Chukhin · Alexander S. Kulikov

The code below implements exactly all this. It also contains an additional technical detail: the function \(\texttt{varnum}\) converts a pair of indices \(0 \le i,j < n\) into a unique index from \(\{1, 2, \dotsc, n^{2}\}\).

from itertools import combinations, product
from pycosat import solve

n = 30
clauses = []


# converts a pair of integers into a unique integer
def varnum(i, j):
    assert i in range(n) and j in range(n)
    return i * n + j + 1


# each row contains at least one queen
for i in range(n):
    clauses.append([varnum(i, j) for j in range(n)])

# each row contains at most one queen
for i, (j1, j2) in product(range(n), combinations(range(n), 2)):
    clauses.append([-varnum(i, j1), -varnum(i, j2)])

# each column contains at most one queen
for j, (i1, i2) in product(range(n), combinations(range(n), 2)):
    clauses.append([-varnum(i1, j), -varnum(i2, j)])

# no two queens stay on the same diagonal
for (i1, i2), (j1, j2) in product(combinations(range(n), 2), product(range(n), repeat=2)):
    if abs(i1 - i2) == abs(j1 - j2):
        clauses.append([-varnum(i1, j1), -varnum(i2, j2)])


assignment = solve(clauses)
for i, j in product(range(n), repeat=2):
    if assignment[varnum(i, j) - 1] > 0:
        print(j, end=' ')

26 24 22 25 23 17 4 9 11 8 21 3 6 0 19 15 7 27 2 28 1 29 18 20 12 14 16 10 13 5