<jupyter_start><jupyter_text>Solve the following Sudoku$$\begin{aligned}&\begin{array}{|ccc|ccc|ccc|}\hline 7 & . & 8 & 2 & 5 & . & . & . &  . \\. & 4 &  . & 8 & . & . & 5 & . & .\\5 & . & . & . & . & . & 6 & . & . \\\hline8 & . & . & 6 & . & . & . & 1 & 4 \\. & 1 & 9 & . & . & . & 2 & 6 & . \\2 & 6 & . & . & . & 1 & . & . & 5 \\\hline. & . & 1 & . & . & . & . & . & . \\. & . & . & . & . & 8 & . & 5 & . \\. & . & . & . & 3 & 4 & 7 & . & 9 \\\hline\end{array}\end{aligned}$$<jupyter_code>size = 9
size_squared = size*size
square_size = 3

A = np.array([[7,0,8,2,5,0,0,0,0],
              [0,4,0,8,0,0,5,0,0],
              [5,0,0,0,0,0,6,0,0],
              [8,0,0,6,0,0,0,1,4],
              [0,1,9,0,0,0,2,6,0],
              [2,6,0,0,0,1,0,0,5],
              [0,0,1,0,0,0,0,0,0],
              [0,0,0,0,0,8,0,5,0],
              [0,0,0,0,3,4,7,0,9]])<jupyter_output><empty_output><jupyter_text>First SolutionEfficent but hard to read<jupyter_code>sudoku = xp.problem()
x = np.array([[[xp.var(vartype=xp.binary) for _ in range(size)] for _ in range(size)] for _ in range(size)], dtype=xp.npvar)
sudoku.addVariable(x)
_ = [[sudoku.addConstraint(xp.Sum(x[i, j]) == 1) for i in range(size)] for j in range(size)]
_ = [[sudoku.addConstraint(xp.Sum(x[i, :, k]) == 1) for i in range(size)] for k in range(size)]
_ = [[sudoku.addConstraint(xp.Sum(x[:, j, k]) == 1) for j in range(size)] for k in range(size)]
_ = [[[sudoku.addConstraint(xp.Sum(x[i:i+square_size, j:j+square_size, k]) == 1) for i in range(0, size, square_size)] for j in range(0, size, square_size)] for k in range(size)]
for i in range(size):
    for j in range(size):
        if A[i, j] != 0:
            sudoku.addConstraint(x[i, j, A[i, j]-1] == 1)
sudoku.solve()
sol = np.array(sudoku.getSolution()).reshape(size, size, size).astype(int)
sol@np.arange(1, 10)<jupyter_output><empty_output><jupyter_text>Second SolutionLess efficent but easier to read<jupyter_code>sudoku = xp.problem()
x = np.array([[xp.var(vartype=xp.integer, lb=1, ub=size) for _ in range(size)] for _ in range(size)], dtype=xp.npvar)
sudoku.addVariable(x)
def add_inequality_constraint(problem, x1, x2, M=size, eps=1):
    y = xp.var(vartype=xp.binary)
    problem.addVariable(y)
    problem.addConstraint(x1 - x2 >= eps - M * y)
    problem.addConstraint(x1 - x2 <= -eps + M * (1 - y))

def add_inequality_constraints_between_variables(problem, variables):
    vars = variables.ravel()
    for i in range(len(vars)):
        for j in range(i+1, len(vars)):
            add_inequality_constraint(problem, vars[i], vars[j])
# numbers on rows and columns must be different
for i in range(size):
    add_inequality_constraints_between_variables(sudoku, x[i])
    add_inequality_constraints_between_variables(sudoku, x[:, i])

# numbers in a square must be different
for i in range(0, size, square_size):
    for j in range(0, size, square_size):
        add_inequality_constraints_between_variables(sudoku, x[i:i+square_size, j:j+square_size])
for i in range(size):
    for j in range(size):
        if A[i, j] != 0:
            sudoku.addConstraint(x[i, j] == A[i, j])
sudoku.solve()
sol = np.array(sudoku.getSolution()[:size_squared]).reshape(size, size).astype(int)

sol<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.20284038283420808, 'fraction_numerical': 0.041988267983945664, 'mean_word_length': 3.127388535031847, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 1, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 17, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '571218', 'license': 'MIT', 'n_tokens_mistral': 1399, 'n_tokens_neox': 1341, 'n_words': 262, 'path': 'Exercises/Labs/sudoku.ipynb', 'repo_name': 'LetteraUnica/mathematical-optimization', 'size': '3239'}