POSTED ON 14 APR 2021
READING TIME: 6 MINUTES
Enterprise application development is, for the most part, solving one of these types of problems:
This last problem type is a graph colouring problem, and the nature of these is that solving one of them is much the same as solving another.
Sudoku is one of these types of problems, but it has very simple rules, so it’s a nice playground to try out different ways to solve graph colouring problems. This post outlines a solution using constraint programming with choco solver.
Constraint programming is a paradigm for programming that can be a little unusual the first time you come to it, since it’s completely different to imperative programming.
In short: you tell the program what problem needs to be solved, but not how to solve that problem.
What this means in practical terms is:
So, to make these ideas more concrete, we’ll use them to solve a simple problem.
For this example, we will choose the world’s hardest sudoku problem, you can find a full example of this in Sudoku.java
If you don’t know Sudoku, the rules are:
That’s it. If you’re wondering what this has to do with resource usage, you could imagine the numbers represent available channels in a cell tower, and the squares represent the messages that need to be sent. The solution to this problem will tell you how you could send out these messages in an evenly distributed manner, without getting any resource contention on the channels.
The complete code for this is available here: Sudoku
Before we do anything else, we must first create an empty model for the game, this is as simple as:
Model model = new Model("sudoku");
This model is where new variables, constraints and optimizations are created.
For the sudoku problem, there are 81 variables, one for each square in our grid.
IntVar[][] grid = new IntVar[9][9];
These come in one of two flavours:
grid[row][col] = model.intVar(row, col), 1, 9);
grid[row][col] = model.intVar(value)
Once we have the variables, we need to set up their constraints, we have 9 rows, columns, and sub-squares where the values must all be different. We use the allDifferent constraint for this.
for (int i = 0; i != 9; i++) {
model.allDifferent(getCellsInRow(grid, i)).post();
model.allDifferent(getCellsInColumn(grid, i)).post();
model.allDifferent(getCellsInSquare(grid, i)).post();
}
Finally, we solve it as follows.
Solver solver = model.getSolver();
solver.solve();
Choco solver will keep looking for solutions until it gives up, because it’s used them all, or because it thinks it won’t find anything better, or because you’ve told it to give up after doing enough work.
Once this is done you can get at the value that choco solver found for each cell as follows
grid[row][column].getValue()
And that’s it, the world’s hardest sudoku is solved in under a second.
Whatever you want it to, so long as you can turn it into a combinatorics constraint problem.
For example, here’s a more complex graph colouring program: GraphColouring.java
What it’s doing is:
This post refers to two simple examples of what is possible, but really most combinatorial problems can be solved using this approach.