Star | Watch | Fork |
Home |
---|
User Guide |
Examples |
About |
In this section we will use a Sudoku game to illustrate how to use integer and multi-dimensional arrays in RSOME. Sudoku is a popular number puzzle. The goal is to place the digits in [1,9] on a nine-by-nine grid, with some of the digits already filled in. The solution must satisfy the following four rules:
The Sudoku game can be considered as a feasibility optimization problem with the objective to be zero and constraints used to fulfill above rules. Consider a binary variable \(x_{ijk}\in \{0, 1\}\), with \(i \in [0, 8]\), \(j \in [0, 8]\), and \(k \in [0, 8]\). It equals to one if an integer \(k+1\) is placed in a cell at the \(i\)th row and \(j\)th column. Let \(a_{ij}\) be the known number at the \(i\)th row and \(j\)th column, with \((i, j)\in\mathcal{I}\times\mathcal{J}\) as \(\mathcal{I}\) and \(\mathcal{J}\) are the row and column indices of numbers with known values, the Sudoku game can be thus written as the following integer program:
\[\begin{align} \min~&0 \\ \text{s.t.}~& \sum\limits_{i=0}^8x_{ijk} = 1, \forall j \in [0, 8], k \in [0, 8] \\ & \sum\limits_{j=0}^8x_{ijk} = 1, \forall i \in [0, 8], k \in [0, 8] \\ & \sum\limits_{k=0}^8x_{ijk} = 1, \forall i \in [0, 8], j \in [0, 8] \\ & x_{ij(a_{ij}-1)} = 1, \forall i \in \mathcal{I}, j \in \mathcal{J} \\ & \sum\limits_{m=0}^2\sum\limits_{n=0}^2x_{(i+m), (j+m), k} = 1, \forall i \in \{0, 3, 6\}, j \in \{0, 3, 6\}, k \in [0, 8] \end{align}\]In the following code, we are using RSOME to implement such a model.
import rsome as rso
import numpy as np
from rsome import ro
from rsome import grb_solver as grb
# Sudoku puzzle
# zeros represent unknown numbers
puzzle = np.array([[5, 3, 0, 0, 7, 0, 0, 0, 2],
[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]])
# create model and binary decision variables
model = ro.Model()
x = model.dvar((9, 9, 9), vtype='B')
# objective is set to be zero
model.min(0)
# constraints 1 to 3
model.st(x.sum(axis=0) == 1,
x.sum(axis=1) == 1,
x.sum(axis=2) == 1)
# constraints 4
i, j = np.where(puzzle)
model.st(x[i, j, puzzle[i, j]-1] == 1)
# constraints 5
for i in range(0, 9, 3):
for j in range(0, 9, 3):
model.st(x[i: i+3, j: j+3, :].sum(axis=(0, 1)) == 1)
# solve the integer programming problem
model.solve(grb)
Being solved by Gurobi...
Solution status: 2
Running time: 0.0017s
The binary variable \(x_{ijk}\) is defined to be a three-dimensional array x
with the shape to be (9, 9, 9)
. Based on the decision variable x
, each set of constraints can be formulated as the array form by using the sum()
method. The method sum()
in RSOME is consistent with that in NumPy, where you may use the axis
argument to specify along which axis the sum is performed.
The Sudoku puzzle and the its solution are presented below.
print(puzzle) # display the Sudoku puzzle
[[5 3 0 0 7 0 0 0 2]
[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]]
x_sol = x.get().astype('int') # retrieve the solution as an array of integers
print((x_sol * np.arange(1, 10).reshape((1, 1, 9))).sum(axis=2))
[[5 3 4 6 7 8 9 1 2]
[6 7 2 1 9 5 3 4 8]
[1 9 8 3 4 2 5 6 7]
[8 5 9 7 6 1 4 2 3]
[4 2 6 8 5 3 7 9 1]
[7 1 3 9 2 4 8 5 6]
[9 6 1 5 3 7 2 8 4]
[2 8 7 4 1 9 6 3 5]
[3 4 5 2 8 6 1 7 9]]
Note that in defining “constraints 4”, variables i
and j
represent the row and column indices of the fixed elements, which can be retrieved by the np.where()
function. An alternative approach is to use the boolean indexing of arrays, as the code below.
# an alternative approach for constraints 4
is_fixed = puzzle > 0
model.st(x[is_fixed, puzzle[is_fixed]-1] == 1)
The variable is_fixed
is an array with elements to be True
if the numbers are fixed and False
if the numbers are unknown. Such an array with boolean data can also be used as indices, thus defining the same constraints.